From 1c94119ae26b94a60bb2c2b33494ed43c3b8a52f Mon Sep 17 00:00:00 2001 From: marha Date: Sun, 16 May 2010 20:50:58 +0000 Subject: svn merge -r588:HEAD ^/branches/released . --- xorg-server/hw/dmx/dmx.c | 2254 +++++----- xorg-server/hw/dmx/dmx_glxvisuals.c | 1202 ++--- xorg-server/hw/dmx/dmxcmap.c | 424 +- xorg-server/hw/dmx/dmxcursor.c | 1970 ++++---- xorg-server/hw/dmx/dmxfont.c | 1110 +++-- xorg-server/hw/dmx/dmxgc.c | 842 ++-- xorg-server/hw/dmx/dmxinit.c | 10 +- xorg-server/hw/dmx/dmxpict.c | 26 +- xorg-server/hw/dmx/dmxpixmap.c | 506 +-- xorg-server/hw/dmx/dmxprop.c | 694 +-- xorg-server/hw/dmx/dmxscrinit.c | 1048 ++--- xorg-server/hw/dmx/dmxsync.c | 386 +- xorg-server/hw/dmx/dmxwindow.c | 2030 ++++----- xorg-server/hw/dmx/doc/dmx.sgml | 5555 ++++++++++++----------- xorg-server/hw/dmx/glxProxy/glxcmds.c | 7220 +++++++++++++++--------------- xorg-server/hw/dmx/glxProxy/glxext.c | 1064 ++--- xorg-server/hw/dmx/glxProxy/glxscreens.c | 754 ++-- xorg-server/hw/dmx/glxProxy/glxsingle.c | 2024 ++++----- xorg-server/hw/dmx/glxProxy/glxswap.c | 1076 ++--- xorg-server/hw/dmx/glxProxy/glxutil.c | 222 +- xorg-server/hw/dmx/glxProxy/glxvendor.c | 1164 ++--- xorg-server/hw/dmx/glxProxy/glxvisuals.c | 1078 ++--- xorg-server/hw/dmx/glxProxy/unpack.h | 456 +- xorg-server/hw/dmx/input/dmxinputinit.c | 2622 +++++------ xorg-server/hw/dmx/input/dmxmotion.c | 284 +- xorg-server/hw/dmx/input/lnx-keyboard.c | 1980 ++++---- xorg-server/hw/dmx/input/usb-keyboard.c | 888 ++-- 27 files changed, 19440 insertions(+), 19449 deletions(-) (limited to 'xorg-server/hw/dmx') diff --git a/xorg-server/hw/dmx/dmx.c b/xorg-server/hw/dmx/dmx.c index a1afe76cf..b201fb8a7 100644 --- a/xorg-server/hw/dmx/dmx.c +++ b/xorg-server/hw/dmx/dmx.c @@ -1,1127 +1,1127 @@ -/* - * Copyright 2002-2004 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: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * This file implements the server-side part of the DMX protocol. A - * vector of fucntions is provided at extension initialization time, so - * most all of the useful functions in this file are declared static and - * do not appear in the doxygen documentation. - * - * Much of the low-level work is done by functions in \a dmxextension.c - * - * Please see the Client-to-Server DMX Extension to the X Protocol - * document for details about the protocol. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include -#include -#include "misc.h" -#include "os.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "opaque.h" - -#include "dmxextension.h" -#include -#include -#include "protocol-versions.h" - -#ifdef PANORAMIX -#include "panoramiX.h" -extern unsigned long XRT_WINDOW; -extern int PanoramiXNumScreens; -#endif - -extern void DMXExtensionInit(void); - -static unsigned char DMXCode; - -static DISPATCH_PROC(ProcDMXDispatch); -static DISPATCH_PROC(ProcDMXQueryVersion); -static DISPATCH_PROC(ProcDMXSync); -static DISPATCH_PROC(ProcDMXForceWindowCreation); -static DISPATCH_PROC(ProcDMXGetScreenCount); -static DISPATCH_PROC(ProcDMXGetScreenAttributes); -static DISPATCH_PROC(ProcDMXChangeScreensAttributes); -static DISPATCH_PROC(ProcDMXAddScreen); -static DISPATCH_PROC(ProcDMXRemoveScreen); -static DISPATCH_PROC(ProcDMXGetWindowAttributes); -static DISPATCH_PROC(ProcDMXGetDesktopAttributes); -static DISPATCH_PROC(ProcDMXChangeDesktopAttributes); -static DISPATCH_PROC(ProcDMXGetInputCount); -static DISPATCH_PROC(ProcDMXGetInputAttributes); -static DISPATCH_PROC(ProcDMXAddInput); -static DISPATCH_PROC(ProcDMXRemoveInput); - -static DISPATCH_PROC(SProcDMXDispatch); -static DISPATCH_PROC(SProcDMXQueryVersion); -static DISPATCH_PROC(SProcDMXSync); -static DISPATCH_PROC(SProcDMXForceWindowCreation); -static DISPATCH_PROC(SProcDMXGetScreenCount); -static DISPATCH_PROC(SProcDMXGetScreenAttributes); -static DISPATCH_PROC(SProcDMXChangeScreensAttributes); -static DISPATCH_PROC(SProcDMXAddScreen); -static DISPATCH_PROC(SProcDMXRemoveScreen); -static DISPATCH_PROC(SProcDMXGetWindowAttributes); -static DISPATCH_PROC(SProcDMXGetDesktopAttributes); -static DISPATCH_PROC(SProcDMXChangeDesktopAttributes); -static DISPATCH_PROC(SProcDMXGetInputCount); -static DISPATCH_PROC(SProcDMXGetInputAttributes); -static DISPATCH_PROC(SProcDMXAddInput); -static DISPATCH_PROC(SProcDMXRemoveInput); - -static int _DMXXineramaActive(void) -{ -#ifdef PANORAMIX - return !noPanoramiXExtension; -#endif - return 0; -} - -/** Initialize the extension. */ -void DMXExtensionInit(void) -{ - ExtensionEntry *extEntry; - - if ((extEntry = AddExtension(DMX_EXTENSION_NAME, 0, 0, - ProcDMXDispatch, SProcDMXDispatch, - NULL, StandardMinorOpcode))) - DMXCode = extEntry->base; -} - -static void dmxSetScreenAttribute(int bit, DMXScreenAttributesPtr attr, - CARD32 value) -{ - switch (1 << bit) { - case DMXScreenWindowWidth: attr->screenWindowWidth = value; break; - case DMXScreenWindowHeight: attr->screenWindowHeight = value; break; - case DMXScreenWindowXoffset: attr->screenWindowXoffset = value; break; - case DMXScreenWindowYoffset: attr->screenWindowYoffset = value; break; - case DMXRootWindowWidth: attr->rootWindowWidth = value; break; - case DMXRootWindowHeight: attr->rootWindowHeight = value; break; - case DMXRootWindowXoffset: attr->rootWindowXoffset = value; break; - case DMXRootWindowYoffset: attr->rootWindowYoffset = value; break; - case DMXRootWindowXorigin: attr->rootWindowXorigin = value; break; - case DMXRootWindowYorigin: attr->rootWindowYorigin = value; break; - } -} - -static int dmxFetchScreenAttributes(unsigned int mask, - DMXScreenAttributesPtr attr, - CARD32 *value_list) -{ - int i; - CARD32 *value = value_list; - int count = 0; - - for (i = 0; i < 32; i++) { - if (mask & (1 << i)) { - dmxSetScreenAttribute(i, attr, *value); - ++value; - ++count; - } - } - return count; -} - -static void dmxSetDesktopAttribute(int bit, DMXDesktopAttributesPtr attr, - CARD32 value) -{ - switch (1 << bit) { - case DMXDesktopWidth: attr->width = value; break; - case DMXDesktopHeight: attr->height = value; break; - case DMXDesktopShiftX: attr->shiftX = value; break; - case DMXDesktopShiftY: attr->shiftY = value; break; - } -} - -static int dmxFetchDesktopAttributes(unsigned int mask, - DMXDesktopAttributesPtr attr, - CARD32 *value_list) -{ - int i; - CARD32 *value = value_list; - int count = 0; - - for (i = 0; i < 32; i++) { - if (mask & (1 << i)) { - dmxSetDesktopAttribute(i, attr, *value); - ++value; - ++count; - } - } - return count; -} - -static void dmxSetInputAttribute(int bit, DMXInputAttributesPtr attr, - CARD32 value) -{ - switch (1 << bit) { - case DMXInputType: attr->inputType = value; break; - case DMXInputPhysicalScreen: attr->physicalScreen = value; break; - case DMXInputSendsCore: attr->sendsCore = !!value; break; - } -} - -static int dmxFetchInputAttributes(unsigned int mask, - DMXInputAttributesPtr attr, - CARD32 *value_list) -{ - int i; - CARD32 *value = value_list; - int count = 0; - - for (i = 0; i < 32; i++) { - if (mask & (1 << i)) { - dmxSetInputAttribute(i, attr, *value); - ++value; - ++count; - } - } - return count; -} - -static int ProcDMXQueryVersion(ClientPtr client) -{ - xDMXQueryVersionReply rep; - int n; - - REQUEST_SIZE_MATCH(xDMXQueryVersionReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.majorVersion = SERVER_DMX_MAJOR_VERSION; - rep.minorVersion = SERVER_DMX_MINOR_VERSION; - rep.patchVersion = SERVER_DMX_PATCH_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.majorVersion, n); - swapl(&rep.minorVersion, n); - swapl(&rep.patchVersion, n); - } - WriteToClient(client, sizeof(xDMXQueryVersionReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXSync(ClientPtr client) -{ - xDMXSyncReply rep; - int n; - - REQUEST_SIZE_MATCH(xDMXSyncReq); - - dmxFlushPendingSyncs(); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = 0; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, sizeof(xDMXSyncReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXForceWindowCreation(ClientPtr client) -{ - xDMXForceWindowCreationReply rep; - REQUEST(xDMXForceWindowCreationReq); - WindowPtr pWin; - int n; - - REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq); - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - PanoramiXRes *win; - int i; - - if (!(win = SecurityLookupIDByType(client, stuff->window, XRT_WINDOW, - DixReadAccess))) - return -1; /* BadWindow */ - - FOR_NSCREENS(i) { - if (Success != dixLookupWindow(&pWin, win->info[i].id, client, - DixReadAccess)) - return -1; /* BadWindow */ - - dmxForceWindowCreation(pWin); - } - goto doreply; - } -#endif - - if (Success != dixLookupWindow(&pWin, stuff->window, client, - DixReadAccess)) - return -1; /* BadWindow */ - - dmxForceWindowCreation(pWin); - doreply: - dmxFlushPendingSyncs(); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = 0; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, sizeof(xDMXForceWindowCreationReply), (char *)&rep); - return Success; -} - -static int ProcDMXGetScreenCount(ClientPtr client) -{ - xDMXGetScreenCountReply rep; - int n; - - REQUEST_SIZE_MATCH(xDMXGetScreenCountReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.screenCount = dmxGetNumScreens(); - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.screenCount, n); - } - WriteToClient(client, sizeof(xDMXGetScreenCountReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXGetScreenAttributes(ClientPtr client) -{ - REQUEST(xDMXGetScreenAttributesReq); - xDMXGetScreenAttributesReply rep; - int n; - int length; - int paddedLength; - DMXScreenAttributesRec attr; - - REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq); - - if (stuff->physicalScreen < 0 - || stuff->physicalScreen >= dmxGetNumScreens()) return BadValue; - - if (!dmxGetScreenAttributes(stuff->physicalScreen, &attr)) - return BadValue; - - rep.logicalScreen = attr.logicalScreen; - rep.screenWindowWidth = attr.screenWindowWidth; - rep.screenWindowHeight = attr.screenWindowHeight; - rep.screenWindowXoffset = attr.screenWindowXoffset; - rep.screenWindowYoffset = attr.screenWindowYoffset; - rep.rootWindowWidth = attr.rootWindowWidth; - rep.rootWindowHeight = attr.rootWindowHeight; - rep.rootWindowXoffset = attr.rootWindowXoffset; - rep.rootWindowYoffset = attr.rootWindowYoffset; - rep.rootWindowXorigin = attr.rootWindowXorigin; - rep.rootWindowYorigin = attr.rootWindowYorigin; - - length = attr.displayName ? strlen(attr.displayName) : 0; - paddedLength = pad_to_int32(length); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = bytes_to_int32((sizeof(xDMXGetScreenAttributesReply) - sizeof(xGenericReply)) - + paddedLength); - rep.displayNameLength = length; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.displayNameLength, n); - swapl(&rep.logicalScreen, n); - swaps(&rep.screenWindowWidth, n); - swaps(&rep.screenWindowHeight, n); - swaps(&rep.screenWindowXoffset, n); - swaps(&rep.screenWindowYoffset, n); - swaps(&rep.rootWindowWidth, n); - swaps(&rep.rootWindowHeight, n); - swaps(&rep.rootWindowXoffset, n); - swaps(&rep.rootWindowYoffset, n); - swaps(&rep.rootWindowXorigin, n); - swaps(&rep.rootWindowYorigin, n); - } - WriteToClient(client, sizeof(xDMXGetScreenAttributesReply), (char *)&rep); - if (length) WriteToClient(client, length, (char *)attr.displayName); - return client->noClientException; -} - -static int ProcDMXChangeScreensAttributes(ClientPtr client) -{ - REQUEST(xDMXChangeScreensAttributesReq); - xDMXChangeScreensAttributesReply rep; - int n; - int status = DMX_BAD_XINERAMA; - unsigned int mask = 0; - unsigned int i; - CARD32 *screen_list; - CARD32 *mask_list; - CARD32 *value_list; - DMXScreenAttributesPtr attribs; - int errorScreen = 0; - unsigned int len; - int ones = 0; - - - REQUEST_AT_LEAST_SIZE(xDMXChangeScreensAttributesReq); - len = client->req_len - bytes_to_int32(sizeof(xDMXChangeScreensAttributesReq)); - if (len < stuff->screenCount + stuff->maskCount) - return BadLength; - - screen_list = (CARD32 *)(stuff + 1); - mask_list = &screen_list[stuff->screenCount]; - value_list = &mask_list[stuff->maskCount]; - - for (i = 0; i < stuff->maskCount; i++) ones += Ones(mask_list[i]); - if (len != stuff->screenCount + stuff->maskCount + ones) - return BadLength; - - if (!_DMXXineramaActive()) goto noxinerama; - - if (!(attribs = xalloc(stuff->screenCount * sizeof(*attribs)))) - return BadAlloc; - - for (i = 0; i < stuff->screenCount; i++) { - int count; - - if (i < stuff->maskCount) mask = mask_list[i]; - dmxGetScreenAttributes(screen_list[i], &attribs[i]); - count = dmxFetchScreenAttributes(mask, &attribs[i], value_list); - value_list += count; - } - -#if PANORAMIX - status = dmxConfigureScreenWindows(stuff->screenCount, - screen_list, - attribs, - &errorScreen); -#endif - - xfree(attribs); - - if (status == BadValue) return status; - - noxinerama: - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - rep.errorScreen = errorScreen; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - swapl(&rep.errorScreen, n); - } - WriteToClient(client, - sizeof(xDMXChangeScreensAttributesReply), - (char *)&rep); - return client->noClientException; -} - -static int ProcDMXAddScreen(ClientPtr client) -{ - REQUEST(xDMXAddScreenReq); - xDMXAddScreenReply rep; - int n; - int status = 0; - CARD32 *value_list; - DMXScreenAttributesRec attr; - int count; - char *name; - int len; - int paddedLength; - - REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq); - paddedLength = pad_to_int32(stuff->displayNameLength); - len = client->req_len - bytes_to_int32(sizeof(xDMXAddScreenReq)); - if (len != Ones(stuff->valueMask) + paddedLength/4) - return BadLength; - - memset(&attr, 0, sizeof(attr)); - dmxGetScreenAttributes(stuff->physicalScreen, &attr); - value_list = (CARD32 *)(stuff + 1); - count = dmxFetchScreenAttributes(stuff->valueMask, &attr, value_list); - - if (!(name = xalloc(stuff->displayNameLength + 1 + 4))) - return BadAlloc; - memcpy(name, &value_list[count], stuff->displayNameLength); - name[stuff->displayNameLength] = '\0'; - attr.displayName = name; - - status = dmxAttachScreen(stuff->physicalScreen, &attr); - - xfree(name); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - rep.physicalScreen = stuff->physicalScreen; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - swapl(&rep.physicalScreen, n); - } - WriteToClient(client, - sizeof(xDMXAddScreenReply), - (char *)&rep); - return client->noClientException; -} - -static int ProcDMXRemoveScreen(ClientPtr client) -{ - REQUEST(xDMXRemoveScreenReq); - xDMXRemoveScreenReply rep; - int n; - int status = 0; - - REQUEST_SIZE_MATCH(xDMXRemoveScreenReq); - - status = dmxDetachScreen(stuff->physicalScreen); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, - sizeof(xDMXRemoveScreenReply), - (char *)&rep); - return client->noClientException; -} - - -#ifdef PANORAMIX -static int dmxPopulatePanoramiX(ClientPtr client, Window window, - CARD32 *screens, CARD32 *windows, - xRectangle *pos, xRectangle *vis) -{ - WindowPtr pWin; - PanoramiXRes *win; - int i; - int count = 0; - DMXWindowAttributesRec attr; - - if (!(win = SecurityLookupIDByType(client, window, XRT_WINDOW, - DixReadAccess))) - return -1; /* BadWindow */ - - FOR_NSCREENS(i) { - if (Success != dixLookupWindow(&pWin, win->info[i].id, client, - DixReadAccess)) - return -1; /* BadWindow */ - if (dmxGetWindowAttributes(pWin, &attr)) { - screens[count] = attr.screen; - windows[count] = attr.window; - pos[count] = attr.pos; - vis[count] = attr.vis; - ++count; /* Only count existing windows */ - } - } - return count; -} -#endif - -static int dmxPopulate(ClientPtr client, Window window, CARD32 *screens, - CARD32 *windows, xRectangle *pos, xRectangle *vis) -{ - WindowPtr pWin; - DMXWindowAttributesRec attr; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) - return dmxPopulatePanoramiX(client, window, screens, windows, - pos, vis); -#endif - - if (Success != dixLookupWindow(&pWin, window, client, DixReadAccess)) - return -1; /* BadWindow */ - - dmxGetWindowAttributes(pWin, &attr); - *screens = attr.screen; - *windows = attr.window; - *pos = attr.pos; - *vis = attr.vis; - return 1; -} - -static int dmxMaxNumScreens(void) -{ -#ifdef PANORAMIX - if (!noPanoramiXExtension) return PanoramiXNumScreens; -#endif - return 1; -} - -static int ProcDMXGetWindowAttributes(ClientPtr client) -{ - REQUEST(xDMXGetWindowAttributesReq); - xDMXGetWindowAttributesReply rep; - int i, n; - CARD32 *screens; - CARD32 *windows; - xRectangle *pos, *vis; - int count = dmxMaxNumScreens(); - - REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq); - - if (!(screens = xalloc(count * sizeof(*screens)))) - return BadAlloc; - if (!(windows = xalloc(count * sizeof(*windows)))) { - xfree(screens); - return BadAlloc; - } - if (!(pos = xalloc(count * sizeof(*pos)))) { - xfree(windows); - xfree(screens); - return BadAlloc; - } - if (!(vis = xalloc(count * sizeof(*vis)))) { - xfree(pos); - xfree(windows); - xfree(screens); - return BadAlloc; - } - - if ((count = dmxPopulate(client, stuff->window, screens, windows, - pos, vis)) < 0) { - xfree(vis); - xfree(pos); - xfree(windows); - xfree(screens); - return BadWindow; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = count * 6; - rep.screenCount = count; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.screenCount, n); - for (i = 0; i < count; i++) { - swapl(&screens[i], n); - swapl(&windows[i], n); - - swaps(&pos[i].x, n); - swaps(&pos[i].y, n); - swaps(&pos[i].width, n); - swaps(&pos[i].height, n); - - swaps(&vis[i].x, n); - swaps(&vis[i].y, n); - swaps(&vis[i].width, n); - swaps(&vis[i].height, n); - } - } - - dmxFlushPendingSyncs(); - - WriteToClient(client, sizeof(xDMXGetWindowAttributesReply), (char *)&rep); - if (count) { - WriteToClient(client, count * sizeof(*screens), (char *)screens); - WriteToClient(client, count * sizeof(*windows), (char *)windows); - WriteToClient(client, count * sizeof(*pos), (char *)pos); - WriteToClient(client, count * sizeof(*vis), (char *)vis); - } - - xfree(vis); - xfree(pos); - xfree(windows); - xfree(screens); - - return client->noClientException; -} - -static int ProcDMXGetDesktopAttributes(ClientPtr client) -{ - xDMXGetDesktopAttributesReply rep; - int n; - DMXDesktopAttributesRec attr; - - REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq); - - dmxGetDesktopAttributes(&attr); - - rep.width = attr.width; - rep.height = attr.height; - rep.shiftX = attr.shiftX; - rep.shiftY = attr.shiftY; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.width, n); - swapl(&rep.height, n); - swapl(&rep.shiftX, n); - swapl(&rep.shiftY, n); - } - WriteToClient(client, sizeof(xDMXGetDesktopAttributesReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXChangeDesktopAttributes(ClientPtr client) -{ - REQUEST(xDMXChangeDesktopAttributesReq); - xDMXChangeDesktopAttributesReply rep; - int n; - int status = DMX_BAD_XINERAMA; - CARD32 *value_list; - DMXDesktopAttributesRec attr; - int len; - - REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq); - len = client->req_len - (sizeof(xDMXChangeDesktopAttributesReq) >> 2); - if (len != Ones(stuff->valueMask)) - return BadLength; - - if (!_DMXXineramaActive()) goto noxinerama; - - value_list = (CARD32 *)(stuff + 1); - - dmxGetDesktopAttributes(&attr); - dmxFetchDesktopAttributes(stuff->valueMask, &attr, value_list); - -#if PANORAMIX - status = dmxConfigureDesktop(&attr); -#endif - if (status == BadValue) return status; - - noxinerama: - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, - sizeof(xDMXChangeDesktopAttributesReply), - (char *)&rep); - return client->noClientException; -} - -static int ProcDMXGetInputCount(ClientPtr client) -{ - xDMXGetInputCountReply rep; - int n; - - REQUEST_SIZE_MATCH(xDMXGetInputCountReq); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.inputCount = dmxGetInputCount(); - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.inputCount, n); - } - WriteToClient(client, sizeof(xDMXGetInputCountReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXGetInputAttributes(ClientPtr client) -{ - REQUEST(xDMXGetInputAttributesReq); - xDMXGetInputAttributesReply rep; - int n; - int length; - int paddedLength; - DMXInputAttributesRec attr; - - REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq); - - if (dmxGetInputAttributes(stuff->deviceId, &attr)) return BadValue; - rep.inputType = attr.inputType; - rep.physicalScreen = attr.physicalScreen; - rep.physicalId = attr.physicalId; - rep.isCore = attr.isCore; - rep.sendsCore = attr.sendsCore; - rep.detached = attr.detached; - - length = attr.name ? strlen(attr.name) : 0; - paddedLength = pad_to_int32(length); - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = bytes_to_int32(paddedLength); - rep.nameLength = length; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.inputType, n); - swapl(&rep.physicalScreen, n); - swapl(&rep.physicalId, n); - swapl(&rep.nameLength, n); - } - WriteToClient(client, sizeof(xDMXGetInputAttributesReply), (char *)&rep); - if (length) WriteToClient(client, length, (char *)attr.name); - return client->noClientException; -} - -static int ProcDMXAddInput(ClientPtr client) -{ - REQUEST(xDMXAddInputReq); - xDMXAddInputReply rep; - int n; - int status = 0; - CARD32 *value_list; - DMXInputAttributesRec attr; - int count; - char *name; - int len; - int paddedLength; - int id = -1; - - REQUEST_AT_LEAST_SIZE(xDMXAddInputReq); - paddedLength = pad_to_int32(stuff->displayNameLength); - len = client->req_len - (sizeof(xDMXAddInputReq) >> 2); - if (len != Ones(stuff->valueMask) + paddedLength/4) - return BadLength; - - memset(&attr, 0, sizeof(attr)); - value_list = (CARD32 *)(stuff + 1); - count = dmxFetchInputAttributes(stuff->valueMask, &attr, value_list); - - if (!(name = xalloc(stuff->displayNameLength + 1 + 4))) - return BadAlloc; - memcpy(name, &value_list[count], stuff->displayNameLength); - name[stuff->displayNameLength] = '\0'; - attr.name = name; - - status = dmxAddInput(&attr, &id); - - xfree(name); - - if (status) return status; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - rep.physicalId = id; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - swapl(&rep.physicalId, n); - } - WriteToClient(client, sizeof(xDMXAddInputReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXRemoveInput(ClientPtr client) -{ - REQUEST(xDMXRemoveInputReq); - xDMXRemoveInputReply rep; - int n; - int status = 0; - - REQUEST_SIZE_MATCH(xDMXRemoveInputReq); - - status = dmxRemoveInput(stuff->physicalId); - - if (status) return status; - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.length = 0; - rep.status = status; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swapl(&rep.status, n); - } - WriteToClient(client, sizeof(xDMXRemoveInputReply), (char *)&rep); - return client->noClientException; -} - -static int ProcDMXDispatch(ClientPtr client) -{ - REQUEST(xReq); - - switch (stuff->data) { - case X_DMXQueryVersion: return ProcDMXQueryVersion(client); - case X_DMXSync: return ProcDMXSync(client); - case X_DMXForceWindowCreation: return ProcDMXForceWindowCreation(client); - case X_DMXGetScreenCount: return ProcDMXGetScreenCount(client); - case X_DMXGetScreenAttributes: return ProcDMXGetScreenAttributes(client); - case X_DMXChangeScreensAttributes: - return ProcDMXChangeScreensAttributes(client); - case X_DMXAddScreen: return ProcDMXAddScreen(client); - case X_DMXRemoveScreen: return ProcDMXRemoveScreen(client); - case X_DMXGetWindowAttributes: return ProcDMXGetWindowAttributes(client); - case X_DMXGetDesktopAttributes: return ProcDMXGetDesktopAttributes(client); - case X_DMXChangeDesktopAttributes: - return ProcDMXChangeDesktopAttributes(client); - case X_DMXGetInputCount: return ProcDMXGetInputCount(client); - case X_DMXGetInputAttributes: return ProcDMXGetInputAttributes(client); - case X_DMXAddInput: return ProcDMXAddInput(client); - case X_DMXRemoveInput: return ProcDMXRemoveInput(client); - - case X_DMXGetScreenInformationDEPRECATED: - case X_DMXForceWindowCreationDEPRECATED: - case X_DMXReconfigureScreenDEPRECATED: - return BadImplementation; - - default: return BadRequest; - } -} - -static int SProcDMXQueryVersion(ClientPtr client) -{ - int n; - REQUEST(xDMXQueryVersionReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXQueryVersionReq); - return ProcDMXQueryVersion(client); -} - -static int SProcDMXSync(ClientPtr client) -{ - int n; - REQUEST(xDMXSyncReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXSyncReq); - return ProcDMXSync(client); -} - -static int SProcDMXForceWindowCreation(ClientPtr client) -{ - int n; - REQUEST(xDMXForceWindowCreationReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq); - swaps(&stuff->window, n); - return ProcDMXForceWindowCreation(client); -} - -static int SProcDMXGetScreenCount(ClientPtr client) -{ - int n; - REQUEST(xDMXGetScreenCountReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetScreenCountReq); - return ProcDMXGetScreenCount(client); -} - -static int SProcDMXGetScreenAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXGetScreenAttributesReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq); - swapl(&stuff->physicalScreen, n); - return ProcDMXGetScreenAttributes(client); -} - -static int SProcDMXChangeScreensAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXChangeScreensAttributesReq); - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xDMXGetScreenAttributesReq); - swapl(&stuff->screenCount, n); - swapl(&stuff->maskCount, n); - SwapRestL(stuff); - return ProcDMXGetScreenAttributes(client); -} - -static int SProcDMXAddScreen(ClientPtr client) -{ - int n; - int paddedLength; - REQUEST(xDMXAddScreenReq); - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq); - swapl(&stuff->displayNameLength, n); - swapl(&stuff->valueMask, n); - paddedLength = pad_to_int32(stuff->displayNameLength); - SwapLongs((CARD32 *)(stuff+1), LengthRestL(stuff) - paddedLength/4); - return ProcDMXAddScreen(client); -} - -static int SProcDMXRemoveScreen(ClientPtr client) -{ - int n; - REQUEST(xDMXRemoveScreenReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXRemoveScreenReq); - swapl(&stuff->physicalScreen, n); - return ProcDMXRemoveScreen(client); -} - -static int SProcDMXGetWindowAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXGetWindowAttributesReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq); - swapl(&stuff->window, n); - return ProcDMXGetWindowAttributes(client); -} - -static int SProcDMXGetDesktopAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXGetDesktopAttributesReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq); - return ProcDMXGetDesktopAttributes(client); -} - -static int SProcDMXChangeDesktopAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXChangeDesktopAttributesReq); - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq); - swapl(&stuff->valueMask, n); - SwapRestL(stuff); - return ProcDMXChangeDesktopAttributes(client); -} - -static int SProcDMXGetInputCount(ClientPtr client) -{ - int n; - REQUEST(xDMXGetInputCountReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetInputCountReq); - return ProcDMXGetInputCount(client); -} - -static int SProcDMXGetInputAttributes(ClientPtr client) -{ - int n; - REQUEST(xDMXGetInputAttributesReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq); - swapl(&stuff->deviceId, n); - return ProcDMXGetInputAttributes(client); -} - -static int SProcDMXAddInput(ClientPtr client) -{ - int n; - int paddedLength; - REQUEST(xDMXAddInputReq); - - swaps(&stuff->length, n); - REQUEST_AT_LEAST_SIZE(xDMXAddInputReq); - swapl(&stuff->displayNameLength, n); - swapl(&stuff->valueMask, n); - paddedLength = pad_to_int32(stuff->displayNameLength); - SwapLongs((CARD32 *)(stuff+1), LengthRestL(stuff) - paddedLength/4); - return ProcDMXAddInput(client); -} - -static int SProcDMXRemoveInput(ClientPtr client) -{ - int n; - REQUEST(xDMXRemoveInputReq); - - swaps(&stuff->length, n); - REQUEST_SIZE_MATCH(xDMXRemoveInputReq); - swapl(&stuff->physicalId, n); - return ProcDMXRemoveInput(client); -} - -static int SProcDMXDispatch (ClientPtr client) -{ - REQUEST(xReq); - - switch (stuff->data) { - case X_DMXQueryVersion: return SProcDMXQueryVersion(client); - case X_DMXSync: return SProcDMXSync(client); - case X_DMXForceWindowCreation: return SProcDMXForceWindowCreation(client); - case X_DMXGetScreenCount: return SProcDMXGetScreenCount(client); - case X_DMXGetScreenAttributes: return SProcDMXGetScreenAttributes(client); - case X_DMXChangeScreensAttributes: - return SProcDMXChangeScreensAttributes(client); - case X_DMXAddScreen: return SProcDMXAddScreen(client); - case X_DMXRemoveScreen: return SProcDMXRemoveScreen(client); - case X_DMXGetWindowAttributes: return SProcDMXGetWindowAttributes(client); - case X_DMXGetDesktopAttributes: - return SProcDMXGetDesktopAttributes(client); - case X_DMXChangeDesktopAttributes: - return SProcDMXChangeDesktopAttributes(client); - case X_DMXGetInputCount: return SProcDMXGetInputCount(client); - case X_DMXGetInputAttributes: return SProcDMXGetInputAttributes(client); - case X_DMXAddInput: return SProcDMXAddInput(client); - case X_DMXRemoveInput: return SProcDMXRemoveInput(client); - - case X_DMXGetScreenInformationDEPRECATED: - case X_DMXForceWindowCreationDEPRECATED: - case X_DMXReconfigureScreenDEPRECATED: - return BadImplementation; - - default: return BadRequest; - } -} +/* + * Copyright 2002-2004 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: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * This file implements the server-side part of the DMX protocol. A + * vector of fucntions is provided at extension initialization time, so + * most all of the useful functions in this file are declared static and + * do not appear in the doxygen documentation. + * + * Much of the low-level work is done by functions in \a dmxextension.c + * + * Please see the Client-to-Server DMX Extension to the X Protocol + * document for details about the protocol. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include +#include +#include "misc.h" +#include "os.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "opaque.h" + +#include "dmxextension.h" +#include +#include +#include "protocol-versions.h" + +#ifdef PANORAMIX +#include "panoramiX.h" +extern unsigned long XRT_WINDOW; +extern int PanoramiXNumScreens; +#endif + +extern void DMXExtensionInit(void); + +static unsigned char DMXCode; + +static DISPATCH_PROC(ProcDMXDispatch); +static DISPATCH_PROC(ProcDMXQueryVersion); +static DISPATCH_PROC(ProcDMXSync); +static DISPATCH_PROC(ProcDMXForceWindowCreation); +static DISPATCH_PROC(ProcDMXGetScreenCount); +static DISPATCH_PROC(ProcDMXGetScreenAttributes); +static DISPATCH_PROC(ProcDMXChangeScreensAttributes); +static DISPATCH_PROC(ProcDMXAddScreen); +static DISPATCH_PROC(ProcDMXRemoveScreen); +static DISPATCH_PROC(ProcDMXGetWindowAttributes); +static DISPATCH_PROC(ProcDMXGetDesktopAttributes); +static DISPATCH_PROC(ProcDMXChangeDesktopAttributes); +static DISPATCH_PROC(ProcDMXGetInputCount); +static DISPATCH_PROC(ProcDMXGetInputAttributes); +static DISPATCH_PROC(ProcDMXAddInput); +static DISPATCH_PROC(ProcDMXRemoveInput); + +static DISPATCH_PROC(SProcDMXDispatch); +static DISPATCH_PROC(SProcDMXQueryVersion); +static DISPATCH_PROC(SProcDMXSync); +static DISPATCH_PROC(SProcDMXForceWindowCreation); +static DISPATCH_PROC(SProcDMXGetScreenCount); +static DISPATCH_PROC(SProcDMXGetScreenAttributes); +static DISPATCH_PROC(SProcDMXChangeScreensAttributes); +static DISPATCH_PROC(SProcDMXAddScreen); +static DISPATCH_PROC(SProcDMXRemoveScreen); +static DISPATCH_PROC(SProcDMXGetWindowAttributes); +static DISPATCH_PROC(SProcDMXGetDesktopAttributes); +static DISPATCH_PROC(SProcDMXChangeDesktopAttributes); +static DISPATCH_PROC(SProcDMXGetInputCount); +static DISPATCH_PROC(SProcDMXGetInputAttributes); +static DISPATCH_PROC(SProcDMXAddInput); +static DISPATCH_PROC(SProcDMXRemoveInput); + +static int _DMXXineramaActive(void) +{ +#ifdef PANORAMIX + return !noPanoramiXExtension; +#endif + return 0; +} + +/** Initialize the extension. */ +void DMXExtensionInit(void) +{ + ExtensionEntry *extEntry; + + if ((extEntry = AddExtension(DMX_EXTENSION_NAME, 0, 0, + ProcDMXDispatch, SProcDMXDispatch, + NULL, StandardMinorOpcode))) + DMXCode = extEntry->base; +} + +static void dmxSetScreenAttribute(int bit, DMXScreenAttributesPtr attr, + CARD32 value) +{ + switch (1 << bit) { + case DMXScreenWindowWidth: attr->screenWindowWidth = value; break; + case DMXScreenWindowHeight: attr->screenWindowHeight = value; break; + case DMXScreenWindowXoffset: attr->screenWindowXoffset = value; break; + case DMXScreenWindowYoffset: attr->screenWindowYoffset = value; break; + case DMXRootWindowWidth: attr->rootWindowWidth = value; break; + case DMXRootWindowHeight: attr->rootWindowHeight = value; break; + case DMXRootWindowXoffset: attr->rootWindowXoffset = value; break; + case DMXRootWindowYoffset: attr->rootWindowYoffset = value; break; + case DMXRootWindowXorigin: attr->rootWindowXorigin = value; break; + case DMXRootWindowYorigin: attr->rootWindowYorigin = value; break; + } +} + +static int dmxFetchScreenAttributes(unsigned int mask, + DMXScreenAttributesPtr attr, + CARD32 *value_list) +{ + int i; + CARD32 *value = value_list; + int count = 0; + + for (i = 0; i < 32; i++) { + if (mask & (1 << i)) { + dmxSetScreenAttribute(i, attr, *value); + ++value; + ++count; + } + } + return count; +} + +static void dmxSetDesktopAttribute(int bit, DMXDesktopAttributesPtr attr, + CARD32 value) +{ + switch (1 << bit) { + case DMXDesktopWidth: attr->width = value; break; + case DMXDesktopHeight: attr->height = value; break; + case DMXDesktopShiftX: attr->shiftX = value; break; + case DMXDesktopShiftY: attr->shiftY = value; break; + } +} + +static int dmxFetchDesktopAttributes(unsigned int mask, + DMXDesktopAttributesPtr attr, + CARD32 *value_list) +{ + int i; + CARD32 *value = value_list; + int count = 0; + + for (i = 0; i < 32; i++) { + if (mask & (1 << i)) { + dmxSetDesktopAttribute(i, attr, *value); + ++value; + ++count; + } + } + return count; +} + +static void dmxSetInputAttribute(int bit, DMXInputAttributesPtr attr, + CARD32 value) +{ + switch (1 << bit) { + case DMXInputType: attr->inputType = value; break; + case DMXInputPhysicalScreen: attr->physicalScreen = value; break; + case DMXInputSendsCore: attr->sendsCore = !!value; break; + } +} + +static int dmxFetchInputAttributes(unsigned int mask, + DMXInputAttributesPtr attr, + CARD32 *value_list) +{ + int i; + CARD32 *value = value_list; + int count = 0; + + for (i = 0; i < 32; i++) { + if (mask & (1 << i)) { + dmxSetInputAttribute(i, attr, *value); + ++value; + ++count; + } + } + return count; +} + +static int ProcDMXQueryVersion(ClientPtr client) +{ + xDMXQueryVersionReply rep; + int n; + + REQUEST_SIZE_MATCH(xDMXQueryVersionReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.majorVersion = SERVER_DMX_MAJOR_VERSION; + rep.minorVersion = SERVER_DMX_MINOR_VERSION; + rep.patchVersion = SERVER_DMX_PATCH_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.majorVersion, n); + swapl(&rep.minorVersion, n); + swapl(&rep.patchVersion, n); + } + WriteToClient(client, sizeof(xDMXQueryVersionReply), (char *)&rep); + return Success; +} + +static int ProcDMXSync(ClientPtr client) +{ + xDMXSyncReply rep; + int n; + + REQUEST_SIZE_MATCH(xDMXSyncReq); + + dmxFlushPendingSyncs(); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = 0; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, sizeof(xDMXSyncReply), (char *)&rep); + return Success; +} + +static int ProcDMXForceWindowCreation(ClientPtr client) +{ + xDMXForceWindowCreationReply rep; + REQUEST(xDMXForceWindowCreationReq); + WindowPtr pWin; + int n; + + REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq); + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + PanoramiXRes *win; + int i; + + if (!(win = SecurityLookupIDByType(client, stuff->window, XRT_WINDOW, + DixReadAccess))) + return -1; /* BadWindow */ + + FOR_NSCREENS(i) { + if (Success != dixLookupWindow(&pWin, win->info[i].id, client, + DixReadAccess)) + return -1; /* BadWindow */ + + dmxForceWindowCreation(pWin); + } + goto doreply; + } +#endif + + if (Success != dixLookupWindow(&pWin, stuff->window, client, + DixReadAccess)) + return -1; /* BadWindow */ + + dmxForceWindowCreation(pWin); + doreply: + dmxFlushPendingSyncs(); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = 0; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, sizeof(xDMXForceWindowCreationReply), (char *)&rep); + return Success; +} + +static int ProcDMXGetScreenCount(ClientPtr client) +{ + xDMXGetScreenCountReply rep; + int n; + + REQUEST_SIZE_MATCH(xDMXGetScreenCountReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.screenCount = dmxGetNumScreens(); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.screenCount, n); + } + WriteToClient(client, sizeof(xDMXGetScreenCountReply), (char *)&rep); + return Success; +} + +static int ProcDMXGetScreenAttributes(ClientPtr client) +{ + REQUEST(xDMXGetScreenAttributesReq); + xDMXGetScreenAttributesReply rep; + int n; + int length; + int paddedLength; + DMXScreenAttributesRec attr; + + REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq); + + if (stuff->physicalScreen < 0 + || stuff->physicalScreen >= dmxGetNumScreens()) return BadValue; + + if (!dmxGetScreenAttributes(stuff->physicalScreen, &attr)) + return BadValue; + + rep.logicalScreen = attr.logicalScreen; + rep.screenWindowWidth = attr.screenWindowWidth; + rep.screenWindowHeight = attr.screenWindowHeight; + rep.screenWindowXoffset = attr.screenWindowXoffset; + rep.screenWindowYoffset = attr.screenWindowYoffset; + rep.rootWindowWidth = attr.rootWindowWidth; + rep.rootWindowHeight = attr.rootWindowHeight; + rep.rootWindowXoffset = attr.rootWindowXoffset; + rep.rootWindowYoffset = attr.rootWindowYoffset; + rep.rootWindowXorigin = attr.rootWindowXorigin; + rep.rootWindowYorigin = attr.rootWindowYorigin; + + length = attr.displayName ? strlen(attr.displayName) : 0; + paddedLength = pad_to_int32(length); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = bytes_to_int32((sizeof(xDMXGetScreenAttributesReply) - sizeof(xGenericReply)) + + paddedLength); + rep.displayNameLength = length; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.displayNameLength, n); + swapl(&rep.logicalScreen, n); + swaps(&rep.screenWindowWidth, n); + swaps(&rep.screenWindowHeight, n); + swaps(&rep.screenWindowXoffset, n); + swaps(&rep.screenWindowYoffset, n); + swaps(&rep.rootWindowWidth, n); + swaps(&rep.rootWindowHeight, n); + swaps(&rep.rootWindowXoffset, n); + swaps(&rep.rootWindowYoffset, n); + swaps(&rep.rootWindowXorigin, n); + swaps(&rep.rootWindowYorigin, n); + } + WriteToClient(client, sizeof(xDMXGetScreenAttributesReply), (char *)&rep); + if (length) WriteToClient(client, length, (char *)attr.displayName); + return Success; +} + +static int ProcDMXChangeScreensAttributes(ClientPtr client) +{ + REQUEST(xDMXChangeScreensAttributesReq); + xDMXChangeScreensAttributesReply rep; + int n; + int status = DMX_BAD_XINERAMA; + unsigned int mask = 0; + unsigned int i; + CARD32 *screen_list; + CARD32 *mask_list; + CARD32 *value_list; + DMXScreenAttributesPtr attribs; + int errorScreen = 0; + unsigned int len; + int ones = 0; + + + REQUEST_AT_LEAST_SIZE(xDMXChangeScreensAttributesReq); + len = client->req_len - bytes_to_int32(sizeof(xDMXChangeScreensAttributesReq)); + if (len < stuff->screenCount + stuff->maskCount) + return BadLength; + + screen_list = (CARD32 *)(stuff + 1); + mask_list = &screen_list[stuff->screenCount]; + value_list = &mask_list[stuff->maskCount]; + + for (i = 0; i < stuff->maskCount; i++) ones += Ones(mask_list[i]); + if (len != stuff->screenCount + stuff->maskCount + ones) + return BadLength; + + if (!_DMXXineramaActive()) goto noxinerama; + + if (!(attribs = malloc(stuff->screenCount * sizeof(*attribs)))) + return BadAlloc; + + for (i = 0; i < stuff->screenCount; i++) { + int count; + + if (i < stuff->maskCount) mask = mask_list[i]; + dmxGetScreenAttributes(screen_list[i], &attribs[i]); + count = dmxFetchScreenAttributes(mask, &attribs[i], value_list); + value_list += count; + } + +#if PANORAMIX + status = dmxConfigureScreenWindows(stuff->screenCount, + screen_list, + attribs, + &errorScreen); +#endif + + free(attribs); + + if (status == BadValue) return status; + + noxinerama: + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + rep.errorScreen = errorScreen; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + swapl(&rep.errorScreen, n); + } + WriteToClient(client, + sizeof(xDMXChangeScreensAttributesReply), + (char *)&rep); + return Success; +} + +static int ProcDMXAddScreen(ClientPtr client) +{ + REQUEST(xDMXAddScreenReq); + xDMXAddScreenReply rep; + int n; + int status = 0; + CARD32 *value_list; + DMXScreenAttributesRec attr; + int count; + char *name; + int len; + int paddedLength; + + REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq); + paddedLength = pad_to_int32(stuff->displayNameLength); + len = client->req_len - bytes_to_int32(sizeof(xDMXAddScreenReq)); + if (len != Ones(stuff->valueMask) + paddedLength/4) + return BadLength; + + memset(&attr, 0, sizeof(attr)); + dmxGetScreenAttributes(stuff->physicalScreen, &attr); + value_list = (CARD32 *)(stuff + 1); + count = dmxFetchScreenAttributes(stuff->valueMask, &attr, value_list); + + if (!(name = malloc(stuff->displayNameLength + 1 + 4))) + return BadAlloc; + memcpy(name, &value_list[count], stuff->displayNameLength); + name[stuff->displayNameLength] = '\0'; + attr.displayName = name; + + status = dmxAttachScreen(stuff->physicalScreen, &attr); + + free(name); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + rep.physicalScreen = stuff->physicalScreen; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + swapl(&rep.physicalScreen, n); + } + WriteToClient(client, + sizeof(xDMXAddScreenReply), + (char *)&rep); + return Success; +} + +static int ProcDMXRemoveScreen(ClientPtr client) +{ + REQUEST(xDMXRemoveScreenReq); + xDMXRemoveScreenReply rep; + int n; + int status = 0; + + REQUEST_SIZE_MATCH(xDMXRemoveScreenReq); + + status = dmxDetachScreen(stuff->physicalScreen); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, + sizeof(xDMXRemoveScreenReply), + (char *)&rep); + return Success; +} + + +#ifdef PANORAMIX +static int dmxPopulatePanoramiX(ClientPtr client, Window window, + CARD32 *screens, CARD32 *windows, + xRectangle *pos, xRectangle *vis) +{ + WindowPtr pWin; + PanoramiXRes *win; + int i; + int count = 0; + DMXWindowAttributesRec attr; + + if (!(win = SecurityLookupIDByType(client, window, XRT_WINDOW, + DixReadAccess))) + return -1; /* BadWindow */ + + FOR_NSCREENS(i) { + if (Success != dixLookupWindow(&pWin, win->info[i].id, client, + DixReadAccess)) + return -1; /* BadWindow */ + if (dmxGetWindowAttributes(pWin, &attr)) { + screens[count] = attr.screen; + windows[count] = attr.window; + pos[count] = attr.pos; + vis[count] = attr.vis; + ++count; /* Only count existing windows */ + } + } + return count; +} +#endif + +static int dmxPopulate(ClientPtr client, Window window, CARD32 *screens, + CARD32 *windows, xRectangle *pos, xRectangle *vis) +{ + WindowPtr pWin; + DMXWindowAttributesRec attr; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) + return dmxPopulatePanoramiX(client, window, screens, windows, + pos, vis); +#endif + + if (Success != dixLookupWindow(&pWin, window, client, DixReadAccess)) + return -1; /* BadWindow */ + + dmxGetWindowAttributes(pWin, &attr); + *screens = attr.screen; + *windows = attr.window; + *pos = attr.pos; + *vis = attr.vis; + return 1; +} + +static int dmxMaxNumScreens(void) +{ +#ifdef PANORAMIX + if (!noPanoramiXExtension) return PanoramiXNumScreens; +#endif + return 1; +} + +static int ProcDMXGetWindowAttributes(ClientPtr client) +{ + REQUEST(xDMXGetWindowAttributesReq); + xDMXGetWindowAttributesReply rep; + int i, n; + CARD32 *screens; + CARD32 *windows; + xRectangle *pos, *vis; + int count = dmxMaxNumScreens(); + + REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq); + + if (!(screens = malloc(count * sizeof(*screens)))) + return BadAlloc; + if (!(windows = malloc(count * sizeof(*windows)))) { + free(screens); + return BadAlloc; + } + if (!(pos = malloc(count * sizeof(*pos)))) { + free(windows); + free(screens); + return BadAlloc; + } + if (!(vis = malloc(count * sizeof(*vis)))) { + free(pos); + free(windows); + free(screens); + return BadAlloc; + } + + if ((count = dmxPopulate(client, stuff->window, screens, windows, + pos, vis)) < 0) { + free(vis); + free(pos); + free(windows); + free(screens); + return BadWindow; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = count * 6; + rep.screenCount = count; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.screenCount, n); + for (i = 0; i < count; i++) { + swapl(&screens[i], n); + swapl(&windows[i], n); + + swaps(&pos[i].x, n); + swaps(&pos[i].y, n); + swaps(&pos[i].width, n); + swaps(&pos[i].height, n); + + swaps(&vis[i].x, n); + swaps(&vis[i].y, n); + swaps(&vis[i].width, n); + swaps(&vis[i].height, n); + } + } + + dmxFlushPendingSyncs(); + + WriteToClient(client, sizeof(xDMXGetWindowAttributesReply), (char *)&rep); + if (count) { + WriteToClient(client, count * sizeof(*screens), (char *)screens); + WriteToClient(client, count * sizeof(*windows), (char *)windows); + WriteToClient(client, count * sizeof(*pos), (char *)pos); + WriteToClient(client, count * sizeof(*vis), (char *)vis); + } + + free(vis); + free(pos); + free(windows); + free(screens); + + return Success; +} + +static int ProcDMXGetDesktopAttributes(ClientPtr client) +{ + xDMXGetDesktopAttributesReply rep; + int n; + DMXDesktopAttributesRec attr; + + REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq); + + dmxGetDesktopAttributes(&attr); + + rep.width = attr.width; + rep.height = attr.height; + rep.shiftX = attr.shiftX; + rep.shiftY = attr.shiftY; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.width, n); + swapl(&rep.height, n); + swapl(&rep.shiftX, n); + swapl(&rep.shiftY, n); + } + WriteToClient(client, sizeof(xDMXGetDesktopAttributesReply), (char *)&rep); + return Success; +} + +static int ProcDMXChangeDesktopAttributes(ClientPtr client) +{ + REQUEST(xDMXChangeDesktopAttributesReq); + xDMXChangeDesktopAttributesReply rep; + int n; + int status = DMX_BAD_XINERAMA; + CARD32 *value_list; + DMXDesktopAttributesRec attr; + int len; + + REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq); + len = client->req_len - (sizeof(xDMXChangeDesktopAttributesReq) >> 2); + if (len != Ones(stuff->valueMask)) + return BadLength; + + if (!_DMXXineramaActive()) goto noxinerama; + + value_list = (CARD32 *)(stuff + 1); + + dmxGetDesktopAttributes(&attr); + dmxFetchDesktopAttributes(stuff->valueMask, &attr, value_list); + +#if PANORAMIX + status = dmxConfigureDesktop(&attr); +#endif + if (status == BadValue) return status; + + noxinerama: + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, + sizeof(xDMXChangeDesktopAttributesReply), + (char *)&rep); + return Success; +} + +static int ProcDMXGetInputCount(ClientPtr client) +{ + xDMXGetInputCountReply rep; + int n; + + REQUEST_SIZE_MATCH(xDMXGetInputCountReq); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.inputCount = dmxGetInputCount(); + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.inputCount, n); + } + WriteToClient(client, sizeof(xDMXGetInputCountReply), (char *)&rep); + return Success; +} + +static int ProcDMXGetInputAttributes(ClientPtr client) +{ + REQUEST(xDMXGetInputAttributesReq); + xDMXGetInputAttributesReply rep; + int n; + int length; + int paddedLength; + DMXInputAttributesRec attr; + + REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq); + + if (dmxGetInputAttributes(stuff->deviceId, &attr)) return BadValue; + rep.inputType = attr.inputType; + rep.physicalScreen = attr.physicalScreen; + rep.physicalId = attr.physicalId; + rep.isCore = attr.isCore; + rep.sendsCore = attr.sendsCore; + rep.detached = attr.detached; + + length = attr.name ? strlen(attr.name) : 0; + paddedLength = pad_to_int32(length); + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = bytes_to_int32(paddedLength); + rep.nameLength = length; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.inputType, n); + swapl(&rep.physicalScreen, n); + swapl(&rep.physicalId, n); + swapl(&rep.nameLength, n); + } + WriteToClient(client, sizeof(xDMXGetInputAttributesReply), (char *)&rep); + if (length) WriteToClient(client, length, (char *)attr.name); + return Success; +} + +static int ProcDMXAddInput(ClientPtr client) +{ + REQUEST(xDMXAddInputReq); + xDMXAddInputReply rep; + int n; + int status = 0; + CARD32 *value_list; + DMXInputAttributesRec attr; + int count; + char *name; + int len; + int paddedLength; + int id = -1; + + REQUEST_AT_LEAST_SIZE(xDMXAddInputReq); + paddedLength = pad_to_int32(stuff->displayNameLength); + len = client->req_len - (sizeof(xDMXAddInputReq) >> 2); + if (len != Ones(stuff->valueMask) + paddedLength/4) + return BadLength; + + memset(&attr, 0, sizeof(attr)); + value_list = (CARD32 *)(stuff + 1); + count = dmxFetchInputAttributes(stuff->valueMask, &attr, value_list); + + if (!(name = malloc(stuff->displayNameLength + 1 + 4))) + return BadAlloc; + memcpy(name, &value_list[count], stuff->displayNameLength); + name[stuff->displayNameLength] = '\0'; + attr.name = name; + + status = dmxAddInput(&attr, &id); + + free(name); + + if (status) return status; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + rep.physicalId = id; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + swapl(&rep.physicalId, n); + } + WriteToClient(client, sizeof(xDMXAddInputReply), (char *)&rep); + return Success; +} + +static int ProcDMXRemoveInput(ClientPtr client) +{ + REQUEST(xDMXRemoveInputReq); + xDMXRemoveInputReply rep; + int n; + int status = 0; + + REQUEST_SIZE_MATCH(xDMXRemoveInputReq); + + status = dmxRemoveInput(stuff->physicalId); + + if (status) return status; + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.length = 0; + rep.status = status; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swapl(&rep.status, n); + } + WriteToClient(client, sizeof(xDMXRemoveInputReply), (char *)&rep); + return Success; +} + +static int ProcDMXDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_DMXQueryVersion: return ProcDMXQueryVersion(client); + case X_DMXSync: return ProcDMXSync(client); + case X_DMXForceWindowCreation: return ProcDMXForceWindowCreation(client); + case X_DMXGetScreenCount: return ProcDMXGetScreenCount(client); + case X_DMXGetScreenAttributes: return ProcDMXGetScreenAttributes(client); + case X_DMXChangeScreensAttributes: + return ProcDMXChangeScreensAttributes(client); + case X_DMXAddScreen: return ProcDMXAddScreen(client); + case X_DMXRemoveScreen: return ProcDMXRemoveScreen(client); + case X_DMXGetWindowAttributes: return ProcDMXGetWindowAttributes(client); + case X_DMXGetDesktopAttributes: return ProcDMXGetDesktopAttributes(client); + case X_DMXChangeDesktopAttributes: + return ProcDMXChangeDesktopAttributes(client); + case X_DMXGetInputCount: return ProcDMXGetInputCount(client); + case X_DMXGetInputAttributes: return ProcDMXGetInputAttributes(client); + case X_DMXAddInput: return ProcDMXAddInput(client); + case X_DMXRemoveInput: return ProcDMXRemoveInput(client); + + case X_DMXGetScreenInformationDEPRECATED: + case X_DMXForceWindowCreationDEPRECATED: + case X_DMXReconfigureScreenDEPRECATED: + return BadImplementation; + + default: return BadRequest; + } +} + +static int SProcDMXQueryVersion(ClientPtr client) +{ + int n; + REQUEST(xDMXQueryVersionReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXQueryVersionReq); + return ProcDMXQueryVersion(client); +} + +static int SProcDMXSync(ClientPtr client) +{ + int n; + REQUEST(xDMXSyncReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXSyncReq); + return ProcDMXSync(client); +} + +static int SProcDMXForceWindowCreation(ClientPtr client) +{ + int n; + REQUEST(xDMXForceWindowCreationReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXForceWindowCreationReq); + swaps(&stuff->window, n); + return ProcDMXForceWindowCreation(client); +} + +static int SProcDMXGetScreenCount(ClientPtr client) +{ + int n; + REQUEST(xDMXGetScreenCountReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetScreenCountReq); + return ProcDMXGetScreenCount(client); +} + +static int SProcDMXGetScreenAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXGetScreenAttributesReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetScreenAttributesReq); + swapl(&stuff->physicalScreen, n); + return ProcDMXGetScreenAttributes(client); +} + +static int SProcDMXChangeScreensAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXChangeScreensAttributesReq); + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xDMXGetScreenAttributesReq); + swapl(&stuff->screenCount, n); + swapl(&stuff->maskCount, n); + SwapRestL(stuff); + return ProcDMXGetScreenAttributes(client); +} + +static int SProcDMXAddScreen(ClientPtr client) +{ + int n; + int paddedLength; + REQUEST(xDMXAddScreenReq); + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xDMXAddScreenReq); + swapl(&stuff->displayNameLength, n); + swapl(&stuff->valueMask, n); + paddedLength = pad_to_int32(stuff->displayNameLength); + SwapLongs((CARD32 *)(stuff+1), LengthRestL(stuff) - paddedLength/4); + return ProcDMXAddScreen(client); +} + +static int SProcDMXRemoveScreen(ClientPtr client) +{ + int n; + REQUEST(xDMXRemoveScreenReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXRemoveScreenReq); + swapl(&stuff->physicalScreen, n); + return ProcDMXRemoveScreen(client); +} + +static int SProcDMXGetWindowAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXGetWindowAttributesReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetWindowAttributesReq); + swapl(&stuff->window, n); + return ProcDMXGetWindowAttributes(client); +} + +static int SProcDMXGetDesktopAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXGetDesktopAttributesReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetDesktopAttributesReq); + return ProcDMXGetDesktopAttributes(client); +} + +static int SProcDMXChangeDesktopAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXChangeDesktopAttributesReq); + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xDMXChangeDesktopAttributesReq); + swapl(&stuff->valueMask, n); + SwapRestL(stuff); + return ProcDMXChangeDesktopAttributes(client); +} + +static int SProcDMXGetInputCount(ClientPtr client) +{ + int n; + REQUEST(xDMXGetInputCountReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetInputCountReq); + return ProcDMXGetInputCount(client); +} + +static int SProcDMXGetInputAttributes(ClientPtr client) +{ + int n; + REQUEST(xDMXGetInputAttributesReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXGetInputAttributesReq); + swapl(&stuff->deviceId, n); + return ProcDMXGetInputAttributes(client); +} + +static int SProcDMXAddInput(ClientPtr client) +{ + int n; + int paddedLength; + REQUEST(xDMXAddInputReq); + + swaps(&stuff->length, n); + REQUEST_AT_LEAST_SIZE(xDMXAddInputReq); + swapl(&stuff->displayNameLength, n); + swapl(&stuff->valueMask, n); + paddedLength = pad_to_int32(stuff->displayNameLength); + SwapLongs((CARD32 *)(stuff+1), LengthRestL(stuff) - paddedLength/4); + return ProcDMXAddInput(client); +} + +static int SProcDMXRemoveInput(ClientPtr client) +{ + int n; + REQUEST(xDMXRemoveInputReq); + + swaps(&stuff->length, n); + REQUEST_SIZE_MATCH(xDMXRemoveInputReq); + swapl(&stuff->physicalId, n); + return ProcDMXRemoveInput(client); +} + +static int SProcDMXDispatch (ClientPtr client) +{ + REQUEST(xReq); + + switch (stuff->data) { + case X_DMXQueryVersion: return SProcDMXQueryVersion(client); + case X_DMXSync: return SProcDMXSync(client); + case X_DMXForceWindowCreation: return SProcDMXForceWindowCreation(client); + case X_DMXGetScreenCount: return SProcDMXGetScreenCount(client); + case X_DMXGetScreenAttributes: return SProcDMXGetScreenAttributes(client); + case X_DMXChangeScreensAttributes: + return SProcDMXChangeScreensAttributes(client); + case X_DMXAddScreen: return SProcDMXAddScreen(client); + case X_DMXRemoveScreen: return SProcDMXRemoveScreen(client); + case X_DMXGetWindowAttributes: return SProcDMXGetWindowAttributes(client); + case X_DMXGetDesktopAttributes: + return SProcDMXGetDesktopAttributes(client); + case X_DMXChangeDesktopAttributes: + return SProcDMXChangeDesktopAttributes(client); + case X_DMXGetInputCount: return SProcDMXGetInputCount(client); + case X_DMXGetInputAttributes: return SProcDMXGetInputAttributes(client); + case X_DMXAddInput: return SProcDMXAddInput(client); + case X_DMXRemoveInput: return SProcDMXRemoveInput(client); + + case X_DMXGetScreenInformationDEPRECATED: + case X_DMXForceWindowCreationDEPRECATED: + case X_DMXReconfigureScreenDEPRECATED: + return BadImplementation; + + default: return BadRequest; + } +} diff --git a/xorg-server/hw/dmx/dmx_glxvisuals.c b/xorg-server/hw/dmx/dmx_glxvisuals.c index ec33468be..50a23e30f 100644 --- a/xorg-server/hw/dmx/dmx_glxvisuals.c +++ b/xorg-server/hw/dmx/dmx_glxvisuals.c @@ -1,601 +1,601 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include -#include -#include -#include - -#include "dmx_glxvisuals.h" - -__GLXvisualConfig *GetGLXVisualConfigs(Display *dpy, int screen, int *nconfigs) -{ - xGLXGetVisualConfigsReq *req; - xGLXGetVisualConfigsReply reply; - __GLXvisualConfig *config, *configs; - GLint i, j, nvisuals, nprops; - INT32 *props, *p; - int majorOpcode, dummy; - int num_good_visuals; - - if (!XQueryExtension(dpy, "GLX", &majorOpcode, &dummy, &dummy)) { - return(NULL); - } - - /* Send the glXGetVisualConfigs request */ - LockDisplay(dpy); - GetReq(GLXGetVisualConfigs,req); - req->reqType = majorOpcode; - req->glxCode = X_GLXGetVisualConfigs; - req->screen = screen; - if (!_XReply(dpy, (xReply*) &reply, 0, False)) { - /* Something is busted. Punt. */ - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - nvisuals = (int)reply.numVisuals; - if (!nvisuals) { - /* This screen does not support GL rendering */ - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - /* Check number of properties per visual */ - nprops = (int)reply.numProps; - if (nprops < __GLX_MIN_CONFIG_PROPS) { - /* Huh? Not in protocol defined limits. Punt */ - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - props = (INT32*) Xmalloc(nprops * __GLX_SIZE_CARD32); - if (!props) { - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - /* Allocate memory for our config structure */ - config = (__GLXvisualConfig*) - Xmalloc(nvisuals * sizeof(__GLXvisualConfig)); - if (!config) { - Xfree(props); - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - memset(config, 0, nvisuals * sizeof(__GLXvisualConfig)); - configs = config; - num_good_visuals = 0; - - /* Convert config structure into our format */ - for (i=0; ivisualRating = GLX_NONE_EXT; - config->transparentPixel = GLX_NONE_EXT; - - /* Copy in the first set of properties */ - config->vid = props[0]; - config->class = props[1]; - - config->rgba = (Bool) props[2]; - - config->redSize = props[3]; - config->greenSize = props[4]; - config->blueSize = props[5]; - config->alphaSize = props[6]; - - config->accumRedSize = props[7]; - config->accumGreenSize = props[8]; - config->accumBlueSize = props[9]; - config->accumAlphaSize = props[10]; - - config->doubleBuffer = (Bool) props[11]; - config->stereo = (Bool) props[12]; - - config->bufferSize = props[13]; - config->depthSize = props[14]; - config->stencilSize = props[15]; - - config->auxBuffers = props[16]; - config->level = props[17]; - - /* Process remaining properties */ - p = &props[18]; - for (j=__GLX_MIN_CONFIG_PROPS; jmultiSampleSize = value; - break; - case GLX_SAMPLE_BUFFERS_SGIS: - config->nMultiSampleBuffers = value; - break; - - case GLX_TRANSPARENT_TYPE_EXT: - config->transparentPixel = value; - break; - case GLX_TRANSPARENT_INDEX_VALUE_EXT: - config->transparentIndex = value; - break; - case GLX_TRANSPARENT_RED_VALUE_EXT: - config->transparentRed = value; - break; - case GLX_TRANSPARENT_GREEN_VALUE_EXT: - config->transparentGreen = value; - break; - case GLX_TRANSPARENT_BLUE_VALUE_EXT: - config->transparentBlue = value; - break; - case GLX_TRANSPARENT_ALPHA_VALUE_EXT: - config->transparentAlpha = value; - break; - - case GLX_VISUAL_CAVEAT_EXT: - config->visualRating = value; - break; - - /* visualSelectGroup is an internal used property */ - case GLX_VISUAL_SELECT_GROUP_SGIX: - config->visualSelectGroup = value; - break; - - default : - /* Ignore properties we don't recognize */ - break; - } - } /* for j */ - - /* - // filter out overlay visuals (dmx does not support overlays) - */ - if (config->level == 0) { - config++; - num_good_visuals++; - } - - } /* for i */ - - UnlockDisplay(dpy); - - nvisuals = num_good_visuals; - - config = configs; - for (i=0; ivid; - vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask, - &template, &n); - - if (vis != NULL) { - config->redMask = vis->red_mask; - config->greenMask = vis->green_mask; - config->blueMask = vis->blue_mask; - config->alphaMask = 0; /* XXX */ - free(vis); - } - } - config++; - } /* for i */ - - XFree(props); - SyncHandle(); - - *nconfigs = nvisuals; - return( configs ); -} - - -__GLXFBConfig *GetGLXFBConfigs(Display *dpy, int glxMajorOpcode, int *nconfigs) -{ - xGLXGetFBConfigsReq *req; - xGLXGetFBConfigsReply reply; - __GLXFBConfig *config, *fbconfigs; - GLint i, j, numFBConfigs, numAttribs; - INT32 *attrs, *p; - int screen = DefaultScreen( dpy ); - int numValidConfigs = 0; - - /* Send the glXGetFBConfigs request */ - LockDisplay(dpy); - GetReq(GLXGetFBConfigs, req); - req->reqType = glxMajorOpcode; - req->glxCode = X_GLXGetFBConfigs; - req->screen = screen; - - *nconfigs = 0; - - if (!_XReply(dpy, (xReply*) &reply, 0, False)) { - /* Something is busted. Punt. */ - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - numFBConfigs = (int)reply.numFBConfigs; - if (!numFBConfigs) { - /* This screen does not support GL rendering */ - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - numAttribs = (int)reply.numAttribs; - if (!numAttribs) { - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - attrs = (INT32*) Xmalloc(2*numAttribs * __GLX_SIZE_CARD32); - if (!attrs) { - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - - /* Allocate memory for our config structure */ - config = (__GLXFBConfig*) - Xmalloc(numFBConfigs * sizeof(__GLXFBConfig)); - if (!config) { - Xfree(attrs); - UnlockDisplay(dpy); - SyncHandle(); - return NULL; - } - memset(config, 0, numFBConfigs * sizeof(__GLXFBConfig)); - fbconfigs = config; - - /* Convert attribute list into our format */ - for (i=0; itransparentType = GLX_NONE_EXT; - config->visualCaveat = GLX_NONE_EXT; - config->minRed = 0.; - config->maxRed = 1.; - config->minGreen = 0.; - config->maxGreen = 1.; - config->minBlue = 0.; - config->maxBlue = 1.; - config->minAlpha = 0.; - config->maxAlpha = 1.; - - /* Read attribute list */ - _XRead(dpy, (char *)attrs, (2*numAttribs * __GLX_SIZE_CARD32)); - - p = attrs; - for (j=0; jid = value; - break; - case GLX_BUFFER_SIZE: - config->indexBits = value; - break; - case GLX_LEVEL: - config->level = value; - break; - case GLX_DOUBLEBUFFER: - config->doubleBufferMode = value; - break; - case GLX_STEREO: - config->stereoMode = value; - break; - case GLX_AUX_BUFFERS: - config->maxAuxBuffers = value; - break; - case GLX_RED_SIZE: - config->redBits = value; - break; - case GLX_GREEN_SIZE: - config->greenBits = value; - break; - case GLX_BLUE_SIZE: - config->blueBits = value; - break; - case GLX_ALPHA_SIZE: - config->alphaBits = value; - break; - case GLX_DEPTH_SIZE: - config->depthBits = value; - break; - case GLX_STENCIL_SIZE: - config->stencilBits = value; - break; - case GLX_ACCUM_RED_SIZE: - config->accumRedBits = value; - break; - case GLX_ACCUM_GREEN_SIZE: - config->accumGreenBits = value; - break; - case GLX_ACCUM_BLUE_SIZE: - config->accumBlueBits = value; - break; - case GLX_ACCUM_ALPHA_SIZE: - config->accumAlphaBits = value; - break; - case GLX_RENDER_TYPE: - config->renderType = value; - break; - case GLX_DRAWABLE_TYPE: - config->drawableType = value; - break; - case GLX_X_VISUAL_TYPE: - config->visualType = value; - break; - case GLX_CONFIG_CAVEAT: - config->visualCaveat = value; - break; - case GLX_TRANSPARENT_TYPE: - config->transparentType = value; - break; - case GLX_TRANSPARENT_INDEX_VALUE: - config->transparentIndex = value; - break; - case GLX_TRANSPARENT_RED_VALUE: - config->transparentRed = value; - break; - case GLX_TRANSPARENT_GREEN_VALUE: - config->transparentGreen = value; - break; - case GLX_TRANSPARENT_BLUE_VALUE: - config->transparentBlue = value; - break; - case GLX_TRANSPARENT_ALPHA_VALUE: - config->transparentAlpha = value; - break; - case GLX_MAX_PBUFFER_WIDTH: - config->maxPbufferWidth = value; - break; - case GLX_MAX_PBUFFER_HEIGHT: - config->maxPbufferHeight = value; - break; - case GLX_MAX_PBUFFER_PIXELS: - config->maxPbufferPixels = value; - break; - case GLX_VISUAL_ID: - config->associatedVisualId = value; - break; - - /* visualSelectGroup is an internal used property */ - case GLX_VISUAL_SELECT_GROUP_SGIX: - config->visualSelectGroup = value; - break; - - /* SGIS_multisample attributes */ - case GLX_SAMPLES_SGIS: - config->multiSampleSize = value; - break; - case GLX_SAMPLE_BUFFERS_SGIS: - config->nMultiSampleBuffers = value; - break; - - /* SGIX_pbuffer specific attributes */ - case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX: - config->optimalPbufferWidth = value; - break; - case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX: - config->optimalPbufferHeight = value; - break; - - default: - /* Ignore attributes we don't recognize */ - break; - } - } /* for j */ - - /* Fill in derived values */ - config->screen = screen; - - config->rgbMode = config->renderType & GLX_RGBA_BIT; - config->colorIndexMode = !config->rgbMode; - - config->haveAccumBuffer = - config->accumRedBits > 0 || - config->accumGreenBits > 0 || - config->accumBlueBits > 0; - /* Can't have alpha without color */ - - config->haveDepthBuffer = config->depthBits > 0; - config->haveStencilBuffer = config->stencilBits > 0; - - /* overlay visuals are not valid for now */ - if (!config->level) { - config++; - numValidConfigs++; - } - - } /* for i */ - UnlockDisplay(dpy); - - config = fbconfigs; - for (i=0; iassociatedVisualId != 0) { - XVisualInfo *vis, template; - int n; - - template.screen = screen; - template.visualid = config->associatedVisualId; - vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask, - &template, &n); - - if (vis != NULL) { - config->redMask = (GLuint)vis->red_mask; - config->greenMask = (GLuint)vis->green_mask; - config->blueMask = (GLuint)vis->blue_mask; - config->alphaMask = 0; /* XXX */ - free(vis); - } - } - - config++; - } /* for i */ - - XFree(attrs); - SyncHandle(); - - *nconfigs = numValidConfigs; - return fbconfigs; -} - -__GLXvisualConfig * -GetGLXVisualConfigsFromFBConfigs(__GLXFBConfig *fbconfigs, int nfbconfigs, - XVisualInfo *visuals, int nvisuals, - __GLXvisualConfig *glxConfigs, int nGlxConfigs, - int *nconfigs) -{ - __GLXvisualConfig *configs = NULL; - int i; - - if (!fbconfigs || !nfbconfigs || !nconfigs) return(NULL); - *nconfigs = 0; - - /* Allocate memory for our config structure */ - configs = (__GLXvisualConfig*) - Xmalloc(nfbconfigs * sizeof(__GLXvisualConfig)); - if (!configs) { - return NULL; - } - memset(configs, 0, nfbconfigs * sizeof(__GLXvisualConfig)); - - for (i=0; iassociatedVisualId > 0) { - __GLXvisualConfig *cfg = configs + (*nconfigs); - int j; - XVisualInfo *vinfo = NULL; - - for (j=0; jassociatedVisualId) { - vinfo = &visuals[j]; - break; - } - } - if (!vinfo) continue; - - /* skip 16 bit colormap visuals */ - if (vinfo->depth == 16 && - vinfo->class != TrueColor && - vinfo->class != DirectColor ) { - continue; - } - - (*nconfigs)++; - - /* - * if the same visualid exists in the glx configs, - * copy the glx attributes from the glx config - */ - for (j=0; jvisualid) - break; - } - if (j < nGlxConfigs) { - memcpy(cfg, &glxConfigs[j], sizeof(__GLXvisualConfig) ); - continue; - } - - /* - * make glx attributes from the FB config attributes - */ - cfg->vid = fbcfg->associatedVisualId; - cfg->class = vinfo->class; - cfg->rgba = !(fbcfg->renderType & GLX_COLOR_INDEX_BIT_SGIX); - cfg->redSize = fbcfg->redBits; - cfg->greenSize = fbcfg->greenBits; - cfg->blueSize = fbcfg->blueBits; - cfg->alphaSize = fbcfg->alphaBits; - cfg->redMask = fbcfg->redMask; - cfg->greenMask = fbcfg->greenMask; - cfg->blueMask = fbcfg->blueMask; - cfg->alphaMask = fbcfg->alphaMask; - cfg->accumRedSize = fbcfg->accumRedBits; - cfg->accumGreenSize = fbcfg->accumGreenBits; - cfg->accumBlueSize = fbcfg->accumBlueBits; - cfg->accumAlphaSize = fbcfg->accumAlphaBits; - cfg->doubleBuffer = fbcfg->doubleBufferMode; - cfg->stereo = fbcfg->stereoMode; - if (vinfo->class == TrueColor || vinfo->class == DirectColor) { - cfg->bufferSize = (fbcfg->rgbMode ? (fbcfg->redBits + - fbcfg->greenBits + - fbcfg->blueBits + - fbcfg->alphaBits) - : fbcfg->indexBits ); - } - else { - cfg->bufferSize = vinfo->depth; - } - cfg->depthSize = fbcfg->depthBits; - cfg->stencilSize = fbcfg->stencilBits; - cfg->auxBuffers = fbcfg->maxAuxBuffers; - cfg->level = fbcfg->level; - cfg->visualRating = fbcfg->visualCaveat; - cfg->transparentPixel = fbcfg->transparentType; - cfg->transparentRed = fbcfg->transparentRed; - cfg->transparentGreen = fbcfg->transparentGreen; - cfg->transparentBlue = fbcfg->transparentBlue; - cfg->transparentAlpha = fbcfg->transparentAlpha; - cfg->transparentIndex = fbcfg->transparentIndex; - cfg->multiSampleSize = fbcfg->multiSampleSize; - cfg->nMultiSampleBuffers = fbcfg->nMultiSampleBuffers; - cfg->visualSelectGroup = fbcfg->visualSelectGroup; - } - } - - return( configs ); -} - +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include +#include +#include +#include + +#include "dmx_glxvisuals.h" + +__GLXvisualConfig *GetGLXVisualConfigs(Display *dpy, int screen, int *nconfigs) +{ + xGLXGetVisualConfigsReq *req; + xGLXGetVisualConfigsReply reply; + __GLXvisualConfig *config, *configs; + GLint i, j, nvisuals, nprops; + INT32 *props, *p; + int majorOpcode, dummy; + int num_good_visuals; + + if (!XQueryExtension(dpy, "GLX", &majorOpcode, &dummy, &dummy)) { + return(NULL); + } + + /* Send the glXGetVisualConfigs request */ + LockDisplay(dpy); + GetReq(GLXGetVisualConfigs,req); + req->reqType = majorOpcode; + req->glxCode = X_GLXGetVisualConfigs; + req->screen = screen; + if (!_XReply(dpy, (xReply*) &reply, 0, False)) { + /* Something is busted. Punt. */ + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + nvisuals = (int)reply.numVisuals; + if (!nvisuals) { + /* This screen does not support GL rendering */ + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + /* Check number of properties per visual */ + nprops = (int)reply.numProps; + if (nprops < __GLX_MIN_CONFIG_PROPS) { + /* Huh? Not in protocol defined limits. Punt */ + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + props = (INT32*) Xmalloc(nprops * __GLX_SIZE_CARD32); + if (!props) { + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + /* Allocate memory for our config structure */ + config = (__GLXvisualConfig*) + Xmalloc(nvisuals * sizeof(__GLXvisualConfig)); + if (!config) { + free(props); + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + memset(config, 0, nvisuals * sizeof(__GLXvisualConfig)); + configs = config; + num_good_visuals = 0; + + /* Convert config structure into our format */ + for (i=0; ivisualRating = GLX_NONE_EXT; + config->transparentPixel = GLX_NONE_EXT; + + /* Copy in the first set of properties */ + config->vid = props[0]; + config->class = props[1]; + + config->rgba = (Bool) props[2]; + + config->redSize = props[3]; + config->greenSize = props[4]; + config->blueSize = props[5]; + config->alphaSize = props[6]; + + config->accumRedSize = props[7]; + config->accumGreenSize = props[8]; + config->accumBlueSize = props[9]; + config->accumAlphaSize = props[10]; + + config->doubleBuffer = (Bool) props[11]; + config->stereo = (Bool) props[12]; + + config->bufferSize = props[13]; + config->depthSize = props[14]; + config->stencilSize = props[15]; + + config->auxBuffers = props[16]; + config->level = props[17]; + + /* Process remaining properties */ + p = &props[18]; + for (j=__GLX_MIN_CONFIG_PROPS; jmultiSampleSize = value; + break; + case GLX_SAMPLE_BUFFERS_SGIS: + config->nMultiSampleBuffers = value; + break; + + case GLX_TRANSPARENT_TYPE_EXT: + config->transparentPixel = value; + break; + case GLX_TRANSPARENT_INDEX_VALUE_EXT: + config->transparentIndex = value; + break; + case GLX_TRANSPARENT_RED_VALUE_EXT: + config->transparentRed = value; + break; + case GLX_TRANSPARENT_GREEN_VALUE_EXT: + config->transparentGreen = value; + break; + case GLX_TRANSPARENT_BLUE_VALUE_EXT: + config->transparentBlue = value; + break; + case GLX_TRANSPARENT_ALPHA_VALUE_EXT: + config->transparentAlpha = value; + break; + + case GLX_VISUAL_CAVEAT_EXT: + config->visualRating = value; + break; + + /* visualSelectGroup is an internal used property */ + case GLX_VISUAL_SELECT_GROUP_SGIX: + config->visualSelectGroup = value; + break; + + default : + /* Ignore properties we don't recognize */ + break; + } + } /* for j */ + + /* + // filter out overlay visuals (dmx does not support overlays) + */ + if (config->level == 0) { + config++; + num_good_visuals++; + } + + } /* for i */ + + UnlockDisplay(dpy); + + nvisuals = num_good_visuals; + + config = configs; + for (i=0; ivid; + vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask, + &template, &n); + + if (vis != NULL) { + config->redMask = vis->red_mask; + config->greenMask = vis->green_mask; + config->blueMask = vis->blue_mask; + config->alphaMask = 0; /* XXX */ + free(vis); + } + } + config++; + } /* for i */ + + XFree(props); + SyncHandle(); + + *nconfigs = nvisuals; + return( configs ); +} + + +__GLXFBConfig *GetGLXFBConfigs(Display *dpy, int glxMajorOpcode, int *nconfigs) +{ + xGLXGetFBConfigsReq *req; + xGLXGetFBConfigsReply reply; + __GLXFBConfig *config, *fbconfigs; + GLint i, j, numFBConfigs, numAttribs; + INT32 *attrs, *p; + int screen = DefaultScreen( dpy ); + int numValidConfigs = 0; + + /* Send the glXGetFBConfigs request */ + LockDisplay(dpy); + GetReq(GLXGetFBConfigs, req); + req->reqType = glxMajorOpcode; + req->glxCode = X_GLXGetFBConfigs; + req->screen = screen; + + *nconfigs = 0; + + if (!_XReply(dpy, (xReply*) &reply, 0, False)) { + /* Something is busted. Punt. */ + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + numFBConfigs = (int)reply.numFBConfigs; + if (!numFBConfigs) { + /* This screen does not support GL rendering */ + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + numAttribs = (int)reply.numAttribs; + if (!numAttribs) { + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + attrs = (INT32*) Xmalloc(2*numAttribs * __GLX_SIZE_CARD32); + if (!attrs) { + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + + /* Allocate memory for our config structure */ + config = (__GLXFBConfig*) + Xmalloc(numFBConfigs * sizeof(__GLXFBConfig)); + if (!config) { + free(attrs); + UnlockDisplay(dpy); + SyncHandle(); + return NULL; + } + memset(config, 0, numFBConfigs * sizeof(__GLXFBConfig)); + fbconfigs = config; + + /* Convert attribute list into our format */ + for (i=0; itransparentType = GLX_NONE_EXT; + config->visualCaveat = GLX_NONE_EXT; + config->minRed = 0.; + config->maxRed = 1.; + config->minGreen = 0.; + config->maxGreen = 1.; + config->minBlue = 0.; + config->maxBlue = 1.; + config->minAlpha = 0.; + config->maxAlpha = 1.; + + /* Read attribute list */ + _XRead(dpy, (char *)attrs, (2*numAttribs * __GLX_SIZE_CARD32)); + + p = attrs; + for (j=0; jid = value; + break; + case GLX_BUFFER_SIZE: + config->indexBits = value; + break; + case GLX_LEVEL: + config->level = value; + break; + case GLX_DOUBLEBUFFER: + config->doubleBufferMode = value; + break; + case GLX_STEREO: + config->stereoMode = value; + break; + case GLX_AUX_BUFFERS: + config->maxAuxBuffers = value; + break; + case GLX_RED_SIZE: + config->redBits = value; + break; + case GLX_GREEN_SIZE: + config->greenBits = value; + break; + case GLX_BLUE_SIZE: + config->blueBits = value; + break; + case GLX_ALPHA_SIZE: + config->alphaBits = value; + break; + case GLX_DEPTH_SIZE: + config->depthBits = value; + break; + case GLX_STENCIL_SIZE: + config->stencilBits = value; + break; + case GLX_ACCUM_RED_SIZE: + config->accumRedBits = value; + break; + case GLX_ACCUM_GREEN_SIZE: + config->accumGreenBits = value; + break; + case GLX_ACCUM_BLUE_SIZE: + config->accumBlueBits = value; + break; + case GLX_ACCUM_ALPHA_SIZE: + config->accumAlphaBits = value; + break; + case GLX_RENDER_TYPE: + config->renderType = value; + break; + case GLX_DRAWABLE_TYPE: + config->drawableType = value; + break; + case GLX_X_VISUAL_TYPE: + config->visualType = value; + break; + case GLX_CONFIG_CAVEAT: + config->visualCaveat = value; + break; + case GLX_TRANSPARENT_TYPE: + config->transparentType = value; + break; + case GLX_TRANSPARENT_INDEX_VALUE: + config->transparentIndex = value; + break; + case GLX_TRANSPARENT_RED_VALUE: + config->transparentRed = value; + break; + case GLX_TRANSPARENT_GREEN_VALUE: + config->transparentGreen = value; + break; + case GLX_TRANSPARENT_BLUE_VALUE: + config->transparentBlue = value; + break; + case GLX_TRANSPARENT_ALPHA_VALUE: + config->transparentAlpha = value; + break; + case GLX_MAX_PBUFFER_WIDTH: + config->maxPbufferWidth = value; + break; + case GLX_MAX_PBUFFER_HEIGHT: + config->maxPbufferHeight = value; + break; + case GLX_MAX_PBUFFER_PIXELS: + config->maxPbufferPixels = value; + break; + case GLX_VISUAL_ID: + config->associatedVisualId = value; + break; + + /* visualSelectGroup is an internal used property */ + case GLX_VISUAL_SELECT_GROUP_SGIX: + config->visualSelectGroup = value; + break; + + /* SGIS_multisample attributes */ + case GLX_SAMPLES_SGIS: + config->multiSampleSize = value; + break; + case GLX_SAMPLE_BUFFERS_SGIS: + config->nMultiSampleBuffers = value; + break; + + /* SGIX_pbuffer specific attributes */ + case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX: + config->optimalPbufferWidth = value; + break; + case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX: + config->optimalPbufferHeight = value; + break; + + default: + /* Ignore attributes we don't recognize */ + break; + } + } /* for j */ + + /* Fill in derived values */ + config->screen = screen; + + config->rgbMode = config->renderType & GLX_RGBA_BIT; + config->colorIndexMode = !config->rgbMode; + + config->haveAccumBuffer = + config->accumRedBits > 0 || + config->accumGreenBits > 0 || + config->accumBlueBits > 0; + /* Can't have alpha without color */ + + config->haveDepthBuffer = config->depthBits > 0; + config->haveStencilBuffer = config->stencilBits > 0; + + /* overlay visuals are not valid for now */ + if (!config->level) { + config++; + numValidConfigs++; + } + + } /* for i */ + UnlockDisplay(dpy); + + config = fbconfigs; + for (i=0; iassociatedVisualId != 0) { + XVisualInfo *vis, template; + int n; + + template.screen = screen; + template.visualid = config->associatedVisualId; + vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask, + &template, &n); + + if (vis != NULL) { + config->redMask = (GLuint)vis->red_mask; + config->greenMask = (GLuint)vis->green_mask; + config->blueMask = (GLuint)vis->blue_mask; + config->alphaMask = 0; /* XXX */ + free(vis); + } + } + + config++; + } /* for i */ + + XFree(attrs); + SyncHandle(); + + *nconfigs = numValidConfigs; + return fbconfigs; +} + +__GLXvisualConfig * +GetGLXVisualConfigsFromFBConfigs(__GLXFBConfig *fbconfigs, int nfbconfigs, + XVisualInfo *visuals, int nvisuals, + __GLXvisualConfig *glxConfigs, int nGlxConfigs, + int *nconfigs) +{ + __GLXvisualConfig *configs = NULL; + int i; + + if (!fbconfigs || !nfbconfigs || !nconfigs) return(NULL); + *nconfigs = 0; + + /* Allocate memory for our config structure */ + configs = (__GLXvisualConfig*) + Xmalloc(nfbconfigs * sizeof(__GLXvisualConfig)); + if (!configs) { + return NULL; + } + memset(configs, 0, nfbconfigs * sizeof(__GLXvisualConfig)); + + for (i=0; iassociatedVisualId > 0) { + __GLXvisualConfig *cfg = configs + (*nconfigs); + int j; + XVisualInfo *vinfo = NULL; + + for (j=0; jassociatedVisualId) { + vinfo = &visuals[j]; + break; + } + } + if (!vinfo) continue; + + /* skip 16 bit colormap visuals */ + if (vinfo->depth == 16 && + vinfo->class != TrueColor && + vinfo->class != DirectColor ) { + continue; + } + + (*nconfigs)++; + + /* + * if the same visualid exists in the glx configs, + * copy the glx attributes from the glx config + */ + for (j=0; jvisualid) + break; + } + if (j < nGlxConfigs) { + memcpy(cfg, &glxConfigs[j], sizeof(__GLXvisualConfig) ); + continue; + } + + /* + * make glx attributes from the FB config attributes + */ + cfg->vid = fbcfg->associatedVisualId; + cfg->class = vinfo->class; + cfg->rgba = !(fbcfg->renderType & GLX_COLOR_INDEX_BIT_SGIX); + cfg->redSize = fbcfg->redBits; + cfg->greenSize = fbcfg->greenBits; + cfg->blueSize = fbcfg->blueBits; + cfg->alphaSize = fbcfg->alphaBits; + cfg->redMask = fbcfg->redMask; + cfg->greenMask = fbcfg->greenMask; + cfg->blueMask = fbcfg->blueMask; + cfg->alphaMask = fbcfg->alphaMask; + cfg->accumRedSize = fbcfg->accumRedBits; + cfg->accumGreenSize = fbcfg->accumGreenBits; + cfg->accumBlueSize = fbcfg->accumBlueBits; + cfg->accumAlphaSize = fbcfg->accumAlphaBits; + cfg->doubleBuffer = fbcfg->doubleBufferMode; + cfg->stereo = fbcfg->stereoMode; + if (vinfo->class == TrueColor || vinfo->class == DirectColor) { + cfg->bufferSize = (fbcfg->rgbMode ? (fbcfg->redBits + + fbcfg->greenBits + + fbcfg->blueBits + + fbcfg->alphaBits) + : fbcfg->indexBits ); + } + else { + cfg->bufferSize = vinfo->depth; + } + cfg->depthSize = fbcfg->depthBits; + cfg->stencilSize = fbcfg->stencilBits; + cfg->auxBuffers = fbcfg->maxAuxBuffers; + cfg->level = fbcfg->level; + cfg->visualRating = fbcfg->visualCaveat; + cfg->transparentPixel = fbcfg->transparentType; + cfg->transparentRed = fbcfg->transparentRed; + cfg->transparentGreen = fbcfg->transparentGreen; + cfg->transparentBlue = fbcfg->transparentBlue; + cfg->transparentAlpha = fbcfg->transparentAlpha; + cfg->transparentIndex = fbcfg->transparentIndex; + cfg->multiSampleSize = fbcfg->multiSampleSize; + cfg->nMultiSampleBuffers = fbcfg->nMultiSampleBuffers; + cfg->visualSelectGroup = fbcfg->visualSelectGroup; + } + } + + return( configs ); +} + diff --git a/xorg-server/hw/dmx/dmxcmap.c b/xorg-server/hw/dmx/dmxcmap.c index 4aa586aff..5a56afda2 100644 --- a/xorg-server/hw/dmx/dmxcmap.c +++ b/xorg-server/hw/dmx/dmxcmap.c @@ -1,212 +1,212 @@ -/* - * Copyright 2001-2004 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: - * Kevin E. Martin - * - */ - -/** \file - * Colormap support. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxlog.h" -#include "dmxsync.h" -#include "dmxcmap.h" -#include "dmxvisual.h" - -#include "micmap.h" - -static Bool dmxAllocateColormapPrivates(ColormapPtr pColormap) -{ - dmxColormapPrivPtr pCmapPriv; - - pCmapPriv = (dmxColormapPrivPtr)xalloc(sizeof(*pCmapPriv)); - if (!pCmapPriv) - return FALSE; - pCmapPriv->cmap = (Colormap)0; - - DMX_SET_COLORMAP_PRIV(pColormap, pCmapPriv); - - return TRUE; -} - -/** Create \a pColormap on the back-end server. */ -Bool dmxBECreateColormap(ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); - VisualPtr pVisual = pColormap->pVisual; - Visual *visual = dmxLookupVisual(pScreen, pVisual); - - if (visual) { - pCmapPriv->cmap = XCreateColormap(dmxScreen->beDisplay, - dmxScreen->scrnWin, - visual, - (pVisual->class & DynamicClass ? - AllocAll : AllocNone)); - return (pCmapPriv->cmap != 0); - } - else { - dmxLog(dmxWarning, "dmxBECreateColormap: No visual found\n"); - return 0; - } -} - -/** Create colormap on back-end server associated with \a pColormap's - * screen. */ -Bool dmxCreateColormap(ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - - if (!dmxAllocateColormapPrivates(pColormap)) - return FALSE; - - if (dmxScreen->beDisplay) { - if (!dmxBECreateColormap(pColormap)) - return FALSE; - } - - DMX_UNWRAP(CreateColormap, dmxScreen, pScreen); - if (pScreen->CreateColormap) - ret = pScreen->CreateColormap(pColormap); - DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen); - - return ret; -} - -/** Destroy \a pColormap on the back-end server. */ -Bool dmxBEFreeColormap(ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); - - if (pCmapPriv->cmap) { - XFreeColormap(dmxScreen->beDisplay, pCmapPriv->cmap); - pCmapPriv->cmap = (Colormap)0; - return TRUE; - } - - return FALSE; -} - -/** Destroy colormap on back-end server associated with \a pColormap's - * screen. */ -void dmxDestroyColormap(ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); - - if (dmxScreen->beDisplay) - dmxBEFreeColormap(pColormap); - xfree(pCmapPriv); - DMX_SET_COLORMAP_PRIV(pColormap, NULL); - - DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen); - if (pScreen->DestroyColormap) - pScreen->DestroyColormap(pColormap); - DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen); -} - -/** Install colormap on back-end server associated with \a pColormap's - * screen. */ -void dmxInstallColormap(ColormapPtr pColormap) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); - - DMX_UNWRAP(InstallColormap, dmxScreen, pScreen); - if (pScreen->InstallColormap) - pScreen->InstallColormap(pColormap); - DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); - - if (dmxScreen->beDisplay) { - XInstallColormap(dmxScreen->beDisplay, pCmapPriv->cmap); - dmxSync(dmxScreen, FALSE); - } -} - -/** Store colors in \a pColormap on back-end server associated with \a - * pColormap's screen. */ -void dmxStoreColors(ColormapPtr pColormap, int ndef, xColorItem *pdef) -{ - ScreenPtr pScreen = pColormap->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); - - if (dmxScreen->beDisplay && (pColormap->pVisual->class & DynamicClass)) { - XColor *color = xalloc(sizeof(*color) * ndef); - int i; - - if (color) { - for (i = 0; i < ndef; i++) { - color[i].pixel = pdef[i].pixel; - color[i].red = pdef[i].red; - color[i].blue = pdef[i].blue; - color[i].green = pdef[i].green; - color[i].flags = pdef[i].flags; - color[i].pad = pdef[i].pad; - } - XStoreColors(dmxScreen->beDisplay, pCmapPriv->cmap, color, ndef); - xfree(color); - } else { /* xalloc failed, so fallback */ - XColor c; - for (i = 0; i < ndef; i++) { - c.pixel = pdef[i].pixel; - c.red = pdef[i].red; - c.blue = pdef[i].blue; - c.green = pdef[i].green; - c.flags = pdef[i].flags; - c.pad = pdef[i].pad; - XStoreColor(dmxScreen->beDisplay, pCmapPriv->cmap, &c); - } - } - dmxSync(dmxScreen, FALSE); - } - - DMX_UNWRAP(StoreColors, dmxScreen, pScreen); - if (pScreen->StoreColors) - pScreen->StoreColors(pColormap, ndef, pdef); - DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen); -} - -/** Create the DMX server's default colormap. */ -Bool dmxCreateDefColormap(ScreenPtr pScreen) -{ - return miCreateDefColormap(pScreen); -} +/* + * Copyright 2001-2004 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: + * Kevin E. Martin + * + */ + +/** \file + * Colormap support. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxlog.h" +#include "dmxsync.h" +#include "dmxcmap.h" +#include "dmxvisual.h" + +#include "micmap.h" + +static Bool dmxAllocateColormapPrivates(ColormapPtr pColormap) +{ + dmxColormapPrivPtr pCmapPriv; + + pCmapPriv = (dmxColormapPrivPtr)malloc(sizeof(*pCmapPriv)); + if (!pCmapPriv) + return FALSE; + pCmapPriv->cmap = (Colormap)0; + + DMX_SET_COLORMAP_PRIV(pColormap, pCmapPriv); + + return TRUE; +} + +/** Create \a pColormap on the back-end server. */ +Bool dmxBECreateColormap(ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); + VisualPtr pVisual = pColormap->pVisual; + Visual *visual = dmxLookupVisual(pScreen, pVisual); + + if (visual) { + pCmapPriv->cmap = XCreateColormap(dmxScreen->beDisplay, + dmxScreen->scrnWin, + visual, + (pVisual->class & DynamicClass ? + AllocAll : AllocNone)); + return (pCmapPriv->cmap != 0); + } + else { + dmxLog(dmxWarning, "dmxBECreateColormap: No visual found\n"); + return 0; + } +} + +/** Create colormap on back-end server associated with \a pColormap's + * screen. */ +Bool dmxCreateColormap(ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + + if (!dmxAllocateColormapPrivates(pColormap)) + return FALSE; + + if (dmxScreen->beDisplay) { + if (!dmxBECreateColormap(pColormap)) + return FALSE; + } + + DMX_UNWRAP(CreateColormap, dmxScreen, pScreen); + if (pScreen->CreateColormap) + ret = pScreen->CreateColormap(pColormap); + DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen); + + return ret; +} + +/** Destroy \a pColormap on the back-end server. */ +Bool dmxBEFreeColormap(ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); + + if (pCmapPriv->cmap) { + XFreeColormap(dmxScreen->beDisplay, pCmapPriv->cmap); + pCmapPriv->cmap = (Colormap)0; + return TRUE; + } + + return FALSE; +} + +/** Destroy colormap on back-end server associated with \a pColormap's + * screen. */ +void dmxDestroyColormap(ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); + + if (dmxScreen->beDisplay) + dmxBEFreeColormap(pColormap); + free(pCmapPriv); + DMX_SET_COLORMAP_PRIV(pColormap, NULL); + + DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen); + if (pScreen->DestroyColormap) + pScreen->DestroyColormap(pColormap); + DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen); +} + +/** Install colormap on back-end server associated with \a pColormap's + * screen. */ +void dmxInstallColormap(ColormapPtr pColormap) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); + + DMX_UNWRAP(InstallColormap, dmxScreen, pScreen); + if (pScreen->InstallColormap) + pScreen->InstallColormap(pColormap); + DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); + + if (dmxScreen->beDisplay) { + XInstallColormap(dmxScreen->beDisplay, pCmapPriv->cmap); + dmxSync(dmxScreen, FALSE); + } +} + +/** Store colors in \a pColormap on back-end server associated with \a + * pColormap's screen. */ +void dmxStoreColors(ColormapPtr pColormap, int ndef, xColorItem *pdef) +{ + ScreenPtr pScreen = pColormap->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxColormapPrivPtr pCmapPriv = DMX_GET_COLORMAP_PRIV(pColormap); + + if (dmxScreen->beDisplay && (pColormap->pVisual->class & DynamicClass)) { + XColor *color = malloc(sizeof(*color) * ndef); + int i; + + if (color) { + for (i = 0; i < ndef; i++) { + color[i].pixel = pdef[i].pixel; + color[i].red = pdef[i].red; + color[i].blue = pdef[i].blue; + color[i].green = pdef[i].green; + color[i].flags = pdef[i].flags; + color[i].pad = pdef[i].pad; + } + XStoreColors(dmxScreen->beDisplay, pCmapPriv->cmap, color, ndef); + free(color); + } else { /* xalloc failed, so fallback */ + XColor c; + for (i = 0; i < ndef; i++) { + c.pixel = pdef[i].pixel; + c.red = pdef[i].red; + c.blue = pdef[i].blue; + c.green = pdef[i].green; + c.flags = pdef[i].flags; + c.pad = pdef[i].pad; + XStoreColor(dmxScreen->beDisplay, pCmapPriv->cmap, &c); + } + } + dmxSync(dmxScreen, FALSE); + } + + DMX_UNWRAP(StoreColors, dmxScreen, pScreen); + if (pScreen->StoreColors) + pScreen->StoreColors(pColormap, ndef, pdef); + DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen); +} + +/** Create the DMX server's default colormap. */ +Bool dmxCreateDefColormap(ScreenPtr pScreen) +{ + return miCreateDefColormap(pScreen); +} diff --git a/xorg-server/hw/dmx/dmxcursor.c b/xorg-server/hw/dmx/dmxcursor.c index 37e66d758..2d0243343 100644 --- a/xorg-server/hw/dmx/dmxcursor.c +++ b/xorg-server/hw/dmx/dmxcursor.c @@ -1,985 +1,985 @@ -/* - * Copyright 2001-2004 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 - * Kevin E. Martin - * Rickard E. (Rik) Faith - * - */ - -/** \file - * This file contains code than supports cursor movement, including the - * code that initializes and reinitializes the screen positions and - * computes screen overlap. - * - * "This code is based very closely on the XFree86 equivalent - * (xfree86/common/xf86Cursor.c)." --David Dawes. - * - * "This code was then extensively re-written, as explained here." - * --Rik Faith - * - * The code in xf86Cursor.c used edge lists to implement the - * CursorOffScreen function. The edge list computation was complex - * (especially in the face of arbitrarily overlapping screens) compared - * with the speed savings in the CursorOffScreen function. The new - * implementation has erred on the side of correctness, readability, and - * maintainability over efficiency. For the common (non-edge) case, the - * dmxCursorOffScreen function does avoid a loop over all the screens. - * When the cursor has left the screen, all the screens are searched, - * and the first screen (in dmxScreens order) containing the cursor will - * be returned. If run-time profiling shows that this routing is a - * performance bottle-neck, then an edge list may have to be - * reimplemented. An edge list algorithm is O(edges) whereas the new - * algorithm is O(dmxNumScreens). Since edges is usually 1-3 and - * dmxNumScreens may be 30-60 for large backend walls, this trade off - * may be compelling. - * - * The xf86InitOrigins routine uses bit masks during the computation and - * is therefore limited to the length of a word (e.g., 32 or 64 bits) - * screens. Because Xdmx is expected to be used with a large number of - * backend displays, this limitation was removed. The new - * implementation has erred on the side of readability over efficiency, - * using the dmxSL* routines to manage a screen list instead of a - * bitmap, and a function call to decrease the length of the main - * routine. Both algorithms are of the same order, and both are called - * only at server generation time, so trading clarity and long-term - * maintainability for efficiency does not seem justified in this case. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#define DMX_CURSOR_DEBUG 0 - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxcursor.h" -#include "dmxlog.h" -#include "dmxprop.h" -#include "dmxinput.h" - -#include "mipointer.h" -#include "windowstr.h" -#include "globals.h" -#include "cursorstr.h" -#include "dixevents.h" /* For GetSpriteCursor() */ -#include "inputstr.h" /* for inputInfo.pointer */ - -#if DMX_CURSOR_DEBUG -#define DMXDBG0(f) dmxLog(dmxDebug,f) -#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) -#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) -#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) -#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) -#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) -#else -#define DMXDBG0(f) -#define DMXDBG1(f,a) -#define DMXDBG2(f,a,b) -#define DMXDBG3(f,a,b,c) -#define DMXDBG4(f,a,b,c,d) -#define DMXDBG5(f,a,b,c,d,e) -#define DMXDBG6(f,a,b,c,d,e,g) -#define DMXDBG7(f,a,b,c,d,e,g,h) -#endif - -static int dmxCursorDoMultiCursors = 1; - -/** Turn off support for displaying multiple cursors on overlapped - back-end displays. See #dmxCursorDoMultiCursors. */ -void dmxCursorNoMulti(void) -{ - dmxCursorDoMultiCursors = 0; -} - -static Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) -{ - DMXScreenInfo *dmxScreen; - int i; - int localX = *x; - int localY = *y; - int globalX; - int globalY; - - if (screenInfo.numScreens == 1) - return FALSE; - - /* On current screen? */ - dmxScreen = &dmxScreens[(*ppScreen)->myNum]; - if (localX >= 0 - && localX < dmxScreen->rootWidth - && localY >= 0 - && localY < dmxScreen->rootHeight) - return FALSE; - - /* Convert to global coordinate space */ - globalX = dmxScreen->rootXOrigin + localX; - globalY = dmxScreen->rootYOrigin + localY; - - /* Is cursor on the current screen? - * This efficiently exits this routine - * for the most common case. */ - if (ppScreen && *ppScreen) { - dmxScreen = &dmxScreens[(*ppScreen)->myNum]; - if (globalX >= dmxScreen->rootXOrigin - && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth - && globalY >= dmxScreen->rootYOrigin - && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) - return FALSE; - } - - /* Find first screen cursor is on */ - for (i = 0; i < dmxNumScreens; i++) { - dmxScreen = &dmxScreens[i]; - if (globalX >= dmxScreen->rootXOrigin - && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth - && globalY >= dmxScreen->rootYOrigin - && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) { - if (dmxScreen->index == (*ppScreen)->myNum) - return FALSE; - *ppScreen = screenInfo.screens[dmxScreen->index]; - *x = globalX - dmxScreen->rootXOrigin; - *y = globalY - dmxScreen->rootYOrigin; - return TRUE; - } - } - return FALSE; -} - -static void dmxCrossScreen(ScreenPtr pScreen, Bool entering) -{ -} - -static void dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y); -#if 11 /*BP*/ - /* This call is depracated. Replace with???? */ - miPointerWarpCursor(pDev, pScreen, x, y); -#else - pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE); -#endif -} - -miPointerScreenFuncRec dmxPointerCursorFuncs = -{ - dmxCursorOffScreen, - dmxCrossScreen, - dmxWarpCursor, - NULL, - NULL, -}; - - -/** Create a list of screens that we'll manipulate. */ -static int *dmxSLCreate(void) -{ - int *list = malloc(dmxNumScreens * sizeof(*list)); - int i; - - for (i = 0; i < dmxNumScreens; i++) - list[i] = 1; - return list; -} - -/** Free list. */ -static void dmxSLFree(int *list) -{ - free(list); -} - -/** Find next uninitialized entry in list. */ -static int dmxSLFindNext(int *list) -{ - int i; - for (i = 0; i < dmxNumScreens; i++) - if (list[i]) - return i; - return -1; -} - -/** Make one pass over all the screens and return the number updated. */ -static int dmxTryComputeScreenOrigins(int *screensLeft) -{ - ScreenPtr pScreen; - DMXScreenInfo *screen; - int i, ref; - int changed = 0; - - for (i = 0; i < dmxNumScreens; i++) { - if (!screensLeft[i]) - continue; - screen = &dmxScreens[i]; - switch (screen->where) { - case PosAbsolute: - dixScreenOrigins[i].x = screen->whereX; - dixScreenOrigins[i].y = screen->whereY; - ++changed, screensLeft[i] = 0; - break; - case PosRelative: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x + screen->whereX; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y + screen->whereY; - ++changed, screensLeft[i] = 0; - break; - case PosRightOf: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[ref]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x + pScreen->width; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y; - ++changed, screensLeft[i] = 0; - break; - case PosLeftOf: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[i]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x - pScreen->width; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y; - ++changed, screensLeft[i] = 0; - break; - case PosBelow: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[ref]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y + pScreen->height; - ++changed, screensLeft[i] = 0; - break; - case PosAbove: - ref = screen->whereRefScreen; - if (screensLeft[ref]) - break; - pScreen = screenInfo.screens[i]; - dixScreenOrigins[i].x = dixScreenOrigins[ref].x; - dixScreenOrigins[i].y = dixScreenOrigins[ref].y - pScreen->height; - ++changed, screensLeft[i] = 0; - break; - case PosNone: - dmxLog(dmxFatal, "No position information for screen %d\n", i); - } - } - return changed; -} - -static void dmxComputeScreenOrigins(void) -{ - int *screensLeft; - int i, ref; - int minX, minY; - - /* Compute origins based on - * configuration information. */ - screensLeft = dmxSLCreate(); - while ((i = dmxSLFindNext(screensLeft)) >= 0) { - while (dmxTryComputeScreenOrigins(screensLeft)); - if ((i = dmxSLFindNext(screensLeft)) >= 0) { - /* All of the remaining screens are referencing each other. - * Assign a value to one of them and go through again. This - * guarantees that we will eventually terminate. - */ - ref = dmxScreens[i].whereRefScreen; - dixScreenOrigins[ref].x = dixScreenOrigins[ref].y = 0; - screensLeft[ref] = 0; - } - } - dmxSLFree(screensLeft); - - - /* Justify the topmost and leftmost to - * (0,0). */ - minX = dixScreenOrigins[0].x; - minY = dixScreenOrigins[0].y; - for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */ - if (dixScreenOrigins[i].x < minX) - minX = dixScreenOrigins[i].x; - if (dixScreenOrigins[i].y < minY) - minY = dixScreenOrigins[i].y; - } - if (minX || minY) { - for (i = 0; i < dmxNumScreens; i++) { - dixScreenOrigins[i].x -= minX; - dixScreenOrigins[i].y -= minY; - } - } -} - -/** Recompute origin information in the #dmxScreens list. This is - * called from #dmxInitOrigins. */ -void dmxReInitOrigins(void) -{ - int i; - - if (dmxNumScreens > MAXSCREENS) - dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", - dmxNumScreens, MAXSCREENS); - - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - dmxLogOutput(dmxScreen, - "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d" - " (be=%dx%d depth=%d bpp=%d)\n", - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY, - - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - - dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, - dmxScreen->beWidth, dmxScreen->beHeight, - dmxScreen->beDepth, dmxScreen->beBPP); - } -} - -/** Initialize screen origins (and relative position). This is called - * for each server generation. For dynamic reconfiguration, use - * #dmxReInitOrigins() instead. */ -void dmxInitOrigins(void) -{ - int i; - - if (dmxNumScreens > MAXSCREENS) - dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", - dmxNumScreens, MAXSCREENS); - - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - dmxLogOutput(dmxScreen, - "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)" - " (be=%dx%d depth=%d bpp=%d)\n", - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY, - - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - - dmxScreen->whereX, dmxScreen->whereY, - dmxScreen->where, - - dmxScreen->beWidth, dmxScreen->beHeight, - dmxScreen->beDepth, dmxScreen->beBPP); - } - - dmxComputeScreenOrigins(); - - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - dmxScreen->rootXOrigin = dixScreenOrigins[i].x; - dmxScreen->rootYOrigin = dixScreenOrigins[i].y; - } - - dmxReInitOrigins(); -} - -/** Returns non-zero if the global \a x, \a y coordinate is on the - * screen window of the \a dmxScreen. */ -int dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen) -{ -#if DMX_CURSOR_DEBUG > 1 - dmxLog(dmxDebug, - "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n", - dmxScreen->index, x, y, - dmxScreen->rootWidth, dmxScreen->rootHeight, - dmxScreen->rootX, dmxScreen->rootY, - dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->scrnX, dmxScreen->scrnY); -#endif - if (x >= dmxScreen->rootXOrigin - && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth - && y >= dmxScreen->rootYOrigin - && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight) return 1; - return 0; -} - -/** Returns non-zero if \a a overlaps \a b. */ -static int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b) -{ - if (dmxOnScreen(a->rootXOrigin, - a->rootYOrigin, b)) - return 1; - - if (dmxOnScreen(a->rootXOrigin, - a->rootYOrigin + a->scrnWidth, b)) - return 1; - - if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, - a->rootYOrigin, b)) - return 1; - - if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, - a->rootYOrigin + a->scrnWidth, b)) - return 1; - - if (dmxOnScreen(b->rootXOrigin, - b->rootYOrigin, a)) - return 1; - - if (dmxOnScreen(b->rootXOrigin, - b->rootYOrigin + b->scrnWidth, a)) - return 1; - - if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, - b->rootYOrigin, a)) - return 1; - - if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, - b->rootYOrigin + b->scrnWidth, a)) - return 1; - - return 0; -} - -/** Used with \a dmxInterateOverlap to print out a list of screens which - * overlap each other. */ -static void *dmxPrintOverlap(DMXScreenInfo *dmxScreen, void *closure) -{ - DMXScreenInfo *a = closure; - if (dmxScreen != a) { - if (dmxScreen->cursorNotShared) - dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name); - else - dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name); - } - return NULL; -} - -/** Iterate over the screens which overlap with the \a start screen, - * calling \a f with the \a closure for each argument. Often used with - * #dmxPrintOverlap. */ -static void *dmxIterateOverlap(DMXScreenInfo *start, - void *(*f)(DMXScreenInfo *dmxScreen, void *), - void *closure) -{ - DMXScreenInfo *pt; - - if (!start->over) return f(start, closure); - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - void *retval; - if ((retval = f(pt, closure))) return retval; - if (pt == start) break; - } - return NULL; -} - -/** Used with #dmxPropertyIterate to determine if screen \a a is the - * same as the screen \a closure. */ -static void *dmxTestSameDisplay(DMXScreenInfo *a, void *closure) -{ - DMXScreenInfo *b = closure; - - if (a == b) - return a; - return NULL; -} - -/** Detects overlapping dmxScreens and creates circular lists. This - * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and - * the computation only needs to be performed for every server - * generation or dynamic reconfiguration . */ -void dmxInitOverlap(void) -{ - int i, j; - DMXScreenInfo *a, *b, *pt; - - for (i = 0; i < dmxNumScreens; i++) - dmxScreens[i].over = NULL; - - for (i = 0; i < dmxNumScreens; i++) { - a = &dmxScreens[i]; - - for (j = i+1; j < dmxNumScreens; j++) { - b = &dmxScreens[j]; - if (b->over) - continue; - - if (dmxDoesOverlap(a, b)) { - DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n", - a->index, b->index, a, a->over, b, b->over); - b->over = (a->over ? a->over : a); - a->over = b; - } - } - } - - for (i = 0; i < dmxNumScreens; i++) { - a = &dmxScreens[i]; - - if (!a->over) - continue; - - /* Flag all pairs that are on same display */ - for (pt = a->over; pt != a; pt = pt->over) { - if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) { - /* The ->over sets contain the transitive set of screens - * that overlap. For screens that are on the same - * backend display, we only want to exclude pairs of - * screens that mutually overlap on the backend display, - * so we call dmxDoesOverlap, which is stricter than the - * ->over set. */ - if (!dmxDoesOverlap(a, pt)) - continue; - a->cursorNotShared = 1; - pt->cursorNotShared = 1; - dmxLog(dmxInfo, - "Screen %d and %d overlap on %s\n", - a->index, pt->index, a->name); - } - } - } - - for (i = 0; i < dmxNumScreens; i++) { - a = &dmxScreens[i]; - - if (a->over) { - dmxLogOutput(a, "Overlaps"); - dmxIterateOverlap(a, dmxPrintOverlap, a); - dmxLogOutputCont(a, "\n"); - } - } -} - -/** Create \a pCursor on the back-end associated with \a pScreen. */ -void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - CursorBitsPtr pBits = pCursor->bits; - Pixmap src, msk; - XColor fg, bg; - XImage *img; - XlibGC gc = NULL; - XGCValues v; - unsigned long m; - int i; - - if (!pCursorPriv) - return; - - m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask; - v.function = GXcopy; - v.plane_mask = AllPlanes; - v.foreground = 1L; - v.background = 0L; - v.clip_mask = None; - - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { - if (dmxScreen->bePixmapFormats[i].depth == 1) { - /* Create GC in the back-end servers */ - gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i], - m, &v); - break; - } - } - if (!gc) - dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n"); - - src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, - pBits->width, pBits->height, 1); - msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, - pBits->width, pBits->height, 1); - - img = XCreateImage(dmxScreen->beDisplay, - dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, - 1, XYBitmap, 0, (char *)pBits->source, - pBits->width, pBits->height, - BitmapPad(dmxScreen->beDisplay), 0); - - XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0, - pBits->width, pBits->height); - - XFree(img); - - img = XCreateImage(dmxScreen->beDisplay, - dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, - 1, XYBitmap, 0, (char *)pBits->mask, - pBits->width, pBits->height, - BitmapPad(dmxScreen->beDisplay), 0); - - XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0, - pBits->width, pBits->height); - - XFree(img); - - fg.red = pCursor->foreRed; - fg.green = pCursor->foreGreen; - fg.blue = pCursor->foreBlue; - - bg.red = pCursor->backRed; - bg.green = pCursor->backGreen; - bg.blue = pCursor->backBlue; - - pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay, - src, msk, - &fg, &bg, - pBits->xhot, pBits->yhot); - - XFreePixmap(dmxScreen->beDisplay, src); - XFreePixmap(dmxScreen->beDisplay, msk); - XFreeGC(dmxScreen->beDisplay, gc); - - dmxSync(dmxScreen, FALSE); -} - -static Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxCursorPrivPtr pCursorPriv; - - DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor); - - DMX_SET_CURSOR_PRIV(pCursor, pScreen, xalloc(sizeof(*pCursorPriv))); - if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen)) - return FALSE; - - pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - pCursorPriv->cursor = (Cursor)0; - - if (!dmxScreen->beDisplay) - return TRUE; - - dmxBECreateCursor(pScreen, pCursor); - return TRUE; -} - -/** Free \a pCursor on the back-end associated with \a pScreen. */ -Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - - if (pCursorPriv) { - XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor); - pCursorPriv->cursor = (Cursor)0; - return TRUE; - } - - return FALSE; -} - -static Bool _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n", - pScreen->myNum, pCursor); - - if (dmxScreen->beDisplay) { - if (dmxBEFreeCursor(pScreen, pCursor)) - xfree(DMX_GET_CURSOR_PRIV(pCursor, pScreen)); - } - DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL); - - return TRUE; -} - -static void _dmxMoveCursor(ScreenPtr pScreen, int x, int y) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - int newX = x + dmxScreen->rootX; - int newY = y + dmxScreen->rootY; - - if (newX < 0) newX = 0; - if (newY < 0) newY = 0; - - DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n", - pScreen->myNum, x, y, newX, newY); - if (dmxScreen->beDisplay) { - XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin, - 0, 0, 0, 0, newX, newY); - dmxSync(dmxScreen, TRUE); - } -} - -static void _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y); - - if (pCursor) { - dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); - if (pCursorPriv && dmxScreen->curCursor != pCursorPriv->cursor) { - if (dmxScreen->beDisplay) - XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, - pCursorPriv->cursor); - dmxScreen->cursor = pCursor; - dmxScreen->curCursor = pCursorPriv->cursor; - dmxScreen->cursorVisible = 1; - } - _dmxMoveCursor(pScreen, x, y); - } else { - if (dmxScreen->beDisplay) - XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, - dmxScreen->noCursor); - dmxScreen->cursor = NULL; - dmxScreen->curCursor = (Cursor)0; - dmxScreen->cursorVisible = 0; - } - if (dmxScreen->beDisplay) dmxSync(dmxScreen, TRUE); -} - -static Bool dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) - return _dmxRealizeCursor(pScreen, pCursor); - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor); - if (pt == start) - break; - } - return TRUE; -} - -static Bool dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) -{ - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) - return _dmxUnrealizeCursor(pScreen, pCursor); - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor); - if (pt == start) - break; - } - return TRUE; -} - -static CursorPtr dmxFindCursor(DMXScreenInfo *start) -{ - DMXScreenInfo *pt; - - if (!start || !start->over) - return GetSpriteCursor(inputInfo.pointer); - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursor) - return pt->cursor; - if (pt == start) - break; - } - return GetSpriteCursor(inputInfo.pointer); -} - -/** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This - * function is usually called via #dmxPointerSpriteFuncs, except during - * reconfiguration when the cursor is repositioned to force an update on - * newley overlapping screens and on screens that no longer overlap. - * - * The coords (x,y) are in global coord space. We'll loop over the - * back-end screens and see if they contain the global coord. If so, call - * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen. - */ -void dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - - DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y); - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { - _dmxMoveCursor(pScreen, x, y); - return; - } - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { - if (/* pt != start && */ !pt->cursorVisible) { - if (!pt->cursor) { - /* This only happens during - * reconfiguration when a new overlap - * occurs. */ - CursorPtr pCursor; - - if ((pCursor = dmxFindCursor(start))) - _dmxRealizeCursor(screenInfo.screens[pt->index], - pt->cursor = pCursor); - - } - _dmxSetCursor(screenInfo.screens[pt->index], - pt->cursor, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } - _dmxMoveCursor(screenInfo.screens[pt->index], - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } else if (/* pt != start && */ pt->cursorVisible) { - _dmxSetCursor(screenInfo.screens[pt->index], - NULL, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } - if (pt == start) - break; - } -} - -static void dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) -{ - DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; - DMXScreenInfo *pt; - int GX, GY, gx, gy; - - DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n", - pScreen->myNum, start, pCursor, x, y); - - /* We do this check here because of two cases: - * - * 1) if a client calls XWarpPointer() - * and Xinerama is not running, we can - * have mi's notion of the pointer - * position out of phase with DMX's - * notion. - * - * 2) if a down button is held while the - * cursor moves outside the root window, - * mi's notion of the pointer position - * is out of phase with DMX's notion and - * the cursor can remain visible when it - * shouldn't be. */ - - dmxGetGlobalPosition(&GX, &GY); - gx = start->rootXOrigin + x; - gy = start->rootYOrigin + y; - if (x && y && (GX != gx || GY != gy)) - dmxCoreMotion(NULL, gx, gy, 0, DMX_NO_BLOCK); - - if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { - _dmxSetCursor(pScreen, pCursor, x, y); - return; - } - - for (pt = start->over; /* condition at end of loop */; pt = pt->over) { - if (pt->cursorNotShared) - continue; - if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { - _dmxSetCursor(screenInfo.screens[pt->index], pCursor, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } else { - _dmxSetCursor(screenInfo.screens[pt->index], NULL, - x + start->rootXOrigin - pt->rootXOrigin, - y + start->rootYOrigin - pt->rootYOrigin); - } - if (pt == start) - break; - } -} - - -/** This routine is used by the backend input routines to hide the - * cursor on a screen that is being used for relative input. \see - * dmxbackend.c */ -void dmxHideCursor(DMXScreenInfo *dmxScreen) -{ - int x, y; - ScreenPtr pScreen = screenInfo.screens[dmxScreen->index]; - - dmxGetGlobalPosition(&x, &y); - _dmxSetCursor(pScreen, NULL, x, y); -} - -/** This routine is called during reconfiguration to make sure the - * cursor is visible. */ -void dmxCheckCursor(void) -{ - int i; - int x, y; - ScreenPtr pScreen; - DMXScreenInfo *firstScreen; - - dmxGetGlobalPosition(&x, &y); - firstScreen = dmxFindFirstScreen(x, y); - - DMXDBG2("dmxCheckCursor %d %d\n", x, y); - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - pScreen = screenInfo.screens[dmxScreen->index]; - - if (!dmxOnScreen(x, y, dmxScreen)) { - if (firstScreen && i == miPointerGetScreen(inputInfo.pointer)->myNum) - miPointerSetScreen(inputInfo.pointer, firstScreen->index, x, y); - _dmxSetCursor(pScreen, NULL, - x - dmxScreen->rootXOrigin, - y - dmxScreen->rootYOrigin); - } else { - if (!dmxScreen->cursor) { - CursorPtr pCursor; - - if ((pCursor = dmxFindCursor(dmxScreen))) { - _dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor); - } - } - _dmxSetCursor(pScreen, dmxScreen->cursor, - x - dmxScreen->rootXOrigin, - y - dmxScreen->rootYOrigin); - } - } - DMXDBG2(" leave dmxCheckCursor %d %d\n", x, y); -} - -static Bool dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr) -{ - return TRUE; -} - -static void dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr) -{ -} - -miPointerSpriteFuncRec dmxPointerSpriteFuncs = -{ - dmxRealizeCursor, - dmxUnrealizeCursor, - dmxSetCursor, - dmxMoveCursor, - dmxDeviceCursorInitialize, - dmxDeviceCursorCleanup -}; +/* + * Copyright 2001-2004 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 + * Kevin E. Martin + * Rickard E. (Rik) Faith + * + */ + +/** \file + * This file contains code than supports cursor movement, including the + * code that initializes and reinitializes the screen positions and + * computes screen overlap. + * + * "This code is based very closely on the XFree86 equivalent + * (xfree86/common/xf86Cursor.c)." --David Dawes. + * + * "This code was then extensively re-written, as explained here." + * --Rik Faith + * + * The code in xf86Cursor.c used edge lists to implement the + * CursorOffScreen function. The edge list computation was complex + * (especially in the face of arbitrarily overlapping screens) compared + * with the speed savings in the CursorOffScreen function. The new + * implementation has erred on the side of correctness, readability, and + * maintainability over efficiency. For the common (non-edge) case, the + * dmxCursorOffScreen function does avoid a loop over all the screens. + * When the cursor has left the screen, all the screens are searched, + * and the first screen (in dmxScreens order) containing the cursor will + * be returned. If run-time profiling shows that this routing is a + * performance bottle-neck, then an edge list may have to be + * reimplemented. An edge list algorithm is O(edges) whereas the new + * algorithm is O(dmxNumScreens). Since edges is usually 1-3 and + * dmxNumScreens may be 30-60 for large backend walls, this trade off + * may be compelling. + * + * The xf86InitOrigins routine uses bit masks during the computation and + * is therefore limited to the length of a word (e.g., 32 or 64 bits) + * screens. Because Xdmx is expected to be used with a large number of + * backend displays, this limitation was removed. The new + * implementation has erred on the side of readability over efficiency, + * using the dmxSL* routines to manage a screen list instead of a + * bitmap, and a function call to decrease the length of the main + * routine. Both algorithms are of the same order, and both are called + * only at server generation time, so trading clarity and long-term + * maintainability for efficiency does not seem justified in this case. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#define DMX_CURSOR_DEBUG 0 + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxcursor.h" +#include "dmxlog.h" +#include "dmxprop.h" +#include "dmxinput.h" + +#include "mipointer.h" +#include "windowstr.h" +#include "globals.h" +#include "cursorstr.h" +#include "dixevents.h" /* For GetSpriteCursor() */ +#include "inputstr.h" /* for inputInfo.pointer */ + +#if DMX_CURSOR_DEBUG +#define DMXDBG0(f) dmxLog(dmxDebug,f) +#define DMXDBG1(f,a) dmxLog(dmxDebug,f,a) +#define DMXDBG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define DMXDBG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define DMXDBG4(f,a,b,c,d) dmxLog(dmxDebug,f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) dmxLog(dmxDebug,f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) dmxLog(dmxDebug,f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) dmxLog(dmxDebug,f,a,b,c,d,e,g,h) +#else +#define DMXDBG0(f) +#define DMXDBG1(f,a) +#define DMXDBG2(f,a,b) +#define DMXDBG3(f,a,b,c) +#define DMXDBG4(f,a,b,c,d) +#define DMXDBG5(f,a,b,c,d,e) +#define DMXDBG6(f,a,b,c,d,e,g) +#define DMXDBG7(f,a,b,c,d,e,g,h) +#endif + +static int dmxCursorDoMultiCursors = 1; + +/** Turn off support for displaying multiple cursors on overlapped + back-end displays. See #dmxCursorDoMultiCursors. */ +void dmxCursorNoMulti(void) +{ + dmxCursorDoMultiCursors = 0; +} + +static Bool dmxCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) +{ + DMXScreenInfo *dmxScreen; + int i; + int localX = *x; + int localY = *y; + int globalX; + int globalY; + + if (screenInfo.numScreens == 1) + return FALSE; + + /* On current screen? */ + dmxScreen = &dmxScreens[(*ppScreen)->myNum]; + if (localX >= 0 + && localX < dmxScreen->rootWidth + && localY >= 0 + && localY < dmxScreen->rootHeight) + return FALSE; + + /* Convert to global coordinate space */ + globalX = dmxScreen->rootXOrigin + localX; + globalY = dmxScreen->rootYOrigin + localY; + + /* Is cursor on the current screen? + * This efficiently exits this routine + * for the most common case. */ + if (ppScreen && *ppScreen) { + dmxScreen = &dmxScreens[(*ppScreen)->myNum]; + if (globalX >= dmxScreen->rootXOrigin + && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth + && globalY >= dmxScreen->rootYOrigin + && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) + return FALSE; + } + + /* Find first screen cursor is on */ + for (i = 0; i < dmxNumScreens; i++) { + dmxScreen = &dmxScreens[i]; + if (globalX >= dmxScreen->rootXOrigin + && globalX < dmxScreen->rootXOrigin + dmxScreen->rootWidth + && globalY >= dmxScreen->rootYOrigin + && globalY < dmxScreen->rootYOrigin + dmxScreen->rootHeight) { + if (dmxScreen->index == (*ppScreen)->myNum) + return FALSE; + *ppScreen = screenInfo.screens[dmxScreen->index]; + *x = globalX - dmxScreen->rootXOrigin; + *y = globalY - dmxScreen->rootYOrigin; + return TRUE; + } + } + return FALSE; +} + +static void dmxCrossScreen(ScreenPtr pScreen, Bool entering) +{ +} + +static void dmxWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + DMXDBG3("dmxWarpCursor(%d,%d,%d)\n", pScreen->myNum, x, y); +#if 11 /*BP*/ + /* This call is depracated. Replace with???? */ + miPointerWarpCursor(pDev, pScreen, x, y); +#else + pScreen->SetCursorPosition(pDev, pScreen, x, y, FALSE); +#endif +} + +miPointerScreenFuncRec dmxPointerCursorFuncs = +{ + dmxCursorOffScreen, + dmxCrossScreen, + dmxWarpCursor, + NULL, + NULL, +}; + + +/** Create a list of screens that we'll manipulate. */ +static int *dmxSLCreate(void) +{ + int *list = malloc(dmxNumScreens * sizeof(*list)); + int i; + + for (i = 0; i < dmxNumScreens; i++) + list[i] = 1; + return list; +} + +/** Free list. */ +static void dmxSLFree(int *list) +{ + free(list); +} + +/** Find next uninitialized entry in list. */ +static int dmxSLFindNext(int *list) +{ + int i; + for (i = 0; i < dmxNumScreens; i++) + if (list[i]) + return i; + return -1; +} + +/** Make one pass over all the screens and return the number updated. */ +static int dmxTryComputeScreenOrigins(int *screensLeft) +{ + ScreenPtr pScreen; + DMXScreenInfo *screen; + int i, ref; + int changed = 0; + + for (i = 0; i < dmxNumScreens; i++) { + if (!screensLeft[i]) + continue; + screen = &dmxScreens[i]; + switch (screen->where) { + case PosAbsolute: + dixScreenOrigins[i].x = screen->whereX; + dixScreenOrigins[i].y = screen->whereY; + ++changed, screensLeft[i] = 0; + break; + case PosRelative: + ref = screen->whereRefScreen; + if (screensLeft[ref]) + break; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x + screen->whereX; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y + screen->whereY; + ++changed, screensLeft[i] = 0; + break; + case PosRightOf: + ref = screen->whereRefScreen; + if (screensLeft[ref]) + break; + pScreen = screenInfo.screens[ref]; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x + pScreen->width; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y; + ++changed, screensLeft[i] = 0; + break; + case PosLeftOf: + ref = screen->whereRefScreen; + if (screensLeft[ref]) + break; + pScreen = screenInfo.screens[i]; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x - pScreen->width; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y; + ++changed, screensLeft[i] = 0; + break; + case PosBelow: + ref = screen->whereRefScreen; + if (screensLeft[ref]) + break; + pScreen = screenInfo.screens[ref]; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y + pScreen->height; + ++changed, screensLeft[i] = 0; + break; + case PosAbove: + ref = screen->whereRefScreen; + if (screensLeft[ref]) + break; + pScreen = screenInfo.screens[i]; + dixScreenOrigins[i].x = dixScreenOrigins[ref].x; + dixScreenOrigins[i].y = dixScreenOrigins[ref].y - pScreen->height; + ++changed, screensLeft[i] = 0; + break; + case PosNone: + dmxLog(dmxFatal, "No position information for screen %d\n", i); + } + } + return changed; +} + +static void dmxComputeScreenOrigins(void) +{ + int *screensLeft; + int i, ref; + int minX, minY; + + /* Compute origins based on + * configuration information. */ + screensLeft = dmxSLCreate(); + while ((i = dmxSLFindNext(screensLeft)) >= 0) { + while (dmxTryComputeScreenOrigins(screensLeft)); + if ((i = dmxSLFindNext(screensLeft)) >= 0) { + /* All of the remaining screens are referencing each other. + * Assign a value to one of them and go through again. This + * guarantees that we will eventually terminate. + */ + ref = dmxScreens[i].whereRefScreen; + dixScreenOrigins[ref].x = dixScreenOrigins[ref].y = 0; + screensLeft[ref] = 0; + } + } + dmxSLFree(screensLeft); + + + /* Justify the topmost and leftmost to + * (0,0). */ + minX = dixScreenOrigins[0].x; + minY = dixScreenOrigins[0].y; + for (i = 1; i < dmxNumScreens; i++) { /* Compute minX, minY */ + if (dixScreenOrigins[i].x < minX) + minX = dixScreenOrigins[i].x; + if (dixScreenOrigins[i].y < minY) + minY = dixScreenOrigins[i].y; + } + if (minX || minY) { + for (i = 0; i < dmxNumScreens; i++) { + dixScreenOrigins[i].x -= minX; + dixScreenOrigins[i].y -= minY; + } + } +} + +/** Recompute origin information in the #dmxScreens list. This is + * called from #dmxInitOrigins. */ +void dmxReInitOrigins(void) +{ + int i; + + if (dmxNumScreens > MAXSCREENS) + dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", + dmxNumScreens, MAXSCREENS); + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + dmxLogOutput(dmxScreen, + "s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d" + " (be=%dx%d depth=%d bpp=%d)\n", + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY, + + dmxScreen->rootWidth, dmxScreen->rootHeight, + dmxScreen->rootX, dmxScreen->rootY, + + dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, + dmxScreen->beWidth, dmxScreen->beHeight, + dmxScreen->beDepth, dmxScreen->beBPP); + } +} + +/** Initialize screen origins (and relative position). This is called + * for each server generation. For dynamic reconfiguration, use + * #dmxReInitOrigins() instead. */ +void dmxInitOrigins(void) +{ + int i; + + if (dmxNumScreens > MAXSCREENS) + dmxLog(dmxFatal, "dmxNumScreens = %d > MAXSCREENS = %d\n", + dmxNumScreens, MAXSCREENS); + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + dmxLogOutput(dmxScreen, + "(request) s=%dx%d%+d%+d r=%dx%d%+d%+d @%d,%d (%d)" + " (be=%dx%d depth=%d bpp=%d)\n", + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY, + + dmxScreen->rootWidth, dmxScreen->rootHeight, + dmxScreen->rootX, dmxScreen->rootY, + + dmxScreen->whereX, dmxScreen->whereY, + dmxScreen->where, + + dmxScreen->beWidth, dmxScreen->beHeight, + dmxScreen->beDepth, dmxScreen->beBPP); + } + + dmxComputeScreenOrigins(); + + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + dmxScreen->rootXOrigin = dixScreenOrigins[i].x; + dmxScreen->rootYOrigin = dixScreenOrigins[i].y; + } + + dmxReInitOrigins(); +} + +/** Returns non-zero if the global \a x, \a y coordinate is on the + * screen window of the \a dmxScreen. */ +int dmxOnScreen(int x, int y, DMXScreenInfo *dmxScreen) +{ +#if DMX_CURSOR_DEBUG > 1 + dmxLog(dmxDebug, + "dmxOnScreen %d %d,%d (r=%dx%d%+d%+d@%d,%d s=%dx%d%+d%+d)\n", + dmxScreen->index, x, y, + dmxScreen->rootWidth, dmxScreen->rootHeight, + dmxScreen->rootX, dmxScreen->rootY, + dmxScreen->rootXOrigin, dmxScreen->rootYOrigin, + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->scrnX, dmxScreen->scrnY); +#endif + if (x >= dmxScreen->rootXOrigin + && x < dmxScreen->rootXOrigin + dmxScreen->rootWidth + && y >= dmxScreen->rootYOrigin + && y < dmxScreen->rootYOrigin + dmxScreen->rootHeight) return 1; + return 0; +} + +/** Returns non-zero if \a a overlaps \a b. */ +static int dmxDoesOverlap(DMXScreenInfo *a, DMXScreenInfo *b) +{ + if (dmxOnScreen(a->rootXOrigin, + a->rootYOrigin, b)) + return 1; + + if (dmxOnScreen(a->rootXOrigin, + a->rootYOrigin + a->scrnWidth, b)) + return 1; + + if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, + a->rootYOrigin, b)) + return 1; + + if (dmxOnScreen(a->rootXOrigin + a->scrnHeight, + a->rootYOrigin + a->scrnWidth, b)) + return 1; + + if (dmxOnScreen(b->rootXOrigin, + b->rootYOrigin, a)) + return 1; + + if (dmxOnScreen(b->rootXOrigin, + b->rootYOrigin + b->scrnWidth, a)) + return 1; + + if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, + b->rootYOrigin, a)) + return 1; + + if (dmxOnScreen(b->rootXOrigin + b->scrnHeight, + b->rootYOrigin + b->scrnWidth, a)) + return 1; + + return 0; +} + +/** Used with \a dmxInterateOverlap to print out a list of screens which + * overlap each other. */ +static void *dmxPrintOverlap(DMXScreenInfo *dmxScreen, void *closure) +{ + DMXScreenInfo *a = closure; + if (dmxScreen != a) { + if (dmxScreen->cursorNotShared) + dmxLogOutputCont(a, " [%d/%s]", dmxScreen->index, dmxScreen->name); + else + dmxLogOutputCont(a, " %d/%s", dmxScreen->index, dmxScreen->name); + } + return NULL; +} + +/** Iterate over the screens which overlap with the \a start screen, + * calling \a f with the \a closure for each argument. Often used with + * #dmxPrintOverlap. */ +static void *dmxIterateOverlap(DMXScreenInfo *start, + void *(*f)(DMXScreenInfo *dmxScreen, void *), + void *closure) +{ + DMXScreenInfo *pt; + + if (!start->over) return f(start, closure); + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + void *retval; + if ((retval = f(pt, closure))) return retval; + if (pt == start) break; + } + return NULL; +} + +/** Used with #dmxPropertyIterate to determine if screen \a a is the + * same as the screen \a closure. */ +static void *dmxTestSameDisplay(DMXScreenInfo *a, void *closure) +{ + DMXScreenInfo *b = closure; + + if (a == b) + return a; + return NULL; +} + +/** Detects overlapping dmxScreens and creates circular lists. This + * uses an O(dmxNumScreens^2) algorithm, but dmxNumScreens is < 100 and + * the computation only needs to be performed for every server + * generation or dynamic reconfiguration . */ +void dmxInitOverlap(void) +{ + int i, j; + DMXScreenInfo *a, *b, *pt; + + for (i = 0; i < dmxNumScreens; i++) + dmxScreens[i].over = NULL; + + for (i = 0; i < dmxNumScreens; i++) { + a = &dmxScreens[i]; + + for (j = i+1; j < dmxNumScreens; j++) { + b = &dmxScreens[j]; + if (b->over) + continue; + + if (dmxDoesOverlap(a, b)) { + DMXDBG6("%d overlaps %d: a=%p %p b=%p %p\n", + a->index, b->index, a, a->over, b, b->over); + b->over = (a->over ? a->over : a); + a->over = b; + } + } + } + + for (i = 0; i < dmxNumScreens; i++) { + a = &dmxScreens[i]; + + if (!a->over) + continue; + + /* Flag all pairs that are on same display */ + for (pt = a->over; pt != a; pt = pt->over) { + if (dmxPropertyIterate(a, dmxTestSameDisplay, pt)) { + /* The ->over sets contain the transitive set of screens + * that overlap. For screens that are on the same + * backend display, we only want to exclude pairs of + * screens that mutually overlap on the backend display, + * so we call dmxDoesOverlap, which is stricter than the + * ->over set. */ + if (!dmxDoesOverlap(a, pt)) + continue; + a->cursorNotShared = 1; + pt->cursorNotShared = 1; + dmxLog(dmxInfo, + "Screen %d and %d overlap on %s\n", + a->index, pt->index, a->name); + } + } + } + + for (i = 0; i < dmxNumScreens; i++) { + a = &dmxScreens[i]; + + if (a->over) { + dmxLogOutput(a, "Overlaps"); + dmxIterateOverlap(a, dmxPrintOverlap, a); + dmxLogOutputCont(a, "\n"); + } + } +} + +/** Create \a pCursor on the back-end associated with \a pScreen. */ +void dmxBECreateCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); + CursorBitsPtr pBits = pCursor->bits; + Pixmap src, msk; + XColor fg, bg; + XImage *img; + XlibGC gc = NULL; + XGCValues v; + unsigned long m; + int i; + + if (!pCursorPriv) + return; + + m = GCFunction | GCPlaneMask | GCForeground | GCBackground | GCClipMask; + v.function = GXcopy; + v.plane_mask = AllPlanes; + v.foreground = 1L; + v.background = 0L; + v.clip_mask = None; + + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + if (dmxScreen->bePixmapFormats[i].depth == 1) { + /* Create GC in the back-end servers */ + gc = XCreateGC(dmxScreen->beDisplay, dmxScreen->scrnDefDrawables[i], + m, &v); + break; + } + } + if (!gc) + dmxLog(dmxFatal, "dmxRealizeCursor: gc not initialized\n"); + + src = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, + pBits->width, pBits->height, 1); + msk = XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, + pBits->width, pBits->height, 1); + + img = XCreateImage(dmxScreen->beDisplay, + dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, + 1, XYBitmap, 0, (char *)pBits->source, + pBits->width, pBits->height, + BitmapPad(dmxScreen->beDisplay), 0); + + XPutImage(dmxScreen->beDisplay, src, gc, img, 0, 0, 0, 0, + pBits->width, pBits->height); + + XFree(img); + + img = XCreateImage(dmxScreen->beDisplay, + dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, + 1, XYBitmap, 0, (char *)pBits->mask, + pBits->width, pBits->height, + BitmapPad(dmxScreen->beDisplay), 0); + + XPutImage(dmxScreen->beDisplay, msk, gc, img, 0, 0, 0, 0, + pBits->width, pBits->height); + + XFree(img); + + fg.red = pCursor->foreRed; + fg.green = pCursor->foreGreen; + fg.blue = pCursor->foreBlue; + + bg.red = pCursor->backRed; + bg.green = pCursor->backGreen; + bg.blue = pCursor->backBlue; + + pCursorPriv->cursor = XCreatePixmapCursor(dmxScreen->beDisplay, + src, msk, + &fg, &bg, + pBits->xhot, pBits->yhot); + + XFreePixmap(dmxScreen->beDisplay, src); + XFreePixmap(dmxScreen->beDisplay, msk); + XFreeGC(dmxScreen->beDisplay, gc); + + dmxSync(dmxScreen, FALSE); +} + +static Bool _dmxRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxCursorPrivPtr pCursorPriv; + + DMXDBG2("_dmxRealizeCursor(%d,%p)\n", pScreen->myNum, pCursor); + + DMX_SET_CURSOR_PRIV(pCursor, pScreen, malloc(sizeof(*pCursorPriv))); + if (!DMX_GET_CURSOR_PRIV(pCursor, pScreen)) + return FALSE; + + pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); + pCursorPriv->cursor = (Cursor)0; + + if (!dmxScreen->beDisplay) + return TRUE; + + dmxBECreateCursor(pScreen, pCursor); + return TRUE; +} + +/** Free \a pCursor on the back-end associated with \a pScreen. */ +Bool dmxBEFreeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); + + if (pCursorPriv) { + XFreeCursor(dmxScreen->beDisplay, pCursorPriv->cursor); + pCursorPriv->cursor = (Cursor)0; + return TRUE; + } + + return FALSE; +} + +static Bool _dmxUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + DMXDBG2("_dmxUnrealizeCursor(%d,%p)\n", + pScreen->myNum, pCursor); + + if (dmxScreen->beDisplay) { + if (dmxBEFreeCursor(pScreen, pCursor)) + free(DMX_GET_CURSOR_PRIV(pCursor, pScreen)); + } + DMX_SET_CURSOR_PRIV(pCursor, pScreen, NULL); + + return TRUE; +} + +static void _dmxMoveCursor(ScreenPtr pScreen, int x, int y) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int newX = x + dmxScreen->rootX; + int newY = y + dmxScreen->rootY; + + if (newX < 0) newX = 0; + if (newY < 0) newY = 0; + + DMXDBG5("_dmxMoveCursor(%d,%d,%d) -> %d,%d\n", + pScreen->myNum, x, y, newX, newY); + if (dmxScreen->beDisplay) { + XWarpPointer(dmxScreen->beDisplay, None, dmxScreen->scrnWin, + 0, 0, 0, 0, newX, newY); + dmxSync(dmxScreen, TRUE); + } +} + +static void _dmxSetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + DMXDBG4("_dmxSetCursor(%d,%p,%d,%d)\n", pScreen->myNum, pCursor, x, y); + + if (pCursor) { + dmxCursorPrivPtr pCursorPriv = DMX_GET_CURSOR_PRIV(pCursor, pScreen); + if (pCursorPriv && dmxScreen->curCursor != pCursorPriv->cursor) { + if (dmxScreen->beDisplay) + XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, + pCursorPriv->cursor); + dmxScreen->cursor = pCursor; + dmxScreen->curCursor = pCursorPriv->cursor; + dmxScreen->cursorVisible = 1; + } + _dmxMoveCursor(pScreen, x, y); + } else { + if (dmxScreen->beDisplay) + XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, + dmxScreen->noCursor); + dmxScreen->cursor = NULL; + dmxScreen->curCursor = (Cursor)0; + dmxScreen->cursorVisible = 0; + } + if (dmxScreen->beDisplay) dmxSync(dmxScreen, TRUE); +} + +static Bool dmxRealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; + DMXScreenInfo *pt; + + if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) + return _dmxRealizeCursor(pScreen, pCursor); + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->cursorNotShared) + continue; + _dmxRealizeCursor(screenInfo.screens[pt->index], pCursor); + if (pt == start) + break; + } + return TRUE; +} + +static Bool dmxUnrealizeCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor) +{ + DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; + DMXScreenInfo *pt; + + if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) + return _dmxUnrealizeCursor(pScreen, pCursor); + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->cursorNotShared) + continue; + _dmxUnrealizeCursor(screenInfo.screens[pt->index], pCursor); + if (pt == start) + break; + } + return TRUE; +} + +static CursorPtr dmxFindCursor(DMXScreenInfo *start) +{ + DMXScreenInfo *pt; + + if (!start || !start->over) + return GetSpriteCursor(inputInfo.pointer); + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->cursor) + return pt->cursor; + if (pt == start) + break; + } + return GetSpriteCursor(inputInfo.pointer); +} + +/** Move the cursor to coordinates (\a x, \a y)on \a pScreen. This + * function is usually called via #dmxPointerSpriteFuncs, except during + * reconfiguration when the cursor is repositioned to force an update on + * newley overlapping screens and on screens that no longer overlap. + * + * The coords (x,y) are in global coord space. We'll loop over the + * back-end screens and see if they contain the global coord. If so, call + * _dmxMoveCursor() (XWarpPointer) to position the pointer on that screen. + */ +void dmxMoveCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; + DMXScreenInfo *pt; + + DMXDBG3("dmxMoveCursor(%d,%d,%d)\n", pScreen->myNum, x, y); + + if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { + _dmxMoveCursor(pScreen, x, y); + return; + } + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->cursorNotShared) + continue; + if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { + if (/* pt != start && */ !pt->cursorVisible) { + if (!pt->cursor) { + /* This only happens during + * reconfiguration when a new overlap + * occurs. */ + CursorPtr pCursor; + + if ((pCursor = dmxFindCursor(start))) + _dmxRealizeCursor(screenInfo.screens[pt->index], + pt->cursor = pCursor); + + } + _dmxSetCursor(screenInfo.screens[pt->index], + pt->cursor, + x + start->rootXOrigin - pt->rootXOrigin, + y + start->rootYOrigin - pt->rootYOrigin); + } + _dmxMoveCursor(screenInfo.screens[pt->index], + x + start->rootXOrigin - pt->rootXOrigin, + y + start->rootYOrigin - pt->rootYOrigin); + } else if (/* pt != start && */ pt->cursorVisible) { + _dmxSetCursor(screenInfo.screens[pt->index], + NULL, + x + start->rootXOrigin - pt->rootXOrigin, + y + start->rootYOrigin - pt->rootYOrigin); + } + if (pt == start) + break; + } +} + +static void dmxSetCursor(DeviceIntPtr pDev, ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +{ + DMXScreenInfo *start = &dmxScreens[pScreen->myNum]; + DMXScreenInfo *pt; + int GX, GY, gx, gy; + + DMXDBG5("dmxSetCursor(%d %p, %p,%d,%d)\n", + pScreen->myNum, start, pCursor, x, y); + + /* We do this check here because of two cases: + * + * 1) if a client calls XWarpPointer() + * and Xinerama is not running, we can + * have mi's notion of the pointer + * position out of phase with DMX's + * notion. + * + * 2) if a down button is held while the + * cursor moves outside the root window, + * mi's notion of the pointer position + * is out of phase with DMX's notion and + * the cursor can remain visible when it + * shouldn't be. */ + + dmxGetGlobalPosition(&GX, &GY); + gx = start->rootXOrigin + x; + gy = start->rootYOrigin + y; + if (x && y && (GX != gx || GY != gy)) + dmxCoreMotion(NULL, gx, gy, 0, DMX_NO_BLOCK); + + if (!start->over || !dmxCursorDoMultiCursors || start->cursorNotShared) { + _dmxSetCursor(pScreen, pCursor, x, y); + return; + } + + for (pt = start->over; /* condition at end of loop */; pt = pt->over) { + if (pt->cursorNotShared) + continue; + if (dmxOnScreen(x + start->rootXOrigin, y + start->rootYOrigin, pt)) { + _dmxSetCursor(screenInfo.screens[pt->index], pCursor, + x + start->rootXOrigin - pt->rootXOrigin, + y + start->rootYOrigin - pt->rootYOrigin); + } else { + _dmxSetCursor(screenInfo.screens[pt->index], NULL, + x + start->rootXOrigin - pt->rootXOrigin, + y + start->rootYOrigin - pt->rootYOrigin); + } + if (pt == start) + break; + } +} + + +/** This routine is used by the backend input routines to hide the + * cursor on a screen that is being used for relative input. \see + * dmxbackend.c */ +void dmxHideCursor(DMXScreenInfo *dmxScreen) +{ + int x, y; + ScreenPtr pScreen = screenInfo.screens[dmxScreen->index]; + + dmxGetGlobalPosition(&x, &y); + _dmxSetCursor(pScreen, NULL, x, y); +} + +/** This routine is called during reconfiguration to make sure the + * cursor is visible. */ +void dmxCheckCursor(void) +{ + int i; + int x, y; + ScreenPtr pScreen; + DMXScreenInfo *firstScreen; + + dmxGetGlobalPosition(&x, &y); + firstScreen = dmxFindFirstScreen(x, y); + + DMXDBG2("dmxCheckCursor %d %d\n", x, y); + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + pScreen = screenInfo.screens[dmxScreen->index]; + + if (!dmxOnScreen(x, y, dmxScreen)) { + if (firstScreen && i == miPointerGetScreen(inputInfo.pointer)->myNum) + miPointerSetScreen(inputInfo.pointer, firstScreen->index, x, y); + _dmxSetCursor(pScreen, NULL, + x - dmxScreen->rootXOrigin, + y - dmxScreen->rootYOrigin); + } else { + if (!dmxScreen->cursor) { + CursorPtr pCursor; + + if ((pCursor = dmxFindCursor(dmxScreen))) { + _dmxRealizeCursor(pScreen, dmxScreen->cursor = pCursor); + } + } + _dmxSetCursor(pScreen, dmxScreen->cursor, + x - dmxScreen->rootXOrigin, + y - dmxScreen->rootYOrigin); + } + } + DMXDBG2(" leave dmxCheckCursor %d %d\n", x, y); +} + +static Bool dmxDeviceCursorInitialize(DeviceIntPtr pDev, ScreenPtr pScr) +{ + return TRUE; +} + +static void dmxDeviceCursorCleanup(DeviceIntPtr pDev, ScreenPtr pScr) +{ +} + +miPointerSpriteFuncRec dmxPointerSpriteFuncs = +{ + dmxRealizeCursor, + dmxUnrealizeCursor, + dmxSetCursor, + dmxMoveCursor, + dmxDeviceCursorInitialize, + dmxDeviceCursorCleanup +}; diff --git a/xorg-server/hw/dmx/dmxfont.c b/xorg-server/hw/dmx/dmxfont.c index c33aee79a..3f0264edb 100644 --- a/xorg-server/hw/dmx/dmxfont.c +++ b/xorg-server/hw/dmx/dmxfont.c @@ -1,559 +1,551 @@ -/* - * Copyright 2001-2004 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: - * Kevin E. Martin - * - */ - -/** \file - * This file provides support for fonts. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#define DMX_FONTPATH_DEBUG 0 - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxfont.h" -#include "dmxlog.h" - -#include -#include "dixfont.h" -#include "dixstruct.h" - -static int (*dmxSaveProcVector[256])(ClientPtr); -static int dmxFontLastError; - -static int dmxFontErrorHandler(Display *dpy, XErrorEvent *ev) -{ - dmxFontLastError = ev->error_code; - - return 0; -} - -static char **dmxGetFontPath(int *npaths) -{ - char **fp; - unsigned char *c, *paths; - char *newfp; - int len, l, i; - - GetFontPath(serverClient, npaths, &len, &paths); - - newfp = xalloc(*npaths + len); - c = (unsigned char *)newfp; - fp = xalloc(*npaths * sizeof(*fp)); - - memmove(newfp, paths+1, *npaths + len - 1); - l = *paths; - for (i = 0; i < *npaths; i++) { - fp[i] = (char *)c; - c += l; - l = *c; - *c++ = '\0'; - } - -#if DMX_FONTPATH_DEBUG - for (i = 0; i < *npaths; i++) - dmxLog(dmxDebug, "FontPath[%d] = %s\n", i, fp[i]); -#endif - - return fp; -} - -static void dmxFreeFontPath(char **fp) -{ - xfree(fp[0]); - xfree(fp); -} - -static Bool dmxCheckFontPathElement(DMXScreenInfo *dmxScreen, char *fp) -{ - int (*oldErrorHandler)(Display *, XErrorEvent *); - - if (!dmxScreen->beDisplay) - return TRUE; - - dmxFontLastError = 0; - oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler); - XSetFontPath(dmxScreen->beDisplay, &fp, 1); - dmxSync(dmxScreen, TRUE); /* Must complete before removing handler */ - XSetErrorHandler(oldErrorHandler); - - return (dmxFontLastError == 0); -} - -static int dmxSetFontPath(DMXScreenInfo *dmxScreen) -{ - int (*oldErrorHandler)(Display *, XErrorEvent *); - char **fp; - int result = Success; - int npaths; - - if (!dmxScreen->beDisplay) - return result; - - fp = dmxGetFontPath(&npaths); - if (!fp) return BadAlloc; - - dmxFontLastError = 0; - oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler); - XSetFontPath(dmxScreen->beDisplay, fp, npaths); - dmxSync(dmxScreen, TRUE); /* Must complete before removing handler */ - XSetErrorHandler(oldErrorHandler); - - if (dmxFontLastError) { - result = dmxFontLastError; - /* We could set *error here to the offending path, but it is - * ignored, so we don't bother figuring out which path is bad. - * If we do add this support in the future, we'll need to add - * error to the function's argument list. - */ - } - - dmxFreeFontPath(fp); - - return result; -} - -static int dmxCheckFontPath(DMXScreenInfo *dmxScreen, int *error) -{ - char **oldFontPath; - int nOldPaths; - int result = Success; - - if (!dmxScreen->beDisplay) - return result; - - /* Save old font path */ - oldFontPath = XGetFontPath(dmxScreen->beDisplay, &nOldPaths); - - result = dmxSetFontPath(dmxScreen); - - /* Restore old font path */ - XSetFontPath(dmxScreen->beDisplay, oldFontPath, nOldPaths); - XFreeFontPath(oldFontPath); - dmxSync(dmxScreen, FALSE); - - return result; -} - -static int dmxProcSetFontPath(ClientPtr client) -{ - unsigned char *ptr; - unsigned long nbytes, total, n; - long nfonts; - int i, result; - int error; - unsigned char *oldFontPath, *tmpFontPath; - int nOldPaths; - int lenOldPaths; - REQUEST(xSetFontPathReq); - - REQUEST_AT_LEAST_SIZE(xSetFontPathReq); - - nbytes = (client->req_len << 2) - sizeof(xSetFontPathReq); - total = nbytes; - ptr = (unsigned char *)&stuff[1]; - nfonts = stuff->nFonts; - - while (--nfonts >= 0) { - if ((total == 0) || (total < (n = (*ptr + 1)))) - return BadLength; - total -= n; - ptr += n; - } - if (total >= 4) - return BadLength; - - GetFontPath(serverClient, &nOldPaths, &lenOldPaths, &tmpFontPath); - oldFontPath = xalloc(nOldPaths + lenOldPaths); - memmove(oldFontPath, tmpFontPath, nOldPaths + lenOldPaths); - - result = SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1], - &error); - if (!result) { - for (i = 0; i < dmxNumScreens; i++) - if ((result = dmxCheckFontPath(&dmxScreens[i], &error))) - break; - - if (result) { - int ignoreresult, ignoreerror; - - /* Restore old fontpath in the DMX server */ - ignoreresult = SetFontPath(client, nOldPaths, oldFontPath, - &ignoreerror); - } else { - result = client->noClientException; - client->errorValue = error; - } - } - - xfree(oldFontPath); - return result; -} - -/** Initialize font support. In addition to the screen function call - * pointers, DMX also hooks in at the ProcVector[] level. Here the old - * ProcVector function pointers are saved and the new ProcVector - * function pointers are initialized. */ -void dmxInitFonts(void) -{ - int i; - - for (i = 0; i < 256; i++) - dmxSaveProcVector[i] = ProcVector[i]; - - ProcVector[X_SetFontPath] = dmxProcSetFontPath; -} - -/** Reset font support by restoring the original ProcVector function - * pointers. */ -void dmxResetFonts(void) -{ - int i; - - for (i = 0; i < 256; i++) - ProcVector[i] = dmxSaveProcVector[i]; -} - -/** Load the font, \a pFont, on the back-end server associated with \a - * pScreen. When a font is loaded, the font path on back-end server is - * first initialized to that specified on the command line with the - * -fontpath options, and then the font is loaded. */ -Bool dmxBELoadFont(ScreenPtr pScreen, FontPtr pFont) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxFontPrivPtr pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); - const char *name; - char **oldFontPath = NULL; - int nOldPaths; - Atom name_atom, value_atom; - int i; - - /* Make sure we have a font private struct to work with */ - if (!pFontPriv) - return FALSE; - - /* Don't load a font over top of itself */ - if (pFontPriv->font[pScreen->myNum]) { - return TRUE; /* Already loaded font */ - } - - /* Save old font path */ - oldFontPath = XGetFontPath(dmxScreen->beDisplay, &nOldPaths); - - /* Set the font path for the font about to be loaded on the back-end */ - if (dmxSetFontPath(dmxScreen)) { - char **fp; - int npaths; - Bool *goodfps; - - /* This could fail only when first starting the X server and - * loading the default font. If it fails here, then the default - * font path is invalid, no default font path will be set, the - * DMX server will fail to load the default font, and it will - * exit with an error unless we remove the offending font paths - * with the -ignorebadfontpaths command line option. - */ - - fp = dmxGetFontPath(&npaths); - if (!fp) { - dmxLog(dmxError, - "No default font path set.\n"); - dmxLog(dmxError, - "Please see the Xdmx man page for information on how to\n"); - dmxLog(dmxError, - "initialize the DMX server's default font path.\n"); - XFreeFontPath(oldFontPath); - return FALSE; - } - - if (!dmxFontPath) - dmxLog(dmxWarning, "No default font path is set.\n"); - - goodfps = xalloc(npaths * sizeof(*goodfps)); - - dmxLog(dmxError, - "The DMX server failed to set the following font paths on " - "screen #%d:\n", pScreen->myNum); - - for (i = 0; i < npaths; i++) - if (!(goodfps[i] = dmxCheckFontPathElement(dmxScreen, fp[i]))) - dmxLog(dmxError, " %s\n", fp[i]); - - if (dmxIgnoreBadFontPaths) { - char *newfp; - int newnpaths = 0; - int len = 0; - int j = 0; - int error; - - dmxLog(dmxError, - "These font paths will not be used because the " - "\"-ignorebadfontpaths\"\n"); - dmxLog(dmxError, - "option is set.\n"); - - for (i = 0; i < npaths; i++) - if (goodfps[i]) { - len += strlen(fp[i]) + 1; - newnpaths++; - } - - if (!newnpaths) { - /* No valid font paths were found */ - dmxLog(dmxError, - "After removing the font paths above, no valid font " - "paths were\n"); - dmxLog(dmxError, - "available. Please check that the font paths set on " - "the command\n"); - dmxLog(dmxError, - "line or in the configuration file via the " - "\"-fontpath\" option\n"); - dmxLog(dmxError, - "are valid on all back-end servers. See the Xdmx man " - "page for\n"); - dmxLog(dmxError, - "more information on font paths.\n"); - dmxFreeFontPath(fp); - XFreeFontPath(oldFontPath); - xfree(goodfps); - return FALSE; - } - - newfp = xalloc(len * sizeof(*newfp)); - for (i = 0; i < npaths; i++) { - if (goodfps[i]) { - int n = strlen(fp[i]); - newfp[j++] = n; - strncpy(&newfp[j], fp[i], n); - j += n; - } - } - - if (SetFontPath(serverClient, newnpaths, (unsigned char *)newfp, - &error)) { - /* Note that this should never happen since all of the - * FPEs were previously valid. */ - dmxLog(dmxError, "Cannot reset the default font path.\n"); - } - } else if (dmxFontPath) { - dmxLog(dmxError, - "Please remove these font paths from the command line " - "or\n"); - dmxLog(dmxError, - "configuration file, or set the \"-ignorebadfontpaths\" " - "option to\n"); - dmxLog(dmxError, - "ignore them. For more information on these options, see " - "the\n"); - dmxLog(dmxError, - "Xdmx man page.\n"); - } else { - dmxLog(dmxError, - "Please specify the font paths that are available on all " - "back-end\n"); - dmxLog(dmxError, - "servers with the \"-fontpath\" option, or use the " - "\"-ignorebadfontpaths\"\n"); - dmxLog(dmxError, - "to ignore bad defaults. For more information on " - "these and other\n"); - dmxLog(dmxError, - "font-path-related options, see the Xdmx man page.\n"); - } - - if (!dmxIgnoreBadFontPaths || - (dmxIgnoreBadFontPaths && dmxSetFontPath(dmxScreen))) { - /* We still have errors so return with error */ - dmxFreeFontPath(fp); - XFreeFontPath(oldFontPath); - xfree(goodfps); - return FALSE; - } - } - - /* Find requested font on back-end server */ - name_atom = MakeAtom("FONT", 4, TRUE); - value_atom = 0L; - - for (i = 0; i < pFont->info.nprops; i++) { - if ((Atom)pFont->info.props[i].name == name_atom) { - value_atom = pFont->info.props[i].value; - break; - } - } - if (!value_atom) return FALSE; - - name = NameForAtom(value_atom); - if (!name) return FALSE; - - pFontPriv->font[pScreen->myNum] = - XLoadQueryFont(dmxScreen->beDisplay, name); - - /* Restore old font path */ - XSetFontPath(dmxScreen->beDisplay, oldFontPath, nOldPaths); - XFreeFontPath(oldFontPath); - dmxSync(dmxScreen, FALSE); - - if (!pFontPriv->font[pScreen->myNum]) return FALSE; - - return TRUE; -} - -/** Realize the font, \a pFont, on the back-end server associated with - * \a pScreen. */ -Bool dmxRealizeFont(ScreenPtr pScreen, FontPtr pFont) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxFontPrivPtr pFontPriv; - - if (!(pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) { - FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); - pFontPriv = xalloc(sizeof(dmxFontPrivRec)); - if (!pFontPriv) return FALSE; - pFontPriv->font = NULL; - MAXSCREENSALLOC(pFontPriv->font); - if (!pFontPriv->font) { - xfree(pFontPriv); - return FALSE; - } - pFontPriv->refcnt = 0; - } - - FontSetPrivate(pFont, dmxFontPrivateIndex, (pointer)pFontPriv); - - if (dmxScreen->beDisplay) { - if (!dmxBELoadFont(pScreen, pFont)) - return FALSE; - - pFontPriv->refcnt++; - } else { - pFontPriv->font[pScreen->myNum] = NULL; - } - - return TRUE; -} - -/** Free \a pFont on the back-end associated with \a pScreen. */ -Bool dmxBEFreeFont(ScreenPtr pScreen, FontPtr pFont) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxFontPrivPtr pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); - - if (pFontPriv && pFontPriv->font[pScreen->myNum]) { - XFreeFont(dmxScreen->beDisplay, pFontPriv->font[pScreen->myNum]); - pFontPriv->font[pScreen->myNum] = NULL; - return TRUE; - } - - return FALSE; -} - -/** Unrealize the font, \a pFont, on the back-end server associated with - * \a pScreen. */ -Bool dmxUnrealizeFont(ScreenPtr pScreen, FontPtr pFont) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxFontPrivPtr pFontPriv; - - if ((pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) { - /* In case the font failed to load properly */ - if (!pFontPriv->refcnt) { - MAXSCREENSFREE(pFontPriv->font); - xfree(pFontPriv); - FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); - } else if (pFontPriv->font[pScreen->myNum]) { - if (dmxScreen->beDisplay) - dmxBEFreeFont(pScreen, pFont); - - /* The code below is non-obvious, so here's an explanation... - * - * When creating the default GC, the server opens up the - * default font once for each screen, which in turn calls - * the RealizeFont function pointer once for each screen. - * During this process both dix's font refcnt and DMX's font - * refcnt are incremented once for each screen. - * - * Later, when shutting down the X server, dix shuts down - * each screen in reverse order. During this shutdown - * procedure, each screen's default GC is freed and then - * that screen is closed by calling the CloseScreen function - * pointer. screenInfo.numScreens is then decremented after - * closing each screen. This procedure means that the dix's - * font refcnt for the font used by the default GC's is - * decremented once for each screen # greater than 0. - * However, since dix's refcnt for the default font is not - * yet 0 for each screen greater than 0, no call to the - * UnrealizeFont function pointer is made for those screens. - * Then, when screen 0 is being closed, dix's font refcnt - * for the default GC's font is finally 0 and the font is - * unrealized. However, since screenInfo.numScreens has - * been decremented already down to 1, only one call to - * UnrealizeFont is made (for screen 0). Thus, even though - * RealizeFont was called once for each screen, - * UnrealizeFont is only called for screen 0. - * - * This is a bug in dix. - * - * To avoid the memory leak of pFontPriv for each server - * generation, we can also free pFontPriv if the refcnt is - * not yet 0 but the # of screens is 1 -- i.e., the case - * described in the dix bug above. This is only a temporary - * workaround until the bug in dix is solved. - * - * The other problem is that the font structure allocated by - * XLoadQueryFont() above is not freed for screens > 0. - * This problem cannot be worked around here since the back- - * end displays for screens > 0 have already been closed by - * the time this code is called from dix. - * - * When the bug in dix described above is fixed, then we can - * remove the "|| screenInfo.numScreens == 1" code below and - * the memory leaks will be eliminated. - */ - if (--pFontPriv->refcnt == 0 -#if 1 - /* Remove this code when the dix bug is fixed */ - || screenInfo.numScreens == 1 -#endif - ) { - MAXSCREENSFREE(pFontPriv->font); - xfree(pFontPriv); - FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); - } - } - } - - return TRUE; -} +/* + * Copyright 2001-2004 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: + * Kevin E. Martin + * + */ + +/** \file + * This file provides support for fonts. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#define DMX_FONTPATH_DEBUG 0 + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxfont.h" +#include "dmxlog.h" + +#include +#include "dixfont.h" +#include "dixstruct.h" + +static int (*dmxSaveProcVector[256])(ClientPtr); +static int dmxFontLastError; + +static int dmxFontErrorHandler(Display *dpy, XErrorEvent *ev) +{ + dmxFontLastError = ev->error_code; + + return 0; +} + +static char **dmxGetFontPath(int *npaths) +{ + char **fp; + unsigned char *c, *paths; + char *newfp; + int len, l, i; + + GetFontPath(serverClient, npaths, &len, &paths); + + newfp = malloc(*npaths + len); + c = (unsigned char *)newfp; + fp = malloc(*npaths * sizeof(*fp)); + + memmove(newfp, paths+1, *npaths + len - 1); + l = *paths; + for (i = 0; i < *npaths; i++) { + fp[i] = (char *)c; + c += l; + l = *c; + *c++ = '\0'; + } + +#if DMX_FONTPATH_DEBUG + for (i = 0; i < *npaths; i++) + dmxLog(dmxDebug, "FontPath[%d] = %s\n", i, fp[i]); +#endif + + return fp; +} + +static void dmxFreeFontPath(char **fp) +{ + free(fp[0]); + free(fp); +} + +static Bool dmxCheckFontPathElement(DMXScreenInfo *dmxScreen, char *fp) +{ + int (*oldErrorHandler)(Display *, XErrorEvent *); + + if (!dmxScreen->beDisplay) + return TRUE; + + dmxFontLastError = 0; + oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler); + XSetFontPath(dmxScreen->beDisplay, &fp, 1); + dmxSync(dmxScreen, TRUE); /* Must complete before removing handler */ + XSetErrorHandler(oldErrorHandler); + + return (dmxFontLastError == 0); +} + +static int dmxSetFontPath(DMXScreenInfo *dmxScreen) +{ + int (*oldErrorHandler)(Display *, XErrorEvent *); + char **fp; + int result = Success; + int npaths; + + if (!dmxScreen->beDisplay) + return result; + + fp = dmxGetFontPath(&npaths); + if (!fp) return BadAlloc; + + dmxFontLastError = 0; + oldErrorHandler = XSetErrorHandler(dmxFontErrorHandler); + XSetFontPath(dmxScreen->beDisplay, fp, npaths); + dmxSync(dmxScreen, TRUE); /* Must complete before removing handler */ + XSetErrorHandler(oldErrorHandler); + + if (dmxFontLastError) { + result = dmxFontLastError; + /* We could set *error here to the offending path, but it is + * ignored, so we don't bother figuring out which path is bad. + * If we do add this support in the future, we'll need to add + * error to the function's argument list. + */ + } + + dmxFreeFontPath(fp); + + return result; +} + +static int dmxCheckFontPath(DMXScreenInfo *dmxScreen, int *error) +{ + char **oldFontPath; + int nOldPaths; + int result = Success; + + if (!dmxScreen->beDisplay) + return result; + + /* Save old font path */ + oldFontPath = XGetFontPath(dmxScreen->beDisplay, &nOldPaths); + + result = dmxSetFontPath(dmxScreen); + + /* Restore old font path */ + XSetFontPath(dmxScreen->beDisplay, oldFontPath, nOldPaths); + XFreeFontPath(oldFontPath); + dmxSync(dmxScreen, FALSE); + + return result; +} + +static int dmxProcSetFontPath(ClientPtr client) +{ + unsigned char *ptr; + unsigned long nbytes, total, n; + long nfonts; + int i, result; + unsigned char *oldFontPath, *tmpFontPath; + int nOldPaths; + int lenOldPaths; + REQUEST(xSetFontPathReq); + + REQUEST_AT_LEAST_SIZE(xSetFontPathReq); + + nbytes = (client->req_len << 2) - sizeof(xSetFontPathReq); + total = nbytes; + ptr = (unsigned char *)&stuff[1]; + nfonts = stuff->nFonts; + + while (--nfonts >= 0) { + if ((total == 0) || (total < (n = (*ptr + 1)))) + return BadLength; + total -= n; + ptr += n; + } + if (total >= 4) + return BadLength; + + GetFontPath(serverClient, &nOldPaths, &lenOldPaths, &tmpFontPath); + oldFontPath = malloc(nOldPaths + lenOldPaths); + memmove(oldFontPath, tmpFontPath, nOldPaths + lenOldPaths); + + result = SetFontPath(client, stuff->nFonts, (unsigned char *)&stuff[1]); + if (!result) { + int error = 0; + for (i = 0; i < dmxNumScreens; i++) + if ((result = dmxCheckFontPath(&dmxScreens[i], &error))) + break; + + if (result) { + /* Restore old fontpath in the DMX server */ + SetFontPath(client, nOldPaths, oldFontPath); + client->errorValue = error; + } + } + + free(oldFontPath); + return result; +} + +/** Initialize font support. In addition to the screen function call + * pointers, DMX also hooks in at the ProcVector[] level. Here the old + * ProcVector function pointers are saved and the new ProcVector + * function pointers are initialized. */ +void dmxInitFonts(void) +{ + int i; + + for (i = 0; i < 256; i++) + dmxSaveProcVector[i] = ProcVector[i]; + + ProcVector[X_SetFontPath] = dmxProcSetFontPath; +} + +/** Reset font support by restoring the original ProcVector function + * pointers. */ +void dmxResetFonts(void) +{ + int i; + + for (i = 0; i < 256; i++) + ProcVector[i] = dmxSaveProcVector[i]; +} + +/** Load the font, \a pFont, on the back-end server associated with \a + * pScreen. When a font is loaded, the font path on back-end server is + * first initialized to that specified on the command line with the + * -fontpath options, and then the font is loaded. */ +Bool dmxBELoadFont(ScreenPtr pScreen, FontPtr pFont) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxFontPrivPtr pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); + const char *name; + char **oldFontPath = NULL; + int nOldPaths; + Atom name_atom, value_atom; + int i; + + /* Make sure we have a font private struct to work with */ + if (!pFontPriv) + return FALSE; + + /* Don't load a font over top of itself */ + if (pFontPriv->font[pScreen->myNum]) { + return TRUE; /* Already loaded font */ + } + + /* Save old font path */ + oldFontPath = XGetFontPath(dmxScreen->beDisplay, &nOldPaths); + + /* Set the font path for the font about to be loaded on the back-end */ + if (dmxSetFontPath(dmxScreen)) { + char **fp; + int npaths; + Bool *goodfps; + + /* This could fail only when first starting the X server and + * loading the default font. If it fails here, then the default + * font path is invalid, no default font path will be set, the + * DMX server will fail to load the default font, and it will + * exit with an error unless we remove the offending font paths + * with the -ignorebadfontpaths command line option. + */ + + fp = dmxGetFontPath(&npaths); + if (!fp) { + dmxLog(dmxError, + "No default font path set.\n"); + dmxLog(dmxError, + "Please see the Xdmx man page for information on how to\n"); + dmxLog(dmxError, + "initialize the DMX server's default font path.\n"); + XFreeFontPath(oldFontPath); + return FALSE; + } + + if (!dmxFontPath) + dmxLog(dmxWarning, "No default font path is set.\n"); + + goodfps = malloc(npaths * sizeof(*goodfps)); + + dmxLog(dmxError, + "The DMX server failed to set the following font paths on " + "screen #%d:\n", pScreen->myNum); + + for (i = 0; i < npaths; i++) + if (!(goodfps[i] = dmxCheckFontPathElement(dmxScreen, fp[i]))) + dmxLog(dmxError, " %s\n", fp[i]); + + if (dmxIgnoreBadFontPaths) { + char *newfp; + int newnpaths = 0; + int len = 0; + int j = 0; + + dmxLog(dmxError, + "These font paths will not be used because the " + "\"-ignorebadfontpaths\"\n"); + dmxLog(dmxError, + "option is set.\n"); + + for (i = 0; i < npaths; i++) + if (goodfps[i]) { + len += strlen(fp[i]) + 1; + newnpaths++; + } + + if (!newnpaths) { + /* No valid font paths were found */ + dmxLog(dmxError, + "After removing the font paths above, no valid font " + "paths were\n"); + dmxLog(dmxError, + "available. Please check that the font paths set on " + "the command\n"); + dmxLog(dmxError, + "line or in the configuration file via the " + "\"-fontpath\" option\n"); + dmxLog(dmxError, + "are valid on all back-end servers. See the Xdmx man " + "page for\n"); + dmxLog(dmxError, + "more information on font paths.\n"); + dmxFreeFontPath(fp); + XFreeFontPath(oldFontPath); + free(goodfps); + return FALSE; + } + + newfp = malloc(len * sizeof(*newfp)); + for (i = 0; i < npaths; i++) { + if (goodfps[i]) { + int n = strlen(fp[i]); + newfp[j++] = n; + strncpy(&newfp[j], fp[i], n); + j += n; + } + } + + if (SetFontPath(serverClient, newnpaths, (unsigned char *)newfp)) { + /* Note that this should never happen since all of the + * FPEs were previously valid. */ + dmxLog(dmxError, "Cannot reset the default font path.\n"); + } + } else if (dmxFontPath) { + dmxLog(dmxError, + "Please remove these font paths from the command line " + "or\n"); + dmxLog(dmxError, + "configuration file, or set the \"-ignorebadfontpaths\" " + "option to\n"); + dmxLog(dmxError, + "ignore them. For more information on these options, see " + "the\n"); + dmxLog(dmxError, + "Xdmx man page.\n"); + } else { + dmxLog(dmxError, + "Please specify the font paths that are available on all " + "back-end\n"); + dmxLog(dmxError, + "servers with the \"-fontpath\" option, or use the " + "\"-ignorebadfontpaths\"\n"); + dmxLog(dmxError, + "to ignore bad defaults. For more information on " + "these and other\n"); + dmxLog(dmxError, + "font-path-related options, see the Xdmx man page.\n"); + } + + if (!dmxIgnoreBadFontPaths || + (dmxIgnoreBadFontPaths && dmxSetFontPath(dmxScreen))) { + /* We still have errors so return with error */ + dmxFreeFontPath(fp); + XFreeFontPath(oldFontPath); + free(goodfps); + return FALSE; + } + } + + /* Find requested font on back-end server */ + name_atom = MakeAtom("FONT", 4, TRUE); + value_atom = 0L; + + for (i = 0; i < pFont->info.nprops; i++) { + if ((Atom)pFont->info.props[i].name == name_atom) { + value_atom = pFont->info.props[i].value; + break; + } + } + if (!value_atom) return FALSE; + + name = NameForAtom(value_atom); + if (!name) return FALSE; + + pFontPriv->font[pScreen->myNum] = + XLoadQueryFont(dmxScreen->beDisplay, name); + + /* Restore old font path */ + XSetFontPath(dmxScreen->beDisplay, oldFontPath, nOldPaths); + XFreeFontPath(oldFontPath); + dmxSync(dmxScreen, FALSE); + + if (!pFontPriv->font[pScreen->myNum]) return FALSE; + + return TRUE; +} + +/** Realize the font, \a pFont, on the back-end server associated with + * \a pScreen. */ +Bool dmxRealizeFont(ScreenPtr pScreen, FontPtr pFont) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxFontPrivPtr pFontPriv; + + if (!(pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) { + FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); + pFontPriv = malloc(sizeof(dmxFontPrivRec)); + if (!pFontPriv) return FALSE; + pFontPriv->font = NULL; + MAXSCREENSALLOC(pFontPriv->font); + if (!pFontPriv->font) { + free(pFontPriv); + return FALSE; + } + pFontPriv->refcnt = 0; + } + + FontSetPrivate(pFont, dmxFontPrivateIndex, (pointer)pFontPriv); + + if (dmxScreen->beDisplay) { + if (!dmxBELoadFont(pScreen, pFont)) + return FALSE; + + pFontPriv->refcnt++; + } else { + pFontPriv->font[pScreen->myNum] = NULL; + } + + return TRUE; +} + +/** Free \a pFont on the back-end associated with \a pScreen. */ +Bool dmxBEFreeFont(ScreenPtr pScreen, FontPtr pFont) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxFontPrivPtr pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); + + if (pFontPriv && pFontPriv->font[pScreen->myNum]) { + XFreeFont(dmxScreen->beDisplay, pFontPriv->font[pScreen->myNum]); + pFontPriv->font[pScreen->myNum] = NULL; + return TRUE; + } + + return FALSE; +} + +/** Unrealize the font, \a pFont, on the back-end server associated with + * \a pScreen. */ +Bool dmxUnrealizeFont(ScreenPtr pScreen, FontPtr pFont) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxFontPrivPtr pFontPriv; + + if ((pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex))) { + /* In case the font failed to load properly */ + if (!pFontPriv->refcnt) { + MAXSCREENSFREE(pFontPriv->font); + free(pFontPriv); + FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); + } else if (pFontPriv->font[pScreen->myNum]) { + if (dmxScreen->beDisplay) + dmxBEFreeFont(pScreen, pFont); + + /* The code below is non-obvious, so here's an explanation... + * + * When creating the default GC, the server opens up the + * default font once for each screen, which in turn calls + * the RealizeFont function pointer once for each screen. + * During this process both dix's font refcnt and DMX's font + * refcnt are incremented once for each screen. + * + * Later, when shutting down the X server, dix shuts down + * each screen in reverse order. During this shutdown + * procedure, each screen's default GC is freed and then + * that screen is closed by calling the CloseScreen function + * pointer. screenInfo.numScreens is then decremented after + * closing each screen. This procedure means that the dix's + * font refcnt for the font used by the default GC's is + * decremented once for each screen # greater than 0. + * However, since dix's refcnt for the default font is not + * yet 0 for each screen greater than 0, no call to the + * UnrealizeFont function pointer is made for those screens. + * Then, when screen 0 is being closed, dix's font refcnt + * for the default GC's font is finally 0 and the font is + * unrealized. However, since screenInfo.numScreens has + * been decremented already down to 1, only one call to + * UnrealizeFont is made (for screen 0). Thus, even though + * RealizeFont was called once for each screen, + * UnrealizeFont is only called for screen 0. + * + * This is a bug in dix. + * + * To avoid the memory leak of pFontPriv for each server + * generation, we can also free pFontPriv if the refcnt is + * not yet 0 but the # of screens is 1 -- i.e., the case + * described in the dix bug above. This is only a temporary + * workaround until the bug in dix is solved. + * + * The other problem is that the font structure allocated by + * XLoadQueryFont() above is not freed for screens > 0. + * This problem cannot be worked around here since the back- + * end displays for screens > 0 have already been closed by + * the time this code is called from dix. + * + * When the bug in dix described above is fixed, then we can + * remove the "|| screenInfo.numScreens == 1" code below and + * the memory leaks will be eliminated. + */ + if (--pFontPriv->refcnt == 0 +#if 1 + /* Remove this code when the dix bug is fixed */ + || screenInfo.numScreens == 1 +#endif + ) { + MAXSCREENSFREE(pFontPriv->font); + free(pFontPriv); + FontSetPrivate(pFont, dmxFontPrivateIndex, NULL); + } + } + } + + return TRUE; +} diff --git a/xorg-server/hw/dmx/dmxgc.c b/xorg-server/hw/dmx/dmxgc.c index eb21d3c60..82f74b6e6 100644 --- a/xorg-server/hw/dmx/dmxgc.c +++ b/xorg-server/hw/dmx/dmxgc.c @@ -1,421 +1,421 @@ -/* - * Copyright 2001-2004 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: - * Kevin E. Martin - * - */ - -/** \file - * This file provides support for GCs. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxgc.h" -#include "dmxgcops.h" -#include "dmxpixmap.h" -#include "dmxfont.h" - -#include "gcstruct.h" -#include "pixmapstr.h" -#include "migc.h" - -static GCFuncs dmxGCFuncs = { - dmxValidateGC, - dmxChangeGC, - dmxCopyGC, - dmxDestroyGC, - dmxChangeClip, - dmxDestroyClip, - dmxCopyClip, -}; - -static GCOps dmxGCOps = { - dmxFillSpans, - dmxSetSpans, - dmxPutImage, - dmxCopyArea, - dmxCopyPlane, - dmxPolyPoint, - dmxPolylines, - dmxPolySegment, - dmxPolyRectangle, - dmxPolyArc, - dmxFillPolygon, - dmxPolyFillRect, - dmxPolyFillArc, - dmxPolyText8, - dmxPolyText16, - dmxImageText8, - dmxImageText16, - dmxImageGlyphBlt, - dmxPolyGlyphBlt, - dmxPushPixels -}; - -/** Initialize the GC on \a pScreen */ -Bool dmxInitGC(ScreenPtr pScreen) -{ - if (!dixRequestPrivate(dmxGCPrivateKey, sizeof(dmxGCPrivRec))) - return FALSE; - return TRUE; -} - -/** Create the GC on the back-end server. */ -void dmxBECreateGC(ScreenPtr pScreen, GCPtr pGC) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - int i; - - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { - if (pGC->depth == dmxScreen->bePixmapFormats[i].depth) { - unsigned long mask; - XGCValues gcvals; - - mask = GCGraphicsExposures; - gcvals.graphics_exposures = FALSE; - - /* Create GC in the back-end servers */ - pGCPriv->gc = XCreateGC(dmxScreen->beDisplay, - dmxScreen->scrnDefDrawables[i], - mask, &gcvals); - break; - } - } -} - -/** Create a graphics context on the back-end server associated /a pGC's - * screen. */ -Bool dmxCreateGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - Bool ret; - - DMX_UNWRAP(CreateGC, dmxScreen, pScreen); - if ((ret = pScreen->CreateGC(pGC))) { - /* Save the old funcs */ - pGCPriv->funcs = pGC->funcs; - pGCPriv->ops = NULL; - - pGC->funcs = &dmxGCFuncs; - - if (dmxScreen->beDisplay) { - dmxBECreateGC(pScreen, pGC); - } else { - pGCPriv->gc = NULL; - } - - /* Check for "magic special case" - * 1. see CreateGC in dix/gc.c for more info - * 2. see dmxChangeGC for more info - */ - pGCPriv->msc = (!pGC->tileIsPixel && !pGC->tile.pixmap); - } - DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); - - return ret; -} - -/** Validate a graphics context, \a pGC, locally in the DMX server and - * recompute the composite clip, if necessary. */ -void dmxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) -{ - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - - DMX_GC_FUNC_PROLOGUE(pGC); -#if 0 - pGC->funcs->ValidateGC(pGC, changes, pDrawable); -#endif - - if (pDrawable->type == DRAWABLE_WINDOW || - pDrawable->type == DRAWABLE_PIXMAP) { - /* Save the old ops, since we're about to change the ops in the - * epilogue. - */ - pGCPriv->ops = pGC->ops; - } else { - pGCPriv->ops = NULL; - } - - /* If the client clip is different or moved OR the subwindowMode has - * changed OR the window's clip has changed since the last - * validation, then we need to recompute the composite clip. - */ - if ((changes & (GCClipXOrigin | - GCClipYOrigin | - GCClipMask | - GCSubwindowMode)) || - (pDrawable->serialNumber != - (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) { - miComputeCompositeClip(pGC, pDrawable); - } - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Set the values in the graphics context on the back-end server - * associated with \a pGC's screen. */ -void dmxChangeGC(GCPtr pGC, unsigned long mask) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - XGCValues v; - - DMX_GC_FUNC_PROLOGUE(pGC); -#if 0 - pGC->funcs->ChangeGC(pGC, mask); -#endif - - /* Handle "magic special case" from CreateGC */ - if (pGCPriv->msc) { - /* The "magic special case" is used to handle the case where a - * foreground pixel is set when the GC is created so that a - * "pseudo default-tile" can be created and used in case the - * fillstyle was set to FillTiled. This specific case is tested - * in xtest (XCreateGC test #3). What has happened in dix by - * the time it reaches here is (1) the pGC->tile.pixel has been - * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a - * tile has also been set, then pGC->tileIsPixel is unset and - * pGC->tile.pixmap is initialized; else, the default tile is - * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is - * initialized to the "pseudo default-tile". In either case, - * pGC->tile.pixmap is set; however, in the "magic special case" - * the mask is not updated to allow us to detect that we should - * initialize the GCTile in the back-end server. Thus, we catch - * this case in dmxCreateGC and add GCTile to the mask here. - * Are there any cases that I've missed? - */ - - /* Make sure that the tile.pixmap is set, just in case the user - * set GCTile in the mask but forgot to set vals.pixmap - */ - if (pGC->tile.pixmap) mask |= GCTile; - - /* This only happens once when the GC is created */ - pGCPriv->msc = FALSE; - } - - /* Update back-end server's gc */ - if (mask & GCFunction) v.function = pGC->alu; - if (mask & GCPlaneMask) v.plane_mask = pGC->planemask; - if (mask & GCForeground) v.foreground = pGC->fgPixel; - if (mask & GCBackground) v.background = pGC->bgPixel; - if (mask & GCLineWidth) v.line_width = pGC->lineWidth; - if (mask & GCLineStyle) v.line_style = pGC->lineStyle; - if (mask & GCCapStyle) v.cap_style = pGC->capStyle; - if (mask & GCJoinStyle) v.join_style = pGC->joinStyle; - if (mask & GCFillStyle) v.fill_style = pGC->fillStyle; - if (mask & GCFillRule) v.fill_rule = pGC->fillRule; - if (mask & GCTile) { - if (pGC->tileIsPixel) { - mask &= ~GCTile; - } else { - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->tile.pixmap); - v.tile = (Drawable)pPixPriv->pixmap; - } - } - if (mask & GCStipple) { - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->stipple); - v.stipple = (Drawable)pPixPriv->pixmap; - } - if (mask & GCTileStipXOrigin) v.ts_x_origin = pGC->patOrg.x; - if (mask & GCTileStipYOrigin) v.ts_y_origin = pGC->patOrg.y; - if (mask & GCFont) { - if (dmxScreen->beDisplay) { - dmxFontPrivPtr pFontPriv; - pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex); - v.font = pFontPriv->font[pScreen->myNum]->fid; - } else { - mask &= ~GCFont; - } - } - if (mask & GCSubwindowMode) v.subwindow_mode = pGC->subWindowMode; - - /* Graphics exposures are not needed on the back-ends since they can - be generated on the front-end thereby saving bandwidth. */ - if (mask & GCGraphicsExposures) mask &= ~GCGraphicsExposures; - - if (mask & GCClipXOrigin) v.clip_x_origin = pGC->clipOrg.x; - if (mask & GCClipYOrigin) v.clip_y_origin = pGC->clipOrg.y; - if (mask & GCClipMask) mask &= ~GCClipMask; /* See ChangeClip */ - if (mask & GCDashOffset) v.dash_offset = pGC->dashOffset; - if (mask & GCDashList) { - mask &= ~GCDashList; - if (dmxScreen->beDisplay) - XSetDashes(dmxScreen->beDisplay, pGCPriv->gc, - pGC->dashOffset, (char *)pGC->dash, - pGC->numInDashList); - } - if (mask & GCArcMode) v.arc_mode = pGC->arcMode; - - if (mask && dmxScreen->beDisplay) { - XChangeGC(dmxScreen->beDisplay, pGCPriv->gc, mask, &v); - dmxSync(dmxScreen, FALSE); - } - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Copy \a pGCSrc to \a pGCDst on the back-end server associated with - * \a pGCSrc's screen. */ -void dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) -{ - ScreenPtr pScreen = pGCSrc->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCSrcPriv = DMX_GET_GC_PRIV(pGCSrc); - dmxGCPrivPtr pGCDstPriv = DMX_GET_GC_PRIV(pGCDst); - - DMX_GC_FUNC_PROLOGUE(pGCDst); - pGCDst->funcs->CopyGC(pGCSrc, changes, pGCDst); - - /* Copy the GC on the back-end server */ - if (dmxScreen->beDisplay) - XCopyGC(dmxScreen->beDisplay, pGCSrcPriv->gc, changes, pGCDstPriv->gc); - - DMX_GC_FUNC_EPILOGUE(pGCDst); -} - -/** Free the \a pGC on the back-end server. */ -Bool dmxBEFreeGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - - if (pGCPriv->gc) { - XFreeGC(dmxScreen->beDisplay, pGCPriv->gc); - pGCPriv->gc = NULL; - return TRUE; - } - - return FALSE; -} - -/** Destroy the graphics context, \a pGC and free the corresponding GC - * on the back-end server. */ -void dmxDestroyGC(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - DMX_GC_FUNC_PROLOGUE(pGC); - - /* Free the GC on the back-end server */ - if (dmxScreen->beDisplay) - dmxBEFreeGC(pGC); - - pGC->funcs->DestroyGC(pGC); - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Change the clip rects for a GC. */ -void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - XRectangle *pRects; - BoxPtr pBox; - int i, nRects; - - DMX_GC_FUNC_PROLOGUE(pGC); - pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); - - /* Set the client clip on the back-end server */ - switch (pGC->clientClipType) { - case CT_NONE: - if (dmxScreen->beDisplay) - XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); - break; - - case CT_REGION: - if (dmxScreen->beDisplay) { - nRects = REGION_NUM_RECTS((RegionPtr)pGC->clientClip); - pRects = xalloc(nRects * sizeof(*pRects)); - pBox = REGION_RECTS((RegionPtr)pGC->clientClip); - - for (i = 0; i < nRects; i++) { - pRects[i].x = pBox[i].x1; - pRects[i].y = pBox[i].y1; - pRects[i].width = pBox[i].x2 - pBox[i].x1; - pRects[i].height = pBox[i].y2 - pBox[i].y1; - } - - XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc, - pGC->clipOrg.x, pGC->clipOrg.y, - pRects, nRects, Unsorted); - - xfree(pRects); - } - break; - - case CT_PIXMAP: - case CT_UNSORTED: - case CT_YSORTED: - case CT_YXSORTED: - case CT_YXBANDED: - /* These clip types are condensed down to either NONE or REGION - in the mi code */ - break; - } - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Destroy a GC's clip rects. */ -void dmxDestroyClip(GCPtr pGC) -{ - ScreenPtr pScreen = pGC->pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); - - DMX_GC_FUNC_PROLOGUE(pGC); - pGC->funcs->DestroyClip(pGC); - - /* Set the client clip on the back-end server to None */ - if (dmxScreen->beDisplay) - XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); - - DMX_GC_FUNC_EPILOGUE(pGC); -} - -/** Copy a GC's clip rects. */ -void dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc) -{ - DMX_GC_FUNC_PROLOGUE(pGCDst); - pGCDst->funcs->CopyClip(pGCDst, pGCSrc); - DMX_GC_FUNC_EPILOGUE(pGCDst); -} +/* + * Copyright 2001-2004 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: + * Kevin E. Martin + * + */ + +/** \file + * This file provides support for GCs. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxgc.h" +#include "dmxgcops.h" +#include "dmxpixmap.h" +#include "dmxfont.h" + +#include "gcstruct.h" +#include "pixmapstr.h" +#include "migc.h" + +static GCFuncs dmxGCFuncs = { + dmxValidateGC, + dmxChangeGC, + dmxCopyGC, + dmxDestroyGC, + dmxChangeClip, + dmxDestroyClip, + dmxCopyClip, +}; + +static GCOps dmxGCOps = { + dmxFillSpans, + dmxSetSpans, + dmxPutImage, + dmxCopyArea, + dmxCopyPlane, + dmxPolyPoint, + dmxPolylines, + dmxPolySegment, + dmxPolyRectangle, + dmxPolyArc, + dmxFillPolygon, + dmxPolyFillRect, + dmxPolyFillArc, + dmxPolyText8, + dmxPolyText16, + dmxImageText8, + dmxImageText16, + dmxImageGlyphBlt, + dmxPolyGlyphBlt, + dmxPushPixels +}; + +/** Initialize the GC on \a pScreen */ +Bool dmxInitGC(ScreenPtr pScreen) +{ + if (!dixRequestPrivate(dmxGCPrivateKey, sizeof(dmxGCPrivRec))) + return FALSE; + return TRUE; +} + +/** Create the GC on the back-end server. */ +void dmxBECreateGC(ScreenPtr pScreen, GCPtr pGC) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + int i; + + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + if (pGC->depth == dmxScreen->bePixmapFormats[i].depth) { + unsigned long mask; + XGCValues gcvals; + + mask = GCGraphicsExposures; + gcvals.graphics_exposures = FALSE; + + /* Create GC in the back-end servers */ + pGCPriv->gc = XCreateGC(dmxScreen->beDisplay, + dmxScreen->scrnDefDrawables[i], + mask, &gcvals); + break; + } + } +} + +/** Create a graphics context on the back-end server associated /a pGC's + * screen. */ +Bool dmxCreateGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + Bool ret; + + DMX_UNWRAP(CreateGC, dmxScreen, pScreen); + if ((ret = pScreen->CreateGC(pGC))) { + /* Save the old funcs */ + pGCPriv->funcs = pGC->funcs; + pGCPriv->ops = NULL; + + pGC->funcs = &dmxGCFuncs; + + if (dmxScreen->beDisplay) { + dmxBECreateGC(pScreen, pGC); + } else { + pGCPriv->gc = NULL; + } + + /* Check for "magic special case" + * 1. see CreateGC in dix/gc.c for more info + * 2. see dmxChangeGC for more info + */ + pGCPriv->msc = (!pGC->tileIsPixel && !pGC->tile.pixmap); + } + DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); + + return ret; +} + +/** Validate a graphics context, \a pGC, locally in the DMX server and + * recompute the composite clip, if necessary. */ +void dmxValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + + DMX_GC_FUNC_PROLOGUE(pGC); +#if 0 + pGC->funcs->ValidateGC(pGC, changes, pDrawable); +#endif + + if (pDrawable->type == DRAWABLE_WINDOW || + pDrawable->type == DRAWABLE_PIXMAP) { + /* Save the old ops, since we're about to change the ops in the + * epilogue. + */ + pGCPriv->ops = pGC->ops; + } else { + pGCPriv->ops = NULL; + } + + /* If the client clip is different or moved OR the subwindowMode has + * changed OR the window's clip has changed since the last + * validation, then we need to recompute the composite clip. + */ + if ((changes & (GCClipXOrigin | + GCClipYOrigin | + GCClipMask | + GCSubwindowMode)) || + (pDrawable->serialNumber != + (pGC->serialNumber & DRAWABLE_SERIAL_BITS))) { + miComputeCompositeClip(pGC, pDrawable); + } + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Set the values in the graphics context on the back-end server + * associated with \a pGC's screen. */ +void dmxChangeGC(GCPtr pGC, unsigned long mask) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + XGCValues v; + + DMX_GC_FUNC_PROLOGUE(pGC); +#if 0 + pGC->funcs->ChangeGC(pGC, mask); +#endif + + /* Handle "magic special case" from CreateGC */ + if (pGCPriv->msc) { + /* The "magic special case" is used to handle the case where a + * foreground pixel is set when the GC is created so that a + * "pseudo default-tile" can be created and used in case the + * fillstyle was set to FillTiled. This specific case is tested + * in xtest (XCreateGC test #3). What has happened in dix by + * the time it reaches here is (1) the pGC->tile.pixel has been + * set to pGC->fgPixel and pGC->tileIsPixel is set, (2) if a + * tile has also been set, then pGC->tileIsPixel is unset and + * pGC->tile.pixmap is initialized; else, the default tile is + * created and pGC->tileIsPixel is unset and pGC->tile.pixmap is + * initialized to the "pseudo default-tile". In either case, + * pGC->tile.pixmap is set; however, in the "magic special case" + * the mask is not updated to allow us to detect that we should + * initialize the GCTile in the back-end server. Thus, we catch + * this case in dmxCreateGC and add GCTile to the mask here. + * Are there any cases that I've missed? + */ + + /* Make sure that the tile.pixmap is set, just in case the user + * set GCTile in the mask but forgot to set vals.pixmap + */ + if (pGC->tile.pixmap) mask |= GCTile; + + /* This only happens once when the GC is created */ + pGCPriv->msc = FALSE; + } + + /* Update back-end server's gc */ + if (mask & GCFunction) v.function = pGC->alu; + if (mask & GCPlaneMask) v.plane_mask = pGC->planemask; + if (mask & GCForeground) v.foreground = pGC->fgPixel; + if (mask & GCBackground) v.background = pGC->bgPixel; + if (mask & GCLineWidth) v.line_width = pGC->lineWidth; + if (mask & GCLineStyle) v.line_style = pGC->lineStyle; + if (mask & GCCapStyle) v.cap_style = pGC->capStyle; + if (mask & GCJoinStyle) v.join_style = pGC->joinStyle; + if (mask & GCFillStyle) v.fill_style = pGC->fillStyle; + if (mask & GCFillRule) v.fill_rule = pGC->fillRule; + if (mask & GCTile) { + if (pGC->tileIsPixel) { + mask &= ~GCTile; + } else { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->tile.pixmap); + v.tile = (Drawable)pPixPriv->pixmap; + } + } + if (mask & GCStipple) { + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pGC->stipple); + v.stipple = (Drawable)pPixPriv->pixmap; + } + if (mask & GCTileStipXOrigin) v.ts_x_origin = pGC->patOrg.x; + if (mask & GCTileStipYOrigin) v.ts_y_origin = pGC->patOrg.y; + if (mask & GCFont) { + if (dmxScreen->beDisplay) { + dmxFontPrivPtr pFontPriv; + pFontPriv = FontGetPrivate(pGC->font, dmxFontPrivateIndex); + v.font = pFontPriv->font[pScreen->myNum]->fid; + } else { + mask &= ~GCFont; + } + } + if (mask & GCSubwindowMode) v.subwindow_mode = pGC->subWindowMode; + + /* Graphics exposures are not needed on the back-ends since they can + be generated on the front-end thereby saving bandwidth. */ + if (mask & GCGraphicsExposures) mask &= ~GCGraphicsExposures; + + if (mask & GCClipXOrigin) v.clip_x_origin = pGC->clipOrg.x; + if (mask & GCClipYOrigin) v.clip_y_origin = pGC->clipOrg.y; + if (mask & GCClipMask) mask &= ~GCClipMask; /* See ChangeClip */ + if (mask & GCDashOffset) v.dash_offset = pGC->dashOffset; + if (mask & GCDashList) { + mask &= ~GCDashList; + if (dmxScreen->beDisplay) + XSetDashes(dmxScreen->beDisplay, pGCPriv->gc, + pGC->dashOffset, (char *)pGC->dash, + pGC->numInDashList); + } + if (mask & GCArcMode) v.arc_mode = pGC->arcMode; + + if (mask && dmxScreen->beDisplay) { + XChangeGC(dmxScreen->beDisplay, pGCPriv->gc, mask, &v); + dmxSync(dmxScreen, FALSE); + } + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Copy \a pGCSrc to \a pGCDst on the back-end server associated with + * \a pGCSrc's screen. */ +void dmxCopyGC(GCPtr pGCSrc, unsigned long changes, GCPtr pGCDst) +{ + ScreenPtr pScreen = pGCSrc->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCSrcPriv = DMX_GET_GC_PRIV(pGCSrc); + dmxGCPrivPtr pGCDstPriv = DMX_GET_GC_PRIV(pGCDst); + + DMX_GC_FUNC_PROLOGUE(pGCDst); + pGCDst->funcs->CopyGC(pGCSrc, changes, pGCDst); + + /* Copy the GC on the back-end server */ + if (dmxScreen->beDisplay) + XCopyGC(dmxScreen->beDisplay, pGCSrcPriv->gc, changes, pGCDstPriv->gc); + + DMX_GC_FUNC_EPILOGUE(pGCDst); +} + +/** Free the \a pGC on the back-end server. */ +Bool dmxBEFreeGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + + if (pGCPriv->gc) { + XFreeGC(dmxScreen->beDisplay, pGCPriv->gc); + pGCPriv->gc = NULL; + return TRUE; + } + + return FALSE; +} + +/** Destroy the graphics context, \a pGC and free the corresponding GC + * on the back-end server. */ +void dmxDestroyGC(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + DMX_GC_FUNC_PROLOGUE(pGC); + + /* Free the GC on the back-end server */ + if (dmxScreen->beDisplay) + dmxBEFreeGC(pGC); + + pGC->funcs->DestroyGC(pGC); + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Change the clip rects for a GC. */ +void dmxChangeClip(GCPtr pGC, int type, pointer pvalue, int nrects) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + XRectangle *pRects; + BoxPtr pBox; + int i, nRects; + + DMX_GC_FUNC_PROLOGUE(pGC); + pGC->funcs->ChangeClip(pGC, type, pvalue, nrects); + + /* Set the client clip on the back-end server */ + switch (pGC->clientClipType) { + case CT_NONE: + if (dmxScreen->beDisplay) + XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); + break; + + case CT_REGION: + if (dmxScreen->beDisplay) { + nRects = REGION_NUM_RECTS((RegionPtr)pGC->clientClip); + pRects = malloc(nRects * sizeof(*pRects)); + pBox = REGION_RECTS((RegionPtr)pGC->clientClip); + + for (i = 0; i < nRects; i++) { + pRects[i].x = pBox[i].x1; + pRects[i].y = pBox[i].y1; + pRects[i].width = pBox[i].x2 - pBox[i].x1; + pRects[i].height = pBox[i].y2 - pBox[i].y1; + } + + XSetClipRectangles(dmxScreen->beDisplay, pGCPriv->gc, + pGC->clipOrg.x, pGC->clipOrg.y, + pRects, nRects, Unsorted); + + free(pRects); + } + break; + + case CT_PIXMAP: + case CT_UNSORTED: + case CT_YSORTED: + case CT_YXSORTED: + case CT_YXBANDED: + /* These clip types are condensed down to either NONE or REGION + in the mi code */ + break; + } + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Destroy a GC's clip rects. */ +void dmxDestroyClip(GCPtr pGC) +{ + ScreenPtr pScreen = pGC->pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxGCPrivPtr pGCPriv = DMX_GET_GC_PRIV(pGC); + + DMX_GC_FUNC_PROLOGUE(pGC); + pGC->funcs->DestroyClip(pGC); + + /* Set the client clip on the back-end server to None */ + if (dmxScreen->beDisplay) + XSetClipMask(dmxScreen->beDisplay, pGCPriv->gc, None); + + DMX_GC_FUNC_EPILOGUE(pGC); +} + +/** Copy a GC's clip rects. */ +void dmxCopyClip(GCPtr pGCDst, GCPtr pGCSrc) +{ + DMX_GC_FUNC_PROLOGUE(pGCDst); + pGCDst->funcs->CopyClip(pGCDst, pGCSrc); + DMX_GC_FUNC_EPILOGUE(pGCDst); +} diff --git a/xorg-server/hw/dmx/dmxinit.c b/xorg-server/hw/dmx/dmxinit.c index 617ec5e49..37b302a25 100644 --- a/xorg-server/hw/dmx/dmxinit.c +++ b/xorg-server/hw/dmx/dmxinit.c @@ -412,7 +412,7 @@ void dmxGetColormaps(DMXScreenInfo *dmxScreen) int i; dmxScreen->beNumDefColormaps = dmxScreen->beNumVisuals; - dmxScreen->beDefColormaps = xalloc(dmxScreen->beNumDefColormaps * + dmxScreen->beDefColormaps = malloc(dmxScreen->beNumDefColormaps * sizeof(*dmxScreen->beDefColormaps)); for (i = 0; i < dmxScreen->beNumDefColormaps; i++) @@ -738,7 +738,7 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) nconfigs = dmxScreen->numGlxVisuals; } - configprivs = xalloc(nconfigs * sizeof(dmxGlxVisualPrivate*)); + configprivs = malloc(nconfigs * sizeof(dmxGlxVisualPrivate*)); if (configs != NULL && configprivs != NULL) { @@ -748,7 +748,7 @@ void InitOutput(ScreenInfo *pScreenInfo, int argc, char *argv[]) for (i = 0; i < nconfigs; i++) { configprivs[i] = (dmxGlxVisualPrivate *) - xalloc(sizeof(dmxGlxVisualPrivate)); + malloc(sizeof(dmxGlxVisualPrivate)); configprivs[i]->x_visual_depth = 0; configprivs[i]->x_visual_class = 0; @@ -816,11 +816,11 @@ static void dmxSetDefaultFontPath(char *fp) int len; len = strlen(dmxFontPath); - dmxFontPath = xrealloc(dmxFontPath, len+fplen+1); + dmxFontPath = realloc(dmxFontPath, len+fplen+1); dmxFontPath[len] = ','; strncpy(&dmxFontPath[len+1], fp, fplen); } else { - dmxFontPath = xalloc(fplen); + dmxFontPath = malloc(fplen); strncpy(dmxFontPath, fp, fplen); } diff --git a/xorg-server/hw/dmx/dmxpict.c b/xorg-server/hw/dmx/dmxpict.c index efb2e41c9..c7bcd5b91 100644 --- a/xorg-server/hw/dmx/dmxpict.c +++ b/xorg-server/hw/dmx/dmxpict.c @@ -274,7 +274,7 @@ static int dmxProcRenderCreateGlyphSet(ClientPtr client) glyphSet = SecurityLookupIDByType(client, stuff->gsid, GlyphSetType, DixDestroyAccess); - glyphPriv = xalloc(sizeof(dmxGlyphPrivRec)); + glyphPriv = malloc(sizeof(dmxGlyphPrivRec)); if (!glyphPriv) return BadAlloc; glyphPriv->glyphSets = NULL; MAXSCREENSALLOC_RETURN(glyphPriv->glyphSets, BadAlloc); @@ -331,7 +331,7 @@ static int dmxProcRenderFreeGlyphSet(ClientPtr client) } MAXSCREENSFREE(glyphPriv->glyphSets); - xfree(glyphPriv); + free(glyphPriv); DMX_SET_GLYPH_PRIV(glyphSet, NULL); } @@ -369,7 +369,7 @@ static int dmxProcRenderAddGlyphs(ClientPtr client) sizeof(xRenderAddGlyphsReq) - (sizeof(CARD32) + sizeof(xGlyphInfo)) * nglyphs); - gidsCopy = xalloc(sizeof(*gidsCopy) * nglyphs); + gidsCopy = malloc(sizeof(*gidsCopy) * nglyphs); for (i = 0; i < nglyphs; i++) gidsCopy[i] = gids[i]; /* FIXME: Will this ever fail? */ @@ -387,7 +387,7 @@ static int dmxProcRenderAddGlyphs(ClientPtr client) dmxSync(dmxScreen, FALSE); } } - xfree(gidsCopy); + free(gidsCopy); } return ret; @@ -411,7 +411,7 @@ static int dmxProcRenderFreeGlyphs(ClientPtr client) nglyphs = ((client->req_len << 2) - sizeof(xRenderFreeGlyphsReq)) >> 2; if (nglyphs) { - gids = xalloc(sizeof(*gids) * nglyphs); + gids = malloc(sizeof(*gids) * nglyphs); for (i = 0; i < nglyphs; i++) gids[i] = ((CARD32 *)(stuff + 1))[i]; @@ -424,7 +424,7 @@ static int dmxProcRenderFreeGlyphs(ClientPtr client) dmxSync(dmxScreen, FALSE); } } - xfree(gids); + free(gids); } } @@ -531,13 +531,13 @@ static int dmxProcRenderCompositeGlyphs(ClientPtr client) /* The following only works for Render version > 0.2 */ /* All of the XGlyphElt* structure sizes are identical */ - elts = xalloc(nelt * sizeof(XGlyphElt8)); + elts = malloc(nelt * sizeof(XGlyphElt8)); if (!elts) return BadAlloc; - glyphs = xalloc(nglyph * size); + glyphs = malloc(nglyph * size); if (!glyphs) { - xfree(elts); + free(elts); return BadAlloc; } @@ -605,8 +605,8 @@ static int dmxProcRenderCompositeGlyphs(ClientPtr client) dmxSync(dmxScreen, FALSE); - xfree(elts); - xfree(glyphs); + free(elts); + free(glyphs); } return ret; @@ -878,7 +878,7 @@ int dmxChangePictureClip(PicturePtr pPicture, int clipType, int nRects; nRects = nBox; - pRects = pRect = xalloc(nRects * sizeof(*pRect)); + pRects = pRect = malloc(nRects * sizeof(*pRect)); while (nBox--) { pRect->x = pBox->x1; @@ -894,7 +894,7 @@ int dmxChangePictureClip(PicturePtr pPicture, int clipType, 0, 0, pRects, nRects); - xfree(pRects); + free(pRects); } else { XRenderSetPictureClipRectangles(dmxScreen->beDisplay, pPictPriv->pict, diff --git a/xorg-server/hw/dmx/dmxpixmap.c b/xorg-server/hw/dmx/dmxpixmap.c index 66224031a..bcbcc3a88 100644 --- a/xorg-server/hw/dmx/dmxpixmap.c +++ b/xorg-server/hw/dmx/dmxpixmap.c @@ -1,253 +1,253 @@ -/* - * Copyright 2001-2004 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: - * Kevin E. Martin - * - */ - -/** \file - * Provides pixmap support. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxpixmap.h" - -#include "pixmapstr.h" -#include "servermd.h" -#include "privates.h" - -/** Initialize a private area in \a pScreen for pixmap information. */ -Bool dmxInitPixmap(ScreenPtr pScreen) -{ - if (!dixRequestPrivate(dmxPixPrivateKey, sizeof(dmxPixPrivRec))) - return FALSE; - - return TRUE; -} - -/** Create a pixmap on the back-end server. */ -void dmxBECreatePixmap(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - - /* Make sure we haven't already created this pixmap. This can - * happen when the pixmap is used elsewhere (e.g., as a background - * or border for a window) and the refcnt > 1. - */ - if (pPixPriv->pixmap) - return; - - if (pPixmap->drawable.width && pPixmap->drawable.height) { - pPixPriv->pixmap = XCreatePixmap(dmxScreen->beDisplay, - dmxScreen->scrnWin, - pPixmap->drawable.width, - pPixmap->drawable.height, - pPixmap->drawable.depth); - dmxSync(dmxScreen, FALSE); - } -} - -/** Create a pixmap for \a pScreen with the specified \a width, \a - * height, and \a depth. */ -PixmapPtr dmxCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, - unsigned usage_hint) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - PixmapPtr pPixmap; - int bpp; - dmxPixPrivPtr pPixPriv; - -#if 0 - DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); - if (pScreen->CreatePixmap) - ret = pScreen->CreatePixmap(pPixmap); -#endif - - /* Create pixmap on back-end server */ - if (depth == 24) bpp = 32; - else bpp = depth; - - pPixmap = AllocatePixmap(pScreen, 0); - if (!pPixmap) - return NullPixmap; - - pPixmap->drawable.type = DRAWABLE_PIXMAP; - pPixmap->drawable.class = 0; - pPixmap->drawable.pScreen = pScreen; - pPixmap->drawable.depth = depth; - pPixmap->drawable.bitsPerPixel = bpp; - pPixmap->drawable.id = 0; - pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; - pPixmap->drawable.x = 0; - pPixmap->drawable.y = 0; - pPixmap->drawable.width = width; - pPixmap->drawable.height = height; - pPixmap->devKind = PixmapBytePad(width, bpp); - pPixmap->refcnt = 1; - pPixmap->usage_hint = usage_hint; - - pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - pPixPriv->pixmap = (Pixmap)0; - pPixPriv->detachedImage = NULL; - - /* Create the pixmap on the back-end server */ - if (dmxScreen->beDisplay) { - dmxBECreatePixmap(pPixmap); - } - -#if 0 - DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); -#endif - - return pPixmap; -} - -/** Destroy the pixmap on the back-end server. */ -Bool dmxBEFreePixmap(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - - if (pPixPriv->pixmap) { - XFreePixmap(dmxScreen->beDisplay, pPixPriv->pixmap); - pPixPriv->pixmap = (Pixmap)0; - return TRUE; - } - - return FALSE; -} - -/** Destroy the pixmap pointed to by \a pPixmap. */ -Bool dmxDestroyPixmap(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - -#if 0 - DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); -#endif - - if (--pPixmap->refcnt) - return TRUE; - - /* Destroy pixmap on back-end server */ - if (dmxScreen->beDisplay) { - if (dmxBEFreePixmap(pPixmap)) { - /* Also make sure that we destroy any detached image */ - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - if (pPixPriv->detachedImage) - XDestroyImage(pPixPriv->detachedImage); - dmxSync(dmxScreen, FALSE); - } - } - dixFreePrivates(pPixmap->devPrivates); - xfree(pPixmap); - -#if 0 - if (pScreen->DestroyPixmap) - ret = pScreen->DestroyPixmap(pPixmap); - DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); -#endif - - return ret; -} - -/** Create and return a region based on the pixmap pointed to by \a - * pPixmap. */ -RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap) -{ - ScreenPtr pScreen = pPixmap->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); - XImage *ximage; - RegionPtr pReg, pTmpReg; - int x, y; - unsigned long previousPixel, currentPixel; - BoxRec Box; - Bool overlap; - - if (!dmxScreen->beDisplay) { - pReg = REGION_CREATE(pScreen, NullBox, 1); - return pReg; - } - - ximage = XGetImage(dmxScreen->beDisplay, pPixPriv->pixmap, 0, 0, - pPixmap->drawable.width, pPixmap->drawable.height, - 1, XYPixmap); - - pReg = REGION_CREATE(pScreen, NullBox, 1); - pTmpReg = REGION_CREATE(pScreen, NullBox, 1); - if(!pReg || !pTmpReg) { - XDestroyImage(ximage); - return NullRegion; - } - - for (y = 0; y < pPixmap->drawable.height; y++) { - Box.y1 = y; - Box.y2 = y + 1; - previousPixel = 0L; - for (x = 0; x < pPixmap->drawable.width; x++) { - currentPixel = XGetPixel(ximage, x, y); - if (previousPixel != currentPixel) { - if (previousPixel == 0L) { - /* left edge */ - Box.x1 = x; - } else if (currentPixel == 0L) { - /* right edge */ - Box.x2 = x; - REGION_RESET(pScreen, pTmpReg, &Box); - REGION_APPEND(pScreen, pReg, pTmpReg); - } - previousPixel = currentPixel; - } - } - if (previousPixel != 0L) { - /* right edge because of the end of pixmap */ - Box.x2 = pPixmap->drawable.width; - REGION_RESET(pScreen, pTmpReg, &Box); - REGION_APPEND(pScreen, pReg, pTmpReg); - } - } - - REGION_DESTROY(pScreen, pTmpReg); - XDestroyImage(ximage); - - REGION_VALIDATE(pScreen, pReg, &overlap); - - dmxSync(dmxScreen, FALSE); - return(pReg); -} +/* + * Copyright 2001-2004 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: + * Kevin E. Martin + * + */ + +/** \file + * Provides pixmap support. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxpixmap.h" + +#include "pixmapstr.h" +#include "servermd.h" +#include "privates.h" + +/** Initialize a private area in \a pScreen for pixmap information. */ +Bool dmxInitPixmap(ScreenPtr pScreen) +{ + if (!dixRequestPrivate(dmxPixPrivateKey, sizeof(dmxPixPrivRec))) + return FALSE; + + return TRUE; +} + +/** Create a pixmap on the back-end server. */ +void dmxBECreatePixmap(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + + /* Make sure we haven't already created this pixmap. This can + * happen when the pixmap is used elsewhere (e.g., as a background + * or border for a window) and the refcnt > 1. + */ + if (pPixPriv->pixmap) + return; + + if (pPixmap->drawable.width && pPixmap->drawable.height) { + pPixPriv->pixmap = XCreatePixmap(dmxScreen->beDisplay, + dmxScreen->scrnWin, + pPixmap->drawable.width, + pPixmap->drawable.height, + pPixmap->drawable.depth); + dmxSync(dmxScreen, FALSE); + } +} + +/** Create a pixmap for \a pScreen with the specified \a width, \a + * height, and \a depth. */ +PixmapPtr dmxCreatePixmap(ScreenPtr pScreen, int width, int height, int depth, + unsigned usage_hint) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + PixmapPtr pPixmap; + int bpp; + dmxPixPrivPtr pPixPriv; + +#if 0 + DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); + if (pScreen->CreatePixmap) + ret = pScreen->CreatePixmap(pPixmap); +#endif + + /* Create pixmap on back-end server */ + if (depth == 24) bpp = 32; + else bpp = depth; + + pPixmap = AllocatePixmap(pScreen, 0); + if (!pPixmap) + return NullPixmap; + + pPixmap->drawable.type = DRAWABLE_PIXMAP; + pPixmap->drawable.class = 0; + pPixmap->drawable.pScreen = pScreen; + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = bpp; + pPixmap->drawable.id = 0; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->devKind = PixmapBytePad(width, bpp); + pPixmap->refcnt = 1; + pPixmap->usage_hint = usage_hint; + + pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + pPixPriv->pixmap = (Pixmap)0; + pPixPriv->detachedImage = NULL; + + /* Create the pixmap on the back-end server */ + if (dmxScreen->beDisplay) { + dmxBECreatePixmap(pPixmap); + } + +#if 0 + DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); +#endif + + return pPixmap; +} + +/** Destroy the pixmap on the back-end server. */ +Bool dmxBEFreePixmap(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + + if (pPixPriv->pixmap) { + XFreePixmap(dmxScreen->beDisplay, pPixPriv->pixmap); + pPixPriv->pixmap = (Pixmap)0; + return TRUE; + } + + return FALSE; +} + +/** Destroy the pixmap pointed to by \a pPixmap. */ +Bool dmxDestroyPixmap(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + +#if 0 + DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); +#endif + + if (--pPixmap->refcnt) + return TRUE; + + /* Destroy pixmap on back-end server */ + if (dmxScreen->beDisplay) { + if (dmxBEFreePixmap(pPixmap)) { + /* Also make sure that we destroy any detached image */ + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + if (pPixPriv->detachedImage) + XDestroyImage(pPixPriv->detachedImage); + dmxSync(dmxScreen, FALSE); + } + } + dixFreePrivates(pPixmap->devPrivates); + free(pPixmap); + +#if 0 + if (pScreen->DestroyPixmap) + ret = pScreen->DestroyPixmap(pPixmap); + DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); +#endif + + return ret; +} + +/** Create and return a region based on the pixmap pointed to by \a + * pPixmap. */ +RegionPtr dmxBitmapToRegion(PixmapPtr pPixmap) +{ + ScreenPtr pScreen = pPixmap->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxPixPrivPtr pPixPriv = DMX_GET_PIXMAP_PRIV(pPixmap); + XImage *ximage; + RegionPtr pReg, pTmpReg; + int x, y; + unsigned long previousPixel, currentPixel; + BoxRec Box; + Bool overlap; + + if (!dmxScreen->beDisplay) { + pReg = REGION_CREATE(pScreen, NullBox, 1); + return pReg; + } + + ximage = XGetImage(dmxScreen->beDisplay, pPixPriv->pixmap, 0, 0, + pPixmap->drawable.width, pPixmap->drawable.height, + 1, XYPixmap); + + pReg = REGION_CREATE(pScreen, NullBox, 1); + pTmpReg = REGION_CREATE(pScreen, NullBox, 1); + if(!pReg || !pTmpReg) { + XDestroyImage(ximage); + return NullRegion; + } + + for (y = 0; y < pPixmap->drawable.height; y++) { + Box.y1 = y; + Box.y2 = y + 1; + previousPixel = 0L; + for (x = 0; x < pPixmap->drawable.width; x++) { + currentPixel = XGetPixel(ximage, x, y); + if (previousPixel != currentPixel) { + if (previousPixel == 0L) { + /* left edge */ + Box.x1 = x; + } else if (currentPixel == 0L) { + /* right edge */ + Box.x2 = x; + REGION_RESET(pScreen, pTmpReg, &Box); + REGION_APPEND(pScreen, pReg, pTmpReg); + } + previousPixel = currentPixel; + } + } + if (previousPixel != 0L) { + /* right edge because of the end of pixmap */ + Box.x2 = pPixmap->drawable.width; + REGION_RESET(pScreen, pTmpReg, &Box); + REGION_APPEND(pScreen, pReg, pTmpReg); + } + } + + REGION_DESTROY(pScreen, pTmpReg); + XDestroyImage(ximage); + + REGION_VALIDATE(pScreen, pReg, &overlap); + + dmxSync(dmxScreen, FALSE); + return(pReg); +} diff --git a/xorg-server/hw/dmx/dmxprop.c b/xorg-server/hw/dmx/dmxprop.c index 376313d8d..95efcb0e0 100644 --- a/xorg-server/hw/dmx/dmxprop.c +++ b/xorg-server/hw/dmx/dmxprop.c @@ -1,347 +1,347 @@ -/* - * Copyright 2002-2003 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: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * - * It is possible for one of the DMX "backend displays" to actually be - * smaller than the dimensions of the backend X server. Therefore, it - * is possible for more than one of the DMX "backend displays" to be - * physically located on the same backend X server. This situation must - * be detected so that cursor motion can be handled in an expected - * fashion. - * - * We could analyze the names used for the DMX "backend displays" (e.g., - * the names passed to the -display command-line parameter), but there - * are many possible names for a single X display, and failing to detect - * sameness leads to very unexpected results. Therefore, whenever the - * DMX server opens a window on a backend X server, a property value is - * queried and set on that backend to detect when another window is - * already open on that server. - * - * Further, it is possible that two different DMX server instantiations - * both have windows on the same physical backend X server. This case - * is also detected so that pointer input is not taken from that - * particular backend X server. - * - * The routines in this file handle the property management. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxprop.h" -#include "dmxlog.h" - -/** Holds the window id of all DMX windows on the backend X server. */ -#define DMX_ATOMNAME "DMX_NAME" - -/** The identification string of this DMX server */ -#define DMX_IDENT "Xdmx" - -extern char *display; - -static int dmxPropertyErrorHandler(Display *dpy, XErrorEvent *ev) -{ - return 0; -} - -static const unsigned char *dmxPropertyIdentifier(void) -{ - /* RATS: These buffers are only used in - * length-limited calls. */ - char hostname[256]; - static char buf[128]; - static int initialized = 0; - - if (initialized++) return (unsigned char *)buf; - - XmuGetHostname(hostname, sizeof(hostname)); - XmuSnprintf(buf, sizeof(buf), "%s:%s:%s", DMX_IDENT, hostname, display); - return (unsigned char *)buf; -} - -/** Starting with the \a start screen, iterate over all of the screens - * on the same physical X server as \a start, calling \a f with the - * screen and the \a closure. (The common case is that \a start is the - * only DMX window on the backend X server.) */ -void *dmxPropertyIterate(DMXScreenInfo *start, - void *(*f)(DMXScreenInfo *dmxScreen, void *), - void *closure) -{ - DMXScreenInfo *pt; - - if (!start->next) { - if (!start->beDisplay) return NULL; - return f(start, closure); - } - - for (pt = start->next; /* condition at end of loop */; pt = pt->next) { - void *retval; - /* beDisplay ban be NULL if a screen was detached */ - dmxLog(dmxDebug, "pt = %p\n", pt); - dmxLog(dmxDebug, "pt->beDisplay = %p\n", pt->beDisplay); - if (pt->beDisplay && (retval = f(pt, closure))) return retval; - if (pt == start) break; - } - return NULL; -} - -/** Returns 0 if this is the only Xdmx session on the display; 1 - * otherwise. */ -static int dmxPropertyCheckOtherServers(DMXScreenInfo *dmxScreen, Atom atom) -{ - Display *dpy = dmxScreen->beDisplay; - XTextProperty tp; - XTextProperty tproot; - const char *pt; - int retcode = 0; - char **list = NULL; - int count = 0; - int i; - int (*dmxOldHandler)(Display *, XErrorEvent *); - - if (!dpy) - return 0; - - if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom) - || !tproot.nitems) return 0; - - /* Ignore BadWindow errors for this - * routine because the window id stored - * in the property might be old */ - dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler); - for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) { - if ((pt = strchr(pt, ','))) { - Window win = strtol(pt+1, NULL, 10); - if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) { - if (!strncmp((char *)tp.value, DMX_IDENT, strlen(DMX_IDENT))) { - int flag = 0; - for (i = 0; i < count; i++) - if (!strcmp(list[i], (char *)tp.value)) { - ++flag; - break; - } - if (flag) continue; - ++retcode; - dmxLogOutputWarning(dmxScreen, - "%s also running on %s\n", - tp.value, dmxScreen->name); - list = xrealloc(list, ++count * sizeof(*list)); - list[count-1] = xalloc(tp.nitems + 2); - strncpy(list[count-1], (char *)tp.value, tp.nitems + 1); - } - XFree(tp.value); - } - } - } - XSetErrorHandler(dmxOldHandler); - - for (i = 0; i < count; i++) xfree(list[i]); - xfree(list); - XFree(tproot.value); - if (!retcode) - dmxLogOutput(dmxScreen, "No Xdmx server running on backend\n"); - return retcode; -} - -/** Returns NULL if this is the only Xdmx window on the display. - * Otherwise, returns a pointer to the dmxScreen of the other windows on - * the display. */ -static DMXScreenInfo *dmxPropertyCheckOtherWindows(DMXScreenInfo *dmxScreen, - Atom atom) -{ - Display *dpy = dmxScreen->beDisplay; - const unsigned char *id = dmxPropertyIdentifier(); - XTextProperty tproot; - XTextProperty tp; - const char *pt; - int (*dmxOldHandler)(Display *, XErrorEvent *); - - if (!dpy) - return NULL; - - if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom) - || !tproot.nitems) return 0; - - /* Ignore BadWindow errors for this - * routine because the window id stored - * in the property might be old */ - dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler); - for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) { - if ((pt = strchr(pt, ','))) { - Window win = strtol(pt+1, NULL, 10); - if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) { - dmxLog(dmxDebug,"On %s/%lu: %s\n", - dmxScreen->name, win, tp.value); - if (!strncmp((char *)tp.value, (char *)id, - strlen((char *)id))) { - int idx; - - if (!(pt = strchr((char *)tp.value, ','))) continue; - idx = strtol(pt+1, NULL, 10); - if (idx < 0 || idx >= dmxNumScreens) continue; - if (dmxScreens[idx].scrnWin != win) continue; - XSetErrorHandler(dmxOldHandler); - return &dmxScreens[idx]; - } - XFree(tp.value); - } - } - } - XSetErrorHandler(dmxOldHandler); - XFree(tproot.value); - return 0; -} - -/** Returns 0 if this is the only Xdmx session on the display; 1 - * otherwise. */ -int dmxPropertyDisplay(DMXScreenInfo *dmxScreen) -{ - Atom atom; - const unsigned char *id = dmxPropertyIdentifier(); - Display *dpy = dmxScreen->beDisplay; - - if (!dpy) - return 0; - - atom = XInternAtom(dpy, DMX_ATOMNAME, False); - if (dmxPropertyCheckOtherServers(dmxScreen, atom)) { - dmxScreen->shared = 1; - return 1; - } - XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8, - PropModeReplace, id, strlen((char *)id)); - return 0; -} - -/** Returns 1 if the dmxScreen and the display in \a name are on the - * same display, or 0 otherwise. We can't just compare the display - * names because there can be multiple synonyms for the same display, - * some of which cannot be determined without accessing the display - * itself (e.g., domain aliases or machines with multiple NICs). */ -int dmxPropertySameDisplay(DMXScreenInfo *dmxScreen, const char *name) -{ - Display *dpy0 = dmxScreen->beDisplay; - Atom atom0; - XTextProperty tp0; - Display *dpy1 = NULL; - Atom atom1; - XTextProperty tp1; - int retval = 0; - - if (!dpy0) - return 0; - - tp0.nitems = 0; - tp1.nitems = 0; - - if ((atom0 = XInternAtom(dpy0, DMX_ATOMNAME, True)) == None) { - dmxLog(dmxWarning, "No atom on %s\n", dmxScreen->name); - return 0; - } - if (!XGetTextProperty(dpy0, RootWindow(dpy0,0), &tp0, atom0) - || !tp0.nitems) { - dmxLog(dmxWarning, "No text property on %s\n", dmxScreen->name); - return 0; - } - - if (!(dpy1 = XOpenDisplay(name))) { - dmxLog(dmxWarning, "Cannot open %s\n", name); - goto cleanup; - } - atom1 = XInternAtom(dpy1, DMX_ATOMNAME, True); - if (atom1 == None) { - dmxLog(dmxDebug, "No atom on %s\n", name); - goto cleanup; - } - if (!XGetTextProperty(dpy1, RootWindow(dpy1,0), &tp1, atom1) - || !tp1.nitems) { - dmxLog(dmxDebug, "No text property on %s\n", name); - goto cleanup; - } - if (!strcmp((char *)tp0.value, (char *)tp1.value)) retval = 1; - - cleanup: - if (tp0.nitems) XFree(tp0.value); - if (tp1.nitems) XFree(tp1.value); - if (dpy1) XCloseDisplay(dpy1); - return retval; -} - -/** Prints a log message if \a dmxScreen is on the same backend X server - * as some other DMX backend (output) screen. Modifies the property - * (#DMX_ATOMNAME) on the backend X server to reflect the creation of \a - * dmxScreen. - * - * The root window of the backend X server holds a list of window ids - * for all DMX windows (on this DMX server or some other DMX server). - * - * This list can then be iterated, and the property for each window can - * be examined. This property contains the following tuple (no quotes): - * - * "#DMX_IDENT::," - */ -void dmxPropertyWindow(DMXScreenInfo *dmxScreen) -{ - Atom atom; - const unsigned char *id = dmxPropertyIdentifier(); - Display *dpy = dmxScreen->beDisplay; - Window win = dmxScreen->scrnWin; - DMXScreenInfo *other; - char buf[128]; /* RATS: only used with XmuSnprintf */ - - if (!dpy) - return; /* FIXME: What should be done here if Xdmx is started - * with this screen initially detached? - */ - - atom = XInternAtom(dpy, DMX_ATOMNAME, False); - if ((other = dmxPropertyCheckOtherWindows(dmxScreen, atom))) { - DMXScreenInfo *tmp = dmxScreen->next; - dmxScreen->next = (other->next ? other->next : other); - other->next = (tmp ? tmp : dmxScreen); - dmxLog(dmxDebug, "%d/%s/%lu and %d/%s/%lu are on the same backend\n", - dmxScreen->index, dmxScreen->name, dmxScreen->scrnWin, - other->index, other->name, other->scrnWin); - } - - XmuSnprintf(buf, sizeof(buf), ".%d,%lu", dmxScreen->index, - (long unsigned)win); - XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8, - PropModeAppend, (unsigned char *)buf, strlen(buf)); - - XmuSnprintf(buf, sizeof(buf), "%s,%d", id, dmxScreen->index); - XChangeProperty(dpy, win, atom, XA_STRING, 8, - PropModeAppend, (unsigned char *)buf, strlen(buf)); -} +/* + * Copyright 2002-2003 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: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * + * It is possible for one of the DMX "backend displays" to actually be + * smaller than the dimensions of the backend X server. Therefore, it + * is possible for more than one of the DMX "backend displays" to be + * physically located on the same backend X server. This situation must + * be detected so that cursor motion can be handled in an expected + * fashion. + * + * We could analyze the names used for the DMX "backend displays" (e.g., + * the names passed to the -display command-line parameter), but there + * are many possible names for a single X display, and failing to detect + * sameness leads to very unexpected results. Therefore, whenever the + * DMX server opens a window on a backend X server, a property value is + * queried and set on that backend to detect when another window is + * already open on that server. + * + * Further, it is possible that two different DMX server instantiations + * both have windows on the same physical backend X server. This case + * is also detected so that pointer input is not taken from that + * particular backend X server. + * + * The routines in this file handle the property management. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxprop.h" +#include "dmxlog.h" + +/** Holds the window id of all DMX windows on the backend X server. */ +#define DMX_ATOMNAME "DMX_NAME" + +/** The identification string of this DMX server */ +#define DMX_IDENT "Xdmx" + +extern char *display; + +static int dmxPropertyErrorHandler(Display *dpy, XErrorEvent *ev) +{ + return 0; +} + +static const unsigned char *dmxPropertyIdentifier(void) +{ + /* RATS: These buffers are only used in + * length-limited calls. */ + char hostname[256]; + static char buf[128]; + static int initialized = 0; + + if (initialized++) return (unsigned char *)buf; + + XmuGetHostname(hostname, sizeof(hostname)); + XmuSnprintf(buf, sizeof(buf), "%s:%s:%s", DMX_IDENT, hostname, display); + return (unsigned char *)buf; +} + +/** Starting with the \a start screen, iterate over all of the screens + * on the same physical X server as \a start, calling \a f with the + * screen and the \a closure. (The common case is that \a start is the + * only DMX window on the backend X server.) */ +void *dmxPropertyIterate(DMXScreenInfo *start, + void *(*f)(DMXScreenInfo *dmxScreen, void *), + void *closure) +{ + DMXScreenInfo *pt; + + if (!start->next) { + if (!start->beDisplay) return NULL; + return f(start, closure); + } + + for (pt = start->next; /* condition at end of loop */; pt = pt->next) { + void *retval; + /* beDisplay ban be NULL if a screen was detached */ + dmxLog(dmxDebug, "pt = %p\n", pt); + dmxLog(dmxDebug, "pt->beDisplay = %p\n", pt->beDisplay); + if (pt->beDisplay && (retval = f(pt, closure))) return retval; + if (pt == start) break; + } + return NULL; +} + +/** Returns 0 if this is the only Xdmx session on the display; 1 + * otherwise. */ +static int dmxPropertyCheckOtherServers(DMXScreenInfo *dmxScreen, Atom atom) +{ + Display *dpy = dmxScreen->beDisplay; + XTextProperty tp; + XTextProperty tproot; + const char *pt; + int retcode = 0; + char **list = NULL; + int count = 0; + int i; + int (*dmxOldHandler)(Display *, XErrorEvent *); + + if (!dpy) + return 0; + + if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom) + || !tproot.nitems) return 0; + + /* Ignore BadWindow errors for this + * routine because the window id stored + * in the property might be old */ + dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler); + for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) { + if ((pt = strchr(pt, ','))) { + Window win = strtol(pt+1, NULL, 10); + if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) { + if (!strncmp((char *)tp.value, DMX_IDENT, strlen(DMX_IDENT))) { + int flag = 0; + for (i = 0; i < count; i++) + if (!strcmp(list[i], (char *)tp.value)) { + ++flag; + break; + } + if (flag) continue; + ++retcode; + dmxLogOutputWarning(dmxScreen, + "%s also running on %s\n", + tp.value, dmxScreen->name); + list = realloc(list, ++count * sizeof(*list)); + list[count-1] = malloc(tp.nitems + 2); + strncpy(list[count-1], (char *)tp.value, tp.nitems + 1); + } + XFree(tp.value); + } + } + } + XSetErrorHandler(dmxOldHandler); + + for (i = 0; i < count; i++) free(list[i]); + free(list); + XFree(tproot.value); + if (!retcode) + dmxLogOutput(dmxScreen, "No Xdmx server running on backend\n"); + return retcode; +} + +/** Returns NULL if this is the only Xdmx window on the display. + * Otherwise, returns a pointer to the dmxScreen of the other windows on + * the display. */ +static DMXScreenInfo *dmxPropertyCheckOtherWindows(DMXScreenInfo *dmxScreen, + Atom atom) +{ + Display *dpy = dmxScreen->beDisplay; + const unsigned char *id = dmxPropertyIdentifier(); + XTextProperty tproot; + XTextProperty tp; + const char *pt; + int (*dmxOldHandler)(Display *, XErrorEvent *); + + if (!dpy) + return NULL; + + if (!XGetTextProperty(dpy, RootWindow(dpy,0), &tproot, atom) + || !tproot.nitems) return 0; + + /* Ignore BadWindow errors for this + * routine because the window id stored + * in the property might be old */ + dmxOldHandler = XSetErrorHandler(dmxPropertyErrorHandler); + for (pt = (const char *)tproot.value; pt && *pt; pt = pt ? pt + 1 : NULL) { + if ((pt = strchr(pt, ','))) { + Window win = strtol(pt+1, NULL, 10); + if (XGetTextProperty(dpy, win, &tp, atom) && tp.nitems) { + dmxLog(dmxDebug,"On %s/%lu: %s\n", + dmxScreen->name, win, tp.value); + if (!strncmp((char *)tp.value, (char *)id, + strlen((char *)id))) { + int idx; + + if (!(pt = strchr((char *)tp.value, ','))) continue; + idx = strtol(pt+1, NULL, 10); + if (idx < 0 || idx >= dmxNumScreens) continue; + if (dmxScreens[idx].scrnWin != win) continue; + XSetErrorHandler(dmxOldHandler); + return &dmxScreens[idx]; + } + XFree(tp.value); + } + } + } + XSetErrorHandler(dmxOldHandler); + XFree(tproot.value); + return 0; +} + +/** Returns 0 if this is the only Xdmx session on the display; 1 + * otherwise. */ +int dmxPropertyDisplay(DMXScreenInfo *dmxScreen) +{ + Atom atom; + const unsigned char *id = dmxPropertyIdentifier(); + Display *dpy = dmxScreen->beDisplay; + + if (!dpy) + return 0; + + atom = XInternAtom(dpy, DMX_ATOMNAME, False); + if (dmxPropertyCheckOtherServers(dmxScreen, atom)) { + dmxScreen->shared = 1; + return 1; + } + XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8, + PropModeReplace, id, strlen((char *)id)); + return 0; +} + +/** Returns 1 if the dmxScreen and the display in \a name are on the + * same display, or 0 otherwise. We can't just compare the display + * names because there can be multiple synonyms for the same display, + * some of which cannot be determined without accessing the display + * itself (e.g., domain aliases or machines with multiple NICs). */ +int dmxPropertySameDisplay(DMXScreenInfo *dmxScreen, const char *name) +{ + Display *dpy0 = dmxScreen->beDisplay; + Atom atom0; + XTextProperty tp0; + Display *dpy1 = NULL; + Atom atom1; + XTextProperty tp1; + int retval = 0; + + if (!dpy0) + return 0; + + tp0.nitems = 0; + tp1.nitems = 0; + + if ((atom0 = XInternAtom(dpy0, DMX_ATOMNAME, True)) == None) { + dmxLog(dmxWarning, "No atom on %s\n", dmxScreen->name); + return 0; + } + if (!XGetTextProperty(dpy0, RootWindow(dpy0,0), &tp0, atom0) + || !tp0.nitems) { + dmxLog(dmxWarning, "No text property on %s\n", dmxScreen->name); + return 0; + } + + if (!(dpy1 = XOpenDisplay(name))) { + dmxLog(dmxWarning, "Cannot open %s\n", name); + goto cleanup; + } + atom1 = XInternAtom(dpy1, DMX_ATOMNAME, True); + if (atom1 == None) { + dmxLog(dmxDebug, "No atom on %s\n", name); + goto cleanup; + } + if (!XGetTextProperty(dpy1, RootWindow(dpy1,0), &tp1, atom1) + || !tp1.nitems) { + dmxLog(dmxDebug, "No text property on %s\n", name); + goto cleanup; + } + if (!strcmp((char *)tp0.value, (char *)tp1.value)) retval = 1; + + cleanup: + if (tp0.nitems) XFree(tp0.value); + if (tp1.nitems) XFree(tp1.value); + if (dpy1) XCloseDisplay(dpy1); + return retval; +} + +/** Prints a log message if \a dmxScreen is on the same backend X server + * as some other DMX backend (output) screen. Modifies the property + * (#DMX_ATOMNAME) on the backend X server to reflect the creation of \a + * dmxScreen. + * + * The root window of the backend X server holds a list of window ids + * for all DMX windows (on this DMX server or some other DMX server). + * + * This list can then be iterated, and the property for each window can + * be examined. This property contains the following tuple (no quotes): + * + * "#DMX_IDENT::," + */ +void dmxPropertyWindow(DMXScreenInfo *dmxScreen) +{ + Atom atom; + const unsigned char *id = dmxPropertyIdentifier(); + Display *dpy = dmxScreen->beDisplay; + Window win = dmxScreen->scrnWin; + DMXScreenInfo *other; + char buf[128]; /* RATS: only used with XmuSnprintf */ + + if (!dpy) + return; /* FIXME: What should be done here if Xdmx is started + * with this screen initially detached? + */ + + atom = XInternAtom(dpy, DMX_ATOMNAME, False); + if ((other = dmxPropertyCheckOtherWindows(dmxScreen, atom))) { + DMXScreenInfo *tmp = dmxScreen->next; + dmxScreen->next = (other->next ? other->next : other); + other->next = (tmp ? tmp : dmxScreen); + dmxLog(dmxDebug, "%d/%s/%lu and %d/%s/%lu are on the same backend\n", + dmxScreen->index, dmxScreen->name, dmxScreen->scrnWin, + other->index, other->name, other->scrnWin); + } + + XmuSnprintf(buf, sizeof(buf), ".%d,%lu", dmxScreen->index, + (long unsigned)win); + XChangeProperty(dpy, RootWindow(dpy,0), atom, XA_STRING, 8, + PropModeAppend, (unsigned char *)buf, strlen(buf)); + + XmuSnprintf(buf, sizeof(buf), "%s,%d", id, dmxScreen->index); + XChangeProperty(dpy, win, atom, XA_STRING, 8, + PropModeAppend, (unsigned char *)buf, strlen(buf)); +} diff --git a/xorg-server/hw/dmx/dmxscrinit.c b/xorg-server/hw/dmx/dmxscrinit.c index c1beb9ba5..edb14a23a 100644 --- a/xorg-server/hw/dmx/dmxscrinit.c +++ b/xorg-server/hw/dmx/dmxscrinit.c @@ -1,524 +1,524 @@ -/* - * Copyright 2001-2004 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: - * Kevin E. Martin - * David H. Dawes - * - */ - -/** \file - * This file provides support for screen initialization. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxshadow.h" -#include "dmxscrinit.h" -#include "dmxcursor.h" -#include "dmxgc.h" -#include "dmxgcops.h" -#include "dmxwindow.h" -#include "dmxpixmap.h" -#include "dmxfont.h" -#include "dmxcmap.h" -#include "dmxprop.h" -#include "dmxdpms.h" - -#include "dmxpict.h" - -#include "fb.h" -#include "mipointer.h" -#include "micmap.h" - -extern Bool dmxCloseScreen(int idx, ScreenPtr pScreen); -static Bool dmxSaveScreen(ScreenPtr pScreen, int what); - -static unsigned long dmxGeneration; -static unsigned long *dmxCursorGeneration; - -static int dmxGCPrivateKeyIndex; -DevPrivateKey dmxGCPrivateKey = &dmxGCPrivateKeyIndex; /**< Private index for GCs */ -static int dmxWinPrivateKeyIndex; -DevPrivateKey dmxWinPrivateKey = &dmxWinPrivateKeyIndex; /**< Private index for Windows */ -static int dmxPixPrivateKeyIndex; -DevPrivateKey dmxPixPrivateKey = &dmxPixPrivateKeyIndex; /**< Private index for Pixmaps */ -int dmxFontPrivateIndex; /**< Private index for Fonts */ -static int dmxScreenPrivateKeyIndex; -DevPrivateKey dmxScreenPrivateKey = &dmxScreenPrivateKeyIndex; /**< Private index for Screens */ -static int dmxColormapPrivateKeyIndex; -DevPrivateKey dmxColormapPrivateKey = &dmxColormapPrivateKeyIndex; /**< Private index for Colormaps */ -static int dmxPictPrivateKeyIndex; -DevPrivateKey dmxPictPrivateKey = &dmxPictPrivateKeyIndex; /**< Private index for Picts */ -static int dmxGlyphSetPrivateKeyIndex; -DevPrivateKey dmxGlyphSetPrivateKey = &dmxGlyphSetPrivateKeyIndex; /**< Private index for GlyphSets */ - -/** Initialize the parts of screen \a idx that require access to the - * back-end server. */ -void dmxBEScreenInit(int idx, ScreenPtr pScreen) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - XSetWindowAttributes attribs; - XGCValues gcvals; - unsigned long mask; - int i, j; - - /* FIXME: The dmxScreenInit() code currently assumes that it will - * not be called if the Xdmx server is started with this screen - * detached -- i.e., it assumes that dmxScreen->beDisplay is always - * valid. This is not necessarily a valid assumption when full - * addition/removal of screens is implemented, but when this code is - * broken out for screen reattachment, then we will reevaluate this - * assumption. - */ - - pScreen->mmWidth = DisplayWidthMM(dmxScreen->beDisplay, - DefaultScreen(dmxScreen->beDisplay)); - pScreen->mmHeight = DisplayHeightMM(dmxScreen->beDisplay, - DefaultScreen(dmxScreen->beDisplay)); - - pScreen->whitePixel = dmxScreen->beWhitePixel; - pScreen->blackPixel = dmxScreen->beBlackPixel; - - /* Handle screen savers and DPMS on the backend */ - dmxDPMSInit(dmxScreen); - - /* Create root window for screen */ - mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect; - attribs.background_pixel = dmxScreen->beBlackPixel; - attribs.event_mask = (KeyPressMask - | KeyReleaseMask - | ButtonPressMask - | ButtonReleaseMask - | EnterWindowMask - | LeaveWindowMask - | PointerMotionMask - | KeymapStateMask - | FocusChangeMask); - attribs.colormap = dmxScreen->beDefColormaps[dmxScreen->beDefVisualIndex]; - attribs.override_redirect = True; - - dmxScreen->scrnWin = - XCreateWindow(dmxScreen->beDisplay, - DefaultRootWindow(dmxScreen->beDisplay), - dmxScreen->scrnX, - dmxScreen->scrnY, - dmxScreen->scrnWidth, - dmxScreen->scrnHeight, - 0, - pScreen->rootDepth, - InputOutput, - dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, - mask, - &attribs); - dmxPropertyWindow(dmxScreen); - - /* - * This turns off the cursor by defining a cursor with no visible - * components. - */ - { - char noCursorData[] = {0, 0, 0, 0, - 0, 0, 0, 0}; - Pixmap pixmap; - XColor color, tmp; - - pixmap = XCreateBitmapFromData(dmxScreen->beDisplay, dmxScreen->scrnWin, - noCursorData, 8, 8); - XAllocNamedColor(dmxScreen->beDisplay, dmxScreen->beDefColormaps[0], - "black", &color, &tmp); - dmxScreen->noCursor = XCreatePixmapCursor(dmxScreen->beDisplay, - pixmap, pixmap, - &color, &color, 0, 0); - XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, - dmxScreen->noCursor); - - XFreePixmap(dmxScreen->beDisplay, pixmap); - } - - XMapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); - - if (dmxShadowFB) { - mask = (GCFunction - | GCPlaneMask - | GCClipMask); - gcvals.function = GXcopy; - gcvals.plane_mask = AllPlanes; - gcvals.clip_mask = None; - - dmxScreen->shadowGC = XCreateGC(dmxScreen->beDisplay, - dmxScreen->scrnWin, - mask, &gcvals); - - dmxScreen->shadowFBImage = - XCreateImage(dmxScreen->beDisplay, - dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, - dmxScreen->beDepth, - ZPixmap, - 0, - (char *)dmxScreen->shadow, - dmxScreen->scrnWidth, dmxScreen->scrnHeight, - dmxScreen->beBPP, - PixmapBytePad(dmxScreen->scrnWidth, - dmxScreen->beBPP)); - } else { - /* Create default drawables (used during GC creation) */ - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) - for (j = 0; j < dmxScreen->beNumDepths; j++) - if ((dmxScreen->bePixmapFormats[i].depth == 1) || - (dmxScreen->bePixmapFormats[i].depth == - dmxScreen->beDepths[j])) { - dmxScreen->scrnDefDrawables[i] = (Drawable) - XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, - 1, 1, dmxScreen->bePixmapFormats[i].depth); - break; - } - } -} - -/** Initialize screen number \a idx. */ -Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - int i, j; - - if (dmxGeneration != serverGeneration) { - /* Allocate font private index */ - dmxFontPrivateIndex = AllocateFontPrivateIndex(); - if (dmxFontPrivateIndex == -1) - return FALSE; - - dmxGeneration = serverGeneration; - } - - if (dmxShadowFB) { - dmxScreen->shadow = shadowAlloc(dmxScreen->scrnWidth, - dmxScreen->scrnHeight, - dmxScreen->beBPP); - } else { - if (!dmxInitGC(pScreen)) return FALSE; - if (!dmxInitWindow(pScreen)) return FALSE; - if (!dmxInitPixmap(pScreen)) return FALSE; - } - - /* - * Initalise the visual types. miSetVisualTypesAndMasks() requires - * that all of the types for each depth be collected together. It's - * intended for slightly different usage to what we would like here. - * Maybe a miAddVisualTypeAndMask() function will be added to make - * things easier here. - */ - for (i = 0; i < dmxScreen->beNumDepths; i++) { - int depth; - int visuals = 0; - int bitsPerRgb = 0; - int preferredClass = -1; - Pixel redMask = 0; - Pixel greenMask = 0; - Pixel blueMask = 0; - - depth = dmxScreen->beDepths[i]; - for (j = 0; j < dmxScreen->beNumVisuals; j++) { - XVisualInfo *vi; - - vi = &dmxScreen->beVisuals[j]; - if (vi->depth == depth) { - /* Assume the masks are all the same. */ - visuals |= (1 << vi->class); - bitsPerRgb = vi->bits_per_rgb; - redMask = vi->red_mask; - greenMask = vi->green_mask; - blueMask = vi->blue_mask; - if (j == dmxScreen->beDefVisualIndex) { - preferredClass = vi->class; - } - } - } - miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, preferredClass, - redMask, greenMask, blueMask); - } - - fbScreenInit(pScreen, - dmxShadowFB ? dmxScreen->shadow : NULL, - dmxScreen->scrnWidth, - dmxScreen->scrnHeight, - dmxScreen->beXDPI, - dmxScreen->beXDPI, - dmxScreen->scrnWidth, - dmxScreen->beBPP); - (void)dmxPictureInit(pScreen, 0, 0); - - /* Not yet... */ - pScreen->GetWindowPixmap = NULL; - pScreen->SetWindowPixmap = NULL; - - if (dmxShadowFB && !shadowInit(pScreen, dmxShadowUpdateProc, NULL)) - return FALSE; - - miInitializeBackingStore(pScreen); - - if (dmxShadowFB) { - miDCInitialize(pScreen, &dmxPointerCursorFuncs); - } else { - MAXSCREENSALLOC(dmxCursorGeneration); - if (dmxCursorGeneration[idx] != serverGeneration) { - if (!(miPointerInitialize(pScreen, - &dmxPointerSpriteFuncs, - &dmxPointerCursorFuncs, - FALSE))) - return FALSE; - - dmxCursorGeneration[idx] = serverGeneration; - } - } - - DMX_WRAP(CloseScreen, dmxCloseScreen, dmxScreen, pScreen); - DMX_WRAP(SaveScreen, dmxSaveScreen, dmxScreen, pScreen); - - dmxBEScreenInit(idx, pScreen); - - if (!dmxShadowFB) { - /* Wrap GC functions */ - DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); - - /* Wrap Window functions */ - DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); - DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); - DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); - DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, - pScreen); - DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); - DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); - DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); - DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); - DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); - - DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); - DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); - - DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); - - /* Wrap Image functions */ - DMX_WRAP(GetImage, dmxGetImage, dmxScreen, pScreen); - DMX_WRAP(GetSpans, dmxGetSpans, dmxScreen, pScreen); - - /* Wrap Pixmap functions */ - DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); - DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); - DMX_WRAP(BitmapToRegion, dmxBitmapToRegion, dmxScreen, pScreen); - - /* Wrap Font functions */ - DMX_WRAP(RealizeFont, dmxRealizeFont, dmxScreen, pScreen); - DMX_WRAP(UnrealizeFont, dmxUnrealizeFont, dmxScreen, pScreen); - - /* Wrap Colormap functions */ - DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen); - DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen); - DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); - DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen); - - /* Wrap Shape functions */ - DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); - } - - if (!dmxCreateDefColormap(pScreen)) - return FALSE; - - return TRUE; -} - -/** Close the \a pScreen resources on the back-end server. */ -void dmxBECloseScreen(ScreenPtr pScreen) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - int i; - - /* Restore the back-end screen-saver and DPMS state. */ - dmxDPMSTerm(dmxScreen); - - /* Free the screen resources */ - - XFreeCursor(dmxScreen->beDisplay, dmxScreen->noCursor); - dmxScreen->noCursor = (Cursor)0; - - XUnmapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); - XDestroyWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); - dmxScreen->scrnWin = (Window)0; - - if (dmxShadowFB) { - /* Free the shadow GC and image assocated with the back-end server */ - XFreeGC(dmxScreen->beDisplay, dmxScreen->shadowGC); - dmxScreen->shadowGC = NULL; - XFree(dmxScreen->shadowFBImage); - dmxScreen->shadowFBImage = NULL; - } else { - /* Free the default drawables */ - for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { - if (dmxScreen->scrnDefDrawables[i]) { - XFreePixmap(dmxScreen->beDisplay, - dmxScreen->scrnDefDrawables[i]); - dmxScreen->scrnDefDrawables[i] = (Drawable)0; - } - } - } - - /* Free resources allocated during initialization (in dmxinit.c) */ - for (i = 0; i < dmxScreen->beNumDefColormaps; i++) - XFreeColormap(dmxScreen->beDisplay, dmxScreen->beDefColormaps[i]); - xfree(dmxScreen->beDefColormaps); - dmxScreen->beDefColormaps = NULL; - -#if 0 - /* Do not free visuals, depths and pixmap formats here. Free them - * in dmxCloseScreen() instead -- see comment below. */ - XFree(dmxScreen->beVisuals); - dmxScreen->beVisuals = NULL; - - XFree(dmxScreen->beDepths); - dmxScreen->beDepths = NULL; - - XFree(dmxScreen->bePixmapFormats); - dmxScreen->bePixmapFormats = NULL; -#endif - -#ifdef GLXEXT - if (dmxScreen->glxVisuals) { - XFree(dmxScreen->glxVisuals); - dmxScreen->glxVisuals = NULL; - dmxScreen->numGlxVisuals = 0; - } -#endif - - /* Close display */ - XCloseDisplay(dmxScreen->beDisplay); - dmxScreen->beDisplay = NULL; -} - -/** Close screen number \a idx. */ -Bool dmxCloseScreen(int idx, ScreenPtr pScreen) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[idx]; - - /* Reset the proc vectors */ - if (idx == 0) { - dmxResetRender(); - dmxResetFonts(); - } - - if (dmxShadowFB) { - /* Free the shadow framebuffer */ - xfree(dmxScreen->shadow); - } else { - - /* Unwrap Shape functions */ - DMX_UNWRAP(SetShape, dmxScreen, pScreen); - - /* Unwrap the pScreen functions */ - DMX_UNWRAP(CreateGC, dmxScreen, pScreen); - - DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); - DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); - DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); - DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); - DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); - DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); - DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); - DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); - DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); - - DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); - DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); - - DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); - - DMX_UNWRAP(GetImage, dmxScreen, pScreen); - DMX_UNWRAP(GetSpans, dmxScreen, pScreen); - - DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); - DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); - DMX_UNWRAP(BitmapToRegion, dmxScreen, pScreen); - - DMX_UNWRAP(RealizeFont, dmxScreen, pScreen); - DMX_UNWRAP(UnrealizeFont, dmxScreen, pScreen); - - DMX_UNWRAP(CreateColormap, dmxScreen, pScreen); - DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen); - DMX_UNWRAP(InstallColormap, dmxScreen, pScreen); - DMX_UNWRAP(StoreColors, dmxScreen, pScreen); - } - - DMX_UNWRAP(SaveScreen, dmxScreen, pScreen); - - if (dmxScreen->beDisplay) { - dmxBECloseScreen(pScreen); - -#if 1 - /* Free visuals, depths and pixmap formats here so that they - * won't be freed when a screen is detached, thereby allowing - * the screen to be reattached to be compared to the one - * previously removed. - */ - XFree(dmxScreen->beVisuals); - dmxScreen->beVisuals = NULL; - - XFree(dmxScreen->beDepths); - dmxScreen->beDepths = NULL; - - XFree(dmxScreen->bePixmapFormats); - dmxScreen->bePixmapFormats = NULL; -#endif - } - - DMX_UNWRAP(CloseScreen, dmxScreen, pScreen); - return pScreen->CloseScreen(idx, pScreen); -} - -static Bool dmxSaveScreen(ScreenPtr pScreen, int what) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - - if (dmxScreen->beDisplay) { - switch (what) { - case SCREEN_SAVER_OFF: - case SCREEN_SAVER_FORCER: - XResetScreenSaver(dmxScreen->beDisplay); - dmxSync(dmxScreen, FALSE); - break; - case SCREEN_SAVER_ON: - case SCREEN_SAVER_CYCLE: - XActivateScreenSaver(dmxScreen->beDisplay); - dmxSync(dmxScreen, FALSE); - break; - } - } - - return TRUE; -} +/* + * Copyright 2001-2004 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: + * Kevin E. Martin + * David H. Dawes + * + */ + +/** \file + * This file provides support for screen initialization. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxshadow.h" +#include "dmxscrinit.h" +#include "dmxcursor.h" +#include "dmxgc.h" +#include "dmxgcops.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxfont.h" +#include "dmxcmap.h" +#include "dmxprop.h" +#include "dmxdpms.h" + +#include "dmxpict.h" + +#include "fb.h" +#include "mipointer.h" +#include "micmap.h" + +extern Bool dmxCloseScreen(int idx, ScreenPtr pScreen); +static Bool dmxSaveScreen(ScreenPtr pScreen, int what); + +static unsigned long dmxGeneration; +static unsigned long *dmxCursorGeneration; + +static int dmxGCPrivateKeyIndex; +DevPrivateKey dmxGCPrivateKey = &dmxGCPrivateKeyIndex; /**< Private index for GCs */ +static int dmxWinPrivateKeyIndex; +DevPrivateKey dmxWinPrivateKey = &dmxWinPrivateKeyIndex; /**< Private index for Windows */ +static int dmxPixPrivateKeyIndex; +DevPrivateKey dmxPixPrivateKey = &dmxPixPrivateKeyIndex; /**< Private index for Pixmaps */ +int dmxFontPrivateIndex; /**< Private index for Fonts */ +static int dmxScreenPrivateKeyIndex; +DevPrivateKey dmxScreenPrivateKey = &dmxScreenPrivateKeyIndex; /**< Private index for Screens */ +static int dmxColormapPrivateKeyIndex; +DevPrivateKey dmxColormapPrivateKey = &dmxColormapPrivateKeyIndex; /**< Private index for Colormaps */ +static int dmxPictPrivateKeyIndex; +DevPrivateKey dmxPictPrivateKey = &dmxPictPrivateKeyIndex; /**< Private index for Picts */ +static int dmxGlyphSetPrivateKeyIndex; +DevPrivateKey dmxGlyphSetPrivateKey = &dmxGlyphSetPrivateKeyIndex; /**< Private index for GlyphSets */ + +/** Initialize the parts of screen \a idx that require access to the + * back-end server. */ +void dmxBEScreenInit(int idx, ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + XSetWindowAttributes attribs; + XGCValues gcvals; + unsigned long mask; + int i, j; + + /* FIXME: The dmxScreenInit() code currently assumes that it will + * not be called if the Xdmx server is started with this screen + * detached -- i.e., it assumes that dmxScreen->beDisplay is always + * valid. This is not necessarily a valid assumption when full + * addition/removal of screens is implemented, but when this code is + * broken out for screen reattachment, then we will reevaluate this + * assumption. + */ + + pScreen->mmWidth = DisplayWidthMM(dmxScreen->beDisplay, + DefaultScreen(dmxScreen->beDisplay)); + pScreen->mmHeight = DisplayHeightMM(dmxScreen->beDisplay, + DefaultScreen(dmxScreen->beDisplay)); + + pScreen->whitePixel = dmxScreen->beWhitePixel; + pScreen->blackPixel = dmxScreen->beBlackPixel; + + /* Handle screen savers and DPMS on the backend */ + dmxDPMSInit(dmxScreen); + + /* Create root window for screen */ + mask = CWBackPixel | CWEventMask | CWColormap | CWOverrideRedirect; + attribs.background_pixel = dmxScreen->beBlackPixel; + attribs.event_mask = (KeyPressMask + | KeyReleaseMask + | ButtonPressMask + | ButtonReleaseMask + | EnterWindowMask + | LeaveWindowMask + | PointerMotionMask + | KeymapStateMask + | FocusChangeMask); + attribs.colormap = dmxScreen->beDefColormaps[dmxScreen->beDefVisualIndex]; + attribs.override_redirect = True; + + dmxScreen->scrnWin = + XCreateWindow(dmxScreen->beDisplay, + DefaultRootWindow(dmxScreen->beDisplay), + dmxScreen->scrnX, + dmxScreen->scrnY, + dmxScreen->scrnWidth, + dmxScreen->scrnHeight, + 0, + pScreen->rootDepth, + InputOutput, + dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, + mask, + &attribs); + dmxPropertyWindow(dmxScreen); + + /* + * This turns off the cursor by defining a cursor with no visible + * components. + */ + { + char noCursorData[] = {0, 0, 0, 0, + 0, 0, 0, 0}; + Pixmap pixmap; + XColor color, tmp; + + pixmap = XCreateBitmapFromData(dmxScreen->beDisplay, dmxScreen->scrnWin, + noCursorData, 8, 8); + XAllocNamedColor(dmxScreen->beDisplay, dmxScreen->beDefColormaps[0], + "black", &color, &tmp); + dmxScreen->noCursor = XCreatePixmapCursor(dmxScreen->beDisplay, + pixmap, pixmap, + &color, &color, 0, 0); + XDefineCursor(dmxScreen->beDisplay, dmxScreen->scrnWin, + dmxScreen->noCursor); + + XFreePixmap(dmxScreen->beDisplay, pixmap); + } + + XMapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); + + if (dmxShadowFB) { + mask = (GCFunction + | GCPlaneMask + | GCClipMask); + gcvals.function = GXcopy; + gcvals.plane_mask = AllPlanes; + gcvals.clip_mask = None; + + dmxScreen->shadowGC = XCreateGC(dmxScreen->beDisplay, + dmxScreen->scrnWin, + mask, &gcvals); + + dmxScreen->shadowFBImage = + XCreateImage(dmxScreen->beDisplay, + dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual, + dmxScreen->beDepth, + ZPixmap, + 0, + (char *)dmxScreen->shadow, + dmxScreen->scrnWidth, dmxScreen->scrnHeight, + dmxScreen->beBPP, + PixmapBytePad(dmxScreen->scrnWidth, + dmxScreen->beBPP)); + } else { + /* Create default drawables (used during GC creation) */ + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) + for (j = 0; j < dmxScreen->beNumDepths; j++) + if ((dmxScreen->bePixmapFormats[i].depth == 1) || + (dmxScreen->bePixmapFormats[i].depth == + dmxScreen->beDepths[j])) { + dmxScreen->scrnDefDrawables[i] = (Drawable) + XCreatePixmap(dmxScreen->beDisplay, dmxScreen->scrnWin, + 1, 1, dmxScreen->bePixmapFormats[i].depth); + break; + } + } +} + +/** Initialize screen number \a idx. */ +Bool dmxScreenInit(int idx, ScreenPtr pScreen, int argc, char *argv[]) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + int i, j; + + if (dmxGeneration != serverGeneration) { + /* Allocate font private index */ + dmxFontPrivateIndex = AllocateFontPrivateIndex(); + if (dmxFontPrivateIndex == -1) + return FALSE; + + dmxGeneration = serverGeneration; + } + + if (dmxShadowFB) { + dmxScreen->shadow = shadowAlloc(dmxScreen->scrnWidth, + dmxScreen->scrnHeight, + dmxScreen->beBPP); + } else { + if (!dmxInitGC(pScreen)) return FALSE; + if (!dmxInitWindow(pScreen)) return FALSE; + if (!dmxInitPixmap(pScreen)) return FALSE; + } + + /* + * Initalise the visual types. miSetVisualTypesAndMasks() requires + * that all of the types for each depth be collected together. It's + * intended for slightly different usage to what we would like here. + * Maybe a miAddVisualTypeAndMask() function will be added to make + * things easier here. + */ + for (i = 0; i < dmxScreen->beNumDepths; i++) { + int depth; + int visuals = 0; + int bitsPerRgb = 0; + int preferredClass = -1; + Pixel redMask = 0; + Pixel greenMask = 0; + Pixel blueMask = 0; + + depth = dmxScreen->beDepths[i]; + for (j = 0; j < dmxScreen->beNumVisuals; j++) { + XVisualInfo *vi; + + vi = &dmxScreen->beVisuals[j]; + if (vi->depth == depth) { + /* Assume the masks are all the same. */ + visuals |= (1 << vi->class); + bitsPerRgb = vi->bits_per_rgb; + redMask = vi->red_mask; + greenMask = vi->green_mask; + blueMask = vi->blue_mask; + if (j == dmxScreen->beDefVisualIndex) { + preferredClass = vi->class; + } + } + } + miSetVisualTypesAndMasks(depth, visuals, bitsPerRgb, preferredClass, + redMask, greenMask, blueMask); + } + + fbScreenInit(pScreen, + dmxShadowFB ? dmxScreen->shadow : NULL, + dmxScreen->scrnWidth, + dmxScreen->scrnHeight, + dmxScreen->beXDPI, + dmxScreen->beXDPI, + dmxScreen->scrnWidth, + dmxScreen->beBPP); + (void)dmxPictureInit(pScreen, 0, 0); + + /* Not yet... */ + pScreen->GetWindowPixmap = NULL; + pScreen->SetWindowPixmap = NULL; + + if (dmxShadowFB && !shadowInit(pScreen, dmxShadowUpdateProc, NULL)) + return FALSE; + + miInitializeBackingStore(pScreen); + + if (dmxShadowFB) { + miDCInitialize(pScreen, &dmxPointerCursorFuncs); + } else { + MAXSCREENSALLOC(dmxCursorGeneration); + if (dmxCursorGeneration[idx] != serverGeneration) { + if (!(miPointerInitialize(pScreen, + &dmxPointerSpriteFuncs, + &dmxPointerCursorFuncs, + FALSE))) + return FALSE; + + dmxCursorGeneration[idx] = serverGeneration; + } + } + + DMX_WRAP(CloseScreen, dmxCloseScreen, dmxScreen, pScreen); + DMX_WRAP(SaveScreen, dmxSaveScreen, dmxScreen, pScreen); + + dmxBEScreenInit(idx, pScreen); + + if (!dmxShadowFB) { + /* Wrap GC functions */ + DMX_WRAP(CreateGC, dmxCreateGC, dmxScreen, pScreen); + + /* Wrap Window functions */ + DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); + DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); + DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); + DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, + pScreen); + DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); + DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); + DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); + DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); + DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); + + DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); + DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); + + DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); + + /* Wrap Image functions */ + DMX_WRAP(GetImage, dmxGetImage, dmxScreen, pScreen); + DMX_WRAP(GetSpans, dmxGetSpans, dmxScreen, pScreen); + + /* Wrap Pixmap functions */ + DMX_WRAP(CreatePixmap, dmxCreatePixmap, dmxScreen, pScreen); + DMX_WRAP(DestroyPixmap, dmxDestroyPixmap, dmxScreen, pScreen); + DMX_WRAP(BitmapToRegion, dmxBitmapToRegion, dmxScreen, pScreen); + + /* Wrap Font functions */ + DMX_WRAP(RealizeFont, dmxRealizeFont, dmxScreen, pScreen); + DMX_WRAP(UnrealizeFont, dmxUnrealizeFont, dmxScreen, pScreen); + + /* Wrap Colormap functions */ + DMX_WRAP(CreateColormap, dmxCreateColormap, dmxScreen, pScreen); + DMX_WRAP(DestroyColormap, dmxDestroyColormap, dmxScreen, pScreen); + DMX_WRAP(InstallColormap, dmxInstallColormap, dmxScreen, pScreen); + DMX_WRAP(StoreColors, dmxStoreColors, dmxScreen, pScreen); + + /* Wrap Shape functions */ + DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); + } + + if (!dmxCreateDefColormap(pScreen)) + return FALSE; + + return TRUE; +} + +/** Close the \a pScreen resources on the back-end server. */ +void dmxBECloseScreen(ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + int i; + + /* Restore the back-end screen-saver and DPMS state. */ + dmxDPMSTerm(dmxScreen); + + /* Free the screen resources */ + + XFreeCursor(dmxScreen->beDisplay, dmxScreen->noCursor); + dmxScreen->noCursor = (Cursor)0; + + XUnmapWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); + XDestroyWindow(dmxScreen->beDisplay, dmxScreen->scrnWin); + dmxScreen->scrnWin = (Window)0; + + if (dmxShadowFB) { + /* Free the shadow GC and image assocated with the back-end server */ + XFreeGC(dmxScreen->beDisplay, dmxScreen->shadowGC); + dmxScreen->shadowGC = NULL; + XFree(dmxScreen->shadowFBImage); + dmxScreen->shadowFBImage = NULL; + } else { + /* Free the default drawables */ + for (i = 0; i < dmxScreen->beNumPixmapFormats; i++) { + if (dmxScreen->scrnDefDrawables[i]) { + XFreePixmap(dmxScreen->beDisplay, + dmxScreen->scrnDefDrawables[i]); + dmxScreen->scrnDefDrawables[i] = (Drawable)0; + } + } + } + + /* Free resources allocated during initialization (in dmxinit.c) */ + for (i = 0; i < dmxScreen->beNumDefColormaps; i++) + XFreeColormap(dmxScreen->beDisplay, dmxScreen->beDefColormaps[i]); + free(dmxScreen->beDefColormaps); + dmxScreen->beDefColormaps = NULL; + +#if 0 + /* Do not free visuals, depths and pixmap formats here. Free them + * in dmxCloseScreen() instead -- see comment below. */ + XFree(dmxScreen->beVisuals); + dmxScreen->beVisuals = NULL; + + XFree(dmxScreen->beDepths); + dmxScreen->beDepths = NULL; + + XFree(dmxScreen->bePixmapFormats); + dmxScreen->bePixmapFormats = NULL; +#endif + +#ifdef GLXEXT + if (dmxScreen->glxVisuals) { + XFree(dmxScreen->glxVisuals); + dmxScreen->glxVisuals = NULL; + dmxScreen->numGlxVisuals = 0; + } +#endif + + /* Close display */ + XCloseDisplay(dmxScreen->beDisplay); + dmxScreen->beDisplay = NULL; +} + +/** Close screen number \a idx. */ +Bool dmxCloseScreen(int idx, ScreenPtr pScreen) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[idx]; + + /* Reset the proc vectors */ + if (idx == 0) { + dmxResetRender(); + dmxResetFonts(); + } + + if (dmxShadowFB) { + /* Free the shadow framebuffer */ + free(dmxScreen->shadow); + } else { + + /* Unwrap Shape functions */ + DMX_UNWRAP(SetShape, dmxScreen, pScreen); + + /* Unwrap the pScreen functions */ + DMX_UNWRAP(CreateGC, dmxScreen, pScreen); + + DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); + DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); + DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); + DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); + DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); + DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); + DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); + DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); + DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); + + DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); + DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); + + DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); + + DMX_UNWRAP(GetImage, dmxScreen, pScreen); + DMX_UNWRAP(GetSpans, dmxScreen, pScreen); + + DMX_UNWRAP(CreatePixmap, dmxScreen, pScreen); + DMX_UNWRAP(DestroyPixmap, dmxScreen, pScreen); + DMX_UNWRAP(BitmapToRegion, dmxScreen, pScreen); + + DMX_UNWRAP(RealizeFont, dmxScreen, pScreen); + DMX_UNWRAP(UnrealizeFont, dmxScreen, pScreen); + + DMX_UNWRAP(CreateColormap, dmxScreen, pScreen); + DMX_UNWRAP(DestroyColormap, dmxScreen, pScreen); + DMX_UNWRAP(InstallColormap, dmxScreen, pScreen); + DMX_UNWRAP(StoreColors, dmxScreen, pScreen); + } + + DMX_UNWRAP(SaveScreen, dmxScreen, pScreen); + + if (dmxScreen->beDisplay) { + dmxBECloseScreen(pScreen); + +#if 1 + /* Free visuals, depths and pixmap formats here so that they + * won't be freed when a screen is detached, thereby allowing + * the screen to be reattached to be compared to the one + * previously removed. + */ + XFree(dmxScreen->beVisuals); + dmxScreen->beVisuals = NULL; + + XFree(dmxScreen->beDepths); + dmxScreen->beDepths = NULL; + + XFree(dmxScreen->bePixmapFormats); + dmxScreen->bePixmapFormats = NULL; +#endif + } + + DMX_UNWRAP(CloseScreen, dmxScreen, pScreen); + return pScreen->CloseScreen(idx, pScreen); +} + +static Bool dmxSaveScreen(ScreenPtr pScreen, int what) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + + if (dmxScreen->beDisplay) { + switch (what) { + case SCREEN_SAVER_OFF: + case SCREEN_SAVER_FORCER: + XResetScreenSaver(dmxScreen->beDisplay); + dmxSync(dmxScreen, FALSE); + break; + case SCREEN_SAVER_ON: + case SCREEN_SAVER_CYCLE: + XActivateScreenSaver(dmxScreen->beDisplay); + dmxSync(dmxScreen, FALSE); + break; + } + } + + return TRUE; +} diff --git a/xorg-server/hw/dmx/dmxsync.c b/xorg-server/hw/dmx/dmxsync.c index 2cec1b97c..8ace59470 100644 --- a/xorg-server/hw/dmx/dmxsync.c +++ b/xorg-server/hw/dmx/dmxsync.c @@ -1,193 +1,193 @@ -/* - * Copyright 2002-2004 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: - * Rickard E. (Rik) Faith - * - */ - -/** \file - * - * The DMX server code is written to call #dmxSync() whenever an XSync() - * might be necessary. However, since XSync() requires a two way - * communication with the other X server, eliminating unnecessary - * XSync() calls is a key performance optimization. Support for this - * optimization is provided here. Statistics about XSync() calls and - * latency are gathered in \a dmxstat.c. - * - * During the initial conversion from calling XSync() immediately to the - * XSync() batching method implemented in this file, it was noted that, - * out of more than 300 \a x11perf tests, 8 tests became more than 100 - * times faster, with 68 more than 50X faster, 114 more than 10X faster, - * and 181 more than 2X faster. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxstat.h" -#include "dmxlog.h" -#include - -static int dmxSyncInterval = 100; /* Default interval in milliseconds */ -static OsTimerPtr dmxSyncTimer; -static int dmxSyncPending; - -static void dmxDoSync(DMXScreenInfo *dmxScreen) -{ - dmxScreen->needsSync = FALSE; - - if (!dmxScreen->beDisplay) - return; /* FIXME: Is this correct behavior for sync stats? */ - - if (!dmxStatInterval) { - XSync(dmxScreen->beDisplay, False); - } else { - struct timeval start, stop; - - gettimeofday(&start, 0); - XSync(dmxScreen->beDisplay, False); - gettimeofday(&stop, 0); - dmxStatSync(dmxScreen, &stop, &start, dmxSyncPending); - } -} - -static CARD32 dmxSyncCallback(OsTimerPtr timer, CARD32 time, pointer arg) -{ - int i; - - if (dmxSyncPending) { - for (i = 0; i < dmxNumScreens; i++) { - DMXScreenInfo *dmxScreen = &dmxScreens[i]; - if (dmxScreen->needsSync) dmxDoSync(dmxScreen); - } - } - dmxSyncPending = 0; - return 0; /* Do not place on queue again */ -} - -static void dmxSyncBlockHandler(pointer blockData, OSTimePtr pTimeout, - pointer pReadMask) -{ - TimerForce(dmxSyncTimer); -} - -static void dmxSyncWakeupHandler(pointer blockData, int result, - pointer pReadMask) -{ -} - -/** Request the XSync() batching optimization with the specified \a - * interval (in mS). If the \a interval is 0, 100mS is used. If the \a - * interval is less than 0, then the XSync() batching optimization is - * not requested (e.g., so the -syncbatch -1 command line option can - * turn off the default 100mS XSync() batching). - * - * Note that the parameter to this routine is a string, since it will - * usually be called from #ddxProcessArgument in \a dmxinit.c */ -void dmxSyncActivate(const char *interval) -{ - dmxSyncInterval = (interval ? atoi(interval) : 100); - - if (dmxSyncInterval < 0) dmxSyncInterval = 0; -} - -/** Initialize the XSync() batching optimization, but only if - * #dmxSyncActivate was last called with a non-negative value. */ -void dmxSyncInit(void) -{ - if (dmxSyncInterval) { - RegisterBlockAndWakeupHandlers(dmxSyncBlockHandler, - dmxSyncWakeupHandler, - NULL); - dmxLog(dmxInfo, "XSync batching with %d ms interval\n", - dmxSyncInterval); - } else { - dmxLog(dmxInfo, "XSync batching disabled\n"); - } -} - -/** Request an XSync() to the display used by \a dmxScreen. If \a now - * is TRUE, call XSync() immediately instead of waiting for the next - * XSync() batching point. Note that if XSync() batching was deselected - * with #dmxSyncActivate() before #dmxSyncInit() was called, then no - * XSync() batching is performed and this function always calles XSync() - * immediately. - * - * (Note that this function uses TimerSet but works correctly in the - * face of a server generation. See the source for details.) - * - * If \a dmxScreen is \a NULL, then all pending syncs will be flushed - * immediately. - */ -void dmxSync(DMXScreenInfo *dmxScreen, Bool now) -{ - static unsigned long dmxGeneration = 0; - - if (dmxSyncInterval) { - if (dmxGeneration != serverGeneration) { - /* Server generation does a TimerInit, which frees all - * timers. So, at this point dmxSyncTimer is either: - * 1) NULL, iff dmxGeneration == 0, - * 2) freed, if it was on a queue (dmxSyncPending != 0), or - * 3) allocated, if it wasn't on a queue (dmxSyncPending == 0) - */ - if (dmxSyncTimer && !dmxSyncPending) xfree(dmxSyncTimer); - dmxSyncTimer = NULL; - now = TRUE; - dmxGeneration = serverGeneration; - } - /* Queue sync */ - if (dmxScreen) { - dmxScreen->needsSync = TRUE; - ++dmxSyncPending; - } - - /* Do sync or set time for later */ - if (now || !dmxScreen) { - if (!TimerForce(dmxSyncTimer)) dmxSyncCallback(NULL, 0, NULL); - /* At this point, dmxSyncPending == 0 because - * dmxSyncCallback must have been called. */ - if (dmxSyncPending) - dmxLog(dmxFatal, "dmxSync(%s,%d): dmxSyncPending = %d\n", - dmxScreen ? dmxScreen->name : "", now, dmxSyncPending); - } else { - dmxScreen->needsSync = TRUE; - if (dmxSyncPending == 1) - dmxSyncTimer = TimerSet(dmxSyncTimer, 0, dmxSyncInterval, - dmxSyncCallback, NULL); - } - } else { - /* If dmxSyncInterval is not being used, - * then all the backends are already - * up-to-date. */ - if (dmxScreen) dmxDoSync(dmxScreen); - } -} +/* + * Copyright 2002-2004 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: + * Rickard E. (Rik) Faith + * + */ + +/** \file + * + * The DMX server code is written to call #dmxSync() whenever an XSync() + * might be necessary. However, since XSync() requires a two way + * communication with the other X server, eliminating unnecessary + * XSync() calls is a key performance optimization. Support for this + * optimization is provided here. Statistics about XSync() calls and + * latency are gathered in \a dmxstat.c. + * + * During the initial conversion from calling XSync() immediately to the + * XSync() batching method implemented in this file, it was noted that, + * out of more than 300 \a x11perf tests, 8 tests became more than 100 + * times faster, with 68 more than 50X faster, 114 more than 10X faster, + * and 181 more than 2X faster. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxstat.h" +#include "dmxlog.h" +#include + +static int dmxSyncInterval = 100; /* Default interval in milliseconds */ +static OsTimerPtr dmxSyncTimer; +static int dmxSyncPending; + +static void dmxDoSync(DMXScreenInfo *dmxScreen) +{ + dmxScreen->needsSync = FALSE; + + if (!dmxScreen->beDisplay) + return; /* FIXME: Is this correct behavior for sync stats? */ + + if (!dmxStatInterval) { + XSync(dmxScreen->beDisplay, False); + } else { + struct timeval start, stop; + + gettimeofday(&start, 0); + XSync(dmxScreen->beDisplay, False); + gettimeofday(&stop, 0); + dmxStatSync(dmxScreen, &stop, &start, dmxSyncPending); + } +} + +static CARD32 dmxSyncCallback(OsTimerPtr timer, CARD32 time, pointer arg) +{ + int i; + + if (dmxSyncPending) { + for (i = 0; i < dmxNumScreens; i++) { + DMXScreenInfo *dmxScreen = &dmxScreens[i]; + if (dmxScreen->needsSync) dmxDoSync(dmxScreen); + } + } + dmxSyncPending = 0; + return 0; /* Do not place on queue again */ +} + +static void dmxSyncBlockHandler(pointer blockData, OSTimePtr pTimeout, + pointer pReadMask) +{ + TimerForce(dmxSyncTimer); +} + +static void dmxSyncWakeupHandler(pointer blockData, int result, + pointer pReadMask) +{ +} + +/** Request the XSync() batching optimization with the specified \a + * interval (in mS). If the \a interval is 0, 100mS is used. If the \a + * interval is less than 0, then the XSync() batching optimization is + * not requested (e.g., so the -syncbatch -1 command line option can + * turn off the default 100mS XSync() batching). + * + * Note that the parameter to this routine is a string, since it will + * usually be called from #ddxProcessArgument in \a dmxinit.c */ +void dmxSyncActivate(const char *interval) +{ + dmxSyncInterval = (interval ? atoi(interval) : 100); + + if (dmxSyncInterval < 0) dmxSyncInterval = 0; +} + +/** Initialize the XSync() batching optimization, but only if + * #dmxSyncActivate was last called with a non-negative value. */ +void dmxSyncInit(void) +{ + if (dmxSyncInterval) { + RegisterBlockAndWakeupHandlers(dmxSyncBlockHandler, + dmxSyncWakeupHandler, + NULL); + dmxLog(dmxInfo, "XSync batching with %d ms interval\n", + dmxSyncInterval); + } else { + dmxLog(dmxInfo, "XSync batching disabled\n"); + } +} + +/** Request an XSync() to the display used by \a dmxScreen. If \a now + * is TRUE, call XSync() immediately instead of waiting for the next + * XSync() batching point. Note that if XSync() batching was deselected + * with #dmxSyncActivate() before #dmxSyncInit() was called, then no + * XSync() batching is performed and this function always calles XSync() + * immediately. + * + * (Note that this function uses TimerSet but works correctly in the + * face of a server generation. See the source for details.) + * + * If \a dmxScreen is \a NULL, then all pending syncs will be flushed + * immediately. + */ +void dmxSync(DMXScreenInfo *dmxScreen, Bool now) +{ + static unsigned long dmxGeneration = 0; + + if (dmxSyncInterval) { + if (dmxGeneration != serverGeneration) { + /* Server generation does a TimerInit, which frees all + * timers. So, at this point dmxSyncTimer is either: + * 1) NULL, iff dmxGeneration == 0, + * 2) freed, if it was on a queue (dmxSyncPending != 0), or + * 3) allocated, if it wasn't on a queue (dmxSyncPending == 0) + */ + if (dmxSyncTimer && !dmxSyncPending) free(dmxSyncTimer); + dmxSyncTimer = NULL; + now = TRUE; + dmxGeneration = serverGeneration; + } + /* Queue sync */ + if (dmxScreen) { + dmxScreen->needsSync = TRUE; + ++dmxSyncPending; + } + + /* Do sync or set time for later */ + if (now || !dmxScreen) { + if (!TimerForce(dmxSyncTimer)) dmxSyncCallback(NULL, 0, NULL); + /* At this point, dmxSyncPending == 0 because + * dmxSyncCallback must have been called. */ + if (dmxSyncPending) + dmxLog(dmxFatal, "dmxSync(%s,%d): dmxSyncPending = %d\n", + dmxScreen ? dmxScreen->name : "", now, dmxSyncPending); + } else { + dmxScreen->needsSync = TRUE; + if (dmxSyncPending == 1) + dmxSyncTimer = TimerSet(dmxSyncTimer, 0, dmxSyncInterval, + dmxSyncCallback, NULL); + } + } else { + /* If dmxSyncInterval is not being used, + * then all the backends are already + * up-to-date. */ + if (dmxScreen) dmxDoSync(dmxScreen); + } +} diff --git a/xorg-server/hw/dmx/dmxwindow.c b/xorg-server/hw/dmx/dmxwindow.c index ea2f2c579..3466f074f 100644 --- a/xorg-server/hw/dmx/dmxwindow.c +++ b/xorg-server/hw/dmx/dmxwindow.c @@ -1,1015 +1,1015 @@ -/* - * Copyright 2001-2004 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: - * Kevin E. Martin - * - */ - -/** \file - * This file provides support for window-related functions. */ - -#ifdef HAVE_DMX_CONFIG_H -#include -#endif - -#include "dmx.h" -#include "dmxsync.h" -#include "dmxwindow.h" -#include "dmxpixmap.h" -#include "dmxcmap.h" -#include "dmxvisual.h" -#include "dmxinput.h" -#include "dmxextension.h" -#include "dmxpict.h" - -#include "windowstr.h" - -static void dmxDoRestackWindow(WindowPtr pWindow); -static void dmxDoChangeWindowAttributes(WindowPtr pWindow, - unsigned long *mask, - XSetWindowAttributes *attribs); - -static void dmxDoSetShape(WindowPtr pWindow); - -/** Initialize the private area for the window functions. */ -Bool dmxInitWindow(ScreenPtr pScreen) -{ - if (!dixRequestPrivate(dmxWinPrivateKey, sizeof(dmxWinPrivRec))) - return FALSE; - - return TRUE; -} - - -Window dmxCreateRootWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - Window parent; - Visual *visual; - unsigned long mask; - XSetWindowAttributes attribs; - ColormapPtr pCmap; - dmxColormapPrivPtr pCmapPriv; - - /* Create root window */ - - parent = dmxScreen->scrnWin; /* This is our "Screen" window */ - visual = dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual; - - pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); - pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); - - mask = CWEventMask | CWBackingStore | CWColormap | CWBorderPixel; - attribs.event_mask = ExposureMask; - attribs.backing_store = NotUseful; - attribs.colormap = pCmapPriv->cmap; - attribs.border_pixel = 0; - - /* Incorporate new attributes, if needed */ - if (pWinPriv->attribMask) { - dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); - mask |= pWinPriv->attribMask; - } - - return XCreateWindow(dmxScreen->beDisplay, - parent, - pWindow->origin.x - wBorderWidth(pWindow), - pWindow->origin.y - wBorderWidth(pWindow), - pWindow->drawable.width, - pWindow->drawable.height, - pWindow->borderWidth, - pWindow->drawable.depth, - pWindow->drawable.class, - visual, - mask, - &attribs); -} - -/** Change the location and size of the "screen" window. Called from - * #dmxConfigureScreenWindow(). */ -void dmxResizeScreenWindow(ScreenPtr pScreen, - int x, int y, int w, int h) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - unsigned int m; - XWindowChanges c; - - if (!dmxScreen->beDisplay) - return; - - /* Handle resizing on back-end server */ - m = CWX | CWY | CWWidth | CWHeight; - c.x = x; - c.y = y; - c.width = w; - c.height = h; - - XConfigureWindow(dmxScreen->beDisplay, dmxScreen->scrnWin, m, &c); - dmxSync(dmxScreen, False); -} - -/** Change the location and size of the "root" window. Called from - * #dmxConfigureRootWindow. */ -void dmxResizeRootWindow(WindowPtr pRoot, - int x, int y, int w, int h) -{ - DMXScreenInfo *dmxScreen = &dmxScreens[pRoot->drawable.pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot); - unsigned int m; - XWindowChanges c; - - /* Handle resizing on back-end server */ - if (dmxScreen->beDisplay) { - m = CWX | CWY | CWWidth | CWHeight; - c.x = x; - c.y = y; - c.width = (w > 0) ? w : 1; - c.height = (h > 0) ? h : 1; - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - } - - if (w == 0 || h == 0) { - if (pWinPriv->mapped) { - if (dmxScreen->beDisplay) - XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); - pWinPriv->mapped = FALSE; - } - } else if (!pWinPriv->mapped) { - if (dmxScreen->beDisplay) - XMapWindow(dmxScreen->beDisplay, pWinPriv->window); - pWinPriv->mapped = TRUE; - } - - if (dmxScreen->beDisplay) - dmxSync(dmxScreen, False); -} - -void dmxGetDefaultWindowAttributes(WindowPtr pWindow, - Colormap *cmap, - Visual **visual) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - - if (pWindow->drawable.class != InputOnly && - pWindow->optional && - pWindow->optional->visual != wVisual(pWindow->parent)) { - - /* Find the matching visual */ - *visual = dmxLookupVisualFromID(pScreen, wVisual(pWindow)); - - /* Handle optional colormaps */ - if (pWindow->optional->colormap) { - ColormapPtr pCmap; - dmxColormapPrivPtr pCmapPriv; - - pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), - RT_COLORMAP); - pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); - *cmap = pCmapPriv->cmap; - } else { - *cmap = dmxColormapFromDefaultVisual(pScreen, *visual); - } - } else { - *visual = CopyFromParent; - *cmap = (Colormap)0; - } -} - -static Window dmxCreateNonRootWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - Window parent; - unsigned long mask = 0L; - XSetWindowAttributes attribs; - dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); - - /* Create window on back-end server */ - - parent = pParentPriv->window; - - /* The parent won't exist if this call to CreateNonRootWindow came - from ReparentWindow and the grandparent window has not yet been - created */ - if (!parent) { - dmxCreateAndRealizeWindow(pWindow->parent, FALSE); - parent = pParentPriv->window; - } - - /* Incorporate new attributes, if needed */ - if (pWinPriv->attribMask) { - dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); - mask |= pWinPriv->attribMask; - } - - /* Add in default attributes */ - if (pWindow->drawable.class != InputOnly) { - mask |= CWBackingStore; - attribs.backing_store = NotUseful; - - if (!(mask & CWColormap) && pWinPriv->cmap) { - mask |= CWColormap; - attribs.colormap = pWinPriv->cmap; - if (!(mask & CWBorderPixel)) { - mask |= CWBorderPixel; - attribs.border_pixel = 0; - } - } - } - - /* Handle case where subwindows are being mapped, but created out of - order -- if current window has a previous sibling, then it cannot - be created on top of the stack, so we must restack the windows */ - pWinPriv->restacked = (pWindow->prevSib != NullWindow); - - return XCreateWindow(dmxScreen->beDisplay, - parent, - pWindow->origin.x - wBorderWidth(pWindow), - pWindow->origin.y - wBorderWidth(pWindow), - pWindow->drawable.width, - pWindow->drawable.height, - pWindow->borderWidth, - pWindow->drawable.depth, - pWindow->drawable.class, - pWinPriv->visual, - mask, - &attribs); -} - -/** This function handles lazy window creation and realization. Window - * creation is handled by #dmxCreateNonRootWindow(). It also handles - * any stacking changes that have occured since the window was - * originally created by calling #dmxDoRestackWindow(). If the window - * is shaped, the shape is set on the back-end server by calling - * #dmxDoSetShape(), and if the window has pictures (from RENDER) - * associated with it, those pictures are created on the back-end - * server by calling #dmxCreatePictureList(). If \a doSync is TRUE, - * then #dmxSync() is called. */ -void dmxCreateAndRealizeWindow(WindowPtr pWindow, Bool doSync) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - if (!dmxScreen->beDisplay) return; - - pWinPriv->window = dmxCreateNonRootWindow(pWindow); - if (pWinPriv->restacked) dmxDoRestackWindow(pWindow); - if (pWinPriv->isShaped) dmxDoSetShape(pWindow); - if (pWinPriv->hasPict) dmxCreatePictureList(pWindow); - if (pWinPriv->mapped) XMapWindow(dmxScreen->beDisplay, - pWinPriv->window); - if (doSync) dmxSync(dmxScreen, False); -} - -/** Create \a pWindow on the back-end server. If the lazy window - * creation optimization is enabled, then the actual creation and - * realization of the window is handled by - * #dmxCreateAndRealizeWindow(). */ -Bool dmxCreateWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - Bool ret = TRUE; - - DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->CreateWindow) - ret = pScreen->CreateWindow(pWindow); -#endif - - /* Set up the defaults */ - pWinPriv->window = (Window)0; - pWinPriv->offscreen = TRUE; - pWinPriv->mapped = FALSE; - pWinPriv->restacked = FALSE; - pWinPriv->attribMask = 0; - pWinPriv->isShaped = FALSE; - pWinPriv->hasPict = FALSE; -#ifdef GLXEXT - pWinPriv->swapGroup = NULL; - pWinPriv->barrier = 0; -#endif - - if (dmxScreen->beDisplay) { - /* Only create the root window at this stage -- non-root windows are - created when they are mapped and are on-screen */ - if (!pWindow->parent) { - dmxScreen->rootWin = pWinPriv->window - = dmxCreateRootWindow(pWindow); - if (dmxScreen->scrnX != dmxScreen->rootX - || dmxScreen->scrnY != dmxScreen->rootY - || dmxScreen->scrnWidth != dmxScreen->rootWidth - || dmxScreen->scrnHeight != dmxScreen->rootHeight) { - dmxResizeRootWindow(pWindow, - dmxScreen->rootX, - dmxScreen->rootY, - dmxScreen->rootWidth, - dmxScreen->rootHeight); - dmxUpdateScreenResources(screenInfo.screens[dmxScreen->index], - dmxScreen->rootX, - dmxScreen->rootY, - dmxScreen->rootWidth, - dmxScreen->rootHeight); - pWindow->origin.x = dmxScreen->rootX; - pWindow->origin.y = dmxScreen->rootY; - } - } else { - dmxGetDefaultWindowAttributes(pWindow, - &pWinPriv->cmap, - &pWinPriv->visual); - - if (dmxLazyWindowCreation) { - /* Save parent's visual for use later */ - if (pWinPriv->visual == CopyFromParent) - pWinPriv->visual = - dmxLookupVisualFromID(pScreen, - wVisual(pWindow->parent)); - } else { - pWinPriv->window = dmxCreateNonRootWindow(pWindow); - } - } - - dmxSync(dmxScreen, False); - } - - DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); - - return ret; -} - -/** Destroy \a pWindow on the back-end server. */ -Bool dmxBEDestroyWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - if (pWinPriv->window) { - XDestroyWindow(dmxScreen->beDisplay, pWinPriv->window); - pWinPriv->window = (Window)0; - return TRUE; - } - - return FALSE; -} - -/** Destroy \a pWindow on the back-end server. If any RENDER pictures - were created, destroy them as well. */ -Bool dmxDestroyWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - Bool needSync = FALSE; -#ifdef GLXEXT - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); -#endif - - DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); - - /* Destroy any picture list associated with this window */ - needSync |= dmxDestroyPictureList(pWindow); - - /* Destroy window on back-end server */ - needSync |= dmxBEDestroyWindow(pWindow); - if (needSync) dmxSync(dmxScreen, FALSE); - -#ifdef GLXEXT - if (pWinPriv->swapGroup && pWinPriv->windowDestroyed) - pWinPriv->windowDestroyed(pWindow); -#endif - - if (pScreen->DestroyWindow) - ret = pScreen->DestroyWindow(pWindow); - - DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); - - return ret; -} - -/** Change the position of \a pWindow to be \a x, \a y. */ -Bool dmxPositionWindow(WindowPtr pWindow, int x, int y) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - unsigned int m; - XWindowChanges c; - - DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->PositionWindow) - ret = pScreen->PositionWindow(pWindow, x, y); -#endif - - /* Determine if the window is completely off the visible portion of - the screen */ - pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); - - /* If the window is now on-screen and it is mapped and it has not - been created yet, create it and map it */ - if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { - dmxCreateAndRealizeWindow(pWindow, TRUE); - } else if (pWinPriv->window) { - /* Position window on back-end server */ - m = CWX | CWY | CWWidth | CWHeight; - c.x = pWindow->origin.x - wBorderWidth(pWindow); - c.y = pWindow->origin.y - wBorderWidth(pWindow); - c.width = pWindow->drawable.width; - c.height = pWindow->drawable.height; - if (pWindow->drawable.class != InputOnly) { - m |= CWBorderWidth; - c.border_width = pWindow->borderWidth; - } - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); - - return ret; -} - -static void dmxDoChangeWindowAttributes(WindowPtr pWindow, - unsigned long *mask, - XSetWindowAttributes *attribs) -{ - dmxPixPrivPtr pPixPriv; - - if (*mask & CWBackPixmap) { - switch (pWindow->backgroundState) { - case None: - attribs->background_pixmap = None; - break; - - case ParentRelative: - attribs->background_pixmap = ParentRelative; - break; - - case BackgroundPixmap: - pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->background.pixmap); - attribs->background_pixmap = pPixPriv->pixmap; - break; - - case BackgroundPixel: - *mask &= ~CWBackPixmap; - break; - } - } - - if (*mask & CWBackPixel) { - if (pWindow->backgroundState == BackgroundPixel) - attribs->background_pixel = pWindow->background.pixel; - else - *mask &= ~CWBackPixel; - } - - if (*mask & CWBorderPixmap) { - if (pWindow->borderIsPixel) - *mask &= ~CWBorderPixmap; - else { - pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->border.pixmap); - attribs->border_pixmap = pPixPriv->pixmap; - } - } - - if (*mask & CWBorderPixel) { - if (pWindow->borderIsPixel) - attribs->border_pixel = pWindow->border.pixel; - else - *mask &= ~CWBorderPixel; - } - - if (*mask & CWBitGravity) - attribs->bit_gravity = pWindow->bitGravity; - - if (*mask & CWWinGravity) - *mask &= ~CWWinGravity; /* Handled by dix */ - - if (*mask & CWBackingStore) - *mask &= ~CWBackingStore; /* Backing store not supported */ - - if (*mask & CWBackingPlanes) - *mask &= ~CWBackingPlanes; /* Backing store not supported */ - - if (*mask & CWBackingPixel) - *mask &= ~CWBackingPixel; /* Backing store not supported */ - - if (*mask & CWOverrideRedirect) - attribs->override_redirect = pWindow->overrideRedirect; - - if (*mask & CWSaveUnder) - *mask &= ~CWSaveUnder; /* Save unders not supported */ - - if (*mask & CWEventMask) - *mask &= ~CWEventMask; /* Events are handled by dix */ - - if (*mask & CWDontPropagate) - *mask &= ~CWDontPropagate; /* Events are handled by dix */ - - if (*mask & CWColormap) { - ColormapPtr pCmap; - dmxColormapPrivPtr pCmapPriv; - - pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); - pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); - attribs->colormap = pCmapPriv->cmap; - } - - if (*mask & CWCursor) - *mask &= ~CWCursor; /* Handled by the cursor code */ -} - -/** Change the window attributes of \a pWindow. */ -Bool dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - XSetWindowAttributes attribs; - - DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); -#if 0 - if (pScreen->ChangeWindowAttributes) - ret = pScreen->ChangeWindowAttributes(pWindow, mask); -#endif - - /* Change window attribs on back-end server */ - dmxDoChangeWindowAttributes(pWindow, &mask, &attribs); - - /* Save mask for lazy window creation optimization */ - pWinPriv->attribMask |= mask; - - if (mask && pWinPriv->window) { - XChangeWindowAttributes(dmxScreen->beDisplay, pWinPriv->window, - mask, &attribs); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, - pScreen); - - return ret; -} - -/** Realize \a pWindow on the back-end server. If the lazy window - * creation optimization is enabled, the window is only realized when - * it at least partially overlaps the screen. */ -Bool dmxRealizeWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->RealizeWindow) - ret = pScreen->RealizeWindow(pWindow); -#endif - - /* Determine if the window is completely off the visible portion of - the screen */ - pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); - - /* If the window hasn't been created and it's not offscreen, then - create it */ - if (!pWinPriv->window && !pWinPriv->offscreen) { - dmxCreateAndRealizeWindow(pWindow, FALSE); - } - - if (pWinPriv->window) { - /* Realize window on back-end server */ - XMapWindow(dmxScreen->beDisplay, pWinPriv->window); - dmxSync(dmxScreen, False); - } - - /* Let the other functions know that the window is now mapped */ - pWinPriv->mapped = TRUE; - - DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); - - dmxUpdateWindowInfo(DMX_UPDATE_REALIZE, pWindow); - return ret; -} - -/** Unrealize \a pWindow on the back-end server. */ -Bool dmxUnrealizeWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - Bool ret = TRUE; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->UnrealizeWindow) - ret = pScreen->UnrealizeWindow(pWindow); -#endif - - if (pWinPriv->window) { - /* Unrealize window on back-end server */ - XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); - dmxSync(dmxScreen, False); - } - - /* When unrealized (i.e., unmapped), the window is always considered - off of the visible portion of the screen */ - pWinPriv->offscreen = TRUE; - pWinPriv->mapped = FALSE; - -#ifdef GLXEXT - if (pWinPriv->swapGroup && pWinPriv->windowUnmapped) - pWinPriv->windowUnmapped(pWindow); -#endif - - DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); - - dmxUpdateWindowInfo(DMX_UPDATE_UNREALIZE, pWindow); - return ret; -} - -static void dmxDoRestackWindow(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - WindowPtr pNextSib = pWindow->nextSib; - unsigned int m; - XWindowChanges c; - - if (pNextSib == NullWindow) { - /* Window is at the bottom of the stack */ - m = CWStackMode; - c.sibling = (Window)0; - c.stack_mode = Below; - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - } else { - /* Window is not at the bottom of the stack */ - dmxWinPrivPtr pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); - - /* Handle case where siblings have not yet been created due to - lazy window creation optimization by first finding the next - sibling in the sibling list that has been created (if any) - and then putting the current window just above that sibling, - and if no next siblings have been created yet, then put it at - the bottom of the stack (since it might have a previous - sibling that should be above it). */ - while (!pNextSibPriv->window) { - pNextSib = pNextSib->nextSib; - if (pNextSib == NullWindow) { - /* Window is at the bottom of the stack */ - m = CWStackMode; - c.sibling = (Window)0; - c.stack_mode = Below; - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - return; - } - pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); - } - - m = CWStackMode | CWSibling; - c.sibling = pNextSibPriv->window; - c.stack_mode = Above; - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - } -} - -/** Handle window restacking. The actual restacking occurs in - * #dmxDoRestackWindow(). */ -void dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->RestackWindow) - pScreen->RestackWindow(pWindow, pOldNextSib); -#endif - - if (pOldNextSib != pWindow->nextSib) { - /* Track restacking for lazy window creation optimization */ - pWinPriv->restacked = TRUE; - - /* Restack window on back-end server */ - if (pWinPriv->window) { - dmxDoRestackWindow(pWindow); - dmxSync(dmxScreen, False); - } - } - - DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_RESTACK, pWindow); -} - -static Bool dmxWindowExposurePredicate(Display *dpy, XEvent *ev, XPointer ptr) -{ - return (ev->type == Expose && ev->xexpose.window == *(Window *)ptr); -} - -/** Handle exposures on \a pWindow. Since window exposures are handled - * in DMX, the events that are generated by the back-end server are - * redundant, so we eat them here. */ -void dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn, - RegionPtr other_exposed) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - XEvent ev; - - DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); - - dmxSync(dmxScreen, False); - - if (pWinPriv->window) { - while (XCheckIfEvent(dmxScreen->beDisplay, &ev, - dmxWindowExposurePredicate, - (XPointer)&pWinPriv->window)) { - /* Handle expose events -- this should not be necessary - since the base window in which the root window was - created is guaranteed to be on top (override_redirect), - so we should just swallow these events. If for some - reason the window is not on top, then we'd need to - collect these events and send them to the client later - (e.g., during the block handler as Xnest does). */ - } - } - -#if 1 - if (pScreen->WindowExposures) - pScreen->WindowExposures(pWindow, prgn, other_exposed); -#endif - DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); -} - -/** Move \a pWindow on the back-end server. Determine whether or not it - * is on or offscreen, and realize it if it is newly on screen and the - * lazy window creation optimization is enabled. */ -void dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - unsigned int m; - XWindowChanges c; - - DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->CopyWindow) - pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc); -#endif - - /* Determine if the window is completely off the visible portion of - the screen */ - pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); - - /* If the window is now on-screen and it is mapped and it has not - been created yet, create it and map it */ - if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { - dmxCreateAndRealizeWindow(pWindow, TRUE); - } else if (pWinPriv->window) { - /* Move window on back-end server */ - m = CWX | CWY | CWWidth | CWHeight; - c.x = pWindow->origin.x - wBorderWidth(pWindow); - c.y = pWindow->origin.y - wBorderWidth(pWindow); - c.width = pWindow->drawable.width; - c.height = pWindow->drawable.height; - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_COPY, pWindow); -} - -/** Resize \a pWindow on the back-end server. Determine whether or not - * it is on or offscreen, and realize it if it is newly on screen and - * the lazy window creation optimization is enabled. */ -void dmxResizeWindow(WindowPtr pWindow, int x, int y, - unsigned int w, unsigned int h, WindowPtr pSib) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - dmxWinPrivPtr pSibPriv; - unsigned int m; - XWindowChanges c; - - if (pSib) - pSibPriv = DMX_GET_WINDOW_PRIV(pSib); - - DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); -#if 1 - if (pScreen->ResizeWindow) - pScreen->ResizeWindow(pWindow, x, y, w, h, pSib); -#endif - - /* Determine if the window is completely off the visible portion of - the screen */ - pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); - - /* If the window is now on-screen and it is mapped and it has not - been created yet, create it and map it */ - if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { - dmxCreateAndRealizeWindow(pWindow, TRUE); - } else if (pWinPriv->window) { - /* Handle resizing on back-end server */ - m = CWX | CWY | CWWidth | CWHeight; - c.x = pWindow->origin.x - wBorderWidth(pWindow); - c.y = pWindow->origin.y - wBorderWidth(pWindow); - c.width = pWindow->drawable.width; - c.height = pWindow->drawable.height; - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_RESIZE, pWindow); -} - -/** Reparent \a pWindow on the back-end server. */ -void dmxReparentWindow(WindowPtr pWindow, WindowPtr pPriorParent) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); - - DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); -#if 0 - if (pScreen->ReparentWindow) - pScreen->ReparentWindow(pWindow, pPriorParent); -#endif - - if (pWinPriv->window) { - if (!pParentPriv->window) { - dmxCreateAndRealizeWindow(pWindow->parent, FALSE); - } - - /* Handle reparenting on back-end server */ - XReparentWindow(dmxScreen->beDisplay, pWinPriv->window, - pParentPriv->window, - pWindow->origin.x - wBorderWidth(pWindow), - pWindow->origin.x - wBorderWidth(pWindow)); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); - dmxUpdateWindowInfo(DMX_UPDATE_REPARENT, pWindow); -} - -/** Change border width for \a pWindow to \a width pixels. */ -void dmxChangeBorderWidth(WindowPtr pWindow, unsigned int width) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - unsigned int m; - XWindowChanges c; - - DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); -#if 1 - if (pScreen->ChangeBorderWidth) - pScreen->ChangeBorderWidth(pWindow, width); -#endif - - /* NOTE: Do we need to check for on/off screen here? */ - - if (pWinPriv->window) { - /* Handle border width change on back-end server */ - m = CWBorderWidth; - c.border_width = width; - - XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); - dmxSync(dmxScreen, False); - } - - DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); -} - -static void dmxDoSetShape(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - int nBox; - BoxPtr pBox; - int nRect; - XRectangle *pRect; - XRectangle *pRectFirst; - - /* First, set the bounding shape */ - if (wBoundingShape(pWindow)) { - pBox = REGION_RECTS(wBoundingShape(pWindow)); - nRect = nBox = REGION_NUM_RECTS(wBoundingShape(pWindow)); - pRectFirst = pRect = xalloc(nRect * sizeof(*pRect)); - while (nBox--) { - pRect->x = pBox->x1; - pRect->y = pBox->y1; - pRect->width = pBox->x2 - pBox->x1; - pRect->height = pBox->y2 - pBox->y1; - pBox++; - pRect++; - } - XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, - ShapeBounding, 0, 0, - pRectFirst, nRect, - ShapeSet, YXBanded); - xfree(pRectFirst); - } else { - XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, - ShapeBounding, 0, 0, None, ShapeSet); - } - - /* Next, set the clip shape */ - if (wClipShape(pWindow)) { - pBox = REGION_RECTS(wClipShape(pWindow)); - nRect = nBox = REGION_NUM_RECTS(wClipShape(pWindow)); - pRectFirst = pRect = xalloc(nRect * sizeof(*pRect)); - while (nBox--) { - pRect->x = pBox->x1; - pRect->y = pBox->y1; - pRect->width = pBox->x2 - pBox->x1; - pRect->height = pBox->y2 - pBox->y1; - pBox++; - pRect++; - } - XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, - ShapeClip, 0, 0, - pRectFirst, nRect, - ShapeSet, YXBanded); - xfree(pRectFirst); - } else { - XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, - ShapeClip, 0, 0, None, ShapeSet); - } - - if (XShapeInputSelected(dmxScreen->beDisplay, pWinPriv->window)) { - ErrorF("Input selected for window %x on Screen %d\n", - (unsigned int)pWinPriv->window, pScreen->myNum); - } -} - -/** Set shape of \a pWindow on the back-end server. */ -void dmxSetShape(WindowPtr pWindow) -{ - ScreenPtr pScreen = pWindow->drawable.pScreen; - DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); - - DMX_UNWRAP(SetShape, dmxScreen, pScreen); -#if 1 - if (pScreen->SetShape) - pScreen->SetShape(pWindow); -#endif - - if (pWinPriv->window) { - /* Handle setting the current shape on the back-end server */ - dmxDoSetShape(pWindow); - dmxSync(dmxScreen, False); - } else { - pWinPriv->isShaped = TRUE; - } - - DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); -} +/* + * Copyright 2001-2004 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: + * Kevin E. Martin + * + */ + +/** \file + * This file provides support for window-related functions. */ + +#ifdef HAVE_DMX_CONFIG_H +#include +#endif + +#include "dmx.h" +#include "dmxsync.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxcmap.h" +#include "dmxvisual.h" +#include "dmxinput.h" +#include "dmxextension.h" +#include "dmxpict.h" + +#include "windowstr.h" + +static void dmxDoRestackWindow(WindowPtr pWindow); +static void dmxDoChangeWindowAttributes(WindowPtr pWindow, + unsigned long *mask, + XSetWindowAttributes *attribs); + +static void dmxDoSetShape(WindowPtr pWindow); + +/** Initialize the private area for the window functions. */ +Bool dmxInitWindow(ScreenPtr pScreen) +{ + if (!dixRequestPrivate(dmxWinPrivateKey, sizeof(dmxWinPrivRec))) + return FALSE; + + return TRUE; +} + + +Window dmxCreateRootWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + Window parent; + Visual *visual; + unsigned long mask; + XSetWindowAttributes attribs; + ColormapPtr pCmap; + dmxColormapPrivPtr pCmapPriv; + + /* Create root window */ + + parent = dmxScreen->scrnWin; /* This is our "Screen" window */ + visual = dmxScreen->beVisuals[dmxScreen->beDefVisualIndex].visual; + + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); + pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); + + mask = CWEventMask | CWBackingStore | CWColormap | CWBorderPixel; + attribs.event_mask = ExposureMask; + attribs.backing_store = NotUseful; + attribs.colormap = pCmapPriv->cmap; + attribs.border_pixel = 0; + + /* Incorporate new attributes, if needed */ + if (pWinPriv->attribMask) { + dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); + mask |= pWinPriv->attribMask; + } + + return XCreateWindow(dmxScreen->beDisplay, + parent, + pWindow->origin.x - wBorderWidth(pWindow), + pWindow->origin.y - wBorderWidth(pWindow), + pWindow->drawable.width, + pWindow->drawable.height, + pWindow->borderWidth, + pWindow->drawable.depth, + pWindow->drawable.class, + visual, + mask, + &attribs); +} + +/** Change the location and size of the "screen" window. Called from + * #dmxConfigureScreenWindow(). */ +void dmxResizeScreenWindow(ScreenPtr pScreen, + int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + unsigned int m; + XWindowChanges c; + + if (!dmxScreen->beDisplay) + return; + + /* Handle resizing on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = x; + c.y = y; + c.width = w; + c.height = h; + + XConfigureWindow(dmxScreen->beDisplay, dmxScreen->scrnWin, m, &c); + dmxSync(dmxScreen, False); +} + +/** Change the location and size of the "root" window. Called from + * #dmxConfigureRootWindow. */ +void dmxResizeRootWindow(WindowPtr pRoot, + int x, int y, int w, int h) +{ + DMXScreenInfo *dmxScreen = &dmxScreens[pRoot->drawable.pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pRoot); + unsigned int m; + XWindowChanges c; + + /* Handle resizing on back-end server */ + if (dmxScreen->beDisplay) { + m = CWX | CWY | CWWidth | CWHeight; + c.x = x; + c.y = y; + c.width = (w > 0) ? w : 1; + c.height = (h > 0) ? h : 1; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + } + + if (w == 0 || h == 0) { + if (pWinPriv->mapped) { + if (dmxScreen->beDisplay) + XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); + pWinPriv->mapped = FALSE; + } + } else if (!pWinPriv->mapped) { + if (dmxScreen->beDisplay) + XMapWindow(dmxScreen->beDisplay, pWinPriv->window); + pWinPriv->mapped = TRUE; + } + + if (dmxScreen->beDisplay) + dmxSync(dmxScreen, False); +} + +void dmxGetDefaultWindowAttributes(WindowPtr pWindow, + Colormap *cmap, + Visual **visual) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + + if (pWindow->drawable.class != InputOnly && + pWindow->optional && + pWindow->optional->visual != wVisual(pWindow->parent)) { + + /* Find the matching visual */ + *visual = dmxLookupVisualFromID(pScreen, wVisual(pWindow)); + + /* Handle optional colormaps */ + if (pWindow->optional->colormap) { + ColormapPtr pCmap; + dmxColormapPrivPtr pCmapPriv; + + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), + RT_COLORMAP); + pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); + *cmap = pCmapPriv->cmap; + } else { + *cmap = dmxColormapFromDefaultVisual(pScreen, *visual); + } + } else { + *visual = CopyFromParent; + *cmap = (Colormap)0; + } +} + +static Window dmxCreateNonRootWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + Window parent; + unsigned long mask = 0L; + XSetWindowAttributes attribs; + dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); + + /* Create window on back-end server */ + + parent = pParentPriv->window; + + /* The parent won't exist if this call to CreateNonRootWindow came + from ReparentWindow and the grandparent window has not yet been + created */ + if (!parent) { + dmxCreateAndRealizeWindow(pWindow->parent, FALSE); + parent = pParentPriv->window; + } + + /* Incorporate new attributes, if needed */ + if (pWinPriv->attribMask) { + dmxDoChangeWindowAttributes(pWindow, &pWinPriv->attribMask, &attribs); + mask |= pWinPriv->attribMask; + } + + /* Add in default attributes */ + if (pWindow->drawable.class != InputOnly) { + mask |= CWBackingStore; + attribs.backing_store = NotUseful; + + if (!(mask & CWColormap) && pWinPriv->cmap) { + mask |= CWColormap; + attribs.colormap = pWinPriv->cmap; + if (!(mask & CWBorderPixel)) { + mask |= CWBorderPixel; + attribs.border_pixel = 0; + } + } + } + + /* Handle case where subwindows are being mapped, but created out of + order -- if current window has a previous sibling, then it cannot + be created on top of the stack, so we must restack the windows */ + pWinPriv->restacked = (pWindow->prevSib != NullWindow); + + return XCreateWindow(dmxScreen->beDisplay, + parent, + pWindow->origin.x - wBorderWidth(pWindow), + pWindow->origin.y - wBorderWidth(pWindow), + pWindow->drawable.width, + pWindow->drawable.height, + pWindow->borderWidth, + pWindow->drawable.depth, + pWindow->drawable.class, + pWinPriv->visual, + mask, + &attribs); +} + +/** This function handles lazy window creation and realization. Window + * creation is handled by #dmxCreateNonRootWindow(). It also handles + * any stacking changes that have occured since the window was + * originally created by calling #dmxDoRestackWindow(). If the window + * is shaped, the shape is set on the back-end server by calling + * #dmxDoSetShape(), and if the window has pictures (from RENDER) + * associated with it, those pictures are created on the back-end + * server by calling #dmxCreatePictureList(). If \a doSync is TRUE, + * then #dmxSync() is called. */ +void dmxCreateAndRealizeWindow(WindowPtr pWindow, Bool doSync) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + if (!dmxScreen->beDisplay) return; + + pWinPriv->window = dmxCreateNonRootWindow(pWindow); + if (pWinPriv->restacked) dmxDoRestackWindow(pWindow); + if (pWinPriv->isShaped) dmxDoSetShape(pWindow); + if (pWinPriv->hasPict) dmxCreatePictureList(pWindow); + if (pWinPriv->mapped) XMapWindow(dmxScreen->beDisplay, + pWinPriv->window); + if (doSync) dmxSync(dmxScreen, False); +} + +/** Create \a pWindow on the back-end server. If the lazy window + * creation optimization is enabled, then the actual creation and + * realization of the window is handled by + * #dmxCreateAndRealizeWindow(). */ +Bool dmxCreateWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + Bool ret = TRUE; + + DMX_UNWRAP(CreateWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->CreateWindow) + ret = pScreen->CreateWindow(pWindow); +#endif + + /* Set up the defaults */ + pWinPriv->window = (Window)0; + pWinPriv->offscreen = TRUE; + pWinPriv->mapped = FALSE; + pWinPriv->restacked = FALSE; + pWinPriv->attribMask = 0; + pWinPriv->isShaped = FALSE; + pWinPriv->hasPict = FALSE; +#ifdef GLXEXT + pWinPriv->swapGroup = NULL; + pWinPriv->barrier = 0; +#endif + + if (dmxScreen->beDisplay) { + /* Only create the root window at this stage -- non-root windows are + created when they are mapped and are on-screen */ + if (!pWindow->parent) { + dmxScreen->rootWin = pWinPriv->window + = dmxCreateRootWindow(pWindow); + if (dmxScreen->scrnX != dmxScreen->rootX + || dmxScreen->scrnY != dmxScreen->rootY + || dmxScreen->scrnWidth != dmxScreen->rootWidth + || dmxScreen->scrnHeight != dmxScreen->rootHeight) { + dmxResizeRootWindow(pWindow, + dmxScreen->rootX, + dmxScreen->rootY, + dmxScreen->rootWidth, + dmxScreen->rootHeight); + dmxUpdateScreenResources(screenInfo.screens[dmxScreen->index], + dmxScreen->rootX, + dmxScreen->rootY, + dmxScreen->rootWidth, + dmxScreen->rootHeight); + pWindow->origin.x = dmxScreen->rootX; + pWindow->origin.y = dmxScreen->rootY; + } + } else { + dmxGetDefaultWindowAttributes(pWindow, + &pWinPriv->cmap, + &pWinPriv->visual); + + if (dmxLazyWindowCreation) { + /* Save parent's visual for use later */ + if (pWinPriv->visual == CopyFromParent) + pWinPriv->visual = + dmxLookupVisualFromID(pScreen, + wVisual(pWindow->parent)); + } else { + pWinPriv->window = dmxCreateNonRootWindow(pWindow); + } + } + + dmxSync(dmxScreen, False); + } + + DMX_WRAP(CreateWindow, dmxCreateWindow, dmxScreen, pScreen); + + return ret; +} + +/** Destroy \a pWindow on the back-end server. */ +Bool dmxBEDestroyWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + if (pWinPriv->window) { + XDestroyWindow(dmxScreen->beDisplay, pWinPriv->window); + pWinPriv->window = (Window)0; + return TRUE; + } + + return FALSE; +} + +/** Destroy \a pWindow on the back-end server. If any RENDER pictures + were created, destroy them as well. */ +Bool dmxDestroyWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + Bool needSync = FALSE; +#ifdef GLXEXT + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); +#endif + + DMX_UNWRAP(DestroyWindow, dmxScreen, pScreen); + + /* Destroy any picture list associated with this window */ + needSync |= dmxDestroyPictureList(pWindow); + + /* Destroy window on back-end server */ + needSync |= dmxBEDestroyWindow(pWindow); + if (needSync) dmxSync(dmxScreen, FALSE); + +#ifdef GLXEXT + if (pWinPriv->swapGroup && pWinPriv->windowDestroyed) + pWinPriv->windowDestroyed(pWindow); +#endif + + if (pScreen->DestroyWindow) + ret = pScreen->DestroyWindow(pWindow); + + DMX_WRAP(DestroyWindow, dmxDestroyWindow, dmxScreen, pScreen); + + return ret; +} + +/** Change the position of \a pWindow to be \a x, \a y. */ +Bool dmxPositionWindow(WindowPtr pWindow, int x, int y) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + unsigned int m; + XWindowChanges c; + + DMX_UNWRAP(PositionWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->PositionWindow) + ret = pScreen->PositionWindow(pWindow, x, y); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window is now on-screen and it is mapped and it has not + been created yet, create it and map it */ + if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, TRUE); + } else if (pWinPriv->window) { + /* Position window on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = pWindow->origin.x - wBorderWidth(pWindow); + c.y = pWindow->origin.y - wBorderWidth(pWindow); + c.width = pWindow->drawable.width; + c.height = pWindow->drawable.height; + if (pWindow->drawable.class != InputOnly) { + m |= CWBorderWidth; + c.border_width = pWindow->borderWidth; + } + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(PositionWindow, dmxPositionWindow, dmxScreen, pScreen); + + return ret; +} + +static void dmxDoChangeWindowAttributes(WindowPtr pWindow, + unsigned long *mask, + XSetWindowAttributes *attribs) +{ + dmxPixPrivPtr pPixPriv; + + if (*mask & CWBackPixmap) { + switch (pWindow->backgroundState) { + case None: + attribs->background_pixmap = None; + break; + + case ParentRelative: + attribs->background_pixmap = ParentRelative; + break; + + case BackgroundPixmap: + pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->background.pixmap); + attribs->background_pixmap = pPixPriv->pixmap; + break; + + case BackgroundPixel: + *mask &= ~CWBackPixmap; + break; + } + } + + if (*mask & CWBackPixel) { + if (pWindow->backgroundState == BackgroundPixel) + attribs->background_pixel = pWindow->background.pixel; + else + *mask &= ~CWBackPixel; + } + + if (*mask & CWBorderPixmap) { + if (pWindow->borderIsPixel) + *mask &= ~CWBorderPixmap; + else { + pPixPriv = DMX_GET_PIXMAP_PRIV(pWindow->border.pixmap); + attribs->border_pixmap = pPixPriv->pixmap; + } + } + + if (*mask & CWBorderPixel) { + if (pWindow->borderIsPixel) + attribs->border_pixel = pWindow->border.pixel; + else + *mask &= ~CWBorderPixel; + } + + if (*mask & CWBitGravity) + attribs->bit_gravity = pWindow->bitGravity; + + if (*mask & CWWinGravity) + *mask &= ~CWWinGravity; /* Handled by dix */ + + if (*mask & CWBackingStore) + *mask &= ~CWBackingStore; /* Backing store not supported */ + + if (*mask & CWBackingPlanes) + *mask &= ~CWBackingPlanes; /* Backing store not supported */ + + if (*mask & CWBackingPixel) + *mask &= ~CWBackingPixel; /* Backing store not supported */ + + if (*mask & CWOverrideRedirect) + attribs->override_redirect = pWindow->overrideRedirect; + + if (*mask & CWSaveUnder) + *mask &= ~CWSaveUnder; /* Save unders not supported */ + + if (*mask & CWEventMask) + *mask &= ~CWEventMask; /* Events are handled by dix */ + + if (*mask & CWDontPropagate) + *mask &= ~CWDontPropagate; /* Events are handled by dix */ + + if (*mask & CWColormap) { + ColormapPtr pCmap; + dmxColormapPrivPtr pCmapPriv; + + pCmap = (ColormapPtr)LookupIDByType(wColormap(pWindow), RT_COLORMAP); + pCmapPriv = DMX_GET_COLORMAP_PRIV(pCmap); + attribs->colormap = pCmapPriv->cmap; + } + + if (*mask & CWCursor) + *mask &= ~CWCursor; /* Handled by the cursor code */ +} + +/** Change the window attributes of \a pWindow. */ +Bool dmxChangeWindowAttributes(WindowPtr pWindow, unsigned long mask) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + XSetWindowAttributes attribs; + + DMX_UNWRAP(ChangeWindowAttributes, dmxScreen, pScreen); +#if 0 + if (pScreen->ChangeWindowAttributes) + ret = pScreen->ChangeWindowAttributes(pWindow, mask); +#endif + + /* Change window attribs on back-end server */ + dmxDoChangeWindowAttributes(pWindow, &mask, &attribs); + + /* Save mask for lazy window creation optimization */ + pWinPriv->attribMask |= mask; + + if (mask && pWinPriv->window) { + XChangeWindowAttributes(dmxScreen->beDisplay, pWinPriv->window, + mask, &attribs); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ChangeWindowAttributes, dmxChangeWindowAttributes, dmxScreen, + pScreen); + + return ret; +} + +/** Realize \a pWindow on the back-end server. If the lazy window + * creation optimization is enabled, the window is only realized when + * it at least partially overlaps the screen. */ +Bool dmxRealizeWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(RealizeWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->RealizeWindow) + ret = pScreen->RealizeWindow(pWindow); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window hasn't been created and it's not offscreen, then + create it */ + if (!pWinPriv->window && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, FALSE); + } + + if (pWinPriv->window) { + /* Realize window on back-end server */ + XMapWindow(dmxScreen->beDisplay, pWinPriv->window); + dmxSync(dmxScreen, False); + } + + /* Let the other functions know that the window is now mapped */ + pWinPriv->mapped = TRUE; + + DMX_WRAP(RealizeWindow, dmxRealizeWindow, dmxScreen, pScreen); + + dmxUpdateWindowInfo(DMX_UPDATE_REALIZE, pWindow); + return ret; +} + +/** Unrealize \a pWindow on the back-end server. */ +Bool dmxUnrealizeWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + Bool ret = TRUE; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(UnrealizeWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->UnrealizeWindow) + ret = pScreen->UnrealizeWindow(pWindow); +#endif + + if (pWinPriv->window) { + /* Unrealize window on back-end server */ + XUnmapWindow(dmxScreen->beDisplay, pWinPriv->window); + dmxSync(dmxScreen, False); + } + + /* When unrealized (i.e., unmapped), the window is always considered + off of the visible portion of the screen */ + pWinPriv->offscreen = TRUE; + pWinPriv->mapped = FALSE; + +#ifdef GLXEXT + if (pWinPriv->swapGroup && pWinPriv->windowUnmapped) + pWinPriv->windowUnmapped(pWindow); +#endif + + DMX_WRAP(UnrealizeWindow, dmxUnrealizeWindow, dmxScreen, pScreen); + + dmxUpdateWindowInfo(DMX_UPDATE_UNREALIZE, pWindow); + return ret; +} + +static void dmxDoRestackWindow(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + WindowPtr pNextSib = pWindow->nextSib; + unsigned int m; + XWindowChanges c; + + if (pNextSib == NullWindow) { + /* Window is at the bottom of the stack */ + m = CWStackMode; + c.sibling = (Window)0; + c.stack_mode = Below; + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + } else { + /* Window is not at the bottom of the stack */ + dmxWinPrivPtr pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); + + /* Handle case where siblings have not yet been created due to + lazy window creation optimization by first finding the next + sibling in the sibling list that has been created (if any) + and then putting the current window just above that sibling, + and if no next siblings have been created yet, then put it at + the bottom of the stack (since it might have a previous + sibling that should be above it). */ + while (!pNextSibPriv->window) { + pNextSib = pNextSib->nextSib; + if (pNextSib == NullWindow) { + /* Window is at the bottom of the stack */ + m = CWStackMode; + c.sibling = (Window)0; + c.stack_mode = Below; + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + return; + } + pNextSibPriv = DMX_GET_WINDOW_PRIV(pNextSib); + } + + m = CWStackMode | CWSibling; + c.sibling = pNextSibPriv->window; + c.stack_mode = Above; + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + } +} + +/** Handle window restacking. The actual restacking occurs in + * #dmxDoRestackWindow(). */ +void dmxRestackWindow(WindowPtr pWindow, WindowPtr pOldNextSib) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(RestackWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->RestackWindow) + pScreen->RestackWindow(pWindow, pOldNextSib); +#endif + + if (pOldNextSib != pWindow->nextSib) { + /* Track restacking for lazy window creation optimization */ + pWinPriv->restacked = TRUE; + + /* Restack window on back-end server */ + if (pWinPriv->window) { + dmxDoRestackWindow(pWindow); + dmxSync(dmxScreen, False); + } + } + + DMX_WRAP(RestackWindow, dmxRestackWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_RESTACK, pWindow); +} + +static Bool dmxWindowExposurePredicate(Display *dpy, XEvent *ev, XPointer ptr) +{ + return (ev->type == Expose && ev->xexpose.window == *(Window *)ptr); +} + +/** Handle exposures on \a pWindow. Since window exposures are handled + * in DMX, the events that are generated by the back-end server are + * redundant, so we eat them here. */ +void dmxWindowExposures(WindowPtr pWindow, RegionPtr prgn, + RegionPtr other_exposed) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + XEvent ev; + + DMX_UNWRAP(WindowExposures, dmxScreen, pScreen); + + dmxSync(dmxScreen, False); + + if (pWinPriv->window) { + while (XCheckIfEvent(dmxScreen->beDisplay, &ev, + dmxWindowExposurePredicate, + (XPointer)&pWinPriv->window)) { + /* Handle expose events -- this should not be necessary + since the base window in which the root window was + created is guaranteed to be on top (override_redirect), + so we should just swallow these events. If for some + reason the window is not on top, then we'd need to + collect these events and send them to the client later + (e.g., during the block handler as Xnest does). */ + } + } + +#if 1 + if (pScreen->WindowExposures) + pScreen->WindowExposures(pWindow, prgn, other_exposed); +#endif + DMX_WRAP(WindowExposures, dmxWindowExposures, dmxScreen, pScreen); +} + +/** Move \a pWindow on the back-end server. Determine whether or not it + * is on or offscreen, and realize it if it is newly on screen and the + * lazy window creation optimization is enabled. */ +void dmxCopyWindow(WindowPtr pWindow, DDXPointRec ptOldOrg, RegionPtr prgnSrc) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + unsigned int m; + XWindowChanges c; + + DMX_UNWRAP(CopyWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->CopyWindow) + pScreen->CopyWindow(pWindow, ptOldOrg, prgnSrc); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window is now on-screen and it is mapped and it has not + been created yet, create it and map it */ + if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, TRUE); + } else if (pWinPriv->window) { + /* Move window on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = pWindow->origin.x - wBorderWidth(pWindow); + c.y = pWindow->origin.y - wBorderWidth(pWindow); + c.width = pWindow->drawable.width; + c.height = pWindow->drawable.height; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(CopyWindow, dmxCopyWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_COPY, pWindow); +} + +/** Resize \a pWindow on the back-end server. Determine whether or not + * it is on or offscreen, and realize it if it is newly on screen and + * the lazy window creation optimization is enabled. */ +void dmxResizeWindow(WindowPtr pWindow, int x, int y, + unsigned int w, unsigned int h, WindowPtr pSib) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + dmxWinPrivPtr pSibPriv; + unsigned int m; + XWindowChanges c; + + if (pSib) + pSibPriv = DMX_GET_WINDOW_PRIV(pSib); + + DMX_UNWRAP(ResizeWindow, dmxScreen, pScreen); +#if 1 + if (pScreen->ResizeWindow) + pScreen->ResizeWindow(pWindow, x, y, w, h, pSib); +#endif + + /* Determine if the window is completely off the visible portion of + the screen */ + pWinPriv->offscreen = DMX_WINDOW_OFFSCREEN(pWindow); + + /* If the window is now on-screen and it is mapped and it has not + been created yet, create it and map it */ + if (!pWinPriv->window && pWinPriv->mapped && !pWinPriv->offscreen) { + dmxCreateAndRealizeWindow(pWindow, TRUE); + } else if (pWinPriv->window) { + /* Handle resizing on back-end server */ + m = CWX | CWY | CWWidth | CWHeight; + c.x = pWindow->origin.x - wBorderWidth(pWindow); + c.y = pWindow->origin.y - wBorderWidth(pWindow); + c.width = pWindow->drawable.width; + c.height = pWindow->drawable.height; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ResizeWindow, dmxResizeWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_RESIZE, pWindow); +} + +/** Reparent \a pWindow on the back-end server. */ +void dmxReparentWindow(WindowPtr pWindow, WindowPtr pPriorParent) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + dmxWinPrivPtr pParentPriv = DMX_GET_WINDOW_PRIV(pWindow->parent); + + DMX_UNWRAP(ReparentWindow, dmxScreen, pScreen); +#if 0 + if (pScreen->ReparentWindow) + pScreen->ReparentWindow(pWindow, pPriorParent); +#endif + + if (pWinPriv->window) { + if (!pParentPriv->window) { + dmxCreateAndRealizeWindow(pWindow->parent, FALSE); + } + + /* Handle reparenting on back-end server */ + XReparentWindow(dmxScreen->beDisplay, pWinPriv->window, + pParentPriv->window, + pWindow->origin.x - wBorderWidth(pWindow), + pWindow->origin.x - wBorderWidth(pWindow)); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ReparentWindow, dmxReparentWindow, dmxScreen, pScreen); + dmxUpdateWindowInfo(DMX_UPDATE_REPARENT, pWindow); +} + +/** Change border width for \a pWindow to \a width pixels. */ +void dmxChangeBorderWidth(WindowPtr pWindow, unsigned int width) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + unsigned int m; + XWindowChanges c; + + DMX_UNWRAP(ChangeBorderWidth, dmxScreen, pScreen); +#if 1 + if (pScreen->ChangeBorderWidth) + pScreen->ChangeBorderWidth(pWindow, width); +#endif + + /* NOTE: Do we need to check for on/off screen here? */ + + if (pWinPriv->window) { + /* Handle border width change on back-end server */ + m = CWBorderWidth; + c.border_width = width; + + XConfigureWindow(dmxScreen->beDisplay, pWinPriv->window, m, &c); + dmxSync(dmxScreen, False); + } + + DMX_WRAP(ChangeBorderWidth, dmxChangeBorderWidth, dmxScreen, pScreen); +} + +static void dmxDoSetShape(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + int nBox; + BoxPtr pBox; + int nRect; + XRectangle *pRect; + XRectangle *pRectFirst; + + /* First, set the bounding shape */ + if (wBoundingShape(pWindow)) { + pBox = REGION_RECTS(wBoundingShape(pWindow)); + nRect = nBox = REGION_NUM_RECTS(wBoundingShape(pWindow)); + pRectFirst = pRect = malloc(nRect * sizeof(*pRect)); + while (nBox--) { + pRect->x = pBox->x1; + pRect->y = pBox->y1; + pRect->width = pBox->x2 - pBox->x1; + pRect->height = pBox->y2 - pBox->y1; + pBox++; + pRect++; + } + XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, + ShapeBounding, 0, 0, + pRectFirst, nRect, + ShapeSet, YXBanded); + free(pRectFirst); + } else { + XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, + ShapeBounding, 0, 0, None, ShapeSet); + } + + /* Next, set the clip shape */ + if (wClipShape(pWindow)) { + pBox = REGION_RECTS(wClipShape(pWindow)); + nRect = nBox = REGION_NUM_RECTS(wClipShape(pWindow)); + pRectFirst = pRect = malloc(nRect * sizeof(*pRect)); + while (nBox--) { + pRect->x = pBox->x1; + pRect->y = pBox->y1; + pRect->width = pBox->x2 - pBox->x1; + pRect->height = pBox->y2 - pBox->y1; + pBox++; + pRect++; + } + XShapeCombineRectangles(dmxScreen->beDisplay, pWinPriv->window, + ShapeClip, 0, 0, + pRectFirst, nRect, + ShapeSet, YXBanded); + free(pRectFirst); + } else { + XShapeCombineMask(dmxScreen->beDisplay, pWinPriv->window, + ShapeClip, 0, 0, None, ShapeSet); + } + + if (XShapeInputSelected(dmxScreen->beDisplay, pWinPriv->window)) { + ErrorF("Input selected for window %x on Screen %d\n", + (unsigned int)pWinPriv->window, pScreen->myNum); + } +} + +/** Set shape of \a pWindow on the back-end server. */ +void dmxSetShape(WindowPtr pWindow) +{ + ScreenPtr pScreen = pWindow->drawable.pScreen; + DMXScreenInfo *dmxScreen = &dmxScreens[pScreen->myNum]; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWindow); + + DMX_UNWRAP(SetShape, dmxScreen, pScreen); +#if 1 + if (pScreen->SetShape) + pScreen->SetShape(pWindow); +#endif + + if (pWinPriv->window) { + /* Handle setting the current shape on the back-end server */ + dmxDoSetShape(pWindow); + dmxSync(dmxScreen, False); + } else { + pWinPriv->isShaped = TRUE; + } + + DMX_WRAP(SetShape, dmxSetShape, dmxScreen, pScreen); +} diff --git a/xorg-server/hw/dmx/doc/dmx.sgml b/xorg-server/hw/dmx/doc/dmx.sgml index ef66d1195..4342c2fce 100644 --- a/xorg-server/hw/dmx/doc/dmx.sgml +++ b/xorg-server/hw/dmx/doc/dmx.sgml @@ -1,2778 +1,2777 @@ - -
- - - Distributed Multihead X design - <author>Kevin E. Martin, David H. Dawes, and Rickard E. Faith - <date>29 June 2004 (created 25 July 2001) - <abstract> - This document covers the motivation, background, design, and - implementation of the distributed multihead X (DMX) system. It - is a living document and describes the current design and - implementation details of the DMX system. As the project - progresses, this document will be continually updated to reflect - the changes in the code and/or design. <it>Copyright 2001 by VA - Linux Systems, Inc., Fremont, California. Copyright 2001-2004 - by Red Hat, Inc., Raleigh, North Carolina</it> - </abstract> - - <!-- Table of contents --> - <toc> - -<!-- Begin the document --> -<sect>Introduction - -<sect1>The Distributed Multihead X Server - -<p>Current Open Source multihead solutions are limited to a single -physical machine. A single X server controls multiple display devices, -which can be arranged as independent heads or unified into a single -desktop (with Xinerama). These solutions are limited to the number of -physical devices that can co-exist in a single machine (e.g., due to the -number of AGP/PCI slots available for graphics cards). Thus, large -tiled displays are not currently possible. The work described in this -paper will eliminate the requirement that the display devices reside in -the same physical machine. This will be accomplished by developing a -front-end proxy X server that will control multiple back-end X servers -that make up the large display. - -<p>The overall structure of the distributed multihead X (DMX) project is -as follows: A single front-end X server will act as a proxy to a set of -back-end X servers, which handle all of the visible rendering. X -clients will connect to the front-end server just as they normally would -to a regular X server. The front-end server will present an abstracted -view to the client of a single large display. This will ensure that all -standard X clients will continue to operate without modification -(limited, as always, by the visuals and extensions provided by the X -server). Clients that are DMX-aware will be able to use an extension to -obtain information about the back-end servers (e.g., for placement of -pop-up windows, window alignments by the window manager, etc.). - -<p>The architecture of the DMX server is divided into two main sections: -input (e.g., mouse and keyboard events) and output (e.g., rendering and -windowing requests). Each of these are describe briefly below, and the -rest of this design document will describe them in greater detail. - -<p>The DMX server can receive input from three general types of input -devices: "local" devices that are physically attached to the machine on -which DMX is running, "backend" devices that are physically attached to -one or more of the back-end X servers (and that generate events via the -X protocol stream from the backend), and "console" devices that can be -abstracted from any non-back-end X server. Backend and console devices -are treated differently because the pointer device on the back-end X -server also controls the location of the hardware X cursor. Full -support for XInput extension devices is provided. - -<p>Rendering requests will be accepted by the front-end server; however, -rendering to visible windows will be broken down as needed and sent to -the appropriate back-end server(s) via X11 library calls for actual -rendering. The basic framework will follow a Xnest-style approach. GC -state will be managed in the front-end server and sent to the -appropriate back-end server(s) as required. Pixmap rendering will (at -least initially) be handled by the front-end X server. Windowing -requests (e.g., ordering, mapping, moving, etc.) will handled in the -front-end server. If the request requires a visible change, the -windowing operation will be translated into requests for the appropriate -back-end server(s). Window state will be mirrored in the back-end -server(s) as needed. - -<sect1>Layout of Paper - -<p>The next section describes the general development plan that was -actually used for implementation. The final section discusses -outstanding issues at the conclusion of development. The first appendix -provides low-level technical detail that may be of interest to those -intimately familiar with the X server architecture. The final appendix -describes the four phases of development that were performed during the -first two years of development. - -<p>The final year of work was divided into 9 tasks that are not -described in specific sections of this document. The major tasks during -that time were the enhancement of the reconfiguration ability added in -Phase IV, addition of support for a dynamic number of back-end displays -(instead of a hard-coded limit), and the support for back-end display -and input removal and addition. This work is mentioned in this paper, -but is not covered in detail. - -<!-- ============================================================ --> -<sect>Development plan - -<p>This section describes the development plan from approximately June -2001 through July 2003. - -<sect1>Bootstrap code - -<p>To allow for rapid development of the DMX server by multiple -developers during the first development stage, the problem will be -broken down into three tasks: the overall DMX framework, back-end -rendering services and input device handling services. However, before -the work begins on these tasks, a simple framework that each developer -could use was implemented to bootstrap the development effort. This -framework renders to a single back-end server and provides dummy input -devices (i.e., the keyboard and mouse). The simple back-end rendering -service was implemented using the shadow framebuffer support currently -available in the XFree86 environment. - -<p>Using this bootstrapping framework, each developer has been able to -work on each of the tasks listed above independently as follows: the -framework will be extended to handle arbitrary back-end server -configurations; the back-end rendering services will be transitioned to -the more efficient Xnest-style implementation; and, an input device -framework to handle various input devices via the input extension will -be developed. - -<p>Status: The boot strap code is complete. <!-- August 2001 --> - - -<sect1>Input device handling - -<p>An X server (including the front-end X server) requires two core -input devices -- a keyboard and a pointer (mouse). These core devices -are handled and required by the core X11 protocol. Additional types of -input devices may be attached and utilized via the XInput extension. -These are usually referred to as ``XInput extension devices'', - -<p>There are some options as to how the front-end X server gets its core -input devices: - -<enum> - <item>Local Input. The physical input devices (e.g., keyboard and - mouse) can be attached directly to the front-end X server. In this - case, the keyboard and mouse on the machine running the front-end X - server will be used. The front-end will have drivers to read the - raw input from those devices and convert it into the required X - input events (e.g., key press/release, pointer button press/release, - pointer motion). The front-end keyboard driver will keep track of - keyboard properties such as key and modifier mappings, autorepeat - state, keyboard sound and led state. Similarly the front-end - pointer driver will keep track if pointer properties such as the - button mapping and movement acceleration parameters. With this - option, input is handled fully in the front-end X server, and the - back-end X servers are used in a display-only mode. This option was - implemented and works for a limited number of Linux-specific - devices. Adding additional local input devices for other - architectures is expected to be relatively simple. - - <p>The following options are available for implementing local input - devices: - - <enum> - <item>The XFree86 X server has modular input drivers that could - be adapted for this purpose. The mouse driver supports a wide - range of mouse types and interfaces, as well as a range of - Operating System platforms. The keyboard driver in XFree86 is - not currently as modular as the mouse driver, but could be made - so. The XFree86 X server also has a range of other input - drivers for extended input devices such as tablets and touch - screens. Unfortunately, the XFree86 drivers are generally - complex, often simultaneously providing support for multiple - devices across multiple architectures; and rely so heavily on - XFree86-specific helper-functions, that this option was not - pursued. - - - <item>The <tt/kdrive/ X server in XFree86 has built-in drivers that - support PS/2 mice and keyboard under Linux. The mouse driver - can indirectly handle other mouse types if the Linux utility - <tt/gpm/ is used as to translate the native mouse protocol into - PS/2 mouse format. These drivers could be adapted and built in - to the front-end X server if this range of hardware and OS - support is sufficient. While much simpler than the XFree86 - drivers, the <tt/kdrive/ drivers were not used for the DMX - implementation. - - <item>Reimplementation of keyboard and mouse drivers from - scratch for the DMX framework. Because keyboard and mouse - drivers are relatively trivial to implement, this pathway was - selected. Other drivers in the X source tree were referenced, - and significant contributions from other drivers are noted in - the DMX source code. - </enum> - - <item>Backend Input. The front-end can make use of the core input - devices attached to one or more of the back-end X servers. Core - input events from multiple back-ends are merged into a single input - event stream. This can work sanely when only a single set of input - devices is used at any given time. The keyboard and pointer state - will be handled in the front-end, with changes propagated to the - back-end servers as needed. This option was implemented and works - well. Because the core pointer on a back-end controls the hardware - mouse on that back-end, core pointers cannot be treated as XInput - extension devices. However, all back-end XInput extensions devices - can be mapped to either DMX core or DMX XInput extension devices. - - <item>Console Input. The front-end server could create a console - window that is displayed on an X server independent of the back-end - X servers. This console window could display things like the - physical screen layout, and the front-end could get its core input - events from events delivered to the console window. This option was - implemented and works well. To help the human navigate, window - outlines are also displayed in the console window. Further, console - windows can be used as either core or XInput extension devices. - - <item>Other options were initially explored, but they were all - partial subsets of the options listed above and, hence, are - irrelevant. - -</enum> - -<p>Although extended input devices are not specifically mentioned in the -Distributed X requirements, the options above were all implemented so -that XInput extension devices were supported. - -<p>The bootstrap code (Xdmx) had dummy input devices, and these are -still supported in the final version. These do the necessary -initialization to satisfy the X server's requirements for core pointer -and keyboard devices, but no input events are ever generated. - -<p>Status: The input code is complete. Because of the complexity of the -XFree86 input device drivers (and their heavy reliance on XFree86 -infrastructure), separate low-level device drivers were implemented for -Xdmx. The following kinds of drivers are supported (in general, the -devices can be treated arbitrarily as "core" input devices or as XInput -"extension" devices; and multiple instances of different kinds of -devices can be simultaneously available): - <enum> - <item> A "dummy" device drive that never generates events. - - <item> "Local" input is from the low-level hardware on which the - Xdmx binary is running. This is the only area where using the - XFree86 driver infrastructure would have been helpful, and then - only partially, since good support for generic USB devices does - not yet exist in XFree86 (in any case, XFree86 and kdrive driver - code was used where possible). Currently, the following local - devices are supported under Linux (porting to other operating - systems should be fairly straightforward): - <itemize> - <item>Linux keyboard - <item>Linux serial mouse (MS) - <item>Linux PS/2 mouse - <item>USB keyboard - <item>USB mouse - <item>USB generic device (e.g., joystick, gamepad, etc.) - </itemize> - - <item> "Backend" input is taken from one or more of the back-end - displays. In this case, events are taken from the back-end X - server and are converted to Xdmx events. Care must be taken so - that the sprite moves properly on the display from which input - is being taken. - - <item> "Console" input is taken from an X window that Xdmx - creates on the operator's display (i.e., on the machine running - the Xdmx binary). When the operator's mouse is inside the - console window, then those events are converted to Xdmx events. - Several special features are available: the console can display - outlines of windows that are on the Xdmx display (to facilitate - navigation), the cursor can be confined to the console, and a - "fine" mode can be activated to allow very precise cursor - positioning. - </enum> - - -<!-- May 2002; July 2003 --> - -<sect1>Output device handling - -<p>The output of the DMX system displays rendering and windowing -requests across multiple screens. The screens are typically arranged in -a grid such that together they represent a single large display. - -<p>The output section of the DMX code consists of two parts. The first -is in the front-end proxy X server (Xdmx), which accepts client -connections, manages the windows, and potentially renders primitives but -does not actually display any of the drawing primitives. The second -part is the back-end X server(s), which accept commands from the -front-end server and display the results on their screens. - -<sect2>Initialization - -<p>The DMX front-end must first initialize its screens by connecting to -each of the back-end X servers and collecting information about each of -these screens. However, the information collected from the back-end X -servers might be inconsistent. Handling these cases can be difficult -and/or inefficient. For example, a two screen system has one back-end X -server running at 16bpp while the second is running at 32bpp. -Converting rendering requests (e.g., XPutImage() or XGetImage() -requests) to the appropriate bit depth can be very time consuming. -Analyzing these cases to determine how or even if it is possible to -handle them is required. The current Xinerama code handles many of -these cases (e.g., in PanoramiXConsolidate()) and will be used as a -starting point. In general, the best solution is to use homogeneous X -servers and display devices. Using back-end servers with the same depth -is a requirement of the final DMX implementation. - -<p>Once this screen consolidation is finished, the relative position of -each back-end X server's screen in the unified screen is initialized. A -full-screen window is opened on each of the back-end X servers, and the -cursor on each screen is turned off. The final DMX implementation can -also make use of a partial-screen window, or multiple windows per -back-end screen. - -<sect2>Handling rendering requests - -<p>After initialization, X applications connect to the front-end server. -There are two possible implementations of how rendering and windowing -requests are handled in the DMX system: - -<enum> - <item>A shadow framebuffer is used in the front-end server as the - render target. In this option, all protocol requests are completely - handled in the front-end server. All state and resources are - maintained in the front-end including a shadow copy of the entire - framebuffer. The framebuffers attached to the back-end servers are - updated by XPutImage() calls with data taken directly from the - shadow framebuffer. - - <p>This solution suffers from two main problems. First, it does not - take advantage of any accelerated hardware available in the system. - Second, the size of the XPutImage() calls can be quite large and - thus will be limited by the bandwidth available. - - <p>The initial DMX implementation used a shadow framebuffer by - default. - - <item>Rendering requests are sent to each back-end server for - handling (as is done in the Xnest server described above). In this - option, certain protocol requests are handled in the front-end - server and certain requests are repackaged and then sent to the - back-end servers. The framebuffer is distributed across the - multiple back-end servers. Rendering to the framebuffer is handled - on each back-end and can take advantage of any acceleration - available on the back-end servers' graphics display device. State - is maintained both in the front and back-end servers. - - <p>This solution suffers from two main drawbacks. First, protocol - requests are sent to all back-end servers -- even those that will - completely clip the rendering primitive -- which wastes bandwidth - and processing time. Second, state is maintained both in the front- - and back-end servers. These drawbacks are not as severe as in - option 1 (above) and can either be overcome through optimizations or - are acceptable. Therefore, this option will be used in the final - implementation. - - <p>The final DMX implementation defaults to this mechanism, but also - supports the shadow framebuffer mechanism. Several optimizations - were implemented to eliminate the drawbacks of the default - mechanism. These optimizations are described the section below and - in Phase II of the Development Results (see appendix). - -</enum> - -<p>Status: Both the shadow framebuffer and Xnest-style code is complete. -<!-- May 2002 --> - - -<sect1>Optimizing DMX - -<p>Initially, the Xnest-style solution's performance will be measured -and analyzed to determine where the performance bottlenecks exist. -There are four main areas that will be addressed. - -<p>First, to obtain reasonable interactivity with the first development -phase, XSync() was called after each protocol request. The XSync() -function flushes any pending protocol requests. It then waits for the -back-end to process the request and send a reply that the request has -completed. This happens with each back-end server and performance -greatly suffers. As a result of the way XSync() is called in the first -development phase, the batching that the X11 library performs is -effectively defeated. The XSync() call usage will be analyzed and -optimized by batching calls and performing them at regular intervals, -except where interactivity will suffer (e.g., on cursor movements). - -<p>Second, the initial Xnest-style solution described above sends the -repackaged protocol requests to all back-end servers regardless of -whether or not they would be completely clipped out. The requests that -are trivially rejected on the back-end server wastes the limited -bandwidth available. By tracking clipping changes in the DMX X server's -windowing code (e.g., by opening, closing, moving or resizing windows), -we can determine whether or not back-end windows are visible so that -trivial tests in the front-end server's GC ops drawing functions can -eliminate these unnecessary protocol requests. - -<p>Third, each protocol request will be analyzed to determine if it is -possible to break the request into smaller pieces at display boundaries. -The initial ones to be analyzed are put and get image requests since -they will require the greatest bandwidth to transmit data between the -front and back-end servers. Other protocol requests will be analyzed -and those that will benefit from breaking them into smaller requests -will be implemented. - -<p>Fourth, an extension is being considered that will allow font glyphs to -be transferred from the front-end DMX X server to each back-end server. -This extension will permit the front-end to handle all font requests and -eliminate the requirement that all back-end X servers share the exact -same fonts as the front-end server. We are investigating the -feasibility of this extension during this development phase. - -<p>Other potential optimizations will be determined from the performance -analysis. - -<p>Please note that in our initial design, we proposed optimizing BLT -operations (e.g., XCopyArea() and window moves) by developing an -extension that would allow individual back-end servers to directly copy -pixel data to other back-end servers. This potential optimization was -in response to the simple image movement implementation that required -potentially many calls to GetImage() and PutImage(). However, the -current Xinerama implementation handles these BLT operations -differently. Instead of copying data to and from screens, they generate -expose events -- just as happens in the case when a window is moved from -off a screen to on screen. This approach saves the limited bandwidth -available between front and back-end servers and is being standardized -with Xinerama. It also eliminates the potential setup problems and -security issues resulting from having each back-end server open -connections to all other back-end servers. Therefore, we suggest -accepting Xinerama's expose event solution. - -<p>Also note that the approach proposed in the second and third -optimizations might cause backing store algorithms in the back-end to be -defeated, so a DMX X server configuration flag will be added to disable -these optimizations. - -<p>Status: The optimizations proposed above are complete. It was -determined that the using the xfs font server was sufficient and -creating a new mechanism to pass glyphs was redundant; therefore, the -fourth optimization proposed above was not included in DMX. -<!-- September 2002 --> - - -<sect1>DMX X extension support - -<p>The DMX X server keeps track of all the windowing information on the -back-end X servers, but does not currently export this information to -any client applications. An extension will be developed to pass the -screen information and back-end window IDs to DMX-aware clients. These -clients can then use this information to directly connect to and render -to the back-end windows. Bypassing the DMX X server allows DMX-aware -clients to break up complex rendering requests on their own and send -them directly to the windows on the back-end server's screens. An -example of a client that can make effective use of this extension is -Chromium. - -<p>Status: The extension, as implemented, is fully documented in -"Client-to-Server DMX Extension to the X Protocol". Future changes -might be required based on feedback and other proposed enhancements to -DMX. Currently, the following facilities are supported: -<enum> - <item> - Screen information (clipping rectangle for each screen relative - to the virtual screen) - <item> - Window information (window IDs and clipping information for each - back-end window that corresponds to each DMX window) - <item> - Input device information (mappings from DMX device IDs to - back-end device IDs) - <item> - Force window creation (so that a client can override the - server-side lazy window creation optimization) - <item> - Reconfiguration (so that a client can request that a screen - position be changed) - <item> - Addition and removal of back-end servers and back-end and - console inputs. -</enum> -<!-- September 2002; July 2003 --> - - -<sect1>Common X extension support - -<p>The XInput, XKeyboard and Shape extensions are commonly used -extensions to the base X11 protocol. XInput allows multiple and -non-standard input devices to be accessed simultaneously. These input -devices can be connected to either the front-end or back-end servers. -XKeyboard allows much better keyboard mappings control. Shape adds -support for arbitrarily shaped windows and is used by various window -managers. Nearly all potential back-end X servers make these extensions -available, and support for each one will be added to the DMX system. - -<p>In addition to the extensions listed above, support for the X -Rendering extension (Render) is being developed. Render adds digital -image composition to the rendering model used by the X Window System. -While this extension is still under development by Keith Packard of HP, -support for the current version will be added to the DMX system. - -<p>Support for the XTest extension was added during the first -development phase. - -<!-- WARNING: this list is duplicated in the Phase IV discussion --> -<p>Status: The following extensions are supported and are discussed in -more detail in Phase IV of the Development Results (see appendix): - BIG-REQUESTS, - DEC-XTRAP, - DMX, - DPMS, - Extended-Visual-Information, - GLX, - LBX, - RECORD, - RENDER, - SECURITY, - SHAPE, - SYNC, - X-Resource, - XC-APPGROUP, - XC-MISC, - XFree86-Bigfont, - XINERAMA, - XInputExtension, - XKEYBOARD, and - XTEST. -<!-- November 2002; updated February 2003, July 2003 --> - -<sect1>OpenGL support - -<p>OpenGL support using the Mesa code base exists in XFree86 release 4 -and later. Currently, the direct rendering infrastructure (DRI) -provides accelerated OpenGL support for local clients and unaccelerated -OpenGL support (i.e., software rendering) is provided for non-local -clients. - -<p>The single head OpenGL support in XFree86 4.x will be extended to use -the DMX system. When the front and back-end servers are on the same -physical hardware, it is possible to use the DRI to directly render to -the back-end servers. First, the existing DRI will be extended to -support multiple display heads, and then to support the DMX system. -OpenGL rendering requests will be direct rendering to each back-end X -server. The DRI will request the screen layout (either from the -existing Xinerama extension or a DMX-specific extension). Support for -synchronized swap buffers will also be added (on hardware that supports -it). Note that a single front-end server with a single back-end server -on the same physical machine can emulate accelerated indirect rendering. - -<p>When the front and back-end servers are on different physical -hardware or are using non-XFree86 4.x X servers, a mechanism to render -primitives across the back-end servers will be provided. There are -several options as to how this can be implemented. - -<enum> - <item>The existing OpenGL support in each back-end server can be - used by repackaging rendering primitives and sending them to each - back-end server. This option is similar to the unoptimized - Xnest-style approach mentioned above. Optimization of this solution - is beyond the scope of this project and is better suited to other - distributed rendering systems. - - <item>Rendering to a pixmap in the front-end server using the - current XFree86 4.x code, and then displaying to the back-ends via - calls to XPutImage() is another option. This option is similar to - the shadow frame buffer approach mentioned above. It is slower and - bandwidth intensive, but has the advantage that the back-end servers - are not required to have OpenGL support. -</enum> - -<p>These, and other, options will be investigated in this phase of the -work. - -<p>Work by others have made Chromium DMX-aware. Chromium will use the -DMX X protocol extension to obtain information about the back-end -servers and will render directly to those servers, bypassing DMX. - -<p>Status: OpenGL support by the glxProxy extension was implemented by -SGI and has been integrated into the DMX code base. -<!-- May 2003--> - - -<!-- ============================================================ --> -<sect>Current issues - -<p>In this sections the current issues are outlined that require further -investigation. - -<sect1>Fonts - -<p>The font path and glyphs need to be the same for the front-end and -each of the back-end servers. Font glyphs could be sent to the back-end -servers as necessary but this would consume a significant amount of -available bandwidth during font rendering for clients that use many -different fonts (e.g., Netscape). Initially, the font server (xfs) will -be used to provide the fonts to both the front-end and back-end servers. -Other possibilities will be investigated during development. - -<sect1>Zero width rendering primitives - -<p>To allow pixmap and on-screen rendering to be pixel perfect, all -back-end servers must render zero width primitives exactly the same as -the front-end renders the primitives to pixmaps. For those back-end -servers that do not exactly match, zero width primitives will be -automatically converted to one width primitives. This can be handled in -the front-end server via the GC state. - -<sect1>Output scaling - -<p>With very large tiled displays, it might be difficult to read the -information on the standard X desktop. In particular, the cursor can be -easily lost and fonts could be difficult to read. Automatic primitive -scaling might prove to be very useful. We will investigate the -possibility of scaling the cursor and providing a set of alternate -pre-scaled fonts to replace the standard fonts that many applications -use (e.g., fixed). Other options for automatic scaling will also be -investigated. - -<sect1>Per-screen colormaps - -<p>Each screen's default colormap in the set of back-end X servers -should be able to be adjusted via a configuration utility. This support -is would allow the back-end screens to be calibrated via custom gamma -tables. On 24-bit systems that support a DirectColor visual, this type -of correction can be accommodated. One possible implementation would be -to advertise to X client of the DMX server a TrueColor visual while -using DirectColor visuals on the back-end servers to implement this type -of color correction. Other options will be investigated. - -<!-- ============================================================ --> -<appendix> - -<sect>Background - -<p>This section describes the existing Open Source architectures that -can be used to handle multiple screens and upon which this development -project is based. This section was written before the implementation -was finished, and may not reflect actual details of the implementation. -It is left for historical interest only. - -<sect1>Core input device handling - -<p>The following is a description of how core input devices are handled -by an X server. - -<sect2>InitInput() - -<p>InitInput() is a DDX function that is called at the start of each -server generation from the X server's main() function. Its purpose is -to determine what input devices are connected to the X server, register -them with the DIX and MI layers, and initialize the input event queue. -InitInput() does not have a return value, but the X server will abort if -either a core keyboard device or a core pointer device are not -registered. Extended input (XInput) devices can also be registered in -InitInput(). - -<p>InitInput() usually has implementation specific code to determine -which input devices are available. For each input device it will be -using, it calls AddInputDevice(): - -<descrip> -<tag/AddInputDevice()/ This DIX function allocates the device structure, -registers a callback function (which handles device init, close, on and -off), and returns the input handle, which can be treated as opaque. It -is called once for each input device. -</descrip> - -<p>Once input handles for core keyboard and core pointer devices have -been obtained from AddInputDevice(), they are registered as core devices -by calling RegisterPointerDevice() and RegisterKeyboardDevice(). Each -of these should be called once. If both core devices are not -registered, then the X server will exit with a fatal error when it -attempts to start the input devices in InitAndStartDevices(), which is -called directly after InitInput() (see below). - -<descrip> -<tag/Register{Pointer,Keyboard}Device()/ These DIX functions take a -handle returned from AddInputDevice() and initialize the core input -device fields in inputInfo, and initialize the input processing and grab -functions for each core input device. -</descrip> - -<p>The core pointer device is then registered with the miPointer code -(which does the high level cursor handling). While this registration -is not necessary for correct miPointer operation in the current XFree86 -code, it is still done mostly for compatibility reasons. - -<descrip> -<tag/miRegisterPointerDevice()/ This MI function registers the core -pointer's input handle with with the miPointer code. -</descrip> - -<p>The final part of InitInput() is the initialization of the input -event queue handling. In most cases, the event queue handling provided -in the MI layer is used. The primary XFree86 X server uses its own -event queue handling to support some special cases related to the XInput -extension and the XFree86-specific DGA extension. For our purposes, the -MI event queue handling should be suitable. It is initialized by -calling mieqInit(): - -<descrip> -<tag/mieqInit()/ This MI function initializes the MI event queue for the -core devices, and is passed the public component of the input handles -for the two core devices. -</descrip> - -<p>If a wakeup handler is required to deliver synchronous input -events, it can be registered here by calling the DIX function -RegisterBlockAndWakeupHandlers(). (See the devReadInput() description -below.) - -<sect2>InitAndStartDevices() - -<p>InitAndStartDevices() is a DIX function that is called immediately -after InitInput() from the X server's main() function. Its purpose is -to initialize each input device that was registered with -AddInputDevice(), enable each input device that was successfully -initialized, and create the list of enabled input devices. Once each -registered device is processed in this way, the list of enabled input -devices is checked to make sure that both a core keyboard device and -core pointer device were registered and successfully enabled. If not, -InitAndStartDevices() returns failure, and results in the the X server -exiting with a fatal error. - -<p>Each registered device is initialized by calling its callback -(dev->deviceProc) with the DEVICE_INIT argument: - -<descrip> -<tag/(*dev->deviceProc)(dev, DEVICE_INIT)/ This function initializes the -device structs with core information relevant to the device. - -<p>For pointer devices, this means specifying the number of buttons, -default button mapping, the function used to get motion events (usually -miPointerGetMotionEvents()), the function used to change/control the -core pointer motion parameters (acceleration and threshold), and the -motion buffer size. - -<p>For keyboard devices, this means specifying the keycode range, -default keycode to keysym mapping, default modifier mapping, and the -functions used to sound the keyboard bell and modify/control the -keyboard parameters (LEDs, bell pitch and duration, key click, which -keys are auto-repeating, etc). -</descrip> - -<p>Each initialized device is enabled by calling EnableDevice(): - -<descrip> -<tag/EnableDevice()/ EnableDevice() calls the device callback with -DEVICE_ON: - <descrip> - <tag/(*dev->deviceProc)(dev, DEVICE_ON)/ This typically opens and - initializes the relevant physical device, and when appropriate, - registers the device's file descriptor (or equivalent) as a valid - input source. - </descrip> - - <p>EnableDevice() then adds the device handle to the X server's - global list of enabled devices. -</descrip> - -<p>InitAndStartDevices() then verifies that a valid core keyboard and -pointer has been initialized and enabled. It returns failure if either -are missing. - -<sect2>devReadInput() - -<p>Each device will have some function that gets called to read its -physical input. These may be called in a number of different ways. In -the case of synchronous I/O, they will be called from a DDX -wakeup-handler that gets called after the server detects that new input is -available. In the case of asynchronous I/O, they will be called from a -(SIGIO) signal handler triggered when new input is available. This -function should do at least two things: make sure that input events get -enqueued, and make sure that the cursor gets moved for motion events -(except if these are handled later by the driver's own event queue -processing function, which cannot be done when using the MI event queue -handling). - -<p>Events are queued by calling mieqEnqueue(): - -<descrip> -<tag/mieqEnqueue()/ This MI function is used to add input events to the -event queue. It is simply passed the event to be queued. -</descrip> - -<p>The cursor position should be updated when motion events are -enqueued, by calling either miPointerAbsoluteCursor() or -miPointerDeltaCursor(): - -<descrip> -<tag/miPointerAbsoluteCursor()/ This MI function is used to move the -cursor to the absolute coordinates provided. -<tag/miPointerDeltaCursor()/ This MI function is used to move the cursor -relative to its current position. -</descrip> - -<sect2>ProcessInputEvents() - -<p>ProcessInputEvents() is a DDX function that is called from the X -server's main dispatch loop when new events are available in the input -event queue. It typically processes the enqueued events, and updates -the cursor/pointer position. It may also do other DDX-specific event -processing. - -<p>Enqueued events are processed by mieqProcessInputEvents() and passed -to the DIX layer for transmission to clients: - -<descrip> -<tag/mieqProcessInputEvents()/ This function processes each event in the -event queue, and passes it to the device's input processing function. -The DIX layer provides default functions to do this processing, and they -handle the task of getting the events passed back to the relevant -clients. -<tag/miPointerUpdate()/ This function resynchronized the cursor position -with the new pointer position. It also takes care of moving the cursor -between screens when needed in multi-head configurations. -</descrip> - - -<sect2>DisableDevice() - -<p>DisableDevice is a DIX function that removes an input device from the -list of enabled devices. The result of this is that the device no -longer generates input events. The device's data structures are kept in -place, and disabling a device like this can be reversed by calling -EnableDevice(). DisableDevice() may be called from the DDX when it is -desirable to do so (e.g., the XFree86 server does this when VT -switching). Except for special cases, this is not normally called for -core input devices. - -<p>DisableDevice() calls the device's callback function with -<tt/DEVICE_OFF/: - -<descrip> -<tag/(*dev->deviceProc)(dev, DEVICE_OFF)/ This typically closes the -relevant physical device, and when appropriate, unregisters the device's -file descriptor (or equivalent) as a valid input source. -</descrip> - -<p>DisableDevice() then removes the device handle from the X server's -global list of enabled devices. - - -<sect2>CloseDevice() - -<p>CloseDevice is a DIX function that removes an input device from the -list of available devices. It disables input from the device and frees -all data structures associated with the device. This function is -usually called from CloseDownDevices(), which is called from main() at -the end of each server generation to close all input devices. - -<p>CloseDevice() calls the device's callback function with -<tt/DEVICE_CLOSE/: - -<descrip> -<tag/(*dev->deviceProc)(dev, DEVICE_CLOSE)/ This typically closes the -relevant physical device, and when appropriate, unregisters the device's -file descriptor (or equivalent) as a valid input source. If any device -specific data structures were allocated when the device was initialized, -they are freed here. -</descrip> - -<p>CloseDevice() then frees the data structures that were allocated -for the device when it was registered/initialized. - - -<sect2>LegalModifier() -<!-- dmx/dmxinput.c - currently returns TRUE --> -<p>LegalModifier() is a required DDX function that can be used to -restrict which keys may be modifier keys. This seems to be present for -historical reasons, so this function should simply return TRUE -unconditionally. - - -<sect1>Output handling - -<p>The following sections describe the main functions required to -initialize, use and close the output device(s) for each screen in the X -server. - -<sect2>InitOutput() - -<p>This DDX function is called near the start of each server generation -from the X server's main() function. InitOutput()'s main purpose is to -initialize each screen and fill in the global screenInfo structure for -each screen. It is passed three arguments: a pointer to the screenInfo -struct, which it is to initialize, and argc and argv from main(), which -can be used to determine additional configuration information. - -<p>The primary tasks for this function are outlined below: - -<enum> - <item><bf/Parse configuration info:/ The first task of InitOutput() - is to parses any configuration information from the configuration - file. In addition to the XF86Config file, other configuration - information can be taken from the command line. The command line - options can be gathered either in InitOutput() or earlier in the - ddxProcessArgument() function, which is called by - ProcessCommandLine(). The configuration information determines the - characteristics of the screen(s). For example, in the XFree86 X - server, the XF86Config file specifies the monitor information, the - screen resolution, the graphics devices and slots in which they are - located, and, for Xinerama, the screens' layout. - - <item><bf/Initialize screen info:/ The next task is to initialize - the screen-dependent internal data structures. For example, part of - what the XFree86 X server does is to allocate its screen and pixmap - private indices, probe for graphics devices, compare the probed - devices to the ones listed in the XF86Config file, and add the ones that - match to the internal xf86Screens[] structure. - - <item><bf/Set pixmap formats:/ The next task is to initialize the - screenInfo's image byte order, bitmap bit order and bitmap scanline - unit/pad. The screenInfo's pixmap format's depth, bits per pixel - and scanline padding is also initialized at this stage. - - <item><bf/Unify screen info:/ An optional task that might be done at - this stage is to compare all of the information from the various - screens and determines if they are compatible (i.e., if the set of - screens can be unified into a single desktop). This task has - potential to be useful to the DMX front-end server, if Xinerama's - PanoramiXConsolidate() function is not sufficient. -</enum> - -<p>Once these tasks are complete, the valid screens are known and each -of these screens can be initialized by calling AddScreen(). - -<sect2>AddScreen() - -<p>This DIX function is called from InitOutput(), in the DDX layer, to -add each new screen to the screenInfo structure. The DDX screen -initialization function and command line arguments (i.e., argc and argv) -are passed to it as arguments. - -<p>This function first allocates a new Screen structure and any privates -that are required. It then initializes some of the fields in the Screen -struct and sets up the pixmap padding information. Finally, it calls -the DDX screen initialization function ScreenInit(), which is described -below. It returns the number of the screen that were just added, or -1 -if there is insufficient memory to add the screen or if the DDX screen -initialization fails. - -<sect2>ScreenInit() - -<p>This DDX function initializes the rest of the Screen structure with -either generic or screen-specific functions (as necessary). It also -fills in various screen attributes (e.g., width and height in -millimeters, black and white pixel values). - -<p>The screen init function usually calls several functions to perform -certain screen initialization functions. They are described below: - -<descrip> -<tag/{mi,*fb}ScreenInit()/ The DDX layer's ScreenInit() function usually -calls another layer's ScreenInit() function (e.g., miScreenInit() or -fbScreenInit()) to initialize the fallbacks that the DDX driver does not -specifically handle. - -<p>After calling another layer's ScreenInit() function, any -screen-specific functions either wrap or replace the other layer's -function pointers. If a function is to be wrapped, each of the old -function pointers from the other layer are stored in a screen private -area. Common functions to wrap are CloseScreen() and SaveScreen(). - -<tag/miInitializeBackingStore()/ This MI function initializes the -screen's backing storage functions, which are used to save areas of -windows that are currently covered by other windows. - -<tag/miDCInitialize()/ This MI function initializes the MI cursor -display structures and function pointers. If a hardware cursor is used, -the DDX layer's ScreenInit() function will wrap additional screen and -the MI cursor display function pointers. -</descrip> - -<p>Another common task for ScreenInit() function is to initialize the -output device state. For example, in the XFree86 X server, the -ScreenInit() function saves the original state of the video card and -then initializes the video mode of the graphics device. - -<sect2>CloseScreen() - -<p>This function restores any wrapped screen functions (and in -particular the wrapped CloseScreen() function) and restores the state of -the output device to its original state. It should also free any -private data it created during the screen initialization. - -<sect2>GC operations - -<p>When the X server is requested to render drawing primitives, it does -so by calling drawing functions through the graphics context's operation -function pointer table (i.e., the GCOps functions). These functions -render the basic graphics operations such as drawing rectangles, lines, -text or copying pixmaps. Default routines are provided either by the MI -layer, which draws indirectly through a simple span interface, or by the -framebuffer layers (e.g., CFB, MFB, FB), which draw directly to a -linearly mapped frame buffer. - -<p>To take advantage of special hardware on the graphics device, -specific GCOps functions can be replaced by device specific code. -However, many times the graphics devices can handle only a subset of the -possible states of the GC, so during graphics context validation, -appropriate routines are selected based on the state and capabilities of -the hardware. For example, some graphics hardware can accelerate single -pixel width lines with certain dash patterns. Thus, for dash patterns -that are not supported by hardware or for width 2 or greater lines, the -default routine is chosen during GC validation. - -<p>Note that some pointers to functions that draw to the screen are -stored in the Screen structure. They include GetImage(), GetSpans(), -PaintWindowBackground(), PaintWindowBorder(), CopyWindow() and -RestoreAreas(). - -<sect2>Xnest - -<p>The Xnest X server is a special proxy X server that relays the X -protocol requests that it receives to a ``real'' X server that then -processes the requests and displays the results, if applicable. To the X -applications, Xnest appears as if it is a regular X server. However, -Xnest is both server to the X application and client of the real X -server, which will actually handle the requests. - -<p>The Xnest server implements all of the standard input and output -initialization steps outlined above. - -<descrip> -<tag/InitOutput()/ Xnest takes its configuration information from -command line arguments via ddxProcessArguments(). This information -includes the real X server display to connect to, its default visual -class, the screen depth, the Xnest window's geometry, etc. Xnest then -connects to the real X server and gathers visual, colormap, depth and -pixmap information about that server's display, creates a window on that -server, which will be used as the root window for Xnest. - -<p>Next, Xnest initializes its internal data structures and uses the -data from the real X server's pixmaps to initialize its own pixmap -formats. Finally, it calls AddScreen(xnestOpenScreen, argc, argv) to -initialize each of its screens. - -<tag/ScreenInit()/ Xnest's ScreenInit() function is called -xnestOpenScreen(). This function initializes its screen's depth and -visual information, and then calls miScreenInit() to set up the default -screen functions. It then calls miInitializeBackingStore() and -miDCInitialize() to initialize backing store and the software cursor. -Finally, it replaces many of the screen functions with its own -functions that repackage and send the requests to the real X server to -which Xnest is attached. - -<tag/CloseScreen()/ This function frees its internal data structure -allocations. Since it replaces instead of wrapping screen functions, -there are no function pointers to unwrap. This can potentially lead to -problems during server regeneration. - -<tag/GC operations/ The GC operations in Xnest are very simple since -they leave all of the drawing to the real X server to which Xnest is -attached. Each of the GCOps takes the request and sends it to the -real X server using standard Xlib calls. For example, the X -application issues a XDrawLines() call. This function turns into a -protocol request to Xnest, which calls the xnestPolylines() function -through Xnest's GCOps function pointer table. The xnestPolylines() -function is only a single line, which calls XDrawLines() using the same -arguments that were passed into it. Other GCOps functions are very -similar. Two exceptions to the simple GCOps functions described above -are the image functions and the BLT operations. - -<p>The image functions, GetImage() and PutImage(), must use a temporary -image to hold the image to be put of the image that was just grabbed -from the screen while it is in transit to the real X server or the -client. When the image has been transmitted, the temporary image is -destroyed. - -<p>The BLT operations, CopyArea() and CopyPlane(), handle not only the -copy function, which is the same as the simple cases described above, -but also the graphics exposures that result when the GC's graphics -exposure bit is set to True. Graphics exposures are handled in a helper -function, xnestBitBlitHelper(). This function collects the exposure -events from the real X server and, if any resulting in regions being -exposed, then those regions are passed back to the MI layer so that it -can generate exposure events for the X application. -</descrip> - -<p>The Xnest server takes its input from the X server to which it is -connected. When the mouse is in the Xnest server's window, keyboard and -mouse events are received by the Xnest server, repackaged and sent back -to any client that requests those events. - -<sect2>Shadow framebuffer - -<p>The most common type of framebuffer is a linear array memory that -maps to the video memory on the graphics device. However, accessing -that video memory over an I/O bus (e.g., ISA or PCI) can be slow. The -shadow framebuffer layer allows the developer to keep the entire -framebuffer in main memory and copy it back to video memory at regular -intervals. It also has been extended to handle planar video memory and -rotated framebuffers. - -<p>There are two main entry points to the shadow framebuffer code: - -<descrip> -<tag/shadowAlloc(width, height, bpp)/ This function allocates the in -memory copy of the framebuffer of size width*height*bpp. It returns a -pointer to that memory, which will be used by the framebuffer -ScreenInit() code during the screen's initialization. - -<tag/shadowInit(pScreen, updateProc, windowProc)/ This function -initializes the shadow framebuffer layer. It wraps several screen -drawing functions, and registers a block handler that will update the -screen. The updateProc is a function that will copy the damaged regions -to the screen, and the windowProc is a function that is used when the -entire linear video memory range cannot be accessed simultaneously so -that only a window into that memory is available (e.g., when using the -VGA aperture). -</descrip> - -<p>The shadow framebuffer code keeps track of the damaged area of each -screen by calculating the bounding box of all drawing operations that -have occurred since the last screen update. Then, when the block handler -is next called, only the damaged portion of the screen is updated. - -<p>Note that since the shadow framebuffer is kept in main memory, all -drawing operations are performed by the CPU and, thus, no accelerated -hardware drawing operations are possible. - - -<sect1>Xinerama - -<p>Xinerama is an X extension that allows multiple physical screens -controlled by a single X server to appear as a single screen. Although -the extension allows clients to find the physical screen layout via -extension requests, it is completely transparent to clients at the core -X11 protocol level. The original public implementation of Xinerama came -from Digital/Compaq. XFree86 rewrote it, filling in some missing pieces -and improving both X11 core protocol compliance and performance. The -Xinerama extension will be passing through X.Org's standardization -process in the near future, and the sample implementation will be based -on this rewritten version. - -<p>The current implementation of Xinerama is based primarily in the DIX -(device independent) and MI (machine independent) layers of the X -server. With few exceptions the DDX layers do not need any changes to -support Xinerama. X server extensions often do need modifications to -provide full Xinerama functionality. - -<p>The following is a code-level description of how Xinerama functions. - -<p>Note: Because the Xinerama extension was originally called the -PanoramiX extension, many of the Xinerama functions still have the -PanoramiX prefix. - -<descrip> - <tag/PanoramiXExtensionInit()/ PanoramiXExtensionInit() is a - device-independent extension function that is called at the start of - each server generation from InitExtensions(), which is called from - the X server's main() function after all output devices have been - initialized, but before any input devices have been initialized. - - <p>PanoramiXNumScreens is set to the number of physical screens. If - only one physical screen is present, the extension is disabled, and - PanoramiXExtensionInit() returns without doing anything else. - - <p>The Xinerama extension is registered by calling AddExtension(). - - <p>A local per-screen array of data structures - (panoramiXdataPtr[]) - is allocated for each physical screen, and GC and Screen private - indexes are allocated, and both GC and Screen private areas are - allocated for each physical screen. These hold Xinerama-specific - per-GC and per-Screen data. Each screen's CreateGC and CloseScreen - functions are wrapped by XineramaCreateGC() and - XineramaCloseScreen() respectively. Some new resource classes are - created for Xinerama drawables and GCs, and resource types for - Xinerama windows, pixmaps and colormaps. - - <p>A region (XineramaScreenRegions[i]) is initialized for each - physical screen, and single region (PanoramiXScreenRegion) is - initialized to be the union of the screen regions. The - panoramiXdataPtr[] array is also initialized with the size and - origin of each screen. The relative positioning information for the - physical screens is taken from the array - dixScreenOrigins[], which - the DDX layer must initialize in InitOutput(). The bounds of the - combined screen is also calculated (PanoramiXPixWidth and - PanoramiXPixHeight). - - <p>The DIX layer has a list of function pointers - (ProcVector[]) that - holds the entry points for the functions that process core protocol - requests. The requests that Xinerama must intercept and break up - into physical screen-specific requests are wrapped. The original - set is copied to SavedProcVector[]. The types of requests - intercepted are Window requests, GC requests, colormap requests, - drawing requests, and some geometry-related requests. This wrapping - allows the bulk of the protocol request processing to be handled - transparently to the DIX layer. Some operations cannot be dealt with - in this way and are handled with Xinerama-specific code within the - DIX layer. - - <tag/PanoramiXConsolidate()/ PanoramiXConsolidate() is a - device-independent extension function that is called directly from - the X server's main() function after extensions and input/output - devices have been initialized, and before the root windows are - defined and initialized. - - <p>This function finds the set of depths (PanoramiXDepths[]) and - visuals (PanoramiXVisuals[]) - common to all of the physical screens. - PanoramiXNumDepths is set to the number of common depths, and - PanoramiXNumVisuals is set to the number of common visuals. - Resources are created for the single root window and the default - colormap. Each of these resources has per-physical screen entries. - - <tag/PanoramiXCreateConnectionBlock()/ PanoramiXConsolidate() is a - device-independent extension function that is called directly from - the X server's main() function after the per-physical screen root - windows are created. It is called instead of the standard DIX - CreateConnectionBlock() function. If this function returns FALSE, - the X server exits with a fatal error. This function will return - FALSE if no common depths were found in PanoramiXConsolidate(). - With no common depths, Xinerama mode is not possible. - - <p>The connection block holds the information that clients get when - they open a connection to the X server. It includes information - such as the supported pixmap formats, number of screens and the - sizes, depths, visuals, default colormap information, etc, for each - of the screens (much of information that <tt/xdpyinfo/ shows). The - connection block is initialized with the combined single screen - values that were calculated in the above two functions. - - <p>The Xinerama extension allows the registration of connection - block callback functions. The purpose of these is to allow other - extensions to do processing at this point. These callbacks can be - registered by calling XineramaRegisterConnectionBlockCallback() from - the other extension's ExtensionInit() function. Each registered - connection block callback is called at the end of - PanoramiXCreateConnectionBlock(). -</descrip> - -<sect2>Xinerama-specific changes to the DIX code - -<p>There are a few types of Xinerama-specific changes within the DIX -code. The main ones are described here. - -<p>Functions that deal with colormap or GC -related operations outside of -the intercepted protocol requests have a test added to only do the -processing for screen numbers > 0. This is because they are handled for -the single Xinerama screen and the processing is done once for screen 0. - -<p>The handling of motion events does some coordinate translation between -the physical screen's origin and screen zero's origin. Also, motion -events must be reported relative to the composite screen origin rather -than the physical screen origins. - -<p>There is some special handling for cursor, window and event processing -that cannot (either not at all or not conveniently) be done via the -intercepted protocol requests. A particular case is the handling of -pointers moving between physical screens. - -<sect2>Xinerama-specific changes to the MI code - -<p>The only Xinerama-specific change to the MI code is in miSendExposures() -to handle the coordinate (and window ID) translation for expose events. - -<sect2>Intercepted DIX core requests - -<p>Xinerama breaks up drawing requests for dispatch to each physical -screen. It also breaks up windows into pieces for each physical screen. -GCs are translated into per-screen GCs. Colormaps are replicated on -each physical screen. The functions handling the intercepted requests -take care of breaking the requests and repackaging them so that they can -be passed to the standard request handling functions for each screen in -turn. In addition, and to aid the repackaging, the information from -many of the intercepted requests is used to keep up to date the -necessary state information for the single composite screen. Requests -(usually those with replies) that can be satisfied completely from this -stored state information do not call the standard request handling -functions. - -<!-- ============================================================ --> - -<sect>Development Results - -<p>In this section the results of each phase of development are -discussed. This development took place between approximately June 2001 -and July 2003. - -<sect1>Phase I - -<p>The initial development phase dealt with the basic implementation -including the bootstrap code, which used the shadow framebuffer, and the -unoptimized implementation, based on an Xnest-style implementation. - -<sect2>Scope - -<p>The goal of Phase I is to provide fundamental functionality that can -act as a foundation for ongoing work: -<enum> - <item>Develop the proxy X server - <itemize> - <item>The proxy X server will operate on the X11 protocol and - relay requests as necessary to correctly perform the request. - <item>Work will be based on the existing work for Xinerama and - Xnest. - <item>Input events and windowing operations are handled in the - proxy server and rendering requests are repackaged and sent to - each of the back-end servers for display. - <item>The multiple screen layout (including support for - overlapping screens) will be user configurable via a - configuration file or through the configuration tool. - </itemize> - <item>Develop graphical configuration tool - <itemize> - <item>There will be potentially a large number of X servers to - configure into a single display. The tool will allow the user - to specify which servers are involved in the configuration and - how they should be laid out. - </itemize> - <item>Pass the X Test Suite - <itemize> - <item>The X Test Suite covers the basic X11 operations. All - tests known to succeed must correctly operate in the distributed - X environment. - </itemize> -</enum> - -<p>For this phase, the back-end X servers are assumed to be unmodified X -servers that do not support any DMX-related protocol extensions; future -optimization pathways are considered, but are not implemented; and the -configuration tool is assumed to rely only on libraries in the X source -tree (e.g., Xt). - -<sect2>Results - -<p>The proxy X server, Xdmx, was developed to distribute X11 protocol -requests to the set of back-end X servers. It opens a window on each -back-end server, which represents the part of the front-end's root -window that is visible on that screen. It mirrors window, pixmap and -other state in each back-end server. Drawing requests are sent to -either windows or pixmaps on each back-end server. This code is based -on Xnest and uses the existing Xinerama extension. - -<p>Input events can be taken from (1) devices attached to the back-end -server, (2) core devices attached directly to the Xdmx server, or (3) -from a ``console'' window on another X server. Events for these devices -are gathered, processed and delivered to clients attached to the Xdmx -server. - -<p>An intuitive configuration format was developed to help the user -easily configure the multiple back-end X servers. It was defined (see -grammar in Xdmx man page) and a parser was implemented that is used by -the Xdmx server and by a standalone xdmxconfig utility. The parsing -support was implemented such that it can be easily factored out of the X -source tree for use with other tools (e.g., vdl). Support for -converting legacy vdl-format configuration files to the DMX format is -provided by the vdltodmx utility. - -<p>Originally, the configuration file was going to be a subsection of -XFree86's XF86Config file, but that was not possible since Xdmx is a -completely separate X server. Thus, a separate config file format was -developed. In addition, a graphical configuration -tool, xdmxconfig, was developed to allow the user to create and arrange -the screens in the configuration file. The <bf/-configfile/ and <bf/-config/ -command-line options can be used to start Xdmx using a configuration -file. - -<p>An extension that enables remote input testing is required for the X -Test Suite to function. During this phase, this extension (XTEST) was -implemented in the Xdmx server. The results from running the X Test -Suite are described in detail below. - -<sect2>X Test Suite - - <sect3> Introduction - <p> - The X Test Suite contains tests that verify Xlib functions - operate correctly. The test suite is designed to run on a - single X server; however, since X applications will not be - able to tell the difference between the DMX server and a - standard X server, the X Test Suite should also run on the - DMX server. - <p> - The Xdmx server was tested with the X Test Suite, and the - existing failures are noted in this section. To put these - results in perspective, we first discuss expected X Test - failures and how errors in underlying systems can impact - Xdmx test results. - - <sect3>Expected Failures for a Single Head - <p> - A correctly implemented X server with a single screen is - expected to fail certain X Test tests. The following - well-known errors occur because of rounding error in the X - server code: - <verb> -XDrawArc: Tests 42, 63, 66, 73 -XDrawArcs: Tests 45, 66, 69, 76 - </verb> - <p> - The following failures occur because of the high-level X - server implementation: - <verb> -XLoadQueryFont: Test 1 -XListFontsWithInfo: Tests 3, 4 -XQueryFont: Tests 1, 2 - </verb> - <p> - The following test fails when running the X server as root - under Linux because of the way directory modes are - interpreted: - <verb> -XWriteBitmapFile: Test 3 - </verb> - <p> - Depending on the video card used for the back-end, other - failures may also occur because of bugs in the low-level - driver implementation. Over time, failures of this kind - are usually fixed by XFree86, but will show up in Xdmx - testing until then. - - <sect3>Expected Failures for Xinerama - <p> - Xinerama fails several X Test Suite tests because of - design decisions made for the current implementation of - Xinerama. Over time, many of these errors will be - corrected by XFree86 and the group working on a new - Xinerama implementation. Therefore, Xdmx will also share - X Suite Test failures with Xinerama. - <p> - We may be able to fix or work-around some of these - failures at the Xdmx level, but this will require - additional exploration that was not part of Phase I. - <p> - Xinerama is constantly improving, and the list of - Xinerama-related failures depends on XFree86 version and - the underlying graphics hardware. We tested with a - variety of hardware, including nVidia, S3, ATI Radeon, - and Matrox G400 (in dual-head mode). The list below - includes only those failures that appear to be from the - Xinerama layer, and does not include failures listed in - the previous section, or failures that appear to be from - the low-level graphics driver itself: - <p> - These failures were noted with multiple Xinerama - configurations: - <verb> -XCopyPlane: Tests 13, 22, 31 (well-known Xinerama implementation issue) -XSetFontPath: Test 4 -XGetDefault: Test 5 -XMatchVisualInfo: Test 1 - </verb> - <p> - These failures were noted only when using one dual-head - video card with a 4.2.99.x XFree86 server: - <verb> -XListPixmapFormats: Test 1 -XDrawRectangles: Test 45 - </verb> - <p> - These failures were noted only when using two video cards - from different vendors with a 4.1.99.x XFree86 server: - <verb> -XChangeWindowAttributes: Test 32 -XCreateWindow: Test 30 -XDrawLine: Test 22 -XFillArc: Test 22 -XChangeKeyboardControl: Tests 9, 10 -XRebindKeysym: Test 1 - </verb> - - <sect3>Additional Failures from Xdmx - <p> - When running Xdmx, no unexpected failures were noted. - Since the Xdmx server is based on Xinerama, we expect to - have most of the Xinerama failures present in the Xdmx - server. Similarly, since the Xdmx server must rely on the - low-level device drivers on each back-end server, we also - expect that Xdmx will exhibit most of the back-end - failures. Here is a summary: - <verb> -XListPixmapFormats: Test 1 (configuration dependent) -XChangeWindowAttributes: Test 32 -XCreateWindow: Test 30 -XCopyPlane: Test 13, 22, 31 -XSetFontPath: Test 4 -XGetDefault: Test 5 (configuration dependent) -XMatchVisualInfo: Test 1 -XRebindKeysym: Test 1 (configuration dependent) - </verb> - <p> - Note that this list is shorter than the combined list for - Xinerama because Xdmx uses different code paths to perform - some Xinerama operations. Further, some Xinerama failures - have been fixed in the XFree86 4.2.99.x CVS repository. - - <sect3>Summary and Future Work - <p> - Running the X Test Suite on Xdmx does not produce any - failures that cannot be accounted for by the underlying - Xinerama subsystem used by the front-end or by the - low-level device-driver code running on the back-end X - servers. The Xdmx server therefore is as ``correct'' as - possible with respect to the standard set of X Test Suite - tests. - <p> - During the following phases, we will continue to verify - Xdmx correctness using the X Test Suite. We may also use - other tests suites or write additional tests that run - under the X Test Suite that specifically verify the - expected behavior of DMX. - -<sect2>Fonts - -<p>In Phase I, fonts are handled directly by both the front-end and the -back-end servers, which is required since we must treat each back-end -server during this phase as a ``black box''. What this requires is that -<bf/the front- and back-end servers must share the exact same font -path/. There are two ways to help make sure that all servers share the -same font path: - -<enum> - <item>First, each server can be configured to use the same font - server. The font server, xfs, can be configured to serve fonts to - multiple X servers via TCP. - - <item>Second, each server can be configured to use the same font - path and either those font paths can be copied to each back-end - machine or they can be mounted (e.g., via NFS) on each back-end - machine. -</enum> - -<p>One additional concern is that a client program can set its own font -path, and if it does so, then that font path must be available on each -back-end machine. - -<p>The -fontpath command line option was added to allow users to -initialize the font path of the front end server. This font path is -propagated to each back-end server when the default font is loaded. If -there are any problems, an error message is printed, which will describe -the problem and list the current font path. For more information about -setting the font path, see the -fontpath option description in the man -page. - -<sect2>Performance - -<p>Phase I of development was not intended to optimize performance. Its -focus was on completely and correctly handling the base X11 protocol in -the Xdmx server. However, several insights were gained during Phase I, -which are listed here for reference during the next phase of -development. - -<enum> - <item>Calls to XSync() can slow down rendering since it requires a - complete round trip to and from a back-end server. This is - especially problematic when communicating over long haul networks. - <item>Sending drawing requests to only the screens that they overlap - should improve performance. -</enum> - -<sect2>Pixmaps - -<p>Pixmaps were originally expected to be handled entirely in the -front-end X server; however, it was found that this overly complicated -the rendering code and would have required sending potentially large -images to each back server that required them when copying from pixmap -to screen. Thus, pixmap state is mirrored in the back-end server just -as it is with regular window state. With this implementation, the same -rendering code that draws to windows can be used to draw to pixmaps on -the back-end server, and no large image transfers are required to copy -from pixmap to window. - -<!-- ============================================================ --> -<sect1>Phase II - -<p>The second phase of development concentrates on performance -optimizations. These optimizations are documented here, with -<tt/x11perf/ data to show how the optimizations improve performance. - -<p>All benchmarks were performed by running Xdmx on a dual processor -1.4GHz AMD Athlon machine with 1GB of RAM connecting over 100baseT to -two single-processor 1GHz Pentium III machines with 256MB of RAM and ATI -Rage 128 (RF) video cards. The front end was running Linux -2.4.20-pre1-ac1 and the back ends were running Linux 2.4.7-10 and -version 4.2.99.1 of XFree86 pulled from the XFree86 CVS repository on -August 7, 2002. All systems were running Red Hat Linux 7.2. - -<sect2>Moving from XFree86 4.1.99.1 to 4.2.0.0 - -<p>For phase II, the working source tree was moved to the branch tagged -with dmx-1-0-branch and was updated from version 4.1.99.1 (20 August -2001) of the XFree86 sources to version 4.2.0.0 (18 January 2002). -After this update, the following tests were noted to be more than 10% -faster: - <verb> -1.13 Fill 300x300 opaque stippled trapezoid (161x145 stipple) -1.16 Fill 1x1 tiled trapezoid (161x145 tile) -1.13 Fill 10x10 tiled trapezoid (161x145 tile) -1.17 Fill 100x100 tiled trapezoid (161x145 tile) -1.16 Fill 1x1 tiled trapezoid (216x208 tile) -1.20 Fill 10x10 tiled trapezoid (216x208 tile) -1.15 Fill 100x100 tiled trapezoid (216x208 tile) -1.37 Circulate Unmapped window (200 kids) - </verb> -And the following tests were noted to be more than 10% slower: - <verb> -0.88 Unmap window via parent (25 kids) -0.75 Circulate Unmapped window (4 kids) -0.79 Circulate Unmapped window (16 kids) -0.80 Circulate Unmapped window (25 kids) -0.82 Circulate Unmapped window (50 kids) -0.85 Circulate Unmapped window (75 kids) - </verb> -<p>These changes were not caused by any changes in the DMX system, and -may point to changes in the XFree86 tree or to tests that have more -"jitter" than most other <tt/x11perf/ tests. - -<sect2>Global changes - -<p>During the development of the Phase II DMX server, several global -changes were made. These changes were also compared with the Phase I -server. The following tests were noted to be more than 10% faster: - <verb> -1.13 Fill 300x300 opaque stippled trapezoid (161x145 stipple) -1.15 Fill 1x1 tiled trapezoid (161x145 tile) -1.13 Fill 10x10 tiled trapezoid (161x145 tile) -1.17 Fill 100x100 tiled trapezoid (161x145 tile) -1.16 Fill 1x1 tiled trapezoid (216x208 tile) -1.19 Fill 10x10 tiled trapezoid (216x208 tile) -1.15 Fill 100x100 tiled trapezoid (216x208 tile) -1.15 Circulate Unmapped window (4 kids) - </verb> - -<p>The following tests were noted to be more than 10% slower: - <verb> -0.69 Scroll 10x10 pixels -0.68 Scroll 100x100 pixels -0.68 Copy 10x10 from window to window -0.68 Copy 100x100 from window to window -0.76 Circulate Unmapped window (75 kids) -0.83 Circulate Unmapped window (100 kids) - </verb> - -<p>For the remainder of this analysis, the baseline of comparison will -be the Phase II deliverable with all optimizations disabled (unless -otherwise noted). This will highlight how the optimizations in -isolation impact performance. - -<sect2>XSync() Batching - -<p>During the Phase I implementation, XSync() was called after every -protocol request made by the DMX server. This provided the DMX server -with an interactive feel, but defeated X11's protocol buffering system -and introduced round-trip wire latency into every operation. During -Phase II, DMX was changed so that protocol requests are no longer -followed by calls to XSync(). Instead, the need for an XSync() is -noted, and XSync() calls are only made every 100mS or when the DMX -server specifically needs to make a call to guarantee interactivity. -With this new system, X11 buffers protocol as much as possible during a -100mS interval, and many unnecessary XSync() calls are avoided. - -<p>Out of more than 300 <tt/x11perf/ tests, 8 tests became more than 100 -times faster, with 68 more than 50X faster, 114 more than 10X faster, -and 181 more than 2X faster. See table below for summary. - -<p>The following tests were noted to be more than 10% slower with -XSync() batching on: - <verb> -0.88 500x500 tiled rectangle (161x145 tile) -0.89 Copy 500x500 from window to window - </verb> - -<sect2>Offscreen Optimization - -<p>Windows span one or more of the back-end servers' screens; however, -during Phase I development, windows were created on every back-end -server and every rendering request was sent to every window regardless -of whether or not that window was visible. With the offscreen -optimization, the DMX server tracks when a window is completely off of a -back-end server's screen and, in that case, it does not send rendering -requests to those back-end windows. This optimization saves bandwidth -between the front and back-end servers, and it reduces the number of -XSync() calls. The performance tests were run on a DMX system with only -two back-end servers. Greater performance gains will be had as the -number of back-end servers increases. - -<p>Out of more than 300 <tt/x11perf/ tests, 3 tests were at least twice as -fast, and 146 tests were at least 10% faster. Two tests were more than -10% slower with the offscreen optimization: - <verb> -0.88 Hide/expose window via popup (4 kids) -0.89 Resize unmapped window (75 kids) - </verb> - -<sect2>Lazy Window Creation Optimization - -<p>As mentioned above, during Phase I, windows were created on every -back-end server even if they were not visible on that back-end. With -the lazy window creation optimization, the DMX server does not create -windows on a back-end server until they are either visible or they -become the parents of a visible window. This optimization builds on the -offscreen optimization (described above) and requires it to be enabled. - -<p>The lazy window creation optimization works by creating the window -data structures in the front-end server when a client creates a window, -but delays creation of the window on the back-end server(s). A private -window structure in the DMX server saves the relevant window data and -tracks changes to the window's attributes and stacking order for later -use. The only times a window is created on a back-end server are (1) -when it is mapped and is at least partially overlapping the back-end -server's screen (tracked by the offscreen optimization), or (2) when the -window becomes the parent of a previously visible window. The first -case occurs when a window is mapped or when a visible window is copied, -moved or resized and now overlaps the back-end server's screen. The -second case occurs when starting a window manager after having created -windows to which the window manager needs to add decorations. - -<p>When either case occurs, a window on the back-end server is created -using the data saved in the DMX server's window private data structure. -The stacking order is then adjusted to correctly place the window on the -back-end and lastly the window is mapped. From this time forward, the -window is handled exactly as if the window had been created at the time -of the client's request. - -<p>Note that when a window is no longer visible on a back-end server's -screen (e.g., it is moved offscreen), the window is not destroyed; -rather, it is kept and reused later if the window once again becomes -visible on the back-end server's screen. Originally with this -optimization, destroying windows was implemented but was later rejected -because it increased bandwidth when windows were opaquely moved or -resized, which is common in many window managers. - -<p>The performance tests were run on a DMX system with only two back-end -servers. Greater performance gains will be had as the number of -back-end servers increases. - -<p>This optimization improved the following <tt/x11perf/ tests by more -than 10%: - <verb> -1.10 500x500 rectangle outline -1.12 Fill 100x100 stippled trapezoid (161x145 stipple) -1.20 Circulate Unmapped window (50 kids) -1.19 Circulate Unmapped window (75 kids) - </verb> - -<sect2>Subdividing Rendering Primitives - -<p>X11 imaging requests transfer significant data between the client and -the X server. During Phase I, the DMX server would then transfer the -image data to each back-end server. Even with the offscreen -optimization (above), these requests still required transferring -significant data to each back-end server that contained a visible -portion of the window. For example, if the client uses XPutImage() to -copy an image to a window that overlaps the entire DMX screen, then the -entire image is copied by the DMX server to every back-end server. - -<p>To reduce the amount of data transferred between the DMX server and -the back-end servers when XPutImage() is called, the image data is -subdivided and only the data that will be visible on a back-end server's -screen is sent to that back-end server. Xinerama already implements a -subdivision algorithm for XGetImage() and no further optimization was -needed. - -<p>Other rendering primitives were analyzed, but the time required to -subdivide these primitives was a significant proportion of the time -required to send the entire rendering request to the back-end server, so -this optimization was rejected for the other rendering primitives. - -<p>Again, the performance tests were run on a DMX system with only two -back-end servers. Greater performance gains will be had as the number -of back-end servers increases. - -<p>This optimization improved the following <tt/x11perf/ tests by more -than 10%: - <verb> -1.12 Fill 100x100 stippled trapezoid (161x145 stipple) -1.26 PutImage 10x10 square -1.83 PutImage 100x100 square -1.91 PutImage 500x500 square -1.40 PutImage XY 10x10 square -1.48 PutImage XY 100x100 square -1.50 PutImage XY 500x500 square -1.45 Circulate Unmapped window (75 kids) -1.74 Circulate Unmapped window (100 kids) - </verb> - -<p>The following test was noted to be more than 10% slower with this -optimization: - <verb> -0.88 10-pixel fill chord partial circle - </verb> - -<sect2>Summary of x11perf Data - -<p>With all of the optimizations on, 53 <tt/x11perf/ tests are more than -100X faster than the unoptimized Phase II deliverable, with 69 more than -50X faster, 73 more than 10X faster, and 199 more than twice as fast. -No tests were more than 10% slower than the unoptimized Phase II -deliverable. (Compared with the Phase I deliverable, only Circulate -Unmapped window (100 kids) was more than 10% slower than the Phase II -deliverable. As noted above, this test seems to have wider variability -than other <tt/x11perf/ tests.) - -<p>The following table summarizes relative <tt/x11perf/ test changes for -all optimizations individually and collectively. Note that some of the -optimizations have a synergistic effect when used together. - <verb> - -1: XSync() batching only -2: Off screen optimizations only -3: Window optimizations only -4: Subdivprims only -5: All optimizations - - 1 2 3 4 5 Operation ------- ---- ---- ---- ------ --------- - 2.14 1.85 1.00 1.00 4.13 Dot - 1.67 1.80 1.00 1.00 3.31 1x1 rectangle - 2.38 1.43 1.00 1.00 2.44 10x10 rectangle - 1.00 1.00 0.92 0.98 1.00 100x100 rectangle - 1.00 1.00 1.00 1.00 1.00 500x500 rectangle - 1.83 1.85 1.05 1.06 3.54 1x1 stippled rectangle (8x8 stipple) - 2.43 1.43 1.00 1.00 2.41 10x10 stippled rectangle (8x8 stipple) - 0.98 1.00 1.00 1.00 1.00 100x100 stippled rectangle (8x8 stipple) - 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (8x8 stipple) - 1.75 1.75 1.00 1.00 3.40 1x1 opaque stippled rectangle (8x8 stipple) - 2.38 1.42 1.00 1.00 2.34 10x10 opaque stippled rectangle (8x8 stipple) - 1.00 1.00 0.97 0.97 1.00 100x100 opaque stippled rectangle (8x8 stipple) - 1.00 1.00 1.00 1.00 0.99 500x500 opaque stippled rectangle (8x8 stipple) - 1.82 1.82 1.04 1.04 3.56 1x1 tiled rectangle (4x4 tile) - 2.33 1.42 1.00 1.00 2.37 10x10 tiled rectangle (4x4 tile) - 1.00 0.92 1.00 1.00 1.00 100x100 tiled rectangle (4x4 tile) - 1.00 1.00 1.00 1.00 1.00 500x500 tiled rectangle (4x4 tile) - 1.94 1.62 1.00 1.00 3.66 1x1 stippled rectangle (17x15 stipple) - 1.74 1.28 1.00 1.00 1.73 10x10 stippled rectangle (17x15 stipple) - 1.00 1.00 1.00 0.89 0.98 100x100 stippled rectangle (17x15 stipple) - 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (17x15 stipple) - 1.94 1.62 1.00 1.00 3.67 1x1 opaque stippled rectangle (17x15 stipple) - 1.69 1.26 1.00 1.00 1.66 10x10 opaque stippled rectangle (17x15 stipple) - 1.00 0.95 1.00 1.00 1.00 100x100 opaque stippled rectangle (17x15 stipple) - 1.00 1.00 1.00 1.00 0.97 500x500 opaque stippled rectangle (17x15 stipple) - 1.93 1.61 0.99 0.99 3.69 1x1 tiled rectangle (17x15 tile) - 1.73 1.27 1.00 1.00 1.72 10x10 tiled rectangle (17x15 tile) - 1.00 1.00 1.00 1.00 0.98 100x100 tiled rectangle (17x15 tile) - 1.00 1.00 0.97 0.97 1.00 500x500 tiled rectangle (17x15 tile) - 1.95 1.63 1.00 1.00 3.83 1x1 stippled rectangle (161x145 stipple) - 1.80 1.30 1.00 1.00 1.83 10x10 stippled rectangle (161x145 stipple) - 0.97 1.00 1.00 1.00 1.01 100x100 stippled rectangle (161x145 stipple) - 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (161x145 stipple) - 1.95 1.63 1.00 1.00 3.56 1x1 opaque stippled rectangle (161x145 stipple) - 1.65 1.25 1.00 1.00 1.68 10x10 opaque stippled rectangle (161x145 stipple) - 1.00 1.00 1.00 1.00 1.01 100x100 opaque stippled rectangle (161x145... - 1.00 1.00 1.00 1.00 0.97 500x500 opaque stippled rectangle (161x145... - 1.95 1.63 0.98 0.99 3.80 1x1 tiled rectangle (161x145 tile) - 1.67 1.26 1.00 1.00 1.67 10x10 tiled rectangle (161x145 tile) - 1.13 1.14 1.14 1.14 1.14 100x100 tiled rectangle (161x145 tile) - 0.88 1.00 1.00 1.00 0.99 500x500 tiled rectangle (161x145 tile) - 1.93 1.63 1.00 1.00 3.53 1x1 tiled rectangle (216x208 tile) - 1.69 1.26 1.00 1.00 1.66 10x10 tiled rectangle (216x208 tile) - 1.00 1.00 1.00 1.00 1.00 100x100 tiled rectangle (216x208 tile) - 1.00 1.00 1.00 1.00 1.00 500x500 tiled rectangle (216x208 tile) - 1.82 1.70 1.00 1.00 3.38 1-pixel line segment - 2.07 1.56 0.90 1.00 3.31 10-pixel line segment - 1.29 1.10 1.00 1.00 1.27 100-pixel line segment - 1.05 1.06 1.03 1.03 1.09 500-pixel line segment - 1.30 1.13 1.00 1.00 1.29 100-pixel line segment (1 kid) - 1.32 1.15 1.00 1.00 1.32 100-pixel line segment (2 kids) - 1.33 1.16 1.00 1.00 1.33 100-pixel line segment (3 kids) - 1.92 1.64 1.00 1.00 3.73 10-pixel dashed segment - 1.34 1.16 1.00 1.00 1.34 100-pixel dashed segment - 1.24 1.11 0.99 0.97 1.23 100-pixel double-dashed segment - 1.72 1.77 1.00 1.00 3.25 10-pixel horizontal line segment - 1.83 1.66 1.01 1.00 3.54 100-pixel horizontal line segment - 1.86 1.30 1.00 1.00 1.84 500-pixel horizontal line segment - 2.11 1.52 1.00 0.99 3.02 10-pixel vertical line segment - 1.21 1.10 1.00 1.00 1.20 100-pixel vertical line segment - 1.03 1.03 1.00 1.00 1.02 500-pixel vertical line segment - 4.42 1.68 1.00 1.01 4.64 10x1 wide horizontal line segment - 1.83 1.31 1.00 1.00 1.83 100x10 wide horizontal line segment - 1.07 1.00 0.96 1.00 1.07 500x50 wide horizontal line segment - 4.10 1.67 1.00 1.00 4.62 10x1 wide vertical line segment - 1.50 1.24 1.06 1.06 1.48 100x10 wide vertical line segment - 1.06 1.03 1.00 1.00 1.05 500x50 wide vertical line segment - 2.54 1.61 1.00 1.00 3.61 1-pixel line - 2.71 1.48 1.00 1.00 2.67 10-pixel line - 1.19 1.09 1.00 1.00 1.19 100-pixel line - 1.04 1.02 1.00 1.00 1.03 500-pixel line - 2.68 1.51 0.98 1.00 3.17 10-pixel dashed line - 1.23 1.11 0.99 0.99 1.23 100-pixel dashed line - 1.15 1.08 1.00 1.00 1.15 100-pixel double-dashed line - 2.27 1.39 1.00 1.00 2.23 10x1 wide line - 1.20 1.09 1.00 1.00 1.20 100x10 wide line - 1.04 1.02 1.00 1.00 1.04 500x50 wide line - 1.52 1.45 1.00 1.00 1.52 100x10 wide dashed line - 1.54 1.47 1.00 1.00 1.54 100x10 wide double-dashed line - 1.97 1.30 0.96 0.95 1.95 10x10 rectangle outline - 1.44 1.27 1.00 1.00 1.43 100x100 rectangle outline - 3.22 2.16 1.10 1.09 3.61 500x500 rectangle outline - 1.95 1.34 1.00 1.00 1.90 10x10 wide rectangle outline - 1.14 1.14 1.00 1.00 1.13 100x100 wide rectangle outline - 1.00 1.00 1.00 1.00 1.00 500x500 wide rectangle outline - 1.57 1.72 1.00 1.00 3.03 1-pixel circle - 1.96 1.35 1.00 1.00 1.92 10-pixel circle - 1.21 1.07 0.86 0.97 1.20 100-pixel circle - 1.08 1.04 1.00 1.00 1.08 500-pixel circle - 1.39 1.19 1.03 1.03 1.38 100-pixel dashed circle - 1.21 1.11 1.00 1.00 1.23 100-pixel double-dashed circle - 1.59 1.28 1.00 1.00 1.58 10-pixel wide circle - 1.22 1.12 0.99 1.00 1.22 100-pixel wide circle - 1.06 1.04 1.00 1.00 1.05 500-pixel wide circle - 1.87 1.84 1.00 1.00 1.85 100-pixel wide dashed circle - 1.90 1.93 1.01 1.01 1.90 100-pixel wide double-dashed circle - 2.13 1.43 1.00 1.00 2.32 10-pixel partial circle - 1.42 1.18 1.00 1.00 1.42 100-pixel partial circle - 1.92 1.85 1.01 1.01 1.89 10-pixel wide partial circle - 1.73 1.67 1.00 1.00 1.73 100-pixel wide partial circle - 1.36 1.95 1.00 1.00 2.64 1-pixel solid circle - 2.02 1.37 1.00 1.00 2.03 10-pixel solid circle - 1.19 1.09 1.00 1.00 1.19 100-pixel solid circle - 1.02 0.99 1.00 1.00 1.01 500-pixel solid circle - 1.74 1.28 1.00 0.88 1.73 10-pixel fill chord partial circle - 1.31 1.13 1.00 1.00 1.31 100-pixel fill chord partial circle - 1.67 1.31 1.03 1.03 1.72 10-pixel fill slice partial circle - 1.30 1.13 1.00 1.00 1.28 100-pixel fill slice partial circle - 2.45 1.49 1.01 1.00 2.71 10-pixel ellipse - 1.22 1.10 1.00 1.00 1.22 100-pixel ellipse - 1.09 1.04 1.00 1.00 1.09 500-pixel ellipse - 1.90 1.28 1.00 1.00 1.89 100-pixel dashed ellipse - 1.62 1.24 0.96 0.97 1.61 100-pixel double-dashed ellipse - 2.43 1.50 1.00 1.00 2.42 10-pixel wide ellipse - 1.61 1.28 1.03 1.03 1.60 100-pixel wide ellipse - 1.08 1.05 1.00 1.00 1.08 500-pixel wide ellipse - 1.93 1.88 1.00 1.00 1.88 100-pixel wide dashed ellipse - 1.94 1.89 1.01 1.00 1.94 100-pixel wide double-dashed ellipse - 2.31 1.48 1.00 1.00 2.67 10-pixel partial ellipse - 1.38 1.17 1.00 1.00 1.38 100-pixel partial ellipse - 2.00 1.85 0.98 0.97 1.98 10-pixel wide partial ellipse - 1.89 1.86 1.00 1.00 1.89 100-pixel wide partial ellipse - 3.49 1.60 1.00 1.00 3.65 10-pixel filled ellipse - 1.67 1.26 1.00 1.00 1.67 100-pixel filled ellipse - 1.06 1.04 1.00 1.00 1.06 500-pixel filled ellipse - 2.38 1.43 1.01 1.00 2.32 10-pixel fill chord partial ellipse - 2.06 1.30 1.00 1.00 2.05 100-pixel fill chord partial ellipse - 2.27 1.41 1.00 1.00 2.27 10-pixel fill slice partial ellipse - 1.98 1.33 1.00 0.97 1.97 100-pixel fill slice partial ellipse - 57.46 1.99 1.01 1.00 114.92 Fill 1x1 equivalent triangle - 56.94 1.98 1.01 1.00 73.89 Fill 10x10 equivalent triangle - 6.07 1.75 1.00 1.00 6.07 Fill 100x100 equivalent triangle - 51.12 1.98 1.00 1.00 102.81 Fill 1x1 trapezoid - 51.42 1.82 1.01 1.00 94.89 Fill 10x10 trapezoid - 6.47 1.80 1.00 1.00 6.44 Fill 100x100 trapezoid - 1.56 1.28 1.00 0.99 1.56 Fill 300x300 trapezoid - 51.27 1.97 0.96 0.97 102.54 Fill 1x1 stippled trapezoid (8x8 stipple) - 51.73 2.00 1.02 1.02 67.92 Fill 10x10 stippled trapezoid (8x8 stipple) - 5.36 1.72 1.00 1.00 5.36 Fill 100x100 stippled trapezoid (8x8 stipple) - 1.54 1.26 1.00 1.00 1.59 Fill 300x300 stippled trapezoid (8x8 stipple) - 51.41 1.94 1.01 1.00 102.82 Fill 1x1 opaque stippled trapezoid (8x8 stipple) - 50.71 1.95 0.99 1.00 65.44 Fill 10x10 opaque stippled trapezoid (8x8... - 5.33 1.73 1.00 1.00 5.36 Fill 100x100 opaque stippled trapezoid (8x8... - 1.58 1.25 1.00 1.00 1.58 Fill 300x300 opaque stippled trapezoid (8x8... - 51.56 1.96 0.99 0.90 103.68 Fill 1x1 tiled trapezoid (4x4 tile) - 51.59 1.99 1.01 1.01 62.25 Fill 10x10 tiled trapezoid (4x4 tile) - 5.38 1.72 1.00 1.00 5.38 Fill 100x100 tiled trapezoid (4x4 tile) - 1.54 1.25 1.00 0.99 1.58 Fill 300x300 tiled trapezoid (4x4 tile) - 51.70 1.98 1.01 1.01 103.98 Fill 1x1 stippled trapezoid (17x15 stipple) - 44.86 1.97 1.00 1.00 44.86 Fill 10x10 stippled trapezoid (17x15 stipple) - 2.74 1.56 1.00 1.00 2.73 Fill 100x100 stippled trapezoid (17x15 stipple) - 1.29 1.14 1.00 1.00 1.27 Fill 300x300 stippled trapezoid (17x15 stipple) - 51.41 1.96 0.96 0.95 103.39 Fill 1x1 opaque stippled trapezoid (17x15... - 45.14 1.96 1.01 1.00 45.14 Fill 10x10 opaque stippled trapezoid (17x15... - 2.68 1.56 1.00 1.00 2.68 Fill 100x100 opaque stippled trapezoid (17x15... - 1.26 1.10 1.00 1.00 1.28 Fill 300x300 opaque stippled trapezoid (17x15... - 51.13 1.97 1.00 0.99 103.39 Fill 1x1 tiled trapezoid (17x15 tile) - 47.58 1.96 1.00 1.00 47.86 Fill 10x10 tiled trapezoid (17x15 tile) - 2.74 1.56 1.00 1.00 2.74 Fill 100x100 tiled trapezoid (17x15 tile) - 1.29 1.14 1.00 1.00 1.28 Fill 300x300 tiled trapezoid (17x15 tile) - 51.13 1.97 0.99 0.97 103.39 Fill 1x1 stippled trapezoid (161x145 stipple) - 45.14 1.97 1.00 1.00 44.29 Fill 10x10 stippled trapezoid (161x145 stipple) - 3.02 1.77 1.12 1.12 3.38 Fill 100x100 stippled trapezoid (161x145 stipple) - 1.31 1.13 1.00 1.00 1.30 Fill 300x300 stippled trapezoid (161x145 stipple) - 51.27 1.97 1.00 1.00 103.10 Fill 1x1 opaque stippled trapezoid (161x145... - 45.01 1.97 1.00 1.00 45.01 Fill 10x10 opaque stippled trapezoid (161x145... - 2.67 1.56 1.00 1.00 2.69 Fill 100x100 opaque stippled trapezoid (161x145.. - 1.29 1.13 1.00 1.01 1.27 Fill 300x300 opaque stippled trapezoid (161x145.. - 51.41 1.96 1.00 0.99 103.39 Fill 1x1 tiled trapezoid (161x145 tile) - 45.01 1.96 0.98 1.00 45.01 Fill 10x10 tiled trapezoid (161x145 tile) - 2.62 1.36 1.00 1.00 2.69 Fill 100x100 tiled trapezoid (161x145 tile) - 1.27 1.13 1.00 1.00 1.22 Fill 300x300 tiled trapezoid (161x145 tile) - 51.13 1.98 1.00 1.00 103.39 Fill 1x1 tiled trapezoid (216x208 tile) - 45.14 1.97 1.01 0.99 45.14 Fill 10x10 tiled trapezoid (216x208 tile) - 2.62 1.55 1.00 1.00 2.71 Fill 100x100 tiled trapezoid (216x208 tile) - 1.28 1.13 1.00 1.00 1.20 Fill 300x300 tiled trapezoid (216x208 tile) - 50.71 1.95 1.00 1.00 54.70 Fill 10x10 equivalent complex polygon - 5.51 1.71 0.96 0.98 5.47 Fill 100x100 equivalent complex polygons - 8.39 1.97 1.00 1.00 16.75 Fill 10x10 64-gon (Convex) - 8.38 1.83 1.00 1.00 8.43 Fill 100x100 64-gon (Convex) - 8.50 1.96 1.00 1.00 16.64 Fill 10x10 64-gon (Complex) - 8.26 1.83 1.00 1.00 8.35 Fill 100x100 64-gon (Complex) - 14.09 1.87 1.00 1.00 14.05 Char in 80-char line (6x13) - 11.91 1.87 1.00 1.00 11.95 Char in 70-char line (8x13) - 11.16 1.85 1.01 1.00 11.10 Char in 60-char line (9x15) - 10.09 1.78 1.00 1.00 10.09 Char16 in 40-char line (k14) - 6.15 1.75 1.00 1.00 6.31 Char16 in 23-char line (k24) - 11.92 1.90 1.03 1.03 11.88 Char in 80-char line (TR 10) - 8.18 1.78 1.00 0.99 8.17 Char in 30-char line (TR 24) - 42.83 1.44 1.01 1.00 42.11 Char in 20/40/20 line (6x13, TR 10) - 27.45 1.43 1.01 1.01 27.45 Char16 in 7/14/7 line (k14, k24) - 12.13 1.85 1.00 1.00 12.05 Char in 80-char image line (6x13) - 10.00 1.84 1.00 1.00 10.00 Char in 70-char image line (8x13) - 9.18 1.83 1.00 1.00 9.12 Char in 60-char image line (9x15) - 9.66 1.82 0.98 0.95 9.66 Char16 in 40-char image line (k14) - 5.82 1.72 1.00 1.00 5.99 Char16 in 23-char image line (k24) - 8.70 1.80 1.00 1.00 8.65 Char in 80-char image line (TR 10) - 4.67 1.66 1.00 1.00 4.67 Char in 30-char image line (TR 24) - 84.43 1.47 1.00 1.00 124.18 Scroll 10x10 pixels - 3.73 1.50 1.00 0.98 3.73 Scroll 100x100 pixels - 1.00 1.00 1.00 1.00 1.00 Scroll 500x500 pixels - 84.43 1.51 1.00 1.00 134.02 Copy 10x10 from window to window - 3.62 1.51 0.98 0.98 3.62 Copy 100x100 from window to window - 0.89 1.00 1.00 1.00 1.00 Copy 500x500 from window to window - 57.06 1.99 1.00 1.00 88.64 Copy 10x10 from pixmap to window - 2.49 2.00 1.00 1.00 2.48 Copy 100x100 from pixmap to window - 1.00 0.91 1.00 1.00 0.98 Copy 500x500 from pixmap to window - 2.04 1.01 1.00 1.00 2.03 Copy 10x10 from window to pixmap - 1.05 1.00 1.00 1.00 1.05 Copy 100x100 from window to pixmap - 1.00 1.00 0.93 1.00 1.04 Copy 500x500 from window to pixmap - 58.52 1.03 1.03 1.02 57.95 Copy 10x10 from pixmap to pixmap - 2.40 1.00 1.00 1.00 2.45 Copy 100x100 from pixmap to pixmap - 1.00 1.00 1.00 1.00 1.00 Copy 500x500 from pixmap to pixmap - 51.57 1.92 1.00 1.00 85.75 Copy 10x10 1-bit deep plane - 6.37 1.75 1.01 1.01 6.37 Copy 100x100 1-bit deep plane - 1.26 1.11 1.00 1.00 1.24 Copy 500x500 1-bit deep plane - 4.23 1.63 0.98 0.97 4.38 Copy 10x10 n-bit deep plane - 1.04 1.02 1.00 1.00 1.04 Copy 100x100 n-bit deep plane - 1.00 1.00 1.00 1.00 1.00 Copy 500x500 n-bit deep plane - 6.45 1.98 1.00 1.26 12.80 PutImage 10x10 square - 1.10 1.87 1.00 1.83 2.11 PutImage 100x100 square - 1.02 1.93 1.00 1.91 1.91 PutImage 500x500 square - 4.17 1.78 1.00 1.40 7.18 PutImage XY 10x10 square - 1.27 1.49 0.97 1.48 2.10 PutImage XY 100x100 square - 1.00 1.50 1.00 1.50 1.52 PutImage XY 500x500 square - 1.07 1.01 1.00 1.00 1.06 GetImage 10x10 square - 1.01 1.00 1.00 1.00 1.01 GetImage 100x100 square - 1.00 1.00 1.00 1.00 1.00 GetImage 500x500 square - 1.56 1.00 0.99 0.97 1.56 GetImage XY 10x10 square - 1.02 1.00 1.00 1.00 1.02 GetImage XY 100x100 square - 1.00 1.00 1.00 1.00 1.00 GetImage XY 500x500 square - 1.00 1.00 1.01 0.98 0.95 X protocol NoOperation - 1.02 1.03 1.04 1.03 1.00 QueryPointer - 1.03 1.02 1.04 1.03 1.00 GetProperty -100.41 1.51 1.00 1.00 198.76 Change graphics context - 45.81 1.00 0.99 0.97 57.10 Create and map subwindows (4 kids) - 78.45 1.01 1.02 1.02 63.07 Create and map subwindows (16 kids) - 73.91 1.01 1.00 1.00 56.37 Create and map subwindows (25 kids) - 73.22 1.00 1.00 1.00 49.07 Create and map subwindows (50 kids) - 72.36 1.01 0.99 1.00 32.14 Create and map subwindows (75 kids) - 70.34 1.00 1.00 1.00 30.12 Create and map subwindows (100 kids) - 55.00 1.00 1.00 0.99 23.75 Create and map subwindows (200 kids) - 55.30 1.01 1.00 1.00 141.03 Create unmapped window (4 kids) - 55.38 1.01 1.01 1.00 163.25 Create unmapped window (16 kids) - 54.75 0.96 1.00 0.99 166.95 Create unmapped window (25 kids) - 54.83 1.00 1.00 0.99 178.81 Create unmapped window (50 kids) - 55.38 1.01 1.01 1.00 181.20 Create unmapped window (75 kids) - 55.38 1.01 1.01 1.00 181.20 Create unmapped window (100 kids) - 54.87 1.01 1.01 1.00 182.05 Create unmapped window (200 kids) - 28.13 1.00 1.00 1.00 30.75 Map window via parent (4 kids) - 36.14 1.01 1.01 1.01 32.58 Map window via parent (16 kids) - 26.13 1.00 0.98 0.95 29.85 Map window via parent (25 kids) - 40.07 1.00 1.01 1.00 27.57 Map window via parent (50 kids) - 23.26 0.99 1.00 1.00 18.23 Map window via parent (75 kids) - 22.91 0.99 1.00 0.99 16.52 Map window via parent (100 kids) - 27.79 1.00 1.00 0.99 12.50 Map window via parent (200 kids) - 22.35 1.00 1.00 1.00 56.19 Unmap window via parent (4 kids) - 9.57 1.00 0.99 1.00 89.78 Unmap window via parent (16 kids) - 80.77 1.01 1.00 1.00 103.85 Unmap window via parent (25 kids) - 96.34 1.00 1.00 1.00 116.06 Unmap window via parent (50 kids) - 99.72 1.00 1.00 1.00 124.93 Unmap window via parent (75 kids) -112.36 1.00 1.00 1.00 125.27 Unmap window via parent (100 kids) -105.41 1.00 1.00 0.99 120.00 Unmap window via parent (200 kids) - 51.29 1.03 1.02 1.02 74.19 Destroy window via parent (4 kids) - 86.75 0.99 0.99 0.99 116.87 Destroy window via parent (16 kids) -106.43 1.01 1.01 1.01 127.49 Destroy window via parent (25 kids) -120.34 1.01 1.01 1.00 140.11 Destroy window via parent (50 kids) -126.67 1.00 0.99 0.99 145.00 Destroy window via parent (75 kids) -126.11 1.01 1.01 1.00 140.56 Destroy window via parent (100 kids) -128.57 1.01 1.00 1.00 137.91 Destroy window via parent (200 kids) - 16.04 0.88 1.00 1.00 20.36 Hide/expose window via popup (4 kids) - 19.04 1.01 1.00 1.00 23.48 Hide/expose window via popup (16 kids) - 19.22 1.00 1.00 1.00 20.44 Hide/expose window via popup (25 kids) - 17.41 1.00 0.91 0.97 17.68 Hide/expose window via popup (50 kids) - 17.29 1.01 1.00 1.01 17.07 Hide/expose window via popup (75 kids) - 16.74 1.00 1.00 1.00 16.17 Hide/expose window via popup (100 kids) - 10.30 1.00 1.00 1.00 10.51 Hide/expose window via popup (200 kids) - 16.48 1.01 1.00 1.00 26.05 Move window (4 kids) - 17.01 0.95 1.00 1.00 23.97 Move window (16 kids) - 16.95 1.00 1.00 1.00 22.90 Move window (25 kids) - 16.05 1.01 1.00 1.00 21.32 Move window (50 kids) - 15.58 1.00 0.98 0.98 19.44 Move window (75 kids) - 14.98 1.02 1.03 1.03 18.17 Move window (100 kids) - 10.90 1.01 1.01 1.00 12.68 Move window (200 kids) - 49.42 1.00 1.00 1.00 198.27 Moved unmapped window (4 kids) - 50.72 0.97 1.00 1.00 193.66 Moved unmapped window (16 kids) - 50.87 1.00 0.99 1.00 195.09 Moved unmapped window (25 kids) - 50.72 1.00 1.00 1.00 189.34 Moved unmapped window (50 kids) - 50.87 1.00 1.00 1.00 191.33 Moved unmapped window (75 kids) - 50.87 1.00 1.00 0.90 186.71 Moved unmapped window (100 kids) - 50.87 1.00 1.00 1.00 179.19 Moved unmapped window (200 kids) - 41.04 1.00 1.00 1.00 56.61 Move window via parent (4 kids) - 69.81 1.00 1.00 1.00 130.82 Move window via parent (16 kids) - 95.81 1.00 1.00 1.00 141.92 Move window via parent (25 kids) - 95.98 1.00 1.00 1.00 149.43 Move window via parent (50 kids) - 96.59 1.01 1.01 1.00 153.98 Move window via parent (75 kids) - 97.19 1.00 1.00 1.00 157.30 Move window via parent (100 kids) - 96.67 1.00 0.99 0.96 159.44 Move window via parent (200 kids) - 17.75 1.01 1.00 1.00 27.61 Resize window (4 kids) - 17.94 1.00 1.00 0.99 25.42 Resize window (16 kids) - 17.92 1.01 1.00 1.00 24.47 Resize window (25 kids) - 17.24 0.97 1.00 1.00 24.14 Resize window (50 kids) - 16.81 1.00 1.00 0.99 22.75 Resize window (75 kids) - 16.08 1.00 1.00 1.00 21.20 Resize window (100 kids) - 12.92 1.00 0.99 1.00 16.26 Resize window (200 kids) - 52.94 1.01 1.00 1.00 327.12 Resize unmapped window (4 kids) - 53.60 1.01 1.01 1.01 333.71 Resize unmapped window (16 kids) - 52.99 1.00 1.00 1.00 337.29 Resize unmapped window (25 kids) - 51.98 1.00 1.00 1.00 329.38 Resize unmapped window (50 kids) - 53.05 0.89 1.00 1.00 322.60 Resize unmapped window (75 kids) - 53.05 1.00 1.00 1.00 318.08 Resize unmapped window (100 kids) - 53.11 1.00 1.00 0.99 306.21 Resize unmapped window (200 kids) - 16.76 1.00 0.96 1.00 19.46 Circulate window (4 kids) - 17.24 1.00 1.00 0.97 16.24 Circulate window (16 kids) - 16.30 1.03 1.03 1.03 15.85 Circulate window (25 kids) - 13.45 1.00 1.00 1.00 14.90 Circulate window (50 kids) - 12.91 1.00 1.00 1.00 13.06 Circulate window (75 kids) - 11.30 0.98 1.00 1.00 11.03 Circulate window (100 kids) - 7.58 1.01 1.01 0.99 7.47 Circulate window (200 kids) - 1.01 1.01 0.98 1.00 0.95 Circulate Unmapped window (4 kids) - 1.07 1.07 1.01 1.07 1.02 Circulate Unmapped window (16 kids) - 1.04 1.09 1.06 1.05 0.97 Circulate Unmapped window (25 kids) - 1.04 1.23 1.20 1.18 1.05 Circulate Unmapped window (50 kids) - 1.18 1.53 1.19 1.45 1.24 Circulate Unmapped window (75 kids) - 1.08 1.02 1.01 1.74 1.01 Circulate Unmapped window (100 kids) - 1.01 1.12 0.98 0.91 0.97 Circulate Unmapped window (200 kids) - </verb> - -<sect2>Profiling with OProfile - -<p>OProfile (available from http://oprofile.sourceforge.net/) is a -system-wide profiler for Linux systems that uses processor-level -counters to collect sampling data. OProfile can provide information -that is similar to that provided by <tt/gprof/, but without the -necessity of recompiling the program with special instrumentation (i.e., -OProfile can collect statistical profiling information about optimized -programs). A test harness was developed to collect OProfile data for -each <tt/x11perf/ test individually. - -<p>Test runs were performed using the RETIRED_INSNS counter on the AMD -Athlon and the CPU_CLK_HALTED counter on the Intel Pentium III (with a -test configuration different from the one described above). We have -examined OProfile output and have compared it with <tt/gprof/ output. -This investigation has not produced results that yield performance -increases in <tt/x11perf/ numbers. - -<!-- -<sect3>Retired Instructions - -<p>The initial tests using OProfile were done using the RETIRED_INSNS -counter with DMX running on the dual-processor AMD Athlon machine - the -same test configuration that was described above and that was used for -other tests. The RETIRED_INSNS counter counts retired instructions and -showed drawing, text, copying, and image tests to be dominated (> -30%) by calls to Hash(), SecurityLookupIDByClass(), -SecurityLookupIDByType(), and StandardReadRequestFromClient(). Some of -these tests also executed significant instructions in -WaitForSomething(). - -<p>In contrast, the window tests executed significant -instructions in SecurityLookupIDByType(), Hash(), -StandardReadRequestFromClient(), but also executed significant -instructions in other routines, such as ConfigureWindow(). Some time -was spent looking at Hash() function, but optimizations in this routine -did not lead to a dramatic increase in <tt/x11perf/ performance. ---> - -<!-- -<sect3>Clock Cycles - -<p>Retired instructions can be misleading because Intel/AMD instructions -execute in variable amounts of time. The OProfile tests were repeated -using the Intel CPU_CLK_HALTED counter with DMX running on the second -back-end machine. Note that this is a different test configuration that -the one described above. However, these tests show the amount of time -(as measured in CPU cycles) that are spent in each routine. Because -<tt/x11perf/ was running on the first back-end machine and because -window optimizations were on, the load on the second back-end machine -was not significant. - -<p>Using CPU_CLK_HALTED, DMX showed simple drawing -tests spending more than 10% of their time in -StandardReadRequestFromClient(), with significant time (> 20% total) -spent in SecurityLookupIDByClass(), WaitForSomething(), and Dispatch(). -For these tests, < 5% of the time was spent in Hash(), which explains -why optimizing the Hash() routine did not impact <tt/x11perf/ results. - -<p>The trapezoid, text, scrolling, copying, and image tests were -dominated by time in ProcFillPoly(), PanoramiXFillPoly(), dmxFillPolygon(), -SecurityLookupIDByClass(), SecurityLookupIDByType(), and -StandardReadRequestFromClient(). Hash() time was generally above 5% but -less than 10% of total time. ---> - -<sect2>X Test Suite - -<p>The X Test Suite was run on the fully optimized DMX server using the -configuration described above. The following failures were noted: - <verb> -XListPixmapFormats: Test 1 [1] -XChangeWindowAttributes: Test 32 [1] -XCreateWindow: Test 30 [1] -XFreeColors: Test 4 [3] -XCopyArea: Test 13, 17, 21, 25, 30 [2] -XCopyPlane: Test 11, 15, 27, 31 [2] -XSetFontPath: Test 4 [1] -XChangeKeyboardControl: Test 9, 10 [1] - -[1] Previously documented errors expected from the Xinerama - implementation (see Phase I discussion). -[2] Newly noted errors that have been verified as expected - behavior of the Xinerama implementation. -[3] Newly noted error that has been verified as a Xinerama - implementation bug. - </verb> - -<!-- ============================================================ --> -<sect1>Phase III - -<p>During the third phase of development, support was provided for the -following extensions: SHAPE, RENDER, XKEYBOARD, XInput. - -<sect2>SHAPE - -<p>The SHAPE extension is supported. Test applications (e.g., xeyes and -oclock) and window managers that make use of the SHAPE extension will -work as expected. - -<sect2>RENDER - -<p>The RENDER extension is supported. The version included in the DMX -CVS tree is version 0.2, and this version is fully supported by Xdmx. -Applications using only version 0.2 functions will work correctly; -however, some apps that make use of functions from later versions do not -properly check the extension's major/minor version numbers. These apps -will fail with a Bad Implementation error when using post-version 0.2 -functions. This is expected behavior. When the DMX CVS tree is updated -to include newer versions of RENDER, support for these newer functions -will be added to the DMX X server. - -<sect2>XKEYBOARD - -<p>The XKEYBOARD extension is supported. If present on the back-end X -servers, the XKEYBOARD extension will be used to obtain information -about the type of the keyboard for initialization. Otherwise, the -keyboard will be initialized using defaults. Note that this departs -from older behavior: when Xdmx is compiled without XKEYBOARD support, -the map from the back-end X server will be preserved. With XKEYBOARD -support, the map is not preserved because better information and control -of the keyboard is available. - -<sect2>XInput - -<p>The XInput extension is supported. Any device can be used as a core -device and be used as an XInput extension device, with the exception of -core devices on the back-end servers. This limitation is present -because cursor handling on the back-end requires that the back-end -cursor sometimes track the Xdmx core cursor -- behavior that is -incompatible with using the back-end pointer as a non-core device. - -<p>Currently, back-end extension devices are not available as Xdmx -extension devices, but this limitation should be removed in the future. - -<p>To demonstrate the XInput extension, and to provide more examples for -low-level input device driver writers, USB device drivers have been -written for mice (usb-mou), keyboards (usb-kbd), and -non-mouse/non-keyboard USB devices (usb-oth). Please see the man page -for information on Linux kernel drivers that are required for using -these Xdmx drivers. - -<sect2>DPMS - -<p>The DPMS extension is exported but does not do anything at this time. - -<sect2>Other Extensions - -<p>The LBX, - SECURITY, - XC-APPGROUP, and - XFree86-Bigfont -extensions do not require any special Xdmx support and have been exported. - -<p>The - BIG-REQUESTS, - DEC-XTRAP, - DOUBLE-BUFFER, - Extended-Visual-Information, - FontCache, - GLX, - MIT-SCREEN-SAVER, - MIT-SHM, - MIT-SUNDRY-NONSTANDARD, - RECORD, - SECURITY, - SGI-GLX, - SYNC, - TOG-CUP, - X-Resource, - XC-MISC, - XFree86-DGA, - XFree86-DRI, - XFree86-Misc, - XFree86-VidModeExtension, and - XVideo -extensions are <it/not/ supported at this time, but will be evaluated -for inclusion in future DMX releases. <bf>See below for additional work -on extensions after Phase III.</bf> - -<sect1>Phase IV - -<sect2>Moving to XFree86 4.3.0 - -<p>For Phase IV, the recent release of XFree86 4.3.0 (27 February 2003) -was merged onto the dmx.sourceforge.net CVS trunk and all work is -proceeding using this tree. - -<sect2>Extensions - -<sect3>XC-MISC (supported) - -<p>XC-MISC is used internally by the X library to recycle XIDs from the -X server. This is important for long-running X server sessions. Xdmx -supports this extension. The X Test Suite passed and failed the exact -same tests before and after this extension was enabled. -<!-- Tested February/March 2003 --> - -<sect3>Extended-Visual-Information (supported) - -<p>The Extended-Visual-Information extension provides a method for an X -client to obtain detailed visual information. Xdmx supports this -extension. It was tested using the <tt>hw/dmx/examples/evi</tt> example -program. <bf/Note that this extension is not Xinerama-aware/ -- it will -return visual information for each screen even though Xinerama is -causing the X server to export a single logical screen. -<!-- Tested March 2003 --> - -<sect3>RES (supported) - -<p>The X-Resource extension provides a mechanism for a client to obtain -detailed information about the resources used by other clients. This -extension was tested with the <tt>hw/dmx/examples/res</tt> program. The -X Test Suite passed and failed the exact same tests before and after -this extension was enabled. -<!-- Tested March 2003 --> - -<sect3>BIG-REQUESTS (supported) - -<p>This extension enables the X11 protocol to handle requests longer -than 262140 bytes. The X Test Suite passed and failed the exact same -tests before and after this extension was enabled. -<!-- Tested March 2003 --> - -<sect3>XSYNC (supported) - -<p>This extension provides facilities for two different X clients to -synchronize their requests. This extension was minimally tested with -<tt/xdpyinfo/ and the X Test Suite passed and failed the exact same -tests before and after this extension was enabled. -<!-- Tested March 2003 --> - -<sect3>XTEST, RECORD, DEC-XTRAP (supported) and XTestExtension1 (not supported) - -<p>The XTEST and RECORD extension were developed by the X Consortium for -use in the X Test Suite and are supported as a standard in the X11R6 -tree. They are also supported in Xdmx. When X Test Suite tests that -make use of the XTEST extension are run, Xdmx passes and fails exactly -the same tests as does a standard XFree86 X server. When the -<tt/rcrdtest/ test (a part of the X Test Suite that verifies the RECORD -extension) is run, Xdmx passes and fails exactly the same tests as does -a standard XFree86 X server. <!-- Tested February/March 2003 --> - -<p>There are two older XTEST-like extensions: DEC-XTRAP and -XTestExtension1. The XTestExtension1 extension was developed for use by -the X Testing Consortium for use with a test suite that eventually -became (part of?) the X Test Suite. Unlike XTEST, which only allows -events to be sent to the server, the XTestExtension1 extension also -allowed events to be recorded (similar to the RECORD extension). The -second is the DEC-XTRAP extension that was developed by the Digital -Equipment Corporation. - -<p>The DEC-XTRAP extension is available from Xdmx and has been tested -with the <tt/xtrap*/ tools which are distributed as standard X11R6 -clients. <!-- Tested March 2003 --> - -<p>The XTestExtension1 is <em/not/ supported because it does not appear -to be used by any modern X clients (the few that support it also support -XTEST) and because there are no good methods available for testing that -it functions correctly (unlike XTEST and DEC-XTRAP, the code for -XTestExtension1 is not part of the standard X server source tree, so -additional testing is important). <!-- Tested March 2003 --> - -<p>Most of these extensions are documented in the X11R6 source tree. -Further, several original papers exist that this author was unable to -locate -- for completeness and historical interest, citations are -provide: -<descrip> -<tag/XRECORD/ Martha Zimet. Extending X For Recording. 8th Annual X -Technical Conference Boston, MA January 24-26, 1994. -<tag/DEC-XTRAP/ Dick Annicchiarico, Robert Chesler, Alan Jamison. XTrap -Architecture. Digital Equipment Corporation, July 1991. -<tag/XTestExtension1/ Larry Woestman. X11 Input Synthesis Extension -Proposal. Hewlett Packard, November 1991. -</descrip> - -<sect3>MIT-MISC (not supported) - -<p>The MIT-MISC extension is used to control a bug-compatibility flag -that provides compatibility with xterm programs from X11R1 and X11R2. -There does not appear to be a single client available that makes use of -this extension and there is not way to verify that it works correctly. -The Xdmx server does <em/not/ support MIT-MISC. - -<sect3>SCREENSAVER (not supported) - -<p>This extension provides special support for the X screen saver. It -was tested with beforelight, which appears to be the only client that -works with it. When Xinerama was not active, <tt/beforelight/ behaved -as expected. However, when Xinerama was active, <tt/beforelight/ did -not behave as expected. Further, when this extension is not active, -<tt/xscreensaver/ (a widely-used X screen saver program) did not behave -as expected. Since this extension is not Xinerama-aware and is not -commonly used with expected results by clients, we have left this -extension disabled at this time. - -<sect3>GLX (supported) - -<p>The GLX extension provides OpenGL and GLX windowing support. In -Xdmx, the extension is called glxProxy, and it is Xinerama aware. It -works by either feeding requests forward through Xdmx to each of the -back-end servers or handling them locally. All rendering requests are -handled on the back-end X servers. This code was donated to the DMX -project by SGI. For the X Test Suite results comparison, see below. - -<sect3>RENDER (supported) - -<p>The X Rendering Extension (RENDER) provides support for digital image -composition. Geometric and text rendering are supported. RENDER is -partially Xinerama-aware, with text and the most basic compositing -operator; however, its higher level primitives (triangles, triangle -strips, and triangle fans) are not yet Xinerama-aware. The RENDER -extension is still under development, and is currently at version 0.8. -Additional support will be required in DMX as more primitives and/or -requests are added to the extension. - -<p>There is currently no test suite for the X Rendering Extension; -however, there has been discussion of developing a test suite as the -extension matures. When that test suite becomes available, additional -testing can be performed with Xdmx. The X Test Suite passed and failed -the exact same tests before and after this extension was enabled. - -<sect3>Summary - -<!-- WARNING: this list is duplicated in the "Common X extension -support" section --> -<p>To summarize, the following extensions are currently supported: - BIG-REQUESTS, - DEC-XTRAP, - DMX, - DPMS, - Extended-Visual-Information, - GLX, - LBX, - RECORD, - RENDER, - SECURITY, - SHAPE, - SYNC, - X-Resource, - XC-APPGROUP, - XC-MISC, - XFree86-Bigfont, - XINERAMA, - XInputExtension, - XKEYBOARD, and - XTEST. - -<p>The following extensions are <em/not/ supported at this time: - DOUBLE-BUFFER, - FontCache, - MIT-SCREEN-SAVER, - MIT-SHM, - MIT-SUNDRY-NONSTANDARD, - TOG-CUP, - XFree86-DGA, - XFree86-Misc, - XFree86-VidModeExtension, - XTestExtensionExt1, and - XVideo. - -<sect2>Additional Testing with the X Test Suite - -<sect3>XFree86 without XTEST - -<p>After the release of XFree86 4.3.0, we retested the XFree86 X server -with and without using the XTEST extension. When the XTEST extension -was <em/not/ used for testing, the XFree86 4.3.0 server running on our -usual test system with a Radeon VE card reported unexpected failures in -the following tests: -<verb> -XListPixmapFormats: Test 1 -XChangeKeyboardControl: Tests 9, 10 -XGetDefault: Test 5 -XRebindKeysym: Test 1 -</verb> - -<sect3>XFree86 with XTEST - -<p>When using the XTEST extension, the XFree86 4.3.0 server reported the -following errors: -<verb> -XListPixmapFormats: Test 1 -XChangeKeyboardControl: Tests 9, 10 -XGetDefault: Test 5 -XRebindKeysym: Test 1 - -XAllowEvents: Tests 20, 21, 24 -XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 -XGrabKey: Test 8 -XSetPointerMapping: Test 3 -XUngrabButton: Test 4 -</verb> - -<p>While these errors may be important, they will probably be fixed -eventually in the XFree86 source tree. We are particularly interested -in demonstrating that the Xdmx server does not introduce additional -failures that are not known Xinerama failures. - -<sect3>Xdmx with XTEST, without Xinerama, without GLX - -<p>Without Xinerama, but using the XTEST extension, the following errors -were reported from Xdmx (note that these are the same as for the XFree86 -4.3.0, except that XGetDefault no longer fails): -<verb> -XListPixmapFormats: Test 1 -XChangeKeyboardControl: Tests 9, 10 -XRebindKeysym: Test 1 - -XAllowEvents: Tests 20, 21, 24 -XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 -XGrabKey: Test 8 -XSetPointerMapping: Test 3 -XUngrabButton: Test 4 -</verb> - -<sect3>Xdmx with XTEST, with Xinerama, without GLX - -<p>With Xinerama, using the XTEST extension, the following errors -were reported from Xdmx: -<verb> -XListPixmapFormats: Test 1 -XChangeKeyboardControl: Tests 9, 10 -XRebindKeysym: Test 1 - -XAllowEvents: Tests 20, 21, 24 -XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 -XGrabKey: Test 8 -XSetPointerMapping: Test 3 -XUngrabButton: Test 4 - -XCopyPlane: Tests 13, 22, 31 (well-known XTEST/Xinerama interaction issue) -XDrawLine: Test 67 -XDrawLines: Test 91 -XDrawSegments: Test 68 -</verb> -Note that the first two sets of errors are the same as for the XFree86 -4.3.0 server, and that the XCopyPlane error is a well-known error -resulting from an XTEST/Xinerama interaction when the request crosses a -screen boundary. The XDraw* errors are resolved when the tests are run -individually and they do not cross a screen boundary. We will -investigate these errors further to determine their cause. - -<sect3>Xdmx with XTEST, with Xinerama, with GLX - -<p>With GLX enabled, using the XTEST extension, the following errors -were reported from Xdmx (these results are from early during the Phase -IV development, but were confirmed with a late Phase IV snapshot): -<verb> -XListPixmapFormats: Test 1 -XChangeKeyboardControl: Tests 9, 10 -XRebindKeysym: Test 1 - -XAllowEvents: Tests 20, 21, 24 -XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 -XGrabKey: Test 8 -XSetPointerMapping: Test 3 -XUngrabButton: Test 4 - -XClearArea: Test 8 -XCopyArea: Tests 4, 5, 11, 14, 17, 23, 25, 27, 30 -XCopyPlane: Tests 6, 7, 10, 19, 22, 31 -XDrawArcs: Tests 89, 100, 102 -XDrawLine: Test 67 -XDrawSegments: Test 68 -</verb> -Note that the first two sets of errors are the same as for the XFree86 -4.3.0 server, and that the third set has different failures than when -Xdmx does not include GLX support. Since the GLX extension adds new -visuals to support GLX's visual configs and the X Test Suite runs tests -over the entire set of visuals, additional rendering tests were run and -presumably more of them crossed a screen boundary. This conclusion is -supported by the fact that nearly all of the rendering errors reported -are resolved when the tests are run individually and they do no cross a -screen boundary. - -<p>Further, when hardware rendering is disabled on the back-end displays, -many of the errors in the third set are eliminated, leaving only: -<verb> -XClearArea: Test 8 -XCopyArea: Test 4, 5, 11, 14, 17, 23, 25, 27, 30 -XCopyPlane: Test 6, 7, 10, 19, 22, 31 -</verb> - -<sect3>Conclusion - -<p>We conclude that all of the X Test Suite errors reported for Xdmx are -the result of errors in the back-end X server or the Xinerama -implementation. Further, all of these errors that can be reasonably -fixed at the Xdmx layer have been. (Where appropriate, we have -submitted patches to the XFree86 and Xinerama upstream maintainers.) - -<sect2>Dynamic Reconfiguration - -<p>During this development phase, dynamic reconfiguration support was -added to DMX. This support allows an application to change the position -and offset of a back-end server's screen. For example, if the -application would like to shift a screen slightly to the left, it could -query Xdmx for the screen's <x,y> position and then dynamically -reconfigure that screen to be at position <x+10,y>. When a screen -is dynamically reconfigured, input handling and a screen's root window -dimensions are adjusted as needed. These adjustments are transparent to -the user. - -<sect3>Dynamic reconfiguration extension - -<p>The application interface to DMX's dynamic reconfiguration is through -a function in the DMX extension library: -<verb> -Bool DMXReconfigureScreen(Display *dpy, int screen, int x, int y) -</verb> -where <it/dpy/ is DMX server's display, <it/screen/ is the number of the -screen to be reconfigured, and <it/x/ and <it/y/ are the new upper, -left-hand coordinates of the screen to be reconfigured. - -<p>The coordinates are not limited other than as required by the X -protocol, which limits all coordinates to a signed 16 bit number. In -addition, all coordinates within a screen must also be legal values. -Therefore, setting a screen's upper, left-hand coordinates such that the -right or bottom edges of the screen is greater than 32,767 is illegal. - -<sect3>Bounding box - -<p>When the Xdmx server is started, a bounding box is calculated from -the screens' layout given either on the command line or in the -configuration file. This bounding box is currently fixed for the -lifetime of the Xdmx server. - -<p>While it is possible to move a screen outside of the bounding box, it -is currently not possible to change the dimensions of the bounding box. -For example, it is possible to specify coordinates of <-100,-100> -for the upper, left-hand corner of the bounding box, which was -previously at coordinates <0,0>. As expected, the screen is moved -down and to the right; however, since the bounding box is fixed, the -left side and upper portions of the screen exposed by the -reconfiguration are no longer accessible on that screen. Those -inaccessible regions are filled with black. - -<p>This fixed bounding box limitation will be addressed in a future -development phase. - -<sect3>Sample applications - -<p>An example of where this extension is useful is in setting up a video -wall. It is not always possible to get everything perfectly aligned, -and sometimes the positions are changed (e.g., someone might bump into a -projector). Instead of physically moving projectors or monitors, it is -now possible to adjust the positions of the back-end server's screens -using the dynamic reconfiguration support in DMX. - -<p>Other applications, such as automatic setup and calibration tools, -can make use of dynamic reconfiguration to correct for projector -alignment problems, as long as the projectors are still arranged -rectilinearly. Horizontal and vertical keystone correction could be -applied to projectors to correct for non-rectilinear alignment problems; -however, this must be done external to Xdmx. - -<p>A sample test program is included in the DMX server's examples -directory to demonstrate the interface and how an application might use -dynamic reconfiguration. See <tt/dmxreconfig.c/ for details. - -<sect3>Additional notes - -<p>In the original development plan, Phase IV was primarily devoted to -adding OpenGL support to DMX; however, SGI became interested in the DMX -project and developed code to support OpenGL/GLX. This code was later -donated to the DMX project and integrated into the DMX code base, which -freed the DMX developers to concentrate on dynamic reconfiguration (as -described above). - -<sect2>Doxygen documentation - -<p>Doxygen is an open-source (GPL) documentation system for generating -browseable documentation from stylized comments in the source code. We -have placed all of the Xdmx server and DMX protocol source code files -under Doxygen so that comprehensive documentation for the Xdmx source -code is available in an easily browseable format. - -<sect2>Valgrind - -<p>Valgrind, an open-source (GPL) memory debugger for Linux, was used to -search for memory management errors. Several memory leaks were detected -and repaired. The following errors were not addressed: -<enum> - <item> - When the X11 transport layer sends a reply to the client, only - those fields that are required by the protocol are filled in -- - unused fields are left as uninitialized memory and are therefore - noted by valgrind. These instances are not errors and were not - repaired. - <item> - At each server generation, glxInitVisuals allocates memory that - is never freed. The amount of memory lost each generation - approximately equal to 128 bytes for each back-end visual. - Because the code involved is automatically generated, this bug - has not been fixed and will be referred to SGI. - <item> - At each server generation, dmxRealizeFont calls XLoadQueryFont, - which allocates a font structure that is not freed. - dmxUnrealizeFont can free the font structure for the first - screen, but cannot free it for the other screens since they are - already closed by the time dmxUnrealizeFont could free them. - The amount of memory lost each generation is approximately equal - to 80 bytes per font per back-end. When this bug is fixed in - the the X server's device-independent (dix) code, DMX will be - able to properly free the memory allocated by XLoadQueryFont. -</enum> - -<sect2>RATS - -<p>RATS (Rough Auditing Tool for Security) is an open-source (GPL) -security analysis tool that scans source code for common -security-related programming errors (e.g., buffer overflows and TOCTOU -races). RATS was used to audit all of the code in the hw/dmx directory -and all "High" notations were checked manually. The code was either -re-written to eliminate the warning, or a comment containing "RATS" was -inserted on the line to indicate that a human had checked the code. -Unrepaired warnings are as follows: -<enum> - <item> - Fixed-size buffers are used in many areas, but code has been - added to protect against buffer overflows (e.g., XmuSnprint). - The only instances that have not yet been fixed are in - config/xdmxconfig.c (which is not part of the Xdmx server) and - input/usb-common.c. - <item> - vprintf and vfprintf are used in the logging routines. In - general, all uses of these functions (e.g., dmxLog) provide a - constant format string from a trusted source, so the use is - relatively benign. - <item> - glxProxy/glxscreens.c uses getenv and strcat. The use of these - functions is safe and will remain safe as long as - ExtensionsString is longer then GLXServerExtensions (ensuring - this may not be ovious to the casual programmer, but this is in - automatically generated code, so we hope that the generator - enforces this constraint). -</enum> - - </article> - - <!-- Local Variables: --> - <!-- fill-column: 72 --> - <!-- End: --> +<!DOCTYPE linuxdoc PUBLIC "-//XFree86//DTD linuxdoc//EN"> + <article> + + <!-- Title information --> + <title>Distributed Multihead X design + <author>Kevin E. Martin, David H. Dawes, and Rickard E. Faith + <date>29 June 2004 (created 25 July 2001) + <abstract> + This document covers the motivation, background, design, and + implementation of the distributed multihead X (DMX) system. It + is a living document and describes the current design and + implementation details of the DMX system. As the project + progresses, this document will be continually updated to reflect + the changes in the code and/or design. <it>Copyright 2001 by VA + Linux Systems, Inc., Fremont, California. Copyright 2001-2004 + by Red Hat, Inc., Raleigh, North Carolina</it> + </abstract> + + <!-- Table of contents --> + <toc> + +<!-- Begin the document --> +<sect>Introduction + +<sect1>The Distributed Multihead X Server + +<p>Current Open Source multihead solutions are limited to a single +physical machine. A single X server controls multiple display devices, +which can be arranged as independent heads or unified into a single +desktop (with Xinerama). These solutions are limited to the number of +physical devices that can co-exist in a single machine (e.g., due to the +number of AGP/PCI slots available for graphics cards). Thus, large +tiled displays are not currently possible. The work described in this +paper will eliminate the requirement that the display devices reside in +the same physical machine. This will be accomplished by developing a +front-end proxy X server that will control multiple back-end X servers +that make up the large display. + +<p>The overall structure of the distributed multihead X (DMX) project is +as follows: A single front-end X server will act as a proxy to a set of +back-end X servers, which handle all of the visible rendering. X +clients will connect to the front-end server just as they normally would +to a regular X server. The front-end server will present an abstracted +view to the client of a single large display. This will ensure that all +standard X clients will continue to operate without modification +(limited, as always, by the visuals and extensions provided by the X +server). Clients that are DMX-aware will be able to use an extension to +obtain information about the back-end servers (e.g., for placement of +pop-up windows, window alignments by the window manager, etc.). + +<p>The architecture of the DMX server is divided into two main sections: +input (e.g., mouse and keyboard events) and output (e.g., rendering and +windowing requests). Each of these are describe briefly below, and the +rest of this design document will describe them in greater detail. + +<p>The DMX server can receive input from three general types of input +devices: "local" devices that are physically attached to the machine on +which DMX is running, "backend" devices that are physically attached to +one or more of the back-end X servers (and that generate events via the +X protocol stream from the backend), and "console" devices that can be +abstracted from any non-back-end X server. Backend and console devices +are treated differently because the pointer device on the back-end X +server also controls the location of the hardware X cursor. Full +support for XInput extension devices is provided. + +<p>Rendering requests will be accepted by the front-end server; however, +rendering to visible windows will be broken down as needed and sent to +the appropriate back-end server(s) via X11 library calls for actual +rendering. The basic framework will follow a Xnest-style approach. GC +state will be managed in the front-end server and sent to the +appropriate back-end server(s) as required. Pixmap rendering will (at +least initially) be handled by the front-end X server. Windowing +requests (e.g., ordering, mapping, moving, etc.) will handled in the +front-end server. If the request requires a visible change, the +windowing operation will be translated into requests for the appropriate +back-end server(s). Window state will be mirrored in the back-end +server(s) as needed. + +<sect1>Layout of Paper + +<p>The next section describes the general development plan that was +actually used for implementation. The final section discusses +outstanding issues at the conclusion of development. The first appendix +provides low-level technical detail that may be of interest to those +intimately familiar with the X server architecture. The final appendix +describes the four phases of development that were performed during the +first two years of development. + +<p>The final year of work was divided into 9 tasks that are not +described in specific sections of this document. The major tasks during +that time were the enhancement of the reconfiguration ability added in +Phase IV, addition of support for a dynamic number of back-end displays +(instead of a hard-coded limit), and the support for back-end display +and input removal and addition. This work is mentioned in this paper, +but is not covered in detail. + +<!-- ============================================================ --> +<sect>Development plan + +<p>This section describes the development plan from approximately June +2001 through July 2003. + +<sect1>Bootstrap code + +<p>To allow for rapid development of the DMX server by multiple +developers during the first development stage, the problem will be +broken down into three tasks: the overall DMX framework, back-end +rendering services and input device handling services. However, before +the work begins on these tasks, a simple framework that each developer +could use was implemented to bootstrap the development effort. This +framework renders to a single back-end server and provides dummy input +devices (i.e., the keyboard and mouse). The simple back-end rendering +service was implemented using the shadow framebuffer support currently +available in the XFree86 environment. + +<p>Using this bootstrapping framework, each developer has been able to +work on each of the tasks listed above independently as follows: the +framework will be extended to handle arbitrary back-end server +configurations; the back-end rendering services will be transitioned to +the more efficient Xnest-style implementation; and, an input device +framework to handle various input devices via the input extension will +be developed. + +<p>Status: The boot strap code is complete. <!-- August 2001 --> + + +<sect1>Input device handling + +<p>An X server (including the front-end X server) requires two core +input devices -- a keyboard and a pointer (mouse). These core devices +are handled and required by the core X11 protocol. Additional types of +input devices may be attached and utilized via the XInput extension. +These are usually referred to as ``XInput extension devices'', + +<p>There are some options as to how the front-end X server gets its core +input devices: + +<enum> + <item>Local Input. The physical input devices (e.g., keyboard and + mouse) can be attached directly to the front-end X server. In this + case, the keyboard and mouse on the machine running the front-end X + server will be used. The front-end will have drivers to read the + raw input from those devices and convert it into the required X + input events (e.g., key press/release, pointer button press/release, + pointer motion). The front-end keyboard driver will keep track of + keyboard properties such as key and modifier mappings, autorepeat + state, keyboard sound and led state. Similarly the front-end + pointer driver will keep track if pointer properties such as the + button mapping and movement acceleration parameters. With this + option, input is handled fully in the front-end X server, and the + back-end X servers are used in a display-only mode. This option was + implemented and works for a limited number of Linux-specific + devices. Adding additional local input devices for other + architectures is expected to be relatively simple. + + <p>The following options are available for implementing local input + devices: + + <enum> + <item>The XFree86 X server has modular input drivers that could + be adapted for this purpose. The mouse driver supports a wide + range of mouse types and interfaces, as well as a range of + Operating System platforms. The keyboard driver in XFree86 is + not currently as modular as the mouse driver, but could be made + so. The XFree86 X server also has a range of other input + drivers for extended input devices such as tablets and touch + screens. Unfortunately, the XFree86 drivers are generally + complex, often simultaneously providing support for multiple + devices across multiple architectures; and rely so heavily on + XFree86-specific helper-functions, that this option was not + pursued. + + + <item>The <tt/kdrive/ X server in XFree86 has built-in drivers that + support PS/2 mice and keyboard under Linux. The mouse driver + can indirectly handle other mouse types if the Linux utility + <tt/gpm/ is used as to translate the native mouse protocol into + PS/2 mouse format. These drivers could be adapted and built in + to the front-end X server if this range of hardware and OS + support is sufficient. While much simpler than the XFree86 + drivers, the <tt/kdrive/ drivers were not used for the DMX + implementation. + + <item>Reimplementation of keyboard and mouse drivers from + scratch for the DMX framework. Because keyboard and mouse + drivers are relatively trivial to implement, this pathway was + selected. Other drivers in the X source tree were referenced, + and significant contributions from other drivers are noted in + the DMX source code. + </enum> + + <item>Backend Input. The front-end can make use of the core input + devices attached to one or more of the back-end X servers. Core + input events from multiple back-ends are merged into a single input + event stream. This can work sanely when only a single set of input + devices is used at any given time. The keyboard and pointer state + will be handled in the front-end, with changes propagated to the + back-end servers as needed. This option was implemented and works + well. Because the core pointer on a back-end controls the hardware + mouse on that back-end, core pointers cannot be treated as XInput + extension devices. However, all back-end XInput extensions devices + can be mapped to either DMX core or DMX XInput extension devices. + + <item>Console Input. The front-end server could create a console + window that is displayed on an X server independent of the back-end + X servers. This console window could display things like the + physical screen layout, and the front-end could get its core input + events from events delivered to the console window. This option was + implemented and works well. To help the human navigate, window + outlines are also displayed in the console window. Further, console + windows can be used as either core or XInput extension devices. + + <item>Other options were initially explored, but they were all + partial subsets of the options listed above and, hence, are + irrelevant. + +</enum> + +<p>Although extended input devices are not specifically mentioned in the +Distributed X requirements, the options above were all implemented so +that XInput extension devices were supported. + +<p>The bootstrap code (Xdmx) had dummy input devices, and these are +still supported in the final version. These do the necessary +initialization to satisfy the X server's requirements for core pointer +and keyboard devices, but no input events are ever generated. + +<p>Status: The input code is complete. Because of the complexity of the +XFree86 input device drivers (and their heavy reliance on XFree86 +infrastructure), separate low-level device drivers were implemented for +Xdmx. The following kinds of drivers are supported (in general, the +devices can be treated arbitrarily as "core" input devices or as XInput +"extension" devices; and multiple instances of different kinds of +devices can be simultaneously available): + <enum> + <item> A "dummy" device drive that never generates events. + + <item> "Local" input is from the low-level hardware on which the + Xdmx binary is running. This is the only area where using the + XFree86 driver infrastructure would have been helpful, and then + only partially, since good support for generic USB devices does + not yet exist in XFree86 (in any case, XFree86 and kdrive driver + code was used where possible). Currently, the following local + devices are supported under Linux (porting to other operating + systems should be fairly straightforward): + <itemize> + <item>Linux keyboard + <item>Linux serial mouse (MS) + <item>Linux PS/2 mouse + <item>USB keyboard + <item>USB mouse + <item>USB generic device (e.g., joystick, gamepad, etc.) + </itemize> + + <item> "Backend" input is taken from one or more of the back-end + displays. In this case, events are taken from the back-end X + server and are converted to Xdmx events. Care must be taken so + that the sprite moves properly on the display from which input + is being taken. + + <item> "Console" input is taken from an X window that Xdmx + creates on the operator's display (i.e., on the machine running + the Xdmx binary). When the operator's mouse is inside the + console window, then those events are converted to Xdmx events. + Several special features are available: the console can display + outlines of windows that are on the Xdmx display (to facilitate + navigation), the cursor can be confined to the console, and a + "fine" mode can be activated to allow very precise cursor + positioning. + </enum> + + +<!-- May 2002; July 2003 --> + +<sect1>Output device handling + +<p>The output of the DMX system displays rendering and windowing +requests across multiple screens. The screens are typically arranged in +a grid such that together they represent a single large display. + +<p>The output section of the DMX code consists of two parts. The first +is in the front-end proxy X server (Xdmx), which accepts client +connections, manages the windows, and potentially renders primitives but +does not actually display any of the drawing primitives. The second +part is the back-end X server(s), which accept commands from the +front-end server and display the results on their screens. + +<sect2>Initialization + +<p>The DMX front-end must first initialize its screens by connecting to +each of the back-end X servers and collecting information about each of +these screens. However, the information collected from the back-end X +servers might be inconsistent. Handling these cases can be difficult +and/or inefficient. For example, a two screen system has one back-end X +server running at 16bpp while the second is running at 32bpp. +Converting rendering requests (e.g., XPutImage() or XGetImage() +requests) to the appropriate bit depth can be very time consuming. +Analyzing these cases to determine how or even if it is possible to +handle them is required. The current Xinerama code handles many of +these cases (e.g., in PanoramiXConsolidate()) and will be used as a +starting point. In general, the best solution is to use homogeneous X +servers and display devices. Using back-end servers with the same depth +is a requirement of the final DMX implementation. + +<p>Once this screen consolidation is finished, the relative position of +each back-end X server's screen in the unified screen is initialized. A +full-screen window is opened on each of the back-end X servers, and the +cursor on each screen is turned off. The final DMX implementation can +also make use of a partial-screen window, or multiple windows per +back-end screen. + +<sect2>Handling rendering requests + +<p>After initialization, X applications connect to the front-end server. +There are two possible implementations of how rendering and windowing +requests are handled in the DMX system: + +<enum> + <item>A shadow framebuffer is used in the front-end server as the + render target. In this option, all protocol requests are completely + handled in the front-end server. All state and resources are + maintained in the front-end including a shadow copy of the entire + framebuffer. The framebuffers attached to the back-end servers are + updated by XPutImage() calls with data taken directly from the + shadow framebuffer. + + <p>This solution suffers from two main problems. First, it does not + take advantage of any accelerated hardware available in the system. + Second, the size of the XPutImage() calls can be quite large and + thus will be limited by the bandwidth available. + + <p>The initial DMX implementation used a shadow framebuffer by + default. + + <item>Rendering requests are sent to each back-end server for + handling (as is done in the Xnest server described above). In this + option, certain protocol requests are handled in the front-end + server and certain requests are repackaged and then sent to the + back-end servers. The framebuffer is distributed across the + multiple back-end servers. Rendering to the framebuffer is handled + on each back-end and can take advantage of any acceleration + available on the back-end servers' graphics display device. State + is maintained both in the front and back-end servers. + + <p>This solution suffers from two main drawbacks. First, protocol + requests are sent to all back-end servers -- even those that will + completely clip the rendering primitive -- which wastes bandwidth + and processing time. Second, state is maintained both in the front- + and back-end servers. These drawbacks are not as severe as in + option 1 (above) and can either be overcome through optimizations or + are acceptable. Therefore, this option will be used in the final + implementation. + + <p>The final DMX implementation defaults to this mechanism, but also + supports the shadow framebuffer mechanism. Several optimizations + were implemented to eliminate the drawbacks of the default + mechanism. These optimizations are described the section below and + in Phase II of the Development Results (see appendix). + +</enum> + +<p>Status: Both the shadow framebuffer and Xnest-style code is complete. +<!-- May 2002 --> + + +<sect1>Optimizing DMX + +<p>Initially, the Xnest-style solution's performance will be measured +and analyzed to determine where the performance bottlenecks exist. +There are four main areas that will be addressed. + +<p>First, to obtain reasonable interactivity with the first development +phase, XSync() was called after each protocol request. The XSync() +function flushes any pending protocol requests. It then waits for the +back-end to process the request and send a reply that the request has +completed. This happens with each back-end server and performance +greatly suffers. As a result of the way XSync() is called in the first +development phase, the batching that the X11 library performs is +effectively defeated. The XSync() call usage will be analyzed and +optimized by batching calls and performing them at regular intervals, +except where interactivity will suffer (e.g., on cursor movements). + +<p>Second, the initial Xnest-style solution described above sends the +repackaged protocol requests to all back-end servers regardless of +whether or not they would be completely clipped out. The requests that +are trivially rejected on the back-end server wastes the limited +bandwidth available. By tracking clipping changes in the DMX X server's +windowing code (e.g., by opening, closing, moving or resizing windows), +we can determine whether or not back-end windows are visible so that +trivial tests in the front-end server's GC ops drawing functions can +eliminate these unnecessary protocol requests. + +<p>Third, each protocol request will be analyzed to determine if it is +possible to break the request into smaller pieces at display boundaries. +The initial ones to be analyzed are put and get image requests since +they will require the greatest bandwidth to transmit data between the +front and back-end servers. Other protocol requests will be analyzed +and those that will benefit from breaking them into smaller requests +will be implemented. + +<p>Fourth, an extension is being considered that will allow font glyphs to +be transferred from the front-end DMX X server to each back-end server. +This extension will permit the front-end to handle all font requests and +eliminate the requirement that all back-end X servers share the exact +same fonts as the front-end server. We are investigating the +feasibility of this extension during this development phase. + +<p>Other potential optimizations will be determined from the performance +analysis. + +<p>Please note that in our initial design, we proposed optimizing BLT +operations (e.g., XCopyArea() and window moves) by developing an +extension that would allow individual back-end servers to directly copy +pixel data to other back-end servers. This potential optimization was +in response to the simple image movement implementation that required +potentially many calls to GetImage() and PutImage(). However, the +current Xinerama implementation handles these BLT operations +differently. Instead of copying data to and from screens, they generate +expose events -- just as happens in the case when a window is moved from +off a screen to on screen. This approach saves the limited bandwidth +available between front and back-end servers and is being standardized +with Xinerama. It also eliminates the potential setup problems and +security issues resulting from having each back-end server open +connections to all other back-end servers. Therefore, we suggest +accepting Xinerama's expose event solution. + +<p>Also note that the approach proposed in the second and third +optimizations might cause backing store algorithms in the back-end to be +defeated, so a DMX X server configuration flag will be added to disable +these optimizations. + +<p>Status: The optimizations proposed above are complete. It was +determined that the using the xfs font server was sufficient and +creating a new mechanism to pass glyphs was redundant; therefore, the +fourth optimization proposed above was not included in DMX. +<!-- September 2002 --> + + +<sect1>DMX X extension support + +<p>The DMX X server keeps track of all the windowing information on the +back-end X servers, but does not currently export this information to +any client applications. An extension will be developed to pass the +screen information and back-end window IDs to DMX-aware clients. These +clients can then use this information to directly connect to and render +to the back-end windows. Bypassing the DMX X server allows DMX-aware +clients to break up complex rendering requests on their own and send +them directly to the windows on the back-end server's screens. An +example of a client that can make effective use of this extension is +Chromium. + +<p>Status: The extension, as implemented, is fully documented in +"Client-to-Server DMX Extension to the X Protocol". Future changes +might be required based on feedback and other proposed enhancements to +DMX. Currently, the following facilities are supported: +<enum> + <item> + Screen information (clipping rectangle for each screen relative + to the virtual screen) + <item> + Window information (window IDs and clipping information for each + back-end window that corresponds to each DMX window) + <item> + Input device information (mappings from DMX device IDs to + back-end device IDs) + <item> + Force window creation (so that a client can override the + server-side lazy window creation optimization) + <item> + Reconfiguration (so that a client can request that a screen + position be changed) + <item> + Addition and removal of back-end servers and back-end and + console inputs. +</enum> +<!-- September 2002; July 2003 --> + + +<sect1>Common X extension support + +<p>The XInput, XKeyboard and Shape extensions are commonly used +extensions to the base X11 protocol. XInput allows multiple and +non-standard input devices to be accessed simultaneously. These input +devices can be connected to either the front-end or back-end servers. +XKeyboard allows much better keyboard mappings control. Shape adds +support for arbitrarily shaped windows and is used by various window +managers. Nearly all potential back-end X servers make these extensions +available, and support for each one will be added to the DMX system. + +<p>In addition to the extensions listed above, support for the X +Rendering extension (Render) is being developed. Render adds digital +image composition to the rendering model used by the X Window System. +While this extension is still under development by Keith Packard of HP, +support for the current version will be added to the DMX system. + +<p>Support for the XTest extension was added during the first +development phase. + +<!-- WARNING: this list is duplicated in the Phase IV discussion --> +<p>Status: The following extensions are supported and are discussed in +more detail in Phase IV of the Development Results (see appendix): + BIG-REQUESTS, + DEC-XTRAP, + DMX, + DPMS, + Extended-Visual-Information, + GLX, + LBX, + RECORD, + RENDER, + SECURITY, + SHAPE, + SYNC, + X-Resource, + XC-APPGROUP, + XC-MISC, + XFree86-Bigfont, + XINERAMA, + XInputExtension, + XKEYBOARD, and + XTEST. +<!-- November 2002; updated February 2003, July 2003 --> + +<sect1>OpenGL support + +<p>OpenGL support using the Mesa code base exists in XFree86 release 4 +and later. Currently, the direct rendering infrastructure (DRI) +provides accelerated OpenGL support for local clients and unaccelerated +OpenGL support (i.e., software rendering) is provided for non-local +clients. + +<p>The single head OpenGL support in XFree86 4.x will be extended to use +the DMX system. When the front and back-end servers are on the same +physical hardware, it is possible to use the DRI to directly render to +the back-end servers. First, the existing DRI will be extended to +support multiple display heads, and then to support the DMX system. +OpenGL rendering requests will be direct rendering to each back-end X +server. The DRI will request the screen layout (either from the +existing Xinerama extension or a DMX-specific extension). Support for +synchronized swap buffers will also be added (on hardware that supports +it). Note that a single front-end server with a single back-end server +on the same physical machine can emulate accelerated indirect rendering. + +<p>When the front and back-end servers are on different physical +hardware or are using non-XFree86 4.x X servers, a mechanism to render +primitives across the back-end servers will be provided. There are +several options as to how this can be implemented. + +<enum> + <item>The existing OpenGL support in each back-end server can be + used by repackaging rendering primitives and sending them to each + back-end server. This option is similar to the unoptimized + Xnest-style approach mentioned above. Optimization of this solution + is beyond the scope of this project and is better suited to other + distributed rendering systems. + + <item>Rendering to a pixmap in the front-end server using the + current XFree86 4.x code, and then displaying to the back-ends via + calls to XPutImage() is another option. This option is similar to + the shadow frame buffer approach mentioned above. It is slower and + bandwidth intensive, but has the advantage that the back-end servers + are not required to have OpenGL support. +</enum> + +<p>These, and other, options will be investigated in this phase of the +work. + +<p>Work by others have made Chromium DMX-aware. Chromium will use the +DMX X protocol extension to obtain information about the back-end +servers and will render directly to those servers, bypassing DMX. + +<p>Status: OpenGL support by the glxProxy extension was implemented by +SGI and has been integrated into the DMX code base. +<!-- May 2003--> + + +<!-- ============================================================ --> +<sect>Current issues + +<p>In this sections the current issues are outlined that require further +investigation. + +<sect1>Fonts + +<p>The font path and glyphs need to be the same for the front-end and +each of the back-end servers. Font glyphs could be sent to the back-end +servers as necessary but this would consume a significant amount of +available bandwidth during font rendering for clients that use many +different fonts (e.g., Netscape). Initially, the font server (xfs) will +be used to provide the fonts to both the front-end and back-end servers. +Other possibilities will be investigated during development. + +<sect1>Zero width rendering primitives + +<p>To allow pixmap and on-screen rendering to be pixel perfect, all +back-end servers must render zero width primitives exactly the same as +the front-end renders the primitives to pixmaps. For those back-end +servers that do not exactly match, zero width primitives will be +automatically converted to one width primitives. This can be handled in +the front-end server via the GC state. + +<sect1>Output scaling + +<p>With very large tiled displays, it might be difficult to read the +information on the standard X desktop. In particular, the cursor can be +easily lost and fonts could be difficult to read. Automatic primitive +scaling might prove to be very useful. We will investigate the +possibility of scaling the cursor and providing a set of alternate +pre-scaled fonts to replace the standard fonts that many applications +use (e.g., fixed). Other options for automatic scaling will also be +investigated. + +<sect1>Per-screen colormaps + +<p>Each screen's default colormap in the set of back-end X servers +should be able to be adjusted via a configuration utility. This support +is would allow the back-end screens to be calibrated via custom gamma +tables. On 24-bit systems that support a DirectColor visual, this type +of correction can be accommodated. One possible implementation would be +to advertise to X client of the DMX server a TrueColor visual while +using DirectColor visuals on the back-end servers to implement this type +of color correction. Other options will be investigated. + +<!-- ============================================================ --> +<appendix> + +<sect>Background + +<p>This section describes the existing Open Source architectures that +can be used to handle multiple screens and upon which this development +project is based. This section was written before the implementation +was finished, and may not reflect actual details of the implementation. +It is left for historical interest only. + +<sect1>Core input device handling + +<p>The following is a description of how core input devices are handled +by an X server. + +<sect2>InitInput() + +<p>InitInput() is a DDX function that is called at the start of each +server generation from the X server's main() function. Its purpose is +to determine what input devices are connected to the X server, register +them with the DIX and MI layers, and initialize the input event queue. +InitInput() does not have a return value, but the X server will abort if +either a core keyboard device or a core pointer device are not +registered. Extended input (XInput) devices can also be registered in +InitInput(). + +<p>InitInput() usually has implementation specific code to determine +which input devices are available. For each input device it will be +using, it calls AddInputDevice(): + +<descrip> +<tag/AddInputDevice()/ This DIX function allocates the device structure, +registers a callback function (which handles device init, close, on and +off), and returns the input handle, which can be treated as opaque. It +is called once for each input device. +</descrip> + +<p>Once input handles for core keyboard and core pointer devices have +been obtained from AddInputDevice(), they are registered as core devices +by calling RegisterPointerDevice() and RegisterKeyboardDevice(). Each +of these should be called once. If both core devices are not +registered, then the X server will exit with a fatal error when it +attempts to start the input devices in InitAndStartDevices(), which is +called directly after InitInput() (see below). + +<descrip> +<tag/Register{Pointer,Keyboard}Device()/ These DIX functions take a +handle returned from AddInputDevice() and initialize the core input +device fields in inputInfo, and initialize the input processing and grab +functions for each core input device. +</descrip> + +<p>The core pointer device is then registered with the miPointer code +(which does the high level cursor handling). While this registration +is not necessary for correct miPointer operation in the current XFree86 +code, it is still done mostly for compatibility reasons. + +<descrip> +<tag/miRegisterPointerDevice()/ This MI function registers the core +pointer's input handle with with the miPointer code. +</descrip> + +<p>The final part of InitInput() is the initialization of the input +event queue handling. In most cases, the event queue handling provided +in the MI layer is used. The primary XFree86 X server uses its own +event queue handling to support some special cases related to the XInput +extension and the XFree86-specific DGA extension. For our purposes, the +MI event queue handling should be suitable. It is initialized by +calling mieqInit(): + +<descrip> +<tag/mieqInit()/ This MI function initializes the MI event queue for the +core devices, and is passed the public component of the input handles +for the two core devices. +</descrip> + +<p>If a wakeup handler is required to deliver synchronous input +events, it can be registered here by calling the DIX function +RegisterBlockAndWakeupHandlers(). (See the devReadInput() description +below.) + +<sect2>InitAndStartDevices() + +<p>InitAndStartDevices() is a DIX function that is called immediately +after InitInput() from the X server's main() function. Its purpose is +to initialize each input device that was registered with +AddInputDevice(), enable each input device that was successfully +initialized, and create the list of enabled input devices. Once each +registered device is processed in this way, the list of enabled input +devices is checked to make sure that both a core keyboard device and +core pointer device were registered and successfully enabled. If not, +InitAndStartDevices() returns failure, and results in the the X server +exiting with a fatal error. + +<p>Each registered device is initialized by calling its callback +(dev->deviceProc) with the DEVICE_INIT argument: + +<descrip> +<tag/(*dev->deviceProc)(dev, DEVICE_INIT)/ This function initializes the +device structs with core information relevant to the device. + +<p>For pointer devices, this means specifying the number of buttons, +default button mapping, the function used to get motion events (usually +miPointerGetMotionEvents()), the function used to change/control the +core pointer motion parameters (acceleration and threshold), and the +motion buffer size. + +<p>For keyboard devices, this means specifying the keycode range, +default keycode to keysym mapping, default modifier mapping, and the +functions used to sound the keyboard bell and modify/control the +keyboard parameters (LEDs, bell pitch and duration, key click, which +keys are auto-repeating, etc). +</descrip> + +<p>Each initialized device is enabled by calling EnableDevice(): + +<descrip> +<tag/EnableDevice()/ EnableDevice() calls the device callback with +DEVICE_ON: + <descrip> + <tag/(*dev->deviceProc)(dev, DEVICE_ON)/ This typically opens and + initializes the relevant physical device, and when appropriate, + registers the device's file descriptor (or equivalent) as a valid + input source. + </descrip> + + <p>EnableDevice() then adds the device handle to the X server's + global list of enabled devices. +</descrip> + +<p>InitAndStartDevices() then verifies that a valid core keyboard and +pointer has been initialized and enabled. It returns failure if either +are missing. + +<sect2>devReadInput() + +<p>Each device will have some function that gets called to read its +physical input. These may be called in a number of different ways. In +the case of synchronous I/O, they will be called from a DDX +wakeup-handler that gets called after the server detects that new input is +available. In the case of asynchronous I/O, they will be called from a +(SIGIO) signal handler triggered when new input is available. This +function should do at least two things: make sure that input events get +enqueued, and make sure that the cursor gets moved for motion events +(except if these are handled later by the driver's own event queue +processing function, which cannot be done when using the MI event queue +handling). + +<p>Events are queued by calling mieqEnqueue(): + +<descrip> +<tag/mieqEnqueue()/ This MI function is used to add input events to the +event queue. It is simply passed the event to be queued. +</descrip> + +<p>The cursor position should be updated when motion events are +enqueued, by calling either miPointerAbsoluteCursor() or +miPointerDeltaCursor(): + +<descrip> +<tag/miPointerAbsoluteCursor()/ This MI function is used to move the +cursor to the absolute coordinates provided. +<tag/miPointerDeltaCursor()/ This MI function is used to move the cursor +relative to its current position. +</descrip> + +<sect2>ProcessInputEvents() + +<p>ProcessInputEvents() is a DDX function that is called from the X +server's main dispatch loop when new events are available in the input +event queue. It typically processes the enqueued events, and updates +the cursor/pointer position. It may also do other DDX-specific event +processing. + +<p>Enqueued events are processed by mieqProcessInputEvents() and passed +to the DIX layer for transmission to clients: + +<descrip> +<tag/mieqProcessInputEvents()/ This function processes each event in the +event queue, and passes it to the device's input processing function. +The DIX layer provides default functions to do this processing, and they +handle the task of getting the events passed back to the relevant +clients. +<tag/miPointerUpdate()/ This function resynchronized the cursor position +with the new pointer position. It also takes care of moving the cursor +between screens when needed in multi-head configurations. +</descrip> + + +<sect2>DisableDevice() + +<p>DisableDevice is a DIX function that removes an input device from the +list of enabled devices. The result of this is that the device no +longer generates input events. The device's data structures are kept in +place, and disabling a device like this can be reversed by calling +EnableDevice(). DisableDevice() may be called from the DDX when it is +desirable to do so (e.g., the XFree86 server does this when VT +switching). Except for special cases, this is not normally called for +core input devices. + +<p>DisableDevice() calls the device's callback function with +<tt/DEVICE_OFF/: + +<descrip> +<tag/(*dev->deviceProc)(dev, DEVICE_OFF)/ This typically closes the +relevant physical device, and when appropriate, unregisters the device's +file descriptor (or equivalent) as a valid input source. +</descrip> + +<p>DisableDevice() then removes the device handle from the X server's +global list of enabled devices. + + +<sect2>CloseDevice() + +<p>CloseDevice is a DIX function that removes an input device from the +list of available devices. It disables input from the device and frees +all data structures associated with the device. This function is +usually called from CloseDownDevices(), which is called from main() at +the end of each server generation to close all input devices. + +<p>CloseDevice() calls the device's callback function with +<tt/DEVICE_CLOSE/: + +<descrip> +<tag/(*dev->deviceProc)(dev, DEVICE_CLOSE)/ This typically closes the +relevant physical device, and when appropriate, unregisters the device's +file descriptor (or equivalent) as a valid input source. If any device +specific data structures were allocated when the device was initialized, +they are freed here. +</descrip> + +<p>CloseDevice() then frees the data structures that were allocated +for the device when it was registered/initialized. + + +<sect2>LegalModifier() +<!-- dmx/dmxinput.c - currently returns TRUE --> +<p>LegalModifier() is a required DDX function that can be used to +restrict which keys may be modifier keys. This seems to be present for +historical reasons, so this function should simply return TRUE +unconditionally. + + +<sect1>Output handling + +<p>The following sections describe the main functions required to +initialize, use and close the output device(s) for each screen in the X +server. + +<sect2>InitOutput() + +<p>This DDX function is called near the start of each server generation +from the X server's main() function. InitOutput()'s main purpose is to +initialize each screen and fill in the global screenInfo structure for +each screen. It is passed three arguments: a pointer to the screenInfo +struct, which it is to initialize, and argc and argv from main(), which +can be used to determine additional configuration information. + +<p>The primary tasks for this function are outlined below: + +<enum> + <item><bf/Parse configuration info:/ The first task of InitOutput() + is to parses any configuration information from the configuration + file. In addition to the XF86Config file, other configuration + information can be taken from the command line. The command line + options can be gathered either in InitOutput() or earlier in the + ddxProcessArgument() function, which is called by + ProcessCommandLine(). The configuration information determines the + characteristics of the screen(s). For example, in the XFree86 X + server, the XF86Config file specifies the monitor information, the + screen resolution, the graphics devices and slots in which they are + located, and, for Xinerama, the screens' layout. + + <item><bf/Initialize screen info:/ The next task is to initialize + the screen-dependent internal data structures. For example, part of + what the XFree86 X server does is to allocate its screen and pixmap + private indices, probe for graphics devices, compare the probed + devices to the ones listed in the XF86Config file, and add the ones that + match to the internal xf86Screens[] structure. + + <item><bf/Set pixmap formats:/ The next task is to initialize the + screenInfo's image byte order, bitmap bit order and bitmap scanline + unit/pad. The screenInfo's pixmap format's depth, bits per pixel + and scanline padding is also initialized at this stage. + + <item><bf/Unify screen info:/ An optional task that might be done at + this stage is to compare all of the information from the various + screens and determines if they are compatible (i.e., if the set of + screens can be unified into a single desktop). This task has + potential to be useful to the DMX front-end server, if Xinerama's + PanoramiXConsolidate() function is not sufficient. +</enum> + +<p>Once these tasks are complete, the valid screens are known and each +of these screens can be initialized by calling AddScreen(). + +<sect2>AddScreen() + +<p>This DIX function is called from InitOutput(), in the DDX layer, to +add each new screen to the screenInfo structure. The DDX screen +initialization function and command line arguments (i.e., argc and argv) +are passed to it as arguments. + +<p>This function first allocates a new Screen structure and any privates +that are required. It then initializes some of the fields in the Screen +struct and sets up the pixmap padding information. Finally, it calls +the DDX screen initialization function ScreenInit(), which is described +below. It returns the number of the screen that were just added, or -1 +if there is insufficient memory to add the screen or if the DDX screen +initialization fails. + +<sect2>ScreenInit() + +<p>This DDX function initializes the rest of the Screen structure with +either generic or screen-specific functions (as necessary). It also +fills in various screen attributes (e.g., width and height in +millimeters, black and white pixel values). + +<p>The screen init function usually calls several functions to perform +certain screen initialization functions. They are described below: + +<descrip> +<tag/{mi,*fb}ScreenInit()/ The DDX layer's ScreenInit() function usually +calls another layer's ScreenInit() function (e.g., miScreenInit() or +fbScreenInit()) to initialize the fallbacks that the DDX driver does not +specifically handle. + +<p>After calling another layer's ScreenInit() function, any +screen-specific functions either wrap or replace the other layer's +function pointers. If a function is to be wrapped, each of the old +function pointers from the other layer are stored in a screen private +area. Common functions to wrap are CloseScreen() and SaveScreen(). + +<tag/miInitializeBackingStore()/ This MI function initializes the +screen's backing storage functions, which are used to save areas of +windows that are currently covered by other windows. + +<tag/miDCInitialize()/ This MI function initializes the MI cursor +display structures and function pointers. If a hardware cursor is used, +the DDX layer's ScreenInit() function will wrap additional screen and +the MI cursor display function pointers. +</descrip> + +<p>Another common task for ScreenInit() function is to initialize the +output device state. For example, in the XFree86 X server, the +ScreenInit() function saves the original state of the video card and +then initializes the video mode of the graphics device. + +<sect2>CloseScreen() + +<p>This function restores any wrapped screen functions (and in +particular the wrapped CloseScreen() function) and restores the state of +the output device to its original state. It should also free any +private data it created during the screen initialization. + +<sect2>GC operations + +<p>When the X server is requested to render drawing primitives, it does +so by calling drawing functions through the graphics context's operation +function pointer table (i.e., the GCOps functions). These functions +render the basic graphics operations such as drawing rectangles, lines, +text or copying pixmaps. Default routines are provided either by the MI +layer, which draws indirectly through a simple span interface, or by the +framebuffer layers (e.g., CFB, MFB, FB), which draw directly to a +linearly mapped frame buffer. + +<p>To take advantage of special hardware on the graphics device, +specific GCOps functions can be replaced by device specific code. +However, many times the graphics devices can handle only a subset of the +possible states of the GC, so during graphics context validation, +appropriate routines are selected based on the state and capabilities of +the hardware. For example, some graphics hardware can accelerate single +pixel width lines with certain dash patterns. Thus, for dash patterns +that are not supported by hardware or for width 2 or greater lines, the +default routine is chosen during GC validation. + +<p>Note that some pointers to functions that draw to the screen are +stored in the Screen structure. They include GetImage(), GetSpans(), +CopyWindow() and RestoreAreas(). + +<sect2>Xnest + +<p>The Xnest X server is a special proxy X server that relays the X +protocol requests that it receives to a ``real'' X server that then +processes the requests and displays the results, if applicable. To the X +applications, Xnest appears as if it is a regular X server. However, +Xnest is both server to the X application and client of the real X +server, which will actually handle the requests. + +<p>The Xnest server implements all of the standard input and output +initialization steps outlined above. + +<descrip> +<tag/InitOutput()/ Xnest takes its configuration information from +command line arguments via ddxProcessArguments(). This information +includes the real X server display to connect to, its default visual +class, the screen depth, the Xnest window's geometry, etc. Xnest then +connects to the real X server and gathers visual, colormap, depth and +pixmap information about that server's display, creates a window on that +server, which will be used as the root window for Xnest. + +<p>Next, Xnest initializes its internal data structures and uses the +data from the real X server's pixmaps to initialize its own pixmap +formats. Finally, it calls AddScreen(xnestOpenScreen, argc, argv) to +initialize each of its screens. + +<tag/ScreenInit()/ Xnest's ScreenInit() function is called +xnestOpenScreen(). This function initializes its screen's depth and +visual information, and then calls miScreenInit() to set up the default +screen functions. It then calls miInitializeBackingStore() and +miDCInitialize() to initialize backing store and the software cursor. +Finally, it replaces many of the screen functions with its own +functions that repackage and send the requests to the real X server to +which Xnest is attached. + +<tag/CloseScreen()/ This function frees its internal data structure +allocations. Since it replaces instead of wrapping screen functions, +there are no function pointers to unwrap. This can potentially lead to +problems during server regeneration. + +<tag/GC operations/ The GC operations in Xnest are very simple since +they leave all of the drawing to the real X server to which Xnest is +attached. Each of the GCOps takes the request and sends it to the +real X server using standard Xlib calls. For example, the X +application issues a XDrawLines() call. This function turns into a +protocol request to Xnest, which calls the xnestPolylines() function +through Xnest's GCOps function pointer table. The xnestPolylines() +function is only a single line, which calls XDrawLines() using the same +arguments that were passed into it. Other GCOps functions are very +similar. Two exceptions to the simple GCOps functions described above +are the image functions and the BLT operations. + +<p>The image functions, GetImage() and PutImage(), must use a temporary +image to hold the image to be put of the image that was just grabbed +from the screen while it is in transit to the real X server or the +client. When the image has been transmitted, the temporary image is +destroyed. + +<p>The BLT operations, CopyArea() and CopyPlane(), handle not only the +copy function, which is the same as the simple cases described above, +but also the graphics exposures that result when the GC's graphics +exposure bit is set to True. Graphics exposures are handled in a helper +function, xnestBitBlitHelper(). This function collects the exposure +events from the real X server and, if any resulting in regions being +exposed, then those regions are passed back to the MI layer so that it +can generate exposure events for the X application. +</descrip> + +<p>The Xnest server takes its input from the X server to which it is +connected. When the mouse is in the Xnest server's window, keyboard and +mouse events are received by the Xnest server, repackaged and sent back +to any client that requests those events. + +<sect2>Shadow framebuffer + +<p>The most common type of framebuffer is a linear array memory that +maps to the video memory on the graphics device. However, accessing +that video memory over an I/O bus (e.g., ISA or PCI) can be slow. The +shadow framebuffer layer allows the developer to keep the entire +framebuffer in main memory and copy it back to video memory at regular +intervals. It also has been extended to handle planar video memory and +rotated framebuffers. + +<p>There are two main entry points to the shadow framebuffer code: + +<descrip> +<tag/shadowAlloc(width, height, bpp)/ This function allocates the in +memory copy of the framebuffer of size width*height*bpp. It returns a +pointer to that memory, which will be used by the framebuffer +ScreenInit() code during the screen's initialization. + +<tag/shadowInit(pScreen, updateProc, windowProc)/ This function +initializes the shadow framebuffer layer. It wraps several screen +drawing functions, and registers a block handler that will update the +screen. The updateProc is a function that will copy the damaged regions +to the screen, and the windowProc is a function that is used when the +entire linear video memory range cannot be accessed simultaneously so +that only a window into that memory is available (e.g., when using the +VGA aperture). +</descrip> + +<p>The shadow framebuffer code keeps track of the damaged area of each +screen by calculating the bounding box of all drawing operations that +have occurred since the last screen update. Then, when the block handler +is next called, only the damaged portion of the screen is updated. + +<p>Note that since the shadow framebuffer is kept in main memory, all +drawing operations are performed by the CPU and, thus, no accelerated +hardware drawing operations are possible. + + +<sect1>Xinerama + +<p>Xinerama is an X extension that allows multiple physical screens +controlled by a single X server to appear as a single screen. Although +the extension allows clients to find the physical screen layout via +extension requests, it is completely transparent to clients at the core +X11 protocol level. The original public implementation of Xinerama came +from Digital/Compaq. XFree86 rewrote it, filling in some missing pieces +and improving both X11 core protocol compliance and performance. The +Xinerama extension will be passing through X.Org's standardization +process in the near future, and the sample implementation will be based +on this rewritten version. + +<p>The current implementation of Xinerama is based primarily in the DIX +(device independent) and MI (machine independent) layers of the X +server. With few exceptions the DDX layers do not need any changes to +support Xinerama. X server extensions often do need modifications to +provide full Xinerama functionality. + +<p>The following is a code-level description of how Xinerama functions. + +<p>Note: Because the Xinerama extension was originally called the +PanoramiX extension, many of the Xinerama functions still have the +PanoramiX prefix. + +<descrip> + <tag/PanoramiXExtensionInit()/ PanoramiXExtensionInit() is a + device-independent extension function that is called at the start of + each server generation from InitExtensions(), which is called from + the X server's main() function after all output devices have been + initialized, but before any input devices have been initialized. + + <p>PanoramiXNumScreens is set to the number of physical screens. If + only one physical screen is present, the extension is disabled, and + PanoramiXExtensionInit() returns without doing anything else. + + <p>The Xinerama extension is registered by calling AddExtension(). + + <p>A local per-screen array of data structures + (panoramiXdataPtr[]) + is allocated for each physical screen, and GC and Screen private + indexes are allocated, and both GC and Screen private areas are + allocated for each physical screen. These hold Xinerama-specific + per-GC and per-Screen data. Each screen's CreateGC and CloseScreen + functions are wrapped by XineramaCreateGC() and + XineramaCloseScreen() respectively. Some new resource classes are + created for Xinerama drawables and GCs, and resource types for + Xinerama windows, pixmaps and colormaps. + + <p>A region (XineramaScreenRegions[i]) is initialized for each + physical screen, and single region (PanoramiXScreenRegion) is + initialized to be the union of the screen regions. The + panoramiXdataPtr[] array is also initialized with the size and + origin of each screen. The relative positioning information for the + physical screens is taken from the array + dixScreenOrigins[], which + the DDX layer must initialize in InitOutput(). The bounds of the + combined screen is also calculated (PanoramiXPixWidth and + PanoramiXPixHeight). + + <p>The DIX layer has a list of function pointers + (ProcVector[]) that + holds the entry points for the functions that process core protocol + requests. The requests that Xinerama must intercept and break up + into physical screen-specific requests are wrapped. The original + set is copied to SavedProcVector[]. The types of requests + intercepted are Window requests, GC requests, colormap requests, + drawing requests, and some geometry-related requests. This wrapping + allows the bulk of the protocol request processing to be handled + transparently to the DIX layer. Some operations cannot be dealt with + in this way and are handled with Xinerama-specific code within the + DIX layer. + + <tag/PanoramiXConsolidate()/ PanoramiXConsolidate() is a + device-independent extension function that is called directly from + the X server's main() function after extensions and input/output + devices have been initialized, and before the root windows are + defined and initialized. + + <p>This function finds the set of depths (PanoramiXDepths[]) and + visuals (PanoramiXVisuals[]) + common to all of the physical screens. + PanoramiXNumDepths is set to the number of common depths, and + PanoramiXNumVisuals is set to the number of common visuals. + Resources are created for the single root window and the default + colormap. Each of these resources has per-physical screen entries. + + <tag/PanoramiXCreateConnectionBlock()/ PanoramiXConsolidate() is a + device-independent extension function that is called directly from + the X server's main() function after the per-physical screen root + windows are created. It is called instead of the standard DIX + CreateConnectionBlock() function. If this function returns FALSE, + the X server exits with a fatal error. This function will return + FALSE if no common depths were found in PanoramiXConsolidate(). + With no common depths, Xinerama mode is not possible. + + <p>The connection block holds the information that clients get when + they open a connection to the X server. It includes information + such as the supported pixmap formats, number of screens and the + sizes, depths, visuals, default colormap information, etc, for each + of the screens (much of information that <tt/xdpyinfo/ shows). The + connection block is initialized with the combined single screen + values that were calculated in the above two functions. + + <p>The Xinerama extension allows the registration of connection + block callback functions. The purpose of these is to allow other + extensions to do processing at this point. These callbacks can be + registered by calling XineramaRegisterConnectionBlockCallback() from + the other extension's ExtensionInit() function. Each registered + connection block callback is called at the end of + PanoramiXCreateConnectionBlock(). +</descrip> + +<sect2>Xinerama-specific changes to the DIX code + +<p>There are a few types of Xinerama-specific changes within the DIX +code. The main ones are described here. + +<p>Functions that deal with colormap or GC -related operations outside of +the intercepted protocol requests have a test added to only do the +processing for screen numbers > 0. This is because they are handled for +the single Xinerama screen and the processing is done once for screen 0. + +<p>The handling of motion events does some coordinate translation between +the physical screen's origin and screen zero's origin. Also, motion +events must be reported relative to the composite screen origin rather +than the physical screen origins. + +<p>There is some special handling for cursor, window and event processing +that cannot (either not at all or not conveniently) be done via the +intercepted protocol requests. A particular case is the handling of +pointers moving between physical screens. + +<sect2>Xinerama-specific changes to the MI code + +<p>The only Xinerama-specific change to the MI code is in miSendExposures() +to handle the coordinate (and window ID) translation for expose events. + +<sect2>Intercepted DIX core requests + +<p>Xinerama breaks up drawing requests for dispatch to each physical +screen. It also breaks up windows into pieces for each physical screen. +GCs are translated into per-screen GCs. Colormaps are replicated on +each physical screen. The functions handling the intercepted requests +take care of breaking the requests and repackaging them so that they can +be passed to the standard request handling functions for each screen in +turn. In addition, and to aid the repackaging, the information from +many of the intercepted requests is used to keep up to date the +necessary state information for the single composite screen. Requests +(usually those with replies) that can be satisfied completely from this +stored state information do not call the standard request handling +functions. + +<!-- ============================================================ --> + +<sect>Development Results + +<p>In this section the results of each phase of development are +discussed. This development took place between approximately June 2001 +and July 2003. + +<sect1>Phase I + +<p>The initial development phase dealt with the basic implementation +including the bootstrap code, which used the shadow framebuffer, and the +unoptimized implementation, based on an Xnest-style implementation. + +<sect2>Scope + +<p>The goal of Phase I is to provide fundamental functionality that can +act as a foundation for ongoing work: +<enum> + <item>Develop the proxy X server + <itemize> + <item>The proxy X server will operate on the X11 protocol and + relay requests as necessary to correctly perform the request. + <item>Work will be based on the existing work for Xinerama and + Xnest. + <item>Input events and windowing operations are handled in the + proxy server and rendering requests are repackaged and sent to + each of the back-end servers for display. + <item>The multiple screen layout (including support for + overlapping screens) will be user configurable via a + configuration file or through the configuration tool. + </itemize> + <item>Develop graphical configuration tool + <itemize> + <item>There will be potentially a large number of X servers to + configure into a single display. The tool will allow the user + to specify which servers are involved in the configuration and + how they should be laid out. + </itemize> + <item>Pass the X Test Suite + <itemize> + <item>The X Test Suite covers the basic X11 operations. All + tests known to succeed must correctly operate in the distributed + X environment. + </itemize> +</enum> + +<p>For this phase, the back-end X servers are assumed to be unmodified X +servers that do not support any DMX-related protocol extensions; future +optimization pathways are considered, but are not implemented; and the +configuration tool is assumed to rely only on libraries in the X source +tree (e.g., Xt). + +<sect2>Results + +<p>The proxy X server, Xdmx, was developed to distribute X11 protocol +requests to the set of back-end X servers. It opens a window on each +back-end server, which represents the part of the front-end's root +window that is visible on that screen. It mirrors window, pixmap and +other state in each back-end server. Drawing requests are sent to +either windows or pixmaps on each back-end server. This code is based +on Xnest and uses the existing Xinerama extension. + +<p>Input events can be taken from (1) devices attached to the back-end +server, (2) core devices attached directly to the Xdmx server, or (3) +from a ``console'' window on another X server. Events for these devices +are gathered, processed and delivered to clients attached to the Xdmx +server. + +<p>An intuitive configuration format was developed to help the user +easily configure the multiple back-end X servers. It was defined (see +grammar in Xdmx man page) and a parser was implemented that is used by +the Xdmx server and by a standalone xdmxconfig utility. The parsing +support was implemented such that it can be easily factored out of the X +source tree for use with other tools (e.g., vdl). Support for +converting legacy vdl-format configuration files to the DMX format is +provided by the vdltodmx utility. + +<p>Originally, the configuration file was going to be a subsection of +XFree86's XF86Config file, but that was not possible since Xdmx is a +completely separate X server. Thus, a separate config file format was +developed. In addition, a graphical configuration +tool, xdmxconfig, was developed to allow the user to create and arrange +the screens in the configuration file. The <bf/-configfile/ and <bf/-config/ +command-line options can be used to start Xdmx using a configuration +file. + +<p>An extension that enables remote input testing is required for the X +Test Suite to function. During this phase, this extension (XTEST) was +implemented in the Xdmx server. The results from running the X Test +Suite are described in detail below. + +<sect2>X Test Suite + + <sect3> Introduction + <p> + The X Test Suite contains tests that verify Xlib functions + operate correctly. The test suite is designed to run on a + single X server; however, since X applications will not be + able to tell the difference between the DMX server and a + standard X server, the X Test Suite should also run on the + DMX server. + <p> + The Xdmx server was tested with the X Test Suite, and the + existing failures are noted in this section. To put these + results in perspective, we first discuss expected X Test + failures and how errors in underlying systems can impact + Xdmx test results. + + <sect3>Expected Failures for a Single Head + <p> + A correctly implemented X server with a single screen is + expected to fail certain X Test tests. The following + well-known errors occur because of rounding error in the X + server code: + <verb> +XDrawArc: Tests 42, 63, 66, 73 +XDrawArcs: Tests 45, 66, 69, 76 + </verb> + <p> + The following failures occur because of the high-level X + server implementation: + <verb> +XLoadQueryFont: Test 1 +XListFontsWithInfo: Tests 3, 4 +XQueryFont: Tests 1, 2 + </verb> + <p> + The following test fails when running the X server as root + under Linux because of the way directory modes are + interpreted: + <verb> +XWriteBitmapFile: Test 3 + </verb> + <p> + Depending on the video card used for the back-end, other + failures may also occur because of bugs in the low-level + driver implementation. Over time, failures of this kind + are usually fixed by XFree86, but will show up in Xdmx + testing until then. + + <sect3>Expected Failures for Xinerama + <p> + Xinerama fails several X Test Suite tests because of + design decisions made for the current implementation of + Xinerama. Over time, many of these errors will be + corrected by XFree86 and the group working on a new + Xinerama implementation. Therefore, Xdmx will also share + X Suite Test failures with Xinerama. + <p> + We may be able to fix or work-around some of these + failures at the Xdmx level, but this will require + additional exploration that was not part of Phase I. + <p> + Xinerama is constantly improving, and the list of + Xinerama-related failures depends on XFree86 version and + the underlying graphics hardware. We tested with a + variety of hardware, including nVidia, S3, ATI Radeon, + and Matrox G400 (in dual-head mode). The list below + includes only those failures that appear to be from the + Xinerama layer, and does not include failures listed in + the previous section, or failures that appear to be from + the low-level graphics driver itself: + <p> + These failures were noted with multiple Xinerama + configurations: + <verb> +XCopyPlane: Tests 13, 22, 31 (well-known Xinerama implementation issue) +XSetFontPath: Test 4 +XGetDefault: Test 5 +XMatchVisualInfo: Test 1 + </verb> + <p> + These failures were noted only when using one dual-head + video card with a 4.2.99.x XFree86 server: + <verb> +XListPixmapFormats: Test 1 +XDrawRectangles: Test 45 + </verb> + <p> + These failures were noted only when using two video cards + from different vendors with a 4.1.99.x XFree86 server: + <verb> +XChangeWindowAttributes: Test 32 +XCreateWindow: Test 30 +XDrawLine: Test 22 +XFillArc: Test 22 +XChangeKeyboardControl: Tests 9, 10 +XRebindKeysym: Test 1 + </verb> + + <sect3>Additional Failures from Xdmx + <p> + When running Xdmx, no unexpected failures were noted. + Since the Xdmx server is based on Xinerama, we expect to + have most of the Xinerama failures present in the Xdmx + server. Similarly, since the Xdmx server must rely on the + low-level device drivers on each back-end server, we also + expect that Xdmx will exhibit most of the back-end + failures. Here is a summary: + <verb> +XListPixmapFormats: Test 1 (configuration dependent) +XChangeWindowAttributes: Test 32 +XCreateWindow: Test 30 +XCopyPlane: Test 13, 22, 31 +XSetFontPath: Test 4 +XGetDefault: Test 5 (configuration dependent) +XMatchVisualInfo: Test 1 +XRebindKeysym: Test 1 (configuration dependent) + </verb> + <p> + Note that this list is shorter than the combined list for + Xinerama because Xdmx uses different code paths to perform + some Xinerama operations. Further, some Xinerama failures + have been fixed in the XFree86 4.2.99.x CVS repository. + + <sect3>Summary and Future Work + <p> + Running the X Test Suite on Xdmx does not produce any + failures that cannot be accounted for by the underlying + Xinerama subsystem used by the front-end or by the + low-level device-driver code running on the back-end X + servers. The Xdmx server therefore is as ``correct'' as + possible with respect to the standard set of X Test Suite + tests. + <p> + During the following phases, we will continue to verify + Xdmx correctness using the X Test Suite. We may also use + other tests suites or write additional tests that run + under the X Test Suite that specifically verify the + expected behavior of DMX. + +<sect2>Fonts + +<p>In Phase I, fonts are handled directly by both the front-end and the +back-end servers, which is required since we must treat each back-end +server during this phase as a ``black box''. What this requires is that +<bf/the front- and back-end servers must share the exact same font +path/. There are two ways to help make sure that all servers share the +same font path: + +<enum> + <item>First, each server can be configured to use the same font + server. The font server, xfs, can be configured to serve fonts to + multiple X servers via TCP. + + <item>Second, each server can be configured to use the same font + path and either those font paths can be copied to each back-end + machine or they can be mounted (e.g., via NFS) on each back-end + machine. +</enum> + +<p>One additional concern is that a client program can set its own font +path, and if it does so, then that font path must be available on each +back-end machine. + +<p>The -fontpath command line option was added to allow users to +initialize the font path of the front end server. This font path is +propagated to each back-end server when the default font is loaded. If +there are any problems, an error message is printed, which will describe +the problem and list the current font path. For more information about +setting the font path, see the -fontpath option description in the man +page. + +<sect2>Performance + +<p>Phase I of development was not intended to optimize performance. Its +focus was on completely and correctly handling the base X11 protocol in +the Xdmx server. However, several insights were gained during Phase I, +which are listed here for reference during the next phase of +development. + +<enum> + <item>Calls to XSync() can slow down rendering since it requires a + complete round trip to and from a back-end server. This is + especially problematic when communicating over long haul networks. + <item>Sending drawing requests to only the screens that they overlap + should improve performance. +</enum> + +<sect2>Pixmaps + +<p>Pixmaps were originally expected to be handled entirely in the +front-end X server; however, it was found that this overly complicated +the rendering code and would have required sending potentially large +images to each back server that required them when copying from pixmap +to screen. Thus, pixmap state is mirrored in the back-end server just +as it is with regular window state. With this implementation, the same +rendering code that draws to windows can be used to draw to pixmaps on +the back-end server, and no large image transfers are required to copy +from pixmap to window. + +<!-- ============================================================ --> +<sect1>Phase II + +<p>The second phase of development concentrates on performance +optimizations. These optimizations are documented here, with +<tt/x11perf/ data to show how the optimizations improve performance. + +<p>All benchmarks were performed by running Xdmx on a dual processor +1.4GHz AMD Athlon machine with 1GB of RAM connecting over 100baseT to +two single-processor 1GHz Pentium III machines with 256MB of RAM and ATI +Rage 128 (RF) video cards. The front end was running Linux +2.4.20-pre1-ac1 and the back ends were running Linux 2.4.7-10 and +version 4.2.99.1 of XFree86 pulled from the XFree86 CVS repository on +August 7, 2002. All systems were running Red Hat Linux 7.2. + +<sect2>Moving from XFree86 4.1.99.1 to 4.2.0.0 + +<p>For phase II, the working source tree was moved to the branch tagged +with dmx-1-0-branch and was updated from version 4.1.99.1 (20 August +2001) of the XFree86 sources to version 4.2.0.0 (18 January 2002). +After this update, the following tests were noted to be more than 10% +faster: + <verb> +1.13 Fill 300x300 opaque stippled trapezoid (161x145 stipple) +1.16 Fill 1x1 tiled trapezoid (161x145 tile) +1.13 Fill 10x10 tiled trapezoid (161x145 tile) +1.17 Fill 100x100 tiled trapezoid (161x145 tile) +1.16 Fill 1x1 tiled trapezoid (216x208 tile) +1.20 Fill 10x10 tiled trapezoid (216x208 tile) +1.15 Fill 100x100 tiled trapezoid (216x208 tile) +1.37 Circulate Unmapped window (200 kids) + </verb> +And the following tests were noted to be more than 10% slower: + <verb> +0.88 Unmap window via parent (25 kids) +0.75 Circulate Unmapped window (4 kids) +0.79 Circulate Unmapped window (16 kids) +0.80 Circulate Unmapped window (25 kids) +0.82 Circulate Unmapped window (50 kids) +0.85 Circulate Unmapped window (75 kids) + </verb> +<p>These changes were not caused by any changes in the DMX system, and +may point to changes in the XFree86 tree or to tests that have more +"jitter" than most other <tt/x11perf/ tests. + +<sect2>Global changes + +<p>During the development of the Phase II DMX server, several global +changes were made. These changes were also compared with the Phase I +server. The following tests were noted to be more than 10% faster: + <verb> +1.13 Fill 300x300 opaque stippled trapezoid (161x145 stipple) +1.15 Fill 1x1 tiled trapezoid (161x145 tile) +1.13 Fill 10x10 tiled trapezoid (161x145 tile) +1.17 Fill 100x100 tiled trapezoid (161x145 tile) +1.16 Fill 1x1 tiled trapezoid (216x208 tile) +1.19 Fill 10x10 tiled trapezoid (216x208 tile) +1.15 Fill 100x100 tiled trapezoid (216x208 tile) +1.15 Circulate Unmapped window (4 kids) + </verb> + +<p>The following tests were noted to be more than 10% slower: + <verb> +0.69 Scroll 10x10 pixels +0.68 Scroll 100x100 pixels +0.68 Copy 10x10 from window to window +0.68 Copy 100x100 from window to window +0.76 Circulate Unmapped window (75 kids) +0.83 Circulate Unmapped window (100 kids) + </verb> + +<p>For the remainder of this analysis, the baseline of comparison will +be the Phase II deliverable with all optimizations disabled (unless +otherwise noted). This will highlight how the optimizations in +isolation impact performance. + +<sect2>XSync() Batching + +<p>During the Phase I implementation, XSync() was called after every +protocol request made by the DMX server. This provided the DMX server +with an interactive feel, but defeated X11's protocol buffering system +and introduced round-trip wire latency into every operation. During +Phase II, DMX was changed so that protocol requests are no longer +followed by calls to XSync(). Instead, the need for an XSync() is +noted, and XSync() calls are only made every 100mS or when the DMX +server specifically needs to make a call to guarantee interactivity. +With this new system, X11 buffers protocol as much as possible during a +100mS interval, and many unnecessary XSync() calls are avoided. + +<p>Out of more than 300 <tt/x11perf/ tests, 8 tests became more than 100 +times faster, with 68 more than 50X faster, 114 more than 10X faster, +and 181 more than 2X faster. See table below for summary. + +<p>The following tests were noted to be more than 10% slower with +XSync() batching on: + <verb> +0.88 500x500 tiled rectangle (161x145 tile) +0.89 Copy 500x500 from window to window + </verb> + +<sect2>Offscreen Optimization + +<p>Windows span one or more of the back-end servers' screens; however, +during Phase I development, windows were created on every back-end +server and every rendering request was sent to every window regardless +of whether or not that window was visible. With the offscreen +optimization, the DMX server tracks when a window is completely off of a +back-end server's screen and, in that case, it does not send rendering +requests to those back-end windows. This optimization saves bandwidth +between the front and back-end servers, and it reduces the number of +XSync() calls. The performance tests were run on a DMX system with only +two back-end servers. Greater performance gains will be had as the +number of back-end servers increases. + +<p>Out of more than 300 <tt/x11perf/ tests, 3 tests were at least twice as +fast, and 146 tests were at least 10% faster. Two tests were more than +10% slower with the offscreen optimization: + <verb> +0.88 Hide/expose window via popup (4 kids) +0.89 Resize unmapped window (75 kids) + </verb> + +<sect2>Lazy Window Creation Optimization + +<p>As mentioned above, during Phase I, windows were created on every +back-end server even if they were not visible on that back-end. With +the lazy window creation optimization, the DMX server does not create +windows on a back-end server until they are either visible or they +become the parents of a visible window. This optimization builds on the +offscreen optimization (described above) and requires it to be enabled. + +<p>The lazy window creation optimization works by creating the window +data structures in the front-end server when a client creates a window, +but delays creation of the window on the back-end server(s). A private +window structure in the DMX server saves the relevant window data and +tracks changes to the window's attributes and stacking order for later +use. The only times a window is created on a back-end server are (1) +when it is mapped and is at least partially overlapping the back-end +server's screen (tracked by the offscreen optimization), or (2) when the +window becomes the parent of a previously visible window. The first +case occurs when a window is mapped or when a visible window is copied, +moved or resized and now overlaps the back-end server's screen. The +second case occurs when starting a window manager after having created +windows to which the window manager needs to add decorations. + +<p>When either case occurs, a window on the back-end server is created +using the data saved in the DMX server's window private data structure. +The stacking order is then adjusted to correctly place the window on the +back-end and lastly the window is mapped. From this time forward, the +window is handled exactly as if the window had been created at the time +of the client's request. + +<p>Note that when a window is no longer visible on a back-end server's +screen (e.g., it is moved offscreen), the window is not destroyed; +rather, it is kept and reused later if the window once again becomes +visible on the back-end server's screen. Originally with this +optimization, destroying windows was implemented but was later rejected +because it increased bandwidth when windows were opaquely moved or +resized, which is common in many window managers. + +<p>The performance tests were run on a DMX system with only two back-end +servers. Greater performance gains will be had as the number of +back-end servers increases. + +<p>This optimization improved the following <tt/x11perf/ tests by more +than 10%: + <verb> +1.10 500x500 rectangle outline +1.12 Fill 100x100 stippled trapezoid (161x145 stipple) +1.20 Circulate Unmapped window (50 kids) +1.19 Circulate Unmapped window (75 kids) + </verb> + +<sect2>Subdividing Rendering Primitives + +<p>X11 imaging requests transfer significant data between the client and +the X server. During Phase I, the DMX server would then transfer the +image data to each back-end server. Even with the offscreen +optimization (above), these requests still required transferring +significant data to each back-end server that contained a visible +portion of the window. For example, if the client uses XPutImage() to +copy an image to a window that overlaps the entire DMX screen, then the +entire image is copied by the DMX server to every back-end server. + +<p>To reduce the amount of data transferred between the DMX server and +the back-end servers when XPutImage() is called, the image data is +subdivided and only the data that will be visible on a back-end server's +screen is sent to that back-end server. Xinerama already implements a +subdivision algorithm for XGetImage() and no further optimization was +needed. + +<p>Other rendering primitives were analyzed, but the time required to +subdivide these primitives was a significant proportion of the time +required to send the entire rendering request to the back-end server, so +this optimization was rejected for the other rendering primitives. + +<p>Again, the performance tests were run on a DMX system with only two +back-end servers. Greater performance gains will be had as the number +of back-end servers increases. + +<p>This optimization improved the following <tt/x11perf/ tests by more +than 10%: + <verb> +1.12 Fill 100x100 stippled trapezoid (161x145 stipple) +1.26 PutImage 10x10 square +1.83 PutImage 100x100 square +1.91 PutImage 500x500 square +1.40 PutImage XY 10x10 square +1.48 PutImage XY 100x100 square +1.50 PutImage XY 500x500 square +1.45 Circulate Unmapped window (75 kids) +1.74 Circulate Unmapped window (100 kids) + </verb> + +<p>The following test was noted to be more than 10% slower with this +optimization: + <verb> +0.88 10-pixel fill chord partial circle + </verb> + +<sect2>Summary of x11perf Data + +<p>With all of the optimizations on, 53 <tt/x11perf/ tests are more than +100X faster than the unoptimized Phase II deliverable, with 69 more than +50X faster, 73 more than 10X faster, and 199 more than twice as fast. +No tests were more than 10% slower than the unoptimized Phase II +deliverable. (Compared with the Phase I deliverable, only Circulate +Unmapped window (100 kids) was more than 10% slower than the Phase II +deliverable. As noted above, this test seems to have wider variability +than other <tt/x11perf/ tests.) + +<p>The following table summarizes relative <tt/x11perf/ test changes for +all optimizations individually and collectively. Note that some of the +optimizations have a synergistic effect when used together. + <verb> + +1: XSync() batching only +2: Off screen optimizations only +3: Window optimizations only +4: Subdivprims only +5: All optimizations + + 1 2 3 4 5 Operation +------ ---- ---- ---- ------ --------- + 2.14 1.85 1.00 1.00 4.13 Dot + 1.67 1.80 1.00 1.00 3.31 1x1 rectangle + 2.38 1.43 1.00 1.00 2.44 10x10 rectangle + 1.00 1.00 0.92 0.98 1.00 100x100 rectangle + 1.00 1.00 1.00 1.00 1.00 500x500 rectangle + 1.83 1.85 1.05 1.06 3.54 1x1 stippled rectangle (8x8 stipple) + 2.43 1.43 1.00 1.00 2.41 10x10 stippled rectangle (8x8 stipple) + 0.98 1.00 1.00 1.00 1.00 100x100 stippled rectangle (8x8 stipple) + 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (8x8 stipple) + 1.75 1.75 1.00 1.00 3.40 1x1 opaque stippled rectangle (8x8 stipple) + 2.38 1.42 1.00 1.00 2.34 10x10 opaque stippled rectangle (8x8 stipple) + 1.00 1.00 0.97 0.97 1.00 100x100 opaque stippled rectangle (8x8 stipple) + 1.00 1.00 1.00 1.00 0.99 500x500 opaque stippled rectangle (8x8 stipple) + 1.82 1.82 1.04 1.04 3.56 1x1 tiled rectangle (4x4 tile) + 2.33 1.42 1.00 1.00 2.37 10x10 tiled rectangle (4x4 tile) + 1.00 0.92 1.00 1.00 1.00 100x100 tiled rectangle (4x4 tile) + 1.00 1.00 1.00 1.00 1.00 500x500 tiled rectangle (4x4 tile) + 1.94 1.62 1.00 1.00 3.66 1x1 stippled rectangle (17x15 stipple) + 1.74 1.28 1.00 1.00 1.73 10x10 stippled rectangle (17x15 stipple) + 1.00 1.00 1.00 0.89 0.98 100x100 stippled rectangle (17x15 stipple) + 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (17x15 stipple) + 1.94 1.62 1.00 1.00 3.67 1x1 opaque stippled rectangle (17x15 stipple) + 1.69 1.26 1.00 1.00 1.66 10x10 opaque stippled rectangle (17x15 stipple) + 1.00 0.95 1.00 1.00 1.00 100x100 opaque stippled rectangle (17x15 stipple) + 1.00 1.00 1.00 1.00 0.97 500x500 opaque stippled rectangle (17x15 stipple) + 1.93 1.61 0.99 0.99 3.69 1x1 tiled rectangle (17x15 tile) + 1.73 1.27 1.00 1.00 1.72 10x10 tiled rectangle (17x15 tile) + 1.00 1.00 1.00 1.00 0.98 100x100 tiled rectangle (17x15 tile) + 1.00 1.00 0.97 0.97 1.00 500x500 tiled rectangle (17x15 tile) + 1.95 1.63 1.00 1.00 3.83 1x1 stippled rectangle (161x145 stipple) + 1.80 1.30 1.00 1.00 1.83 10x10 stippled rectangle (161x145 stipple) + 0.97 1.00 1.00 1.00 1.01 100x100 stippled rectangle (161x145 stipple) + 1.00 1.00 1.00 1.00 0.98 500x500 stippled rectangle (161x145 stipple) + 1.95 1.63 1.00 1.00 3.56 1x1 opaque stippled rectangle (161x145 stipple) + 1.65 1.25 1.00 1.00 1.68 10x10 opaque stippled rectangle (161x145 stipple) + 1.00 1.00 1.00 1.00 1.01 100x100 opaque stippled rectangle (161x145... + 1.00 1.00 1.00 1.00 0.97 500x500 opaque stippled rectangle (161x145... + 1.95 1.63 0.98 0.99 3.80 1x1 tiled rectangle (161x145 tile) + 1.67 1.26 1.00 1.00 1.67 10x10 tiled rectangle (161x145 tile) + 1.13 1.14 1.14 1.14 1.14 100x100 tiled rectangle (161x145 tile) + 0.88 1.00 1.00 1.00 0.99 500x500 tiled rectangle (161x145 tile) + 1.93 1.63 1.00 1.00 3.53 1x1 tiled rectangle (216x208 tile) + 1.69 1.26 1.00 1.00 1.66 10x10 tiled rectangle (216x208 tile) + 1.00 1.00 1.00 1.00 1.00 100x100 tiled rectangle (216x208 tile) + 1.00 1.00 1.00 1.00 1.00 500x500 tiled rectangle (216x208 tile) + 1.82 1.70 1.00 1.00 3.38 1-pixel line segment + 2.07 1.56 0.90 1.00 3.31 10-pixel line segment + 1.29 1.10 1.00 1.00 1.27 100-pixel line segment + 1.05 1.06 1.03 1.03 1.09 500-pixel line segment + 1.30 1.13 1.00 1.00 1.29 100-pixel line segment (1 kid) + 1.32 1.15 1.00 1.00 1.32 100-pixel line segment (2 kids) + 1.33 1.16 1.00 1.00 1.33 100-pixel line segment (3 kids) + 1.92 1.64 1.00 1.00 3.73 10-pixel dashed segment + 1.34 1.16 1.00 1.00 1.34 100-pixel dashed segment + 1.24 1.11 0.99 0.97 1.23 100-pixel double-dashed segment + 1.72 1.77 1.00 1.00 3.25 10-pixel horizontal line segment + 1.83 1.66 1.01 1.00 3.54 100-pixel horizontal line segment + 1.86 1.30 1.00 1.00 1.84 500-pixel horizontal line segment + 2.11 1.52 1.00 0.99 3.02 10-pixel vertical line segment + 1.21 1.10 1.00 1.00 1.20 100-pixel vertical line segment + 1.03 1.03 1.00 1.00 1.02 500-pixel vertical line segment + 4.42 1.68 1.00 1.01 4.64 10x1 wide horizontal line segment + 1.83 1.31 1.00 1.00 1.83 100x10 wide horizontal line segment + 1.07 1.00 0.96 1.00 1.07 500x50 wide horizontal line segment + 4.10 1.67 1.00 1.00 4.62 10x1 wide vertical line segment + 1.50 1.24 1.06 1.06 1.48 100x10 wide vertical line segment + 1.06 1.03 1.00 1.00 1.05 500x50 wide vertical line segment + 2.54 1.61 1.00 1.00 3.61 1-pixel line + 2.71 1.48 1.00 1.00 2.67 10-pixel line + 1.19 1.09 1.00 1.00 1.19 100-pixel line + 1.04 1.02 1.00 1.00 1.03 500-pixel line + 2.68 1.51 0.98 1.00 3.17 10-pixel dashed line + 1.23 1.11 0.99 0.99 1.23 100-pixel dashed line + 1.15 1.08 1.00 1.00 1.15 100-pixel double-dashed line + 2.27 1.39 1.00 1.00 2.23 10x1 wide line + 1.20 1.09 1.00 1.00 1.20 100x10 wide line + 1.04 1.02 1.00 1.00 1.04 500x50 wide line + 1.52 1.45 1.00 1.00 1.52 100x10 wide dashed line + 1.54 1.47 1.00 1.00 1.54 100x10 wide double-dashed line + 1.97 1.30 0.96 0.95 1.95 10x10 rectangle outline + 1.44 1.27 1.00 1.00 1.43 100x100 rectangle outline + 3.22 2.16 1.10 1.09 3.61 500x500 rectangle outline + 1.95 1.34 1.00 1.00 1.90 10x10 wide rectangle outline + 1.14 1.14 1.00 1.00 1.13 100x100 wide rectangle outline + 1.00 1.00 1.00 1.00 1.00 500x500 wide rectangle outline + 1.57 1.72 1.00 1.00 3.03 1-pixel circle + 1.96 1.35 1.00 1.00 1.92 10-pixel circle + 1.21 1.07 0.86 0.97 1.20 100-pixel circle + 1.08 1.04 1.00 1.00 1.08 500-pixel circle + 1.39 1.19 1.03 1.03 1.38 100-pixel dashed circle + 1.21 1.11 1.00 1.00 1.23 100-pixel double-dashed circle + 1.59 1.28 1.00 1.00 1.58 10-pixel wide circle + 1.22 1.12 0.99 1.00 1.22 100-pixel wide circle + 1.06 1.04 1.00 1.00 1.05 500-pixel wide circle + 1.87 1.84 1.00 1.00 1.85 100-pixel wide dashed circle + 1.90 1.93 1.01 1.01 1.90 100-pixel wide double-dashed circle + 2.13 1.43 1.00 1.00 2.32 10-pixel partial circle + 1.42 1.18 1.00 1.00 1.42 100-pixel partial circle + 1.92 1.85 1.01 1.01 1.89 10-pixel wide partial circle + 1.73 1.67 1.00 1.00 1.73 100-pixel wide partial circle + 1.36 1.95 1.00 1.00 2.64 1-pixel solid circle + 2.02 1.37 1.00 1.00 2.03 10-pixel solid circle + 1.19 1.09 1.00 1.00 1.19 100-pixel solid circle + 1.02 0.99 1.00 1.00 1.01 500-pixel solid circle + 1.74 1.28 1.00 0.88 1.73 10-pixel fill chord partial circle + 1.31 1.13 1.00 1.00 1.31 100-pixel fill chord partial circle + 1.67 1.31 1.03 1.03 1.72 10-pixel fill slice partial circle + 1.30 1.13 1.00 1.00 1.28 100-pixel fill slice partial circle + 2.45 1.49 1.01 1.00 2.71 10-pixel ellipse + 1.22 1.10 1.00 1.00 1.22 100-pixel ellipse + 1.09 1.04 1.00 1.00 1.09 500-pixel ellipse + 1.90 1.28 1.00 1.00 1.89 100-pixel dashed ellipse + 1.62 1.24 0.96 0.97 1.61 100-pixel double-dashed ellipse + 2.43 1.50 1.00 1.00 2.42 10-pixel wide ellipse + 1.61 1.28 1.03 1.03 1.60 100-pixel wide ellipse + 1.08 1.05 1.00 1.00 1.08 500-pixel wide ellipse + 1.93 1.88 1.00 1.00 1.88 100-pixel wide dashed ellipse + 1.94 1.89 1.01 1.00 1.94 100-pixel wide double-dashed ellipse + 2.31 1.48 1.00 1.00 2.67 10-pixel partial ellipse + 1.38 1.17 1.00 1.00 1.38 100-pixel partial ellipse + 2.00 1.85 0.98 0.97 1.98 10-pixel wide partial ellipse + 1.89 1.86 1.00 1.00 1.89 100-pixel wide partial ellipse + 3.49 1.60 1.00 1.00 3.65 10-pixel filled ellipse + 1.67 1.26 1.00 1.00 1.67 100-pixel filled ellipse + 1.06 1.04 1.00 1.00 1.06 500-pixel filled ellipse + 2.38 1.43 1.01 1.00 2.32 10-pixel fill chord partial ellipse + 2.06 1.30 1.00 1.00 2.05 100-pixel fill chord partial ellipse + 2.27 1.41 1.00 1.00 2.27 10-pixel fill slice partial ellipse + 1.98 1.33 1.00 0.97 1.97 100-pixel fill slice partial ellipse + 57.46 1.99 1.01 1.00 114.92 Fill 1x1 equivalent triangle + 56.94 1.98 1.01 1.00 73.89 Fill 10x10 equivalent triangle + 6.07 1.75 1.00 1.00 6.07 Fill 100x100 equivalent triangle + 51.12 1.98 1.00 1.00 102.81 Fill 1x1 trapezoid + 51.42 1.82 1.01 1.00 94.89 Fill 10x10 trapezoid + 6.47 1.80 1.00 1.00 6.44 Fill 100x100 trapezoid + 1.56 1.28 1.00 0.99 1.56 Fill 300x300 trapezoid + 51.27 1.97 0.96 0.97 102.54 Fill 1x1 stippled trapezoid (8x8 stipple) + 51.73 2.00 1.02 1.02 67.92 Fill 10x10 stippled trapezoid (8x8 stipple) + 5.36 1.72 1.00 1.00 5.36 Fill 100x100 stippled trapezoid (8x8 stipple) + 1.54 1.26 1.00 1.00 1.59 Fill 300x300 stippled trapezoid (8x8 stipple) + 51.41 1.94 1.01 1.00 102.82 Fill 1x1 opaque stippled trapezoid (8x8 stipple) + 50.71 1.95 0.99 1.00 65.44 Fill 10x10 opaque stippled trapezoid (8x8... + 5.33 1.73 1.00 1.00 5.36 Fill 100x100 opaque stippled trapezoid (8x8... + 1.58 1.25 1.00 1.00 1.58 Fill 300x300 opaque stippled trapezoid (8x8... + 51.56 1.96 0.99 0.90 103.68 Fill 1x1 tiled trapezoid (4x4 tile) + 51.59 1.99 1.01 1.01 62.25 Fill 10x10 tiled trapezoid (4x4 tile) + 5.38 1.72 1.00 1.00 5.38 Fill 100x100 tiled trapezoid (4x4 tile) + 1.54 1.25 1.00 0.99 1.58 Fill 300x300 tiled trapezoid (4x4 tile) + 51.70 1.98 1.01 1.01 103.98 Fill 1x1 stippled trapezoid (17x15 stipple) + 44.86 1.97 1.00 1.00 44.86 Fill 10x10 stippled trapezoid (17x15 stipple) + 2.74 1.56 1.00 1.00 2.73 Fill 100x100 stippled trapezoid (17x15 stipple) + 1.29 1.14 1.00 1.00 1.27 Fill 300x300 stippled trapezoid (17x15 stipple) + 51.41 1.96 0.96 0.95 103.39 Fill 1x1 opaque stippled trapezoid (17x15... + 45.14 1.96 1.01 1.00 45.14 Fill 10x10 opaque stippled trapezoid (17x15... + 2.68 1.56 1.00 1.00 2.68 Fill 100x100 opaque stippled trapezoid (17x15... + 1.26 1.10 1.00 1.00 1.28 Fill 300x300 opaque stippled trapezoid (17x15... + 51.13 1.97 1.00 0.99 103.39 Fill 1x1 tiled trapezoid (17x15 tile) + 47.58 1.96 1.00 1.00 47.86 Fill 10x10 tiled trapezoid (17x15 tile) + 2.74 1.56 1.00 1.00 2.74 Fill 100x100 tiled trapezoid (17x15 tile) + 1.29 1.14 1.00 1.00 1.28 Fill 300x300 tiled trapezoid (17x15 tile) + 51.13 1.97 0.99 0.97 103.39 Fill 1x1 stippled trapezoid (161x145 stipple) + 45.14 1.97 1.00 1.00 44.29 Fill 10x10 stippled trapezoid (161x145 stipple) + 3.02 1.77 1.12 1.12 3.38 Fill 100x100 stippled trapezoid (161x145 stipple) + 1.31 1.13 1.00 1.00 1.30 Fill 300x300 stippled trapezoid (161x145 stipple) + 51.27 1.97 1.00 1.00 103.10 Fill 1x1 opaque stippled trapezoid (161x145... + 45.01 1.97 1.00 1.00 45.01 Fill 10x10 opaque stippled trapezoid (161x145... + 2.67 1.56 1.00 1.00 2.69 Fill 100x100 opaque stippled trapezoid (161x145.. + 1.29 1.13 1.00 1.01 1.27 Fill 300x300 opaque stippled trapezoid (161x145.. + 51.41 1.96 1.00 0.99 103.39 Fill 1x1 tiled trapezoid (161x145 tile) + 45.01 1.96 0.98 1.00 45.01 Fill 10x10 tiled trapezoid (161x145 tile) + 2.62 1.36 1.00 1.00 2.69 Fill 100x100 tiled trapezoid (161x145 tile) + 1.27 1.13 1.00 1.00 1.22 Fill 300x300 tiled trapezoid (161x145 tile) + 51.13 1.98 1.00 1.00 103.39 Fill 1x1 tiled trapezoid (216x208 tile) + 45.14 1.97 1.01 0.99 45.14 Fill 10x10 tiled trapezoid (216x208 tile) + 2.62 1.55 1.00 1.00 2.71 Fill 100x100 tiled trapezoid (216x208 tile) + 1.28 1.13 1.00 1.00 1.20 Fill 300x300 tiled trapezoid (216x208 tile) + 50.71 1.95 1.00 1.00 54.70 Fill 10x10 equivalent complex polygon + 5.51 1.71 0.96 0.98 5.47 Fill 100x100 equivalent complex polygons + 8.39 1.97 1.00 1.00 16.75 Fill 10x10 64-gon (Convex) + 8.38 1.83 1.00 1.00 8.43 Fill 100x100 64-gon (Convex) + 8.50 1.96 1.00 1.00 16.64 Fill 10x10 64-gon (Complex) + 8.26 1.83 1.00 1.00 8.35 Fill 100x100 64-gon (Complex) + 14.09 1.87 1.00 1.00 14.05 Char in 80-char line (6x13) + 11.91 1.87 1.00 1.00 11.95 Char in 70-char line (8x13) + 11.16 1.85 1.01 1.00 11.10 Char in 60-char line (9x15) + 10.09 1.78 1.00 1.00 10.09 Char16 in 40-char line (k14) + 6.15 1.75 1.00 1.00 6.31 Char16 in 23-char line (k24) + 11.92 1.90 1.03 1.03 11.88 Char in 80-char line (TR 10) + 8.18 1.78 1.00 0.99 8.17 Char in 30-char line (TR 24) + 42.83 1.44 1.01 1.00 42.11 Char in 20/40/20 line (6x13, TR 10) + 27.45 1.43 1.01 1.01 27.45 Char16 in 7/14/7 line (k14, k24) + 12.13 1.85 1.00 1.00 12.05 Char in 80-char image line (6x13) + 10.00 1.84 1.00 1.00 10.00 Char in 70-char image line (8x13) + 9.18 1.83 1.00 1.00 9.12 Char in 60-char image line (9x15) + 9.66 1.82 0.98 0.95 9.66 Char16 in 40-char image line (k14) + 5.82 1.72 1.00 1.00 5.99 Char16 in 23-char image line (k24) + 8.70 1.80 1.00 1.00 8.65 Char in 80-char image line (TR 10) + 4.67 1.66 1.00 1.00 4.67 Char in 30-char image line (TR 24) + 84.43 1.47 1.00 1.00 124.18 Scroll 10x10 pixels + 3.73 1.50 1.00 0.98 3.73 Scroll 100x100 pixels + 1.00 1.00 1.00 1.00 1.00 Scroll 500x500 pixels + 84.43 1.51 1.00 1.00 134.02 Copy 10x10 from window to window + 3.62 1.51 0.98 0.98 3.62 Copy 100x100 from window to window + 0.89 1.00 1.00 1.00 1.00 Copy 500x500 from window to window + 57.06 1.99 1.00 1.00 88.64 Copy 10x10 from pixmap to window + 2.49 2.00 1.00 1.00 2.48 Copy 100x100 from pixmap to window + 1.00 0.91 1.00 1.00 0.98 Copy 500x500 from pixmap to window + 2.04 1.01 1.00 1.00 2.03 Copy 10x10 from window to pixmap + 1.05 1.00 1.00 1.00 1.05 Copy 100x100 from window to pixmap + 1.00 1.00 0.93 1.00 1.04 Copy 500x500 from window to pixmap + 58.52 1.03 1.03 1.02 57.95 Copy 10x10 from pixmap to pixmap + 2.40 1.00 1.00 1.00 2.45 Copy 100x100 from pixmap to pixmap + 1.00 1.00 1.00 1.00 1.00 Copy 500x500 from pixmap to pixmap + 51.57 1.92 1.00 1.00 85.75 Copy 10x10 1-bit deep plane + 6.37 1.75 1.01 1.01 6.37 Copy 100x100 1-bit deep plane + 1.26 1.11 1.00 1.00 1.24 Copy 500x500 1-bit deep plane + 4.23 1.63 0.98 0.97 4.38 Copy 10x10 n-bit deep plane + 1.04 1.02 1.00 1.00 1.04 Copy 100x100 n-bit deep plane + 1.00 1.00 1.00 1.00 1.00 Copy 500x500 n-bit deep plane + 6.45 1.98 1.00 1.26 12.80 PutImage 10x10 square + 1.10 1.87 1.00 1.83 2.11 PutImage 100x100 square + 1.02 1.93 1.00 1.91 1.91 PutImage 500x500 square + 4.17 1.78 1.00 1.40 7.18 PutImage XY 10x10 square + 1.27 1.49 0.97 1.48 2.10 PutImage XY 100x100 square + 1.00 1.50 1.00 1.50 1.52 PutImage XY 500x500 square + 1.07 1.01 1.00 1.00 1.06 GetImage 10x10 square + 1.01 1.00 1.00 1.00 1.01 GetImage 100x100 square + 1.00 1.00 1.00 1.00 1.00 GetImage 500x500 square + 1.56 1.00 0.99 0.97 1.56 GetImage XY 10x10 square + 1.02 1.00 1.00 1.00 1.02 GetImage XY 100x100 square + 1.00 1.00 1.00 1.00 1.00 GetImage XY 500x500 square + 1.00 1.00 1.01 0.98 0.95 X protocol NoOperation + 1.02 1.03 1.04 1.03 1.00 QueryPointer + 1.03 1.02 1.04 1.03 1.00 GetProperty +100.41 1.51 1.00 1.00 198.76 Change graphics context + 45.81 1.00 0.99 0.97 57.10 Create and map subwindows (4 kids) + 78.45 1.01 1.02 1.02 63.07 Create and map subwindows (16 kids) + 73.91 1.01 1.00 1.00 56.37 Create and map subwindows (25 kids) + 73.22 1.00 1.00 1.00 49.07 Create and map subwindows (50 kids) + 72.36 1.01 0.99 1.00 32.14 Create and map subwindows (75 kids) + 70.34 1.00 1.00 1.00 30.12 Create and map subwindows (100 kids) + 55.00 1.00 1.00 0.99 23.75 Create and map subwindows (200 kids) + 55.30 1.01 1.00 1.00 141.03 Create unmapped window (4 kids) + 55.38 1.01 1.01 1.00 163.25 Create unmapped window (16 kids) + 54.75 0.96 1.00 0.99 166.95 Create unmapped window (25 kids) + 54.83 1.00 1.00 0.99 178.81 Create unmapped window (50 kids) + 55.38 1.01 1.01 1.00 181.20 Create unmapped window (75 kids) + 55.38 1.01 1.01 1.00 181.20 Create unmapped window (100 kids) + 54.87 1.01 1.01 1.00 182.05 Create unmapped window (200 kids) + 28.13 1.00 1.00 1.00 30.75 Map window via parent (4 kids) + 36.14 1.01 1.01 1.01 32.58 Map window via parent (16 kids) + 26.13 1.00 0.98 0.95 29.85 Map window via parent (25 kids) + 40.07 1.00 1.01 1.00 27.57 Map window via parent (50 kids) + 23.26 0.99 1.00 1.00 18.23 Map window via parent (75 kids) + 22.91 0.99 1.00 0.99 16.52 Map window via parent (100 kids) + 27.79 1.00 1.00 0.99 12.50 Map window via parent (200 kids) + 22.35 1.00 1.00 1.00 56.19 Unmap window via parent (4 kids) + 9.57 1.00 0.99 1.00 89.78 Unmap window via parent (16 kids) + 80.77 1.01 1.00 1.00 103.85 Unmap window via parent (25 kids) + 96.34 1.00 1.00 1.00 116.06 Unmap window via parent (50 kids) + 99.72 1.00 1.00 1.00 124.93 Unmap window via parent (75 kids) +112.36 1.00 1.00 1.00 125.27 Unmap window via parent (100 kids) +105.41 1.00 1.00 0.99 120.00 Unmap window via parent (200 kids) + 51.29 1.03 1.02 1.02 74.19 Destroy window via parent (4 kids) + 86.75 0.99 0.99 0.99 116.87 Destroy window via parent (16 kids) +106.43 1.01 1.01 1.01 127.49 Destroy window via parent (25 kids) +120.34 1.01 1.01 1.00 140.11 Destroy window via parent (50 kids) +126.67 1.00 0.99 0.99 145.00 Destroy window via parent (75 kids) +126.11 1.01 1.01 1.00 140.56 Destroy window via parent (100 kids) +128.57 1.01 1.00 1.00 137.91 Destroy window via parent (200 kids) + 16.04 0.88 1.00 1.00 20.36 Hide/expose window via popup (4 kids) + 19.04 1.01 1.00 1.00 23.48 Hide/expose window via popup (16 kids) + 19.22 1.00 1.00 1.00 20.44 Hide/expose window via popup (25 kids) + 17.41 1.00 0.91 0.97 17.68 Hide/expose window via popup (50 kids) + 17.29 1.01 1.00 1.01 17.07 Hide/expose window via popup (75 kids) + 16.74 1.00 1.00 1.00 16.17 Hide/expose window via popup (100 kids) + 10.30 1.00 1.00 1.00 10.51 Hide/expose window via popup (200 kids) + 16.48 1.01 1.00 1.00 26.05 Move window (4 kids) + 17.01 0.95 1.00 1.00 23.97 Move window (16 kids) + 16.95 1.00 1.00 1.00 22.90 Move window (25 kids) + 16.05 1.01 1.00 1.00 21.32 Move window (50 kids) + 15.58 1.00 0.98 0.98 19.44 Move window (75 kids) + 14.98 1.02 1.03 1.03 18.17 Move window (100 kids) + 10.90 1.01 1.01 1.00 12.68 Move window (200 kids) + 49.42 1.00 1.00 1.00 198.27 Moved unmapped window (4 kids) + 50.72 0.97 1.00 1.00 193.66 Moved unmapped window (16 kids) + 50.87 1.00 0.99 1.00 195.09 Moved unmapped window (25 kids) + 50.72 1.00 1.00 1.00 189.34 Moved unmapped window (50 kids) + 50.87 1.00 1.00 1.00 191.33 Moved unmapped window (75 kids) + 50.87 1.00 1.00 0.90 186.71 Moved unmapped window (100 kids) + 50.87 1.00 1.00 1.00 179.19 Moved unmapped window (200 kids) + 41.04 1.00 1.00 1.00 56.61 Move window via parent (4 kids) + 69.81 1.00 1.00 1.00 130.82 Move window via parent (16 kids) + 95.81 1.00 1.00 1.00 141.92 Move window via parent (25 kids) + 95.98 1.00 1.00 1.00 149.43 Move window via parent (50 kids) + 96.59 1.01 1.01 1.00 153.98 Move window via parent (75 kids) + 97.19 1.00 1.00 1.00 157.30 Move window via parent (100 kids) + 96.67 1.00 0.99 0.96 159.44 Move window via parent (200 kids) + 17.75 1.01 1.00 1.00 27.61 Resize window (4 kids) + 17.94 1.00 1.00 0.99 25.42 Resize window (16 kids) + 17.92 1.01 1.00 1.00 24.47 Resize window (25 kids) + 17.24 0.97 1.00 1.00 24.14 Resize window (50 kids) + 16.81 1.00 1.00 0.99 22.75 Resize window (75 kids) + 16.08 1.00 1.00 1.00 21.20 Resize window (100 kids) + 12.92 1.00 0.99 1.00 16.26 Resize window (200 kids) + 52.94 1.01 1.00 1.00 327.12 Resize unmapped window (4 kids) + 53.60 1.01 1.01 1.01 333.71 Resize unmapped window (16 kids) + 52.99 1.00 1.00 1.00 337.29 Resize unmapped window (25 kids) + 51.98 1.00 1.00 1.00 329.38 Resize unmapped window (50 kids) + 53.05 0.89 1.00 1.00 322.60 Resize unmapped window (75 kids) + 53.05 1.00 1.00 1.00 318.08 Resize unmapped window (100 kids) + 53.11 1.00 1.00 0.99 306.21 Resize unmapped window (200 kids) + 16.76 1.00 0.96 1.00 19.46 Circulate window (4 kids) + 17.24 1.00 1.00 0.97 16.24 Circulate window (16 kids) + 16.30 1.03 1.03 1.03 15.85 Circulate window (25 kids) + 13.45 1.00 1.00 1.00 14.90 Circulate window (50 kids) + 12.91 1.00 1.00 1.00 13.06 Circulate window (75 kids) + 11.30 0.98 1.00 1.00 11.03 Circulate window (100 kids) + 7.58 1.01 1.01 0.99 7.47 Circulate window (200 kids) + 1.01 1.01 0.98 1.00 0.95 Circulate Unmapped window (4 kids) + 1.07 1.07 1.01 1.07 1.02 Circulate Unmapped window (16 kids) + 1.04 1.09 1.06 1.05 0.97 Circulate Unmapped window (25 kids) + 1.04 1.23 1.20 1.18 1.05 Circulate Unmapped window (50 kids) + 1.18 1.53 1.19 1.45 1.24 Circulate Unmapped window (75 kids) + 1.08 1.02 1.01 1.74 1.01 Circulate Unmapped window (100 kids) + 1.01 1.12 0.98 0.91 0.97 Circulate Unmapped window (200 kids) + </verb> + +<sect2>Profiling with OProfile + +<p>OProfile (available from http://oprofile.sourceforge.net/) is a +system-wide profiler for Linux systems that uses processor-level +counters to collect sampling data. OProfile can provide information +that is similar to that provided by <tt/gprof/, but without the +necessity of recompiling the program with special instrumentation (i.e., +OProfile can collect statistical profiling information about optimized +programs). A test harness was developed to collect OProfile data for +each <tt/x11perf/ test individually. + +<p>Test runs were performed using the RETIRED_INSNS counter on the AMD +Athlon and the CPU_CLK_HALTED counter on the Intel Pentium III (with a +test configuration different from the one described above). We have +examined OProfile output and have compared it with <tt/gprof/ output. +This investigation has not produced results that yield performance +increases in <tt/x11perf/ numbers. + +<!-- +<sect3>Retired Instructions + +<p>The initial tests using OProfile were done using the RETIRED_INSNS +counter with DMX running on the dual-processor AMD Athlon machine - the +same test configuration that was described above and that was used for +other tests. The RETIRED_INSNS counter counts retired instructions and +showed drawing, text, copying, and image tests to be dominated (> +30%) by calls to Hash(), SecurityLookupIDByClass(), +SecurityLookupIDByType(), and StandardReadRequestFromClient(). Some of +these tests also executed significant instructions in +WaitForSomething(). + +<p>In contrast, the window tests executed significant +instructions in SecurityLookupIDByType(), Hash(), +StandardReadRequestFromClient(), but also executed significant +instructions in other routines, such as ConfigureWindow(). Some time +was spent looking at Hash() function, but optimizations in this routine +did not lead to a dramatic increase in <tt/x11perf/ performance. +--> + +<!-- +<sect3>Clock Cycles + +<p>Retired instructions can be misleading because Intel/AMD instructions +execute in variable amounts of time. The OProfile tests were repeated +using the Intel CPU_CLK_HALTED counter with DMX running on the second +back-end machine. Note that this is a different test configuration that +the one described above. However, these tests show the amount of time +(as measured in CPU cycles) that are spent in each routine. Because +<tt/x11perf/ was running on the first back-end machine and because +window optimizations were on, the load on the second back-end machine +was not significant. + +<p>Using CPU_CLK_HALTED, DMX showed simple drawing +tests spending more than 10% of their time in +StandardReadRequestFromClient(), with significant time (> 20% total) +spent in SecurityLookupIDByClass(), WaitForSomething(), and Dispatch(). +For these tests, < 5% of the time was spent in Hash(), which explains +why optimizing the Hash() routine did not impact <tt/x11perf/ results. + +<p>The trapezoid, text, scrolling, copying, and image tests were +dominated by time in ProcFillPoly(), PanoramiXFillPoly(), dmxFillPolygon(), +SecurityLookupIDByClass(), SecurityLookupIDByType(), and +StandardReadRequestFromClient(). Hash() time was generally above 5% but +less than 10% of total time. +--> + +<sect2>X Test Suite + +<p>The X Test Suite was run on the fully optimized DMX server using the +configuration described above. The following failures were noted: + <verb> +XListPixmapFormats: Test 1 [1] +XChangeWindowAttributes: Test 32 [1] +XCreateWindow: Test 30 [1] +XFreeColors: Test 4 [3] +XCopyArea: Test 13, 17, 21, 25, 30 [2] +XCopyPlane: Test 11, 15, 27, 31 [2] +XSetFontPath: Test 4 [1] +XChangeKeyboardControl: Test 9, 10 [1] + +[1] Previously documented errors expected from the Xinerama + implementation (see Phase I discussion). +[2] Newly noted errors that have been verified as expected + behavior of the Xinerama implementation. +[3] Newly noted error that has been verified as a Xinerama + implementation bug. + </verb> + +<!-- ============================================================ --> +<sect1>Phase III + +<p>During the third phase of development, support was provided for the +following extensions: SHAPE, RENDER, XKEYBOARD, XInput. + +<sect2>SHAPE + +<p>The SHAPE extension is supported. Test applications (e.g., xeyes and +oclock) and window managers that make use of the SHAPE extension will +work as expected. + +<sect2>RENDER + +<p>The RENDER extension is supported. The version included in the DMX +CVS tree is version 0.2, and this version is fully supported by Xdmx. +Applications using only version 0.2 functions will work correctly; +however, some apps that make use of functions from later versions do not +properly check the extension's major/minor version numbers. These apps +will fail with a Bad Implementation error when using post-version 0.2 +functions. This is expected behavior. When the DMX CVS tree is updated +to include newer versions of RENDER, support for these newer functions +will be added to the DMX X server. + +<sect2>XKEYBOARD + +<p>The XKEYBOARD extension is supported. If present on the back-end X +servers, the XKEYBOARD extension will be used to obtain information +about the type of the keyboard for initialization. Otherwise, the +keyboard will be initialized using defaults. Note that this departs +from older behavior: when Xdmx is compiled without XKEYBOARD support, +the map from the back-end X server will be preserved. With XKEYBOARD +support, the map is not preserved because better information and control +of the keyboard is available. + +<sect2>XInput + +<p>The XInput extension is supported. Any device can be used as a core +device and be used as an XInput extension device, with the exception of +core devices on the back-end servers. This limitation is present +because cursor handling on the back-end requires that the back-end +cursor sometimes track the Xdmx core cursor -- behavior that is +incompatible with using the back-end pointer as a non-core device. + +<p>Currently, back-end extension devices are not available as Xdmx +extension devices, but this limitation should be removed in the future. + +<p>To demonstrate the XInput extension, and to provide more examples for +low-level input device driver writers, USB device drivers have been +written for mice (usb-mou), keyboards (usb-kbd), and +non-mouse/non-keyboard USB devices (usb-oth). Please see the man page +for information on Linux kernel drivers that are required for using +these Xdmx drivers. + +<sect2>DPMS + +<p>The DPMS extension is exported but does not do anything at this time. + +<sect2>Other Extensions + +<p>The LBX, + SECURITY, + XC-APPGROUP, and + XFree86-Bigfont +extensions do not require any special Xdmx support and have been exported. + +<p>The + BIG-REQUESTS, + DEC-XTRAP, + DOUBLE-BUFFER, + Extended-Visual-Information, + FontCache, + GLX, + MIT-SCREEN-SAVER, + MIT-SHM, + MIT-SUNDRY-NONSTANDARD, + RECORD, + SECURITY, + SGI-GLX, + SYNC, + TOG-CUP, + X-Resource, + XC-MISC, + XFree86-DGA, + XFree86-DRI, + XFree86-Misc, + XFree86-VidModeExtension, and + XVideo +extensions are <it/not/ supported at this time, but will be evaluated +for inclusion in future DMX releases. <bf>See below for additional work +on extensions after Phase III.</bf> + +<sect1>Phase IV + +<sect2>Moving to XFree86 4.3.0 + +<p>For Phase IV, the recent release of XFree86 4.3.0 (27 February 2003) +was merged onto the dmx.sourceforge.net CVS trunk and all work is +proceeding using this tree. + +<sect2>Extensions + +<sect3>XC-MISC (supported) + +<p>XC-MISC is used internally by the X library to recycle XIDs from the +X server. This is important for long-running X server sessions. Xdmx +supports this extension. The X Test Suite passed and failed the exact +same tests before and after this extension was enabled. +<!-- Tested February/March 2003 --> + +<sect3>Extended-Visual-Information (supported) + +<p>The Extended-Visual-Information extension provides a method for an X +client to obtain detailed visual information. Xdmx supports this +extension. It was tested using the <tt>hw/dmx/examples/evi</tt> example +program. <bf/Note that this extension is not Xinerama-aware/ -- it will +return visual information for each screen even though Xinerama is +causing the X server to export a single logical screen. +<!-- Tested March 2003 --> + +<sect3>RES (supported) + +<p>The X-Resource extension provides a mechanism for a client to obtain +detailed information about the resources used by other clients. This +extension was tested with the <tt>hw/dmx/examples/res</tt> program. The +X Test Suite passed and failed the exact same tests before and after +this extension was enabled. +<!-- Tested March 2003 --> + +<sect3>BIG-REQUESTS (supported) + +<p>This extension enables the X11 protocol to handle requests longer +than 262140 bytes. The X Test Suite passed and failed the exact same +tests before and after this extension was enabled. +<!-- Tested March 2003 --> + +<sect3>XSYNC (supported) + +<p>This extension provides facilities for two different X clients to +synchronize their requests. This extension was minimally tested with +<tt/xdpyinfo/ and the X Test Suite passed and failed the exact same +tests before and after this extension was enabled. +<!-- Tested March 2003 --> + +<sect3>XTEST, RECORD, DEC-XTRAP (supported) and XTestExtension1 (not supported) + +<p>The XTEST and RECORD extension were developed by the X Consortium for +use in the X Test Suite and are supported as a standard in the X11R6 +tree. They are also supported in Xdmx. When X Test Suite tests that +make use of the XTEST extension are run, Xdmx passes and fails exactly +the same tests as does a standard XFree86 X server. When the +<tt/rcrdtest/ test (a part of the X Test Suite that verifies the RECORD +extension) is run, Xdmx passes and fails exactly the same tests as does +a standard XFree86 X server. <!-- Tested February/March 2003 --> + +<p>There are two older XTEST-like extensions: DEC-XTRAP and +XTestExtension1. The XTestExtension1 extension was developed for use by +the X Testing Consortium for use with a test suite that eventually +became (part of?) the X Test Suite. Unlike XTEST, which only allows +events to be sent to the server, the XTestExtension1 extension also +allowed events to be recorded (similar to the RECORD extension). The +second is the DEC-XTRAP extension that was developed by the Digital +Equipment Corporation. + +<p>The DEC-XTRAP extension is available from Xdmx and has been tested +with the <tt/xtrap*/ tools which are distributed as standard X11R6 +clients. <!-- Tested March 2003 --> + +<p>The XTestExtension1 is <em/not/ supported because it does not appear +to be used by any modern X clients (the few that support it also support +XTEST) and because there are no good methods available for testing that +it functions correctly (unlike XTEST and DEC-XTRAP, the code for +XTestExtension1 is not part of the standard X server source tree, so +additional testing is important). <!-- Tested March 2003 --> + +<p>Most of these extensions are documented in the X11R6 source tree. +Further, several original papers exist that this author was unable to +locate -- for completeness and historical interest, citations are +provide: +<descrip> +<tag/XRECORD/ Martha Zimet. Extending X For Recording. 8th Annual X +Technical Conference Boston, MA January 24-26, 1994. +<tag/DEC-XTRAP/ Dick Annicchiarico, Robert Chesler, Alan Jamison. XTrap +Architecture. Digital Equipment Corporation, July 1991. +<tag/XTestExtension1/ Larry Woestman. X11 Input Synthesis Extension +Proposal. Hewlett Packard, November 1991. +</descrip> + +<sect3>MIT-MISC (not supported) + +<p>The MIT-MISC extension is used to control a bug-compatibility flag +that provides compatibility with xterm programs from X11R1 and X11R2. +There does not appear to be a single client available that makes use of +this extension and there is not way to verify that it works correctly. +The Xdmx server does <em/not/ support MIT-MISC. + +<sect3>SCREENSAVER (not supported) + +<p>This extension provides special support for the X screen saver. It +was tested with beforelight, which appears to be the only client that +works with it. When Xinerama was not active, <tt/beforelight/ behaved +as expected. However, when Xinerama was active, <tt/beforelight/ did +not behave as expected. Further, when this extension is not active, +<tt/xscreensaver/ (a widely-used X screen saver program) did not behave +as expected. Since this extension is not Xinerama-aware and is not +commonly used with expected results by clients, we have left this +extension disabled at this time. + +<sect3>GLX (supported) + +<p>The GLX extension provides OpenGL and GLX windowing support. In +Xdmx, the extension is called glxProxy, and it is Xinerama aware. It +works by either feeding requests forward through Xdmx to each of the +back-end servers or handling them locally. All rendering requests are +handled on the back-end X servers. This code was donated to the DMX +project by SGI. For the X Test Suite results comparison, see below. + +<sect3>RENDER (supported) + +<p>The X Rendering Extension (RENDER) provides support for digital image +composition. Geometric and text rendering are supported. RENDER is +partially Xinerama-aware, with text and the most basic compositing +operator; however, its higher level primitives (triangles, triangle +strips, and triangle fans) are not yet Xinerama-aware. The RENDER +extension is still under development, and is currently at version 0.8. +Additional support will be required in DMX as more primitives and/or +requests are added to the extension. + +<p>There is currently no test suite for the X Rendering Extension; +however, there has been discussion of developing a test suite as the +extension matures. When that test suite becomes available, additional +testing can be performed with Xdmx. The X Test Suite passed and failed +the exact same tests before and after this extension was enabled. + +<sect3>Summary + +<!-- WARNING: this list is duplicated in the "Common X extension +support" section --> +<p>To summarize, the following extensions are currently supported: + BIG-REQUESTS, + DEC-XTRAP, + DMX, + DPMS, + Extended-Visual-Information, + GLX, + LBX, + RECORD, + RENDER, + SECURITY, + SHAPE, + SYNC, + X-Resource, + XC-APPGROUP, + XC-MISC, + XFree86-Bigfont, + XINERAMA, + XInputExtension, + XKEYBOARD, and + XTEST. + +<p>The following extensions are <em/not/ supported at this time: + DOUBLE-BUFFER, + FontCache, + MIT-SCREEN-SAVER, + MIT-SHM, + MIT-SUNDRY-NONSTANDARD, + TOG-CUP, + XFree86-DGA, + XFree86-Misc, + XFree86-VidModeExtension, + XTestExtensionExt1, and + XVideo. + +<sect2>Additional Testing with the X Test Suite + +<sect3>XFree86 without XTEST + +<p>After the release of XFree86 4.3.0, we retested the XFree86 X server +with and without using the XTEST extension. When the XTEST extension +was <em/not/ used for testing, the XFree86 4.3.0 server running on our +usual test system with a Radeon VE card reported unexpected failures in +the following tests: +<verb> +XListPixmapFormats: Test 1 +XChangeKeyboardControl: Tests 9, 10 +XGetDefault: Test 5 +XRebindKeysym: Test 1 +</verb> + +<sect3>XFree86 with XTEST + +<p>When using the XTEST extension, the XFree86 4.3.0 server reported the +following errors: +<verb> +XListPixmapFormats: Test 1 +XChangeKeyboardControl: Tests 9, 10 +XGetDefault: Test 5 +XRebindKeysym: Test 1 + +XAllowEvents: Tests 20, 21, 24 +XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 +XGrabKey: Test 8 +XSetPointerMapping: Test 3 +XUngrabButton: Test 4 +</verb> + +<p>While these errors may be important, they will probably be fixed +eventually in the XFree86 source tree. We are particularly interested +in demonstrating that the Xdmx server does not introduce additional +failures that are not known Xinerama failures. + +<sect3>Xdmx with XTEST, without Xinerama, without GLX + +<p>Without Xinerama, but using the XTEST extension, the following errors +were reported from Xdmx (note that these are the same as for the XFree86 +4.3.0, except that XGetDefault no longer fails): +<verb> +XListPixmapFormats: Test 1 +XChangeKeyboardControl: Tests 9, 10 +XRebindKeysym: Test 1 + +XAllowEvents: Tests 20, 21, 24 +XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 +XGrabKey: Test 8 +XSetPointerMapping: Test 3 +XUngrabButton: Test 4 +</verb> + +<sect3>Xdmx with XTEST, with Xinerama, without GLX + +<p>With Xinerama, using the XTEST extension, the following errors +were reported from Xdmx: +<verb> +XListPixmapFormats: Test 1 +XChangeKeyboardControl: Tests 9, 10 +XRebindKeysym: Test 1 + +XAllowEvents: Tests 20, 21, 24 +XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 +XGrabKey: Test 8 +XSetPointerMapping: Test 3 +XUngrabButton: Test 4 + +XCopyPlane: Tests 13, 22, 31 (well-known XTEST/Xinerama interaction issue) +XDrawLine: Test 67 +XDrawLines: Test 91 +XDrawSegments: Test 68 +</verb> +Note that the first two sets of errors are the same as for the XFree86 +4.3.0 server, and that the XCopyPlane error is a well-known error +resulting from an XTEST/Xinerama interaction when the request crosses a +screen boundary. The XDraw* errors are resolved when the tests are run +individually and they do not cross a screen boundary. We will +investigate these errors further to determine their cause. + +<sect3>Xdmx with XTEST, with Xinerama, with GLX + +<p>With GLX enabled, using the XTEST extension, the following errors +were reported from Xdmx (these results are from early during the Phase +IV development, but were confirmed with a late Phase IV snapshot): +<verb> +XListPixmapFormats: Test 1 +XChangeKeyboardControl: Tests 9, 10 +XRebindKeysym: Test 1 + +XAllowEvents: Tests 20, 21, 24 +XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25 +XGrabKey: Test 8 +XSetPointerMapping: Test 3 +XUngrabButton: Test 4 + +XClearArea: Test 8 +XCopyArea: Tests 4, 5, 11, 14, 17, 23, 25, 27, 30 +XCopyPlane: Tests 6, 7, 10, 19, 22, 31 +XDrawArcs: Tests 89, 100, 102 +XDrawLine: Test 67 +XDrawSegments: Test 68 +</verb> +Note that the first two sets of errors are the same as for the XFree86 +4.3.0 server, and that the third set has different failures than when +Xdmx does not include GLX support. Since the GLX extension adds new +visuals to support GLX's visual configs and the X Test Suite runs tests +over the entire set of visuals, additional rendering tests were run and +presumably more of them crossed a screen boundary. This conclusion is +supported by the fact that nearly all of the rendering errors reported +are resolved when the tests are run individually and they do no cross a +screen boundary. + +<p>Further, when hardware rendering is disabled on the back-end displays, +many of the errors in the third set are eliminated, leaving only: +<verb> +XClearArea: Test 8 +XCopyArea: Test 4, 5, 11, 14, 17, 23, 25, 27, 30 +XCopyPlane: Test 6, 7, 10, 19, 22, 31 +</verb> + +<sect3>Conclusion + +<p>We conclude that all of the X Test Suite errors reported for Xdmx are +the result of errors in the back-end X server or the Xinerama +implementation. Further, all of these errors that can be reasonably +fixed at the Xdmx layer have been. (Where appropriate, we have +submitted patches to the XFree86 and Xinerama upstream maintainers.) + +<sect2>Dynamic Reconfiguration + +<p>During this development phase, dynamic reconfiguration support was +added to DMX. This support allows an application to change the position +and offset of a back-end server's screen. For example, if the +application would like to shift a screen slightly to the left, it could +query Xdmx for the screen's <x,y> position and then dynamically +reconfigure that screen to be at position <x+10,y>. When a screen +is dynamically reconfigured, input handling and a screen's root window +dimensions are adjusted as needed. These adjustments are transparent to +the user. + +<sect3>Dynamic reconfiguration extension + +<p>The application interface to DMX's dynamic reconfiguration is through +a function in the DMX extension library: +<verb> +Bool DMXReconfigureScreen(Display *dpy, int screen, int x, int y) +</verb> +where <it/dpy/ is DMX server's display, <it/screen/ is the number of the +screen to be reconfigured, and <it/x/ and <it/y/ are the new upper, +left-hand coordinates of the screen to be reconfigured. + +<p>The coordinates are not limited other than as required by the X +protocol, which limits all coordinates to a signed 16 bit number. In +addition, all coordinates within a screen must also be legal values. +Therefore, setting a screen's upper, left-hand coordinates such that the +right or bottom edges of the screen is greater than 32,767 is illegal. + +<sect3>Bounding box + +<p>When the Xdmx server is started, a bounding box is calculated from +the screens' layout given either on the command line or in the +configuration file. This bounding box is currently fixed for the +lifetime of the Xdmx server. + +<p>While it is possible to move a screen outside of the bounding box, it +is currently not possible to change the dimensions of the bounding box. +For example, it is possible to specify coordinates of <-100,-100> +for the upper, left-hand corner of the bounding box, which was +previously at coordinates <0,0>. As expected, the screen is moved +down and to the right; however, since the bounding box is fixed, the +left side and upper portions of the screen exposed by the +reconfiguration are no longer accessible on that screen. Those +inaccessible regions are filled with black. + +<p>This fixed bounding box limitation will be addressed in a future +development phase. + +<sect3>Sample applications + +<p>An example of where this extension is useful is in setting up a video +wall. It is not always possible to get everything perfectly aligned, +and sometimes the positions are changed (e.g., someone might bump into a +projector). Instead of physically moving projectors or monitors, it is +now possible to adjust the positions of the back-end server's screens +using the dynamic reconfiguration support in DMX. + +<p>Other applications, such as automatic setup and calibration tools, +can make use of dynamic reconfiguration to correct for projector +alignment problems, as long as the projectors are still arranged +rectilinearly. Horizontal and vertical keystone correction could be +applied to projectors to correct for non-rectilinear alignment problems; +however, this must be done external to Xdmx. + +<p>A sample test program is included in the DMX server's examples +directory to demonstrate the interface and how an application might use +dynamic reconfiguration. See <tt/dmxreconfig.c/ for details. + +<sect3>Additional notes + +<p>In the original development plan, Phase IV was primarily devoted to +adding OpenGL support to DMX; however, SGI became interested in the DMX +project and developed code to support OpenGL/GLX. This code was later +donated to the DMX project and integrated into the DMX code base, which +freed the DMX developers to concentrate on dynamic reconfiguration (as +described above). + +<sect2>Doxygen documentation + +<p>Doxygen is an open-source (GPL) documentation system for generating +browseable documentation from stylized comments in the source code. We +have placed all of the Xdmx server and DMX protocol source code files +under Doxygen so that comprehensive documentation for the Xdmx source +code is available in an easily browseable format. + +<sect2>Valgrind + +<p>Valgrind, an open-source (GPL) memory debugger for Linux, was used to +search for memory management errors. Several memory leaks were detected +and repaired. The following errors were not addressed: +<enum> + <item> + When the X11 transport layer sends a reply to the client, only + those fields that are required by the protocol are filled in -- + unused fields are left as uninitialized memory and are therefore + noted by valgrind. These instances are not errors and were not + repaired. + <item> + At each server generation, glxInitVisuals allocates memory that + is never freed. The amount of memory lost each generation + approximately equal to 128 bytes for each back-end visual. + Because the code involved is automatically generated, this bug + has not been fixed and will be referred to SGI. + <item> + At each server generation, dmxRealizeFont calls XLoadQueryFont, + which allocates a font structure that is not freed. + dmxUnrealizeFont can free the font structure for the first + screen, but cannot free it for the other screens since they are + already closed by the time dmxUnrealizeFont could free them. + The amount of memory lost each generation is approximately equal + to 80 bytes per font per back-end. When this bug is fixed in + the the X server's device-independent (dix) code, DMX will be + able to properly free the memory allocated by XLoadQueryFont. +</enum> + +<sect2>RATS + +<p>RATS (Rough Auditing Tool for Security) is an open-source (GPL) +security analysis tool that scans source code for common +security-related programming errors (e.g., buffer overflows and TOCTOU +races). RATS was used to audit all of the code in the hw/dmx directory +and all "High" notations were checked manually. The code was either +re-written to eliminate the warning, or a comment containing "RATS" was +inserted on the line to indicate that a human had checked the code. +Unrepaired warnings are as follows: +<enum> + <item> + Fixed-size buffers are used in many areas, but code has been + added to protect against buffer overflows (e.g., XmuSnprint). + The only instances that have not yet been fixed are in + config/xdmxconfig.c (which is not part of the Xdmx server) and + input/usb-common.c. + <item> + vprintf and vfprintf are used in the logging routines. In + general, all uses of these functions (e.g., dmxLog) provide a + constant format string from a trusted source, so the use is + relatively benign. + <item> + glxProxy/glxscreens.c uses getenv and strcat. The use of these + functions is safe and will remain safe as long as + ExtensionsString is longer then GLXServerExtensions (ensuring + this may not be ovious to the casual programmer, but this is in + automatically generated code, so we hope that the generator + enforces this constraint). +</enum> + + </article> + + <!-- Local Variables: --> + <!-- fill-column: 72 --> + <!-- End: --> diff --git a/xorg-server/hw/dmx/glxProxy/glxcmds.c b/xorg-server/hw/dmx/glxProxy/glxcmds.c index 31fd431e7..a2fe0b27b 100644 --- a/xorg-server/hw/dmx/glxProxy/glxcmds.c +++ b/xorg-server/hw/dmx/glxProxy/glxcmds.c @@ -1,3610 +1,3610 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxwindow.h" -#include "dmxpixmap.h" -#include "dmxfont.h" -#include "dmxsync.h" - -#undef Xmalloc -#undef Xcalloc -#undef Xrealloc -#undef Xfree - -#include "glxserver.h" -#include <GL/glxtokens.h> -#include "g_disptab.h" -#include <pixmapstr.h> -#include <windowstr.h> -#include "glxutil.h" -#include "glxext.h" -#include "unpack.h" - -#include "GL/glxproto.h" -#include "glxvendor.h" -#include "glxvisuals.h" -#include "glxswap.h" - -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#endif - -extern __GLXFBConfig **__glXFBConfigs; -extern int __glXNumFBConfigs; - -extern __GLXFBConfig *glxLookupFBConfig( GLXFBConfigID id ); -extern __GLXFBConfig *glxLookupFBConfigByVID( VisualID vid ); -extern __GLXFBConfig *glxLookupBackEndFBConfig( GLXFBConfigID id, int screen ); -extern int glxIsExtensionSupported( char *ext ); -extern int __glXGetFBConfigsSGIX(__GLXclientState *cl, GLbyte *pc); - -#define BE_TO_CLIENT_ERROR(x) \ - ( (x) >= __glXerrorBase ? \ - (x) - dmxScreen->glxErrorBase + __glXerrorBase \ - : (x) ) - -Display *GetBackEndDisplay( __GLXclientState *cl, int s ) -{ - if (! cl->be_displays[s] ) { - cl->be_displays[s] = XOpenDisplay( DisplayString(dmxScreens[s].beDisplay) ); - } - return( cl->be_displays[s] ); -} - -/* -** Create a GL context with the given properties. -*/ -static int CreateContext(__GLXclientState *cl, - GLXContextID gcId, - VisualID vid, GLXFBConfigID fbconfigId, - int screen, - GLXContextID shareList, - int isDirect ) -{ - ClientPtr client = cl->client; - xGLXCreateContextReq *be_req; - xGLXCreateNewContextReq *be_new_req; - VisualPtr pVisual; - ScreenPtr pScreen; - __GLXcontext *glxc, *shareglxc; - __GLXvisualConfig *pGlxVisual; - __GLXscreenInfo *pGlxScreen; - VisualID visual = vid; - GLint i; - int from_screen = screen; - int to_screen = screen; - DMXScreenInfo *dmxScreen; - VisualID be_vid; - GLXFBConfigID be_fbconfigId; - int num_be_screens; - Display *dpy; - - /* - ** Check if screen exists. - */ - if (screen >= screenInfo.numScreens) { - client->errorValue = screen; - return BadValue; - } - - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - /* - ** Find the display list space that we want to share. - ** - */ - if (shareList == None) { - shareglxc = NULL; - } else { - shareglxc = (__GLXcontext *) LookupIDByType(shareList, __glXContextRes); - if (!shareglxc) { - client->errorValue = shareList; - return __glXBadContext; - } - } - - /* - ** Allocate memory for the new context - */ - glxc = __glXCalloc(1, sizeof(__GLXcontext)); - if (!glxc) { - return BadAlloc; - } - - pScreen = screenInfo.screens[screen]; - pGlxScreen = &__glXActiveScreens[screen]; - - if (fbconfigId != None) { - glxc->pFBConfig = glxLookupFBConfig( fbconfigId ); - if (!glxc->pFBConfig) { - client->errorValue = fbconfigId; - __glXFree( glxc ); - return BadValue; - } - visual = glxc->pFBConfig->associatedVisualId; - } - else { - glxc->pFBConfig = NULL; - } - - if (visual != None) { - /* - ** Check if the visual ID is valid for this screen. - */ - pVisual = pScreen->visuals; - for (i = 0; i < pScreen->numVisuals; i++, pVisual++) { - if (pVisual->vid == visual) { - break; - } - } - if (i == pScreen->numVisuals) { - client->errorValue = visual; - __glXFree( glxc ); - return BadValue; - } - - pGlxVisual = pGlxScreen->pGlxVisual; - for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { - if (pGlxVisual->vid == visual) { - break; - } - } - if (i == pGlxScreen->numVisuals) { - /* - ** Visual not support on this screen by this OpenGL implementation. - */ - client->errorValue = visual; - __glXFree( glxc ); - return BadValue; - } - - if ( glxc->pFBConfig == NULL ) { - glxc->pFBConfig = glxLookupFBConfigByVID( visual ); - - if ( glxc->pFBConfig == NULL ) { - /* - * visual does not have an FBConfig ??? - client->errorValue = visual; - __glXFree( glxc ); - return BadValue; - */ - } - } - } - else { - pVisual = NULL; - pGlxVisual = NULL; - } - - glxc->pScreen = pScreen; - glxc->pGlxScreen = pGlxScreen; - glxc->pVisual = pVisual; - glxc->pGlxVisual = pGlxVisual; - - /* - * allocate memory for back-end servers info - */ - num_be_screens = to_screen - from_screen + 1; - glxc->real_ids = (XID *)__glXMalloc(sizeof(XID) * num_be_screens); - if (!glxc->real_ids) { - return BadAlloc; - } - glxc->real_vids = (XID *)__glXMalloc(sizeof(XID) * num_be_screens); - if (!glxc->real_vids) { - return BadAlloc; - } - - for (screen = from_screen; screen <= to_screen; screen++) { - int sent = 0; - pScreen = screenInfo.screens[screen]; - pGlxScreen = &__glXActiveScreens[screen]; - dmxScreen = &dmxScreens[screen]; - - if (glxc->pFBConfig) { - __GLXFBConfig *beFBConfig = glxLookupBackEndFBConfig( glxc->pFBConfig->id, - screen ); - be_fbconfigId = beFBConfig->id; - } - - if (pGlxVisual) { - - be_vid = glxMatchGLXVisualInConfigList( pGlxVisual, - dmxScreen->glxVisuals, - dmxScreen->numGlxVisuals ); - - if (!be_vid) { - /* visual is not supported on the back-end server */ - __glXFree( glxc->real_ids ); - __glXFree( glxc->real_vids ); - __glXFree( glxc ); - return BadValue; - } - } - - glxc->real_ids[screen-from_screen] = XAllocID(GetBackEndDisplay(cl,screen)); - - /* send the create context request to the back-end server */ - dpy = GetBackEndDisplay(cl,screen); - if (glxc->pFBConfig) { - /*Since for a certain visual both RGB and COLOR INDEX - *can be on then the only parmeter to choose the renderType - * should be the class of the colormap since all 4 first - * classes does not support RGB mode only COLOR INDEX , - * and so TrueColor and DirectColor does not support COLOR INDEX*/ - int renderType = glxc->pFBConfig->renderType; - if ( pVisual ) { - switch ( pVisual->class ){ - case PseudoColor: - case StaticColor: - case GrayScale: - case StaticGray: - renderType = GLX_COLOR_INDEX_TYPE; - break; - case TrueColor: - case DirectColor: - default: - renderType = GLX_RGBA_TYPE; - break; - } - } - if ( __GLX_IS_VERSION_SUPPORTED(1,3) ) { - LockDisplay(dpy); - GetReq(GLXCreateNewContext,be_new_req); - be_new_req->reqType = dmxScreen->glxMajorOpcode; - be_new_req->glxCode = X_GLXCreateNewContext; - be_new_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; - be_new_req->fbconfig = (unsigned int)be_fbconfigId; - be_new_req->screen = DefaultScreen(dpy); - be_new_req->renderType = renderType; - - be_new_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); - be_new_req->isDirect = 0; - UnlockDisplay(dpy); - glxc->real_vids[screen-from_screen] = be_fbconfigId; - sent = 1; - } - else if (glxIsExtensionSupported("GLX_SGIX_fbconfig")) { - - xGLXCreateContextWithConfigSGIXReq *ext_req; - xGLXVendorPrivateReq *vpreq; - LockDisplay(dpy); - GetReqExtra(GLXVendorPrivate, - sz_xGLXCreateContextWithConfigSGIXReq - sz_xGLXVendorPrivateReq, - vpreq); - ext_req = (xGLXCreateContextWithConfigSGIXReq *)vpreq; - ext_req->reqType = dmxScreen->glxMajorOpcode; - ext_req->glxCode = X_GLXVendorPrivate; - ext_req->vendorCode = X_GLXvop_CreateContextWithConfigSGIX; - ext_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; - ext_req->fbconfig = (unsigned int)be_fbconfigId; - ext_req->screen = DefaultScreen(dpy); - ext_req->renderType = renderType; - ext_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); - ext_req->isDirect = 0; - UnlockDisplay(dpy); - glxc->real_vids[screen-from_screen] = be_fbconfigId; - sent = 1; - } - } - - if (!sent) { - LockDisplay(dpy); - GetReq(GLXCreateContext,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXCreateContext; - be_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; - be_req->visual = (unsigned int)be_vid; - be_req->screen = DefaultScreen(dpy); - be_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); - be_req->isDirect = 0; - UnlockDisplay(dpy); - glxc->real_vids[screen-from_screen] = be_vid; - } - SyncHandle(); - - } - - /* - ** Register this context as a resource. - */ - if (!AddResource(gcId, __glXContextRes, (pointer)glxc)) { - __glXFree( glxc->real_ids ); - __glXFree( glxc->real_vids ); - __glXFree( glxc ); - client->errorValue = gcId; - return BadAlloc; - } - - /* - ** Finally, now that everything is working, setup the rest of the - ** context. - */ - glxc->id = gcId; - glxc->share_id = shareList; - glxc->idExists = GL_TRUE; - glxc->isCurrent = GL_FALSE; - - return Success; -} - -int __glXCreateContext(__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; - - return( CreateContext(cl, req->context,req->visual, None, - req->screen, req->shareList, req->isDirect) ); - -} - -int __glXCreateNewContext(__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc; - - return( CreateContext(cl, req->context,None, req->fbconfig, - req->screen, req->shareList, req->isDirect) ); - -} - -int __glXCreateContextWithConfigSGIX(__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateContextWithConfigSGIXReq *req = (xGLXCreateContextWithConfigSGIXReq *) pc; - - return( CreateContext(cl, req->context, None, req->fbconfig, - req->screen, req->shareList, req->isDirect) ); - -} - -int __glXQueryMaxSwapBarriersSGIX(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXQueryMaxSwapBarriersSGIXReq *req = - (xGLXQueryMaxSwapBarriersSGIXReq *)pc; - xGLXQueryMaxSwapBarriersSGIXReply reply; - - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = 0; - reply.max = QueryMaxSwapBarriersSGIX(req->screen); - - if (client->swapped) { - __glXSwapQueryMaxSwapBarriersSGIXReply(client, &reply); - } else { - WriteToClient(client, sz_xGLXQueryMaxSwapBarriersSGIXReply, - (char *)&reply); - } - - return Success; -} - -int __glXBindSwapBarrierSGIX(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXBindSwapBarrierSGIXReq *req = (xGLXBindSwapBarrierSGIXReq *)pc; - DrawablePtr pDraw; - __GLXpixmap *pGlxPixmap = NULL; - __glXWindow *pGlxWindow = NULL; - int rc; - - rc = dixLookupDrawable(&pDraw, req->drawable, client, 0, DixGetAttrAccess); - if (rc != Success) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->drawable, - __glXPixmapRes); - if (pGlxPixmap) pDraw = pGlxPixmap->pDraw; - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(req->drawable, - __glXWindowRes); - if (pGlxWindow) pDraw = pGlxWindow->pDraw; - } - - if (!pDraw) { - client->errorValue = req->drawable; - return __glXBadDrawable; - } - - return BindSwapBarrierSGIX(pDraw, req->barrier); -} - -int __glXJoinSwapGroupSGIX(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXJoinSwapGroupSGIXReq *req = (xGLXJoinSwapGroupSGIXReq *)pc; - DrawablePtr pDraw, pMember = NULL; - __GLXpixmap *pGlxPixmap = NULL; - __glXWindow *pGlxWindow = NULL; - int rc; - - rc = dixLookupDrawable(&pDraw, req->drawable, client, 0, DixManageAccess); - if (rc != Success) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->drawable, - __glXPixmapRes); - if (pGlxPixmap) pDraw = pGlxPixmap->pDraw; - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(req->drawable, - __glXWindowRes); - if (pGlxWindow) pDraw = pGlxWindow->pDraw; - } - - if (!pDraw) { - client->errorValue = req->drawable; - return __glXBadDrawable; - } - - if (req->member != None) { - rc = dixLookupDrawable(&pMember, req->member, client, 0, - DixGetAttrAccess); - if (rc != Success) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->member, - __glXPixmapRes); - if (pGlxPixmap) pMember = pGlxPixmap->pDraw; - } - - if (!pMember && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(req->member, - __glXWindowRes); - if (pGlxWindow) pMember = pGlxWindow->pDraw; - } - - if (!pMember) { - client->errorValue = req->member; - return __glXBadDrawable; - } - } - - return JoinSwapGroupSGIX(pDraw, pMember); -} - - -/* -** Destroy a GL context as an X resource. -*/ -int __glXDestroyContext(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc; - xGLXDestroyContextReq *be_req; - GLXContextID gcId = req->context; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - int s; - - glxc = (__GLXcontext *) LookupIDByType(gcId, __glXContextRes); - if (glxc) { - /* - ** Just free the resource; don't actually destroy the context, - ** because it might be in use. The - ** destroy method will be called by the resource destruction routine - ** if necessary. - */ - FreeResourceByType(gcId, __glXContextRes, FALSE); - - from_screen = to_screen = glxc->pScreen->myNum; - - } else { - client->errorValue = gcId; - return __glXBadContext; - } - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - /* - * send DestroyContext request to all back-end servers - */ - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReq(GLXDestroyContext,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXDestroyContext; - be_req->context = glxc->real_ids[s-from_screen]; - UnlockDisplay(dpy); - SyncHandle(); - } - - return Success; -} - -/*****************************************************************************/ - -/* -** For each client, the server keeps a table of all the contexts that are -** current for that client (each thread of a client may have its own current -** context). These routines add, change, and lookup contexts in the table. -*/ - -/* -** Add a current context, and return the tag that will be used to refer to it. -*/ -static int AddCurrentContext(__GLXclientState *cl, __GLXcontext *glxc, DrawablePtr pDraw) -{ - int i; - int num = cl->numCurrentContexts; - __GLXcontext **table = cl->currentContexts; - - if (!glxc) return -1; - - /* - ** Try to find an empty slot and use it. - */ - for (i=0; i < num; i++) { - if (!table[i]) { - table[i] = glxc; - return i+1; - } - } - /* - ** Didn't find a free slot, so we'll have to grow the table. - */ - if (!num) { - table = (__GLXcontext **) __glXMalloc(sizeof(__GLXcontext *)); - cl->currentDrawables = (DrawablePtr *) __glXMalloc(sizeof(DrawablePtr)); - cl->be_currentCTag = (GLXContextTag *) __glXMalloc(screenInfo.numScreens *sizeof(GLXContextTag)); - } else { - table = (__GLXcontext **) __glXRealloc(table, - (num+1)*sizeof(__GLXcontext *)); - cl->currentDrawables = (DrawablePtr *) __glXRealloc( - cl->currentDrawables , - (num+1)*sizeof(DrawablePtr)); - cl->be_currentCTag = (GLXContextTag *) __glXRealloc(cl->be_currentCTag, - (num+1)*screenInfo.numScreens*sizeof(GLXContextTag)); - } - table[num] = glxc; - cl->currentDrawables[num] = pDraw; - cl->currentContexts = table; - cl->numCurrentContexts++; - - memset(cl->be_currentCTag + num*screenInfo.numScreens, 0, - screenInfo.numScreens * sizeof(GLXContextTag)); - - return num+1; -} - -/* -** Given a tag, change the current context for the corresponding entry. -*/ -static void ChangeCurrentContext(__GLXclientState *cl, __GLXcontext *glxc, - GLXContextTag tag) -{ - __GLXcontext **table = cl->currentContexts; - table[tag-1] = glxc; -} - -/* -** Given a tag, and back-end screen number, retrives the current back-end -** tag. -*/ -int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s) -{ - if (tag >0) { - return( cl->be_currentCTag[ (tag-1)*screenInfo.numScreens + s ] ); - } - else { - return( 0 ); - } -} - -/* -** Given a tag, and back-end screen number, sets the current back-end -** tag. -*/ -static void SetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s, GLXContextTag be_tag) -{ - if (tag >0) { - cl->be_currentCTag[ (tag-1)*screenInfo.numScreens + s ] = be_tag; - } -} - -/* -** For this implementation we have chosen to simply use the index of the -** context's entry in the table as the context tag. A tag must be greater -** than 0. -*/ -__GLXcontext *__glXLookupContextByTag(__GLXclientState *cl, GLXContextTag tag) -{ - int num = cl->numCurrentContexts; - - if (tag < 1 || tag > num) { - return 0; - } else { - return cl->currentContexts[tag-1]; - } -} - -DrawablePtr __glXLookupDrawableByTag(__GLXclientState *cl, GLXContextTag tag) -{ - int num = cl->numCurrentContexts; - - if (tag < 1 || tag > num) { - return 0; - } else { - return cl->currentDrawables[tag-1]; - } -} - -/*****************************************************************************/ - -static void StopUsingContext(__GLXcontext *glxc) -{ - if (glxc) { - if (glxc == __glXLastContext) { - /* Tell server GL library */ - __glXLastContext = 0; - } - glxc->isCurrent = GL_FALSE; - if (!glxc->idExists) { - __glXFreeContext(glxc); - } - } -} - -static void StartUsingContext(__GLXclientState *cl, __GLXcontext *glxc) -{ - glxc->isCurrent = GL_TRUE; -} - -/*****************************************************************************/ -/* -** Make an OpenGL context and drawable current. -*/ -static int MakeCurrent(__GLXclientState *cl, - GLXDrawable drawable, - GLXDrawable readdrawable, - GLXContextID context, - GLXContextTag oldContextTag) -{ - ClientPtr client = cl->client; - DrawablePtr pDraw = NULL; - DrawablePtr pReadDraw = NULL; - xGLXMakeCurrentReadSGIReply new_reply; - xGLXMakeCurrentReq *be_req; - xGLXMakeCurrentReply be_reply; - xGLXMakeContextCurrentReq *be_new_req; - xGLXMakeContextCurrentReply be_new_reply; - GLXDrawable drawId = drawable; - GLXDrawable readId = readdrawable; - GLXContextID contextId = context; - __GLXpixmap *pGlxPixmap = 0; - __GLXpixmap *pReadGlxPixmap = 0; - __GLXcontext *glxc, *prevglxc; - GLXContextTag tag = oldContextTag; - WindowPtr pWin = NULL; - WindowPtr pReadWin = NULL; - __glXWindow *pGlxWindow = NULL; - __glXWindow *pGlxReadWindow = NULL; - __glXPbuffer *pGlxPbuffer = NULL; - __glXPbuffer *pGlxReadPbuffer = NULL; -#ifdef PANORAMIX - PanoramiXRes *pXinDraw = NULL; - PanoramiXRes *pXinReadDraw = NULL; -#endif - int from_screen = 0; - int to_screen = 0; - int s, rc; - - /* - ** If one is None and the other isn't, it's a bad match. - */ - if ((drawId == None && contextId != None) || - (drawId != None && contextId == None)) { - return BadMatch; - } - - /* - ** Lookup old context. If we have one, it must be in a usable state. - */ - if (tag != 0) { - prevglxc = __glXLookupContextByTag(cl, tag); - if (!prevglxc) { - /* - ** Tag for previous context is invalid. - */ - return __glXBadContextTag; - } - } else { - prevglxc = 0; - } - - /* - ** Lookup new context. It must not be current for someone else. - */ - if (contextId != None) { - glxc = (__GLXcontext *) LookupIDByType(contextId, __glXContextRes); - if (!glxc) { - client->errorValue = contextId; - return __glXBadContext; - } - if ((glxc != prevglxc) && glxc->isCurrent) { - /* Context is current to somebody else */ - return BadAccess; - } - } else { - /* Switching to no context. Ignore new drawable. */ - glxc = 0; - } - - if (drawId != None) { - rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); - if (rc == Success) { - if (pDraw->type == DRAWABLE_WINDOW) { - /* - ** Drawable is an X Window. - */ - VisualID vid; - pWin = (WindowPtr)pDraw; - vid = wVisual(pWin); - - new_reply.writeVid = (glxc->pFBConfig ? glxc->pFBConfig->id : vid); - new_reply.writeType = GLX_WINDOW_TYPE; - - /* - ** Check if window and context are similar. - */ - if ((vid != glxc->pVisual->vid) || - (pWin->drawable.pScreen != glxc->pScreen)) { - client->errorValue = drawId; - return BadMatch; - } - - from_screen = to_screen = pWin->drawable.pScreen->myNum; - - } else { - /* - ** An X Pixmap is not allowed as a parameter (a GLX Pixmap - ** is, but it must first be created with glxCreateGLXPixmap). - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - if (!pDraw) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, - __glXPixmapRes); - if (pGlxPixmap) { - /* - ** Check if pixmap and context are similar. - */ - if (pGlxPixmap->pScreen != glxc->pScreen || - pGlxPixmap->pGlxVisual != glxc->pGlxVisual) { - client->errorValue = drawId; - return BadMatch; - } - pDraw = pGlxPixmap->pDraw; - - new_reply.writeVid = (glxc->pFBConfig ? glxc->pFBConfig->id : - pGlxPixmap->pGlxVisual->vid); - - new_reply.writeType = GLX_PIXMAP_TYPE; - - from_screen = to_screen = pGlxPixmap->pScreen->myNum; - - } - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); - if (pGlxWindow) { - /* - ** Drawable is a GLXWindow. - ** - ** Check if GLX window and context are similar. - */ - if (pGlxWindow->pScreen != glxc->pScreen || - pGlxWindow->pGlxFBConfig != glxc->pFBConfig) { - client->errorValue = drawId; - return BadMatch; - } - - pDraw = pGlxWindow->pDraw; - new_reply.writeVid = pGlxWindow->pGlxFBConfig->id; - new_reply.writeType = GLX_GLXWINDOW_TYPE; - } - - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); - if (pGlxPbuffer) { - if (pGlxPbuffer->pScreen != glxc->pScreen || - pGlxPbuffer->pFBConfig != glxc->pFBConfig) { - client->errorValue = drawId; - return BadMatch; - } - - pDraw = (DrawablePtr)pGlxPbuffer; - new_reply.writeVid = pGlxPbuffer->pFBConfig->id; - new_reply.writeType = GLX_PBUFFER_TYPE; - } - } - - if (!pDraw) { - /* - ** Drawable is not a Window , GLXWindow or a GLXPixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - - } else { - pDraw = 0; - } - - if (readId != None && readId != drawId ) { - rc = dixLookupDrawable(&pReadDraw, readId, client, 0, DixReadAccess); - if (rc == Success) { - if (pReadDraw->type == DRAWABLE_WINDOW) { - /* - ** Drawable is an X Window. - */ - VisualID vid; - pReadWin = (WindowPtr)pDraw; - vid = wVisual(pReadWin); - - new_reply.readVid = (glxc->pFBConfig ? glxc->pFBConfig->id : vid); - new_reply.readType = GLX_WINDOW_TYPE; - - /* - ** Check if window and context are similar. - */ - if ((vid != glxc->pVisual->vid) || - (pReadWin->drawable.pScreen != glxc->pScreen)) { - client->errorValue = readId; - return BadMatch; - } - - } else { - - /* - ** An X Pixmap is not allowed as a parameter (a GLX Pixmap - ** is, but it must first be created with glxCreateGLXPixmap). - */ - client->errorValue = readId; - return __glXBadDrawable; - } - } - - if (!pReadDraw) { - pReadGlxPixmap = (__GLXpixmap *) LookupIDByType(readId, - __glXPixmapRes); - if (pReadGlxPixmap) { - /* - ** Check if pixmap and context are similar. - */ - if (pReadGlxPixmap->pScreen != glxc->pScreen || - pReadGlxPixmap->pGlxVisual != glxc->pGlxVisual) { - client->errorValue = readId; - return BadMatch; - } - pReadDraw = pReadGlxPixmap->pDraw; - - new_reply.readVid = (glxc->pFBConfig ? glxc->pFBConfig->id : - pReadGlxPixmap->pGlxVisual->vid ); - new_reply.readType = GLX_PIXMAP_TYPE; - - } - } - - if (!pReadDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxReadWindow = (__glXWindow *) - LookupIDByType(readId, __glXWindowRes); - if (pGlxReadWindow) { - /* - ** Drawable is a GLXWindow. - ** - ** Check if GLX window and context are similar. - */ - if (pGlxReadWindow->pScreen != glxc->pScreen || - pGlxReadWindow->pGlxFBConfig != glxc->pFBConfig) { - client->errorValue = readId; - return BadMatch; - } - - pReadDraw = pGlxReadWindow->pDraw; - new_reply.readVid = pGlxReadWindow->pGlxFBConfig->id; - new_reply.readType = GLX_GLXWINDOW_TYPE; - } - } - - if (!pReadDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxReadPbuffer = (__glXPbuffer *)LookupIDByType(readId, __glXPbufferRes); - if (pGlxReadPbuffer) { - if (pGlxReadPbuffer->pScreen != glxc->pScreen || - pGlxReadPbuffer->pFBConfig != glxc->pFBConfig) { - client->errorValue = drawId; - return BadMatch; - } - - pReadDraw = (DrawablePtr)pGlxReadPbuffer; - new_reply.readVid = pGlxReadPbuffer->pFBConfig->id; - new_reply.readType = GLX_PBUFFER_TYPE; - } - } - - if (!pReadDraw) { - /* - ** Drawable is neither a Window nor a GLXPixmap. - */ - client->errorValue = readId; - return __glXBadDrawable; - } - - } else { - pReadDraw = pDraw; - pReadGlxPixmap = pGlxPixmap; - pReadWin = pWin; - new_reply.readVid = new_reply.writeVid; - new_reply.readType = new_reply.writeType; - } - - if (prevglxc) { - - if (prevglxc->pGlxPixmap) { - /* - ** The previous drawable was a glx pixmap, release it. - */ - prevglxc->pGlxPixmap->refcnt--; - __glXFreeGLXPixmap( prevglxc->pGlxPixmap ); - prevglxc->pGlxPixmap = 0; - } - - if (prevglxc->pGlxReadPixmap) { - /* - ** The previous drawable was a glx pixmap, release it. - */ - prevglxc->pGlxReadPixmap->refcnt--; - __glXFreeGLXPixmap( prevglxc->pGlxReadPixmap ); - prevglxc->pGlxReadPixmap = 0; - } - - if (prevglxc->pGlxWindow) { - /* - ** The previous drawable was a glx window, release it. - */ - prevglxc->pGlxWindow->refcnt--; - __glXFreeGLXWindow( prevglxc->pGlxWindow ); - prevglxc->pGlxWindow = 0; - } - - if (prevglxc->pGlxReadWindow) { - /* - ** The previous drawable was a glx window, release it. - */ - prevglxc->pGlxReadWindow->refcnt--; - __glXFreeGLXWindow( prevglxc->pGlxReadWindow ); - prevglxc->pGlxReadWindow = 0; - } - - if (prevglxc->pGlxPbuffer) { - /* - ** The previous drawable was a glx Pbuffer, release it. - */ - prevglxc->pGlxPbuffer->refcnt--; - __glXFreeGLXPbuffer( prevglxc->pGlxPbuffer ); - prevglxc->pGlxPbuffer = 0; - } - - if (prevglxc->pGlxReadPbuffer) { - /* - ** The previous drawable was a glx Pbuffer, release it. - */ - prevglxc->pGlxReadPbuffer->refcnt--; - __glXFreeGLXPbuffer( prevglxc->pGlxReadPbuffer ); - prevglxc->pGlxReadPbuffer = 0; - } - - ChangeCurrentContext(cl, glxc, tag); - ChangeCurrentContext(cl, glxc, tag); - StopUsingContext(prevglxc); - } else { - tag = AddCurrentContext(cl, glxc, pDraw); - } - if (glxc) { - - glxc->pGlxPixmap = pGlxPixmap; - glxc->pGlxReadPixmap = pReadGlxPixmap; - glxc->pGlxWindow = pGlxWindow; - glxc->pGlxReadWindow = pGlxReadWindow; - glxc->pGlxPbuffer = pGlxPbuffer; - glxc->pGlxReadPbuffer = pGlxReadPbuffer; - - if (pGlxPixmap) { - pGlxPixmap->refcnt++; - } - - if (pReadGlxPixmap) { - pReadGlxPixmap->refcnt++; - } - - if (pGlxWindow) { - pGlxWindow->refcnt++; - } - - if (pGlxReadWindow) { - pGlxReadWindow->refcnt++; - } - - if (pGlxPbuffer) { - pGlxPbuffer->refcnt++; - } - - if (pGlxReadPbuffer) { - pGlxReadPbuffer->refcnt++; - } - - StartUsingContext(cl, glxc); - new_reply.contextTag = tag; - } else { - new_reply.contextTag = 0; - } - new_reply.length = 0; - new_reply.type = X_Reply; - new_reply.sequenceNumber = client->sequence; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - - if (pDraw && new_reply.writeType != GLX_PBUFFER_TYPE) { - pXinDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); - } - - if (pReadDraw && pReadDraw != pDraw && - new_reply.readType != GLX_PBUFFER_TYPE) { - pXinReadDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pReadDraw->id, XRC_DRAWABLE, DixReadAccess); - } - else { - pXinReadDraw = pXinDraw; - } - } -#endif - - - /* send the MakeCurrent request to all required - * back-end servers. - */ - for (s = from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - unsigned int be_draw = None; - unsigned int be_read_draw = None; - - if (pGlxPixmap) { - be_draw = pGlxPixmap->be_xids[s]; - } - else if (pGlxPbuffer) { - be_draw = pGlxPbuffer->be_xids[s]; - } -#ifdef PANORAMIX - else if (pXinDraw) { - dixLookupWindow(&pWin, pXinDraw->info[s].id, client, DixReadAccess); - } -#endif - else if (pGlxWindow) { - pWin = (WindowPtr)pGlxWindow->pDraw; - } - - if (pWin && be_draw == None) { - be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - if (!be_draw) { - /* it might be that the window did not created yet on the */ - /* back-end server (lazy window creation option), force */ - /* creation of the window */ - dmxCreateAndRealizeWindow( pWin, TRUE ); - be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - } - } - - /* - * Before sending the MakeCurrent request - sync the - * X11 connection to the back-end servers to make sure - * that drawable is already created - */ - dmxSync( dmxScreen, 1 ); - - if (drawId == readId) { - LockDisplay(dpy); - GetReq(GLXMakeCurrent, be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXMakeCurrent; - be_req->drawable = be_draw; - be_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); - be_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); - if (!_XReply(dpy, (xReply *) &be_reply, 0, False)) { - - /* The make current failed */ - UnlockDisplay(dpy); - SyncHandle(); - return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); - } - - UnlockDisplay(dpy); - SyncHandle(); - - SetCurrentBackEndTag( cl, tag, s, be_reply.contextTag ); - } - else { - - if (pReadGlxPixmap) { - be_read_draw = pReadGlxPixmap->be_xids[s]; - } - else if (pGlxReadPbuffer) { - be_read_draw = pGlxReadPbuffer->be_xids[s]; - } -#ifdef PANORAMIX - else if (pXinReadDraw) { - dixLookupWindow(&pReadWin, pXinReadDraw->info[s].id, client, - DixReadAccess); - } -#endif - else if (pGlxReadWindow) { - pReadWin = (WindowPtr)pGlxReadWindow->pDraw; - } - - if (pReadWin && be_read_draw == None) { - be_read_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pReadWin))->window; - if (!be_read_draw) { - /* it might be that the window did not created yet on the */ - /* back-end server (lazy window creation option), force */ - /* creation of the window */ - dmxCreateAndRealizeWindow( pReadWin, TRUE ); - be_read_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pReadWin))->window; - dmxSync( dmxScreen, 1 ); - } - } - - if ( __GLX_IS_VERSION_SUPPORTED(1,3) ) { - LockDisplay(dpy); - GetReq(GLXMakeContextCurrent, be_new_req); - be_new_req->reqType = dmxScreen->glxMajorOpcode; - be_new_req->glxCode = X_GLXMakeContextCurrent; - be_new_req->drawable = be_draw; - be_new_req->readdrawable = be_read_draw; - be_new_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); - be_new_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); - if (!_XReply(dpy, (xReply *) &be_new_reply, 0, False)) { - - /* The make current failed */ - UnlockDisplay(dpy); - SyncHandle(); - return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); - } - - UnlockDisplay(dpy); - SyncHandle(); - - SetCurrentBackEndTag( cl, tag, s, be_new_reply.contextTag ); - } - else if (glxIsExtensionSupported("GLX_SGI_make_current_read")) { - xGLXMakeCurrentReadSGIReq *ext_req; - xGLXVendorPrivateWithReplyReq *vpreq; - xGLXMakeCurrentReadSGIReply ext_reply; - - LockDisplay(dpy); - GetReqExtra(GLXVendorPrivateWithReply, - sz_xGLXMakeCurrentReadSGIReq - sz_xGLXVendorPrivateWithReplyReq, - vpreq); - ext_req = (xGLXMakeCurrentReadSGIReq *)vpreq; - ext_req->reqType = dmxScreen->glxMajorOpcode; - ext_req->glxCode = X_GLXVendorPrivateWithReply; - ext_req->vendorCode = X_GLXvop_MakeCurrentReadSGI; - ext_req->drawable = be_draw; - ext_req->readable = be_read_draw; - ext_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); - ext_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); - if (!_XReply(dpy, (xReply *) &ext_reply, 0, False)) { - - /* The make current failed */ - UnlockDisplay(dpy); - SyncHandle(); - return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); - } - - UnlockDisplay(dpy); - SyncHandle(); - - SetCurrentBackEndTag( cl, tag, s, ext_reply.contextTag ); - - } - else { - return BadMatch; - } - } - - XFlush( dpy ); - } - - if (client->swapped) { - __glXSwapMakeCurrentReply(client, &new_reply); - } else { - WriteToClient(client, sz_xGLXMakeContextCurrentReply, (char *)&new_reply); - } - - return Success; -} - -int __glXMakeCurrent(__GLXclientState *cl, GLbyte *pc) -{ - xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc; - - return( MakeCurrent(cl, req->drawable, req->drawable, - req->context, req->oldContextTag ) ); -} - -int __glXMakeContextCurrent(__GLXclientState *cl, GLbyte *pc) -{ - xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) pc; - - return( MakeCurrent(cl, req->drawable, req->readdrawable, - req->context, req->oldContextTag ) ); -} - -int __glXMakeCurrentReadSGI(__GLXclientState *cl, GLbyte *pc) -{ - xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) pc; - - return( MakeCurrent(cl, req->drawable, req->readable, - req->context, req->oldContextTag ) ); -} - -int __glXIsDirect(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc; - xGLXIsDirectReply reply; - __GLXcontext *glxc; - - /* - ** Find the GL context. - */ - glxc = (__GLXcontext *) LookupIDByType(req->context, __glXContextRes); - if (!glxc) { - client->errorValue = req->context; - return __glXBadContext; - } - - reply.isDirect = 0; - reply.length = 0; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (client->swapped) { - __glXSwapIsDirectReply(client, &reply); - } else { - WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply); - } - - return Success; -} - -int __glXQueryVersion(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; -/* xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc; */ - xGLXQueryVersionReply reply; - - /* - ** Server should take into consideration the version numbers sent by the - ** client if it wants to work with older clients; however, in this - ** implementation the server just returns its version number. - */ - reply.majorVersion = __glXVersionMajor; - reply.minorVersion = __glXVersionMinor; - reply.length = 0; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (client->swapped) { - __glXSwapQueryVersionReply(client, &reply); - } else { - WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply); - } - return Success; -} - -int __glXWaitGL(__GLXclientState *cl, GLbyte *pc) -{ - xGLXWaitGLReq *req = (xGLXWaitGLReq *)pc; - xGLXWaitGLReq *be_req = (xGLXWaitGLReq *)pc; - int from_screen = 0; - int to_screen = 0; - int s; - __GLXcontext *glxc = NULL; - - if (req->contextTag != 0) { - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (glxc) { - from_screen = to_screen = glxc->pScreen->myNum; - } - } - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReq(GLXWaitGL,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXWaitGL; - be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); - UnlockDisplay(dpy); - SyncHandle(); - - XSync(dpy, False); - } - - return Success; -} - -int __glXWaitX(__GLXclientState *cl, GLbyte *pc) -{ - xGLXWaitXReq *req = (xGLXWaitXReq *)pc; - xGLXWaitXReq *be_req; - int from_screen = 0; - int to_screen = 0; - int s; - __GLXcontext *glxc = NULL; - - if (req->contextTag != 0) { - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (glxc) { - from_screen = to_screen = glxc->pScreen->myNum; - } - } - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReq(GLXWaitX,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXWaitX; - be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); - UnlockDisplay(dpy); - SyncHandle(); - - XFlush( dpy ); - } - - return Success; -} - -int __glXCopyContext(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXCopyContextReq *be_req; - xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc; - GLXContextID source = req->source; - GLXContextID dest = req->dest; - GLXContextTag tag = req->contextTag; - unsigned long mask = req->mask; - __GLXcontext *src, *dst; - int s; - int from_screen = 0; - int to_screen = 0; - - /* - ** Check that each context exists. - */ - src = (__GLXcontext *) LookupIDByType(source, __glXContextRes); - if (!src) { - client->errorValue = source; - return __glXBadContext; - } - dst = (__GLXcontext *) LookupIDByType(dest, __glXContextRes); - if (!dst) { - client->errorValue = dest; - return __glXBadContext; - } - - /* - ** They must be in the same address space, and same screen. - */ - if (src->pGlxScreen != dst->pGlxScreen) { - client->errorValue = source; - return BadMatch; - } - - /* - ** The destination context must not be current for any client. - */ - if (dst->isCurrent) { - client->errorValue = dest; - return BadAccess; - } - - if (tag) { - __GLXcontext *tagcx = __glXLookupContextByTag(cl, tag); - - if (!tagcx) { - return __glXBadContextTag; - } - if (tagcx != src) { - /* - ** This would be caused by a faulty implementation of the client - ** library. - */ - return BadMatch; - } - } - - from_screen = to_screen = src->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReq(GLXCopyContext,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXCopyContext; - be_req->source = (unsigned int)src->real_ids[s-from_screen]; - be_req->dest = (unsigned int)dst->real_ids[s-from_screen]; - be_req->mask = mask; - be_req->contextTag = (tag ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); - UnlockDisplay(dpy); - SyncHandle(); - } - - return Success; -} - -int __glXGetVisualConfigs(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) pc; - xGLXGetVisualConfigsReply reply; - __GLXscreenInfo *pGlxScreen; - __GLXvisualConfig *pGlxVisual; - CARD32 buf[__GLX_TOTAL_CONFIG]; - unsigned int screen; - int i, p; - - screen = req->screen; - if (screen > screenInfo.numScreens) { - /* The client library must send a valid screen number. */ - client->errorValue = screen; - return BadValue; - } - pGlxScreen = &__glXActiveScreens[screen]; - - reply.numVisuals = pGlxScreen->numGLXVisuals; - reply.numProps = __GLX_TOTAL_CONFIG; - reply.length = (pGlxScreen->numGLXVisuals * __GLX_SIZE_CARD32 * - __GLX_TOTAL_CONFIG) >> 2; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char *)&reply); - - for (i=0; i < pGlxScreen->numVisuals; i++) { - pGlxVisual = &pGlxScreen->pGlxVisual[i]; - if (!pGlxScreen->isGLXvis[i] || pGlxVisual->vid == 0) { - /* not a usable visual */ - continue; - } - p = 0; - buf[p++] = pGlxVisual->vid; - buf[p++] = pGlxVisual->class; - buf[p++] = pGlxVisual->rgba; - - buf[p++] = pGlxVisual->redSize; - buf[p++] = pGlxVisual->greenSize; - buf[p++] = pGlxVisual->blueSize; - buf[p++] = pGlxVisual->alphaSize; - buf[p++] = pGlxVisual->accumRedSize; - buf[p++] = pGlxVisual->accumGreenSize; - buf[p++] = pGlxVisual->accumBlueSize; - buf[p++] = pGlxVisual->accumAlphaSize; - - buf[p++] = pGlxVisual->doubleBuffer; - buf[p++] = pGlxVisual->stereo; - - buf[p++] = pGlxVisual->bufferSize; - buf[p++] = pGlxVisual->depthSize; - buf[p++] = pGlxVisual->stencilSize; - buf[p++] = pGlxVisual->auxBuffers; - buf[p++] = pGlxVisual->level; - /* - ** Add token/value pairs for extensions. - */ - buf[p++] = GLX_VISUAL_CAVEAT_EXT; - buf[p++] = pGlxVisual->visualRating; - buf[p++] = GLX_TRANSPARENT_TYPE_EXT; - buf[p++] = pGlxVisual->transparentPixel; - buf[p++] = GLX_TRANSPARENT_RED_VALUE_EXT; - buf[p++] = pGlxVisual->transparentRed; - buf[p++] = GLX_TRANSPARENT_GREEN_VALUE_EXT; - buf[p++] = pGlxVisual->transparentGreen; - buf[p++] = GLX_TRANSPARENT_BLUE_VALUE_EXT; - buf[p++] = pGlxVisual->transparentBlue; - buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE_EXT; - buf[p++] = pGlxVisual->transparentAlpha; - buf[p++] = GLX_TRANSPARENT_INDEX_VALUE_EXT; - buf[p++] = pGlxVisual->transparentIndex; - buf[p++] = GLX_SAMPLES_SGIS; - buf[p++] = pGlxVisual->multiSampleSize; - buf[p++] = GLX_SAMPLE_BUFFERS_SGIS; - buf[p++] = pGlxVisual->nMultiSampleBuffers; - buf[p++] = GLX_VISUAL_SELECT_GROUP_SGIX; - buf[p++] = pGlxVisual->visualSelectGroup; - - WriteToClient(client, __GLX_SIZE_CARD32 * __GLX_TOTAL_CONFIG, - (char *)buf); - } - return Success; -} - -/* -** Create a GLX Pixmap from an X Pixmap. -*/ -static int CreateGLXPixmap(__GLXclientState *cl, - VisualID visual, GLXFBConfigID fbconfigId, - int screenNum, XID pixmapId, XID glxpixmapId ) -{ - ClientPtr client = cl->client; - xGLXCreateGLXPixmapReq *be_req; - xGLXCreatePixmapReq *be_new_req; - DrawablePtr pDraw; - ScreenPtr pScreen; - VisualPtr pVisual; - __GLXpixmap *pGlxPixmap; - __GLXscreenInfo *pGlxScreen; - __GLXvisualConfig *pGlxVisual; - __GLXFBConfig *pFBConfig; - int i, s, rc; - int from_screen, to_screen; -#ifdef PANORAMIX - PanoramiXRes *pXinDraw = NULL; -#endif - - rc = dixLookupDrawable(&pDraw, pixmapId, client, M_DRAWABLE_PIXMAP, - DixAddAccess); - if (rc != Success) - return rc; - - /* - ** Check if screen of visual matches screen of pixmap. - */ - pScreen = pDraw->pScreen; - if (screenNum != pScreen->myNum) { - return BadMatch; - } - - if (fbconfigId == NULL && visual == NULL) { - return BadValue; - } - - if (fbconfigId != None) { - pFBConfig = glxLookupFBConfig( fbconfigId ); - if (!pFBConfig) { - client->errorValue = fbconfigId; - return BadValue; - } - visual = pFBConfig->associatedVisualId; - } - else { - pFBConfig = NULL; - } - - if (visual != None) { - /* - ** Find the VisualRec for this visual. - */ - pVisual = pScreen->visuals; - for (i=0; i < pScreen->numVisuals; i++, pVisual++) { - if (pVisual->vid == visual) { - break; - } - } - if (i == pScreen->numVisuals) { - client->errorValue = visual; - return BadValue; - } - /* - ** Check if depth of visual matches depth of pixmap. - */ - if (pVisual->nplanes != pDraw->depth) { - client->errorValue = visual; - return BadMatch; - } - - /* - ** Get configuration of the visual. - */ - pGlxScreen = &__glXActiveScreens[screenNum]; - pGlxVisual = pGlxScreen->pGlxVisual; - for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { - if (pGlxVisual->vid == visual) { - break; - } - } - if (i == pGlxScreen->numVisuals) { - /* - ** Visual not support on this screen by this OpenGL implementation. - */ - client->errorValue = visual; - return BadValue; - } - - - /* find the FBConfig for that visual (if any) */ - if ( pFBConfig == NULL ) { - pFBConfig = glxLookupFBConfigByVID( visual ); - - if ( pFBConfig == NULL ) { - /* - * visual does not have an FBConfig ??? - client->errorValue = visual; - return BadValue; - */ - } - } - } - else { - pVisual = NULL; - pGlxVisual = NULL; - } - - pGlxPixmap = (__GLXpixmap *) __glXMalloc(sizeof(__GLXpixmap)); - if (!pGlxPixmap) { - return BadAlloc; - } - pGlxPixmap->be_xids = (XID *) __glXMalloc(sizeof(XID) * screenInfo.numScreens); - if (!pGlxPixmap->be_xids) { - __glXFree( pGlxPixmap ); - return BadAlloc; - } - - pGlxPixmap->pDraw = pDraw; - pGlxPixmap->pGlxScreen = pGlxScreen; - pGlxPixmap->pGlxVisual = pGlxVisual; - pGlxPixmap->pFBConfig = pFBConfig; - pGlxPixmap->pScreen = pScreen; - pGlxPixmap->idExists = True; - pGlxPixmap->refcnt = 0; - - /* - ** Bump the ref count on the X pixmap so it won't disappear. - */ - ((PixmapPtr) pDraw)->refcnt++; - - /* - * send the request to the back-end server(s) - */ - from_screen = to_screen = screenNum; -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - - pXinDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - Pixmap be_pixmap; - DrawablePtr pRealDraw = pDraw; - -#ifdef PANORAMIX - if (pXinDraw) { - dixLookupDrawable(&pRealDraw, pXinDraw->info[s].id, client, 0, - DixAddAccess); - } -#endif - - be_pixmap = (DMX_GET_PIXMAP_PRIV((PixmapPtr)pRealDraw))->pixmap; - - /* make sure pixmap already created on back-end */ - dmxSync( dmxScreen, 1 ); - - if ( pFBConfig && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - __GLXFBConfig *be_FBConfig = glxLookupBackEndFBConfig( pFBConfig->id, s ); - - LockDisplay(dpy); - pGlxPixmap->be_xids[s] = XAllocID(dpy); - GetReq(GLXCreatePixmap,be_new_req); - be_new_req->reqType = dmxScreen->glxMajorOpcode; - be_new_req->glxCode = X_GLXCreatePixmap; - be_new_req->screen = DefaultScreen(dpy); - be_new_req->fbconfig = be_FBConfig->id; - be_new_req->pixmap = (unsigned int)be_pixmap; - be_new_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; - be_new_req->numAttribs = 0; - UnlockDisplay(dpy); - SyncHandle(); - } - else if (pFBConfig && glxIsExtensionSupported("GLX_SGIX_fbconfig")) { - __GLXFBConfig *be_FBConfig = glxLookupBackEndFBConfig( pFBConfig->id, s ); - xGLXCreateGLXPixmapWithConfigSGIXReq *ext_req; - xGLXVendorPrivateReq *vpreq; - - LockDisplay(dpy); - pGlxPixmap->be_xids[s] = XAllocID(dpy); - GetReqExtra(GLXVendorPrivate, - sz_xGLXCreateGLXPixmapWithConfigSGIXReq-sz_xGLXVendorPrivateReq, - vpreq); - ext_req = (xGLXCreateGLXPixmapWithConfigSGIXReq *)vpreq; - ext_req->reqType = dmxScreen->glxMajorOpcode; - ext_req->glxCode = X_GLXVendorPrivate; - ext_req->vendorCode = X_GLXvop_CreateGLXPixmapWithConfigSGIX; - ext_req->screen = DefaultScreen(dpy); - ext_req->fbconfig = be_FBConfig->id; - ext_req->pixmap = (unsigned int)be_pixmap; - ext_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; - UnlockDisplay(dpy); - SyncHandle(); - } - else if (pGlxVisual) { - LockDisplay(dpy); - pGlxPixmap->be_xids[s] = XAllocID(dpy); - GetReq(GLXCreateGLXPixmap,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXCreateGLXPixmap; - be_req->screen = DefaultScreen(dpy); - be_req->visual = (unsigned int)glxMatchGLXVisualInConfigList( - pGlxVisual, - dmxScreen->glxVisuals, - dmxScreen->numGlxVisuals ); - be_req->pixmap = (unsigned int)be_pixmap; - be_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; - UnlockDisplay(dpy); - SyncHandle(); - } - else { - client->errorValue = ( visual ? visual : fbconfigId ); - __glXFree( pGlxPixmap ); - return BadValue; - } - - XFlush( dpy ); - } - - if (!(AddResource(glxpixmapId, __glXPixmapRes, pGlxPixmap))) { - __glXFree( pGlxPixmap ); - return BadAlloc; - } - - return Success; -} - -int __glXCreateGLXPixmap(__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateGLXPixmapReq *req = (xGLXCreateGLXPixmapReq *) pc; - - return( CreateGLXPixmap(cl, req->visual, None, - req->screen, req->pixmap, req->glxpixmap) ); -} - -int __glXCreatePixmap(__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreatePixmapReq *req = (xGLXCreatePixmapReq *) pc; - - return( CreateGLXPixmap(cl, None, req->fbconfig, - req->screen, req->pixmap, req->glxpixmap) ); -} - -int __glXDestroyGLXPixmap(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc; - XID glxpixmap = req->glxpixmap; - __GLXpixmap *pGlxPixmap; - int s; - int from_screen, to_screen; - - /* - ** Check if it's a valid GLX pixmap. - */ - pGlxPixmap = (__GLXpixmap *)LookupIDByType(glxpixmap, __glXPixmapRes); - if (!pGlxPixmap) { - client->errorValue = glxpixmap; - return __glXBadPixmap; - } - FreeResource(glxpixmap, FALSE); - - /* - * destroy the pixmap on the back-end server(s). - */ - from_screen = to_screen = pGlxPixmap->pDraw->pScreen->myNum; -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - /* make sure pixmap exist in back-end */ - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReq(GLXDestroyGLXPixmap,req); - req->reqType = dmxScreen->glxMajorOpcode; - req->glxCode = X_GLXDestroyGLXPixmap; - req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; - UnlockDisplay(dpy); - SyncHandle(); - } - - - return Success; -} - -/*****************************************************************************/ - -/* -** NOTE: There is no portable implementation for swap buffers as of -** this time that is of value. Consequently, this code must be -** implemented by somebody other than SGI. -*/ -int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag) -{ - ClientPtr client = cl->client; - DrawablePtr pDraw; - xGLXSwapBuffersReq *be_req; - WindowPtr pWin = NULL; - __GLXpixmap *pGlxPixmap = NULL; - __GLXcontext *glxc = NULL; -#ifdef PANORAMIX - PanoramiXRes *pXinDraw = NULL; -#endif - __glXWindow *pGlxWindow = NULL; - int from_screen = 0; - int to_screen = 0; - int s, rc; - - /* - ** Check that the GLX drawable is valid. - */ - rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); - if (rc == Success) { - from_screen = to_screen = pDraw->pScreen->myNum; - - if (pDraw->type == DRAWABLE_WINDOW) { - /* - ** Drawable is an X window. - */ - pWin = (WindowPtr)pDraw; - } else { - /* - ** Drawable is an X pixmap, which is not allowed. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - if (!pDraw) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, - __glXPixmapRes); - if (pGlxPixmap) { - /* - ** Drawable is a GLX pixmap. - */ - pDraw = pGlxPixmap->pDraw; - from_screen = to_screen = pGlxPixmap->pScreen->myNum; - } - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); - if (pGlxWindow) { - /* - ** Drawable is a GLXWindow. - */ - pDraw = pGlxWindow->pDraw; - from_screen = to_screen = pGlxWindow->pScreen->myNum; - } - } - - if (!pDraw) { - /* - ** Drawable is neither a X window nor a GLX pixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - - if (tag) { - glxc = __glXLookupContextByTag(cl, tag); - if (!glxc) { - return __glXBadContextTag; - } - } - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - pXinDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); - } -#endif - - /* If requested, send a glFinish to all back-end servers before swapping. */ - if (dmxGLXFinishSwap) { - for (s=from_screen; s<=to_screen; s++) { - Display *dpy = GetBackEndDisplay(cl,s); - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - xGLXSingleReq *finishReq; - xGLXSingleReply reply; - -#define X_GLXSingle 0 /* needed by GetReq below */ - - LockDisplay(dpy); - GetReq(GLXSingle,finishReq); - finishReq->reqType = dmxScreen->glxMajorOpcode; - finishReq->glxCode = X_GLsop_Finish; - finishReq->contextTag = (tag ? GetCurrentBackEndTag(cl,tag,s) : 0); - (void) _XReply(dpy, (xReply*) &reply, 0, False); - UnlockDisplay(dpy); - SyncHandle(); - } - } - - /* If requested, send an XSync to all back-end servers before swapping. */ - if (dmxGLXSyncSwap) { - for (s=from_screen; s<=to_screen; s++) - XSync(GetBackEndDisplay(cl,s), False); - } - - - /* send the SwapBuffers request to all back-end servers */ - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - unsigned int be_draw = 0; - - if (pGlxPixmap) { - be_draw = (unsigned int)pGlxPixmap->be_xids[s]; - } -#ifdef PANORAMIX - else if (pXinDraw) { - dixLookupWindow(&pWin, pXinDraw->info[s].id, client, DixReadAccess); - } -#endif - else if (pGlxWindow) { - pWin = (WindowPtr)pGlxWindow->pDraw; - } - - if (pWin && !be_draw) { - be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - if (!be_draw) { - /* it might be that the window did not created yet on the */ - /* back-end server (lazy window creation option), force */ - /* creation of the window */ - dmxCreateAndRealizeWindow( pWin, TRUE ); - be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - } - } - - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReq(GLXSwapBuffers,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXSwapBuffers; - be_req->drawable = be_draw; - be_req->contextTag = ( tag ? GetCurrentBackEndTag(cl,tag,s) : 0 ); - UnlockDisplay(dpy); - SyncHandle(); - XFlush(dpy); - } - - return Success; -} - -int __glXSwapBuffers(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - DrawablePtr pDraw; - xGLXSwapBuffersReq *req = (xGLXSwapBuffersReq *) pc; - GLXContextTag tag = req->contextTag; - XID drawId = req->drawable; - __GLXpixmap *pGlxPixmap = NULL; - __GLXcontext *glxc = NULL; - __glXWindow *pGlxWindow = NULL; - int rc; - - /* - ** Check that the GLX drawable is valid. - */ - rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); - if (rc == Success) { - if (pDraw->type != DRAWABLE_WINDOW) { - /* - ** Drawable is an X pixmap, which is not allowed. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - if (!pDraw) { - pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, - __glXPixmapRes); - if (pGlxPixmap) { - /* - ** Drawable is a GLX pixmap. - */ - pDraw = pGlxPixmap->pDraw; - } - } - - if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { - pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); - if (pGlxWindow) { - /* - ** Drawable is a GLXWindow. - */ - pDraw = pGlxWindow->pDraw; - } - } - - if (!pDraw) { - /* - ** Drawable is neither a X window nor a GLX pixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - - if (tag) { - glxc = __glXLookupContextByTag(cl, tag); - if (!glxc) { - return __glXBadContextTag; - } - } - - if (pDraw && - pDraw->type == DRAWABLE_WINDOW && - DMX_GET_WINDOW_PRIV((WindowPtr)pDraw)->swapGroup) { - return SGSwapBuffers(cl, drawId, tag, pDraw); - } - - return __glXDoSwapBuffers(cl, drawId, tag); -} - - -/************************************************************************/ - -/* -** Render and Renderlarge are not in the GLX API. They are used by the GLX -** client library to send batches of GL rendering commands. -*/ - -/* -** Execute all the drawing commands in a request. -*/ -int __glXRender(__GLXclientState *cl, GLbyte *pc) -{ - xGLXRenderReq *req; - xGLXRenderReq *be_req; - int size; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - int s; - - /* - ** NOTE: much of this code also appears in the byteswapping version of this - ** routine, __glXSwapRender(). Any changes made here should also be - ** duplicated there. - */ - - req = (xGLXRenderReq *) pc; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXRenderReq; - size = (req->length << 2) - sz_xGLXRenderReq; - - /* - * just forward the request to back-end server(s) - */ - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReq(GLXRender,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXRender; - be_req->length = req->length; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - _XSend(dpy, (const char *)pc, size); - UnlockDisplay(dpy); - SyncHandle(); - } - - return Success; -} - -/* -** Execute a large rendering request (one that spans multiple X requests). -*/ -int __glXRenderLarge(__GLXclientState *cl, GLbyte *pc) -{ - xGLXRenderLargeReq *req; - xGLXRenderLargeReq *be_req; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - int s; - - /* - ** NOTE: much of this code also appears in the byteswapping version of this - ** routine, __glXSwapRenderLarge(). Any changes made here should also be - ** duplicated there. - */ - - req = (xGLXRenderLargeReq *) pc; - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXRenderLargeReq; - - /* - * just forward the request to back-end server(s) - */ - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - GetReq(GLXRenderLarge,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXRenderLarge; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - be_req->length = req->length; - be_req->requestNumber = req->requestNumber; - be_req->requestTotal = req->requestTotal; - be_req->dataBytes = req->dataBytes; - Data(dpy, (const char *)pc, req->dataBytes); - UnlockDisplay(dpy); - SyncHandle(); - - } - - return Success; -} - - -/************************************************************************/ - -int __glXVendorPrivate(__GLXclientState *cl, GLbyte *pc) -{ - xGLXVendorPrivateReq *req; - - req = (xGLXVendorPrivateReq *) pc; - - switch( req->vendorCode ) { - - case X_GLvop_DeleteTexturesEXT: - return __glXVForwardSingleReq( cl, pc ); - break; - - case X_GLXvop_SwapIntervalSGI: - if (glxIsExtensionSupported("SGI_swap_control")) { - return __glXVForwardSingleReq( cl, pc ); - } - else { - return Success; - } - break; - -#if 0 /* glx 1.3 */ - case X_GLXvop_CreateGLXVideoSourceSGIX: - break; - case X_GLXvop_DestroyGLXVideoSourceSGIX: - break; - case X_GLXvop_CreateGLXPixmapWithConfigSGIX: - break; - case X_GLXvop_DestroyGLXPbufferSGIX: - break; - case X_GLXvop_ChangeDrawableAttributesSGIX: - break; -#endif - - case X_GLXvop_BindSwapBarrierSGIX: - return __glXBindSwapBarrierSGIX( cl, pc ); - break; - - case X_GLXvop_JoinSwapGroupSGIX: - return __glXJoinSwapGroupSGIX( cl, pc ); - break; - - case X_GLXvop_CreateContextWithConfigSGIX: - return __glXCreateContextWithConfigSGIX( cl, pc ); - break; - - default: - /* - ** unsupported private request - */ - cl->client->errorValue = req->vendorCode; - return __glXUnsupportedPrivateRequest; - } - - cl->client->errorValue = req->vendorCode; - return __glXUnsupportedPrivateRequest; - -} - -int __glXVendorPrivateWithReply(__GLXclientState *cl, GLbyte *pc) -{ - xGLXVendorPrivateWithReplyReq *req; - - req = (xGLXVendorPrivateWithReplyReq *) pc; - - switch( req->vendorCode ) { - - case X_GLvop_GetConvolutionFilterEXT: - case X_GLvop_GetConvolutionParameterfvEXT: - case X_GLvop_GetConvolutionParameterivEXT: - case X_GLvop_GetSeparableFilterEXT: - case X_GLvop_GetHistogramEXT: - case X_GLvop_GetHistogramParameterivEXT: - case X_GLvop_GetMinmaxEXT: - case X_GLvop_GetMinmaxParameterfvEXT: - case X_GLvop_GetMinmaxParameterivEXT: - case X_GLvop_AreTexturesResidentEXT: - case X_GLvop_IsTextureEXT: - return( __glXVForwardPipe0WithReply(cl, pc) ); - break; - - case X_GLvop_GenTexturesEXT: - return( __glXVForwardAllWithReply(cl, pc) ); - break; - - -#if 0 /* glx1.3 */ - case X_GLvop_GetDetailTexFuncSGIS: - case X_GLvop_GetSharpenTexFuncSGIS: - case X_GLvop_GetColorTableSGI: - case X_GLvop_GetColorTableParameterfvSGI: - case X_GLvop_GetColorTableParameterivSGI: - case X_GLvop_GetTexFilterFuncSGIS: - case X_GLvop_GetInstrumentsSGIX: - case X_GLvop_InstrumentsBufferSGIX: - case X_GLvop_PollInstrumentsSGIX: - case X_GLvop_FlushRasterSGIX: - case X_GLXvop_CreateGLXPbufferSGIX: - case X_GLXvop_GetDrawableAttributesSGIX: - case X_GLXvop_QueryHyperpipeNetworkSGIX: - case X_GLXvop_QueryHyperpipeConfigSGIX: - case X_GLXvop_HyperpipeConfigSGIX: - case X_GLXvop_DestroyHyperpipeConfigSGIX: -#endif - case X_GLXvop_QueryMaxSwapBarriersSGIX: - return( __glXQueryMaxSwapBarriersSGIX(cl, pc) ); - break; - - case X_GLXvop_GetFBConfigsSGIX: - return( __glXGetFBConfigsSGIX(cl, pc) ); - break; - - case X_GLXvop_MakeCurrentReadSGI: - return( __glXMakeCurrentReadSGI(cl, pc) ); - break; - - case X_GLXvop_QueryContextInfoEXT: - return( __glXQueryContextInfoEXT(cl,pc) ); - break; - - default: - /* - ** unsupported private request - */ - cl->client->errorValue = req->vendorCode; - return __glXUnsupportedPrivateRequest; - } - -} - -int __glXQueryExtensionsString(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXQueryExtensionsStringReq *req = (xGLXQueryExtensionsStringReq *) pc; - xGLXQueryExtensionsStringReply reply; - GLint screen; - size_t length; - int len, numbytes; - char *be_buf; - -#ifdef FWD_QUERY_REQ - xGLXQueryExtensionsStringReq *be_req; - xGLXQueryExtensionsStringReply be_reply; - DMXScreenInfo *dmxScreen; - Display *dpy; - int slop; -#endif - - screen = req->screen; - - /* - ** Check if screen exists. - */ - if ((screen < 0) || (screen >= screenInfo.numScreens)) { - client->errorValue = screen; - return BadValue; - } - -#ifdef FWD_QUERY_REQ - dmxScreen = &dmxScreens[screen]; - - /* Send the glXQueryServerString request */ - dpy = GetBackEndDisplay(cl,screen); - LockDisplay(dpy); - GetReq(GLXQueryExtensionsString,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXQueryServerString; - be_req->screen = DefaultScreen(dpy); - _XReply(dpy, (xReply*) &be_reply, 0, False); - len = (int)be_reply.length; - numbytes = (int)be_reply.n; - slop = numbytes * __GLX_SIZE_INT8 & 3; - be_buf = (char *)Xalloc(numbytes); - if (!be_buf) { - /* Throw data on the floor */ - _XEatData(dpy, len); - } else { - _XRead(dpy, (char *)be_buf, numbytes); - if (slop) _XEatData(dpy,4-slop); - } - UnlockDisplay(dpy); - SyncHandle(); - -#else - - be_buf = __glXGetServerString(GLX_EXTENSIONS); - numbytes = strlen(be_buf) + 1; - len = __GLX_PAD(numbytes) >> 2; - -#endif - - length = len; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = len; - reply.n = numbytes; - - if (client->swapped) { - glxSwapQueryExtensionsStringReply(client, &reply, be_buf); - } else { - WriteToClient(client, sz_xGLXQueryExtensionsStringReply,(char *)&reply); - WriteToClient(client, (int)(length << 2), (char *)be_buf); - } - - return Success; -} - -int __glXQueryServerString(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) pc; - xGLXQueryServerStringReply reply; - int name; - GLint screen; - size_t length; - int len, numbytes; - char *be_buf; -#ifdef FWD_QUERY_REQ - xGLXQueryServerStringReq *be_req; - xGLXQueryServerStringReply be_reply; - DMXScreenInfo *dmxScreen; - Display *dpy; - int slop; -#endif - - name = req->name; - screen = req->screen; - /* - ** Check if screen exists. - */ - if ((screen < 0) || (screen >= screenInfo.numScreens)) { - client->errorValue = screen; - return BadValue; - } - -#ifdef FWD_QUERY_REQ - dmxScreen = &dmxScreens[screen]; - - /* Send the glXQueryServerString request */ - dpy = GetBackEndDisplay(cl,screen); - LockDisplay(dpy); - GetReq(GLXQueryServerString,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXQueryServerString; - be_req->screen = DefaultScreen(dpy); - be_req->name = name; - _XReply(dpy, (xReply*) &be_reply, 0, False); - len = (int)be_reply.length; - numbytes = (int)be_reply.n; - slop = numbytes * __GLX_SIZE_INT8 & 3; - be_buf = (char *)Xalloc(numbytes); - if (!be_buf) { - /* Throw data on the floor */ - _XEatData(dpy, len); - } else { - _XRead(dpy, (char *)be_buf, numbytes); - if (slop) _XEatData(dpy,4-slop); - } - UnlockDisplay(dpy); - SyncHandle(); - -#else - be_buf = __glXGetServerString(name); - numbytes = strlen(be_buf) + 1; - len = __GLX_PAD(numbytes) >> 2; -#endif - - length = len; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = length; - reply.n = numbytes; - - if (client->swapped) { - glxSwapQueryServerStringReply(client, &reply, be_buf); - } else { - WriteToClient(client, sz_xGLXQueryServerStringReply, (char *)&reply); - WriteToClient(client, (int)(length << 2), be_buf); - } - - return Success; -} - -int __glXClientInfo(__GLXclientState *cl, GLbyte *pc) -{ - xGLXClientInfoReq *req = (xGLXClientInfoReq *) pc; - xGLXClientInfoReq *be_req; - const char *buf; - int from_screen = 0; - int to_screen = 0; - int s; - - cl->GLClientmajorVersion = req->major; - cl->GLClientminorVersion = req->minor; - if (cl->GLClientextensions) __glXFree(cl->GLClientextensions); - buf = (const char *)(req+1); - cl->GLClientextensions = strdup(buf); - - to_screen = screenInfo.numScreens - 1; - - for (s=from_screen; s<=to_screen; s++) - { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReq(GLXClientInfo,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXClientInfo; - be_req->major = req->major; - be_req->minor = req->minor; - be_req->length = req->length; - be_req->numbytes = req->numbytes; - Data(dpy, buf, req->numbytes); - - UnlockDisplay(dpy); - SyncHandle(); - } - - return Success; -} - -int __glXUseXFont(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXUseXFontReq *req; - xGLXUseXFontReq *be_req; - FontPtr pFont; - __GLXcontext *glxc = NULL; - int from_screen = 0; - int to_screen = 0; - int s; - dmxFontPrivPtr pFontPriv; - DMXScreenInfo *dmxScreen; - Display *dpy; - - req = (xGLXUseXFontReq *) pc; - - if (req->contextTag != 0) { - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (glxc) { - from_screen = to_screen = glxc->pScreen->myNum; - } - } - - /* - ** Font can actually be either the ID of a font or the ID of a GC - ** containing a font. - */ - pFont = (FontPtr)LookupIDByType(req->font, RT_FONT); - if (!pFont) { - GC *pGC = (GC *)LookupIDByType(req->font, RT_GC); - if (!pGC) { - client->errorValue = req->font; - return BadFont; - } - pFont = pGC->font; - } - - pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - - for (s=from_screen; s<=to_screen; s++) { - dmxScreen = &dmxScreens[s]; - dpy = GetBackEndDisplay(cl,s); - - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReq(GLXUseXFont,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXUseXFont; - be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); - be_req->font = pFontPriv->font[s]->fid; - be_req->first = req->first; - be_req->count = req->count; - be_req->listBase = req->listBase; - UnlockDisplay(dpy); - SyncHandle(); - - XSync( dpy, False ); - } - - return Success; -} - -/* - * start GLX 1.3 here - */ - -int __glXGetFBConfigs(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXGetFBConfigsReq *req = (xGLXGetFBConfigsReq *) pc; - xGLXGetFBConfigsReply reply; - __GLXFBConfig *pFBConfig; - CARD32 buf[2 * __GLX_TOTAL_FBCONFIG_PROPS]; - int numAttribs = __GLX_TOTAL_FBCONFIG_PROPS; - unsigned int screen = req->screen; - int numFBConfigs, i, p; - __GLXscreenInfo *pGlxScreen; - - if (screen > screenInfo.numScreens) { - /* The client library must send a valid screen number. */ - client->errorValue = screen; - return BadValue; - } - - pGlxScreen = &__glXActiveScreens[screen]; - numFBConfigs = __glXNumFBConfigs; - - reply.numFBConfigs = numFBConfigs; - reply.numAttribs = numAttribs; - reply.length = (numFBConfigs * 2 * numAttribs * __GLX_SIZE_CARD32) >> 2; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (client->swapped) { - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - __GLX_SWAP_INT(&reply.numFBConfigs); - __GLX_SWAP_INT(&reply.numAttribs); - } - WriteToClient(client, sz_xGLXGetFBConfigsReply, (char *)&reply); - - for (i=0; i < numFBConfigs; i++) { - int associatedVisualId = 0; - int drawableTypeIndex; - pFBConfig = __glXFBConfigs[ i * (screenInfo.numScreens+1) ]; - - p = 0; - /* core attributes */ - buf[p++] = GLX_FBCONFIG_ID; - buf[p++] = pFBConfig->id; - buf[p++] = GLX_BUFFER_SIZE; - buf[p++] = pFBConfig->indexBits; - buf[p++] = GLX_LEVEL; - buf[p++] = pFBConfig->level; - buf[p++] = GLX_DOUBLEBUFFER; - buf[p++] = pFBConfig->doubleBufferMode; - buf[p++] = GLX_STEREO; - buf[p++] = pFBConfig->stereoMode; - buf[p++] = GLX_AUX_BUFFERS; - buf[p++] = pFBConfig->maxAuxBuffers; - buf[p++] = GLX_RED_SIZE; - buf[p++] = pFBConfig->redBits; - buf[p++] = GLX_GREEN_SIZE; - buf[p++] = pFBConfig->greenBits; - buf[p++] = GLX_BLUE_SIZE; - buf[p++] = pFBConfig->blueBits; - buf[p++] = GLX_ALPHA_SIZE; - buf[p++] = pFBConfig->alphaBits; - buf[p++] = GLX_DEPTH_SIZE; - buf[p++] = pFBConfig->depthBits; - buf[p++] = GLX_STENCIL_SIZE; - buf[p++] = pFBConfig->stencilBits; - buf[p++] = GLX_ACCUM_RED_SIZE; - buf[p++] = pFBConfig->accumRedBits; - buf[p++] = GLX_ACCUM_GREEN_SIZE; - buf[p++] = pFBConfig->accumGreenBits; - buf[p++] = GLX_ACCUM_BLUE_SIZE; - buf[p++] = pFBConfig->accumBlueBits; - buf[p++] = GLX_ACCUM_ALPHA_SIZE; - buf[p++] = pFBConfig->accumAlphaBits; - buf[p++] = GLX_RENDER_TYPE; - buf[p++] = pFBConfig->renderType; - buf[p++] = GLX_DRAWABLE_TYPE; - drawableTypeIndex = p; - buf[p++] = pFBConfig->drawableType; - buf[p++] = GLX_X_VISUAL_TYPE; - buf[p++] = pFBConfig->visualType; - buf[p++] = GLX_CONFIG_CAVEAT; - buf[p++] = pFBConfig->visualCaveat; - buf[p++] = GLX_TRANSPARENT_TYPE; - buf[p++] = pFBConfig->transparentType; - buf[p++] = GLX_TRANSPARENT_RED_VALUE; - buf[p++] = pFBConfig->transparentRed; - buf[p++] = GLX_TRANSPARENT_GREEN_VALUE; - buf[p++] = pFBConfig->transparentGreen; - buf[p++] = GLX_TRANSPARENT_BLUE_VALUE; - buf[p++] = pFBConfig->transparentBlue; - buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE; - buf[p++] = pFBConfig->transparentAlpha; - buf[p++] = GLX_TRANSPARENT_INDEX_VALUE; - buf[p++] = pFBConfig->transparentIndex; - buf[p++] = GLX_MAX_PBUFFER_WIDTH; - buf[p++] = pFBConfig->maxPbufferWidth; - buf[p++] = GLX_MAX_PBUFFER_HEIGHT; - buf[p++] = pFBConfig->maxPbufferHeight; - buf[p++] = GLX_MAX_PBUFFER_PIXELS; - buf[p++] = pFBConfig->maxPbufferPixels; - - /* - * find the visual of the back-end server and match a visual - * on the proxy. - * do only once - if a visual is not yet associated. - */ - if (pFBConfig->associatedVisualId == (unsigned int)-1) { - DMXScreenInfo *dmxScreen = &dmxScreens[screen]; - __GLXFBConfig *be_pFBConfig = __glXFBConfigs[ i * (screenInfo.numScreens+1)+screen+1 ]; - __GLXvisualConfig *pGlxVisual = NULL; - int v; - int found = 0; - for (v=0; v<dmxScreen->numGlxVisuals; v++) { - if (dmxScreen->glxVisuals[v].vid == be_pFBConfig->associatedVisualId) { - pGlxVisual = &dmxScreen->glxVisuals[v]; - break; - } - } - - if (pGlxVisual) { - for (v=0; v<pGlxScreen->numVisuals; v++) { - if (glxVisualsMatch(&pGlxScreen->pGlxVisual[v], pGlxVisual)) { - associatedVisualId = pGlxScreen->pGlxVisual[v].vid; - found = 1; - break; - } - } - } - - if (!found) { - associatedVisualId = 0; - pFBConfig->drawableType &= ~(GLX_WINDOW_BIT); - buf[drawableTypeIndex] = pFBConfig->drawableType; - } -#ifdef PANORAMIX - else if (!noPanoramiXExtension) { - /* convert the associated visualId to the panoramix one */ - pFBConfig->associatedVisualId = - PanoramiXTranslateVisualID(screen, v); - } -#endif - } - else { - associatedVisualId = pFBConfig->associatedVisualId; - } - - buf[p++] = GLX_VISUAL_ID; - buf[p++] = associatedVisualId; - - /* SGIS_multisample attributes */ - buf[p++] = GLX_SAMPLES_SGIS; - buf[p++] = pFBConfig->multiSampleSize; - buf[p++] = GLX_SAMPLE_BUFFERS_SGIS; - buf[p++] = pFBConfig->nMultiSampleBuffers; - - /* SGIX_pbuffer specific attributes */ - buf[p++] = GLX_OPTIMAL_PBUFFER_WIDTH_SGIX; - buf[p++] = pFBConfig->optimalPbufferWidth; - buf[p++] = GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX; - buf[p++] = pFBConfig->optimalPbufferHeight; - - buf[p++] = GLX_VISUAL_SELECT_GROUP_SGIX; - buf[p++] = pFBConfig->visualSelectGroup; - - if (client->swapped) { - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_SWAP_INT_ARRAY((int *)buf, 2*numAttribs); - } - WriteToClient(client, 2*numAttribs * __GLX_SIZE_CARD32, (char *)buf); - } - return Success; -} - -int __glXGetFBConfigsSGIX(__GLXclientState *cl, GLbyte *pc) -{ - xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *)pc; - xGLXGetFBConfigsReq new_req; - - new_req.reqType = req->reqType; - new_req.glxCode = req->glxCode; - new_req.length = req->length; - new_req.screen = req->screen; - - return( __glXGetFBConfigs( cl, (GLbyte *)&new_req ) ); -} - - -int __glXCreateWindow(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXCreateWindowReq *req = (xGLXCreateWindowReq *) pc; - int screen = req->screen; - GLXFBConfigID fbconfigId = req->fbconfig; - XID windowId = req->window; - XID glxwindowId = req->glxwindow; - DrawablePtr pDraw; - ScreenPtr pScreen; - __glXWindow *pGlxWindow; - __GLXFBConfig *pGlxFBConfig = NULL; - VisualPtr pVisual; - VisualID visId; - int i, rc; - - /* - ** Check if windowId is valid - */ - rc = dixLookupDrawable(&pDraw, windowId, client, M_DRAWABLE_WINDOW, - DixAddAccess); - if (rc != Success) - return rc; - - /* - ** Check if screen of window matches screen of fbconfig. - */ - pScreen = pDraw->pScreen; - if (screen != pScreen->myNum) { - return BadMatch; - } - - /* - ** Find the FBConfigRec for this fbconfigid. - */ - if (!(pGlxFBConfig = glxLookupFBConfig(fbconfigId))) { - client->errorValue = fbconfigId; - return __glXBadFBConfig; - } - visId = pGlxFBConfig->associatedVisualId; - - /* - ** Check if the fbconfig supports rendering to windows - */ - if( !(pGlxFBConfig->drawableType & GLX_WINDOW_BIT) ) { - return BadMatch; - } - - if (visId != None) { - /* - ** Check if the visual ID is valid for this screen. - */ - pVisual = pScreen->visuals; - for (i = 0; i < pScreen->numVisuals; i++, pVisual++) { - if (pVisual->vid == visId) { - break; - } - } - if (i == pScreen->numVisuals) { - client->errorValue = visId; - return BadValue; - } - - /* - ** Check if color buffer depth of fbconfig matches depth - ** of window. - */ - if (pVisual->nplanes != pDraw->depth) { - return BadMatch; - } - } else - /* - ** The window was created with no visual that corresponds - ** to fbconfig - */ - return BadMatch; - - /* - ** Check if there is already a fbconfig associated with this window - */ - if ( LookupIDByType(glxwindowId, __glXWindowRes) ) { - client->errorValue = glxwindowId; - return BadAlloc; - } - - pGlxWindow = (__glXWindow *) xalloc(sizeof(__glXWindow)); - if (!pGlxWindow) { - return BadAlloc; - } - - /* - ** Register this GLX window as a resource - */ - if (!(AddResource(glxwindowId, __glXWindowRes, pGlxWindow))) { - return BadAlloc; - } - - pGlxWindow->pDraw = pDraw; - pGlxWindow->type = GLX_GLXWINDOW_TYPE; - pGlxWindow->idExists = True; - pGlxWindow->refcnt = 0; - pGlxWindow->pGlxFBConfig = pGlxFBConfig; - pGlxWindow->pScreen = pScreen; - - return Success; -} - -int __glXDestroyWindow(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXDestroyWindowReq *req = (xGLXDestroyWindowReq *) pc; - XID glxwindow = req->glxwindow; - - /* - ** Check if it's a valid GLX window. - */ - if (!LookupIDByType(glxwindow, __glXWindowRes)) { - client->errorValue = glxwindow; - return __glXBadDrawable; - } - /* - ** The glx window destructor will check whether it's current before - ** freeing anything. - */ - FreeResource(glxwindow, RT_NONE); - - return Success; -} - -int __glXQueryContext(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - __GLXcontext *ctx; - xGLXQueryContextReq *req; - xGLXQueryContextReply reply; - int nProps; - int *sendBuf, *pSendBuf; - int nReplyBytes; - - req = (xGLXQueryContextReq *)pc; - ctx = (__GLXcontext *) LookupIDByType(req->context, __glXContextRes); - if (!ctx) { - client->errorValue = req->context; - return __glXBadContext; - } - - nProps = 3; - - reply.length = nProps << 1; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.n = nProps; - - nReplyBytes = reply.length << 2; - sendBuf = (int *)xalloc(nReplyBytes); - pSendBuf = sendBuf; - *pSendBuf++ = GLX_FBCONFIG_ID; - *pSendBuf++ = (int)(ctx->pFBConfig->id); - *pSendBuf++ = GLX_RENDER_TYPE; - *pSendBuf++ = (int)(ctx->pFBConfig->renderType); - *pSendBuf++ = GLX_SCREEN; - *pSendBuf++ = (int)(ctx->pScreen->myNum); - - if (client->swapped) { - __glXSwapQueryContextReply(client, &reply, sendBuf); - } else { - WriteToClient(client, sz_xGLXQueryContextReply, (char *)&reply); - WriteToClient(client, nReplyBytes, (char *)sendBuf); - } - xfree((char *)sendBuf); - - return Success; -} - -int __glXQueryContextInfoEXT(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - __GLXcontext *ctx; - xGLXQueryContextInfoEXTReq *req; - xGLXQueryContextInfoEXTReply reply; - int nProps; - int *sendBuf, *pSendBuf; - int nReplyBytes; - - req = (xGLXQueryContextInfoEXTReq *)pc; - ctx = (__GLXcontext *) SecurityLookupIDByType(client, req->context, __glXContextRes, DixReadAccess); - if (!ctx) { - client->errorValue = req->context; - return __glXBadContext; - } - - nProps = 4; - - reply.length = nProps << 1; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.n = nProps; - - nReplyBytes = reply.length << 2; - sendBuf = (int *)xalloc(nReplyBytes); - pSendBuf = sendBuf; - *pSendBuf++ = GLX_SHARE_CONTEXT_EXT; - *pSendBuf++ = (int)(ctx->share_id); - *pSendBuf++ = GLX_VISUAL_ID_EXT; - *pSendBuf++ = (int)(ctx->pVisual ? ctx->pVisual->vid : 0); - *pSendBuf++ = GLX_SCREEN_EXT; - *pSendBuf++ = (int)(ctx->pScreen->myNum); - *pSendBuf++ = GLX_FBCONFIG_ID; - *pSendBuf++ = (int)(ctx->pFBConfig ? ctx->pFBConfig->id : 0); - - if (client->swapped) { - __glXSwapQueryContextInfoEXTReply(client, &reply, sendBuf); - } else { - WriteToClient(client, sz_xGLXQueryContextInfoEXTReply, (char *)&reply); - WriteToClient(client, nReplyBytes, (char *)sendBuf); - } - xfree((char *)sendBuf); - - return Success; -} - -int __glXCreatePbuffer(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXCreatePbufferReq *req = (xGLXCreatePbufferReq *)pc; - xGLXCreatePbufferReq *be_req; - int screen = req->screen; - GLXFBConfigID fbconfigId = req->fbconfig; - GLXPbuffer pbuffer = req->pbuffer; - __glXPbuffer *pGlxPbuffer; - int numAttribs = req->numAttribs; - int *attr; - ScreenPtr pScreen; - __GLXFBConfig *pGlxFBConfig; - __GLXFBConfig *be_pGlxFBConfig; - XID be_xid; - Display *dpy; - DMXScreenInfo *dmxScreen; - int s; - int from_screen, to_screen; - - /* - ** Look up screen and FBConfig. - */ - if (screen > screenInfo.numScreens) { - /* The client library must send a valid screen number. */ - client->errorValue = screen; - return BadValue; - } - pScreen = screenInfo.screens[screen]; - - /* - ** Find the FBConfigRec for this fbconfigid. - */ - if (!(pGlxFBConfig = glxLookupFBConfig(fbconfigId))) { - client->errorValue = fbconfigId; - return __glXBadFBConfig; - } - - /* - ** Create the GLX part of the Pbuffer. - */ - pGlxPbuffer = (__glXPbuffer *) xalloc(sizeof(__glXPbuffer)); - if (!pGlxPbuffer) { - return BadAlloc; - } - - pGlxPbuffer->be_xids = (XID *) xalloc( sizeof(XID) * screenInfo.numScreens ); - if (!pGlxPbuffer->be_xids) { - xfree(pGlxPbuffer); - return BadAlloc; - } - - /* - * Allocate an XID on the back-end server(s) and send him the request - */ - from_screen = to_screen = screen; -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - dpy = GetBackEndDisplay(cl,s); - be_xid = XAllocID(dpy); - dmxScreen = &dmxScreens[s]; - be_pGlxFBConfig = glxLookupBackEndFBConfig( pGlxFBConfig->id, s ); - - attr = (int *)( req+1 ); - - LockDisplay(dpy); - GetReqExtra(GLXCreatePbuffer, 2 * numAttribs * __GLX_SIZE_CARD32, be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXCreatePbuffer; - be_req->screen = be_pGlxFBConfig->screen; - be_req->fbconfig = be_pGlxFBConfig->id; - be_req->pbuffer = be_xid; - be_req->numAttribs = numAttribs; - - /* Send attributes */ - if ( attr != NULL ) { - CARD32 *pc = (CARD32 *)(be_req + 1); - - while (numAttribs-- > 0) { - *pc++ = *attr++; /* token */ - *pc++ = *attr++; /* value */ - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - pGlxPbuffer->be_xids[s] = be_xid; - } - - - pGlxPbuffer->idExists = True; - pGlxPbuffer->refcnt = 0; - pGlxPbuffer->pFBConfig = pGlxFBConfig; - pGlxPbuffer->pScreen = pScreen; - - /* - ** Register the resource. - */ - if (!(AddResource(pbuffer, __glXPbufferRes, pGlxPbuffer))) { - return BadAlloc; - } - - return Success; - -} - -int __glXDestroyPbuffer(__GLXclientState *cl, GLbyte *pc) -{ - ClientPtr client = cl->client; - xGLXDestroyPbufferReq *req = (xGLXDestroyPbufferReq *) pc; - xGLXDestroyPbufferReq *be_req; - GLXPbuffer pbuffer = req->pbuffer; - Display *dpy; - int screen; - DMXScreenInfo *dmxScreen; - __glXPbuffer *pGlxPbuffer; - int s; - int from_screen, to_screen; - - /* - ** Check if it's a valid Pbuffer - */ - pGlxPbuffer = (__glXPbuffer *)LookupIDByType(pbuffer, __glXPbufferRes); - if (!pGlxPbuffer) { - client->errorValue = pbuffer; - return __glXBadPbuffer; - } - - screen = pGlxPbuffer->pScreen->myNum; - - from_screen = to_screen = screen; -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - for (s=from_screen; s<=to_screen; s++) { - dpy = GetBackEndDisplay(cl,s); - dmxScreen = &dmxScreens[s]; - - /* send the destroy request to the back-end server */ - LockDisplay(dpy); - GetReq(GLXDestroyPbuffer, be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXDestroyPbuffer; - be_req->pbuffer = pGlxPbuffer->be_xids[s]; - UnlockDisplay(dpy); - SyncHandle(); - } - - FreeResource(pbuffer, RT_NONE); - - return Success; -} - -int __glXGetDrawableAttributes(__GLXclientState *cl, GLbyte *pc) -{ - xGLXGetDrawableAttributesReq *req = (xGLXGetDrawableAttributesReq *)pc; - xGLXGetDrawableAttributesReq *be_req; - xGLXGetDrawableAttributesReply reply; - ClientPtr client = cl->client; - GLXDrawable drawId = req->drawable; - GLXDrawable be_drawable = 0; - DrawablePtr pDraw = NULL; - Display *dpy; - int screen, rc; - DMXScreenInfo *dmxScreen; - CARD32 *attribs = NULL; - int attribs_size; -#ifdef PANORAMIX - PanoramiXRes *pXinDraw = NULL; -#endif - - if (drawId != None) { - rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixGetAttrAccess); - if (rc == Success) { - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDraw; - be_drawable = 0; - screen = pWin->drawable.pScreen->myNum; - - } - else { - /* - ** Drawable is not a Window , GLXWindow or a GLXPixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - if (!pDraw) { - __GLXpixmap *pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, - __glXPixmapRes); - if (pGlxPixmap) { - pDraw = pGlxPixmap->pDraw; - screen = pGlxPixmap->pScreen->myNum; - be_drawable = pGlxPixmap->be_xids[screen]; - } - } - - if (!pDraw) { - __glXWindow *pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); - if (pGlxWindow) { - pDraw = pGlxWindow->pDraw; - screen = pGlxWindow->pScreen->myNum; - be_drawable = 0; - } - } - - if (!pDraw) { - __glXPbuffer *pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); - if (pGlxPbuffer) { - pDraw = (DrawablePtr)pGlxPbuffer; - screen = pGlxPbuffer->pScreen->myNum; - be_drawable = pGlxPbuffer->be_xids[screen]; - } - } - - - if (!pDraw) { - /* - ** Drawable is not a Window , GLXWindow or a GLXPixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - - /* if the drawable is a window or GLXWindow - - * we need to find the base id on the back-end server - */ - if (!be_drawable) { - WindowPtr pWin = (WindowPtr)pDraw; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - pXinDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); - if (!pXinDraw) { - client->errorValue = drawId; - return __glXBadDrawable; - } - - dixLookupWindow(&pWin, pXinDraw->info[screen].id, client, - DixReadAccess); - } -#endif - - if (pWin) { - be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - if (!be_drawable) { - /* it might be that the window did not created yet on the */ - /* back-end server (lazy window creation option), force */ - /* creation of the window */ - dmxCreateAndRealizeWindow( pWin, TRUE ); - be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - } - } - else { - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - - /* send the request to the back-end server */ - dpy = GetBackEndDisplay(cl,screen); - dmxScreen = &dmxScreens[screen]; - - /* make sure drawable exists on back-end */ - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReq(GLXGetDrawableAttributes, be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXGetDrawableAttributes; - be_req->drawable = be_drawable; - be_req->length = req->length; - if (!_XReply(dpy, (xReply *) &reply, 0, False)) { - UnlockDisplay(dpy); - SyncHandle(); - return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); - } - - if (reply.numAttribs) { - attribs_size = 2 * reply.numAttribs * __GLX_SIZE_CARD32; - attribs = (CARD32 *) Xalloc(attribs_size); - if (attribs == NULL) { - UnlockDisplay(dpy); - SyncHandle(); - return BadAlloc; - } - - _XRead(dpy, (char *) attribs, attribs_size); - } - - UnlockDisplay(dpy); - SyncHandle(); - - - /* send the reply back to the client */ - reply.sequenceNumber = client->sequence; - if (client->swapped) { - __glXSwapGetDrawableAttributesReply(client, &reply, (int *)attribs); - } - else { - WriteToClient(client, sz_xGLXGetDrawableAttributesReply, (char *)&reply); - WriteToClient(client, attribs_size, (char *)attribs); - } - - Xfree(attribs); - - return Success; -} - -int __glXChangeDrawableAttributes(__GLXclientState *cl, GLbyte *pc) -{ - xGLXChangeDrawableAttributesReq *req = (xGLXChangeDrawableAttributesReq *)pc; - xGLXChangeDrawableAttributesReq *be_req; - ClientPtr client = cl->client; - GLXDrawable drawId = req->drawable; - GLXDrawable be_drawable = 0; - DrawablePtr pDraw = NULL; - Display *dpy; - int screen, rc; - DMXScreenInfo *dmxScreen; - char *attrbuf; -#ifdef PANORAMIX - PanoramiXRes *pXinDraw = NULL; - PanoramiXRes *pXinReadDraw = NULL; -#endif - - if (drawId != None) { - rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixSetAttrAccess); - if (rc == Success) { - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDraw; - be_drawable = 0; - screen = pWin->drawable.pScreen->myNum; - - } - else { - /* - ** Drawable is not a Window , GLXWindow or a GLXPixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - if (!pDraw) { - __GLXpixmap *pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, - __glXPixmapRes); - if (pGlxPixmap) { - pDraw = pGlxPixmap->pDraw; - screen = pGlxPixmap->pScreen->myNum; - be_drawable = pGlxPixmap->be_xids[screen]; - } - } - - if (!pDraw) { - __glXWindow *pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); - if (pGlxWindow) { - pDraw = pGlxWindow->pDraw; - screen = pGlxWindow->pScreen->myNum; - be_drawable = 0; - } - } - - if (!pDraw) { - __glXPbuffer *pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); - if (pGlxPbuffer) { - pDraw = (DrawablePtr)pGlxPbuffer; - screen = pGlxPbuffer->pScreen->myNum; - be_drawable = pGlxPbuffer->be_xids[screen]; - } - } - - - if (!pDraw) { - /* - ** Drawable is not a Window , GLXWindow or a GLXPixmap. - */ - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - - /* if the drawable is a window or GLXWindow - - * we need to find the base id on the back-end server - */ - if (!be_drawable) { - WindowPtr pWin = (WindowPtr)pDraw; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - pXinDraw = (PanoramiXRes *) - SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); - if (!pXinDraw) { - client->errorValue = drawId; - return __glXBadDrawable; - } - - dixLookupWindow(&pWin, pXinDraw->info[screen].id, client, - DixReadAccess); - } -#endif - - if (pWin) { - be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - if (!be_drawable) { - /* it might be that the window did not created yet on the */ - /* back-end server (lazy window creation option), force */ - /* creation of the window */ - dmxCreateAndRealizeWindow( pWin, TRUE ); - be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; - } - } - else { - client->errorValue = drawId; - return __glXBadDrawable; - } - } - - - /* send the request to the back-end server */ - dpy = GetBackEndDisplay(cl,screen); - dmxScreen = &dmxScreens[screen]; - - /* make sure drawable exists on back-end */ - dmxSync( dmxScreen, 1 ); - - LockDisplay(dpy); - GetReqExtra(GLXChangeDrawableAttributes, - 2 * req->numAttribs * __GLX_SIZE_CARD32, be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLXChangeDrawableAttributes; - be_req->drawable = be_drawable; - be_req->numAttribs = req->numAttribs; - be_req->length = req->length; - - UnlockDisplay(dpy); - SyncHandle(); - - return Success; -} - -int __glXSendLargeCommand(__GLXclientState *cl, GLXContextTag contextTag) -{ - ClientPtr client = cl->client; - xGLXRenderLargeReq *req; - GLint maxSize, amount; - GLint totalRequests, requestNumber; - GLint dataLen; - GLbyte *data; - __GLXcontext *glxc; - int s; - int from_screen, to_screen; - - maxSize = cl->largeCmdMaxReqDataSize - (GLint)sizeof(xGLXRenderLargeReq); - dataLen = cl->largeCmdBytesTotal; - totalRequests = (dataLen / maxSize); - if (dataLen % maxSize) totalRequests++; - - glxc = __glXLookupContextByTag(cl, contextTag); - if (!glxc) { - client->errorValue = contextTag; - return __glXBadContext; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - /* - ** Send enough requests until the whole array is sent. - */ - requestNumber = 1; - data = cl->largeCmdBuf; - while (dataLen > 0) { - amount = dataLen; - if (amount > maxSize) { - amount = maxSize; - } - - for (s=from_screen; s<=to_screen; s++) { - - Display *dpy = GetBackEndDisplay(cl,s); - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - - LockDisplay(dpy); - GetReq(GLXRenderLarge,req); - req->reqType = dmxScreen->glxMajorOpcode; - req->glxCode = X_GLXRenderLarge; - req->contextTag = GetCurrentBackEndTag(cl,contextTag,s); - req->length += (amount + 3) >> 2; - req->requestNumber = requestNumber++; - req->requestTotal = totalRequests; - req->dataBytes = amount; - Data(dpy, ((const char*)data), amount); - dataLen -= amount; - data = ((GLbyte *) data) + amount; - UnlockDisplay(dpy); - SyncHandle(); - } - } - - return Success; -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxfont.h" +#include "dmxsync.h" + +#undef Xmalloc +#undef Xcalloc +#undef Xrealloc +#undef Xfree + +#include "glxserver.h" +#include <GL/glxtokens.h> +#include "g_disptab.h" +#include <pixmapstr.h> +#include <windowstr.h> +#include "glxutil.h" +#include "glxext.h" +#include "unpack.h" + +#include "GL/glxproto.h" +#include "glxvendor.h" +#include "glxvisuals.h" +#include "glxswap.h" + +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +extern __GLXFBConfig **__glXFBConfigs; +extern int __glXNumFBConfigs; + +extern __GLXFBConfig *glxLookupFBConfig( GLXFBConfigID id ); +extern __GLXFBConfig *glxLookupFBConfigByVID( VisualID vid ); +extern __GLXFBConfig *glxLookupBackEndFBConfig( GLXFBConfigID id, int screen ); +extern int glxIsExtensionSupported( char *ext ); +extern int __glXGetFBConfigsSGIX(__GLXclientState *cl, GLbyte *pc); + +#define BE_TO_CLIENT_ERROR(x) \ + ( (x) >= __glXerrorBase ? \ + (x) - dmxScreen->glxErrorBase + __glXerrorBase \ + : (x) ) + +Display *GetBackEndDisplay( __GLXclientState *cl, int s ) +{ + if (! cl->be_displays[s] ) { + cl->be_displays[s] = XOpenDisplay( DisplayString(dmxScreens[s].beDisplay) ); + } + return( cl->be_displays[s] ); +} + +/* +** Create a GL context with the given properties. +*/ +static int CreateContext(__GLXclientState *cl, + GLXContextID gcId, + VisualID vid, GLXFBConfigID fbconfigId, + int screen, + GLXContextID shareList, + int isDirect ) +{ + ClientPtr client = cl->client; + xGLXCreateContextReq *be_req; + xGLXCreateNewContextReq *be_new_req; + VisualPtr pVisual; + ScreenPtr pScreen; + __GLXcontext *glxc, *shareglxc; + __GLXvisualConfig *pGlxVisual; + __GLXscreenInfo *pGlxScreen; + VisualID visual = vid; + GLint i; + int from_screen = screen; + int to_screen = screen; + DMXScreenInfo *dmxScreen; + VisualID be_vid; + GLXFBConfigID be_fbconfigId; + int num_be_screens; + Display *dpy; + + /* + ** Check if screen exists. + */ + if (screen >= screenInfo.numScreens) { + client->errorValue = screen; + return BadValue; + } + + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + /* + ** Find the display list space that we want to share. + ** + */ + if (shareList == None) { + shareglxc = NULL; + } else { + shareglxc = (__GLXcontext *) LookupIDByType(shareList, __glXContextRes); + if (!shareglxc) { + client->errorValue = shareList; + return __glXBadContext; + } + } + + /* + ** Allocate memory for the new context + */ + glxc = __glXCalloc(1, sizeof(__GLXcontext)); + if (!glxc) { + return BadAlloc; + } + + pScreen = screenInfo.screens[screen]; + pGlxScreen = &__glXActiveScreens[screen]; + + if (fbconfigId != None) { + glxc->pFBConfig = glxLookupFBConfig( fbconfigId ); + if (!glxc->pFBConfig) { + client->errorValue = fbconfigId; + __glXFree( glxc ); + return BadValue; + } + visual = glxc->pFBConfig->associatedVisualId; + } + else { + glxc->pFBConfig = NULL; + } + + if (visual != None) { + /* + ** Check if the visual ID is valid for this screen. + */ + pVisual = pScreen->visuals; + for (i = 0; i < pScreen->numVisuals; i++, pVisual++) { + if (pVisual->vid == visual) { + break; + } + } + if (i == pScreen->numVisuals) { + client->errorValue = visual; + __glXFree( glxc ); + return BadValue; + } + + pGlxVisual = pGlxScreen->pGlxVisual; + for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { + if (pGlxVisual->vid == visual) { + break; + } + } + if (i == pGlxScreen->numVisuals) { + /* + ** Visual not support on this screen by this OpenGL implementation. + */ + client->errorValue = visual; + __glXFree( glxc ); + return BadValue; + } + + if ( glxc->pFBConfig == NULL ) { + glxc->pFBConfig = glxLookupFBConfigByVID( visual ); + + if ( glxc->pFBConfig == NULL ) { + /* + * visual does not have an FBConfig ??? + client->errorValue = visual; + __glXFree( glxc ); + return BadValue; + */ + } + } + } + else { + pVisual = NULL; + pGlxVisual = NULL; + } + + glxc->pScreen = pScreen; + glxc->pGlxScreen = pGlxScreen; + glxc->pVisual = pVisual; + glxc->pGlxVisual = pGlxVisual; + + /* + * allocate memory for back-end servers info + */ + num_be_screens = to_screen - from_screen + 1; + glxc->real_ids = (XID *)__glXMalloc(sizeof(XID) * num_be_screens); + if (!glxc->real_ids) { + return BadAlloc; + } + glxc->real_vids = (XID *)__glXMalloc(sizeof(XID) * num_be_screens); + if (!glxc->real_vids) { + return BadAlloc; + } + + for (screen = from_screen; screen <= to_screen; screen++) { + int sent = 0; + pScreen = screenInfo.screens[screen]; + pGlxScreen = &__glXActiveScreens[screen]; + dmxScreen = &dmxScreens[screen]; + + if (glxc->pFBConfig) { + __GLXFBConfig *beFBConfig = glxLookupBackEndFBConfig( glxc->pFBConfig->id, + screen ); + be_fbconfigId = beFBConfig->id; + } + + if (pGlxVisual) { + + be_vid = glxMatchGLXVisualInConfigList( pGlxVisual, + dmxScreen->glxVisuals, + dmxScreen->numGlxVisuals ); + + if (!be_vid) { + /* visual is not supported on the back-end server */ + __glXFree( glxc->real_ids ); + __glXFree( glxc->real_vids ); + __glXFree( glxc ); + return BadValue; + } + } + + glxc->real_ids[screen-from_screen] = XAllocID(GetBackEndDisplay(cl,screen)); + + /* send the create context request to the back-end server */ + dpy = GetBackEndDisplay(cl,screen); + if (glxc->pFBConfig) { + /*Since for a certain visual both RGB and COLOR INDEX + *can be on then the only parmeter to choose the renderType + * should be the class of the colormap since all 4 first + * classes does not support RGB mode only COLOR INDEX , + * and so TrueColor and DirectColor does not support COLOR INDEX*/ + int renderType = glxc->pFBConfig->renderType; + if ( pVisual ) { + switch ( pVisual->class ){ + case PseudoColor: + case StaticColor: + case GrayScale: + case StaticGray: + renderType = GLX_COLOR_INDEX_TYPE; + break; + case TrueColor: + case DirectColor: + default: + renderType = GLX_RGBA_TYPE; + break; + } + } + if ( __GLX_IS_VERSION_SUPPORTED(1,3) ) { + LockDisplay(dpy); + GetReq(GLXCreateNewContext,be_new_req); + be_new_req->reqType = dmxScreen->glxMajorOpcode; + be_new_req->glxCode = X_GLXCreateNewContext; + be_new_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; + be_new_req->fbconfig = (unsigned int)be_fbconfigId; + be_new_req->screen = DefaultScreen(dpy); + be_new_req->renderType = renderType; + + be_new_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); + be_new_req->isDirect = 0; + UnlockDisplay(dpy); + glxc->real_vids[screen-from_screen] = be_fbconfigId; + sent = 1; + } + else if (glxIsExtensionSupported("GLX_SGIX_fbconfig")) { + + xGLXCreateContextWithConfigSGIXReq *ext_req; + xGLXVendorPrivateReq *vpreq; + LockDisplay(dpy); + GetReqExtra(GLXVendorPrivate, + sz_xGLXCreateContextWithConfigSGIXReq - sz_xGLXVendorPrivateReq, + vpreq); + ext_req = (xGLXCreateContextWithConfigSGIXReq *)vpreq; + ext_req->reqType = dmxScreen->glxMajorOpcode; + ext_req->glxCode = X_GLXVendorPrivate; + ext_req->vendorCode = X_GLXvop_CreateContextWithConfigSGIX; + ext_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; + ext_req->fbconfig = (unsigned int)be_fbconfigId; + ext_req->screen = DefaultScreen(dpy); + ext_req->renderType = renderType; + ext_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); + ext_req->isDirect = 0; + UnlockDisplay(dpy); + glxc->real_vids[screen-from_screen] = be_fbconfigId; + sent = 1; + } + } + + if (!sent) { + LockDisplay(dpy); + GetReq(GLXCreateContext,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXCreateContext; + be_req->context = (unsigned int)glxc->real_ids[screen-from_screen]; + be_req->visual = (unsigned int)be_vid; + be_req->screen = DefaultScreen(dpy); + be_req->shareList = (shareglxc ? shareglxc->real_ids[screen-from_screen] : 0); + be_req->isDirect = 0; + UnlockDisplay(dpy); + glxc->real_vids[screen-from_screen] = be_vid; + } + SyncHandle(); + + } + + /* + ** Register this context as a resource. + */ + if (!AddResource(gcId, __glXContextRes, (pointer)glxc)) { + __glXFree( glxc->real_ids ); + __glXFree( glxc->real_vids ); + __glXFree( glxc ); + client->errorValue = gcId; + return BadAlloc; + } + + /* + ** Finally, now that everything is working, setup the rest of the + ** context. + */ + glxc->id = gcId; + glxc->share_id = shareList; + glxc->idExists = GL_TRUE; + glxc->isCurrent = GL_FALSE; + + return Success; +} + +int __glXCreateContext(__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; + + return( CreateContext(cl, req->context,req->visual, None, + req->screen, req->shareList, req->isDirect) ); + +} + +int __glXCreateNewContext(__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc; + + return( CreateContext(cl, req->context,None, req->fbconfig, + req->screen, req->shareList, req->isDirect) ); + +} + +int __glXCreateContextWithConfigSGIX(__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateContextWithConfigSGIXReq *req = (xGLXCreateContextWithConfigSGIXReq *) pc; + + return( CreateContext(cl, req->context, None, req->fbconfig, + req->screen, req->shareList, req->isDirect) ); + +} + +int __glXQueryMaxSwapBarriersSGIX(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXQueryMaxSwapBarriersSGIXReq *req = + (xGLXQueryMaxSwapBarriersSGIXReq *)pc; + xGLXQueryMaxSwapBarriersSGIXReply reply; + + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = 0; + reply.max = QueryMaxSwapBarriersSGIX(req->screen); + + if (client->swapped) { + __glXSwapQueryMaxSwapBarriersSGIXReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXQueryMaxSwapBarriersSGIXReply, + (char *)&reply); + } + + return Success; +} + +int __glXBindSwapBarrierSGIX(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXBindSwapBarrierSGIXReq *req = (xGLXBindSwapBarrierSGIXReq *)pc; + DrawablePtr pDraw; + __GLXpixmap *pGlxPixmap = NULL; + __glXWindow *pGlxWindow = NULL; + int rc; + + rc = dixLookupDrawable(&pDraw, req->drawable, client, 0, DixGetAttrAccess); + if (rc != Success) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->drawable, + __glXPixmapRes); + if (pGlxPixmap) pDraw = pGlxPixmap->pDraw; + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(req->drawable, + __glXWindowRes); + if (pGlxWindow) pDraw = pGlxWindow->pDraw; + } + + if (!pDraw) { + client->errorValue = req->drawable; + return __glXBadDrawable; + } + + return BindSwapBarrierSGIX(pDraw, req->barrier); +} + +int __glXJoinSwapGroupSGIX(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXJoinSwapGroupSGIXReq *req = (xGLXJoinSwapGroupSGIXReq *)pc; + DrawablePtr pDraw, pMember = NULL; + __GLXpixmap *pGlxPixmap = NULL; + __glXWindow *pGlxWindow = NULL; + int rc; + + rc = dixLookupDrawable(&pDraw, req->drawable, client, 0, DixManageAccess); + if (rc != Success) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->drawable, + __glXPixmapRes); + if (pGlxPixmap) pDraw = pGlxPixmap->pDraw; + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(req->drawable, + __glXWindowRes); + if (pGlxWindow) pDraw = pGlxWindow->pDraw; + } + + if (!pDraw) { + client->errorValue = req->drawable; + return __glXBadDrawable; + } + + if (req->member != None) { + rc = dixLookupDrawable(&pMember, req->member, client, 0, + DixGetAttrAccess); + if (rc != Success) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(req->member, + __glXPixmapRes); + if (pGlxPixmap) pMember = pGlxPixmap->pDraw; + } + + if (!pMember && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(req->member, + __glXWindowRes); + if (pGlxWindow) pMember = pGlxWindow->pDraw; + } + + if (!pMember) { + client->errorValue = req->member; + return __glXBadDrawable; + } + } + + return JoinSwapGroupSGIX(pDraw, pMember); +} + + +/* +** Destroy a GL context as an X resource. +*/ +int __glXDestroyContext(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc; + xGLXDestroyContextReq *be_req; + GLXContextID gcId = req->context; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + int s; + + glxc = (__GLXcontext *) LookupIDByType(gcId, __glXContextRes); + if (glxc) { + /* + ** Just free the resource; don't actually destroy the context, + ** because it might be in use. The + ** destroy method will be called by the resource destruction routine + ** if necessary. + */ + FreeResourceByType(gcId, __glXContextRes, FALSE); + + from_screen = to_screen = glxc->pScreen->myNum; + + } else { + client->errorValue = gcId; + return __glXBadContext; + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + /* + * send DestroyContext request to all back-end servers + */ + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReq(GLXDestroyContext,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXDestroyContext; + be_req->context = glxc->real_ids[s-from_screen]; + UnlockDisplay(dpy); + SyncHandle(); + } + + return Success; +} + +/*****************************************************************************/ + +/* +** For each client, the server keeps a table of all the contexts that are +** current for that client (each thread of a client may have its own current +** context). These routines add, change, and lookup contexts in the table. +*/ + +/* +** Add a current context, and return the tag that will be used to refer to it. +*/ +static int AddCurrentContext(__GLXclientState *cl, __GLXcontext *glxc, DrawablePtr pDraw) +{ + int i; + int num = cl->numCurrentContexts; + __GLXcontext **table = cl->currentContexts; + + if (!glxc) return -1; + + /* + ** Try to find an empty slot and use it. + */ + for (i=0; i < num; i++) { + if (!table[i]) { + table[i] = glxc; + return i+1; + } + } + /* + ** Didn't find a free slot, so we'll have to grow the table. + */ + if (!num) { + table = (__GLXcontext **) __glXMalloc(sizeof(__GLXcontext *)); + cl->currentDrawables = (DrawablePtr *) __glXMalloc(sizeof(DrawablePtr)); + cl->be_currentCTag = (GLXContextTag *) __glXMalloc(screenInfo.numScreens *sizeof(GLXContextTag)); + } else { + table = (__GLXcontext **) __glXRealloc(table, + (num+1)*sizeof(__GLXcontext *)); + cl->currentDrawables = (DrawablePtr *) __glXRealloc( + cl->currentDrawables , + (num+1)*sizeof(DrawablePtr)); + cl->be_currentCTag = (GLXContextTag *) __glXRealloc(cl->be_currentCTag, + (num+1)*screenInfo.numScreens*sizeof(GLXContextTag)); + } + table[num] = glxc; + cl->currentDrawables[num] = pDraw; + cl->currentContexts = table; + cl->numCurrentContexts++; + + memset(cl->be_currentCTag + num*screenInfo.numScreens, 0, + screenInfo.numScreens * sizeof(GLXContextTag)); + + return num+1; +} + +/* +** Given a tag, change the current context for the corresponding entry. +*/ +static void ChangeCurrentContext(__GLXclientState *cl, __GLXcontext *glxc, + GLXContextTag tag) +{ + __GLXcontext **table = cl->currentContexts; + table[tag-1] = glxc; +} + +/* +** Given a tag, and back-end screen number, retrives the current back-end +** tag. +*/ +int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s) +{ + if (tag >0) { + return( cl->be_currentCTag[ (tag-1)*screenInfo.numScreens + s ] ); + } + else { + return( 0 ); + } +} + +/* +** Given a tag, and back-end screen number, sets the current back-end +** tag. +*/ +static void SetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s, GLXContextTag be_tag) +{ + if (tag >0) { + cl->be_currentCTag[ (tag-1)*screenInfo.numScreens + s ] = be_tag; + } +} + +/* +** For this implementation we have chosen to simply use the index of the +** context's entry in the table as the context tag. A tag must be greater +** than 0. +*/ +__GLXcontext *__glXLookupContextByTag(__GLXclientState *cl, GLXContextTag tag) +{ + int num = cl->numCurrentContexts; + + if (tag < 1 || tag > num) { + return 0; + } else { + return cl->currentContexts[tag-1]; + } +} + +DrawablePtr __glXLookupDrawableByTag(__GLXclientState *cl, GLXContextTag tag) +{ + int num = cl->numCurrentContexts; + + if (tag < 1 || tag > num) { + return 0; + } else { + return cl->currentDrawables[tag-1]; + } +} + +/*****************************************************************************/ + +static void StopUsingContext(__GLXcontext *glxc) +{ + if (glxc) { + if (glxc == __glXLastContext) { + /* Tell server GL library */ + __glXLastContext = 0; + } + glxc->isCurrent = GL_FALSE; + if (!glxc->idExists) { + __glXFreeContext(glxc); + } + } +} + +static void StartUsingContext(__GLXclientState *cl, __GLXcontext *glxc) +{ + glxc->isCurrent = GL_TRUE; +} + +/*****************************************************************************/ +/* +** Make an OpenGL context and drawable current. +*/ +static int MakeCurrent(__GLXclientState *cl, + GLXDrawable drawable, + GLXDrawable readdrawable, + GLXContextID context, + GLXContextTag oldContextTag) +{ + ClientPtr client = cl->client; + DrawablePtr pDraw = NULL; + DrawablePtr pReadDraw = NULL; + xGLXMakeCurrentReadSGIReply new_reply; + xGLXMakeCurrentReq *be_req; + xGLXMakeCurrentReply be_reply; + xGLXMakeContextCurrentReq *be_new_req; + xGLXMakeContextCurrentReply be_new_reply; + GLXDrawable drawId = drawable; + GLXDrawable readId = readdrawable; + GLXContextID contextId = context; + __GLXpixmap *pGlxPixmap = 0; + __GLXpixmap *pReadGlxPixmap = 0; + __GLXcontext *glxc, *prevglxc; + GLXContextTag tag = oldContextTag; + WindowPtr pWin = NULL; + WindowPtr pReadWin = NULL; + __glXWindow *pGlxWindow = NULL; + __glXWindow *pGlxReadWindow = NULL; + __glXPbuffer *pGlxPbuffer = NULL; + __glXPbuffer *pGlxReadPbuffer = NULL; +#ifdef PANORAMIX + PanoramiXRes *pXinDraw = NULL; + PanoramiXRes *pXinReadDraw = NULL; +#endif + int from_screen = 0; + int to_screen = 0; + int s, rc; + + /* + ** If one is None and the other isn't, it's a bad match. + */ + if ((drawId == None && contextId != None) || + (drawId != None && contextId == None)) { + return BadMatch; + } + + /* + ** Lookup old context. If we have one, it must be in a usable state. + */ + if (tag != 0) { + prevglxc = __glXLookupContextByTag(cl, tag); + if (!prevglxc) { + /* + ** Tag for previous context is invalid. + */ + return __glXBadContextTag; + } + } else { + prevglxc = 0; + } + + /* + ** Lookup new context. It must not be current for someone else. + */ + if (contextId != None) { + glxc = (__GLXcontext *) LookupIDByType(contextId, __glXContextRes); + if (!glxc) { + client->errorValue = contextId; + return __glXBadContext; + } + if ((glxc != prevglxc) && glxc->isCurrent) { + /* Context is current to somebody else */ + return BadAccess; + } + } else { + /* Switching to no context. Ignore new drawable. */ + glxc = 0; + } + + if (drawId != None) { + rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); + if (rc == Success) { + if (pDraw->type == DRAWABLE_WINDOW) { + /* + ** Drawable is an X Window. + */ + VisualID vid; + pWin = (WindowPtr)pDraw; + vid = wVisual(pWin); + + new_reply.writeVid = (glxc->pFBConfig ? glxc->pFBConfig->id : vid); + new_reply.writeType = GLX_WINDOW_TYPE; + + /* + ** Check if window and context are similar. + */ + if ((vid != glxc->pVisual->vid) || + (pWin->drawable.pScreen != glxc->pScreen)) { + client->errorValue = drawId; + return BadMatch; + } + + from_screen = to_screen = pWin->drawable.pScreen->myNum; + + } else { + /* + ** An X Pixmap is not allowed as a parameter (a GLX Pixmap + ** is, but it must first be created with glxCreateGLXPixmap). + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (!pDraw) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + /* + ** Check if pixmap and context are similar. + */ + if (pGlxPixmap->pScreen != glxc->pScreen || + pGlxPixmap->pGlxVisual != glxc->pGlxVisual) { + client->errorValue = drawId; + return BadMatch; + } + pDraw = pGlxPixmap->pDraw; + + new_reply.writeVid = (glxc->pFBConfig ? glxc->pFBConfig->id : + pGlxPixmap->pGlxVisual->vid); + + new_reply.writeType = GLX_PIXMAP_TYPE; + + from_screen = to_screen = pGlxPixmap->pScreen->myNum; + + } + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); + if (pGlxWindow) { + /* + ** Drawable is a GLXWindow. + ** + ** Check if GLX window and context are similar. + */ + if (pGlxWindow->pScreen != glxc->pScreen || + pGlxWindow->pGlxFBConfig != glxc->pFBConfig) { + client->errorValue = drawId; + return BadMatch; + } + + pDraw = pGlxWindow->pDraw; + new_reply.writeVid = pGlxWindow->pGlxFBConfig->id; + new_reply.writeType = GLX_GLXWINDOW_TYPE; + } + + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); + if (pGlxPbuffer) { + if (pGlxPbuffer->pScreen != glxc->pScreen || + pGlxPbuffer->pFBConfig != glxc->pFBConfig) { + client->errorValue = drawId; + return BadMatch; + } + + pDraw = (DrawablePtr)pGlxPbuffer; + new_reply.writeVid = pGlxPbuffer->pFBConfig->id; + new_reply.writeType = GLX_PBUFFER_TYPE; + } + } + + if (!pDraw) { + /* + ** Drawable is not a Window , GLXWindow or a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + + } else { + pDraw = 0; + } + + if (readId != None && readId != drawId ) { + rc = dixLookupDrawable(&pReadDraw, readId, client, 0, DixReadAccess); + if (rc == Success) { + if (pReadDraw->type == DRAWABLE_WINDOW) { + /* + ** Drawable is an X Window. + */ + VisualID vid; + pReadWin = (WindowPtr)pDraw; + vid = wVisual(pReadWin); + + new_reply.readVid = (glxc->pFBConfig ? glxc->pFBConfig->id : vid); + new_reply.readType = GLX_WINDOW_TYPE; + + /* + ** Check if window and context are similar. + */ + if ((vid != glxc->pVisual->vid) || + (pReadWin->drawable.pScreen != glxc->pScreen)) { + client->errorValue = readId; + return BadMatch; + } + + } else { + + /* + ** An X Pixmap is not allowed as a parameter (a GLX Pixmap + ** is, but it must first be created with glxCreateGLXPixmap). + */ + client->errorValue = readId; + return __glXBadDrawable; + } + } + + if (!pReadDraw) { + pReadGlxPixmap = (__GLXpixmap *) LookupIDByType(readId, + __glXPixmapRes); + if (pReadGlxPixmap) { + /* + ** Check if pixmap and context are similar. + */ + if (pReadGlxPixmap->pScreen != glxc->pScreen || + pReadGlxPixmap->pGlxVisual != glxc->pGlxVisual) { + client->errorValue = readId; + return BadMatch; + } + pReadDraw = pReadGlxPixmap->pDraw; + + new_reply.readVid = (glxc->pFBConfig ? glxc->pFBConfig->id : + pReadGlxPixmap->pGlxVisual->vid ); + new_reply.readType = GLX_PIXMAP_TYPE; + + } + } + + if (!pReadDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxReadWindow = (__glXWindow *) + LookupIDByType(readId, __glXWindowRes); + if (pGlxReadWindow) { + /* + ** Drawable is a GLXWindow. + ** + ** Check if GLX window and context are similar. + */ + if (pGlxReadWindow->pScreen != glxc->pScreen || + pGlxReadWindow->pGlxFBConfig != glxc->pFBConfig) { + client->errorValue = readId; + return BadMatch; + } + + pReadDraw = pGlxReadWindow->pDraw; + new_reply.readVid = pGlxReadWindow->pGlxFBConfig->id; + new_reply.readType = GLX_GLXWINDOW_TYPE; + } + } + + if (!pReadDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxReadPbuffer = (__glXPbuffer *)LookupIDByType(readId, __glXPbufferRes); + if (pGlxReadPbuffer) { + if (pGlxReadPbuffer->pScreen != glxc->pScreen || + pGlxReadPbuffer->pFBConfig != glxc->pFBConfig) { + client->errorValue = drawId; + return BadMatch; + } + + pReadDraw = (DrawablePtr)pGlxReadPbuffer; + new_reply.readVid = pGlxReadPbuffer->pFBConfig->id; + new_reply.readType = GLX_PBUFFER_TYPE; + } + } + + if (!pReadDraw) { + /* + ** Drawable is neither a Window nor a GLXPixmap. + */ + client->errorValue = readId; + return __glXBadDrawable; + } + + } else { + pReadDraw = pDraw; + pReadGlxPixmap = pGlxPixmap; + pReadWin = pWin; + new_reply.readVid = new_reply.writeVid; + new_reply.readType = new_reply.writeType; + } + + if (prevglxc) { + + if (prevglxc->pGlxPixmap) { + /* + ** The previous drawable was a glx pixmap, release it. + */ + prevglxc->pGlxPixmap->refcnt--; + __glXFreeGLXPixmap( prevglxc->pGlxPixmap ); + prevglxc->pGlxPixmap = 0; + } + + if (prevglxc->pGlxReadPixmap) { + /* + ** The previous drawable was a glx pixmap, release it. + */ + prevglxc->pGlxReadPixmap->refcnt--; + __glXFreeGLXPixmap( prevglxc->pGlxReadPixmap ); + prevglxc->pGlxReadPixmap = 0; + } + + if (prevglxc->pGlxWindow) { + /* + ** The previous drawable was a glx window, release it. + */ + prevglxc->pGlxWindow->refcnt--; + __glXFreeGLXWindow( prevglxc->pGlxWindow ); + prevglxc->pGlxWindow = 0; + } + + if (prevglxc->pGlxReadWindow) { + /* + ** The previous drawable was a glx window, release it. + */ + prevglxc->pGlxReadWindow->refcnt--; + __glXFreeGLXWindow( prevglxc->pGlxReadWindow ); + prevglxc->pGlxReadWindow = 0; + } + + if (prevglxc->pGlxPbuffer) { + /* + ** The previous drawable was a glx Pbuffer, release it. + */ + prevglxc->pGlxPbuffer->refcnt--; + __glXFreeGLXPbuffer( prevglxc->pGlxPbuffer ); + prevglxc->pGlxPbuffer = 0; + } + + if (prevglxc->pGlxReadPbuffer) { + /* + ** The previous drawable was a glx Pbuffer, release it. + */ + prevglxc->pGlxReadPbuffer->refcnt--; + __glXFreeGLXPbuffer( prevglxc->pGlxReadPbuffer ); + prevglxc->pGlxReadPbuffer = 0; + } + + ChangeCurrentContext(cl, glxc, tag); + ChangeCurrentContext(cl, glxc, tag); + StopUsingContext(prevglxc); + } else { + tag = AddCurrentContext(cl, glxc, pDraw); + } + if (glxc) { + + glxc->pGlxPixmap = pGlxPixmap; + glxc->pGlxReadPixmap = pReadGlxPixmap; + glxc->pGlxWindow = pGlxWindow; + glxc->pGlxReadWindow = pGlxReadWindow; + glxc->pGlxPbuffer = pGlxPbuffer; + glxc->pGlxReadPbuffer = pGlxReadPbuffer; + + if (pGlxPixmap) { + pGlxPixmap->refcnt++; + } + + if (pReadGlxPixmap) { + pReadGlxPixmap->refcnt++; + } + + if (pGlxWindow) { + pGlxWindow->refcnt++; + } + + if (pGlxReadWindow) { + pGlxReadWindow->refcnt++; + } + + if (pGlxPbuffer) { + pGlxPbuffer->refcnt++; + } + + if (pGlxReadPbuffer) { + pGlxReadPbuffer->refcnt++; + } + + StartUsingContext(cl, glxc); + new_reply.contextTag = tag; + } else { + new_reply.contextTag = 0; + } + new_reply.length = 0; + new_reply.type = X_Reply; + new_reply.sequenceNumber = client->sequence; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + + if (pDraw && new_reply.writeType != GLX_PBUFFER_TYPE) { + pXinDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); + } + + if (pReadDraw && pReadDraw != pDraw && + new_reply.readType != GLX_PBUFFER_TYPE) { + pXinReadDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pReadDraw->id, XRC_DRAWABLE, DixReadAccess); + } + else { + pXinReadDraw = pXinDraw; + } + } +#endif + + + /* send the MakeCurrent request to all required + * back-end servers. + */ + for (s = from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + unsigned int be_draw = None; + unsigned int be_read_draw = None; + + if (pGlxPixmap) { + be_draw = pGlxPixmap->be_xids[s]; + } + else if (pGlxPbuffer) { + be_draw = pGlxPbuffer->be_xids[s]; + } +#ifdef PANORAMIX + else if (pXinDraw) { + dixLookupWindow(&pWin, pXinDraw->info[s].id, client, DixReadAccess); + } +#endif + else if (pGlxWindow) { + pWin = (WindowPtr)pGlxWindow->pDraw; + } + + if (pWin && be_draw == None) { + be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + if (!be_draw) { + /* it might be that the window did not created yet on the */ + /* back-end server (lazy window creation option), force */ + /* creation of the window */ + dmxCreateAndRealizeWindow( pWin, TRUE ); + be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + } + } + + /* + * Before sending the MakeCurrent request - sync the + * X11 connection to the back-end servers to make sure + * that drawable is already created + */ + dmxSync( dmxScreen, 1 ); + + if (drawId == readId) { + LockDisplay(dpy); + GetReq(GLXMakeCurrent, be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXMakeCurrent; + be_req->drawable = be_draw; + be_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); + be_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); + if (!_XReply(dpy, (xReply *) &be_reply, 0, False)) { + + /* The make current failed */ + UnlockDisplay(dpy); + SyncHandle(); + return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); + } + + UnlockDisplay(dpy); + SyncHandle(); + + SetCurrentBackEndTag( cl, tag, s, be_reply.contextTag ); + } + else { + + if (pReadGlxPixmap) { + be_read_draw = pReadGlxPixmap->be_xids[s]; + } + else if (pGlxReadPbuffer) { + be_read_draw = pGlxReadPbuffer->be_xids[s]; + } +#ifdef PANORAMIX + else if (pXinReadDraw) { + dixLookupWindow(&pReadWin, pXinReadDraw->info[s].id, client, + DixReadAccess); + } +#endif + else if (pGlxReadWindow) { + pReadWin = (WindowPtr)pGlxReadWindow->pDraw; + } + + if (pReadWin && be_read_draw == None) { + be_read_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pReadWin))->window; + if (!be_read_draw) { + /* it might be that the window did not created yet on the */ + /* back-end server (lazy window creation option), force */ + /* creation of the window */ + dmxCreateAndRealizeWindow( pReadWin, TRUE ); + be_read_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pReadWin))->window; + dmxSync( dmxScreen, 1 ); + } + } + + if ( __GLX_IS_VERSION_SUPPORTED(1,3) ) { + LockDisplay(dpy); + GetReq(GLXMakeContextCurrent, be_new_req); + be_new_req->reqType = dmxScreen->glxMajorOpcode; + be_new_req->glxCode = X_GLXMakeContextCurrent; + be_new_req->drawable = be_draw; + be_new_req->readdrawable = be_read_draw; + be_new_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); + be_new_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); + if (!_XReply(dpy, (xReply *) &be_new_reply, 0, False)) { + + /* The make current failed */ + UnlockDisplay(dpy); + SyncHandle(); + return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); + } + + UnlockDisplay(dpy); + SyncHandle(); + + SetCurrentBackEndTag( cl, tag, s, be_new_reply.contextTag ); + } + else if (glxIsExtensionSupported("GLX_SGI_make_current_read")) { + xGLXMakeCurrentReadSGIReq *ext_req; + xGLXVendorPrivateWithReplyReq *vpreq; + xGLXMakeCurrentReadSGIReply ext_reply; + + LockDisplay(dpy); + GetReqExtra(GLXVendorPrivateWithReply, + sz_xGLXMakeCurrentReadSGIReq - sz_xGLXVendorPrivateWithReplyReq, + vpreq); + ext_req = (xGLXMakeCurrentReadSGIReq *)vpreq; + ext_req->reqType = dmxScreen->glxMajorOpcode; + ext_req->glxCode = X_GLXVendorPrivateWithReply; + ext_req->vendorCode = X_GLXvop_MakeCurrentReadSGI; + ext_req->drawable = be_draw; + ext_req->readable = be_read_draw; + ext_req->context = (unsigned int)(glxc ? glxc->real_ids[s-from_screen] : 0); + ext_req->oldContextTag = GetCurrentBackEndTag(cl, tag, s); + if (!_XReply(dpy, (xReply *) &ext_reply, 0, False)) { + + /* The make current failed */ + UnlockDisplay(dpy); + SyncHandle(); + return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); + } + + UnlockDisplay(dpy); + SyncHandle(); + + SetCurrentBackEndTag( cl, tag, s, ext_reply.contextTag ); + + } + else { + return BadMatch; + } + } + + XFlush( dpy ); + } + + if (client->swapped) { + __glXSwapMakeCurrentReply(client, &new_reply); + } else { + WriteToClient(client, sz_xGLXMakeContextCurrentReply, (char *)&new_reply); + } + + return Success; +} + +int __glXMakeCurrent(__GLXclientState *cl, GLbyte *pc) +{ + xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc; + + return( MakeCurrent(cl, req->drawable, req->drawable, + req->context, req->oldContextTag ) ); +} + +int __glXMakeContextCurrent(__GLXclientState *cl, GLbyte *pc) +{ + xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) pc; + + return( MakeCurrent(cl, req->drawable, req->readdrawable, + req->context, req->oldContextTag ) ); +} + +int __glXMakeCurrentReadSGI(__GLXclientState *cl, GLbyte *pc) +{ + xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) pc; + + return( MakeCurrent(cl, req->drawable, req->readable, + req->context, req->oldContextTag ) ); +} + +int __glXIsDirect(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc; + xGLXIsDirectReply reply; + __GLXcontext *glxc; + + /* + ** Find the GL context. + */ + glxc = (__GLXcontext *) LookupIDByType(req->context, __glXContextRes); + if (!glxc) { + client->errorValue = req->context; + return __glXBadContext; + } + + reply.isDirect = 0; + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + __glXSwapIsDirectReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply); + } + + return Success; +} + +int __glXQueryVersion(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; +/* xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc; */ + xGLXQueryVersionReply reply; + + /* + ** Server should take into consideration the version numbers sent by the + ** client if it wants to work with older clients; however, in this + ** implementation the server just returns its version number. + */ + reply.majorVersion = __glXVersionMajor; + reply.minorVersion = __glXVersionMinor; + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + __glXSwapQueryVersionReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply); + } + return Success; +} + +int __glXWaitGL(__GLXclientState *cl, GLbyte *pc) +{ + xGLXWaitGLReq *req = (xGLXWaitGLReq *)pc; + xGLXWaitGLReq *be_req = (xGLXWaitGLReq *)pc; + int from_screen = 0; + int to_screen = 0; + int s; + __GLXcontext *glxc = NULL; + + if (req->contextTag != 0) { + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (glxc) { + from_screen = to_screen = glxc->pScreen->myNum; + } + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReq(GLXWaitGL,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXWaitGL; + be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); + UnlockDisplay(dpy); + SyncHandle(); + + XSync(dpy, False); + } + + return Success; +} + +int __glXWaitX(__GLXclientState *cl, GLbyte *pc) +{ + xGLXWaitXReq *req = (xGLXWaitXReq *)pc; + xGLXWaitXReq *be_req; + int from_screen = 0; + int to_screen = 0; + int s; + __GLXcontext *glxc = NULL; + + if (req->contextTag != 0) { + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (glxc) { + from_screen = to_screen = glxc->pScreen->myNum; + } + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReq(GLXWaitX,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXWaitX; + be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); + UnlockDisplay(dpy); + SyncHandle(); + + XFlush( dpy ); + } + + return Success; +} + +int __glXCopyContext(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXCopyContextReq *be_req; + xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc; + GLXContextID source = req->source; + GLXContextID dest = req->dest; + GLXContextTag tag = req->contextTag; + unsigned long mask = req->mask; + __GLXcontext *src, *dst; + int s; + int from_screen = 0; + int to_screen = 0; + + /* + ** Check that each context exists. + */ + src = (__GLXcontext *) LookupIDByType(source, __glXContextRes); + if (!src) { + client->errorValue = source; + return __glXBadContext; + } + dst = (__GLXcontext *) LookupIDByType(dest, __glXContextRes); + if (!dst) { + client->errorValue = dest; + return __glXBadContext; + } + + /* + ** They must be in the same address space, and same screen. + */ + if (src->pGlxScreen != dst->pGlxScreen) { + client->errorValue = source; + return BadMatch; + } + + /* + ** The destination context must not be current for any client. + */ + if (dst->isCurrent) { + client->errorValue = dest; + return BadAccess; + } + + if (tag) { + __GLXcontext *tagcx = __glXLookupContextByTag(cl, tag); + + if (!tagcx) { + return __glXBadContextTag; + } + if (tagcx != src) { + /* + ** This would be caused by a faulty implementation of the client + ** library. + */ + return BadMatch; + } + } + + from_screen = to_screen = src->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReq(GLXCopyContext,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXCopyContext; + be_req->source = (unsigned int)src->real_ids[s-from_screen]; + be_req->dest = (unsigned int)dst->real_ids[s-from_screen]; + be_req->mask = mask; + be_req->contextTag = (tag ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); + UnlockDisplay(dpy); + SyncHandle(); + } + + return Success; +} + +int __glXGetVisualConfigs(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) pc; + xGLXGetVisualConfigsReply reply; + __GLXscreenInfo *pGlxScreen; + __GLXvisualConfig *pGlxVisual; + CARD32 buf[__GLX_TOTAL_CONFIG]; + unsigned int screen; + int i, p; + + screen = req->screen; + if (screen > screenInfo.numScreens) { + /* The client library must send a valid screen number. */ + client->errorValue = screen; + return BadValue; + } + pGlxScreen = &__glXActiveScreens[screen]; + + reply.numVisuals = pGlxScreen->numGLXVisuals; + reply.numProps = __GLX_TOTAL_CONFIG; + reply.length = (pGlxScreen->numGLXVisuals * __GLX_SIZE_CARD32 * + __GLX_TOTAL_CONFIG) >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char *)&reply); + + for (i=0; i < pGlxScreen->numVisuals; i++) { + pGlxVisual = &pGlxScreen->pGlxVisual[i]; + if (!pGlxScreen->isGLXvis[i] || pGlxVisual->vid == 0) { + /* not a usable visual */ + continue; + } + p = 0; + buf[p++] = pGlxVisual->vid; + buf[p++] = pGlxVisual->class; + buf[p++] = pGlxVisual->rgba; + + buf[p++] = pGlxVisual->redSize; + buf[p++] = pGlxVisual->greenSize; + buf[p++] = pGlxVisual->blueSize; + buf[p++] = pGlxVisual->alphaSize; + buf[p++] = pGlxVisual->accumRedSize; + buf[p++] = pGlxVisual->accumGreenSize; + buf[p++] = pGlxVisual->accumBlueSize; + buf[p++] = pGlxVisual->accumAlphaSize; + + buf[p++] = pGlxVisual->doubleBuffer; + buf[p++] = pGlxVisual->stereo; + + buf[p++] = pGlxVisual->bufferSize; + buf[p++] = pGlxVisual->depthSize; + buf[p++] = pGlxVisual->stencilSize; + buf[p++] = pGlxVisual->auxBuffers; + buf[p++] = pGlxVisual->level; + /* + ** Add token/value pairs for extensions. + */ + buf[p++] = GLX_VISUAL_CAVEAT_EXT; + buf[p++] = pGlxVisual->visualRating; + buf[p++] = GLX_TRANSPARENT_TYPE_EXT; + buf[p++] = pGlxVisual->transparentPixel; + buf[p++] = GLX_TRANSPARENT_RED_VALUE_EXT; + buf[p++] = pGlxVisual->transparentRed; + buf[p++] = GLX_TRANSPARENT_GREEN_VALUE_EXT; + buf[p++] = pGlxVisual->transparentGreen; + buf[p++] = GLX_TRANSPARENT_BLUE_VALUE_EXT; + buf[p++] = pGlxVisual->transparentBlue; + buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE_EXT; + buf[p++] = pGlxVisual->transparentAlpha; + buf[p++] = GLX_TRANSPARENT_INDEX_VALUE_EXT; + buf[p++] = pGlxVisual->transparentIndex; + buf[p++] = GLX_SAMPLES_SGIS; + buf[p++] = pGlxVisual->multiSampleSize; + buf[p++] = GLX_SAMPLE_BUFFERS_SGIS; + buf[p++] = pGlxVisual->nMultiSampleBuffers; + buf[p++] = GLX_VISUAL_SELECT_GROUP_SGIX; + buf[p++] = pGlxVisual->visualSelectGroup; + + WriteToClient(client, __GLX_SIZE_CARD32 * __GLX_TOTAL_CONFIG, + (char *)buf); + } + return Success; +} + +/* +** Create a GLX Pixmap from an X Pixmap. +*/ +static int CreateGLXPixmap(__GLXclientState *cl, + VisualID visual, GLXFBConfigID fbconfigId, + int screenNum, XID pixmapId, XID glxpixmapId ) +{ + ClientPtr client = cl->client; + xGLXCreateGLXPixmapReq *be_req; + xGLXCreatePixmapReq *be_new_req; + DrawablePtr pDraw; + ScreenPtr pScreen; + VisualPtr pVisual; + __GLXpixmap *pGlxPixmap; + __GLXscreenInfo *pGlxScreen; + __GLXvisualConfig *pGlxVisual; + __GLXFBConfig *pFBConfig; + int i, s, rc; + int from_screen, to_screen; +#ifdef PANORAMIX + PanoramiXRes *pXinDraw = NULL; +#endif + + rc = dixLookupDrawable(&pDraw, pixmapId, client, M_DRAWABLE_PIXMAP, + DixAddAccess); + if (rc != Success) + return rc; + + /* + ** Check if screen of visual matches screen of pixmap. + */ + pScreen = pDraw->pScreen; + if (screenNum != pScreen->myNum) { + return BadMatch; + } + + if (fbconfigId == NULL && visual == NULL) { + return BadValue; + } + + if (fbconfigId != None) { + pFBConfig = glxLookupFBConfig( fbconfigId ); + if (!pFBConfig) { + client->errorValue = fbconfigId; + return BadValue; + } + visual = pFBConfig->associatedVisualId; + } + else { + pFBConfig = NULL; + } + + if (visual != None) { + /* + ** Find the VisualRec for this visual. + */ + pVisual = pScreen->visuals; + for (i=0; i < pScreen->numVisuals; i++, pVisual++) { + if (pVisual->vid == visual) { + break; + } + } + if (i == pScreen->numVisuals) { + client->errorValue = visual; + return BadValue; + } + /* + ** Check if depth of visual matches depth of pixmap. + */ + if (pVisual->nplanes != pDraw->depth) { + client->errorValue = visual; + return BadMatch; + } + + /* + ** Get configuration of the visual. + */ + pGlxScreen = &__glXActiveScreens[screenNum]; + pGlxVisual = pGlxScreen->pGlxVisual; + for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { + if (pGlxVisual->vid == visual) { + break; + } + } + if (i == pGlxScreen->numVisuals) { + /* + ** Visual not support on this screen by this OpenGL implementation. + */ + client->errorValue = visual; + return BadValue; + } + + + /* find the FBConfig for that visual (if any) */ + if ( pFBConfig == NULL ) { + pFBConfig = glxLookupFBConfigByVID( visual ); + + if ( pFBConfig == NULL ) { + /* + * visual does not have an FBConfig ??? + client->errorValue = visual; + return BadValue; + */ + } + } + } + else { + pVisual = NULL; + pGlxVisual = NULL; + } + + pGlxPixmap = (__GLXpixmap *) __glXMalloc(sizeof(__GLXpixmap)); + if (!pGlxPixmap) { + return BadAlloc; + } + pGlxPixmap->be_xids = (XID *) __glXMalloc(sizeof(XID) * screenInfo.numScreens); + if (!pGlxPixmap->be_xids) { + __glXFree( pGlxPixmap ); + return BadAlloc; + } + + pGlxPixmap->pDraw = pDraw; + pGlxPixmap->pGlxScreen = pGlxScreen; + pGlxPixmap->pGlxVisual = pGlxVisual; + pGlxPixmap->pFBConfig = pFBConfig; + pGlxPixmap->pScreen = pScreen; + pGlxPixmap->idExists = True; + pGlxPixmap->refcnt = 0; + + /* + ** Bump the ref count on the X pixmap so it won't disappear. + */ + ((PixmapPtr) pDraw)->refcnt++; + + /* + * send the request to the back-end server(s) + */ + from_screen = to_screen = screenNum; +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + + pXinDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + Pixmap be_pixmap; + DrawablePtr pRealDraw = pDraw; + +#ifdef PANORAMIX + if (pXinDraw) { + dixLookupDrawable(&pRealDraw, pXinDraw->info[s].id, client, 0, + DixAddAccess); + } +#endif + + be_pixmap = (DMX_GET_PIXMAP_PRIV((PixmapPtr)pRealDraw))->pixmap; + + /* make sure pixmap already created on back-end */ + dmxSync( dmxScreen, 1 ); + + if ( pFBConfig && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + __GLXFBConfig *be_FBConfig = glxLookupBackEndFBConfig( pFBConfig->id, s ); + + LockDisplay(dpy); + pGlxPixmap->be_xids[s] = XAllocID(dpy); + GetReq(GLXCreatePixmap,be_new_req); + be_new_req->reqType = dmxScreen->glxMajorOpcode; + be_new_req->glxCode = X_GLXCreatePixmap; + be_new_req->screen = DefaultScreen(dpy); + be_new_req->fbconfig = be_FBConfig->id; + be_new_req->pixmap = (unsigned int)be_pixmap; + be_new_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; + be_new_req->numAttribs = 0; + UnlockDisplay(dpy); + SyncHandle(); + } + else if (pFBConfig && glxIsExtensionSupported("GLX_SGIX_fbconfig")) { + __GLXFBConfig *be_FBConfig = glxLookupBackEndFBConfig( pFBConfig->id, s ); + xGLXCreateGLXPixmapWithConfigSGIXReq *ext_req; + xGLXVendorPrivateReq *vpreq; + + LockDisplay(dpy); + pGlxPixmap->be_xids[s] = XAllocID(dpy); + GetReqExtra(GLXVendorPrivate, + sz_xGLXCreateGLXPixmapWithConfigSGIXReq-sz_xGLXVendorPrivateReq, + vpreq); + ext_req = (xGLXCreateGLXPixmapWithConfigSGIXReq *)vpreq; + ext_req->reqType = dmxScreen->glxMajorOpcode; + ext_req->glxCode = X_GLXVendorPrivate; + ext_req->vendorCode = X_GLXvop_CreateGLXPixmapWithConfigSGIX; + ext_req->screen = DefaultScreen(dpy); + ext_req->fbconfig = be_FBConfig->id; + ext_req->pixmap = (unsigned int)be_pixmap; + ext_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; + UnlockDisplay(dpy); + SyncHandle(); + } + else if (pGlxVisual) { + LockDisplay(dpy); + pGlxPixmap->be_xids[s] = XAllocID(dpy); + GetReq(GLXCreateGLXPixmap,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXCreateGLXPixmap; + be_req->screen = DefaultScreen(dpy); + be_req->visual = (unsigned int)glxMatchGLXVisualInConfigList( + pGlxVisual, + dmxScreen->glxVisuals, + dmxScreen->numGlxVisuals ); + be_req->pixmap = (unsigned int)be_pixmap; + be_req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; + UnlockDisplay(dpy); + SyncHandle(); + } + else { + client->errorValue = ( visual ? visual : fbconfigId ); + __glXFree( pGlxPixmap ); + return BadValue; + } + + XFlush( dpy ); + } + + if (!(AddResource(glxpixmapId, __glXPixmapRes, pGlxPixmap))) { + __glXFree( pGlxPixmap ); + return BadAlloc; + } + + return Success; +} + +int __glXCreateGLXPixmap(__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateGLXPixmapReq *req = (xGLXCreateGLXPixmapReq *) pc; + + return( CreateGLXPixmap(cl, req->visual, None, + req->screen, req->pixmap, req->glxpixmap) ); +} + +int __glXCreatePixmap(__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreatePixmapReq *req = (xGLXCreatePixmapReq *) pc; + + return( CreateGLXPixmap(cl, None, req->fbconfig, + req->screen, req->pixmap, req->glxpixmap) ); +} + +int __glXDestroyGLXPixmap(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc; + XID glxpixmap = req->glxpixmap; + __GLXpixmap *pGlxPixmap; + int s; + int from_screen, to_screen; + + /* + ** Check if it's a valid GLX pixmap. + */ + pGlxPixmap = (__GLXpixmap *)LookupIDByType(glxpixmap, __glXPixmapRes); + if (!pGlxPixmap) { + client->errorValue = glxpixmap; + return __glXBadPixmap; + } + FreeResource(glxpixmap, FALSE); + + /* + * destroy the pixmap on the back-end server(s). + */ + from_screen = to_screen = pGlxPixmap->pDraw->pScreen->myNum; +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + /* make sure pixmap exist in back-end */ + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReq(GLXDestroyGLXPixmap,req); + req->reqType = dmxScreen->glxMajorOpcode; + req->glxCode = X_GLXDestroyGLXPixmap; + req->glxpixmap = (unsigned int)pGlxPixmap->be_xids[s]; + UnlockDisplay(dpy); + SyncHandle(); + } + + + return Success; +} + +/*****************************************************************************/ + +/* +** NOTE: There is no portable implementation for swap buffers as of +** this time that is of value. Consequently, this code must be +** implemented by somebody other than SGI. +*/ +int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag) +{ + ClientPtr client = cl->client; + DrawablePtr pDraw; + xGLXSwapBuffersReq *be_req; + WindowPtr pWin = NULL; + __GLXpixmap *pGlxPixmap = NULL; + __GLXcontext *glxc = NULL; +#ifdef PANORAMIX + PanoramiXRes *pXinDraw = NULL; +#endif + __glXWindow *pGlxWindow = NULL; + int from_screen = 0; + int to_screen = 0; + int s, rc; + + /* + ** Check that the GLX drawable is valid. + */ + rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); + if (rc == Success) { + from_screen = to_screen = pDraw->pScreen->myNum; + + if (pDraw->type == DRAWABLE_WINDOW) { + /* + ** Drawable is an X window. + */ + pWin = (WindowPtr)pDraw; + } else { + /* + ** Drawable is an X pixmap, which is not allowed. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (!pDraw) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + /* + ** Drawable is a GLX pixmap. + */ + pDraw = pGlxPixmap->pDraw; + from_screen = to_screen = pGlxPixmap->pScreen->myNum; + } + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); + if (pGlxWindow) { + /* + ** Drawable is a GLXWindow. + */ + pDraw = pGlxWindow->pDraw; + from_screen = to_screen = pGlxWindow->pScreen->myNum; + } + } + + if (!pDraw) { + /* + ** Drawable is neither a X window nor a GLX pixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + + if (tag) { + glxc = __glXLookupContextByTag(cl, tag); + if (!glxc) { + return __glXBadContextTag; + } + } + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + pXinDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); + } +#endif + + /* If requested, send a glFinish to all back-end servers before swapping. */ + if (dmxGLXFinishSwap) { + for (s=from_screen; s<=to_screen; s++) { + Display *dpy = GetBackEndDisplay(cl,s); + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + xGLXSingleReq *finishReq; + xGLXSingleReply reply; + +#define X_GLXSingle 0 /* needed by GetReq below */ + + LockDisplay(dpy); + GetReq(GLXSingle,finishReq); + finishReq->reqType = dmxScreen->glxMajorOpcode; + finishReq->glxCode = X_GLsop_Finish; + finishReq->contextTag = (tag ? GetCurrentBackEndTag(cl,tag,s) : 0); + (void) _XReply(dpy, (xReply*) &reply, 0, False); + UnlockDisplay(dpy); + SyncHandle(); + } + } + + /* If requested, send an XSync to all back-end servers before swapping. */ + if (dmxGLXSyncSwap) { + for (s=from_screen; s<=to_screen; s++) + XSync(GetBackEndDisplay(cl,s), False); + } + + + /* send the SwapBuffers request to all back-end servers */ + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + unsigned int be_draw = 0; + + if (pGlxPixmap) { + be_draw = (unsigned int)pGlxPixmap->be_xids[s]; + } +#ifdef PANORAMIX + else if (pXinDraw) { + dixLookupWindow(&pWin, pXinDraw->info[s].id, client, DixReadAccess); + } +#endif + else if (pGlxWindow) { + pWin = (WindowPtr)pGlxWindow->pDraw; + } + + if (pWin && !be_draw) { + be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + if (!be_draw) { + /* it might be that the window did not created yet on the */ + /* back-end server (lazy window creation option), force */ + /* creation of the window */ + dmxCreateAndRealizeWindow( pWin, TRUE ); + be_draw = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + } + } + + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReq(GLXSwapBuffers,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXSwapBuffers; + be_req->drawable = be_draw; + be_req->contextTag = ( tag ? GetCurrentBackEndTag(cl,tag,s) : 0 ); + UnlockDisplay(dpy); + SyncHandle(); + XFlush(dpy); + } + + return Success; +} + +int __glXSwapBuffers(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + DrawablePtr pDraw; + xGLXSwapBuffersReq *req = (xGLXSwapBuffersReq *) pc; + GLXContextTag tag = req->contextTag; + XID drawId = req->drawable; + __GLXpixmap *pGlxPixmap = NULL; + __GLXcontext *glxc = NULL; + __glXWindow *pGlxWindow = NULL; + int rc; + + /* + ** Check that the GLX drawable is valid. + */ + rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixWriteAccess); + if (rc == Success) { + if (pDraw->type != DRAWABLE_WINDOW) { + /* + ** Drawable is an X pixmap, which is not allowed. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (!pDraw) { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + /* + ** Drawable is a GLX pixmap. + */ + pDraw = pGlxPixmap->pDraw; + } + } + + if (!pDraw && __GLX_IS_VERSION_SUPPORTED(1,3) ) { + pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); + if (pGlxWindow) { + /* + ** Drawable is a GLXWindow. + */ + pDraw = pGlxWindow->pDraw; + } + } + + if (!pDraw) { + /* + ** Drawable is neither a X window nor a GLX pixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + + if (tag) { + glxc = __glXLookupContextByTag(cl, tag); + if (!glxc) { + return __glXBadContextTag; + } + } + + if (pDraw && + pDraw->type == DRAWABLE_WINDOW && + DMX_GET_WINDOW_PRIV((WindowPtr)pDraw)->swapGroup) { + return SGSwapBuffers(cl, drawId, tag, pDraw); + } + + return __glXDoSwapBuffers(cl, drawId, tag); +} + + +/************************************************************************/ + +/* +** Render and Renderlarge are not in the GLX API. They are used by the GLX +** client library to send batches of GL rendering commands. +*/ + +/* +** Execute all the drawing commands in a request. +*/ +int __glXRender(__GLXclientState *cl, GLbyte *pc) +{ + xGLXRenderReq *req; + xGLXRenderReq *be_req; + int size; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + int s; + + /* + ** NOTE: much of this code also appears in the byteswapping version of this + ** routine, __glXSwapRender(). Any changes made here should also be + ** duplicated there. + */ + + req = (xGLXRenderReq *) pc; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXRenderReq; + size = (req->length << 2) - sz_xGLXRenderReq; + + /* + * just forward the request to back-end server(s) + */ + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReq(GLXRender,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXRender; + be_req->length = req->length; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + _XSend(dpy, (const char *)pc, size); + UnlockDisplay(dpy); + SyncHandle(); + } + + return Success; +} + +/* +** Execute a large rendering request (one that spans multiple X requests). +*/ +int __glXRenderLarge(__GLXclientState *cl, GLbyte *pc) +{ + xGLXRenderLargeReq *req; + xGLXRenderLargeReq *be_req; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + int s; + + /* + ** NOTE: much of this code also appears in the byteswapping version of this + ** routine, __glXSwapRenderLarge(). Any changes made here should also be + ** duplicated there. + */ + + req = (xGLXRenderLargeReq *) pc; + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXRenderLargeReq; + + /* + * just forward the request to back-end server(s) + */ + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + GetReq(GLXRenderLarge,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXRenderLarge; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + be_req->length = req->length; + be_req->requestNumber = req->requestNumber; + be_req->requestTotal = req->requestTotal; + be_req->dataBytes = req->dataBytes; + Data(dpy, (const char *)pc, req->dataBytes); + UnlockDisplay(dpy); + SyncHandle(); + + } + + return Success; +} + + +/************************************************************************/ + +int __glXVendorPrivate(__GLXclientState *cl, GLbyte *pc) +{ + xGLXVendorPrivateReq *req; + + req = (xGLXVendorPrivateReq *) pc; + + switch( req->vendorCode ) { + + case X_GLvop_DeleteTexturesEXT: + return __glXVForwardSingleReq( cl, pc ); + break; + + case X_GLXvop_SwapIntervalSGI: + if (glxIsExtensionSupported("SGI_swap_control")) { + return __glXVForwardSingleReq( cl, pc ); + } + else { + return Success; + } + break; + +#if 0 /* glx 1.3 */ + case X_GLXvop_CreateGLXVideoSourceSGIX: + break; + case X_GLXvop_DestroyGLXVideoSourceSGIX: + break; + case X_GLXvop_CreateGLXPixmapWithConfigSGIX: + break; + case X_GLXvop_DestroyGLXPbufferSGIX: + break; + case X_GLXvop_ChangeDrawableAttributesSGIX: + break; +#endif + + case X_GLXvop_BindSwapBarrierSGIX: + return __glXBindSwapBarrierSGIX( cl, pc ); + break; + + case X_GLXvop_JoinSwapGroupSGIX: + return __glXJoinSwapGroupSGIX( cl, pc ); + break; + + case X_GLXvop_CreateContextWithConfigSGIX: + return __glXCreateContextWithConfigSGIX( cl, pc ); + break; + + default: + /* + ** unsupported private request + */ + cl->client->errorValue = req->vendorCode; + return __glXUnsupportedPrivateRequest; + } + + cl->client->errorValue = req->vendorCode; + return __glXUnsupportedPrivateRequest; + +} + +int __glXVendorPrivateWithReply(__GLXclientState *cl, GLbyte *pc) +{ + xGLXVendorPrivateWithReplyReq *req; + + req = (xGLXVendorPrivateWithReplyReq *) pc; + + switch( req->vendorCode ) { + + case X_GLvop_GetConvolutionFilterEXT: + case X_GLvop_GetConvolutionParameterfvEXT: + case X_GLvop_GetConvolutionParameterivEXT: + case X_GLvop_GetSeparableFilterEXT: + case X_GLvop_GetHistogramEXT: + case X_GLvop_GetHistogramParameterivEXT: + case X_GLvop_GetMinmaxEXT: + case X_GLvop_GetMinmaxParameterfvEXT: + case X_GLvop_GetMinmaxParameterivEXT: + case X_GLvop_AreTexturesResidentEXT: + case X_GLvop_IsTextureEXT: + return( __glXVForwardPipe0WithReply(cl, pc) ); + break; + + case X_GLvop_GenTexturesEXT: + return( __glXVForwardAllWithReply(cl, pc) ); + break; + + +#if 0 /* glx1.3 */ + case X_GLvop_GetDetailTexFuncSGIS: + case X_GLvop_GetSharpenTexFuncSGIS: + case X_GLvop_GetColorTableSGI: + case X_GLvop_GetColorTableParameterfvSGI: + case X_GLvop_GetColorTableParameterivSGI: + case X_GLvop_GetTexFilterFuncSGIS: + case X_GLvop_GetInstrumentsSGIX: + case X_GLvop_InstrumentsBufferSGIX: + case X_GLvop_PollInstrumentsSGIX: + case X_GLvop_FlushRasterSGIX: + case X_GLXvop_CreateGLXPbufferSGIX: + case X_GLXvop_GetDrawableAttributesSGIX: + case X_GLXvop_QueryHyperpipeNetworkSGIX: + case X_GLXvop_QueryHyperpipeConfigSGIX: + case X_GLXvop_HyperpipeConfigSGIX: + case X_GLXvop_DestroyHyperpipeConfigSGIX: +#endif + case X_GLXvop_QueryMaxSwapBarriersSGIX: + return( __glXQueryMaxSwapBarriersSGIX(cl, pc) ); + break; + + case X_GLXvop_GetFBConfigsSGIX: + return( __glXGetFBConfigsSGIX(cl, pc) ); + break; + + case X_GLXvop_MakeCurrentReadSGI: + return( __glXMakeCurrentReadSGI(cl, pc) ); + break; + + case X_GLXvop_QueryContextInfoEXT: + return( __glXQueryContextInfoEXT(cl,pc) ); + break; + + default: + /* + ** unsupported private request + */ + cl->client->errorValue = req->vendorCode; + return __glXUnsupportedPrivateRequest; + } + +} + +int __glXQueryExtensionsString(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXQueryExtensionsStringReq *req = (xGLXQueryExtensionsStringReq *) pc; + xGLXQueryExtensionsStringReply reply; + GLint screen; + size_t length; + int len, numbytes; + char *be_buf; + +#ifdef FWD_QUERY_REQ + xGLXQueryExtensionsStringReq *be_req; + xGLXQueryExtensionsStringReply be_reply; + DMXScreenInfo *dmxScreen; + Display *dpy; + int slop; +#endif + + screen = req->screen; + + /* + ** Check if screen exists. + */ + if ((screen < 0) || (screen >= screenInfo.numScreens)) { + client->errorValue = screen; + return BadValue; + } + +#ifdef FWD_QUERY_REQ + dmxScreen = &dmxScreens[screen]; + + /* Send the glXQueryServerString request */ + dpy = GetBackEndDisplay(cl,screen); + LockDisplay(dpy); + GetReq(GLXQueryExtensionsString,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXQueryServerString; + be_req->screen = DefaultScreen(dpy); + _XReply(dpy, (xReply*) &be_reply, 0, False); + len = (int)be_reply.length; + numbytes = (int)be_reply.n; + slop = numbytes * __GLX_SIZE_INT8 & 3; + be_buf = (char *)malloc(numbytes); + if (!be_buf) { + /* Throw data on the floor */ + _XEatData(dpy, len); + } else { + _XRead(dpy, (char *)be_buf, numbytes); + if (slop) _XEatData(dpy,4-slop); + } + UnlockDisplay(dpy); + SyncHandle(); + +#else + + be_buf = __glXGetServerString(GLX_EXTENSIONS); + numbytes = strlen(be_buf) + 1; + len = __GLX_PAD(numbytes) >> 2; + +#endif + + length = len; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = len; + reply.n = numbytes; + + if (client->swapped) { + glxSwapQueryExtensionsStringReply(client, &reply, be_buf); + } else { + WriteToClient(client, sz_xGLXQueryExtensionsStringReply,(char *)&reply); + WriteToClient(client, (int)(length << 2), (char *)be_buf); + } + + return Success; +} + +int __glXQueryServerString(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) pc; + xGLXQueryServerStringReply reply; + int name; + GLint screen; + size_t length; + int len, numbytes; + char *be_buf; +#ifdef FWD_QUERY_REQ + xGLXQueryServerStringReq *be_req; + xGLXQueryServerStringReply be_reply; + DMXScreenInfo *dmxScreen; + Display *dpy; + int slop; +#endif + + name = req->name; + screen = req->screen; + /* + ** Check if screen exists. + */ + if ((screen < 0) || (screen >= screenInfo.numScreens)) { + client->errorValue = screen; + return BadValue; + } + +#ifdef FWD_QUERY_REQ + dmxScreen = &dmxScreens[screen]; + + /* Send the glXQueryServerString request */ + dpy = GetBackEndDisplay(cl,screen); + LockDisplay(dpy); + GetReq(GLXQueryServerString,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXQueryServerString; + be_req->screen = DefaultScreen(dpy); + be_req->name = name; + _XReply(dpy, (xReply*) &be_reply, 0, False); + len = (int)be_reply.length; + numbytes = (int)be_reply.n; + slop = numbytes * __GLX_SIZE_INT8 & 3; + be_buf = (char *)malloc(numbytes); + if (!be_buf) { + /* Throw data on the floor */ + _XEatData(dpy, len); + } else { + _XRead(dpy, (char *)be_buf, numbytes); + if (slop) _XEatData(dpy,4-slop); + } + UnlockDisplay(dpy); + SyncHandle(); + +#else + be_buf = __glXGetServerString(name); + numbytes = strlen(be_buf) + 1; + len = __GLX_PAD(numbytes) >> 2; +#endif + + length = len; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = length; + reply.n = numbytes; + + if (client->swapped) { + glxSwapQueryServerStringReply(client, &reply, be_buf); + } else { + WriteToClient(client, sz_xGLXQueryServerStringReply, (char *)&reply); + WriteToClient(client, (int)(length << 2), be_buf); + } + + return Success; +} + +int __glXClientInfo(__GLXclientState *cl, GLbyte *pc) +{ + xGLXClientInfoReq *req = (xGLXClientInfoReq *) pc; + xGLXClientInfoReq *be_req; + const char *buf; + int from_screen = 0; + int to_screen = 0; + int s; + + cl->GLClientmajorVersion = req->major; + cl->GLClientminorVersion = req->minor; + if (cl->GLClientextensions) __glXFree(cl->GLClientextensions); + buf = (const char *)(req+1); + cl->GLClientextensions = strdup(buf); + + to_screen = screenInfo.numScreens - 1; + + for (s=from_screen; s<=to_screen; s++) + { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReq(GLXClientInfo,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXClientInfo; + be_req->major = req->major; + be_req->minor = req->minor; + be_req->length = req->length; + be_req->numbytes = req->numbytes; + Data(dpy, buf, req->numbytes); + + UnlockDisplay(dpy); + SyncHandle(); + } + + return Success; +} + +int __glXUseXFont(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXUseXFontReq *req; + xGLXUseXFontReq *be_req; + FontPtr pFont; + __GLXcontext *glxc = NULL; + int from_screen = 0; + int to_screen = 0; + int s; + dmxFontPrivPtr pFontPriv; + DMXScreenInfo *dmxScreen; + Display *dpy; + + req = (xGLXUseXFontReq *) pc; + + if (req->contextTag != 0) { + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (glxc) { + from_screen = to_screen = glxc->pScreen->myNum; + } + } + + /* + ** Font can actually be either the ID of a font or the ID of a GC + ** containing a font. + */ + pFont = (FontPtr)LookupIDByType(req->font, RT_FONT); + if (!pFont) { + GC *pGC = (GC *)LookupIDByType(req->font, RT_GC); + if (!pGC) { + client->errorValue = req->font; + return BadFont; + } + pFont = pGC->font; + } + + pFontPriv = FontGetPrivate(pFont, dmxFontPrivateIndex); + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + + for (s=from_screen; s<=to_screen; s++) { + dmxScreen = &dmxScreens[s]; + dpy = GetBackEndDisplay(cl,s); + + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReq(GLXUseXFont,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXUseXFont; + be_req->contextTag = (glxc ? GetCurrentBackEndTag(cl,req->contextTag,s) : 0); + be_req->font = pFontPriv->font[s]->fid; + be_req->first = req->first; + be_req->count = req->count; + be_req->listBase = req->listBase; + UnlockDisplay(dpy); + SyncHandle(); + + XSync( dpy, False ); + } + + return Success; +} + +/* + * start GLX 1.3 here + */ + +int __glXGetFBConfigs(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXGetFBConfigsReq *req = (xGLXGetFBConfigsReq *) pc; + xGLXGetFBConfigsReply reply; + __GLXFBConfig *pFBConfig; + CARD32 buf[2 * __GLX_TOTAL_FBCONFIG_PROPS]; + int numAttribs = __GLX_TOTAL_FBCONFIG_PROPS; + unsigned int screen = req->screen; + int numFBConfigs, i, p; + __GLXscreenInfo *pGlxScreen; + + if (screen > screenInfo.numScreens) { + /* The client library must send a valid screen number. */ + client->errorValue = screen; + return BadValue; + } + + pGlxScreen = &__glXActiveScreens[screen]; + numFBConfigs = __glXNumFBConfigs; + + reply.numFBConfigs = numFBConfigs; + reply.numAttribs = numAttribs; + reply.length = (numFBConfigs * 2 * numAttribs * __GLX_SIZE_CARD32) >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + __GLX_SWAP_INT(&reply.numFBConfigs); + __GLX_SWAP_INT(&reply.numAttribs); + } + WriteToClient(client, sz_xGLXGetFBConfigsReply, (char *)&reply); + + for (i=0; i < numFBConfigs; i++) { + int associatedVisualId = 0; + int drawableTypeIndex; + pFBConfig = __glXFBConfigs[ i * (screenInfo.numScreens+1) ]; + + p = 0; + /* core attributes */ + buf[p++] = GLX_FBCONFIG_ID; + buf[p++] = pFBConfig->id; + buf[p++] = GLX_BUFFER_SIZE; + buf[p++] = pFBConfig->indexBits; + buf[p++] = GLX_LEVEL; + buf[p++] = pFBConfig->level; + buf[p++] = GLX_DOUBLEBUFFER; + buf[p++] = pFBConfig->doubleBufferMode; + buf[p++] = GLX_STEREO; + buf[p++] = pFBConfig->stereoMode; + buf[p++] = GLX_AUX_BUFFERS; + buf[p++] = pFBConfig->maxAuxBuffers; + buf[p++] = GLX_RED_SIZE; + buf[p++] = pFBConfig->redBits; + buf[p++] = GLX_GREEN_SIZE; + buf[p++] = pFBConfig->greenBits; + buf[p++] = GLX_BLUE_SIZE; + buf[p++] = pFBConfig->blueBits; + buf[p++] = GLX_ALPHA_SIZE; + buf[p++] = pFBConfig->alphaBits; + buf[p++] = GLX_DEPTH_SIZE; + buf[p++] = pFBConfig->depthBits; + buf[p++] = GLX_STENCIL_SIZE; + buf[p++] = pFBConfig->stencilBits; + buf[p++] = GLX_ACCUM_RED_SIZE; + buf[p++] = pFBConfig->accumRedBits; + buf[p++] = GLX_ACCUM_GREEN_SIZE; + buf[p++] = pFBConfig->accumGreenBits; + buf[p++] = GLX_ACCUM_BLUE_SIZE; + buf[p++] = pFBConfig->accumBlueBits; + buf[p++] = GLX_ACCUM_ALPHA_SIZE; + buf[p++] = pFBConfig->accumAlphaBits; + buf[p++] = GLX_RENDER_TYPE; + buf[p++] = pFBConfig->renderType; + buf[p++] = GLX_DRAWABLE_TYPE; + drawableTypeIndex = p; + buf[p++] = pFBConfig->drawableType; + buf[p++] = GLX_X_VISUAL_TYPE; + buf[p++] = pFBConfig->visualType; + buf[p++] = GLX_CONFIG_CAVEAT; + buf[p++] = pFBConfig->visualCaveat; + buf[p++] = GLX_TRANSPARENT_TYPE; + buf[p++] = pFBConfig->transparentType; + buf[p++] = GLX_TRANSPARENT_RED_VALUE; + buf[p++] = pFBConfig->transparentRed; + buf[p++] = GLX_TRANSPARENT_GREEN_VALUE; + buf[p++] = pFBConfig->transparentGreen; + buf[p++] = GLX_TRANSPARENT_BLUE_VALUE; + buf[p++] = pFBConfig->transparentBlue; + buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE; + buf[p++] = pFBConfig->transparentAlpha; + buf[p++] = GLX_TRANSPARENT_INDEX_VALUE; + buf[p++] = pFBConfig->transparentIndex; + buf[p++] = GLX_MAX_PBUFFER_WIDTH; + buf[p++] = pFBConfig->maxPbufferWidth; + buf[p++] = GLX_MAX_PBUFFER_HEIGHT; + buf[p++] = pFBConfig->maxPbufferHeight; + buf[p++] = GLX_MAX_PBUFFER_PIXELS; + buf[p++] = pFBConfig->maxPbufferPixels; + + /* + * find the visual of the back-end server and match a visual + * on the proxy. + * do only once - if a visual is not yet associated. + */ + if (pFBConfig->associatedVisualId == (unsigned int)-1) { + DMXScreenInfo *dmxScreen = &dmxScreens[screen]; + __GLXFBConfig *be_pFBConfig = __glXFBConfigs[ i * (screenInfo.numScreens+1)+screen+1 ]; + __GLXvisualConfig *pGlxVisual = NULL; + int v; + int found = 0; + for (v=0; v<dmxScreen->numGlxVisuals; v++) { + if (dmxScreen->glxVisuals[v].vid == be_pFBConfig->associatedVisualId) { + pGlxVisual = &dmxScreen->glxVisuals[v]; + break; + } + } + + if (pGlxVisual) { + for (v=0; v<pGlxScreen->numVisuals; v++) { + if (glxVisualsMatch(&pGlxScreen->pGlxVisual[v], pGlxVisual)) { + associatedVisualId = pGlxScreen->pGlxVisual[v].vid; + found = 1; + break; + } + } + } + + if (!found) { + associatedVisualId = 0; + pFBConfig->drawableType &= ~(GLX_WINDOW_BIT); + buf[drawableTypeIndex] = pFBConfig->drawableType; + } +#ifdef PANORAMIX + else if (!noPanoramiXExtension) { + /* convert the associated visualId to the panoramix one */ + pFBConfig->associatedVisualId = + PanoramiXTranslateVisualID(screen, v); + } +#endif + } + else { + associatedVisualId = pFBConfig->associatedVisualId; + } + + buf[p++] = GLX_VISUAL_ID; + buf[p++] = associatedVisualId; + + /* SGIS_multisample attributes */ + buf[p++] = GLX_SAMPLES_SGIS; + buf[p++] = pFBConfig->multiSampleSize; + buf[p++] = GLX_SAMPLE_BUFFERS_SGIS; + buf[p++] = pFBConfig->nMultiSampleBuffers; + + /* SGIX_pbuffer specific attributes */ + buf[p++] = GLX_OPTIMAL_PBUFFER_WIDTH_SGIX; + buf[p++] = pFBConfig->optimalPbufferWidth; + buf[p++] = GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX; + buf[p++] = pFBConfig->optimalPbufferHeight; + + buf[p++] = GLX_VISUAL_SELECT_GROUP_SGIX; + buf[p++] = pFBConfig->visualSelectGroup; + + if (client->swapped) { + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_SWAP_INT_ARRAY((int *)buf, 2*numAttribs); + } + WriteToClient(client, 2*numAttribs * __GLX_SIZE_CARD32, (char *)buf); + } + return Success; +} + +int __glXGetFBConfigsSGIX(__GLXclientState *cl, GLbyte *pc) +{ + xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *)pc; + xGLXGetFBConfigsReq new_req; + + new_req.reqType = req->reqType; + new_req.glxCode = req->glxCode; + new_req.length = req->length; + new_req.screen = req->screen; + + return( __glXGetFBConfigs( cl, (GLbyte *)&new_req ) ); +} + + +int __glXCreateWindow(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXCreateWindowReq *req = (xGLXCreateWindowReq *) pc; + int screen = req->screen; + GLXFBConfigID fbconfigId = req->fbconfig; + XID windowId = req->window; + XID glxwindowId = req->glxwindow; + DrawablePtr pDraw; + ScreenPtr pScreen; + __glXWindow *pGlxWindow; + __GLXFBConfig *pGlxFBConfig = NULL; + VisualPtr pVisual; + VisualID visId; + int i, rc; + + /* + ** Check if windowId is valid + */ + rc = dixLookupDrawable(&pDraw, windowId, client, M_DRAWABLE_WINDOW, + DixAddAccess); + if (rc != Success) + return rc; + + /* + ** Check if screen of window matches screen of fbconfig. + */ + pScreen = pDraw->pScreen; + if (screen != pScreen->myNum) { + return BadMatch; + } + + /* + ** Find the FBConfigRec for this fbconfigid. + */ + if (!(pGlxFBConfig = glxLookupFBConfig(fbconfigId))) { + client->errorValue = fbconfigId; + return __glXBadFBConfig; + } + visId = pGlxFBConfig->associatedVisualId; + + /* + ** Check if the fbconfig supports rendering to windows + */ + if( !(pGlxFBConfig->drawableType & GLX_WINDOW_BIT) ) { + return BadMatch; + } + + if (visId != None) { + /* + ** Check if the visual ID is valid for this screen. + */ + pVisual = pScreen->visuals; + for (i = 0; i < pScreen->numVisuals; i++, pVisual++) { + if (pVisual->vid == visId) { + break; + } + } + if (i == pScreen->numVisuals) { + client->errorValue = visId; + return BadValue; + } + + /* + ** Check if color buffer depth of fbconfig matches depth + ** of window. + */ + if (pVisual->nplanes != pDraw->depth) { + return BadMatch; + } + } else + /* + ** The window was created with no visual that corresponds + ** to fbconfig + */ + return BadMatch; + + /* + ** Check if there is already a fbconfig associated with this window + */ + if ( LookupIDByType(glxwindowId, __glXWindowRes) ) { + client->errorValue = glxwindowId; + return BadAlloc; + } + + pGlxWindow = (__glXWindow *) malloc(sizeof(__glXWindow)); + if (!pGlxWindow) { + return BadAlloc; + } + + /* + ** Register this GLX window as a resource + */ + if (!(AddResource(glxwindowId, __glXWindowRes, pGlxWindow))) { + return BadAlloc; + } + + pGlxWindow->pDraw = pDraw; + pGlxWindow->type = GLX_GLXWINDOW_TYPE; + pGlxWindow->idExists = True; + pGlxWindow->refcnt = 0; + pGlxWindow->pGlxFBConfig = pGlxFBConfig; + pGlxWindow->pScreen = pScreen; + + return Success; +} + +int __glXDestroyWindow(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXDestroyWindowReq *req = (xGLXDestroyWindowReq *) pc; + XID glxwindow = req->glxwindow; + + /* + ** Check if it's a valid GLX window. + */ + if (!LookupIDByType(glxwindow, __glXWindowRes)) { + client->errorValue = glxwindow; + return __glXBadDrawable; + } + /* + ** The glx window destructor will check whether it's current before + ** freeing anything. + */ + FreeResource(glxwindow, RT_NONE); + + return Success; +} + +int __glXQueryContext(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + __GLXcontext *ctx; + xGLXQueryContextReq *req; + xGLXQueryContextReply reply; + int nProps; + int *sendBuf, *pSendBuf; + int nReplyBytes; + + req = (xGLXQueryContextReq *)pc; + ctx = (__GLXcontext *) LookupIDByType(req->context, __glXContextRes); + if (!ctx) { + client->errorValue = req->context; + return __glXBadContext; + } + + nProps = 3; + + reply.length = nProps << 1; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.n = nProps; + + nReplyBytes = reply.length << 2; + sendBuf = (int *)malloc(nReplyBytes); + pSendBuf = sendBuf; + *pSendBuf++ = GLX_FBCONFIG_ID; + *pSendBuf++ = (int)(ctx->pFBConfig->id); + *pSendBuf++ = GLX_RENDER_TYPE; + *pSendBuf++ = (int)(ctx->pFBConfig->renderType); + *pSendBuf++ = GLX_SCREEN; + *pSendBuf++ = (int)(ctx->pScreen->myNum); + + if (client->swapped) { + __glXSwapQueryContextReply(client, &reply, sendBuf); + } else { + WriteToClient(client, sz_xGLXQueryContextReply, (char *)&reply); + WriteToClient(client, nReplyBytes, (char *)sendBuf); + } + free((char *)sendBuf); + + return Success; +} + +int __glXQueryContextInfoEXT(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + __GLXcontext *ctx; + xGLXQueryContextInfoEXTReq *req; + xGLXQueryContextInfoEXTReply reply; + int nProps; + int *sendBuf, *pSendBuf; + int nReplyBytes; + + req = (xGLXQueryContextInfoEXTReq *)pc; + ctx = (__GLXcontext *) SecurityLookupIDByType(client, req->context, __glXContextRes, DixReadAccess); + if (!ctx) { + client->errorValue = req->context; + return __glXBadContext; + } + + nProps = 4; + + reply.length = nProps << 1; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.n = nProps; + + nReplyBytes = reply.length << 2; + sendBuf = (int *)malloc(nReplyBytes); + pSendBuf = sendBuf; + *pSendBuf++ = GLX_SHARE_CONTEXT_EXT; + *pSendBuf++ = (int)(ctx->share_id); + *pSendBuf++ = GLX_VISUAL_ID_EXT; + *pSendBuf++ = (int)(ctx->pVisual ? ctx->pVisual->vid : 0); + *pSendBuf++ = GLX_SCREEN_EXT; + *pSendBuf++ = (int)(ctx->pScreen->myNum); + *pSendBuf++ = GLX_FBCONFIG_ID; + *pSendBuf++ = (int)(ctx->pFBConfig ? ctx->pFBConfig->id : 0); + + if (client->swapped) { + __glXSwapQueryContextInfoEXTReply(client, &reply, sendBuf); + } else { + WriteToClient(client, sz_xGLXQueryContextInfoEXTReply, (char *)&reply); + WriteToClient(client, nReplyBytes, (char *)sendBuf); + } + free((char *)sendBuf); + + return Success; +} + +int __glXCreatePbuffer(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXCreatePbufferReq *req = (xGLXCreatePbufferReq *)pc; + xGLXCreatePbufferReq *be_req; + int screen = req->screen; + GLXFBConfigID fbconfigId = req->fbconfig; + GLXPbuffer pbuffer = req->pbuffer; + __glXPbuffer *pGlxPbuffer; + int numAttribs = req->numAttribs; + int *attr; + ScreenPtr pScreen; + __GLXFBConfig *pGlxFBConfig; + __GLXFBConfig *be_pGlxFBConfig; + XID be_xid; + Display *dpy; + DMXScreenInfo *dmxScreen; + int s; + int from_screen, to_screen; + + /* + ** Look up screen and FBConfig. + */ + if (screen > screenInfo.numScreens) { + /* The client library must send a valid screen number. */ + client->errorValue = screen; + return BadValue; + } + pScreen = screenInfo.screens[screen]; + + /* + ** Find the FBConfigRec for this fbconfigid. + */ + if (!(pGlxFBConfig = glxLookupFBConfig(fbconfigId))) { + client->errorValue = fbconfigId; + return __glXBadFBConfig; + } + + /* + ** Create the GLX part of the Pbuffer. + */ + pGlxPbuffer = (__glXPbuffer *) malloc(sizeof(__glXPbuffer)); + if (!pGlxPbuffer) { + return BadAlloc; + } + + pGlxPbuffer->be_xids = (XID *) malloc( sizeof(XID) * screenInfo.numScreens ); + if (!pGlxPbuffer->be_xids) { + free(pGlxPbuffer); + return BadAlloc; + } + + /* + * Allocate an XID on the back-end server(s) and send him the request + */ + from_screen = to_screen = screen; +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + dpy = GetBackEndDisplay(cl,s); + be_xid = XAllocID(dpy); + dmxScreen = &dmxScreens[s]; + be_pGlxFBConfig = glxLookupBackEndFBConfig( pGlxFBConfig->id, s ); + + attr = (int *)( req+1 ); + + LockDisplay(dpy); + GetReqExtra(GLXCreatePbuffer, 2 * numAttribs * __GLX_SIZE_CARD32, be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXCreatePbuffer; + be_req->screen = be_pGlxFBConfig->screen; + be_req->fbconfig = be_pGlxFBConfig->id; + be_req->pbuffer = be_xid; + be_req->numAttribs = numAttribs; + + /* Send attributes */ + if ( attr != NULL ) { + CARD32 *pc = (CARD32 *)(be_req + 1); + + while (numAttribs-- > 0) { + *pc++ = *attr++; /* token */ + *pc++ = *attr++; /* value */ + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + pGlxPbuffer->be_xids[s] = be_xid; + } + + + pGlxPbuffer->idExists = True; + pGlxPbuffer->refcnt = 0; + pGlxPbuffer->pFBConfig = pGlxFBConfig; + pGlxPbuffer->pScreen = pScreen; + + /* + ** Register the resource. + */ + if (!(AddResource(pbuffer, __glXPbufferRes, pGlxPbuffer))) { + return BadAlloc; + } + + return Success; + +} + +int __glXDestroyPbuffer(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXDestroyPbufferReq *req = (xGLXDestroyPbufferReq *) pc; + xGLXDestroyPbufferReq *be_req; + GLXPbuffer pbuffer = req->pbuffer; + Display *dpy; + int screen; + DMXScreenInfo *dmxScreen; + __glXPbuffer *pGlxPbuffer; + int s; + int from_screen, to_screen; + + /* + ** Check if it's a valid Pbuffer + */ + pGlxPbuffer = (__glXPbuffer *)LookupIDByType(pbuffer, __glXPbufferRes); + if (!pGlxPbuffer) { + client->errorValue = pbuffer; + return __glXBadPbuffer; + } + + screen = pGlxPbuffer->pScreen->myNum; + + from_screen = to_screen = screen; +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + for (s=from_screen; s<=to_screen; s++) { + dpy = GetBackEndDisplay(cl,s); + dmxScreen = &dmxScreens[s]; + + /* send the destroy request to the back-end server */ + LockDisplay(dpy); + GetReq(GLXDestroyPbuffer, be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXDestroyPbuffer; + be_req->pbuffer = pGlxPbuffer->be_xids[s]; + UnlockDisplay(dpy); + SyncHandle(); + } + + FreeResource(pbuffer, RT_NONE); + + return Success; +} + +int __glXGetDrawableAttributes(__GLXclientState *cl, GLbyte *pc) +{ + xGLXGetDrawableAttributesReq *req = (xGLXGetDrawableAttributesReq *)pc; + xGLXGetDrawableAttributesReq *be_req; + xGLXGetDrawableAttributesReply reply; + ClientPtr client = cl->client; + GLXDrawable drawId = req->drawable; + GLXDrawable be_drawable = 0; + DrawablePtr pDraw = NULL; + Display *dpy; + int screen, rc; + DMXScreenInfo *dmxScreen; + CARD32 *attribs = NULL; + int attribs_size; +#ifdef PANORAMIX + PanoramiXRes *pXinDraw = NULL; +#endif + + if (drawId != None) { + rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixGetAttrAccess); + if (rc == Success) { + if (pDraw->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDraw; + be_drawable = 0; + screen = pWin->drawable.pScreen->myNum; + + } + else { + /* + ** Drawable is not a Window , GLXWindow or a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (!pDraw) { + __GLXpixmap *pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + pDraw = pGlxPixmap->pDraw; + screen = pGlxPixmap->pScreen->myNum; + be_drawable = pGlxPixmap->be_xids[screen]; + } + } + + if (!pDraw) { + __glXWindow *pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); + if (pGlxWindow) { + pDraw = pGlxWindow->pDraw; + screen = pGlxWindow->pScreen->myNum; + be_drawable = 0; + } + } + + if (!pDraw) { + __glXPbuffer *pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); + if (pGlxPbuffer) { + pDraw = (DrawablePtr)pGlxPbuffer; + screen = pGlxPbuffer->pScreen->myNum; + be_drawable = pGlxPbuffer->be_xids[screen]; + } + } + + + if (!pDraw) { + /* + ** Drawable is not a Window , GLXWindow or a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + + /* if the drawable is a window or GLXWindow - + * we need to find the base id on the back-end server + */ + if (!be_drawable) { + WindowPtr pWin = (WindowPtr)pDraw; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + pXinDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); + if (!pXinDraw) { + client->errorValue = drawId; + return __glXBadDrawable; + } + + dixLookupWindow(&pWin, pXinDraw->info[screen].id, client, + DixReadAccess); + } +#endif + + if (pWin) { + be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + if (!be_drawable) { + /* it might be that the window did not created yet on the */ + /* back-end server (lazy window creation option), force */ + /* creation of the window */ + dmxCreateAndRealizeWindow( pWin, TRUE ); + be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + } + } + else { + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + + /* send the request to the back-end server */ + dpy = GetBackEndDisplay(cl,screen); + dmxScreen = &dmxScreens[screen]; + + /* make sure drawable exists on back-end */ + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReq(GLXGetDrawableAttributes, be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXGetDrawableAttributes; + be_req->drawable = be_drawable; + be_req->length = req->length; + if (!_XReply(dpy, (xReply *) &reply, 0, False)) { + UnlockDisplay(dpy); + SyncHandle(); + return( BE_TO_CLIENT_ERROR(dmxLastErrorEvent.error_code) ); + } + + if (reply.numAttribs) { + attribs_size = 2 * reply.numAttribs * __GLX_SIZE_CARD32; + attribs = (CARD32 *) malloc(attribs_size); + if (attribs == NULL) { + UnlockDisplay(dpy); + SyncHandle(); + return BadAlloc; + } + + _XRead(dpy, (char *) attribs, attribs_size); + } + + UnlockDisplay(dpy); + SyncHandle(); + + + /* send the reply back to the client */ + reply.sequenceNumber = client->sequence; + if (client->swapped) { + __glXSwapGetDrawableAttributesReply(client, &reply, (int *)attribs); + } + else { + WriteToClient(client, sz_xGLXGetDrawableAttributesReply, (char *)&reply); + WriteToClient(client, attribs_size, (char *)attribs); + } + + Xfree(attribs); + + return Success; +} + +int __glXChangeDrawableAttributes(__GLXclientState *cl, GLbyte *pc) +{ + xGLXChangeDrawableAttributesReq *req = (xGLXChangeDrawableAttributesReq *)pc; + xGLXChangeDrawableAttributesReq *be_req; + ClientPtr client = cl->client; + GLXDrawable drawId = req->drawable; + GLXDrawable be_drawable = 0; + DrawablePtr pDraw = NULL; + Display *dpy; + int screen, rc; + DMXScreenInfo *dmxScreen; + char *attrbuf; +#ifdef PANORAMIX + PanoramiXRes *pXinDraw = NULL; + PanoramiXRes *pXinReadDraw = NULL; +#endif + + if (drawId != None) { + rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixSetAttrAccess); + if (rc == Success) { + if (pDraw->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDraw; + be_drawable = 0; + screen = pWin->drawable.pScreen->myNum; + + } + else { + /* + ** Drawable is not a Window , GLXWindow or a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (!pDraw) { + __GLXpixmap *pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + pDraw = pGlxPixmap->pDraw; + screen = pGlxPixmap->pScreen->myNum; + be_drawable = pGlxPixmap->be_xids[screen]; + } + } + + if (!pDraw) { + __glXWindow *pGlxWindow = (__glXWindow *) LookupIDByType(drawId, __glXWindowRes); + if (pGlxWindow) { + pDraw = pGlxWindow->pDraw; + screen = pGlxWindow->pScreen->myNum; + be_drawable = 0; + } + } + + if (!pDraw) { + __glXPbuffer *pGlxPbuffer = (__glXPbuffer *)LookupIDByType(drawId, __glXPbufferRes); + if (pGlxPbuffer) { + pDraw = (DrawablePtr)pGlxPbuffer; + screen = pGlxPbuffer->pScreen->myNum; + be_drawable = pGlxPbuffer->be_xids[screen]; + } + } + + + if (!pDraw) { + /* + ** Drawable is not a Window , GLXWindow or a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + + /* if the drawable is a window or GLXWindow - + * we need to find the base id on the back-end server + */ + if (!be_drawable) { + WindowPtr pWin = (WindowPtr)pDraw; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + pXinDraw = (PanoramiXRes *) + SecurityLookupIDByClass(client, pDraw->id, XRC_DRAWABLE, DixReadAccess); + if (!pXinDraw) { + client->errorValue = drawId; + return __glXBadDrawable; + } + + dixLookupWindow(&pWin, pXinDraw->info[screen].id, client, + DixReadAccess); + } +#endif + + if (pWin) { + be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + if (!be_drawable) { + /* it might be that the window did not created yet on the */ + /* back-end server (lazy window creation option), force */ + /* creation of the window */ + dmxCreateAndRealizeWindow( pWin, TRUE ); + be_drawable = (unsigned int)(DMX_GET_WINDOW_PRIV(pWin))->window; + } + } + else { + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + + /* send the request to the back-end server */ + dpy = GetBackEndDisplay(cl,screen); + dmxScreen = &dmxScreens[screen]; + + /* make sure drawable exists on back-end */ + dmxSync( dmxScreen, 1 ); + + LockDisplay(dpy); + GetReqExtra(GLXChangeDrawableAttributes, + 2 * req->numAttribs * __GLX_SIZE_CARD32, be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLXChangeDrawableAttributes; + be_req->drawable = be_drawable; + be_req->numAttribs = req->numAttribs; + be_req->length = req->length; + + UnlockDisplay(dpy); + SyncHandle(); + + return Success; +} + +int __glXSendLargeCommand(__GLXclientState *cl, GLXContextTag contextTag) +{ + ClientPtr client = cl->client; + xGLXRenderLargeReq *req; + GLint maxSize, amount; + GLint totalRequests, requestNumber; + GLint dataLen; + GLbyte *data; + __GLXcontext *glxc; + int s; + int from_screen, to_screen; + + maxSize = cl->largeCmdMaxReqDataSize - (GLint)sizeof(xGLXRenderLargeReq); + dataLen = cl->largeCmdBytesTotal; + totalRequests = (dataLen / maxSize); + if (dataLen % maxSize) totalRequests++; + + glxc = __glXLookupContextByTag(cl, contextTag); + if (!glxc) { + client->errorValue = contextTag; + return __glXBadContext; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + /* + ** Send enough requests until the whole array is sent. + */ + requestNumber = 1; + data = cl->largeCmdBuf; + while (dataLen > 0) { + amount = dataLen; + if (amount > maxSize) { + amount = maxSize; + } + + for (s=from_screen; s<=to_screen; s++) { + + Display *dpy = GetBackEndDisplay(cl,s); + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + + LockDisplay(dpy); + GetReq(GLXRenderLarge,req); + req->reqType = dmxScreen->glxMajorOpcode; + req->glxCode = X_GLXRenderLarge; + req->contextTag = GetCurrentBackEndTag(cl,contextTag,s); + req->length += (amount + 3) >> 2; + req->requestNumber = requestNumber++; + req->requestTotal = totalRequests; + req->dataBytes = amount; + Data(dpy, ((const char*)data), amount); + dataLen -= amount; + data = ((GLbyte *) data) + amount; + UnlockDisplay(dpy); + SyncHandle(); + } + } + + return Success; +} diff --git a/xorg-server/hw/dmx/glxProxy/glxext.c b/xorg-server/hw/dmx/glxProxy/glxext.c index 6cd8bb41a..6589e43bb 100644 --- a/xorg-server/hw/dmx/glxProxy/glxext.c +++ b/xorg-server/hw/dmx/glxProxy/glxext.c @@ -1,532 +1,532 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" - -#include "glxserver.h" -#include <windowstr.h> -#include <propertyst.h> -#include <os.h> -#include "g_disptab.h" -#include "glxutil.h" -#include "glxext.h" -#include "glxvisuals.h" -#include "micmap.h" -#include "glxswap.h" - -/* -** Stubs to satisfy miinitext.c references. -*/ -typedef int __GLXprovider; -__GLXprovider __glXDRISWRastProvider; -void GlxPushProvider(__GLXprovider *provider) { } - -/* -** Forward declarations. -*/ -static int __glXSwapDispatch(ClientPtr); -static int __glXDispatch(ClientPtr); - -/* -** Called when the extension is reset. -*/ -static void ResetExtension(ExtensionEntry* extEntry) -{ - __glXFlushContextCache(); - __glXScreenReset(); - SwapBarrierReset(); -} - -/* -** Initialize the per-client context storage. -*/ -static void ResetClientState(int clientIndex) -{ - __GLXclientState *cl = __glXClients[clientIndex]; - Display **keep_be_displays; - int i; - - if (cl->returnBuf) __glXFree(cl->returnBuf); - if (cl->currentContexts) __glXFree(cl->currentContexts); - if (cl->currentDrawables) __glXFree(cl->currentDrawables); - if (cl->largeCmdBuf) __glXFree(cl->largeCmdBuf); - - for (i=0; i< screenInfo.numScreens; i++) { - if (cl->be_displays[i]) - XCloseDisplay( cl->be_displays[i] ); - } - - keep_be_displays = cl->be_displays; - memset(cl, 0, sizeof(__GLXclientState)); - cl->be_displays = keep_be_displays; - - /* - ** By default, assume that the client supports - ** GLX major version 1 minor version 0 protocol. - */ - cl->GLClientmajorVersion = 1; - cl->GLClientminorVersion = 0; - if (cl->GLClientextensions) __glXFree(cl->GLClientextensions); - - memset(cl->be_displays, 0, screenInfo.numScreens * sizeof(Display *)); -} - - -/* -** This procedure is called when the client who created the context goes -** away OR when glXDestroyContext is called. In either case, all we do is -** flag that the ID is no longer valid, and (maybe) free the context. -** use. -*/ -static int ContextGone(__GLXcontext* cx, XID id) -{ - cx->idExists = GL_FALSE; - if (!cx->isCurrent) { - __glXFreeContext(cx); - } - - return True; -} - -/* -** Free a client's state. -*/ -static int ClientGone(int clientIndex, XID id) -{ - __GLXcontext *cx; - __GLXclientState *cl = __glXClients[clientIndex]; - int i; - - if (cl) { - /* - ** Free all the contexts that are current for this client. - */ - for (i=0; i < cl->numCurrentContexts; i++) { - cx = cl->currentContexts[i]; - if (cx) { - cx->isCurrent = GL_FALSE; - if (!cx->idExists) { - __glXFreeContext(cx); - } - } - } - /* - ** Re-initialize the client state structure. Don't free it because - ** we'll probably get another client with this index and use the struct - ** again. There is a maximum of MAXCLIENTS of these structures. - */ - ResetClientState(clientIndex); - } - - return True; -} - -/* -** Free a GLX Pixmap. -*/ -void __glXFreeGLXPixmap( __GLXpixmap *pGlxPixmap ) -{ - if (!pGlxPixmap->idExists && - !pGlxPixmap->refcnt) { - - PixmapPtr pPixmap = (PixmapPtr) pGlxPixmap->pDraw; - - /* - ** The DestroyPixmap routine should decrement the refcount and free - ** only if it's zero. - */ - (*pGlxPixmap->pScreen->DestroyPixmap)(pPixmap); - __glXFree(pGlxPixmap->be_xids); - __glXFree(pGlxPixmap); - } - -} - -static int PixmapGone(__GLXpixmap *pGlxPixmap, XID id) -{ - - pGlxPixmap->idExists = False; - __glXFreeGLXPixmap( pGlxPixmap ); - - return True; -} - -void __glXFreeGLXWindow(__glXWindow *pGlxWindow) -{ - if (!pGlxWindow->idExists && !pGlxWindow->refcnt) { - WindowPtr pWindow = (WindowPtr) pGlxWindow->pDraw; - - if (LookupIDByType(pWindow->drawable.id, RT_WINDOW) == pWindow) { - (*pGlxWindow->pScreen->DestroyWindow)(pWindow); - } - - xfree(pGlxWindow); - } -} - -static void WindowGone(__glXWindow *pGlxWindow, XID id) -{ - pGlxWindow->idExists = False; - __glXFreeGLXWindow(pGlxWindow); -} - -void __glXFreeGLXPbuffer(__glXPbuffer *pGlxPbuffer) -{ - if (!pGlxPbuffer->idExists && !pGlxPbuffer->refcnt) { - xfree(pGlxPbuffer->be_xids); - xfree(pGlxPbuffer); - } -} - -static void PbufferGone(__glXPbuffer *pGlxPbuffer, XID id) -{ - pGlxPbuffer->idExists = False; - __glXFreeGLXPbuffer(pGlxPbuffer); -} - -/* -** Free a context. -*/ -GLboolean __glXFreeContext(__GLXcontext *cx) -{ - if (cx->idExists || cx->isCurrent) return GL_FALSE; - - if (cx->feedbackBuf) __glXFree(cx->feedbackBuf); - if (cx->selectBuf) __glXFree(cx->selectBuf); - if (cx->real_ids) __glXFree(cx->real_ids); - if (cx->real_vids) __glXFree(cx->real_vids); - - if (cx->pGlxPixmap) { - /* - ** The previous drawable was a glx pixmap, release it. - */ - cx->pGlxPixmap->refcnt--; - __glXFreeGLXPixmap( cx->pGlxPixmap ); - cx->pGlxPixmap = 0; - } - - if (cx->pGlxReadPixmap) { - /* - ** The previous drawable was a glx pixmap, release it. - */ - cx->pGlxReadPixmap->refcnt--; - __glXFreeGLXPixmap( cx->pGlxReadPixmap ); - cx->pGlxReadPixmap = 0; - } - - if (cx->pGlxWindow) { - /* - ** The previous drawable was a glx window, release it. - */ - cx->pGlxWindow->refcnt--; - __glXFreeGLXWindow( cx->pGlxWindow ); - cx->pGlxWindow = 0; - } - - if (cx->pGlxReadWindow) { - /* - ** The previous drawable was a glx window, release it. - */ - cx->pGlxReadWindow->refcnt--; - __glXFreeGLXWindow( cx->pGlxReadWindow ); - cx->pGlxReadWindow = 0; - } - - __glXFree(cx); - - if (cx == __glXLastContext) { - __glXFlushContextCache(); - } - - return GL_TRUE; -} - -/* -** Initialize the GLX extension. -*/ -void GlxExtensionInit(void) -{ - ExtensionEntry *extEntry; - int i; - int glxSupported = 1; - - /* - // do not initialize GLX extension if GLX is not supported - // by ALL back-end servers. - */ - for (i=0; i<screenInfo.numScreens; i++) { - glxSupported &= (dmxScreens[i].glxMajorOpcode > 0); - } - - if (!glxSupported || !dmxGLXProxy) { - return; - } - - __glXContextRes = CreateNewResourceType((DeleteType)ContextGone, - "GLXContext"); - __glXClientRes = CreateNewResourceType((DeleteType)ClientGone, - "GLXClient"); - __glXPixmapRes = CreateNewResourceType((DeleteType)PixmapGone, - "GLXPixmap"); - __glXWindowRes = CreateNewResourceType((DeleteType)WindowGone, - "GLXWindow"); - __glXPbufferRes = CreateNewResourceType((DeleteType)PbufferGone, - "GLXPbuffer"); - - if (!__glXContextRes || !__glXClientRes || !__glXPixmapRes || - !__glXWindowRes || !__glXPbufferRes) - return; - - /* - ** Add extension to server extensions. - */ - extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS, - __GLX_NUMBER_ERRORS, __glXDispatch, - __glXSwapDispatch, ResetExtension, - StandardMinorOpcode); - if (!extEntry) { - FatalError("__glXExtensionInit: AddExtensions failed\n"); - return; - } - /* - if (!AddExtensionAlias(GLX_EXTENSION_ALIAS, extEntry)) { - ErrorF("__glXExtensionInit: AddExtensionAlias failed\n"); - return; - } - */ - - __glXerrorBase = extEntry->errorBase; - __glXBadContext = extEntry->errorBase + GLXBadContext; - __glXBadContextState = extEntry->errorBase + GLXBadContextState; - __glXBadDrawable = extEntry->errorBase + GLXBadDrawable; - __glXBadPixmap = extEntry->errorBase + GLXBadPixmap; - __glXBadContextTag = extEntry->errorBase + GLXBadContextTag; - __glXBadCurrentWindow = extEntry->errorBase + GLXBadCurrentWindow; - __glXBadRenderRequest = extEntry->errorBase + GLXBadRenderRequest; - __glXBadLargeRequest = extEntry->errorBase + GLXBadLargeRequest; - __glXUnsupportedPrivateRequest = extEntry->errorBase + - GLXUnsupportedPrivateRequest; - __glXBadFBConfig = extEntry->errorBase + GLXBadFBConfig; - __glXBadPbuffer = extEntry->errorBase + GLXBadPbuffer; - - /* - ** Initialize table of client state. There is never a client 0. - */ - for (i=1; i <= MAXCLIENTS; i++) { - __glXClients[i] = 0; - } - - /* - ** Initialize screen specific data. - */ - __glXScreenInit(screenInfo.numScreens); - - /* - ** Initialize swap barrier support. - */ - SwapBarrierInit(); -} - -/************************************************************************/ - -Bool __glXCoreType(void) -{ - return 0; -} - -/************************************************************************/ - -void GlxSetVisualConfigs(int nconfigs, - __GLXvisualConfig *configs, void **privates) -{ - glxSetVisualConfigs(nconfigs, configs, privates); -} - -static miInitVisualsProcPtr saveInitVisualsProc; - -Bool GlxInitVisuals(VisualPtr *visualp, DepthPtr *depthp, - int *nvisualp, int *ndepthp, - int *rootDepthp, VisualID *defaultVisp, - unsigned long sizes, int bitsPerRGB, - int preferredVis) -{ - Bool ret; - - if (saveInitVisualsProc) { - ret = saveInitVisualsProc(visualp, depthp, nvisualp, ndepthp, - rootDepthp, defaultVisp, sizes, bitsPerRGB, - preferredVis); - if (!ret) - return False; - } - - glxInitVisuals(nvisualp, visualp, defaultVisp, *ndepthp, *depthp,*rootDepthp); - - return True; -} - -void -GlxWrapInitVisuals(miInitVisualsProcPtr *initVisProc) -{ - if (dmxGLXProxy) { - saveInitVisualsProc = *initVisProc; - *initVisProc = GlxInitVisuals; - } -} - -/************************************************************************/ - -void __glXFlushContextCache(void) -{ - __glXLastContext = 0; -} - -/************************************************************************/ - -/* -** Top level dispatcher; all commands are executed from here down. -*/ -static int __glXDispatch(ClientPtr client) -{ - REQUEST(xGLXSingleReq); - CARD8 opcode; - int (*proc)(__GLXclientState *cl, GLbyte *pc); - __GLXclientState *cl; - - opcode = stuff->glxCode; - cl = __glXClients[client->index]; - if (!cl) { - cl = __glXCalloc(1, sizeof(__GLXclientState)); - __glXClients[client->index] = cl; - if (!cl) { - return BadAlloc; - } - - cl->be_displays = __glXCalloc(screenInfo.numScreens, sizeof(Display *)); - if (!cl->be_displays) { - __glXFree( cl ); - return BadAlloc; - } - } - - if (!cl->inUse) { - /* - ** This is first request from this client. Associate a resource - ** with the client so we will be notified when the client dies. - */ - XID xid = FakeClientID(client->index); - if (!AddResource( xid, __glXClientRes, (pointer)(long)client->index)) { - return BadAlloc; - } - ResetClientState(client->index); - cl->largeCmdRequestsTotal = 0; - cl->inUse = GL_TRUE; - cl->client = client; - } - - /* - ** Check for valid opcode. - */ - if (opcode >= __GLX_SINGLE_TABLE_SIZE) { - return BadRequest; - } - - /* - ** Use the opcode to index into the procedure table. - */ - proc = __glXSingleTable[opcode]; - return (*proc)(cl, (GLbyte *) stuff); -} - -static int __glXSwapDispatch(ClientPtr client) -{ - REQUEST(xGLXSingleReq); - CARD8 opcode; - int (*proc)(__GLXclientState *cl, GLbyte *pc); - __GLXclientState *cl; - - opcode = stuff->glxCode; - cl = __glXClients[client->index]; - if (!cl) { - cl = __glXCalloc(1, sizeof(__GLXclientState)); - __glXClients[client->index] = cl; - if (!cl) { - return BadAlloc; - } - - cl->be_displays = __glXCalloc(screenInfo.numScreens, sizeof(Display *)); - if (!cl->be_displays) { - __glXFree( cl ); - return BadAlloc; - } - } - - if (!cl->inUse) { - /* - ** This is first request from this client. Associate a resource - ** with the client so we will be notified when the client dies. - */ - XID xid = FakeClientID(client->index); - if (!AddResource( xid, __glXClientRes, (pointer)(long)client->index)) { - return BadAlloc; - } - ResetClientState(client->index); - cl->inUse = GL_TRUE; - cl->client = client; - } - - /* - ** Check for valid opcode. - */ - if (opcode >= __GLX_SINGLE_TABLE_SIZE) { - return BadRequest; - } - - /* - ** Use the opcode to index into the procedure table. - */ - proc = __glXSwapSingleTable[opcode]; - return (*proc)(cl, (GLbyte *) stuff); -} - -int __glXNoSuchSingleOpcode(__GLXclientState *cl, GLbyte *pc) -{ - return BadRequest; -} - -void __glXNoSuchRenderOpcode(GLbyte *pc) -{ - return; -} - +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" + +#include "glxserver.h" +#include <windowstr.h> +#include <propertyst.h> +#include <os.h> +#include "g_disptab.h" +#include "glxutil.h" +#include "glxext.h" +#include "glxvisuals.h" +#include "micmap.h" +#include "glxswap.h" + +/* +** Stubs to satisfy miinitext.c references. +*/ +typedef int __GLXprovider; +__GLXprovider __glXDRISWRastProvider; +void GlxPushProvider(__GLXprovider *provider) { } + +/* +** Forward declarations. +*/ +static int __glXSwapDispatch(ClientPtr); +static int __glXDispatch(ClientPtr); + +/* +** Called when the extension is reset. +*/ +static void ResetExtension(ExtensionEntry* extEntry) +{ + __glXFlushContextCache(); + __glXScreenReset(); + SwapBarrierReset(); +} + +/* +** Initialize the per-client context storage. +*/ +static void ResetClientState(int clientIndex) +{ + __GLXclientState *cl = __glXClients[clientIndex]; + Display **keep_be_displays; + int i; + + if (cl->returnBuf) __glXFree(cl->returnBuf); + if (cl->currentContexts) __glXFree(cl->currentContexts); + if (cl->currentDrawables) __glXFree(cl->currentDrawables); + if (cl->largeCmdBuf) __glXFree(cl->largeCmdBuf); + + for (i=0; i< screenInfo.numScreens; i++) { + if (cl->be_displays[i]) + XCloseDisplay( cl->be_displays[i] ); + } + + keep_be_displays = cl->be_displays; + memset(cl, 0, sizeof(__GLXclientState)); + cl->be_displays = keep_be_displays; + + /* + ** By default, assume that the client supports + ** GLX major version 1 minor version 0 protocol. + */ + cl->GLClientmajorVersion = 1; + cl->GLClientminorVersion = 0; + if (cl->GLClientextensions) __glXFree(cl->GLClientextensions); + + memset(cl->be_displays, 0, screenInfo.numScreens * sizeof(Display *)); +} + + +/* +** This procedure is called when the client who created the context goes +** away OR when glXDestroyContext is called. In either case, all we do is +** flag that the ID is no longer valid, and (maybe) free the context. +** use. +*/ +static int ContextGone(__GLXcontext* cx, XID id) +{ + cx->idExists = GL_FALSE; + if (!cx->isCurrent) { + __glXFreeContext(cx); + } + + return True; +} + +/* +** Free a client's state. +*/ +static int ClientGone(int clientIndex, XID id) +{ + __GLXcontext *cx; + __GLXclientState *cl = __glXClients[clientIndex]; + int i; + + if (cl) { + /* + ** Free all the contexts that are current for this client. + */ + for (i=0; i < cl->numCurrentContexts; i++) { + cx = cl->currentContexts[i]; + if (cx) { + cx->isCurrent = GL_FALSE; + if (!cx->idExists) { + __glXFreeContext(cx); + } + } + } + /* + ** Re-initialize the client state structure. Don't free it because + ** we'll probably get another client with this index and use the struct + ** again. There is a maximum of MAXCLIENTS of these structures. + */ + ResetClientState(clientIndex); + } + + return True; +} + +/* +** Free a GLX Pixmap. +*/ +void __glXFreeGLXPixmap( __GLXpixmap *pGlxPixmap ) +{ + if (!pGlxPixmap->idExists && + !pGlxPixmap->refcnt) { + + PixmapPtr pPixmap = (PixmapPtr) pGlxPixmap->pDraw; + + /* + ** The DestroyPixmap routine should decrement the refcount and free + ** only if it's zero. + */ + (*pGlxPixmap->pScreen->DestroyPixmap)(pPixmap); + __glXFree(pGlxPixmap->be_xids); + __glXFree(pGlxPixmap); + } + +} + +static int PixmapGone(__GLXpixmap *pGlxPixmap, XID id) +{ + + pGlxPixmap->idExists = False; + __glXFreeGLXPixmap( pGlxPixmap ); + + return True; +} + +void __glXFreeGLXWindow(__glXWindow *pGlxWindow) +{ + if (!pGlxWindow->idExists && !pGlxWindow->refcnt) { + WindowPtr pWindow = (WindowPtr) pGlxWindow->pDraw; + + if (LookupIDByType(pWindow->drawable.id, RT_WINDOW) == pWindow) { + (*pGlxWindow->pScreen->DestroyWindow)(pWindow); + } + + free(pGlxWindow); + } +} + +static void WindowGone(__glXWindow *pGlxWindow, XID id) +{ + pGlxWindow->idExists = False; + __glXFreeGLXWindow(pGlxWindow); +} + +void __glXFreeGLXPbuffer(__glXPbuffer *pGlxPbuffer) +{ + if (!pGlxPbuffer->idExists && !pGlxPbuffer->refcnt) { + free(pGlxPbuffer->be_xids); + free(pGlxPbuffer); + } +} + +static void PbufferGone(__glXPbuffer *pGlxPbuffer, XID id) +{ + pGlxPbuffer->idExists = False; + __glXFreeGLXPbuffer(pGlxPbuffer); +} + +/* +** Free a context. +*/ +GLboolean __glXFreeContext(__GLXcontext *cx) +{ + if (cx->idExists || cx->isCurrent) return GL_FALSE; + + if (cx->feedbackBuf) __glXFree(cx->feedbackBuf); + if (cx->selectBuf) __glXFree(cx->selectBuf); + if (cx->real_ids) __glXFree(cx->real_ids); + if (cx->real_vids) __glXFree(cx->real_vids); + + if (cx->pGlxPixmap) { + /* + ** The previous drawable was a glx pixmap, release it. + */ + cx->pGlxPixmap->refcnt--; + __glXFreeGLXPixmap( cx->pGlxPixmap ); + cx->pGlxPixmap = 0; + } + + if (cx->pGlxReadPixmap) { + /* + ** The previous drawable was a glx pixmap, release it. + */ + cx->pGlxReadPixmap->refcnt--; + __glXFreeGLXPixmap( cx->pGlxReadPixmap ); + cx->pGlxReadPixmap = 0; + } + + if (cx->pGlxWindow) { + /* + ** The previous drawable was a glx window, release it. + */ + cx->pGlxWindow->refcnt--; + __glXFreeGLXWindow( cx->pGlxWindow ); + cx->pGlxWindow = 0; + } + + if (cx->pGlxReadWindow) { + /* + ** The previous drawable was a glx window, release it. + */ + cx->pGlxReadWindow->refcnt--; + __glXFreeGLXWindow( cx->pGlxReadWindow ); + cx->pGlxReadWindow = 0; + } + + __glXFree(cx); + + if (cx == __glXLastContext) { + __glXFlushContextCache(); + } + + return GL_TRUE; +} + +/* +** Initialize the GLX extension. +*/ +void GlxExtensionInit(void) +{ + ExtensionEntry *extEntry; + int i; + int glxSupported = 1; + + /* + // do not initialize GLX extension if GLX is not supported + // by ALL back-end servers. + */ + for (i=0; i<screenInfo.numScreens; i++) { + glxSupported &= (dmxScreens[i].glxMajorOpcode > 0); + } + + if (!glxSupported || !dmxGLXProxy) { + return; + } + + __glXContextRes = CreateNewResourceType((DeleteType)ContextGone, + "GLXContext"); + __glXClientRes = CreateNewResourceType((DeleteType)ClientGone, + "GLXClient"); + __glXPixmapRes = CreateNewResourceType((DeleteType)PixmapGone, + "GLXPixmap"); + __glXWindowRes = CreateNewResourceType((DeleteType)WindowGone, + "GLXWindow"); + __glXPbufferRes = CreateNewResourceType((DeleteType)PbufferGone, + "GLXPbuffer"); + + if (!__glXContextRes || !__glXClientRes || !__glXPixmapRes || + !__glXWindowRes || !__glXPbufferRes) + return; + + /* + ** Add extension to server extensions. + */ + extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS, + __GLX_NUMBER_ERRORS, __glXDispatch, + __glXSwapDispatch, ResetExtension, + StandardMinorOpcode); + if (!extEntry) { + FatalError("__glXExtensionInit: AddExtensions failed\n"); + return; + } + /* + if (!AddExtensionAlias(GLX_EXTENSION_ALIAS, extEntry)) { + ErrorF("__glXExtensionInit: AddExtensionAlias failed\n"); + return; + } + */ + + __glXerrorBase = extEntry->errorBase; + __glXBadContext = extEntry->errorBase + GLXBadContext; + __glXBadContextState = extEntry->errorBase + GLXBadContextState; + __glXBadDrawable = extEntry->errorBase + GLXBadDrawable; + __glXBadPixmap = extEntry->errorBase + GLXBadPixmap; + __glXBadContextTag = extEntry->errorBase + GLXBadContextTag; + __glXBadCurrentWindow = extEntry->errorBase + GLXBadCurrentWindow; + __glXBadRenderRequest = extEntry->errorBase + GLXBadRenderRequest; + __glXBadLargeRequest = extEntry->errorBase + GLXBadLargeRequest; + __glXUnsupportedPrivateRequest = extEntry->errorBase + + GLXUnsupportedPrivateRequest; + __glXBadFBConfig = extEntry->errorBase + GLXBadFBConfig; + __glXBadPbuffer = extEntry->errorBase + GLXBadPbuffer; + + /* + ** Initialize table of client state. There is never a client 0. + */ + for (i=1; i <= MAXCLIENTS; i++) { + __glXClients[i] = 0; + } + + /* + ** Initialize screen specific data. + */ + __glXScreenInit(screenInfo.numScreens); + + /* + ** Initialize swap barrier support. + */ + SwapBarrierInit(); +} + +/************************************************************************/ + +Bool __glXCoreType(void) +{ + return 0; +} + +/************************************************************************/ + +void GlxSetVisualConfigs(int nconfigs, + __GLXvisualConfig *configs, void **privates) +{ + glxSetVisualConfigs(nconfigs, configs, privates); +} + +static miInitVisualsProcPtr saveInitVisualsProc; + +Bool GlxInitVisuals(VisualPtr *visualp, DepthPtr *depthp, + int *nvisualp, int *ndepthp, + int *rootDepthp, VisualID *defaultVisp, + unsigned long sizes, int bitsPerRGB, + int preferredVis) +{ + Bool ret; + + if (saveInitVisualsProc) { + ret = saveInitVisualsProc(visualp, depthp, nvisualp, ndepthp, + rootDepthp, defaultVisp, sizes, bitsPerRGB, + preferredVis); + if (!ret) + return False; + } + + glxInitVisuals(nvisualp, visualp, defaultVisp, *ndepthp, *depthp,*rootDepthp); + + return True; +} + +void +GlxWrapInitVisuals(miInitVisualsProcPtr *initVisProc) +{ + if (dmxGLXProxy) { + saveInitVisualsProc = *initVisProc; + *initVisProc = GlxInitVisuals; + } +} + +/************************************************************************/ + +void __glXFlushContextCache(void) +{ + __glXLastContext = 0; +} + +/************************************************************************/ + +/* +** Top level dispatcher; all commands are executed from here down. +*/ +static int __glXDispatch(ClientPtr client) +{ + REQUEST(xGLXSingleReq); + CARD8 opcode; + int (*proc)(__GLXclientState *cl, GLbyte *pc); + __GLXclientState *cl; + + opcode = stuff->glxCode; + cl = __glXClients[client->index]; + if (!cl) { + cl = __glXCalloc(1, sizeof(__GLXclientState)); + __glXClients[client->index] = cl; + if (!cl) { + return BadAlloc; + } + + cl->be_displays = __glXCalloc(screenInfo.numScreens, sizeof(Display *)); + if (!cl->be_displays) { + __glXFree( cl ); + return BadAlloc; + } + } + + if (!cl->inUse) { + /* + ** This is first request from this client. Associate a resource + ** with the client so we will be notified when the client dies. + */ + XID xid = FakeClientID(client->index); + if (!AddResource( xid, __glXClientRes, (pointer)(long)client->index)) { + return BadAlloc; + } + ResetClientState(client->index); + cl->largeCmdRequestsTotal = 0; + cl->inUse = GL_TRUE; + cl->client = client; + } + + /* + ** Check for valid opcode. + */ + if (opcode >= __GLX_SINGLE_TABLE_SIZE) { + return BadRequest; + } + + /* + ** Use the opcode to index into the procedure table. + */ + proc = __glXSingleTable[opcode]; + return (*proc)(cl, (GLbyte *) stuff); +} + +static int __glXSwapDispatch(ClientPtr client) +{ + REQUEST(xGLXSingleReq); + CARD8 opcode; + int (*proc)(__GLXclientState *cl, GLbyte *pc); + __GLXclientState *cl; + + opcode = stuff->glxCode; + cl = __glXClients[client->index]; + if (!cl) { + cl = __glXCalloc(1, sizeof(__GLXclientState)); + __glXClients[client->index] = cl; + if (!cl) { + return BadAlloc; + } + + cl->be_displays = __glXCalloc(screenInfo.numScreens, sizeof(Display *)); + if (!cl->be_displays) { + __glXFree( cl ); + return BadAlloc; + } + } + + if (!cl->inUse) { + /* + ** This is first request from this client. Associate a resource + ** with the client so we will be notified when the client dies. + */ + XID xid = FakeClientID(client->index); + if (!AddResource( xid, __glXClientRes, (pointer)(long)client->index)) { + return BadAlloc; + } + ResetClientState(client->index); + cl->inUse = GL_TRUE; + cl->client = client; + } + + /* + ** Check for valid opcode. + */ + if (opcode >= __GLX_SINGLE_TABLE_SIZE) { + return BadRequest; + } + + /* + ** Use the opcode to index into the procedure table. + */ + proc = __glXSwapSingleTable[opcode]; + return (*proc)(cl, (GLbyte *) stuff); +} + +int __glXNoSuchSingleOpcode(__GLXclientState *cl, GLbyte *pc) +{ + return BadRequest; +} + +void __glXNoSuchRenderOpcode(GLbyte *pc) +{ + return; +} + diff --git a/xorg-server/hw/dmx/glxProxy/glxscreens.c b/xorg-server/hw/dmx/glxProxy/glxscreens.c index 39978a74d..4c40d2315 100644 --- a/xorg-server/hw/dmx/glxProxy/glxscreens.c +++ b/xorg-server/hw/dmx/glxProxy/glxscreens.c @@ -1,377 +1,377 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxlog.h" - -#undef Xmalloc -#undef Xcalloc -#undef Xrealloc -#undef Xfree - -#include "glxserver.h" - -#include <windowstr.h> - -#include "glxfbconfig.h" - -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#endif - -__GLXscreenInfo *__glXActiveScreens; -GLint __glXNumActiveScreens; - -__GLXFBConfig **__glXFBConfigs; -int __glXNumFBConfigs; - -static char GLXServerVendorName[] = "SGI DMX/glxProxy"; -static char GLXServerVersion[64]; -static char GLXServerExtensions[] = - "GLX_EXT_visual_info " - "GLX_EXT_visual_rating " - "GLX_EXT_import_context " - "GLX_SGIX_fbconfig " - "GLX_SGI_make_current_read " - "GLX_SGI_swap_control " - ; - -static char ExtensionsString[1024]; - -static void CalcServerVersionAndExtensions( void ) -{ - int s; - xGLXQueryVersionReq *req; - xGLXQueryVersionReply reply; - char **be_extensions; - char *ext; - char *denied_extensions; - - /* - * set the server glx version to be the minimum version - * supported by all back-end servers - */ - __glXVersionMajor = 0; - __glXVersionMinor = 0; - for (s=0; s<__glXNumActiveScreens; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = dmxScreen->beDisplay; - - /* Send the glXQueryVersion request */ - LockDisplay(dpy); - GetReq(GLXQueryVersion,req); - req->reqType = dmxScreen->glxMajorOpcode; - req->glxCode = X_GLXQueryVersion; - req->majorVersion = GLX_SERVER_MAJOR_VERSION; - req->minorVersion = GLX_SERVER_MINOR_VERSION; - _XReply(dpy, (xReply*) &reply, 0, False); - UnlockDisplay(dpy); - SyncHandle(); - - if (s == 0) { - __glXVersionMajor = reply.majorVersion; - __glXVersionMinor = reply.minorVersion; - } - else { - if (reply.majorVersion < __glXVersionMajor) { - __glXVersionMajor = reply.majorVersion; - __glXVersionMinor = reply.minorVersion; - } - else if ( (reply.majorVersion == __glXVersionMajor) && - (reply.minorVersion < __glXVersionMinor) ) { - __glXVersionMinor = reply.minorVersion; - } - } - - } - - if (GLX_SERVER_MAJOR_VERSION < __glXVersionMajor) { - __glXVersionMajor = GLX_SERVER_MAJOR_VERSION; - __glXVersionMinor = GLX_SERVER_MINOR_VERSION; - } - else if ( (GLX_SERVER_MAJOR_VERSION == __glXVersionMajor) && - (GLX_SERVER_MINOR_VERSION < __glXVersionMinor) ) { - __glXVersionMinor = GLX_SERVER_MINOR_VERSION; - } - - sprintf(GLXServerVersion, "%d.%d DMX %d back-end server(s)", - __glXVersionMajor, __glXVersionMinor, __glXNumActiveScreens ); - /* - * set the ExtensionsString to the minimum extensions string - */ - ExtensionsString[0] = '\0'; - - /* - * read extensions strings of all back-end servers - */ - be_extensions = (char **)Xalloc( __glXNumActiveScreens * sizeof(char *) ); - if (!be_extensions) - return; - - for (s=0; s<__glXNumActiveScreens; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = dmxScreen->beDisplay; - xGLXQueryServerStringReq *req; - xGLXQueryServerStringReply reply; - int length, numbytes, slop; - - /* Send the glXQueryServerString request */ - LockDisplay(dpy); - GetReq(GLXQueryServerString,req); - req->reqType = dmxScreen->glxMajorOpcode; - req->glxCode = X_GLXQueryServerString; - req->screen = DefaultScreen(dpy); - req->name = GLX_EXTENSIONS; - _XReply(dpy, (xReply*) &reply, 0, False); - - length = (int)reply.length; - numbytes = (int)reply.n; - slop = numbytes * __GLX_SIZE_INT8 & 3; - be_extensions[s] = (char *)Xalloc(numbytes); - if (!be_extensions[s]) { - /* Throw data on the floor */ - _XEatData(dpy, length); - } else { - _XRead(dpy, (char *)be_extensions[s], numbytes); - if (slop) _XEatData(dpy,4-slop); - } - UnlockDisplay(dpy); - SyncHandle(); - } - - /* - * extensions string will include only extensions that our - * server supports as well as all back-end servers supports. - * extensions that are in the DMX_DENY_EXTENSIONS string will - * not be supported. - */ - denied_extensions = getenv("DMX_DENY_GLX_EXTENSIONS"); - ext = strtok(GLXServerExtensions, " "); - while( ext ) { - int supported = 1; - - if (denied_extensions && strstr(denied_extensions, ext)) { - supported = 0; - } - else { - for (s=0; s<__glXNumActiveScreens && supported; s++) { - if ( !strstr(be_extensions[s], ext) ) { - supported = 0; - } - } - } - - if (supported) { - strcat(ExtensionsString, ext); - strcat(ExtensionsString, " "); - } - - ext = strtok(NULL, " "); - } - - /* - * release temporary storage - */ - for (s=0; s<__glXNumActiveScreens; s++) { - if (be_extensions[s]) Xfree(be_extensions[s]); - } - Xfree( be_extensions ); - - if (dmxGLXSwapGroupSupport) { - if (!denied_extensions || - !strstr(denied_extensions, "GLX_SGIX_swap_group")) { - strcat(ExtensionsString, "GLX_SGIX_swap_group"); - if (!denied_extensions || - !strstr(denied_extensions, "GLX_SGIX_swap_barrier")) { - strcat(ExtensionsString, " GLX_SGIX_swap_barrier"); - } - } - } - -} - -void __glXScreenInit(GLint numscreens) -{ - int s; - int c; - DMXScreenInfo *dmxScreen0 = &dmxScreens[0]; - __glXNumActiveScreens = numscreens; - - - CalcServerVersionAndExtensions(); - - - __glXFBConfigs = NULL; - __glXNumFBConfigs = 0; - - if ( (__glXVersionMajor == 1 && __glXVersionMinor >= 3) || - (__glXVersionMajor > 1) || - ( strstr(ExtensionsString, "GLX_SGIX_fbconfig") ) ) { - - /* - // Initialize FBConfig info. - // find the set of FBConfigs that are present on all back-end - // servers - only those configs will be supported - */ - __glXFBConfigs = (__GLXFBConfig **)Xalloc( dmxScreen0->numFBConfigs * - (numscreens+1) * sizeof(__GLXFBConfig *) ); - __glXNumFBConfigs = 0; - - for (c=0; c<dmxScreen0->numFBConfigs; c++) { - __GLXFBConfig *cfg = NULL; - - if (numscreens > 1) { - for (s=1; s<numscreens; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - __GLXscreenInfo *glxScreen = &__glXActiveScreens[s]; - - cfg = FindMatchingFBConfig( &dmxScreen0->fbconfigs[c], - dmxScreen->fbconfigs, - dmxScreen->numFBConfigs ); - __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + s + 1 ] = cfg; - if (!cfg) { - dmxLog(dmxInfo,"screen0 FBConfig 0x%x is missing on screen#%d\n", dmxScreen0->fbconfigs[c].id, s); - break; - } - else { - dmxLog(dmxInfo,"screen0 FBConfig 0x%x matched to 0x%x on screen#%d\n", dmxScreen0->fbconfigs[c].id, cfg->id, s); - } - } - } - else { - cfg = &dmxScreen0->fbconfigs[c]; - } - - if (cfg) { - - /* filter out overlay visuals */ - if (cfg->level == 0) { - __GLXFBConfig *proxy_cfg; - - __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + 1 ] = - &dmxScreen0->fbconfigs[c]; - - proxy_cfg = Xalloc( sizeof(__GLXFBConfig) ); - memcpy( proxy_cfg, cfg, sizeof(__GLXFBConfig) ); - proxy_cfg->id = FakeClientID(0); - /* visual will be associated later in __glXGetFBConfigs */ - proxy_cfg->associatedVisualId = (unsigned int)-1; - - __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + 0 ] = proxy_cfg; - - __glXNumFBConfigs++; - } - - } - - } - - } - -} - -void __glXScreenReset(void) -{ - __glXNumActiveScreens = 0; -} - -char *__glXGetServerString( unsigned int name ) -{ - char *ret = NULL; - - switch( name) { - - case GLX_VENDOR: - ret = GLXServerVendorName; - break; - - case GLX_VERSION: - ret = GLXServerVersion; - break; - - case GLX_EXTENSIONS: - ret = ExtensionsString; - break; - - default: - break; - } - - return( ret ); - -} - - -__GLXFBConfig *glxLookupFBConfig( GLXFBConfigID id ) -{ - int i,j; - - for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { - if ( __glXFBConfigs[j]->id == id) - return( __glXFBConfigs[j] ); - } - - return(NULL); -} - -__GLXFBConfig *glxLookupFBConfigByVID( VisualID vid ) -{ - int i,j; - - for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { - if ( __glXFBConfigs[j]->associatedVisualId == vid) - return( __glXFBConfigs[j] ); - } - - return(NULL); -} - -__GLXFBConfig *glxLookupBackEndFBConfig( GLXFBConfigID id, int screen ) -{ - int i; - int j; - - for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { - if ( __glXFBConfigs[j]->id == id) - return( __glXFBConfigs[j+screen+1] ); - } - - return(NULL); - -} - -int glxIsExtensionSupported( char *ext ) -{ - return( strstr(ExtensionsString, ext) != NULL ); -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxlog.h" + +#undef Xmalloc +#undef Xcalloc +#undef Xrealloc +#undef Xfree + +#include "glxserver.h" + +#include <windowstr.h> + +#include "glxfbconfig.h" + +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +__GLXscreenInfo *__glXActiveScreens; +GLint __glXNumActiveScreens; + +__GLXFBConfig **__glXFBConfigs; +int __glXNumFBConfigs; + +static char GLXServerVendorName[] = "SGI DMX/glxProxy"; +static char GLXServerVersion[64]; +static char GLXServerExtensions[] = + "GLX_EXT_visual_info " + "GLX_EXT_visual_rating " + "GLX_EXT_import_context " + "GLX_SGIX_fbconfig " + "GLX_SGI_make_current_read " + "GLX_SGI_swap_control " + ; + +static char ExtensionsString[1024]; + +static void CalcServerVersionAndExtensions( void ) +{ + int s; + xGLXQueryVersionReq *req; + xGLXQueryVersionReply reply; + char **be_extensions; + char *ext; + char *denied_extensions; + + /* + * set the server glx version to be the minimum version + * supported by all back-end servers + */ + __glXVersionMajor = 0; + __glXVersionMinor = 0; + for (s=0; s<__glXNumActiveScreens; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = dmxScreen->beDisplay; + + /* Send the glXQueryVersion request */ + LockDisplay(dpy); + GetReq(GLXQueryVersion,req); + req->reqType = dmxScreen->glxMajorOpcode; + req->glxCode = X_GLXQueryVersion; + req->majorVersion = GLX_SERVER_MAJOR_VERSION; + req->minorVersion = GLX_SERVER_MINOR_VERSION; + _XReply(dpy, (xReply*) &reply, 0, False); + UnlockDisplay(dpy); + SyncHandle(); + + if (s == 0) { + __glXVersionMajor = reply.majorVersion; + __glXVersionMinor = reply.minorVersion; + } + else { + if (reply.majorVersion < __glXVersionMajor) { + __glXVersionMajor = reply.majorVersion; + __glXVersionMinor = reply.minorVersion; + } + else if ( (reply.majorVersion == __glXVersionMajor) && + (reply.minorVersion < __glXVersionMinor) ) { + __glXVersionMinor = reply.minorVersion; + } + } + + } + + if (GLX_SERVER_MAJOR_VERSION < __glXVersionMajor) { + __glXVersionMajor = GLX_SERVER_MAJOR_VERSION; + __glXVersionMinor = GLX_SERVER_MINOR_VERSION; + } + else if ( (GLX_SERVER_MAJOR_VERSION == __glXVersionMajor) && + (GLX_SERVER_MINOR_VERSION < __glXVersionMinor) ) { + __glXVersionMinor = GLX_SERVER_MINOR_VERSION; + } + + sprintf(GLXServerVersion, "%d.%d DMX %d back-end server(s)", + __glXVersionMajor, __glXVersionMinor, __glXNumActiveScreens ); + /* + * set the ExtensionsString to the minimum extensions string + */ + ExtensionsString[0] = '\0'; + + /* + * read extensions strings of all back-end servers + */ + be_extensions = (char **)malloc( __glXNumActiveScreens * sizeof(char *) ); + if (!be_extensions) + return; + + for (s=0; s<__glXNumActiveScreens; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = dmxScreen->beDisplay; + xGLXQueryServerStringReq *req; + xGLXQueryServerStringReply reply; + int length, numbytes, slop; + + /* Send the glXQueryServerString request */ + LockDisplay(dpy); + GetReq(GLXQueryServerString,req); + req->reqType = dmxScreen->glxMajorOpcode; + req->glxCode = X_GLXQueryServerString; + req->screen = DefaultScreen(dpy); + req->name = GLX_EXTENSIONS; + _XReply(dpy, (xReply*) &reply, 0, False); + + length = (int)reply.length; + numbytes = (int)reply.n; + slop = numbytes * __GLX_SIZE_INT8 & 3; + be_extensions[s] = (char *)malloc(numbytes); + if (!be_extensions[s]) { + /* Throw data on the floor */ + _XEatData(dpy, length); + } else { + _XRead(dpy, (char *)be_extensions[s], numbytes); + if (slop) _XEatData(dpy,4-slop); + } + UnlockDisplay(dpy); + SyncHandle(); + } + + /* + * extensions string will include only extensions that our + * server supports as well as all back-end servers supports. + * extensions that are in the DMX_DENY_EXTENSIONS string will + * not be supported. + */ + denied_extensions = getenv("DMX_DENY_GLX_EXTENSIONS"); + ext = strtok(GLXServerExtensions, " "); + while( ext ) { + int supported = 1; + + if (denied_extensions && strstr(denied_extensions, ext)) { + supported = 0; + } + else { + for (s=0; s<__glXNumActiveScreens && supported; s++) { + if ( !strstr(be_extensions[s], ext) ) { + supported = 0; + } + } + } + + if (supported) { + strcat(ExtensionsString, ext); + strcat(ExtensionsString, " "); + } + + ext = strtok(NULL, " "); + } + + /* + * release temporary storage + */ + for (s=0; s<__glXNumActiveScreens; s++) { + if (be_extensions[s]) Xfree(be_extensions[s]); + } + Xfree( be_extensions ); + + if (dmxGLXSwapGroupSupport) { + if (!denied_extensions || + !strstr(denied_extensions, "GLX_SGIX_swap_group")) { + strcat(ExtensionsString, "GLX_SGIX_swap_group"); + if (!denied_extensions || + !strstr(denied_extensions, "GLX_SGIX_swap_barrier")) { + strcat(ExtensionsString, " GLX_SGIX_swap_barrier"); + } + } + } + +} + +void __glXScreenInit(GLint numscreens) +{ + int s; + int c; + DMXScreenInfo *dmxScreen0 = &dmxScreens[0]; + __glXNumActiveScreens = numscreens; + + + CalcServerVersionAndExtensions(); + + + __glXFBConfigs = NULL; + __glXNumFBConfigs = 0; + + if ( (__glXVersionMajor == 1 && __glXVersionMinor >= 3) || + (__glXVersionMajor > 1) || + ( strstr(ExtensionsString, "GLX_SGIX_fbconfig") ) ) { + + /* + // Initialize FBConfig info. + // find the set of FBConfigs that are present on all back-end + // servers - only those configs will be supported + */ + __glXFBConfigs = (__GLXFBConfig **)malloc( dmxScreen0->numFBConfigs * + (numscreens+1) * sizeof(__GLXFBConfig *) ); + __glXNumFBConfigs = 0; + + for (c=0; c<dmxScreen0->numFBConfigs; c++) { + __GLXFBConfig *cfg = NULL; + + if (numscreens > 1) { + for (s=1; s<numscreens; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + __GLXscreenInfo *glxScreen = &__glXActiveScreens[s]; + + cfg = FindMatchingFBConfig( &dmxScreen0->fbconfigs[c], + dmxScreen->fbconfigs, + dmxScreen->numFBConfigs ); + __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + s + 1 ] = cfg; + if (!cfg) { + dmxLog(dmxInfo,"screen0 FBConfig 0x%x is missing on screen#%d\n", dmxScreen0->fbconfigs[c].id, s); + break; + } + else { + dmxLog(dmxInfo,"screen0 FBConfig 0x%x matched to 0x%x on screen#%d\n", dmxScreen0->fbconfigs[c].id, cfg->id, s); + } + } + } + else { + cfg = &dmxScreen0->fbconfigs[c]; + } + + if (cfg) { + + /* filter out overlay visuals */ + if (cfg->level == 0) { + __GLXFBConfig *proxy_cfg; + + __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + 1 ] = + &dmxScreen0->fbconfigs[c]; + + proxy_cfg = malloc( sizeof(__GLXFBConfig) ); + memcpy( proxy_cfg, cfg, sizeof(__GLXFBConfig) ); + proxy_cfg->id = FakeClientID(0); + /* visual will be associated later in __glXGetFBConfigs */ + proxy_cfg->associatedVisualId = (unsigned int)-1; + + __glXFBConfigs[ __glXNumFBConfigs * (numscreens+1) + 0 ] = proxy_cfg; + + __glXNumFBConfigs++; + } + + } + + } + + } + +} + +void __glXScreenReset(void) +{ + __glXNumActiveScreens = 0; +} + +char *__glXGetServerString( unsigned int name ) +{ + char *ret = NULL; + + switch( name) { + + case GLX_VENDOR: + ret = GLXServerVendorName; + break; + + case GLX_VERSION: + ret = GLXServerVersion; + break; + + case GLX_EXTENSIONS: + ret = ExtensionsString; + break; + + default: + break; + } + + return( ret ); + +} + + +__GLXFBConfig *glxLookupFBConfig( GLXFBConfigID id ) +{ + int i,j; + + for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { + if ( __glXFBConfigs[j]->id == id) + return( __glXFBConfigs[j] ); + } + + return(NULL); +} + +__GLXFBConfig *glxLookupFBConfigByVID( VisualID vid ) +{ + int i,j; + + for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { + if ( __glXFBConfigs[j]->associatedVisualId == vid) + return( __glXFBConfigs[j] ); + } + + return(NULL); +} + +__GLXFBConfig *glxLookupBackEndFBConfig( GLXFBConfigID id, int screen ) +{ + int i; + int j; + + for (i=0, j=0; i<__glXNumFBConfigs; i++,j+=(__glXNumActiveScreens+1) ) { + if ( __glXFBConfigs[j]->id == id) + return( __glXFBConfigs[j+screen+1] ); + } + + return(NULL); + +} + +int glxIsExtensionSupported( char *ext ) +{ + return( strstr(ExtensionsString, ext) != NULL ); +} diff --git a/xorg-server/hw/dmx/glxProxy/glxsingle.c b/xorg-server/hw/dmx/glxProxy/glxsingle.c index dcc604052..19f12ad58 100644 --- a/xorg-server/hw/dmx/glxProxy/glxsingle.c +++ b/xorg-server/hw/dmx/glxProxy/glxsingle.c @@ -1,1012 +1,1012 @@ -/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED */ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxwindow.h" -#include "dmxpixmap.h" -#include "dmxfont.h" -#include "dmxcb.h" - -#undef Xmalloc -#undef Xcalloc -#undef Xrealloc -#undef Xfree - -#include "glxserver.h" -#include "glxext.h" -#include "g_disptab.h" -/* #include "g_disptab_EXT.h" */ -#include "unpack.h" -#include "glxutil.h" - -#include "GL/glxproto.h" - -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#endif - -/* - * GetReqSingle - this is the equivalent of GetReq macro - * from Xlibint.h but it does not set the reqType field (the opcode). - * this is because the GL single opcodes has different naming convension - * the other X opcodes (ie. X_GLsop_GetFloatv). - */ -#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) -#define GetReqSingle(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x##name##Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ - req->length = (SIZEOF(x##name##Req))>>2;\ - dpy->bufptr += SIZEOF(x##name##Req);\ - dpy->request++ - -#else /* non-ANSI C uses empty comment instead of "##" for token concatenation */ -#define GetReqSingle(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x/**/name/**/Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x/**/name/**/Req *)(dpy->last_req = dpy->bufptr);\ - req->length = (SIZEOF(x/**/name/**/Req))>>2;\ - dpy->bufptr += SIZEOF(x/**/name/**/Req);\ - dpy->request++ -#endif - -#define X_GLXSingle 0 /* needed by GetReqExtra */ - -extern Display *GetBackEndDisplay( __GLXclientState *cl, int s ); -extern int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s); - -static int swap_vec_element_size = 0; - -static void SendSwappedReply( ClientPtr client, - xGLXSingleReply *reply, - char *buf, - int buf_size ) -{ - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_SWAP_SHORT(&reply->sequenceNumber); - __GLX_SWAP_INT(&reply->length); - __GLX_SWAP_INT(&reply->retval); - __GLX_SWAP_INT(&reply->size); - - if ( (buf_size == 0) && (swap_vec_element_size > 0) ) { - /* - * the reply has single component - need to swap pad3 - */ - if (swap_vec_element_size == 2) { - __GLX_SWAP_SHORT(&reply->pad3); - } - else if (swap_vec_element_size == 4) { - __GLX_SWAP_INT(&reply->pad3); - __GLX_SWAP_INT(&reply->pad4); /* some requests use also pad4 - * i.e GetConvolutionFilter - */ - } - else if (swap_vec_element_size == 8) { - __GLX_SWAP_DOUBLE(&reply->pad3); - } - } - else if ( (buf_size > 0) && (swap_vec_element_size > 0) ) { - /* - * the reply has vector of elements which needs to be swapped - */ - int vsize = buf_size / swap_vec_element_size; - char *p = buf; - int i; - - for (i=0; i<vsize; i++) { - if (swap_vec_element_size == 2) { - __GLX_SWAP_SHORT(p); - } - else if (swap_vec_element_size == 4) { - __GLX_SWAP_INT(p); - } - else if (swap_vec_element_size == 8) { - __GLX_SWAP_DOUBLE(p); - } - - p += swap_vec_element_size; - } - - /* - * swap pad words as well - for case that some single reply uses - * them as well - */ - __GLX_SWAP_INT(&reply->pad3); - __GLX_SWAP_INT(&reply->pad4); - __GLX_SWAP_INT(&reply->pad5); - __GLX_SWAP_INT(&reply->pad6); - - } - - WriteToClient(client, sizeof(xGLXSingleReply),(char *)reply); - if (buf_size > 0) - WriteToClient(client, buf_size, (char *)buf); - -} - -int __glXForwardSingleReq( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - xGLXSingleReq *be_req; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - int buf_size; - int s; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXSingleReq; - buf_size = (req->length << 2) - sz_xGLXSingleReq; - - /* - * just forward the request to back-end server(s) - */ - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReqSingle(GLXSingle,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - UnlockDisplay(dpy); - SyncHandle(); - - if (req->glxCode == X_GLsop_Flush) { - XFlush(dpy); - } - - } - - return Success; -} - -int __glXForwardPipe0WithReply( __GLXclientState *cl, GLbyte *pc ) -{ - ClientPtr client = cl->client; - xGLXSingleReq *req = (xGLXSingleReq *)pc; - xGLXSingleReq *be_req; - xGLXSingleReply reply; - xGLXSingleReply be_reply; - __GLXcontext *glxc; - int buf_size; - char *be_buf; - int be_buf_size; - DMXScreenInfo *dmxScreen; - Display *dpy; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return __glXBadContext; - } - - pc += sz_xGLXSingleReq; - buf_size = (req->length << 2) - sz_xGLXSingleReq; - - dmxScreen = &dmxScreens[glxc->pScreen->myNum]; - dpy = GetBackEndDisplay(cl, glxc->pScreen->myNum); - - /* - * send the request to the first back-end server - */ - LockDisplay(dpy); - GetReqSingle(GLXSingle,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,glxc->pScreen->myNum); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - - /* - * get the reply from the back-end server - */ - _XReply(dpy, (xReply*) &be_reply, 0, False); - be_buf_size = be_reply.length << 2; - if (be_buf_size > 0) { - be_buf = (char *)Xalloc( be_buf_size ); - if (be_buf) { - _XRead(dpy, be_buf, be_buf_size); - } - else { - /* Throw data on the floor */ - _XEatData(dpy, be_buf_size); - return BadAlloc; - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - /* - * send the reply to the client - */ - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = be_reply.length; - reply.retval = be_reply.retval; - reply.size = be_reply.size; - reply.pad3 = be_reply.pad3; - reply.pad4 = be_reply.pad4; - - if (client->swapped) { - SendSwappedReply( client, &reply, be_buf, be_buf_size ); - } - else { - WriteToClient(client, sizeof(xGLXSingleReply),(char *)&reply); - if (be_buf_size > 0) - WriteToClient(client, be_buf_size, (char *)be_buf); - } - - if (be_buf_size > 0) Xfree(be_buf); - - return Success; -} - -int __glXForwardAllWithReply( __GLXclientState *cl, GLbyte *pc ) -{ - ClientPtr client = cl->client; - xGLXSingleReq *req = (xGLXSingleReq *)pc; - xGLXSingleReq *be_req; - xGLXSingleReply reply; - xGLXSingleReply be_reply; - __GLXcontext *glxc; - int buf_size; - char *be_buf; - int be_buf_size; - int from_screen = 0; - int to_screen = 0; - int s; - - DMXScreenInfo *dmxScreen; - Display *dpy; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXSingleReq; - buf_size = (req->length << 2) - sz_xGLXSingleReq; - - /* - * send the request to the first back-end server(s) - */ - for (s=to_screen; s>=from_screen; s--) { - dmxScreen = &dmxScreens[s]; - dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReqSingle(GLXSingle,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - - /* - * get the reply from the back-end server - */ - _XReply(dpy, (xReply*) &be_reply, 0, False); - be_buf_size = be_reply.length << 2; - if (be_buf_size > 0) { - be_buf = (char *)Xalloc( be_buf_size ); - if (be_buf) { - _XRead(dpy, be_buf, be_buf_size); - } - else { - /* Throw data on the floor */ - _XEatData(dpy, be_buf_size); - return BadAlloc; - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - if (s > from_screen && be_buf_size > 0) { - Xfree(be_buf); - } - } - - /* - * send the reply to the client - */ - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = be_reply.length; - reply.retval = be_reply.retval; - reply.size = be_reply.size; - reply.pad3 = be_reply.pad3; - reply.pad4 = be_reply.pad4; - - if (client->swapped) { - SendSwappedReply( client, &reply, be_buf, be_buf_size ); - } - else { - WriteToClient(client, sizeof(xGLXSingleReply),(char *)&reply); - if (be_buf_size > 0) - WriteToClient(client, be_buf_size, (char *)be_buf); - } - - if (be_buf_size > 0) Xfree(be_buf); - - return Success; -} - -int __glXForwardSingleReqSwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXForwardSingleReq( cl, pc ) ); -} - -int __glXForwardPipe0WithReplySwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXForwardPipe0WithReply( cl, pc ) ); -} - -int __glXForwardPipe0WithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 2; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardPipe0WithReply( cl, pc ) ); -} - -int __glXForwardPipe0WithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 4; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardPipe0WithReply( cl, pc ) ); -} - -int __glXForwardPipe0WithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 8; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardPipe0WithReply( cl, pc ) ); -} - -int __glXForwardAllWithReplySwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardAllWithReply( cl, pc ) ); -} - -int __glXForwardAllWithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 2; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardAllWithReply( cl, pc ) ); -} - -int __glXForwardAllWithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 4; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardAllWithReply( cl, pc ) ); -} - -int __glXForwardAllWithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 8; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXSingleReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXSingleReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - - return( __glXForwardAllWithReply( cl, pc ) ); -} - -static GLint __glReadPixels_size(GLenum format, GLenum type, GLint w, GLint h, - int *elementbits_return, int *rowbytes_return ) -{ - GLint elements, esize; - GLint rowsize, padding; - - if (w < 0 || h < 0) { - return -1; - } - switch (format) { - case GL_COLOR_INDEX: - case GL_STENCIL_INDEX: - case GL_DEPTH_COMPONENT: - elements = 1; - break; - case GL_RED: - case GL_GREEN: - case GL_BLUE: - case GL_ALPHA: - case GL_LUMINANCE: - elements = 1; - break; - case GL_LUMINANCE_ALPHA: - elements = 2; - break; - case GL_RGB: - case GL_BGR: - elements = 3; - break; - case GL_RGBA: - case GL_BGRA: - case GL_ABGR_EXT: - elements = 4; - break; - default: - return -1; - } - /* - ** According to the GLX protocol, each row must be padded to a multiple of - ** 4 bytes. 4 bytes also happens to be the default alignment in the pixel - ** store modes of the GL. - */ - switch (type) { - case GL_BITMAP: - if (format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX) { - rowsize = ((w * elements)+7)/8; - padding = rowsize % 4; - if (padding) { - rowsize += 4 - padding; - } - if (elementbits_return) *elementbits_return = elements; - if (rowbytes_return) *rowbytes_return = rowsize; - return (rowsize * h); - } else { - return -1; - } - case GL_BYTE: - case GL_UNSIGNED_BYTE: - esize = 1; - break; - case GL_UNSIGNED_BYTE_3_3_2: - case GL_UNSIGNED_BYTE_2_3_3_REV: - esize = 1; - elements = 1; - break; - case GL_SHORT: - case GL_UNSIGNED_SHORT: - esize = 2; - break; - case GL_UNSIGNED_SHORT_5_6_5: - case GL_UNSIGNED_SHORT_5_6_5_REV: - case GL_UNSIGNED_SHORT_4_4_4_4: - case GL_UNSIGNED_SHORT_4_4_4_4_REV: - case GL_UNSIGNED_SHORT_5_5_5_1: - case GL_UNSIGNED_SHORT_1_5_5_5_REV: - esize = 2; - elements = 1; - break; - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - esize = 4; - break; - case GL_UNSIGNED_INT_8_8_8_8: - case GL_UNSIGNED_INT_8_8_8_8_REV: - case GL_UNSIGNED_INT_10_10_10_2: - case GL_UNSIGNED_INT_2_10_10_10_REV: - esize = 4; - elements = 1; - break; - default: - return -1; - } - rowsize = w * elements * esize; - padding = rowsize % 4; - if (padding) { - rowsize += 4 - padding; - } - - if (elementbits_return) *elementbits_return = esize*elements*8; - if (rowbytes_return) *rowbytes_return = rowsize; - - return (rowsize * h); -} - -static int intersectRect( int x1, int x2, int y1, int y2, - int X1, int X2, int Y1, int Y2, - int *ix1, int *ix2, int *iy1, int *iy2 ) -{ - int right = (x2 < X2 ? x2 : X2); - int bottom = (y2 < Y2 ? y2 : Y2); - int left = (x1 > X1 ? x1 : X1); - int top = (y1 > Y1 ? y1 : Y1); - int width = right - left + 1; - int height = bottom - top + 1; - - if ( (width <= 0) || (height <= 0) ) { - *ix1 = *ix2 = *iy1 = *iy2 = 0; - return(0); - } - else { - *ix1 = left; - *ix2 = right; - *iy1 = top; - *iy2 = bottom; - return( width * height ); - } - -} - -int __glXDisp_ReadPixels(__GLXclientState *cl, GLbyte *pc) -{ - xGLXSingleReq *req = (xGLXSingleReq *)pc; - xGLXSingleReq *be_req; - xGLXReadPixelsReply reply; - xGLXReadPixelsReply be_reply; - GLbyte *be_pc; - GLint x,y; - GLsizei width, height; - GLenum format, type; - GLboolean swapBytes, lsbFirst; - ClientPtr client = cl->client; - DrawablePtr pDraw; - int error; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - char *buf; - int buf_size; - int s; - int win_x1, win_x2; - int win_y1, win_y2; - int ebits, rowsize; - __GLX_DECLARE_SWAP_VARIABLES; - - if (client->swapped) { - __GLX_SWAP_INT(&req->contextTag); - } - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXSingleReq; - x = *(GLint *)(pc + 0); - y = *(GLint *)(pc + 4); - width = *(GLsizei *)(pc + 8); - height = *(GLsizei *)(pc + 12); - format = *(GLenum *)(pc + 16); - type = *(GLenum *)(pc + 20); - swapBytes = *(GLboolean *)(pc + 24); - lsbFirst = *(GLboolean *)(pc + 25); - - if (client->swapped) { - __GLX_SWAP_INT(&x); - __GLX_SWAP_INT(&y); - __GLX_SWAP_INT(&width); - __GLX_SWAP_INT(&height); - __GLX_SWAP_INT(&format); - __GLX_SWAP_INT(&type); - swapBytes = !swapBytes; - } - - buf_size = __glReadPixels_size(format,type,width,height, &ebits, &rowsize); - if (buf_size > 0) { - buf = (char *) Xalloc( buf_size ); - if ( !buf ) { - return( BadAlloc ); - } - } - else { - buf_size = 0; - } - - if (buf_size > 0) { - /* - * Get the current drawable this context is bound to - */ - pDraw = __glXLookupDrawableByTag( cl, req->contextTag ); - win_x1 = pDraw->x + x; - win_x2 = win_x1 + width - 1; - win_y1 = (dmxGlobalHeight - pDraw->y - pDraw->height) + y; - win_y2 = win_y1 + height - 1; - if (pDraw->type != DRAWABLE_WINDOW) { - from_screen = to_screen = 0; - } - - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - int scr_x1 = dmxScreen->rootXOrigin; - int scr_x2 = dmxScreen->rootXOrigin + dmxScreen->scrnWidth - 1; - int scr_y1 = dmxScreen->rootYOrigin; - int scr_y2 = dmxScreen->rootYOrigin + dmxScreen->scrnHeight - 1; - int wx1, wx2, wy1, wy2; - int sx, sy, sw, sh; - int npixels; - - /* - * find the window portion that is on the current screen - */ - if (pDraw->type == DRAWABLE_WINDOW) { - npixels = intersectRect( scr_x1, scr_x2, scr_y1, scr_y2, - win_x1, win_x2, win_y1, win_y2, - &wx1, &wx2, &wy1, &wy2 ); - } - else { - wx1 = win_x1; - wx2 = win_x2; - wy1 = win_y1; - wy2 = win_y2; - npixels = (wx2-wx1+1) * (wy2-wy1+1); - } - - if (npixels > 0) { - - /* send the request to the back-end server */ - LockDisplay(dpy); - GetReqExtra(GLXSingle,__GLX_PAD(26),be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = X_GLsop_ReadPixels; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - be_pc = ((GLbyte *)(be_req) + sz_xGLXSingleReq); - - sx = wx1 - pDraw->x; - sy = wy1 - (dmxGlobalHeight - pDraw->y - pDraw->height); - sw = (wx2-wx1+1); - sh = (wy2-wy1+1); - - *(GLint *)(be_pc + 0) = sx; /* x */ - *(GLint *)(be_pc + 4) = sy; /* y */ - *(GLsizei *)(be_pc + 8) = sw; /* width */ - *(GLsizei *)(be_pc + 12) = sh; /* height */ - *(GLenum *)(be_pc + 16) = format; - *(GLenum *)(be_pc + 20) = type; - *(GLboolean *)(be_pc + 24) = swapBytes; - *(GLboolean *)(be_pc + 25) = lsbFirst; - - _XReply(dpy, (xReply*) &be_reply, 0, False); - - if (be_reply.length > 0) { - char *be_buf; - int be_buf_size = be_reply.length << 2; - - be_buf = (char *) Xalloc( be_buf_size ); - if (be_buf) { - _XRead(dpy, be_buf, be_buf_size); - - /* copy pixels data to the right location of the */ - /* reply buffer */ - if ( type != GL_BITMAP ) { - int pbytes = ebits / 8; - char *dst = buf + (sy-y)*rowsize + (sx-x)*pbytes; - char *src = be_buf; - int pad = (pbytes * sw) % 4; - int r; - - for (r=0; r<sh; r++) { - memcpy( dst, src, pbytes*sw ); - dst += rowsize; - src += (pbytes*sw + (pad ? 4-pad : 0) ); - } - } - else { - /* this is a GL_BITMAP pixel type, should copy bits */ - int r; - int src_rowsize = bits_to_bytes(sw * ebits); - int src_pad = src_rowsize % 4; - if ( src_pad ) { - src_rowsize += (4 - src_pad); - } - - for (r=0; r<sh; r++) { - unsigned char dst_mask = 0x80 >> (sx % 8); - unsigned char src_mask = 0x80; - char *dst = buf + (sy-y+r)*rowsize + (sx-x)/8; - char *src = be_buf + r*src_rowsize; - int b; - - for (b=0; b<sw*ebits; b++) { - if ( *src & src_mask ) { - *dst |= dst_mask; - } - else { - *dst &= ~dst_mask; - } - - if (dst_mask > 1) dst_mask >>= 1; - else { - dst_mask = 0x80; - dst++; - } - - if (src_mask > 1) src_mask >>= 1; - else { - src_mask = 0x80; - src++; - } - } - } - - } - - Xfree( be_buf ); - } - else { - /* Throw data on the floor */ - _XEatData(dpy, be_buf_size); - Xfree( buf ); - return BadAlloc; - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - } /* of npixels > 0 */ - - } /* of for loop */ - - } /* of if buf_size > 0 */ - - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - reply.length = buf_size >> 2; - - if (client->swapped) { - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - } - - WriteToClient(client, sizeof(xGLXReadPixelsReply),(char *)&reply); - if (buf_size > 0) { - WriteToClient(client, buf_size, (char *)buf); - Xfree( buf ); - } - - return Success; -} - -int __glXDispSwap_GetTexImage(__GLXclientState *cl, GLbyte *pc) -{ - __GLX_DECLARE_SWAP_VARIABLES; - GLbyte *lpc = pc; - - lpc += sz_xGLXSingleReq; - __GLX_SWAP_INT(lpc+0); - __GLX_SWAP_INT(lpc+4); - __GLX_SWAP_INT(lpc+8); - __GLX_SWAP_INT(lpc+12); - - /* reverse swapBytes */ - *(GLboolean *)(lpc + 16) = ! *(GLboolean *)(lpc + 16); - - return( __glXForwardPipe0WithReplySwap( cl, pc ) ); -} - -int __glXDispSwap_GetColorTable(__GLXclientState *cl, GLbyte *pc) -{ - __GLX_DECLARE_SWAP_VARIABLES; - GLbyte *lpc = pc; - - lpc += sz_xGLXSingleReq; - __GLX_SWAP_INT(lpc+0); - __GLX_SWAP_INT(lpc+4); - __GLX_SWAP_INT(lpc+8); - - /* reverse swapBytes */ - *(GLboolean *)(lpc + 12) = ! *(GLboolean *)(lpc + 12); - - return( __glXForwardPipe0WithReplySwap( cl, pc ) ); -} - - +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED */ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxfont.h" +#include "dmxcb.h" + +#undef Xmalloc +#undef Xcalloc +#undef Xrealloc +#undef Xfree + +#include "glxserver.h" +#include "glxext.h" +#include "g_disptab.h" +/* #include "g_disptab_EXT.h" */ +#include "unpack.h" +#include "glxutil.h" + +#include "GL/glxproto.h" + +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +/* + * GetReqSingle - this is the equivalent of GetReq macro + * from Xlibint.h but it does not set the reqType field (the opcode). + * this is because the GL single opcodes has different naming convension + * the other X opcodes (ie. X_GLsop_GetFloatv). + */ +#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) +#define GetReqSingle(name, req) \ + WORD64ALIGN\ + if ((dpy->bufptr + SIZEOF(x##name##Req)) > dpy->bufmax)\ + _XFlush(dpy);\ + req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ + req->length = (SIZEOF(x##name##Req))>>2;\ + dpy->bufptr += SIZEOF(x##name##Req);\ + dpy->request++ + +#else /* non-ANSI C uses empty comment instead of "##" for token concatenation */ +#define GetReqSingle(name, req) \ + WORD64ALIGN\ + if ((dpy->bufptr + SIZEOF(x/**/name/**/Req)) > dpy->bufmax)\ + _XFlush(dpy);\ + req = (x/**/name/**/Req *)(dpy->last_req = dpy->bufptr);\ + req->length = (SIZEOF(x/**/name/**/Req))>>2;\ + dpy->bufptr += SIZEOF(x/**/name/**/Req);\ + dpy->request++ +#endif + +#define X_GLXSingle 0 /* needed by GetReqExtra */ + +extern Display *GetBackEndDisplay( __GLXclientState *cl, int s ); +extern int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s); + +static int swap_vec_element_size = 0; + +static void SendSwappedReply( ClientPtr client, + xGLXSingleReply *reply, + char *buf, + int buf_size ) +{ + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_SWAP_SHORT(&reply->sequenceNumber); + __GLX_SWAP_INT(&reply->length); + __GLX_SWAP_INT(&reply->retval); + __GLX_SWAP_INT(&reply->size); + + if ( (buf_size == 0) && (swap_vec_element_size > 0) ) { + /* + * the reply has single component - need to swap pad3 + */ + if (swap_vec_element_size == 2) { + __GLX_SWAP_SHORT(&reply->pad3); + } + else if (swap_vec_element_size == 4) { + __GLX_SWAP_INT(&reply->pad3); + __GLX_SWAP_INT(&reply->pad4); /* some requests use also pad4 + * i.e GetConvolutionFilter + */ + } + else if (swap_vec_element_size == 8) { + __GLX_SWAP_DOUBLE(&reply->pad3); + } + } + else if ( (buf_size > 0) && (swap_vec_element_size > 0) ) { + /* + * the reply has vector of elements which needs to be swapped + */ + int vsize = buf_size / swap_vec_element_size; + char *p = buf; + int i; + + for (i=0; i<vsize; i++) { + if (swap_vec_element_size == 2) { + __GLX_SWAP_SHORT(p); + } + else if (swap_vec_element_size == 4) { + __GLX_SWAP_INT(p); + } + else if (swap_vec_element_size == 8) { + __GLX_SWAP_DOUBLE(p); + } + + p += swap_vec_element_size; + } + + /* + * swap pad words as well - for case that some single reply uses + * them as well + */ + __GLX_SWAP_INT(&reply->pad3); + __GLX_SWAP_INT(&reply->pad4); + __GLX_SWAP_INT(&reply->pad5); + __GLX_SWAP_INT(&reply->pad6); + + } + + WriteToClient(client, sizeof(xGLXSingleReply),(char *)reply); + if (buf_size > 0) + WriteToClient(client, buf_size, (char *)buf); + +} + +int __glXForwardSingleReq( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + xGLXSingleReq *be_req; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + int buf_size; + int s; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXSingleReq; + buf_size = (req->length << 2) - sz_xGLXSingleReq; + + /* + * just forward the request to back-end server(s) + */ + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReqSingle(GLXSingle,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + UnlockDisplay(dpy); + SyncHandle(); + + if (req->glxCode == X_GLsop_Flush) { + XFlush(dpy); + } + + } + + return Success; +} + +int __glXForwardPipe0WithReply( __GLXclientState *cl, GLbyte *pc ) +{ + ClientPtr client = cl->client; + xGLXSingleReq *req = (xGLXSingleReq *)pc; + xGLXSingleReq *be_req; + xGLXSingleReply reply; + xGLXSingleReply be_reply; + __GLXcontext *glxc; + int buf_size; + char *be_buf; + int be_buf_size; + DMXScreenInfo *dmxScreen; + Display *dpy; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return __glXBadContext; + } + + pc += sz_xGLXSingleReq; + buf_size = (req->length << 2) - sz_xGLXSingleReq; + + dmxScreen = &dmxScreens[glxc->pScreen->myNum]; + dpy = GetBackEndDisplay(cl, glxc->pScreen->myNum); + + /* + * send the request to the first back-end server + */ + LockDisplay(dpy); + GetReqSingle(GLXSingle,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,glxc->pScreen->myNum); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + + /* + * get the reply from the back-end server + */ + _XReply(dpy, (xReply*) &be_reply, 0, False); + be_buf_size = be_reply.length << 2; + if (be_buf_size > 0) { + be_buf = (char *)malloc( be_buf_size ); + if (be_buf) { + _XRead(dpy, be_buf, be_buf_size); + } + else { + /* Throw data on the floor */ + _XEatData(dpy, be_buf_size); + return BadAlloc; + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + /* + * send the reply to the client + */ + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = be_reply.length; + reply.retval = be_reply.retval; + reply.size = be_reply.size; + reply.pad3 = be_reply.pad3; + reply.pad4 = be_reply.pad4; + + if (client->swapped) { + SendSwappedReply( client, &reply, be_buf, be_buf_size ); + } + else { + WriteToClient(client, sizeof(xGLXSingleReply),(char *)&reply); + if (be_buf_size > 0) + WriteToClient(client, be_buf_size, (char *)be_buf); + } + + if (be_buf_size > 0) Xfree(be_buf); + + return Success; +} + +int __glXForwardAllWithReply( __GLXclientState *cl, GLbyte *pc ) +{ + ClientPtr client = cl->client; + xGLXSingleReq *req = (xGLXSingleReq *)pc; + xGLXSingleReq *be_req; + xGLXSingleReply reply; + xGLXSingleReply be_reply; + __GLXcontext *glxc; + int buf_size; + char *be_buf; + int be_buf_size; + int from_screen = 0; + int to_screen = 0; + int s; + + DMXScreenInfo *dmxScreen; + Display *dpy; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXSingleReq; + buf_size = (req->length << 2) - sz_xGLXSingleReq; + + /* + * send the request to the first back-end server(s) + */ + for (s=to_screen; s>=from_screen; s--) { + dmxScreen = &dmxScreens[s]; + dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReqSingle(GLXSingle,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + + /* + * get the reply from the back-end server + */ + _XReply(dpy, (xReply*) &be_reply, 0, False); + be_buf_size = be_reply.length << 2; + if (be_buf_size > 0) { + be_buf = (char *)malloc( be_buf_size ); + if (be_buf) { + _XRead(dpy, be_buf, be_buf_size); + } + else { + /* Throw data on the floor */ + _XEatData(dpy, be_buf_size); + return BadAlloc; + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + if (s > from_screen && be_buf_size > 0) { + Xfree(be_buf); + } + } + + /* + * send the reply to the client + */ + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = be_reply.length; + reply.retval = be_reply.retval; + reply.size = be_reply.size; + reply.pad3 = be_reply.pad3; + reply.pad4 = be_reply.pad4; + + if (client->swapped) { + SendSwappedReply( client, &reply, be_buf, be_buf_size ); + } + else { + WriteToClient(client, sizeof(xGLXSingleReply),(char *)&reply); + if (be_buf_size > 0) + WriteToClient(client, be_buf_size, (char *)be_buf); + } + + if (be_buf_size > 0) Xfree(be_buf); + + return Success; +} + +int __glXForwardSingleReqSwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXForwardSingleReq( cl, pc ) ); +} + +int __glXForwardPipe0WithReplySwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXForwardPipe0WithReply( cl, pc ) ); +} + +int __glXForwardPipe0WithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 2; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardPipe0WithReply( cl, pc ) ); +} + +int __glXForwardPipe0WithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 4; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardPipe0WithReply( cl, pc ) ); +} + +int __glXForwardPipe0WithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 8; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardPipe0WithReply( cl, pc ) ); +} + +int __glXForwardAllWithReplySwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardAllWithReply( cl, pc ) ); +} + +int __glXForwardAllWithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 2; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardAllWithReply( cl, pc ) ); +} + +int __glXForwardAllWithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 4; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardAllWithReply( cl, pc ) ); +} + +int __glXForwardAllWithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 8; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXSingleReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXSingleReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + + return( __glXForwardAllWithReply( cl, pc ) ); +} + +static GLint __glReadPixels_size(GLenum format, GLenum type, GLint w, GLint h, + int *elementbits_return, int *rowbytes_return ) +{ + GLint elements, esize; + GLint rowsize, padding; + + if (w < 0 || h < 0) { + return -1; + } + switch (format) { + case GL_COLOR_INDEX: + case GL_STENCIL_INDEX: + case GL_DEPTH_COMPONENT: + elements = 1; + break; + case GL_RED: + case GL_GREEN: + case GL_BLUE: + case GL_ALPHA: + case GL_LUMINANCE: + elements = 1; + break; + case GL_LUMINANCE_ALPHA: + elements = 2; + break; + case GL_RGB: + case GL_BGR: + elements = 3; + break; + case GL_RGBA: + case GL_BGRA: + case GL_ABGR_EXT: + elements = 4; + break; + default: + return -1; + } + /* + ** According to the GLX protocol, each row must be padded to a multiple of + ** 4 bytes. 4 bytes also happens to be the default alignment in the pixel + ** store modes of the GL. + */ + switch (type) { + case GL_BITMAP: + if (format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX) { + rowsize = ((w * elements)+7)/8; + padding = rowsize % 4; + if (padding) { + rowsize += 4 - padding; + } + if (elementbits_return) *elementbits_return = elements; + if (rowbytes_return) *rowbytes_return = rowsize; + return (rowsize * h); + } else { + return -1; + } + case GL_BYTE: + case GL_UNSIGNED_BYTE: + esize = 1; + break; + case GL_UNSIGNED_BYTE_3_3_2: + case GL_UNSIGNED_BYTE_2_3_3_REV: + esize = 1; + elements = 1; + break; + case GL_SHORT: + case GL_UNSIGNED_SHORT: + esize = 2; + break; + case GL_UNSIGNED_SHORT_5_6_5: + case GL_UNSIGNED_SHORT_5_6_5_REV: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_4_4_4_4_REV: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + esize = 2; + elements = 1; + break; + case GL_INT: + case GL_UNSIGNED_INT: + case GL_FLOAT: + esize = 4; + break; + case GL_UNSIGNED_INT_8_8_8_8: + case GL_UNSIGNED_INT_8_8_8_8_REV: + case GL_UNSIGNED_INT_10_10_10_2: + case GL_UNSIGNED_INT_2_10_10_10_REV: + esize = 4; + elements = 1; + break; + default: + return -1; + } + rowsize = w * elements * esize; + padding = rowsize % 4; + if (padding) { + rowsize += 4 - padding; + } + + if (elementbits_return) *elementbits_return = esize*elements*8; + if (rowbytes_return) *rowbytes_return = rowsize; + + return (rowsize * h); +} + +static int intersectRect( int x1, int x2, int y1, int y2, + int X1, int X2, int Y1, int Y2, + int *ix1, int *ix2, int *iy1, int *iy2 ) +{ + int right = (x2 < X2 ? x2 : X2); + int bottom = (y2 < Y2 ? y2 : Y2); + int left = (x1 > X1 ? x1 : X1); + int top = (y1 > Y1 ? y1 : Y1); + int width = right - left + 1; + int height = bottom - top + 1; + + if ( (width <= 0) || (height <= 0) ) { + *ix1 = *ix2 = *iy1 = *iy2 = 0; + return(0); + } + else { + *ix1 = left; + *ix2 = right; + *iy1 = top; + *iy2 = bottom; + return( width * height ); + } + +} + +int __glXDisp_ReadPixels(__GLXclientState *cl, GLbyte *pc) +{ + xGLXSingleReq *req = (xGLXSingleReq *)pc; + xGLXSingleReq *be_req; + xGLXReadPixelsReply reply; + xGLXReadPixelsReply be_reply; + GLbyte *be_pc; + GLint x,y; + GLsizei width, height; + GLenum format, type; + GLboolean swapBytes, lsbFirst; + ClientPtr client = cl->client; + DrawablePtr pDraw; + int error; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + char *buf; + int buf_size; + int s; + int win_x1, win_x2; + int win_y1, win_y2; + int ebits, rowsize; + __GLX_DECLARE_SWAP_VARIABLES; + + if (client->swapped) { + __GLX_SWAP_INT(&req->contextTag); + } + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXSingleReq; + x = *(GLint *)(pc + 0); + y = *(GLint *)(pc + 4); + width = *(GLsizei *)(pc + 8); + height = *(GLsizei *)(pc + 12); + format = *(GLenum *)(pc + 16); + type = *(GLenum *)(pc + 20); + swapBytes = *(GLboolean *)(pc + 24); + lsbFirst = *(GLboolean *)(pc + 25); + + if (client->swapped) { + __GLX_SWAP_INT(&x); + __GLX_SWAP_INT(&y); + __GLX_SWAP_INT(&width); + __GLX_SWAP_INT(&height); + __GLX_SWAP_INT(&format); + __GLX_SWAP_INT(&type); + swapBytes = !swapBytes; + } + + buf_size = __glReadPixels_size(format,type,width,height, &ebits, &rowsize); + if (buf_size > 0) { + buf = (char *) malloc( buf_size ); + if ( !buf ) { + return( BadAlloc ); + } + } + else { + buf_size = 0; + } + + if (buf_size > 0) { + /* + * Get the current drawable this context is bound to + */ + pDraw = __glXLookupDrawableByTag( cl, req->contextTag ); + win_x1 = pDraw->x + x; + win_x2 = win_x1 + width - 1; + win_y1 = (dmxGlobalHeight - pDraw->y - pDraw->height) + y; + win_y2 = win_y1 + height - 1; + if (pDraw->type != DRAWABLE_WINDOW) { + from_screen = to_screen = 0; + } + + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + int scr_x1 = dmxScreen->rootXOrigin; + int scr_x2 = dmxScreen->rootXOrigin + dmxScreen->scrnWidth - 1; + int scr_y1 = dmxScreen->rootYOrigin; + int scr_y2 = dmxScreen->rootYOrigin + dmxScreen->scrnHeight - 1; + int wx1, wx2, wy1, wy2; + int sx, sy, sw, sh; + int npixels; + + /* + * find the window portion that is on the current screen + */ + if (pDraw->type == DRAWABLE_WINDOW) { + npixels = intersectRect( scr_x1, scr_x2, scr_y1, scr_y2, + win_x1, win_x2, win_y1, win_y2, + &wx1, &wx2, &wy1, &wy2 ); + } + else { + wx1 = win_x1; + wx2 = win_x2; + wy1 = win_y1; + wy2 = win_y2; + npixels = (wx2-wx1+1) * (wy2-wy1+1); + } + + if (npixels > 0) { + + /* send the request to the back-end server */ + LockDisplay(dpy); + GetReqExtra(GLXSingle,__GLX_PAD(26),be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = X_GLsop_ReadPixels; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + be_pc = ((GLbyte *)(be_req) + sz_xGLXSingleReq); + + sx = wx1 - pDraw->x; + sy = wy1 - (dmxGlobalHeight - pDraw->y - pDraw->height); + sw = (wx2-wx1+1); + sh = (wy2-wy1+1); + + *(GLint *)(be_pc + 0) = sx; /* x */ + *(GLint *)(be_pc + 4) = sy; /* y */ + *(GLsizei *)(be_pc + 8) = sw; /* width */ + *(GLsizei *)(be_pc + 12) = sh; /* height */ + *(GLenum *)(be_pc + 16) = format; + *(GLenum *)(be_pc + 20) = type; + *(GLboolean *)(be_pc + 24) = swapBytes; + *(GLboolean *)(be_pc + 25) = lsbFirst; + + _XReply(dpy, (xReply*) &be_reply, 0, False); + + if (be_reply.length > 0) { + char *be_buf; + int be_buf_size = be_reply.length << 2; + + be_buf = (char *) malloc( be_buf_size ); + if (be_buf) { + _XRead(dpy, be_buf, be_buf_size); + + /* copy pixels data to the right location of the */ + /* reply buffer */ + if ( type != GL_BITMAP ) { + int pbytes = ebits / 8; + char *dst = buf + (sy-y)*rowsize + (sx-x)*pbytes; + char *src = be_buf; + int pad = (pbytes * sw) % 4; + int r; + + for (r=0; r<sh; r++) { + memcpy( dst, src, pbytes*sw ); + dst += rowsize; + src += (pbytes*sw + (pad ? 4-pad : 0) ); + } + } + else { + /* this is a GL_BITMAP pixel type, should copy bits */ + int r; + int src_rowsize = bits_to_bytes(sw * ebits); + int src_pad = src_rowsize % 4; + if ( src_pad ) { + src_rowsize += (4 - src_pad); + } + + for (r=0; r<sh; r++) { + unsigned char dst_mask = 0x80 >> (sx % 8); + unsigned char src_mask = 0x80; + char *dst = buf + (sy-y+r)*rowsize + (sx-x)/8; + char *src = be_buf + r*src_rowsize; + int b; + + for (b=0; b<sw*ebits; b++) { + if ( *src & src_mask ) { + *dst |= dst_mask; + } + else { + *dst &= ~dst_mask; + } + + if (dst_mask > 1) dst_mask >>= 1; + else { + dst_mask = 0x80; + dst++; + } + + if (src_mask > 1) src_mask >>= 1; + else { + src_mask = 0x80; + src++; + } + } + } + + } + + Xfree( be_buf ); + } + else { + /* Throw data on the floor */ + _XEatData(dpy, be_buf_size); + Xfree( buf ); + return BadAlloc; + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + } /* of npixels > 0 */ + + } /* of for loop */ + + } /* of if buf_size > 0 */ + + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = buf_size >> 2; + + if (client->swapped) { + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + } + + WriteToClient(client, sizeof(xGLXReadPixelsReply),(char *)&reply); + if (buf_size > 0) { + WriteToClient(client, buf_size, (char *)buf); + Xfree( buf ); + } + + return Success; +} + +int __glXDispSwap_GetTexImage(__GLXclientState *cl, GLbyte *pc) +{ + __GLX_DECLARE_SWAP_VARIABLES; + GLbyte *lpc = pc; + + lpc += sz_xGLXSingleReq; + __GLX_SWAP_INT(lpc+0); + __GLX_SWAP_INT(lpc+4); + __GLX_SWAP_INT(lpc+8); + __GLX_SWAP_INT(lpc+12); + + /* reverse swapBytes */ + *(GLboolean *)(lpc + 16) = ! *(GLboolean *)(lpc + 16); + + return( __glXForwardPipe0WithReplySwap( cl, pc ) ); +} + +int __glXDispSwap_GetColorTable(__GLXclientState *cl, GLbyte *pc) +{ + __GLX_DECLARE_SWAP_VARIABLES; + GLbyte *lpc = pc; + + lpc += sz_xGLXSingleReq; + __GLX_SWAP_INT(lpc+0); + __GLX_SWAP_INT(lpc+4); + __GLX_SWAP_INT(lpc+8); + + /* reverse swapBytes */ + *(GLboolean *)(lpc + 12) = ! *(GLboolean *)(lpc + 12); + + return( __glXForwardPipe0WithReplySwap( cl, pc ) ); +} + + diff --git a/xorg-server/hw/dmx/glxProxy/glxswap.c b/xorg-server/hw/dmx/glxProxy/glxswap.c index 1e184f914..1471d8b5f 100644 --- a/xorg-server/hw/dmx/glxProxy/glxswap.c +++ b/xorg-server/hw/dmx/glxProxy/glxswap.c @@ -1,538 +1,538 @@ -/* - * Copyright 2003 Red Hat Inc., Raleigh, 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: - * Kevin E. Martin <kem@redhat.com> - * - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxwindow.h" -#include "glxserver.h" -#include "glxswap.h" - -extern int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId, - GLXContextTag tag); - -typedef struct _SwapGroup *SwapGroupPtr; - -static Bool SwapBarrierIsReadyToSwap(GLuint barrier); -static void SwapSwapBarrier(GLuint barrier); -static void UpdateSwapBarrierList(GLuint barrier, - SwapGroupPtr pOldSwap, - SwapGroupPtr pNewSwap); - - -/************************************************************************ - * - * Swap Groups - * - ************************************************************************/ - -typedef struct _SwapGroup { - WindowPtr pWin; - SwapGroupPtr pNext; - - Bool swapping; - Bool sleeping; - GLuint barrier; - - XID drawable; - GLXContextTag tag; - __GLXclientState *clState; -} SwapGroupRec; - - -static void SwapSwapGroup(SwapGroupPtr pSwap) -{ - SwapGroupPtr pCur; - - /* All drawables in swap group are ready to swap, so just swap all - * drawables buffers and then wake up those clients that were - * previously sleeping */ - - for (pCur = pSwap; pCur; pCur = pCur->pNext) { - if (pCur->swapping) { - /* Swap pCur's buffers */ - __glXDoSwapBuffers(pCur->clState, pCur->drawable, pCur->tag); - pCur->swapping = FALSE; - } - - /* Wakeup client */ - if (pCur->sleeping) { - ClientWakeup(pCur->clState->client); - pCur->sleeping = FALSE; - } - } -} - -static Bool SwapGroupIsReadyToSwap(SwapGroupPtr pSwap) -{ - Bool isReady = TRUE; - - /* The swap group is ready to swap when all drawables are ready to - * swap. NOTE: A drawable is also ready to swap if it is not - * currently mapped */ - for (; pSwap; pSwap = pSwap->pNext) { - isReady &= (pSwap->swapping || !pSwap->pWin->mapped); - /* FIXME: Should we use pSwap->pWin->mapped or ...->realized ??? */ - } - - return isReady; -} - -static Bool SGSwapCleanup(ClientPtr client, pointer closure) -{ - /* SwapGroupPtr pSwap = (SwapGroupPtr)closure; */ - - /* This should not be called unless the client has died in which - * case we should remove the buffer from the swap list */ - - return TRUE; -} - -int SGSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag, - DrawablePtr pDraw) -{ - WindowPtr pWin = (WindowPtr)pDraw; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pSwap = pWinPriv->swapGroup; - SwapGroupPtr pCur; - - for (pCur = pSwap; pCur && pCur->pWin != pWin; pCur = pCur->pNext); - if (!pCur) - return BadDrawable; - - pCur->clState = cl; - pCur->drawable = drawId; - pCur->tag = tag; - - /* We are now in the process of swapping */ - pCur->swapping = TRUE; - - if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) { - /* The swap group is bound to a barrier and the barrier is ready - * to swap, so swap all the swap groups that are bound to this - * group's swap barrier */ - SwapSwapBarrier(pSwap->barrier); - } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) { - /* Do the swap if the entire swap group is ready to swap and the - * group is not bound to a swap barrier */ - SwapSwapGroup(pSwap); - } else { - /* The swap group/barrier is not yet ready to swap, so put - * client to sleep until the rest are ready to swap */ - ClientSleep(cl->client, SGSwapCleanup, (pointer)pWin); - pCur->sleeping = TRUE; - } - - return Success; -} - -static void SGWindowUnmapped(WindowPtr pWin) -{ - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pSwap = pWinPriv->swapGroup; - - /* Now that one of the windows in the swap group has been unmapped, - * see if the entire swap group/barrier is ready to swap */ - - if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) { - SwapSwapBarrier(pSwap->barrier); - } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) { - SwapSwapGroup(pSwap); - } -} - -static void SGWindowDestroyed(WindowPtr pWin) -{ - JoinSwapGroupSGIX((DrawablePtr)pWin, NULL); -} - -static SwapGroupPtr CreateSwapEntry(WindowPtr pWin) -{ - SwapGroupPtr pEntry; - - /* Allocate new swap group */ - pEntry = xalloc(sizeof(*pEntry)); - if (!pEntry) return NULL; - - /* Initialize swap group */ - pEntry->pWin = pWin; - pEntry->pNext = NULL; - pEntry->swapping = FALSE; - pEntry->sleeping = FALSE; - pEntry->barrier = 0; - /* The following are not initialized until SwapBuffers is called: - * pEntry->drawable - * pEntry->tag - * pEntry->clState - */ - - return pEntry; -} - -static void FreeSwapEntry(SwapGroupPtr pEntry) -{ - /* Since we have removed the drawable from its previous swap group - * and it won't be added to another swap group, the only thing that - * we need to do is to make sure that the drawable's client is not - * sleeping. This could happen if one thread is sleeping, while - * another thread called glxJoinSwapGroup(). Note that all sleeping - * threads should also be swapping, but there is a small window in - * the SGSwapBuffer() logic, above, where swapping can be set but - * sleeping is not. We check both independently here just to be - * pedantic. */ - - /* Handle swap buffer request */ - if (pEntry->swapping) - __glXDoSwapBuffers(pEntry->clState, pEntry->drawable, pEntry->tag); - - /* Wake up client */ - if (pEntry->sleeping) - ClientWakeup(pEntry->clState->client); - - /* We can free the pEntry entry since it has already been removed - * from the swap group list and it won't be needed any longer */ - xfree(pEntry); -} - -int JoinSwapGroupSGIX(DrawablePtr pDraw, DrawablePtr pMember) -{ - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDraw; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pOldSwap = NULL; - SwapGroupPtr pEntry; - - /* If pDraw and pMember are already members of the same swap - * group, just return Success since there is nothing to do */ - for (pEntry = pWinPriv->swapGroup; pEntry; pEntry = pEntry->pNext) - if (pEntry->pWin == (WindowPtr)pMember) - return Success; - - /* Remove pDraw from its current swap group */ - if (pWinPriv->swapGroup) { - SwapGroupPtr pSwapGroup = pWinPriv->swapGroup; - SwapGroupPtr pPrev; - - /* Find old swap entry in swap group and save in pOldSwap - * for later use */ - for (pOldSwap = pWinPriv->swapGroup, pPrev = NULL; - pOldSwap && pOldSwap->pWin != pWin; - pPrev = pOldSwap, pOldSwap = pOldSwap->pNext); - if (!pOldSwap) - return BadDrawable; - - /* Remove pDraw's swap group entry from swap group list */ - if (pPrev) { - pPrev->pNext = pOldSwap->pNext; - } else { - /* pWin is at the head of the swap group list, so we - * need to update all other members of this swap - * group */ - for (pEntry = pOldSwap->pNext; pEntry; pEntry = pEntry->pNext) - DMX_GET_WINDOW_PRIV(pEntry->pWin)->swapGroup - = pOldSwap->pNext; - - /* Update the barrier list as well */ - if (pOldSwap->barrier) - UpdateSwapBarrierList(pOldSwap->barrier, - pOldSwap, pOldSwap->pNext); - - /* Set pSwapGroup to point to the swap group without - * pOldSwap */ - pSwapGroup = pOldSwap->pNext; - } - - /* Check to see if current swap group can now swap since we - * know at this point that pDraw and pMember are guaranteed - * to previously be in different swap groups */ - if (pSwapGroup && SwapGroupIsReadyToSwap(pSwapGroup)) { - SwapSwapGroup(pSwapGroup); - } - - /* Make the old swap entry a standalone group */ - pOldSwap->pNext = NULL; - pOldSwap->barrier = 0; - - /* Reset pWin's swap group */ - pWinPriv->swapGroup = NULL; - pWinPriv->windowDestroyed = NULL; - pWinPriv->windowUnmapped = NULL; - } - - if (!pMember || pMember->type != DRAWABLE_WINDOW) { - /* Free old swap group since it is no longer needed */ - if (pOldSwap) FreeSwapEntry(pOldSwap); - } else if (pDraw == pMember && pOldSwap) { - /* Special case where pDraw was previously created and we - * are now just putting it to its own swap group */ - pWinPriv->swapGroup = pOldSwap; - pWinPriv->windowDestroyed = SGWindowDestroyed; - pWinPriv->windowUnmapped = SGWindowUnmapped; - - /* Check to see if pDraw is ready to swap */ - if (SwapGroupIsReadyToSwap(pOldSwap)) - SwapSwapGroup(pOldSwap); - } else if (pMember->type == DRAWABLE_WINDOW) { - WindowPtr pMemberWin = (WindowPtr)pMember; - dmxWinPrivPtr pMemberPriv = DMX_GET_WINDOW_PRIV(pMemberWin); - SwapGroupPtr pMemberSwapGroup = pMemberPriv->swapGroup; - - /* Finally, how we can add pDraw to pMember's swap group */ - - /* If pMember is not currently in a swap group, then create - * one for it since we are just about to add pDraw to it. */ - if (!pMemberSwapGroup) { - /* Create new swap group */ - pMemberSwapGroup = CreateSwapEntry(pMemberWin); - if (!pMemberSwapGroup) { - if (pOldSwap) FreeSwapEntry(pOldSwap); - return BadAlloc; - } - - /* Set pMember's swap group */ - pMemberPriv->swapGroup = pMemberSwapGroup; - pMemberPriv->windowDestroyed = SGWindowDestroyed; - pMemberPriv->windowUnmapped = SGWindowUnmapped; - } - - /* If pDraw == pMember, that means pDraw was not a member of - * a group previously (or it would have been handled by the - * special case above), so no additional work is required - * since we just created a new swap group for pMember (i.e., - * pDraw). */ - - if (pDraw != pMember) { - /* If pDraw was not previously in a swap group, then create - * an entry for it */ - if (!pOldSwap) { - /* Create new swap group */ - pOldSwap = CreateSwapEntry(pWin); - if (!pOldSwap) { - /* If we just created a swap group for pMember, we - * need to free it here */ - if (pMemberSwapGroup->pNext == NULL) { - FreeSwapEntry(pMemberSwapGroup); - pMemberPriv->swapGroup = NULL; - } - return BadAlloc; - } - } - - /* Find last entry in pMember's swap group */ - for (pEntry = pMemberSwapGroup; - pEntry->pNext; - pEntry = pEntry->pNext); - - /* Add pDraw's swap group entry to pMember's swap group list */ - pEntry->pNext = pOldSwap; - - /* Add pDraw to pMember's swap barrier */ - pOldSwap->barrier = pEntry->barrier; - - /* Set pDraw's swap group */ - pWinPriv->swapGroup = pMemberSwapGroup; - pWinPriv->windowDestroyed = SGWindowDestroyed; - pWinPriv->windowUnmapped = SGWindowUnmapped; - } - } - } - - return Success; -} - - -/************************************************************************ - * - * Swap Barriers - * - ************************************************************************/ - -#define GLX_MAX_SWAP_BARRIERS 10 - -typedef struct _SwapBarrier *SwapBarrierPtr; -typedef struct _SwapBarrier { - SwapGroupPtr pSwap; - SwapBarrierPtr pNext; -} SwapBarrierRec; - -static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS+1]; - -void SwapBarrierInit(void) -{ - int i; - - for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) - SwapBarrierList[i] = NULL; -} - -void SwapBarrierReset(void) -{ - int i; - - for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) { - SwapBarrierPtr pBarrier, pNextBarrier; - for (pBarrier = SwapBarrierList[i]; - pBarrier; - pBarrier = pNextBarrier) { - pNextBarrier = pBarrier->pNext; - xfree(pBarrier); - } - SwapBarrierList[i] = NULL; - } -} - -int QueryMaxSwapBarriersSGIX(int screen) -{ - return GLX_MAX_SWAP_BARRIERS; -} - -static Bool BindSwapGroupToBarrier(GLuint barrier, SwapGroupPtr pSwapGroup) -{ - SwapBarrierPtr pBarrier; - - pBarrier = xalloc(sizeof(*pBarrier)); - if (!pBarrier) return FALSE; - - /* Add the swap group to barrier's list */ - pBarrier->pSwap = pSwapGroup; - pBarrier->pNext = SwapBarrierList[barrier]; - SwapBarrierList[barrier] = pBarrier; - - return TRUE; -} - -static Bool UnbindSwapGroupFromBarrier(GLuint barrier, SwapGroupPtr pSwapGroup) -{ - SwapBarrierPtr pBarrier, pPrevBarrier; - - /* Find the swap group in barrier's list */ - for (pBarrier = SwapBarrierList[barrier], pPrevBarrier = NULL; - pBarrier && pBarrier->pSwap != pSwapGroup; - pPrevBarrier = pBarrier, pBarrier = pBarrier->pNext); - if (!pBarrier) return FALSE; - - /* Remove the swap group from barrier's list */ - if (pPrevBarrier) pPrevBarrier->pNext = pBarrier->pNext; - else SwapBarrierList[barrier] = pBarrier->pNext; - - /* Free memory */ - xfree(pBarrier); - - return TRUE; -} - -static void UpdateSwapBarrierList(GLuint barrier, - SwapGroupPtr pOldSwap, - SwapGroupPtr pNewSwap) -{ - SwapBarrierPtr pBarrier; - - /* If the old swap group is being destroyed, then we need to remove - * the swap group from the list entirely */ - if (!pNewSwap) { - UnbindSwapGroupFromBarrier(barrier, pOldSwap); - return; - } - - /* Otherwise, find the old swap group in the barrier list and change - * it to the new swap group */ - for (pBarrier = SwapBarrierList[barrier]; - pBarrier; - pBarrier = pBarrier->pNext) { - if (pBarrier->pSwap == pOldSwap) { - pBarrier->pSwap = pNewSwap; - return; - } - } -} - -static Bool SwapBarrierIsReadyToSwap(GLuint barrier) -{ - SwapBarrierPtr pBarrier; - Bool isReady = TRUE; - - /* The swap barier is ready to swap when swap groups that are bound - * to barrier are ready to swap */ - for (pBarrier = SwapBarrierList[barrier]; - pBarrier; - pBarrier = pBarrier->pNext) - isReady &= SwapGroupIsReadyToSwap(pBarrier->pSwap); - - return isReady; -} - -static void SwapSwapBarrier(GLuint barrier) -{ - SwapBarrierPtr pBarrier; - - /* Swap each group that is a member of this barrier */ - for (pBarrier = SwapBarrierList[barrier]; - pBarrier; - pBarrier = pBarrier->pNext) - SwapSwapGroup(pBarrier->pSwap); -} - -int BindSwapBarrierSGIX(DrawablePtr pDraw, int barrier) -{ - /* FIXME: Check for errors when pDraw->type != DRAWABLE_WINDOW */ - - if (barrier < 0 || barrier > GLX_MAX_SWAP_BARRIERS) - return BadValue; - - if (pDraw->type == DRAWABLE_WINDOW) { - WindowPtr pWin = (WindowPtr)pDraw; - dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); - SwapGroupPtr pSwapGroup = pWinPriv->swapGroup; - SwapGroupPtr pCur; - - if (!pSwapGroup) return BadDrawable; - if (barrier && pSwapGroup->barrier) return BadValue; - - /* Update the swap barrier list */ - if (barrier) { - if (!BindSwapGroupToBarrier(barrier, pSwapGroup)) - return BadAlloc; - } else { - if (!UnbindSwapGroupFromBarrier(pSwapGroup->barrier, pSwapGroup)) - return BadDrawable; - } - - /* Set the barrier for each member of this swap group */ - for (pCur = pSwapGroup; pCur; pCur = pCur->pNext) - pCur->barrier = barrier; - } - - return Success; -} +/* + * Copyright 2003 Red Hat Inc., Raleigh, 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: + * Kevin E. Martin <kem@redhat.com> + * + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxwindow.h" +#include "glxserver.h" +#include "glxswap.h" + +extern int __glXDoSwapBuffers(__GLXclientState *cl, XID drawId, + GLXContextTag tag); + +typedef struct _SwapGroup *SwapGroupPtr; + +static Bool SwapBarrierIsReadyToSwap(GLuint barrier); +static void SwapSwapBarrier(GLuint barrier); +static void UpdateSwapBarrierList(GLuint barrier, + SwapGroupPtr pOldSwap, + SwapGroupPtr pNewSwap); + + +/************************************************************************ + * + * Swap Groups + * + ************************************************************************/ + +typedef struct _SwapGroup { + WindowPtr pWin; + SwapGroupPtr pNext; + + Bool swapping; + Bool sleeping; + GLuint barrier; + + XID drawable; + GLXContextTag tag; + __GLXclientState *clState; +} SwapGroupRec; + + +static void SwapSwapGroup(SwapGroupPtr pSwap) +{ + SwapGroupPtr pCur; + + /* All drawables in swap group are ready to swap, so just swap all + * drawables buffers and then wake up those clients that were + * previously sleeping */ + + for (pCur = pSwap; pCur; pCur = pCur->pNext) { + if (pCur->swapping) { + /* Swap pCur's buffers */ + __glXDoSwapBuffers(pCur->clState, pCur->drawable, pCur->tag); + pCur->swapping = FALSE; + } + + /* Wakeup client */ + if (pCur->sleeping) { + ClientWakeup(pCur->clState->client); + pCur->sleeping = FALSE; + } + } +} + +static Bool SwapGroupIsReadyToSwap(SwapGroupPtr pSwap) +{ + Bool isReady = TRUE; + + /* The swap group is ready to swap when all drawables are ready to + * swap. NOTE: A drawable is also ready to swap if it is not + * currently mapped */ + for (; pSwap; pSwap = pSwap->pNext) { + isReady &= (pSwap->swapping || !pSwap->pWin->mapped); + /* FIXME: Should we use pSwap->pWin->mapped or ...->realized ??? */ + } + + return isReady; +} + +static Bool SGSwapCleanup(ClientPtr client, pointer closure) +{ + /* SwapGroupPtr pSwap = (SwapGroupPtr)closure; */ + + /* This should not be called unless the client has died in which + * case we should remove the buffer from the swap list */ + + return TRUE; +} + +int SGSwapBuffers(__GLXclientState *cl, XID drawId, GLXContextTag tag, + DrawablePtr pDraw) +{ + WindowPtr pWin = (WindowPtr)pDraw; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + SwapGroupPtr pSwap = pWinPriv->swapGroup; + SwapGroupPtr pCur; + + for (pCur = pSwap; pCur && pCur->pWin != pWin; pCur = pCur->pNext); + if (!pCur) + return BadDrawable; + + pCur->clState = cl; + pCur->drawable = drawId; + pCur->tag = tag; + + /* We are now in the process of swapping */ + pCur->swapping = TRUE; + + if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) { + /* The swap group is bound to a barrier and the barrier is ready + * to swap, so swap all the swap groups that are bound to this + * group's swap barrier */ + SwapSwapBarrier(pSwap->barrier); + } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) { + /* Do the swap if the entire swap group is ready to swap and the + * group is not bound to a swap barrier */ + SwapSwapGroup(pSwap); + } else { + /* The swap group/barrier is not yet ready to swap, so put + * client to sleep until the rest are ready to swap */ + ClientSleep(cl->client, SGSwapCleanup, (pointer)pWin); + pCur->sleeping = TRUE; + } + + return Success; +} + +static void SGWindowUnmapped(WindowPtr pWin) +{ + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + SwapGroupPtr pSwap = pWinPriv->swapGroup; + + /* Now that one of the windows in the swap group has been unmapped, + * see if the entire swap group/barrier is ready to swap */ + + if (pSwap->barrier && SwapBarrierIsReadyToSwap(pSwap->barrier)) { + SwapSwapBarrier(pSwap->barrier); + } else if (!pSwap->barrier && SwapGroupIsReadyToSwap(pSwap)) { + SwapSwapGroup(pSwap); + } +} + +static void SGWindowDestroyed(WindowPtr pWin) +{ + JoinSwapGroupSGIX((DrawablePtr)pWin, NULL); +} + +static SwapGroupPtr CreateSwapEntry(WindowPtr pWin) +{ + SwapGroupPtr pEntry; + + /* Allocate new swap group */ + pEntry = malloc(sizeof(*pEntry)); + if (!pEntry) return NULL; + + /* Initialize swap group */ + pEntry->pWin = pWin; + pEntry->pNext = NULL; + pEntry->swapping = FALSE; + pEntry->sleeping = FALSE; + pEntry->barrier = 0; + /* The following are not initialized until SwapBuffers is called: + * pEntry->drawable + * pEntry->tag + * pEntry->clState + */ + + return pEntry; +} + +static void FreeSwapEntry(SwapGroupPtr pEntry) +{ + /* Since we have removed the drawable from its previous swap group + * and it won't be added to another swap group, the only thing that + * we need to do is to make sure that the drawable's client is not + * sleeping. This could happen if one thread is sleeping, while + * another thread called glxJoinSwapGroup(). Note that all sleeping + * threads should also be swapping, but there is a small window in + * the SGSwapBuffer() logic, above, where swapping can be set but + * sleeping is not. We check both independently here just to be + * pedantic. */ + + /* Handle swap buffer request */ + if (pEntry->swapping) + __glXDoSwapBuffers(pEntry->clState, pEntry->drawable, pEntry->tag); + + /* Wake up client */ + if (pEntry->sleeping) + ClientWakeup(pEntry->clState->client); + + /* We can free the pEntry entry since it has already been removed + * from the swap group list and it won't be needed any longer */ + free(pEntry); +} + +int JoinSwapGroupSGIX(DrawablePtr pDraw, DrawablePtr pMember) +{ + if (pDraw->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDraw; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + SwapGroupPtr pOldSwap = NULL; + SwapGroupPtr pEntry; + + /* If pDraw and pMember are already members of the same swap + * group, just return Success since there is nothing to do */ + for (pEntry = pWinPriv->swapGroup; pEntry; pEntry = pEntry->pNext) + if (pEntry->pWin == (WindowPtr)pMember) + return Success; + + /* Remove pDraw from its current swap group */ + if (pWinPriv->swapGroup) { + SwapGroupPtr pSwapGroup = pWinPriv->swapGroup; + SwapGroupPtr pPrev; + + /* Find old swap entry in swap group and save in pOldSwap + * for later use */ + for (pOldSwap = pWinPriv->swapGroup, pPrev = NULL; + pOldSwap && pOldSwap->pWin != pWin; + pPrev = pOldSwap, pOldSwap = pOldSwap->pNext); + if (!pOldSwap) + return BadDrawable; + + /* Remove pDraw's swap group entry from swap group list */ + if (pPrev) { + pPrev->pNext = pOldSwap->pNext; + } else { + /* pWin is at the head of the swap group list, so we + * need to update all other members of this swap + * group */ + for (pEntry = pOldSwap->pNext; pEntry; pEntry = pEntry->pNext) + DMX_GET_WINDOW_PRIV(pEntry->pWin)->swapGroup + = pOldSwap->pNext; + + /* Update the barrier list as well */ + if (pOldSwap->barrier) + UpdateSwapBarrierList(pOldSwap->barrier, + pOldSwap, pOldSwap->pNext); + + /* Set pSwapGroup to point to the swap group without + * pOldSwap */ + pSwapGroup = pOldSwap->pNext; + } + + /* Check to see if current swap group can now swap since we + * know at this point that pDraw and pMember are guaranteed + * to previously be in different swap groups */ + if (pSwapGroup && SwapGroupIsReadyToSwap(pSwapGroup)) { + SwapSwapGroup(pSwapGroup); + } + + /* Make the old swap entry a standalone group */ + pOldSwap->pNext = NULL; + pOldSwap->barrier = 0; + + /* Reset pWin's swap group */ + pWinPriv->swapGroup = NULL; + pWinPriv->windowDestroyed = NULL; + pWinPriv->windowUnmapped = NULL; + } + + if (!pMember || pMember->type != DRAWABLE_WINDOW) { + /* Free old swap group since it is no longer needed */ + if (pOldSwap) FreeSwapEntry(pOldSwap); + } else if (pDraw == pMember && pOldSwap) { + /* Special case where pDraw was previously created and we + * are now just putting it to its own swap group */ + pWinPriv->swapGroup = pOldSwap; + pWinPriv->windowDestroyed = SGWindowDestroyed; + pWinPriv->windowUnmapped = SGWindowUnmapped; + + /* Check to see if pDraw is ready to swap */ + if (SwapGroupIsReadyToSwap(pOldSwap)) + SwapSwapGroup(pOldSwap); + } else if (pMember->type == DRAWABLE_WINDOW) { + WindowPtr pMemberWin = (WindowPtr)pMember; + dmxWinPrivPtr pMemberPriv = DMX_GET_WINDOW_PRIV(pMemberWin); + SwapGroupPtr pMemberSwapGroup = pMemberPriv->swapGroup; + + /* Finally, how we can add pDraw to pMember's swap group */ + + /* If pMember is not currently in a swap group, then create + * one for it since we are just about to add pDraw to it. */ + if (!pMemberSwapGroup) { + /* Create new swap group */ + pMemberSwapGroup = CreateSwapEntry(pMemberWin); + if (!pMemberSwapGroup) { + if (pOldSwap) FreeSwapEntry(pOldSwap); + return BadAlloc; + } + + /* Set pMember's swap group */ + pMemberPriv->swapGroup = pMemberSwapGroup; + pMemberPriv->windowDestroyed = SGWindowDestroyed; + pMemberPriv->windowUnmapped = SGWindowUnmapped; + } + + /* If pDraw == pMember, that means pDraw was not a member of + * a group previously (or it would have been handled by the + * special case above), so no additional work is required + * since we just created a new swap group for pMember (i.e., + * pDraw). */ + + if (pDraw != pMember) { + /* If pDraw was not previously in a swap group, then create + * an entry for it */ + if (!pOldSwap) { + /* Create new swap group */ + pOldSwap = CreateSwapEntry(pWin); + if (!pOldSwap) { + /* If we just created a swap group for pMember, we + * need to free it here */ + if (pMemberSwapGroup->pNext == NULL) { + FreeSwapEntry(pMemberSwapGroup); + pMemberPriv->swapGroup = NULL; + } + return BadAlloc; + } + } + + /* Find last entry in pMember's swap group */ + for (pEntry = pMemberSwapGroup; + pEntry->pNext; + pEntry = pEntry->pNext); + + /* Add pDraw's swap group entry to pMember's swap group list */ + pEntry->pNext = pOldSwap; + + /* Add pDraw to pMember's swap barrier */ + pOldSwap->barrier = pEntry->barrier; + + /* Set pDraw's swap group */ + pWinPriv->swapGroup = pMemberSwapGroup; + pWinPriv->windowDestroyed = SGWindowDestroyed; + pWinPriv->windowUnmapped = SGWindowUnmapped; + } + } + } + + return Success; +} + + +/************************************************************************ + * + * Swap Barriers + * + ************************************************************************/ + +#define GLX_MAX_SWAP_BARRIERS 10 + +typedef struct _SwapBarrier *SwapBarrierPtr; +typedef struct _SwapBarrier { + SwapGroupPtr pSwap; + SwapBarrierPtr pNext; +} SwapBarrierRec; + +static SwapBarrierPtr SwapBarrierList[GLX_MAX_SWAP_BARRIERS+1]; + +void SwapBarrierInit(void) +{ + int i; + + for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) + SwapBarrierList[i] = NULL; +} + +void SwapBarrierReset(void) +{ + int i; + + for (i = 0; i <= GLX_MAX_SWAP_BARRIERS; i++) { + SwapBarrierPtr pBarrier, pNextBarrier; + for (pBarrier = SwapBarrierList[i]; + pBarrier; + pBarrier = pNextBarrier) { + pNextBarrier = pBarrier->pNext; + free(pBarrier); + } + SwapBarrierList[i] = NULL; + } +} + +int QueryMaxSwapBarriersSGIX(int screen) +{ + return GLX_MAX_SWAP_BARRIERS; +} + +static Bool BindSwapGroupToBarrier(GLuint barrier, SwapGroupPtr pSwapGroup) +{ + SwapBarrierPtr pBarrier; + + pBarrier = malloc(sizeof(*pBarrier)); + if (!pBarrier) return FALSE; + + /* Add the swap group to barrier's list */ + pBarrier->pSwap = pSwapGroup; + pBarrier->pNext = SwapBarrierList[barrier]; + SwapBarrierList[barrier] = pBarrier; + + return TRUE; +} + +static Bool UnbindSwapGroupFromBarrier(GLuint barrier, SwapGroupPtr pSwapGroup) +{ + SwapBarrierPtr pBarrier, pPrevBarrier; + + /* Find the swap group in barrier's list */ + for (pBarrier = SwapBarrierList[barrier], pPrevBarrier = NULL; + pBarrier && pBarrier->pSwap != pSwapGroup; + pPrevBarrier = pBarrier, pBarrier = pBarrier->pNext); + if (!pBarrier) return FALSE; + + /* Remove the swap group from barrier's list */ + if (pPrevBarrier) pPrevBarrier->pNext = pBarrier->pNext; + else SwapBarrierList[barrier] = pBarrier->pNext; + + /* Free memory */ + free(pBarrier); + + return TRUE; +} + +static void UpdateSwapBarrierList(GLuint barrier, + SwapGroupPtr pOldSwap, + SwapGroupPtr pNewSwap) +{ + SwapBarrierPtr pBarrier; + + /* If the old swap group is being destroyed, then we need to remove + * the swap group from the list entirely */ + if (!pNewSwap) { + UnbindSwapGroupFromBarrier(barrier, pOldSwap); + return; + } + + /* Otherwise, find the old swap group in the barrier list and change + * it to the new swap group */ + for (pBarrier = SwapBarrierList[barrier]; + pBarrier; + pBarrier = pBarrier->pNext) { + if (pBarrier->pSwap == pOldSwap) { + pBarrier->pSwap = pNewSwap; + return; + } + } +} + +static Bool SwapBarrierIsReadyToSwap(GLuint barrier) +{ + SwapBarrierPtr pBarrier; + Bool isReady = TRUE; + + /* The swap barier is ready to swap when swap groups that are bound + * to barrier are ready to swap */ + for (pBarrier = SwapBarrierList[barrier]; + pBarrier; + pBarrier = pBarrier->pNext) + isReady &= SwapGroupIsReadyToSwap(pBarrier->pSwap); + + return isReady; +} + +static void SwapSwapBarrier(GLuint barrier) +{ + SwapBarrierPtr pBarrier; + + /* Swap each group that is a member of this barrier */ + for (pBarrier = SwapBarrierList[barrier]; + pBarrier; + pBarrier = pBarrier->pNext) + SwapSwapGroup(pBarrier->pSwap); +} + +int BindSwapBarrierSGIX(DrawablePtr pDraw, int barrier) +{ + /* FIXME: Check for errors when pDraw->type != DRAWABLE_WINDOW */ + + if (barrier < 0 || barrier > GLX_MAX_SWAP_BARRIERS) + return BadValue; + + if (pDraw->type == DRAWABLE_WINDOW) { + WindowPtr pWin = (WindowPtr)pDraw; + dmxWinPrivPtr pWinPriv = DMX_GET_WINDOW_PRIV(pWin); + SwapGroupPtr pSwapGroup = pWinPriv->swapGroup; + SwapGroupPtr pCur; + + if (!pSwapGroup) return BadDrawable; + if (barrier && pSwapGroup->barrier) return BadValue; + + /* Update the swap barrier list */ + if (barrier) { + if (!BindSwapGroupToBarrier(barrier, pSwapGroup)) + return BadAlloc; + } else { + if (!UnbindSwapGroupFromBarrier(pSwapGroup->barrier, pSwapGroup)) + return BadDrawable; + } + + /* Set the barrier for each member of this swap group */ + for (pCur = pSwapGroup; pCur; pCur = pCur->pNext) + pCur->barrier = barrier; + } + + return Success; +} diff --git a/xorg-server/hw/dmx/glxProxy/glxutil.c b/xorg-server/hw/dmx/glxProxy/glxutil.c index d0ce50486..2460ed0dc 100644 --- a/xorg-server/hw/dmx/glxProxy/glxutil.c +++ b/xorg-server/hw/dmx/glxProxy/glxutil.c @@ -1,111 +1,111 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#include "glxserver.h" -#include <GL/glxtokens.h> -#include <pixmapstr.h> -#include <windowstr.h> -#include "glxutil.h" -#include <stdlib.h> - -/************************************************************************/ - -void __glXNop(void) {} - -/************************************************************************/ - -/* Memory Allocation for GLX */ - -void * -__glXMalloc(size_t size) -{ - void *addr; - - if (size == 0) { - return NULL; - } - addr = malloc(size); - if (addr == NULL) { - /* XXX: handle out of memory error */ - return NULL; - } - return addr; -} - -void * -__glXCalloc(size_t numElements, size_t elementSize) -{ - void *addr; - size_t size; - - if ((numElements == 0) || (elementSize == 0)) { - return NULL; - } - addr = calloc(numElements, elementSize); - if (addr == NULL) { - /* XXX: handle out of memory error */ - return NULL; - } - return addr; -} - -void * -__glXRealloc(void *addr, size_t newSize) -{ - void *newAddr; - - if (addr) { - if (newSize == 0) { - xfree(addr); - return NULL; - } else { - newAddr = realloc(addr, newSize); - } - } else { - if (newSize == 0) { - return NULL; - } else { - newAddr = malloc(newSize); - } - } - if (newAddr == NULL) { - return NULL; /* XXX: out of memory */ - } - - return newAddr; -} - -void -__glXFree(void *addr) -{ - if (addr) { - free(addr); - } -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#include "glxserver.h" +#include <GL/glxtokens.h> +#include <pixmapstr.h> +#include <windowstr.h> +#include "glxutil.h" +#include <stdlib.h> + +/************************************************************************/ + +void __glXNop(void) {} + +/************************************************************************/ + +/* Memory Allocation for GLX */ + +void * +__glXMalloc(size_t size) +{ + void *addr; + + if (size == 0) { + return NULL; + } + addr = malloc(size); + if (addr == NULL) { + /* XXX: handle out of memory error */ + return NULL; + } + return addr; +} + +void * +__glXCalloc(size_t numElements, size_t elementSize) +{ + void *addr; + size_t size; + + if ((numElements == 0) || (elementSize == 0)) { + return NULL; + } + addr = calloc(numElements, elementSize); + if (addr == NULL) { + /* XXX: handle out of memory error */ + return NULL; + } + return addr; +} + +void * +__glXRealloc(void *addr, size_t newSize) +{ + void *newAddr; + + if (addr) { + if (newSize == 0) { + free(addr); + return NULL; + } else { + newAddr = realloc(addr, newSize); + } + } else { + if (newSize == 0) { + return NULL; + } else { + newAddr = malloc(newSize); + } + } + if (newAddr == NULL) { + return NULL; /* XXX: out of memory */ + } + + return newAddr; +} + +void +__glXFree(void *addr) +{ + if (addr) { + free(addr); + } +} diff --git a/xorg-server/hw/dmx/glxProxy/glxvendor.c b/xorg-server/hw/dmx/glxProxy/glxvendor.c index 6b1f9a820..e8460fad8 100644 --- a/xorg-server/hw/dmx/glxProxy/glxvendor.c +++ b/xorg-server/hw/dmx/glxProxy/glxvendor.c @@ -1,582 +1,582 @@ -/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED */ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "dmx.h" -#include "dmxwindow.h" -#include "dmxpixmap.h" -#include "dmxfont.h" - -#undef Xmalloc -#undef Xcalloc -#undef Xrealloc -#undef Xfree - -#include "glxserver.h" -#include "glxext.h" -#include "g_disptab.h" -/* #include "g_disptab_EXT.h" */ -#include "unpack.h" -#include "glxutil.h" - -#include "GL/glxproto.h" - -#ifdef PANORAMIX -#include "panoramiXsrv.h" -#endif - -/* - * GetReqVendorPrivate - this is the equivalent of GetReq macro - * from Xlibint.h but it does not set the reqType field (the opcode). - * this is because the GL single opcodes has different naming convension - * the other X opcodes (ie. X_GLsop_GetFloatv). - */ -#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) -#define GetReqVendorPrivate(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x##name##Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ - req->length = (SIZEOF(x##name##Req))>>2;\ - dpy->bufptr += SIZEOF(x##name##Req);\ - dpy->request++ - -#else /* non-ANSI C uses empty comment instead of "##" for token concatenation */ -#define GetReqVendorPrivate(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(x/**/name/**/Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (x/**/name/**/Req *)(dpy->last_req = dpy->bufptr);\ - req->length = (SIZEOF(x/**/name/**/Req))>>2;\ - dpy->bufptr += SIZEOF(x/**/name/**/Req);\ - dpy->request++ -#endif - -extern Display *GetBackEndDisplay( __GLXclientState *cl, int s ); -extern int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s); - -static int swap_vec_element_size = 0; - -static void SendSwappedReply( ClientPtr client, - xGLXVendorPrivReply *reply, - char *buf, - int buf_size ) -{ - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_SWAP_SHORT(&reply->sequenceNumber); - __GLX_SWAP_INT(&reply->length); - __GLX_SWAP_INT(&reply->retval); - __GLX_SWAP_INT(&reply->size); - - if ( (buf_size == 0) && (swap_vec_element_size > 0) ) { - /* - * the reply has single component - need to swap pad3 - */ - if (swap_vec_element_size == 2) { - __GLX_SWAP_SHORT(&reply->pad3); - } - else if (swap_vec_element_size == 4) { - __GLX_SWAP_INT(&reply->pad3); - __GLX_SWAP_INT(&reply->pad4); - } - else if (swap_vec_element_size == 8) { - __GLX_SWAP_DOUBLE(&reply->pad3); - } - } - else if ( (buf_size > 0) && (swap_vec_element_size > 0) ) { - /* - * the reply has vector of elements which needs to be swapped - */ - int vsize = buf_size / swap_vec_element_size; - char *p = buf; - int i; - - for (i=0; i<vsize; i++) { - if (swap_vec_element_size == 2) { - __GLX_SWAP_SHORT(p); - } - else if (swap_vec_element_size == 4) { - __GLX_SWAP_INT(p); - } - else if (swap_vec_element_size == 8) { - __GLX_SWAP_DOUBLE(p); - } - - p += swap_vec_element_size; - } - - __GLX_SWAP_INT(&reply->pad3); - __GLX_SWAP_INT(&reply->pad4); - __GLX_SWAP_INT(&reply->pad5); - __GLX_SWAP_INT(&reply->pad6); - - } - - WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)reply); - if (buf_size > 0) - WriteToClient(client, buf_size, (char *)buf); - -} - -int __glXVForwardSingleReq( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - xGLXVendorPrivateReq *be_req; - __GLXcontext *glxc; - int from_screen = 0; - int to_screen = 0; - int buf_size; - int s; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXVendorPrivateReq; - buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; - - /* - * just forward the request to back-end server(s) - */ - for (s=from_screen; s<=to_screen; s++) { - DMXScreenInfo *dmxScreen = &dmxScreens[s]; - Display *dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReqVendorPrivate(GLXVendorPrivate,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->vendorCode = req->vendorCode; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - UnlockDisplay(dpy); - SyncHandle(); - } - - return Success; -} - -int __glXVForwardPipe0WithReply( __GLXclientState *cl, GLbyte *pc ) -{ - ClientPtr client = cl->client; - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - xGLXVendorPrivateReq *be_req; - xGLXVendorPrivReply reply; - xGLXVendorPrivReply be_reply; - __GLXcontext *glxc; - int buf_size; - char *be_buf; - int be_buf_size; - DMXScreenInfo *dmxScreen; - Display *dpy; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return __glXBadContext; - } - - pc += sz_xGLXVendorPrivateReq; - buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; - - dmxScreen = &dmxScreens[glxc->pScreen->myNum]; - dpy = GetBackEndDisplay(cl, glxc->pScreen->myNum); - - /* - * send the request to the first back-end server - */ - LockDisplay(dpy); - GetReqVendorPrivate(GLXVendorPrivate,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->vendorCode = req->vendorCode; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag, glxc->pScreen->myNum); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - - /* - * get the reply from the back-end server - */ - _XReply(dpy, (xReply*) &be_reply, 0, False); - be_buf_size = be_reply.length << 2; - if (be_buf_size > 0) { - be_buf = (char *)Xalloc( be_buf_size ); - if (be_buf) { - _XRead(dpy, be_buf, be_buf_size); - } - else { - /* Throw data on the floor */ - _XEatData(dpy, be_buf_size); - return BadAlloc; - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - /* - * send the reply to the client - */ - memcpy( &reply, &be_reply, sz_xGLXVendorPrivReply ); - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (client->swapped) { - SendSwappedReply( client, &reply, be_buf, be_buf_size ); - } - else { - WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)&reply); - if (be_buf_size > 0) - WriteToClient(client, be_buf_size, (char *)be_buf); - } - - if (be_buf_size > 0) Xfree(be_buf); - - return Success; -} - -int __glXVForwardAllWithReply( __GLXclientState *cl, GLbyte *pc ) -{ - ClientPtr client = cl->client; - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - xGLXVendorPrivateReq *be_req; - xGLXVendorPrivReply reply; - xGLXVendorPrivReply be_reply; - __GLXcontext *glxc; - int buf_size; - char *be_buf; - int be_buf_size; - int from_screen = 0; - int to_screen = 0; - int s; - - DMXScreenInfo *dmxScreen; - Display *dpy; - - glxc = __glXLookupContextByTag(cl, req->contextTag); - if (!glxc) { - return 0; - } - from_screen = to_screen = glxc->pScreen->myNum; - -#ifdef PANORAMIX - if (!noPanoramiXExtension) { - from_screen = 0; - to_screen = screenInfo.numScreens - 1; - } -#endif - - pc += sz_xGLXVendorPrivateReq; - buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; - - /* - * send the request to the first back-end server(s) - */ - for (s=to_screen; s>=from_screen; s--) { - dmxScreen = &dmxScreens[s]; - dpy = GetBackEndDisplay(cl,s); - - LockDisplay(dpy); - GetReqVendorPrivate(GLXVendorPrivate,be_req); - be_req->reqType = dmxScreen->glxMajorOpcode; - be_req->glxCode = req->glxCode; - be_req->length = req->length; - be_req->vendorCode = req->vendorCode; - be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); - if (buf_size > 0) - _XSend(dpy, (const char *)pc, buf_size); - - /* - * get the reply from the back-end server - */ - _XReply(dpy, (xReply*) &be_reply, 0, False); - be_buf_size = be_reply.length << 2; - if (be_buf_size > 0) { - be_buf = (char *)Xalloc( be_buf_size ); - if (be_buf) { - _XRead(dpy, be_buf, be_buf_size); - } - else { - /* Throw data on the floor */ - _XEatData(dpy, be_buf_size); - return BadAlloc; - } - } - - UnlockDisplay(dpy); - SyncHandle(); - - if (s > from_screen && be_buf_size > 0) { - Xfree(be_buf); - } - } - - /* - * send the reply to the client - */ - memcpy( &reply, &be_reply, sz_xGLXVendorPrivReply ); - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (client->swapped) { - SendSwappedReply( client, &reply, be_buf, be_buf_size ); - } - else { - WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)&reply); - if (be_buf_size > 0) - WriteToClient(client, be_buf_size, (char *)be_buf); - } - - if (be_buf_size > 0) Xfree(be_buf); - - return Success; -} - -int __glXVForwardSingleReqSwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - return( __glXVForwardSingleReq( cl, pc ) ); -} - -int __glXVForwardPipe0WithReplySwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardPipe0WithReply( cl, pc ) ); -} - -int __glXVForwardPipe0WithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 2; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardPipe0WithReply( cl, pc ) ); -} - -int __glXVForwardPipe0WithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 4; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardPipe0WithReply( cl, pc ) ); -} - -int __glXVForwardPipe0WithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 8; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardPipe0WithReply( cl, pc ) ); -} - -int __glXVForwardAllWithReplySwap( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 0; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardAllWithReply( cl, pc ) ); -} - -int __glXVForwardAllWithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 2; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardAllWithReply( cl, pc ) ); -} - -int __glXVForwardAllWithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 4; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardAllWithReply( cl, pc ) ); -} - -int __glXVForwardAllWithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) -{ - xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT(&req->length); - __GLX_SWAP_INT(&req->vendorCode); - __GLX_SWAP_INT(&req->contextTag); - - swap_vec_element_size = 8; - - /* - * swap extra data in request - assuming all data - * (if available) are arrays of 4 bytes components ! - */ - if (req->length > sz_xGLXVendorPrivateReq/4) { - int *data = (int *)(req+1); - int count = req->length - sz_xGLXVendorPrivateReq/4; - __GLX_SWAP_INT_ARRAY(data, count ); - } - - return( __glXVForwardAllWithReply( cl, pc ) ); -} - +/* DO NOT EDIT - THIS FILE IS AUTOMATICALLY GENERATED */ +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "dmx.h" +#include "dmxwindow.h" +#include "dmxpixmap.h" +#include "dmxfont.h" + +#undef Xmalloc +#undef Xcalloc +#undef Xrealloc +#undef Xfree + +#include "glxserver.h" +#include "glxext.h" +#include "g_disptab.h" +/* #include "g_disptab_EXT.h" */ +#include "unpack.h" +#include "glxutil.h" + +#include "GL/glxproto.h" + +#ifdef PANORAMIX +#include "panoramiXsrv.h" +#endif + +/* + * GetReqVendorPrivate - this is the equivalent of GetReq macro + * from Xlibint.h but it does not set the reqType field (the opcode). + * this is because the GL single opcodes has different naming convension + * the other X opcodes (ie. X_GLsop_GetFloatv). + */ +#if (defined(__STDC__) && !defined(UNIXCPP)) || defined(ANSICPP) +#define GetReqVendorPrivate(name, req) \ + WORD64ALIGN\ + if ((dpy->bufptr + SIZEOF(x##name##Req)) > dpy->bufmax)\ + _XFlush(dpy);\ + req = (x##name##Req *)(dpy->last_req = dpy->bufptr);\ + req->length = (SIZEOF(x##name##Req))>>2;\ + dpy->bufptr += SIZEOF(x##name##Req);\ + dpy->request++ + +#else /* non-ANSI C uses empty comment instead of "##" for token concatenation */ +#define GetReqVendorPrivate(name, req) \ + WORD64ALIGN\ + if ((dpy->bufptr + SIZEOF(x/**/name/**/Req)) > dpy->bufmax)\ + _XFlush(dpy);\ + req = (x/**/name/**/Req *)(dpy->last_req = dpy->bufptr);\ + req->length = (SIZEOF(x/**/name/**/Req))>>2;\ + dpy->bufptr += SIZEOF(x/**/name/**/Req);\ + dpy->request++ +#endif + +extern Display *GetBackEndDisplay( __GLXclientState *cl, int s ); +extern int GetCurrentBackEndTag(__GLXclientState *cl, GLXContextTag tag, int s); + +static int swap_vec_element_size = 0; + +static void SendSwappedReply( ClientPtr client, + xGLXVendorPrivReply *reply, + char *buf, + int buf_size ) +{ + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_SWAP_SHORT(&reply->sequenceNumber); + __GLX_SWAP_INT(&reply->length); + __GLX_SWAP_INT(&reply->retval); + __GLX_SWAP_INT(&reply->size); + + if ( (buf_size == 0) && (swap_vec_element_size > 0) ) { + /* + * the reply has single component - need to swap pad3 + */ + if (swap_vec_element_size == 2) { + __GLX_SWAP_SHORT(&reply->pad3); + } + else if (swap_vec_element_size == 4) { + __GLX_SWAP_INT(&reply->pad3); + __GLX_SWAP_INT(&reply->pad4); + } + else if (swap_vec_element_size == 8) { + __GLX_SWAP_DOUBLE(&reply->pad3); + } + } + else if ( (buf_size > 0) && (swap_vec_element_size > 0) ) { + /* + * the reply has vector of elements which needs to be swapped + */ + int vsize = buf_size / swap_vec_element_size; + char *p = buf; + int i; + + for (i=0; i<vsize; i++) { + if (swap_vec_element_size == 2) { + __GLX_SWAP_SHORT(p); + } + else if (swap_vec_element_size == 4) { + __GLX_SWAP_INT(p); + } + else if (swap_vec_element_size == 8) { + __GLX_SWAP_DOUBLE(p); + } + + p += swap_vec_element_size; + } + + __GLX_SWAP_INT(&reply->pad3); + __GLX_SWAP_INT(&reply->pad4); + __GLX_SWAP_INT(&reply->pad5); + __GLX_SWAP_INT(&reply->pad6); + + } + + WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)reply); + if (buf_size > 0) + WriteToClient(client, buf_size, (char *)buf); + +} + +int __glXVForwardSingleReq( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + xGLXVendorPrivateReq *be_req; + __GLXcontext *glxc; + int from_screen = 0; + int to_screen = 0; + int buf_size; + int s; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXVendorPrivateReq; + buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; + + /* + * just forward the request to back-end server(s) + */ + for (s=from_screen; s<=to_screen; s++) { + DMXScreenInfo *dmxScreen = &dmxScreens[s]; + Display *dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReqVendorPrivate(GLXVendorPrivate,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->vendorCode = req->vendorCode; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + UnlockDisplay(dpy); + SyncHandle(); + } + + return Success; +} + +int __glXVForwardPipe0WithReply( __GLXclientState *cl, GLbyte *pc ) +{ + ClientPtr client = cl->client; + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + xGLXVendorPrivateReq *be_req; + xGLXVendorPrivReply reply; + xGLXVendorPrivReply be_reply; + __GLXcontext *glxc; + int buf_size; + char *be_buf; + int be_buf_size; + DMXScreenInfo *dmxScreen; + Display *dpy; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return __glXBadContext; + } + + pc += sz_xGLXVendorPrivateReq; + buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; + + dmxScreen = &dmxScreens[glxc->pScreen->myNum]; + dpy = GetBackEndDisplay(cl, glxc->pScreen->myNum); + + /* + * send the request to the first back-end server + */ + LockDisplay(dpy); + GetReqVendorPrivate(GLXVendorPrivate,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->vendorCode = req->vendorCode; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag, glxc->pScreen->myNum); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + + /* + * get the reply from the back-end server + */ + _XReply(dpy, (xReply*) &be_reply, 0, False); + be_buf_size = be_reply.length << 2; + if (be_buf_size > 0) { + be_buf = (char *)malloc( be_buf_size ); + if (be_buf) { + _XRead(dpy, be_buf, be_buf_size); + } + else { + /* Throw data on the floor */ + _XEatData(dpy, be_buf_size); + return BadAlloc; + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + /* + * send the reply to the client + */ + memcpy( &reply, &be_reply, sz_xGLXVendorPrivReply ); + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + SendSwappedReply( client, &reply, be_buf, be_buf_size ); + } + else { + WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)&reply); + if (be_buf_size > 0) + WriteToClient(client, be_buf_size, (char *)be_buf); + } + + if (be_buf_size > 0) Xfree(be_buf); + + return Success; +} + +int __glXVForwardAllWithReply( __GLXclientState *cl, GLbyte *pc ) +{ + ClientPtr client = cl->client; + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + xGLXVendorPrivateReq *be_req; + xGLXVendorPrivReply reply; + xGLXVendorPrivReply be_reply; + __GLXcontext *glxc; + int buf_size; + char *be_buf; + int be_buf_size; + int from_screen = 0; + int to_screen = 0; + int s; + + DMXScreenInfo *dmxScreen; + Display *dpy; + + glxc = __glXLookupContextByTag(cl, req->contextTag); + if (!glxc) { + return 0; + } + from_screen = to_screen = glxc->pScreen->myNum; + +#ifdef PANORAMIX + if (!noPanoramiXExtension) { + from_screen = 0; + to_screen = screenInfo.numScreens - 1; + } +#endif + + pc += sz_xGLXVendorPrivateReq; + buf_size = (req->length << 2) - sz_xGLXVendorPrivateReq; + + /* + * send the request to the first back-end server(s) + */ + for (s=to_screen; s>=from_screen; s--) { + dmxScreen = &dmxScreens[s]; + dpy = GetBackEndDisplay(cl,s); + + LockDisplay(dpy); + GetReqVendorPrivate(GLXVendorPrivate,be_req); + be_req->reqType = dmxScreen->glxMajorOpcode; + be_req->glxCode = req->glxCode; + be_req->length = req->length; + be_req->vendorCode = req->vendorCode; + be_req->contextTag = GetCurrentBackEndTag(cl,req->contextTag,s); + if (buf_size > 0) + _XSend(dpy, (const char *)pc, buf_size); + + /* + * get the reply from the back-end server + */ + _XReply(dpy, (xReply*) &be_reply, 0, False); + be_buf_size = be_reply.length << 2; + if (be_buf_size > 0) { + be_buf = (char *)malloc( be_buf_size ); + if (be_buf) { + _XRead(dpy, be_buf, be_buf_size); + } + else { + /* Throw data on the floor */ + _XEatData(dpy, be_buf_size); + return BadAlloc; + } + } + + UnlockDisplay(dpy); + SyncHandle(); + + if (s > from_screen && be_buf_size > 0) { + Xfree(be_buf); + } + } + + /* + * send the reply to the client + */ + memcpy( &reply, &be_reply, sz_xGLXVendorPrivReply ); + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + SendSwappedReply( client, &reply, be_buf, be_buf_size ); + } + else { + WriteToClient(client, sizeof(xGLXVendorPrivReply),(char *)&reply); + if (be_buf_size > 0) + WriteToClient(client, be_buf_size, (char *)be_buf); + } + + if (be_buf_size > 0) Xfree(be_buf); + + return Success; +} + +int __glXVForwardSingleReqSwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + return( __glXVForwardSingleReq( cl, pc ) ); +} + +int __glXVForwardPipe0WithReplySwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardPipe0WithReply( cl, pc ) ); +} + +int __glXVForwardPipe0WithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 2; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardPipe0WithReply( cl, pc ) ); +} + +int __glXVForwardPipe0WithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 4; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardPipe0WithReply( cl, pc ) ); +} + +int __glXVForwardPipe0WithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 8; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardPipe0WithReply( cl, pc ) ); +} + +int __glXVForwardAllWithReplySwap( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 0; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardAllWithReply( cl, pc ) ); +} + +int __glXVForwardAllWithReplySwapsv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 2; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardAllWithReply( cl, pc ) ); +} + +int __glXVForwardAllWithReplySwapiv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 4; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardAllWithReply( cl, pc ) ); +} + +int __glXVForwardAllWithReplySwapdv( __GLXclientState *cl, GLbyte *pc ) +{ + xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *)pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT(&req->length); + __GLX_SWAP_INT(&req->vendorCode); + __GLX_SWAP_INT(&req->contextTag); + + swap_vec_element_size = 8; + + /* + * swap extra data in request - assuming all data + * (if available) are arrays of 4 bytes components ! + */ + if (req->length > sz_xGLXVendorPrivateReq/4) { + int *data = (int *)(req+1); + int count = req->length - sz_xGLXVendorPrivateReq/4; + __GLX_SWAP_INT_ARRAY(data, count ); + } + + return( __glXVForwardAllWithReply( cl, pc ) ); +} + diff --git a/xorg-server/hw/dmx/glxProxy/glxvisuals.c b/xorg-server/hw/dmx/glxProxy/glxvisuals.c index 898c6be7b..6e30b4edc 100644 --- a/xorg-server/hw/dmx/glxProxy/glxvisuals.c +++ b/xorg-server/hw/dmx/glxProxy/glxvisuals.c @@ -1,539 +1,539 @@ -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include <assert.h> -#include "dmx.h" -#include "glxserver.h" -#include "glxutil.h" -#include "dmx_glxvisuals.h" -#include <stdlib.h> - -static int numConfigs = 0; -static __GLXvisualConfig *visualConfigs = NULL; -static void **visualPrivates = NULL; - -int glxVisualsMatch( __GLXvisualConfig *v1, __GLXvisualConfig *v2 ) -{ - if ( (v1->class == v2->class) && - (v1->rgba == v2->rgba) && - (v1->redSize == v2->redSize) && - (v1->greenSize == v2->greenSize) && - (v1->blueSize == v2->blueSize) && - (v1->alphaSize == v2->alphaSize) && - (v1->redMask == v2->redMask) && - (v1->greenMask == v2->greenMask) && - (v1->blueMask == v2->blueMask) && - (v1->alphaMask == v2->alphaMask) && - (v1->accumRedSize == v2->accumRedSize) && - (v1->accumGreenSize == v2->accumGreenSize) && - (v1->accumBlueSize == v2->accumBlueSize) && - (v1->accumAlphaSize == v2->accumAlphaSize) && - (v1->doubleBuffer == v2->doubleBuffer) && - (v1->stereo == v2->stereo) && - (v1->bufferSize == v2->bufferSize) && - (v1->depthSize == v2->depthSize) && - (v1->stencilSize == v2->stencilSize) && - (v1->auxBuffers == v2->auxBuffers) && - (v1->level == v2->level) && - (v1->visualRating == v2->visualRating) && - (v1->transparentPixel == v2->transparentPixel) && - (v1->transparentRed == v2->transparentRed) && - (v1->transparentGreen == v2->transparentGreen) && - (v1->transparentBlue == v2->transparentBlue) && - (v1->transparentAlpha == v2->transparentAlpha) && - (v1->transparentIndex == v2->transparentIndex) && - (v1->multiSampleSize == v2->multiSampleSize) && - (v1->nMultiSampleBuffers == v2->nMultiSampleBuffers) && - (v1->visualSelectGroup == v2->visualSelectGroup) ) { - - return(1); - - } - - return(0); - -} - -VisualID glxMatchGLXVisualInConfigList( __GLXvisualConfig *pGlxVisual, __GLXvisualConfig *configs, int nconfigs ) -{ - int i; - - for (i=0; i<nconfigs; i++) { - - if (glxVisualsMatch( pGlxVisual, &configs[i] )) { - - return( configs[i].vid ); - - } - } - - return(0); -} - -VisualID glxMatchVisualInConfigList( ScreenPtr pScreen, VisualPtr pVisual, __GLXvisualConfig *configs, int nconfigs ) -{ - __GLXscreenInfo *pGlxScreen; - __GLXvisualConfig *pGlxVisual; - int i; - - /* check that the glx extension has been initialized */ - if ( !__glXActiveScreens ) - return(0); - - pGlxScreen = &__glXActiveScreens[pScreen->myNum]; - pGlxVisual = pGlxScreen->pGlxVisual; - - /* find the glx visual info for pVisual */ - for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { - if (pGlxVisual->vid == pVisual->vid) { - break; - } - } - if (i == pGlxScreen->numVisuals) { - /* - * the visual is not supported by glx - */ - return(0); - } - - return( glxMatchGLXVisualInConfigList(pGlxVisual, configs, nconfigs) ); -} - -VisualPtr glxMatchVisual( ScreenPtr pScreen, VisualPtr pVisual, ScreenPtr pMatchScreen ) -{ - __GLXscreenInfo *pGlxScreen2; - int j; - VisualID vid; - - /* check that the glx extension has been initialized */ - if ( !__glXActiveScreens ) - return NULL; - - pGlxScreen2 = &__glXActiveScreens[pMatchScreen->myNum]; - - vid = glxMatchVisualInConfigList( pScreen, pVisual, - pGlxScreen2->pGlxVisual, - pGlxScreen2->numVisuals ); - if (vid) { - /* - * find the X visual of the matching glx visual - */ - for (j=0; j<pMatchScreen->numVisuals; j++) { - if (vid == pMatchScreen->visuals[j].vid) { - return( &pMatchScreen->visuals[j] ); - } - } - } - - return(0); -} - -void glxSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, - void **privates) -{ - numConfigs = nconfigs; - visualConfigs = configs; - visualPrivates = privates; -} - -static int count_bits(unsigned int n) -{ - int bits = 0; - - while (n > 0) { - if (n & 1) bits++; - n >>= 1; - } - return bits; -} - -static VisualID FindClosestVisual( VisualPtr pVisual, int rootDepth, - DepthPtr pdepth, int ndepths, - VisualPtr pNewVisual, int numNewVisuals) -{ - int d, v; - VisualPtr vis; - - /* - * find the first visual with the same or deeper depth - * of the same class. - */ - for (d=0; d<ndepths; d++) { - if (pdepth[d].depth >= rootDepth) { - for (v=0; v<pdepth[d].numVids; v++) { - - /* find the new visual structure */ - vis = pNewVisual; - while( pdepth[d].vids[v] != vis->vid ) vis++; - - if (vis->class == pVisual->class) { - return( pdepth[d].vids[v] ); - } - } - } - } - - /* - * did not find any. - * try to look for the same class only. - */ - for (d=0; d<ndepths; d++) { - for (v=0; v<pdepth[d].numVids; v++) { - - /* find the new visual structure */ - vis = pNewVisual; - while( pdepth[d].vids[v] != vis->vid ) vis++; - - if (vis->class == pVisual->class) { - return( pdepth[d].vids[v] ); - } - } - } - - /* - * if not found - just take the first visual - */ - return( pdepth[0].vids[0] ); -} - -Bool glxInitVisuals(int *nvisualp, VisualPtr *visualp, - VisualID *defaultVisp, - int ndepth, DepthPtr pdepth, - int rootDepth) -{ - int numRGBconfigs; - int numCIconfigs; - int numVisuals = *nvisualp; - int numNewVisuals; - int numNewConfigs; - VisualPtr pVisual = *visualp; - VisualPtr pVisualNew = NULL; - VisualID *orig_vid = NULL; - __GLXvisualConfig *glXVisualPtr = NULL; - __GLXvisualConfig *pNewVisualConfigs = NULL; - void **glXVisualPriv; - dmxGlxVisualPrivate **pNewVisualPriv; - int found_default; - int i, j, k; - int numGLXvis = 0; - GLint *isGLXvis; - - if (numConfigs > 0) - numNewConfigs = numConfigs; - else - return False; - - MAXSCREENSALLOC(__glXActiveScreens); - if (!__glXActiveScreens) - return False; - - /* Alloc space for the list of new GLX visuals */ - pNewVisualConfigs = (__GLXvisualConfig *) - __glXMalloc(numNewConfigs * sizeof(__GLXvisualConfig)); - if (!pNewVisualConfigs) { - return FALSE; - } - - /* Alloc space for the list of new GLX visual privates */ - pNewVisualPriv = (dmxGlxVisualPrivate **) __glXMalloc(numNewConfigs * sizeof(dmxGlxVisualPrivate *)); - if (!pNewVisualPriv) { - __glXFree(pNewVisualConfigs); - return FALSE; - } - - /* copy driver's visual config info */ - for (i = 0; i < numConfigs; i++) { - pNewVisualConfigs[i] = visualConfigs[i]; - pNewVisualPriv[i] = (dmxGlxVisualPrivate *)visualPrivates[i]; - } - -#if 1 - /* FIXME: This is a hack to workaround a hang in xtest caused by a - * mismatch between what the front end (i.e., DMX) server calculates - * for the visual configs and what the back-end servers have. - */ - { - int numTCRGBconfigs = 0; - int numDCRGBconfigs = 0; - - numRGBconfigs = 0; - numCIconfigs = 0; - - for (i = 0; i < numNewConfigs; i++) { - if (pNewVisualConfigs[i].rgba) { - if (pNewVisualConfigs[i].class == TrueColor) - numTCRGBconfigs++; - else - numDCRGBconfigs++; - numRGBconfigs++; - } else - numCIconfigs++; - } - - /* Count the total number of visuals to compute */ - numNewVisuals = 0; - for (i = 0; i < numVisuals; i++) { - numNewVisuals += - (pVisual[i].class == TrueColor) ? numTCRGBconfigs : - (pVisual[i].class == DirectColor) ? numDCRGBconfigs : - numCIconfigs; - } - } -#else - /* Count the number of RGB and CI visual configs */ - numRGBconfigs = 0; - numCIconfigs = 0; - for (i = 0; i < numNewConfigs; i++) { - if (pNewVisualConfigs[i].rgba) - numRGBconfigs++; - else - numCIconfigs++; - } - - /* Count the total number of visuals to compute */ - numNewVisuals = 0; - for (i = 0; i < numVisuals; i++) { - numNewVisuals += - (pVisual[i].class == TrueColor || pVisual[i].class == DirectColor) - ? numRGBconfigs : numCIconfigs; - } -#endif - - /* Reset variables for use with the next screen/driver's visual configs */ - visualConfigs = NULL; - numConfigs = 0; - - /* Alloc temp space for the list of orig VisualIDs for each new visual */ - orig_vid = (VisualID *)__glXMalloc(numNewVisuals * sizeof(VisualID)); - if (!orig_vid) { - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - return FALSE; - } - - /* Alloc space for the list of glXVisuals */ - glXVisualPtr = (__GLXvisualConfig *)__glXMalloc(numNewVisuals * - sizeof(__GLXvisualConfig)); - if (!glXVisualPtr) { - __glXFree(orig_vid); - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - return FALSE; - } - - /* Alloc space for the list of glXVisualPrivates */ - glXVisualPriv = (void **)__glXMalloc(numNewVisuals * sizeof(void *)); - if (!glXVisualPriv) { - __glXFree(glXVisualPtr); - __glXFree(orig_vid); - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - return FALSE; - } - - /* Alloc space for the new list of the X server's visuals */ - pVisualNew = (VisualPtr)__glXMalloc(numNewVisuals * sizeof(VisualRec)); - if (!pVisualNew) { - __glXFree(glXVisualPriv); - __glXFree(glXVisualPtr); - __glXFree(orig_vid); - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - return FALSE; - } - - isGLXvis = (GLint *) __glXMalloc(numNewVisuals * sizeof(GLint)); - if (!isGLXvis) { - __glXFree(glXVisualPriv); - __glXFree(glXVisualPtr); - __glXFree(orig_vid); - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - __glXFree(pVisualNew); - return FALSE; - } - - /* Initialize the new visuals */ - found_default = FALSE; - for (i = j = 0; i < numVisuals; i++) { - - for (k = 0; k < numNewConfigs; k++) { - - int new_depth; - int depth; - int d,v; - - /* find the depth of the new visual config */ - new_depth = pNewVisualPriv[k]->x_visual_depth; - - /* find the depth of the original visual */ - depth = 0; - d = 0; - while( (depth==0) && (d < ndepth) ) { - v = 0; - while( (depth==0) && (v < pdepth[d].numVids) ) { - if (pdepth[d].vids[v] == pVisual[i].vid) { - depth = pdepth[d].depth; - } - v++; - } - d++; - } - - /* check that the visual has the same class and depth - * as the new config - */ - if ( pVisual[i].class != pNewVisualPriv[k]->x_visual_class || - (depth != new_depth) ) - continue; - - /* Initialize the new visual */ - pVisualNew[j] = pVisual[i]; - pVisualNew[j].vid = FakeClientID(0); - - /* Check for the default visual */ - if (!found_default && pVisual[i].vid == *defaultVisp) { - *defaultVisp = pVisualNew[j].vid; - found_default = TRUE; - } - - /* Save the old VisualID */ - orig_vid[j] = pVisual[i].vid; - - /* Initialize the glXVisual */ - glXVisualPtr[j] = pNewVisualConfigs[k]; - glXVisualPtr[j].vid = pVisualNew[j].vid; - - /* - * If the class is -1, then assume the X visual information - * is identical to what GLX needs, and take them from the X - * visual. NOTE: if class != -1, then all other fields MUST - * be initialized. - */ - if (glXVisualPtr[j].class == -1) { - glXVisualPtr[j].class = pVisual[i].class; - glXVisualPtr[j].redSize = count_bits(pVisual[i].redMask); - glXVisualPtr[j].greenSize = count_bits(pVisual[i].greenMask); - glXVisualPtr[j].blueSize = count_bits(pVisual[i].blueMask); - glXVisualPtr[j].alphaSize = glXVisualPtr[j].alphaSize; - glXVisualPtr[j].redMask = pVisual[i].redMask; - glXVisualPtr[j].greenMask = pVisual[i].greenMask; - glXVisualPtr[j].blueMask = pVisual[i].blueMask; - glXVisualPtr[j].alphaMask = glXVisualPtr[j].alphaMask; - glXVisualPtr[j].bufferSize = rootDepth; - } - - /* Save the device-dependent private for this visual */ - glXVisualPriv[j] = pNewVisualPriv[k]; - - isGLXvis[j] = glxMatchGLXVisualInConfigList( &glXVisualPtr[j], - dmxScreens[screenInfo.numScreens-1].glxVisuals, - dmxScreens[screenInfo.numScreens-1].numGlxVisuals ); - if (isGLXvis[j]) numGLXvis++; - - j++; - } - } - - assert(j <= numNewVisuals); - numNewVisuals = j; /* correct number of new visuals */ - - /* Save the GLX visuals in the screen structure */ - __glXActiveScreens[screenInfo.numScreens-1].numVisuals = numNewVisuals; - __glXActiveScreens[screenInfo.numScreens-1].numGLXVisuals = numGLXvis; - __glXActiveScreens[screenInfo.numScreens-1].isGLXvis = isGLXvis; - __glXActiveScreens[screenInfo.numScreens-1].pGlxVisual = glXVisualPtr; - - - /* Set up depth's VisualIDs */ - for (i = 0; i < ndepth; i++) { - int numVids = 0; - VisualID *pVids = NULL; - int k, n = 0; - - /* Count the new number of VisualIDs at this depth */ - for (j = 0; j < pdepth[i].numVids; j++) - for (k = 0; k < numNewVisuals; k++) - if (pdepth[i].vids[j] == orig_vid[k]) - numVids++; - - /* Allocate a new list of VisualIDs for this depth */ - pVids = (VisualID *)__glXMalloc(numVids * sizeof(VisualID)); - - /* Initialize the new list of VisualIDs for this depth */ - for (j = 0; j < pdepth[i].numVids; j++) - for (k = 0; k < numNewVisuals; k++) - if (pdepth[i].vids[j] == orig_vid[k]) - pVids[n++] = pVisualNew[k].vid; - - /* Update this depth's list of VisualIDs */ - __glXFree(pdepth[i].vids); - pdepth[i].vids = pVids; - pdepth[i].numVids = numVids; - } - - /* - * if the default visual was rejected - need to choose new - * default visual ! - */ - if ( !found_default ) { - - for (i=0; i<numVisuals; i++) - if (pVisual[i].vid == *defaultVisp) - break; - - if (i < numVisuals) { - *defaultVisp = FindClosestVisual( &pVisual[i], rootDepth, pdepth, ndepth, pVisualNew, numNewVisuals ); - } - } - - /* Update the X server's visuals */ - *nvisualp = numNewVisuals; - *visualp = pVisualNew; - - /* Free the old list of the X server's visuals */ - __glXFree(pVisual); - - /* Clean up temporary allocations */ - __glXFree(orig_vid); - __glXFree(pNewVisualPriv); - __glXFree(pNewVisualConfigs); - - /* Free the private list created by DDX HW driver */ - if (visualPrivates) - xfree(visualPrivates); - visualPrivates = NULL; - - return TRUE; -} +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include <assert.h> +#include "dmx.h" +#include "glxserver.h" +#include "glxutil.h" +#include "dmx_glxvisuals.h" +#include <stdlib.h> + +static int numConfigs = 0; +static __GLXvisualConfig *visualConfigs = NULL; +static void **visualPrivates = NULL; + +int glxVisualsMatch( __GLXvisualConfig *v1, __GLXvisualConfig *v2 ) +{ + if ( (v1->class == v2->class) && + (v1->rgba == v2->rgba) && + (v1->redSize == v2->redSize) && + (v1->greenSize == v2->greenSize) && + (v1->blueSize == v2->blueSize) && + (v1->alphaSize == v2->alphaSize) && + (v1->redMask == v2->redMask) && + (v1->greenMask == v2->greenMask) && + (v1->blueMask == v2->blueMask) && + (v1->alphaMask == v2->alphaMask) && + (v1->accumRedSize == v2->accumRedSize) && + (v1->accumGreenSize == v2->accumGreenSize) && + (v1->accumBlueSize == v2->accumBlueSize) && + (v1->accumAlphaSize == v2->accumAlphaSize) && + (v1->doubleBuffer == v2->doubleBuffer) && + (v1->stereo == v2->stereo) && + (v1->bufferSize == v2->bufferSize) && + (v1->depthSize == v2->depthSize) && + (v1->stencilSize == v2->stencilSize) && + (v1->auxBuffers == v2->auxBuffers) && + (v1->level == v2->level) && + (v1->visualRating == v2->visualRating) && + (v1->transparentPixel == v2->transparentPixel) && + (v1->transparentRed == v2->transparentRed) && + (v1->transparentGreen == v2->transparentGreen) && + (v1->transparentBlue == v2->transparentBlue) && + (v1->transparentAlpha == v2->transparentAlpha) && + (v1->transparentIndex == v2->transparentIndex) && + (v1->multiSampleSize == v2->multiSampleSize) && + (v1->nMultiSampleBuffers == v2->nMultiSampleBuffers) && + (v1->visualSelectGroup == v2->visualSelectGroup) ) { + + return(1); + + } + + return(0); + +} + +VisualID glxMatchGLXVisualInConfigList( __GLXvisualConfig *pGlxVisual, __GLXvisualConfig *configs, int nconfigs ) +{ + int i; + + for (i=0; i<nconfigs; i++) { + + if (glxVisualsMatch( pGlxVisual, &configs[i] )) { + + return( configs[i].vid ); + + } + } + + return(0); +} + +VisualID glxMatchVisualInConfigList( ScreenPtr pScreen, VisualPtr pVisual, __GLXvisualConfig *configs, int nconfigs ) +{ + __GLXscreenInfo *pGlxScreen; + __GLXvisualConfig *pGlxVisual; + int i; + + /* check that the glx extension has been initialized */ + if ( !__glXActiveScreens ) + return(0); + + pGlxScreen = &__glXActiveScreens[pScreen->myNum]; + pGlxVisual = pGlxScreen->pGlxVisual; + + /* find the glx visual info for pVisual */ + for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { + if (pGlxVisual->vid == pVisual->vid) { + break; + } + } + if (i == pGlxScreen->numVisuals) { + /* + * the visual is not supported by glx + */ + return(0); + } + + return( glxMatchGLXVisualInConfigList(pGlxVisual, configs, nconfigs) ); +} + +VisualPtr glxMatchVisual( ScreenPtr pScreen, VisualPtr pVisual, ScreenPtr pMatchScreen ) +{ + __GLXscreenInfo *pGlxScreen2; + int j; + VisualID vid; + + /* check that the glx extension has been initialized */ + if ( !__glXActiveScreens ) + return NULL; + + pGlxScreen2 = &__glXActiveScreens[pMatchScreen->myNum]; + + vid = glxMatchVisualInConfigList( pScreen, pVisual, + pGlxScreen2->pGlxVisual, + pGlxScreen2->numVisuals ); + if (vid) { + /* + * find the X visual of the matching glx visual + */ + for (j=0; j<pMatchScreen->numVisuals; j++) { + if (vid == pMatchScreen->visuals[j].vid) { + return( &pMatchScreen->visuals[j] ); + } + } + } + + return(0); +} + +void glxSetVisualConfigs(int nconfigs, __GLXvisualConfig *configs, + void **privates) +{ + numConfigs = nconfigs; + visualConfigs = configs; + visualPrivates = privates; +} + +static int count_bits(unsigned int n) +{ + int bits = 0; + + while (n > 0) { + if (n & 1) bits++; + n >>= 1; + } + return bits; +} + +static VisualID FindClosestVisual( VisualPtr pVisual, int rootDepth, + DepthPtr pdepth, int ndepths, + VisualPtr pNewVisual, int numNewVisuals) +{ + int d, v; + VisualPtr vis; + + /* + * find the first visual with the same or deeper depth + * of the same class. + */ + for (d=0; d<ndepths; d++) { + if (pdepth[d].depth >= rootDepth) { + for (v=0; v<pdepth[d].numVids; v++) { + + /* find the new visual structure */ + vis = pNewVisual; + while( pdepth[d].vids[v] != vis->vid ) vis++; + + if (vis->class == pVisual->class) { + return( pdepth[d].vids[v] ); + } + } + } + } + + /* + * did not find any. + * try to look for the same class only. + */ + for (d=0; d<ndepths; d++) { + for (v=0; v<pdepth[d].numVids; v++) { + + /* find the new visual structure */ + vis = pNewVisual; + while( pdepth[d].vids[v] != vis->vid ) vis++; + + if (vis->class == pVisual->class) { + return( pdepth[d].vids[v] ); + } + } + } + + /* + * if not found - just take the first visual + */ + return( pdepth[0].vids[0] ); +} + +Bool glxInitVisuals(int *nvisualp, VisualPtr *visualp, + VisualID *defaultVisp, + int ndepth, DepthPtr pdepth, + int rootDepth) +{ + int numRGBconfigs; + int numCIconfigs; + int numVisuals = *nvisualp; + int numNewVisuals; + int numNewConfigs; + VisualPtr pVisual = *visualp; + VisualPtr pVisualNew = NULL; + VisualID *orig_vid = NULL; + __GLXvisualConfig *glXVisualPtr = NULL; + __GLXvisualConfig *pNewVisualConfigs = NULL; + void **glXVisualPriv; + dmxGlxVisualPrivate **pNewVisualPriv; + int found_default; + int i, j, k; + int numGLXvis = 0; + GLint *isGLXvis; + + if (numConfigs > 0) + numNewConfigs = numConfigs; + else + return False; + + MAXSCREENSALLOC(__glXActiveScreens); + if (!__glXActiveScreens) + return False; + + /* Alloc space for the list of new GLX visuals */ + pNewVisualConfigs = (__GLXvisualConfig *) + __glXMalloc(numNewConfigs * sizeof(__GLXvisualConfig)); + if (!pNewVisualConfigs) { + return FALSE; + } + + /* Alloc space for the list of new GLX visual privates */ + pNewVisualPriv = (dmxGlxVisualPrivate **) __glXMalloc(numNewConfigs * sizeof(dmxGlxVisualPrivate *)); + if (!pNewVisualPriv) { + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* copy driver's visual config info */ + for (i = 0; i < numConfigs; i++) { + pNewVisualConfigs[i] = visualConfigs[i]; + pNewVisualPriv[i] = (dmxGlxVisualPrivate *)visualPrivates[i]; + } + +#if 1 + /* FIXME: This is a hack to workaround a hang in xtest caused by a + * mismatch between what the front end (i.e., DMX) server calculates + * for the visual configs and what the back-end servers have. + */ + { + int numTCRGBconfigs = 0; + int numDCRGBconfigs = 0; + + numRGBconfigs = 0; + numCIconfigs = 0; + + for (i = 0; i < numNewConfigs; i++) { + if (pNewVisualConfigs[i].rgba) { + if (pNewVisualConfigs[i].class == TrueColor) + numTCRGBconfigs++; + else + numDCRGBconfigs++; + numRGBconfigs++; + } else + numCIconfigs++; + } + + /* Count the total number of visuals to compute */ + numNewVisuals = 0; + for (i = 0; i < numVisuals; i++) { + numNewVisuals += + (pVisual[i].class == TrueColor) ? numTCRGBconfigs : + (pVisual[i].class == DirectColor) ? numDCRGBconfigs : + numCIconfigs; + } + } +#else + /* Count the number of RGB and CI visual configs */ + numRGBconfigs = 0; + numCIconfigs = 0; + for (i = 0; i < numNewConfigs; i++) { + if (pNewVisualConfigs[i].rgba) + numRGBconfigs++; + else + numCIconfigs++; + } + + /* Count the total number of visuals to compute */ + numNewVisuals = 0; + for (i = 0; i < numVisuals; i++) { + numNewVisuals += + (pVisual[i].class == TrueColor || pVisual[i].class == DirectColor) + ? numRGBconfigs : numCIconfigs; + } +#endif + + /* Reset variables for use with the next screen/driver's visual configs */ + visualConfigs = NULL; + numConfigs = 0; + + /* Alloc temp space for the list of orig VisualIDs for each new visual */ + orig_vid = (VisualID *)__glXMalloc(numNewVisuals * sizeof(VisualID)); + if (!orig_vid) { + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the list of glXVisuals */ + glXVisualPtr = (__GLXvisualConfig *)__glXMalloc(numNewVisuals * + sizeof(__GLXvisualConfig)); + if (!glXVisualPtr) { + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the list of glXVisualPrivates */ + glXVisualPriv = (void **)__glXMalloc(numNewVisuals * sizeof(void *)); + if (!glXVisualPriv) { + __glXFree(glXVisualPtr); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + /* Alloc space for the new list of the X server's visuals */ + pVisualNew = (VisualPtr)__glXMalloc(numNewVisuals * sizeof(VisualRec)); + if (!pVisualNew) { + __glXFree(glXVisualPriv); + __glXFree(glXVisualPtr); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + return FALSE; + } + + isGLXvis = (GLint *) __glXMalloc(numNewVisuals * sizeof(GLint)); + if (!isGLXvis) { + __glXFree(glXVisualPriv); + __glXFree(glXVisualPtr); + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + __glXFree(pVisualNew); + return FALSE; + } + + /* Initialize the new visuals */ + found_default = FALSE; + for (i = j = 0; i < numVisuals; i++) { + + for (k = 0; k < numNewConfigs; k++) { + + int new_depth; + int depth; + int d,v; + + /* find the depth of the new visual config */ + new_depth = pNewVisualPriv[k]->x_visual_depth; + + /* find the depth of the original visual */ + depth = 0; + d = 0; + while( (depth==0) && (d < ndepth) ) { + v = 0; + while( (depth==0) && (v < pdepth[d].numVids) ) { + if (pdepth[d].vids[v] == pVisual[i].vid) { + depth = pdepth[d].depth; + } + v++; + } + d++; + } + + /* check that the visual has the same class and depth + * as the new config + */ + if ( pVisual[i].class != pNewVisualPriv[k]->x_visual_class || + (depth != new_depth) ) + continue; + + /* Initialize the new visual */ + pVisualNew[j] = pVisual[i]; + pVisualNew[j].vid = FakeClientID(0); + + /* Check for the default visual */ + if (!found_default && pVisual[i].vid == *defaultVisp) { + *defaultVisp = pVisualNew[j].vid; + found_default = TRUE; + } + + /* Save the old VisualID */ + orig_vid[j] = pVisual[i].vid; + + /* Initialize the glXVisual */ + glXVisualPtr[j] = pNewVisualConfigs[k]; + glXVisualPtr[j].vid = pVisualNew[j].vid; + + /* + * If the class is -1, then assume the X visual information + * is identical to what GLX needs, and take them from the X + * visual. NOTE: if class != -1, then all other fields MUST + * be initialized. + */ + if (glXVisualPtr[j].class == -1) { + glXVisualPtr[j].class = pVisual[i].class; + glXVisualPtr[j].redSize = count_bits(pVisual[i].redMask); + glXVisualPtr[j].greenSize = count_bits(pVisual[i].greenMask); + glXVisualPtr[j].blueSize = count_bits(pVisual[i].blueMask); + glXVisualPtr[j].alphaSize = glXVisualPtr[j].alphaSize; + glXVisualPtr[j].redMask = pVisual[i].redMask; + glXVisualPtr[j].greenMask = pVisual[i].greenMask; + glXVisualPtr[j].blueMask = pVisual[i].blueMask; + glXVisualPtr[j].alphaMask = glXVisualPtr[j].alphaMask; + glXVisualPtr[j].bufferSize = rootDepth; + } + + /* Save the device-dependent private for this visual */ + glXVisualPriv[j] = pNewVisualPriv[k]; + + isGLXvis[j] = glxMatchGLXVisualInConfigList( &glXVisualPtr[j], + dmxScreens[screenInfo.numScreens-1].glxVisuals, + dmxScreens[screenInfo.numScreens-1].numGlxVisuals ); + if (isGLXvis[j]) numGLXvis++; + + j++; + } + } + + assert(j <= numNewVisuals); + numNewVisuals = j; /* correct number of new visuals */ + + /* Save the GLX visuals in the screen structure */ + __glXActiveScreens[screenInfo.numScreens-1].numVisuals = numNewVisuals; + __glXActiveScreens[screenInfo.numScreens-1].numGLXVisuals = numGLXvis; + __glXActiveScreens[screenInfo.numScreens-1].isGLXvis = isGLXvis; + __glXActiveScreens[screenInfo.numScreens-1].pGlxVisual = glXVisualPtr; + + + /* Set up depth's VisualIDs */ + for (i = 0; i < ndepth; i++) { + int numVids = 0; + VisualID *pVids = NULL; + int k, n = 0; + + /* Count the new number of VisualIDs at this depth */ + for (j = 0; j < pdepth[i].numVids; j++) + for (k = 0; k < numNewVisuals; k++) + if (pdepth[i].vids[j] == orig_vid[k]) + numVids++; + + /* Allocate a new list of VisualIDs for this depth */ + pVids = (VisualID *)__glXMalloc(numVids * sizeof(VisualID)); + + /* Initialize the new list of VisualIDs for this depth */ + for (j = 0; j < pdepth[i].numVids; j++) + for (k = 0; k < numNewVisuals; k++) + if (pdepth[i].vids[j] == orig_vid[k]) + pVids[n++] = pVisualNew[k].vid; + + /* Update this depth's list of VisualIDs */ + __glXFree(pdepth[i].vids); + pdepth[i].vids = pVids; + pdepth[i].numVids = numVids; + } + + /* + * if the default visual was rejected - need to choose new + * default visual ! + */ + if ( !found_default ) { + + for (i=0; i<numVisuals; i++) + if (pVisual[i].vid == *defaultVisp) + break; + + if (i < numVisuals) { + *defaultVisp = FindClosestVisual( &pVisual[i], rootDepth, pdepth, ndepth, pVisualNew, numNewVisuals ); + } + } + + /* Update the X server's visuals */ + *nvisualp = numNewVisuals; + *visualp = pVisualNew; + + /* Free the old list of the X server's visuals */ + __glXFree(pVisual); + + /* Clean up temporary allocations */ + __glXFree(orig_vid); + __glXFree(pNewVisualPriv); + __glXFree(pNewVisualConfigs); + + /* Free the private list created by DDX HW driver */ + if (visualPrivates) + free(visualPrivates); + visualPrivates = NULL; + + return TRUE; +} diff --git a/xorg-server/hw/dmx/glxProxy/unpack.h b/xorg-server/hw/dmx/glxProxy/unpack.h index 98fa10ee7..73d0485e3 100644 --- a/xorg-server/hw/dmx/glxProxy/unpack.h +++ b/xorg-server/hw/dmx/glxProxy/unpack.h @@ -1,228 +1,228 @@ -#ifndef __GLX_unpack_h__ -#define __GLX_unpack_h__ - -/* - * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) - * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and - * either this permission notice or a reference to - * http://oss.sgi.com/projects/FreeB/ - * 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 - * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. - * shall not be used in advertising or otherwise to promote the sale, use or - * other dealings in this Software without prior written authorization from - * Silicon Graphics, Inc. - */ - -#define __GLX_PAD(s) (((s)+3) & (GLuint)~3) - -/* -** Fetch the context-id out of a SingleReq request pointed to by pc. -*/ -#define __GLX_GET_SINGLE_CONTEXT_TAG(pc) (((xGLXSingleReq*)pc)->contextTag) -#define __GLX_GET_VENDPRIV_CONTEXT_TAG(pc) (((xGLXVendorPrivateReq*)pc)->contextTag) - -/* -** Fetch a double from potentially unaligned memory. -*/ -#ifdef __GLX_ALIGN64 -#define __GLX_MEM_COPY(dst,src,n) memcpy(dst,src,n) -#define __GLX_GET_DOUBLE(dst,src) __GLX_MEM_COPY(&dst,src,8) -#else -#define __GLX_GET_DOUBLE(dst,src) (dst) = *((GLdouble*)(src)) -#endif - -extern void __glXMemInit(void); - -extern xGLXSingleReply __glXReply; - -#define __GLX_BEGIN_REPLY(size) \ - __glXReply.length = __GLX_PAD(size) >> 2; \ - __glXReply.type = X_Reply; \ - __glXReply.sequenceNumber = client->sequence; - -#define __GLX_SEND_HEADER() \ - WriteToClient( client, sz_xGLXSingleReply, (char *)&__glXReply); - -#define __GLX_PUT_RETVAL(a) \ - __glXReply.retval = (a); - -#define __GLX_PUT_SIZE(a) \ - __glXReply.size = (a); - -#define __GLX_PUT_RENDERMODE(m) \ - __glXReply.pad3 = (m) - -/* -** Get a buffer to hold returned data, with the given alignment. If we have -** to realloc, allocate size+align, in case the pointer has to be bumped for -** alignment. The answerBuffer should already be aligned. -** -** NOTE: the cast (long)res below assumes a long is large enough to hold a -** pointer. -*/ -#define __GLX_GET_ANSWER_BUFFER(res,cl,size,align) \ - if ((size) > sizeof(answerBuffer)) { \ - int bump; \ - if ((cl)->returnBufSize < (size)+(align)) { \ - (cl)->returnBuf = (GLbyte*)Xrealloc((cl)->returnBuf, \ - (size)+(align)); \ - if (!(cl)->returnBuf) { \ - return BadAlloc; \ - } \ - (cl)->returnBufSize = (size)+(align); \ - } \ - res = (char*)cl->returnBuf; \ - bump = (long)(res) % (align); \ - if (bump) res += (align) - (bump); \ - } else { \ - res = (char *)answerBuffer; \ - } - -#define __GLX_PUT_BYTE() \ - *(GLbyte *)&__glXReply.pad3 = *(GLbyte *)answer - -#define __GLX_PUT_SHORT() \ - *(GLshort *)&__glXReply.pad3 = *(GLshort *)answer - -#define __GLX_PUT_INT() \ - *(GLint *)&__glXReply.pad3 = *(GLint *)answer - -#define __GLX_PUT_FLOAT() \ - *(GLfloat *)&__glXReply.pad3 = *(GLfloat *)answer - -#define __GLX_PUT_DOUBLE() \ - *(GLdouble *)&__glXReply.pad3 = *(GLdouble *)answer - -#define __GLX_SEND_BYTE_ARRAY(len) \ - WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT8), (char *)answer) - -#define __GLX_SEND_SHORT_ARRAY(len) \ - WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT16), (char *)answer) - -#define __GLX_SEND_INT_ARRAY(len) \ - WriteToClient(client, (len)*__GLX_SIZE_INT32, (char *)answer) - -#define __GLX_SEND_FLOAT_ARRAY(len) \ - WriteToClient(client, (len)*__GLX_SIZE_FLOAT32, (char *)answer) - -#define __GLX_SEND_DOUBLE_ARRAY(len) \ - WriteToClient(client, (len)*__GLX_SIZE_FLOAT64, (char *)answer) - - -#define __GLX_SEND_VOID_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) -#define __GLX_SEND_UBYTE_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) -#define __GLX_SEND_USHORT_ARRAY(len) __GLX_SEND_SHORT_ARRAY(len) -#define __GLX_SEND_UINT_ARRAY(len) __GLX_SEND_INT_ARRAY(len) - -/* -** PERFORMANCE NOTE: -** Machine dependent optimizations abound here; these swapping macros can -** conceivably be replaced with routines that do the job faster. -*/ -#define __GLX_DECLARE_SWAP_VARIABLES \ - GLbyte sw; \ - GLbyte *swapPC; \ - GLbyte *swapEnd - - -#define __GLX_SWAP_INT(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ - ((GLbyte *)(pc))[3] = sw; \ - sw = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ - ((GLbyte *)(pc))[2] = sw; - -#define __GLX_SWAP_SHORT(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = sw; - -#define __GLX_SWAP_DOUBLE(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[7]; \ - ((GLbyte *)(pc))[7] = sw; \ - sw = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[6]; \ - ((GLbyte *)(pc))[6] = sw; \ - sw = ((GLbyte *)(pc))[2]; \ - ((GLbyte *)(pc))[2] = ((GLbyte *)(pc))[5]; \ - ((GLbyte *)(pc))[5] = sw; \ - sw = ((GLbyte *)(pc))[3]; \ - ((GLbyte *)(pc))[3] = ((GLbyte *)(pc))[4]; \ - ((GLbyte *)(pc))[4] = sw; - -#define __GLX_SWAP_FLOAT(pc) \ - sw = ((GLbyte *)(pc))[0]; \ - ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ - ((GLbyte *)(pc))[3] = sw; \ - sw = ((GLbyte *)(pc))[1]; \ - ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ - ((GLbyte *)(pc))[2] = sw; - -#define __GLX_SWAP_INT_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT32;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_INT(swapPC); \ - swapPC += __GLX_SIZE_INT32; \ - } - -#define __GLX_SWAP_SHORT_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT16;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_SHORT(swapPC); \ - swapPC += __GLX_SIZE_INT16; \ - } - -#define __GLX_SWAP_DOUBLE_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT64;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_DOUBLE(swapPC); \ - swapPC += __GLX_SIZE_FLOAT64; \ - } - -#define __GLX_SWAP_FLOAT_ARRAY(pc, count) \ - swapPC = ((GLbyte *)(pc)); \ - swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT32;\ - while (swapPC < swapEnd) { \ - __GLX_SWAP_FLOAT(swapPC); \ - swapPC += __GLX_SIZE_FLOAT32; \ - } - -#define __GLX_SWAP_REPLY_HEADER() \ - __GLX_SWAP_SHORT(&__glXReply.sequenceNumber); \ - __GLX_SWAP_INT(&__glXReply.length); - -#define __GLX_SWAP_REPLY_RETVAL() \ - __GLX_SWAP_INT(&__glXReply.retval) - -#define __GLX_SWAP_REPLY_SIZE() \ - __GLX_SWAP_INT(&__glXReply.size) - -#endif /* !__GLX_unpack_h__ */ - - - - - +#ifndef __GLX_unpack_h__ +#define __GLX_unpack_h__ + +/* + * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) + * Copyright (C) 1991-2000 Silicon Graphics, Inc. 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 including the dates of first publication and + * either this permission notice or a reference to + * http://oss.sgi.com/projects/FreeB/ + * 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 + * SILICON GRAPHICS, INC. 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 Silicon Graphics, Inc. + * shall not be used in advertising or otherwise to promote the sale, use or + * other dealings in this Software without prior written authorization from + * Silicon Graphics, Inc. + */ + +#define __GLX_PAD(s) (((s)+3) & (GLuint)~3) + +/* +** Fetch the context-id out of a SingleReq request pointed to by pc. +*/ +#define __GLX_GET_SINGLE_CONTEXT_TAG(pc) (((xGLXSingleReq*)pc)->contextTag) +#define __GLX_GET_VENDPRIV_CONTEXT_TAG(pc) (((xGLXVendorPrivateReq*)pc)->contextTag) + +/* +** Fetch a double from potentially unaligned memory. +*/ +#ifdef __GLX_ALIGN64 +#define __GLX_MEM_COPY(dst,src,n) memcpy(dst,src,n) +#define __GLX_GET_DOUBLE(dst,src) __GLX_MEM_COPY(&dst,src,8) +#else +#define __GLX_GET_DOUBLE(dst,src) (dst) = *((GLdouble*)(src)) +#endif + +extern void __glXMemInit(void); + +extern xGLXSingleReply __glXReply; + +#define __GLX_BEGIN_REPLY(size) \ + __glXReply.length = __GLX_PAD(size) >> 2; \ + __glXReply.type = X_Reply; \ + __glXReply.sequenceNumber = client->sequence; + +#define __GLX_SEND_HEADER() \ + WriteToClient( client, sz_xGLXSingleReply, (char *)&__glXReply); + +#define __GLX_PUT_RETVAL(a) \ + __glXReply.retval = (a); + +#define __GLX_PUT_SIZE(a) \ + __glXReply.size = (a); + +#define __GLX_PUT_RENDERMODE(m) \ + __glXReply.pad3 = (m) + +/* +** Get a buffer to hold returned data, with the given alignment. If we have +** to realloc, allocate size+align, in case the pointer has to be bumped for +** alignment. The answerBuffer should already be aligned. +** +** NOTE: the cast (long)res below assumes a long is large enough to hold a +** pointer. +*/ +#define __GLX_GET_ANSWER_BUFFER(res,cl,size,align) \ + if ((size) > sizeof(answerBuffer)) { \ + int bump; \ + if ((cl)->returnBufSize < (size)+(align)) { \ + (cl)->returnBuf = (GLbyte*)realloc((cl)->returnBuf, \ + (size)+(align)); \ + if (!(cl)->returnBuf) { \ + return BadAlloc; \ + } \ + (cl)->returnBufSize = (size)+(align); \ + } \ + res = (char*)cl->returnBuf; \ + bump = (long)(res) % (align); \ + if (bump) res += (align) - (bump); \ + } else { \ + res = (char *)answerBuffer; \ + } + +#define __GLX_PUT_BYTE() \ + *(GLbyte *)&__glXReply.pad3 = *(GLbyte *)answer + +#define __GLX_PUT_SHORT() \ + *(GLshort *)&__glXReply.pad3 = *(GLshort *)answer + +#define __GLX_PUT_INT() \ + *(GLint *)&__glXReply.pad3 = *(GLint *)answer + +#define __GLX_PUT_FLOAT() \ + *(GLfloat *)&__glXReply.pad3 = *(GLfloat *)answer + +#define __GLX_PUT_DOUBLE() \ + *(GLdouble *)&__glXReply.pad3 = *(GLdouble *)answer + +#define __GLX_SEND_BYTE_ARRAY(len) \ + WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT8), (char *)answer) + +#define __GLX_SEND_SHORT_ARRAY(len) \ + WriteToClient(client, __GLX_PAD((len)*__GLX_SIZE_INT16), (char *)answer) + +#define __GLX_SEND_INT_ARRAY(len) \ + WriteToClient(client, (len)*__GLX_SIZE_INT32, (char *)answer) + +#define __GLX_SEND_FLOAT_ARRAY(len) \ + WriteToClient(client, (len)*__GLX_SIZE_FLOAT32, (char *)answer) + +#define __GLX_SEND_DOUBLE_ARRAY(len) \ + WriteToClient(client, (len)*__GLX_SIZE_FLOAT64, (char *)answer) + + +#define __GLX_SEND_VOID_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) +#define __GLX_SEND_UBYTE_ARRAY(len) __GLX_SEND_BYTE_ARRAY(len) +#define __GLX_SEND_USHORT_ARRAY(len) __GLX_SEND_SHORT_ARRAY(len) +#define __GLX_SEND_UINT_ARRAY(len) __GLX_SEND_INT_ARRAY(len) + +/* +** PERFORMANCE NOTE: +** Machine dependent optimizations abound here; these swapping macros can +** conceivably be replaced with routines that do the job faster. +*/ +#define __GLX_DECLARE_SWAP_VARIABLES \ + GLbyte sw; \ + GLbyte *swapPC; \ + GLbyte *swapEnd + + +#define __GLX_SWAP_INT(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ + ((GLbyte *)(pc))[3] = sw; \ + sw = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ + ((GLbyte *)(pc))[2] = sw; + +#define __GLX_SWAP_SHORT(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = sw; + +#define __GLX_SWAP_DOUBLE(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[7]; \ + ((GLbyte *)(pc))[7] = sw; \ + sw = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[6]; \ + ((GLbyte *)(pc))[6] = sw; \ + sw = ((GLbyte *)(pc))[2]; \ + ((GLbyte *)(pc))[2] = ((GLbyte *)(pc))[5]; \ + ((GLbyte *)(pc))[5] = sw; \ + sw = ((GLbyte *)(pc))[3]; \ + ((GLbyte *)(pc))[3] = ((GLbyte *)(pc))[4]; \ + ((GLbyte *)(pc))[4] = sw; + +#define __GLX_SWAP_FLOAT(pc) \ + sw = ((GLbyte *)(pc))[0]; \ + ((GLbyte *)(pc))[0] = ((GLbyte *)(pc))[3]; \ + ((GLbyte *)(pc))[3] = sw; \ + sw = ((GLbyte *)(pc))[1]; \ + ((GLbyte *)(pc))[1] = ((GLbyte *)(pc))[2]; \ + ((GLbyte *)(pc))[2] = sw; + +#define __GLX_SWAP_INT_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT32;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_INT(swapPC); \ + swapPC += __GLX_SIZE_INT32; \ + } + +#define __GLX_SWAP_SHORT_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_INT16;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_SHORT(swapPC); \ + swapPC += __GLX_SIZE_INT16; \ + } + +#define __GLX_SWAP_DOUBLE_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT64;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_DOUBLE(swapPC); \ + swapPC += __GLX_SIZE_FLOAT64; \ + } + +#define __GLX_SWAP_FLOAT_ARRAY(pc, count) \ + swapPC = ((GLbyte *)(pc)); \ + swapEnd = ((GLbyte *)(pc)) + (count)*__GLX_SIZE_FLOAT32;\ + while (swapPC < swapEnd) { \ + __GLX_SWAP_FLOAT(swapPC); \ + swapPC += __GLX_SIZE_FLOAT32; \ + } + +#define __GLX_SWAP_REPLY_HEADER() \ + __GLX_SWAP_SHORT(&__glXReply.sequenceNumber); \ + __GLX_SWAP_INT(&__glXReply.length); + +#define __GLX_SWAP_REPLY_RETVAL() \ + __GLX_SWAP_INT(&__glXReply.retval) + +#define __GLX_SWAP_REPLY_SIZE() \ + __GLX_SWAP_INT(&__glXReply.size) + +#endif /* !__GLX_unpack_h__ */ + + + + + diff --git a/xorg-server/hw/dmx/input/dmxinputinit.c b/xorg-server/hw/dmx/input/dmxinputinit.c index 5a486a464..f9acaa039 100644 --- a/xorg-server/hw/dmx/input/dmxinputinit.c +++ b/xorg-server/hw/dmx/input/dmxinputinit.c @@ -1,1311 +1,1311 @@ -/* - * Copyright 2002-2003 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: - * Rickard E. (Rik) Faith <faith@redhat.com> - * - */ - -/** \file - * This file provides generic input support. Functions here set up - * input and lead to the calling of low-level device drivers for - * input. */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#define DMX_WINDOW_DEBUG 0 - -#include "dmxinputinit.h" -#include "dmxextension.h" /* For dmxInputCount */ - -#include "dmxdummy.h" -#include "dmxbackend.h" -#include "dmxconsole.h" -#include "dmxcommon.h" -#include "dmxevents.h" -#include "dmxmotion.h" -#include "dmxprop.h" -#include "config/dmxconfig.h" -#include "dmxcursor.h" - -#include "lnx-keyboard.h" -#include "lnx-ms.h" -#include "lnx-ps2.h" -#include "usb-keyboard.h" -#include "usb-mouse.h" -#include "usb-other.h" -#include "usb-common.h" - -#include "dmxsigio.h" -#include "dmxarg.h" - -#include "inputstr.h" -#include "input.h" -#include "mipointer.h" -#include "windowstr.h" -#include "mi.h" -#include "xkbsrv.h" - -#include <X11/extensions/XI.h> -#include <X11/extensions/XIproto.h> -#include "exevents.h" -#include "extinit.h" - -DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; - -static DMXLocalInputInfoRec DMXDummyMou = { - "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo -}; - -static DMXLocalInputInfoRec DMXDummyKbd = { - "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo -}; - -static DMXLocalInputInfoRec DMXBackendMou = { - "backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2, - dmxBackendCreatePrivate, dmxBackendDestroyPrivate, - dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo, - dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition, - NULL, NULL, NULL, - dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL, - dmxCommonMouCtrl -}; - -static DMXLocalInputInfoRec DMXBackendKbd = { - "backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND, - 1, /* With backend-mou or console-mou */ - dmxCommonCopyPrivate, NULL, - dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo, - dmxCommonKbdOn, dmxCommonKbdOff, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, dmxCommonKbdCtrl, dmxCommonKbdBell -}; - -static DMXLocalInputInfoRec DMXConsoleMou = { - "console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2, - dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate, - dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo, - dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition, - NULL, NULL, NULL, - dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo, - dmxCommonMouCtrl -}; - -static DMXLocalInputInfoRec DMXConsoleKbd = { - "console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE, - 1, /* With backend-mou or console-mou */ - dmxCommonCopyPrivate, NULL, - dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo, - dmxCommonKbdOn, dmxCommonKbdOff, NULL, - NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, dmxCommonKbdCtrl, dmxCommonKbdBell -}; - -static DMXLocalInputInfoRec DMXCommonOth = { - "common-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_COMMON, 1, - dmxCommonCopyPrivate, NULL, - NULL, NULL, NULL, dmxCommonOthGetInfo, - dmxCommonOthOn, dmxCommonOthOff -}; - - -static DMXLocalInputInfoRec DMXLocalDevices[] = { - /* Dummy drivers that can compile on any OS */ -#ifdef __linux__ - /* Linux-specific drivers */ - { - "kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate, - kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo, - kbdLinuxOn, kbdLinuxOff, NULL, - kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch, - kbdLinuxRead, NULL, NULL, NULL, - NULL, kbdLinuxCtrl, kbdLinuxBell - }, - { - "ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - msLinuxCreatePrivate, msLinuxDestroyPrivate, - msLinuxInit, NULL, NULL, msLinuxGetInfo, - msLinuxOn, msLinuxOff, NULL, - msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL, - msLinuxRead - }, - { - "ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate, - ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo, - ps2LinuxOn, ps2LinuxOff, NULL, - ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL, - ps2LinuxRead - }, -#endif -#ifdef __linux__ - /* USB drivers, currently only for - Linux, but relatively easy to port to - other OSs */ - { - "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - usbCreatePrivate, usbDestroyPrivate, - kbdUSBInit, NULL, NULL, kbdUSBGetInfo, - kbdUSBOn, usbOff, NULL, - NULL, NULL, NULL, - kbdUSBRead, NULL, NULL, NULL, - NULL, kbdUSBCtrl - }, - { - "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - usbCreatePrivate, usbDestroyPrivate, - mouUSBInit, NULL, NULL, mouUSBGetInfo, - mouUSBOn, usbOff, NULL, - NULL, NULL, NULL, - mouUSBRead - }, - { - "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1, - usbCreatePrivate, usbDestroyPrivate, - othUSBInit, NULL, NULL, othUSBGetInfo, - othUSBOn, usbOff, NULL, - NULL, NULL, NULL, - othUSBRead - }, -#endif - { - "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo - }, - { - "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, - NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo - }, - { NULL } /* Must be last */ -}; - - -#if 11 /*BP*/ -void -DDXRingBell(int volume, int pitch, int duration) -{ - /* NO-OP */ -} - -/* taken from kdrive/src/kinput.c: */ -static void -dmxKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) -{ -#if 0 - KdKeyboardInfo *ki; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev && ki->dixdev->id == pDevice->id) - break; - } - - if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) - return; - - KdSetLeds(ki, ctrl->leds); - ki->bellPitch = ctrl->bell_pitch; - ki->bellDuration = ctrl->bell_duration; -#endif -} - -/* taken from kdrive/src/kinput.c: */ -static void -dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something) -{ -#if 0 - KeybdCtrl *ctrl = arg; - KdKeyboardInfo *ki = NULL; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev && ki->dixdev->id == pDev->id) - break; - } - - if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) - return; - - KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); -#endif -} - -#endif /*BP*/ - -static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal, - PtrCtrl *ctrl) -{ - if (!dmxLocal) return; - dmxLocal->mctrl = *ctrl; - if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl); -} - -/** Change the pointer control information for the \a pDevice. If the - * device sends core events, then also change the control information - * for all of the pointer devices that send core events. */ -void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl) -{ - GETDMXLOCALFROMPDEVICE; - int i, j; - - if (dmxLocal->sendsCore) { /* Do for all core devices */ - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->detached) continue; - for (j = 0; j < dmxInput->numDevs; j++) - if (dmxInput->devs[j]->sendsCore) - _dmxChangePointerControl(dmxInput->devs[j], ctrl); - } - } else { /* Do for this device only */ - _dmxChangePointerControl(dmxLocal, ctrl); - } -} - -static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal, - KeybdCtrl *ctrl) -{ - dmxLocal->kctrl = *ctrl; - if (dmxLocal->kCtrl) { - dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl); - if (dmxLocal->pDevice->kbdfeed) { - XkbEventCauseRec cause; - XkbSetCauseUnknown(&cause); - /* Generate XKB events, as necessary */ - XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False, - NULL, &cause); - } - } -} - - -/** Change the keyboard control information for the \a pDevice. If the - * device sends core events, then also change the control information - * for all of the keyboard devices that send core events. */ -void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl) -{ - GETDMXLOCALFROMPDEVICE; - int i, j; - - if (dmxLocal->sendsCore) { /* Do for all core devices */ - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->detached) continue; - for (j = 0; j < dmxInput->numDevs; j++) - if (dmxInput->devs[j]->sendsCore) - _dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl); - } - } else { /* Do for this device only */ - _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl); - } -} - -static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent) -{ - if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public, - percent, - dmxLocal->kctrl.bell, - dmxLocal->kctrl.bell_pitch, - dmxLocal->kctrl.bell_duration); -} - -/** Sound the bell on the device. If the device send core events, then - * sound the bell on all of the devices that send core events. */ -void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, - pointer ctrl, int unknown) -{ - GETDMXLOCALFROMPDEVICE; - int i, j; - - if (dmxLocal->sendsCore) { /* Do for all core devices */ - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->detached) continue; - for (j = 0; j < dmxInput->numDevs; j++) - if (dmxInput->devs[j]->sendsCore) - _dmxKeyboardBellProc(dmxInput->devs[j], percent); - } - } else { /* Do for this device only */ - _dmxKeyboardBellProc(dmxLocal, percent); - } -} - -static void dmxKeyboardFreeNames(XkbComponentNamesPtr names) -{ - if (names->keycodes) XFree(names->keycodes); - if (names->types) XFree(names->types); - if (names->compat) XFree(names->compat); - if (names->symbols) XFree(names->symbols); - if (names->geometry) XFree(names->geometry); -} - - -static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info) -{ - GETDMXINPUTFROMPDEVICE; - XkbRMLVOSet rmlvo; - - rmlvo.rules = dmxConfigGetXkbRules(); - rmlvo.model = dmxConfigGetXkbModel(); - rmlvo.layout = dmxConfigGetXkbLayout(); - rmlvo.variant = dmxConfigGetXkbVariant(); - rmlvo.options = dmxConfigGetXkbOptions(); - - XkbSetRulesDflts(&rmlvo); - if (!info->force && (dmxInput->keycodes - || dmxInput->symbols - || dmxInput->geometry)) { - if (info->freenames) dmxKeyboardFreeNames(&info->names); - info->freenames = 0; - info->names.keycodes = dmxInput->keycodes; - info->names.types = NULL; - info->names.compat = NULL; - info->names.symbols = dmxInput->symbols; - info->names.geometry = dmxInput->geometry; - - dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s", - info->names.keycodes); - if (info->names.symbols && *info->names.symbols) - dmxLogInputCont(dmxInput, " %s", info->names.symbols); - if (info->names.geometry && *info->names.geometry) - dmxLogInputCont(dmxInput, " %s", info->names.geometry); - dmxLogInputCont(dmxInput, "\n"); - } else if (info->names.keycodes) { - dmxLogInput(dmxInput, "XKEYBOARD: From device: %s", - info->names.keycodes); - if (info->names.symbols && *info->names.symbols) - dmxLogInputCont(dmxInput, " %s", info->names.symbols); - if (info->names.geometry && *info->names.geometry) - dmxLogInputCont(dmxInput, " %s", info->names.geometry); - dmxLogInputCont(dmxInput, "\n"); - } else { - dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n", - dmxConfigGetXkbRules(), - dmxConfigGetXkbLayout(), - dmxConfigGetXkbModel(), - dmxConfigGetXkbVariant() - ? dmxConfigGetXkbVariant() : "", - dmxConfigGetXkbOptions() - ? dmxConfigGetXkbOptions() : ""); - } - InitKeyboardDeviceStruct(pDevice, &rmlvo, - dmxKeyboardBellProc, - dmxKeyboardKbdCtrlProc); - - if (info->freenames) dmxKeyboardFreeNames(&info->names); - - return Success; -} - - -static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what) -{ - GETDMXINPUTFROMPDEVICE; - int fd; - DMXLocalInitInfo info; - int i; - Atom btn_labels[MAX_BUTTONS] = {0}; /* FIXME */ - Atom axis_labels[MAX_VALUATORS] = {0}; /* FIXME */ - - if (dmxInput->detached) return Success; - - memset(&info, 0, sizeof(info)); - switch (what) { - case DEVICE_INIT: - if (dmxLocal->init) - dmxLocal->init(pDev); - if (dmxLocal->get_info) - dmxLocal->get_info(pDev, &info); - if (info.keyboard) { /* XKEYBOARD makes this a special case */ - dmxKeyboardOn(pDevice, &info); - break; - } - if (info.keyClass) { - XkbRMLVOSet rmlvo; - - rmlvo.rules = dmxConfigGetXkbRules(); - rmlvo.model = dmxConfigGetXkbModel(); - rmlvo.layout = dmxConfigGetXkbLayout(); - rmlvo.variant = dmxConfigGetXkbVariant(); - rmlvo.options = dmxConfigGetXkbOptions(); - - InitKeyboardDeviceStruct(pDevice, - &rmlvo, - dmxBell, dmxKbdCtrl); - } - if (info.buttonClass) { - InitButtonClassDeviceStruct(pDevice, info.numButtons, - btn_labels, info.map); - } - if (info.valuatorClass) { - if (info.numRelAxes && dmxLocal->sendsCore) { - InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, - axis_labels, - GetMaximumEventsNum(), - Relative); - for (i = 0; i < info.numRelAxes; i++) - InitValuatorAxisStruct(pDevice, i, axis_labels[i], - info.minval[i], info.maxval[i], - info.res[i], - info.minres[i], info.maxres[i]); - } else if (info.numRelAxes) { - InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, - axis_labels, - dmxPointerGetMotionBufferSize(), - Relative); - for (i = 0; i < info.numRelAxes; i++) - InitValuatorAxisStruct(pDevice, i, axis_labels[i], - info.minval[i], - info.maxval[i], info.res[i], - info.minres[i], info.maxres[i]); - } else if (info.numAbsAxes) { - InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes, - axis_labels, - dmxPointerGetMotionBufferSize(), - Absolute); - for (i = 0; i < info.numAbsAxes; i++) - InitValuatorAxisStruct(pDevice, i, - axis_labels[i], - info.minval[i], info.maxval[i], - info.res[i], info.minres[i], - info.maxres[i]); - } - } - if (info.focusClass) InitFocusClassDeviceStruct(pDevice); - if (info.proximityClass) InitProximityClassDeviceStruct(pDevice); - if (info.ptrFeedbackClass) - InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl); - if (info.intFeedbackClass || info.strFeedbackClass) - dmxLog(dmxWarning, - "Integer and string feedback not supported for %s\n", - pDevice->name); - if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass)) - dmxLog(dmxWarning, - "Led and bel feedback not supported for non-keyboard %s\n", - pDevice->name); - break; - case DEVICE_ON: - if (!pDev->on) { - if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0) - dmxSigioRegister(dmxInput, fd); - pDev->on = TRUE; - } - break; - case DEVICE_OFF: - case DEVICE_CLOSE: - /* This can get called twice consecutively: once for a - * detached screen (DEVICE_OFF), and then again at server - * generation time (DEVICE_CLOSE). */ - if (pDev->on) { - dmxSigioUnregister(dmxInput); - if (dmxLocal->off) dmxLocal->off(pDev); - pDev->on = FALSE; - } - break; - } - if (info.keySyms.map && info.freemap) { - XFree(info.keySyms.map); - info.keySyms.map = NULL; - } - if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True); - return Success; -} - -static void dmxProcessInputEvents(DMXInputInfo *dmxInput) -{ - int i; - - mieqProcessInputEvents(); -#if 00 /*BP*/ - miPointerUpdate(); -#endif - if (dmxInput->detached) - 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); - } - -#if 11 /*BP*/ - mieqProcessInputEvents(); -#endif -} - -static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput, - DMXUpdateType type, - WindowPtr pWindow) -{ - int i; - -#ifdef PANORAMIX - if (!noPanoramiXExtension && pWindow && pWindow->parent != WindowTable[0]) - return; -#endif -#if DMX_WINDOW_DEBUG - { - const char *name = "Unknown"; - switch (type) { - case DMX_UPDATE_REALIZE: name = "Realize"; break; - case DMX_UPDATE_UNREALIZE: name = "Unrealize"; break; - case DMX_UPDATE_RESTACK: name = "Restack"; break; - case DMX_UPDATE_COPY: name = "Copy"; break; - case DMX_UPDATE_RESIZE: name = "Resize"; break; - case DMX_UPDATE_REPARENT: name = "Repaint"; break; - } - dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name); - } -#endif - - if (dmxInput->detached) - return; - for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) - if (dmxInput->devs[i]->update_info) - dmxInput->devs[i]->update_info(dmxInput->devs[i]->private, - type, pWindow); -} - -static void dmxCollectAll(DMXInputInfo *dmxInput) -{ - int i; - - if (dmxInput->detached) - return; - for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) - if (dmxInput->devs[i]->collect_events) - dmxInput->devs[i]->collect_events(&dmxInput->devs[i]->pDevice->public, - dmxMotion, - dmxEnqueue, - dmxCheckSpecialKeys, DMX_BLOCK); -} - -static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout, - pointer pReadMask) -{ - DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; - static unsigned long generation = 0; - - if (generation != serverGeneration) { - generation = serverGeneration; - dmxCollectAll(dmxInput); - } -} - -static void dmxSwitchReturn(pointer p) -{ - DMXInputInfo *dmxInput = p; - int i; - - dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched); - - if (!dmxInput->vt_switched) - dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n"); - dmxSigioEnableInput(); - for (i = 0; i < dmxInput->numDevs; i++) - if (dmxInput->devs[i]->vt_post_switch) - dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private); - dmxInput->vt_switched = 0; -} - -static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask) -{ - DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; - int i; - - if (dmxInput->vt_switch_pending) { - dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending); - for (i = 0; i < dmxInput->numDevs; i++) - if (dmxInput->devs[i]->vt_pre_switch) - dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private); - dmxInput->vt_switched = dmxInput->vt_switch_pending; - dmxInput->vt_switch_pending = 0; - for (i = 0; i < dmxInput->numDevs; i++) { - if (dmxInput->devs[i]->vt_switch) { - dmxSigioDisableInput(); - if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private, - dmxInput->vt_switched, - dmxSwitchReturn, - dmxInput)) - dmxSwitchReturn(dmxInput); - break; /* Only call one vt_switch routine */ - } - } - } - dmxCollectAll(dmxInput); -} - -static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal) -{ - static int k = 0; - static int m = 0; - static int o = 0; - static unsigned long dmxGeneration = 0; -#define LEN 32 - char * buf = xalloc(LEN); - - if (dmxGeneration != serverGeneration) { - k = m = o = 0; - dmxGeneration = serverGeneration; - } - - switch (dmxLocal->type) { - case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break; - case DMX_LOCAL_MOUSE: XmuSnprintf(buf, LEN, "Mouse%d", m++); break; - default: XmuSnprintf(buf, LEN, "Other%d", o++); break; - } - - return buf; -} - -static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal) -{ - DeviceIntPtr pDevice; - Atom atom; - const char *name = NULL; - void (*registerProcPtr)(DeviceIntPtr) = NULL; - char *devname; - DMXInputInfo *dmxInput; - - if (!dmxLocal) - return NULL; - dmxInput = &dmxInputs[dmxLocal->inputIdx]; - - if (dmxLocal->sendsCore) { - if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) { - dmxLocal->isCore = 1; - dmxLocalCoreKeyboard = dmxLocal; - name = "keyboard"; - registerProcPtr = RegisterKeyboardDevice; - } - if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) { - dmxLocal->isCore = 1; - dmxLocalCorePointer = dmxLocal; - name = "pointer"; - registerProcPtr = RegisterPointerDevice; - } - } - - if (!name) { - name = "extension"; - registerProcPtr = RegisterOtherDevice; - } - - if (!name || !registerProcPtr) - dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name); - - pDevice = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE); - if (!pDevice) { - dmxLog(dmxError, "Too many devices -- cannot add device %s\n", - dmxLocal->name); - return NULL; - } - pDevice->public.devicePrivate = dmxLocal; - dmxLocal->pDevice = pDevice; - - devname = dmxMakeUniqueDeviceName(dmxLocal); - atom = MakeAtom((char *)devname, strlen(devname), TRUE); - pDevice->type = atom; - pDevice->name = devname; - - registerProcPtr(pDevice); - - if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) { -#if 00 /*BP*/ - miRegisterPointerDevice(screenInfo.screens[0], pDevice); -#else - /* Nothing? dmxDeviceOnOff() should get called to init, right? */ -#endif - } - - if (dmxLocal->create_private) - dmxLocal->private = dmxLocal->create_private(pDevice); - - dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n", - dmxLocal->name, name, devname, - dmxLocal->isCore - ? " [core]" - : (dmxLocal->sendsCore - ? " [sends core events]" - : "")); - - return pDevice; -} - -static DMXLocalInputInfoPtr dmxLookupLocal(const char *name) -{ - DMXLocalInputInfoPtr pt; - - for (pt = &DMXLocalDevices[0]; pt->name; ++pt) - if (!strcmp(pt->name, name)) return pt; /* search for device name */ - return NULL; -} - -/** Copy the local input information from \a s into a new \a devs slot - * in \a dmxInput. */ -DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, - DMXLocalInputInfoPtr s) -{ - DMXLocalInputInfoPtr dmxLocal = xalloc(sizeof(*dmxLocal)); - - if (!dmxLocal) - dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n"); - - memcpy(dmxLocal, s, sizeof(*dmxLocal)); - dmxLocal->inputIdx = dmxInput->inputIdx; - dmxLocal->sendsCore = dmxInput->core; - dmxLocal->savedSendsCore = dmxInput->core; - dmxLocal->deviceId = -1; - - ++dmxInput->numDevs; - dmxInput->devs = xrealloc(dmxInput->devs, - dmxInput->numDevs * sizeof(*dmxInput->devs)); - dmxInput->devs[dmxInput->numDevs-1] = dmxLocal; - - return dmxLocal; -} - -static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a) -{ - int i; - int help = 0; - DMXLocalInputInfoRec *pt; - - for (i = 1; i < dmxArgC(a); i++) { - const char *name = dmxArgV(a, i); - if ((pt = dmxLookupLocal(name))) { - dmxInputCopyLocal(dmxInput, pt); - } else { - if (strlen(name)) - dmxLog(dmxWarning, - "Could not find a driver called %s\n", name); - ++help; - } - } - if (help) { - dmxLog(dmxInfo, "Available local device drivers:\n"); - for (pt = &DMXLocalDevices[0]; pt->name; ++pt) { - const char *type; - switch (pt->type) { - case DMX_LOCAL_KEYBOARD: type = "keyboard"; break; - case DMX_LOCAL_MOUSE: type = "pointer"; break; - default: type = "unknown"; break; - } - dmxLog(dmxInfo, " %s (%s)\n", pt->name, type); - } - dmxLog(dmxFatal, "Must have valid local device driver\n"); - } -} - -int dmxInputExtensionErrorHandler(Display *dsp, char *name, char *reason) -{ - return 0; -} - -static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI) -{ - XExtensionVersion *ext; - XDeviceInfo *devices; - Display *display; - int num; - int i, j; - DMXLocalInputInfoPtr dmxLocal; - int (*handler)(Display *, char *, char *); - - if (!(display = XOpenDisplay(dmxInput->name))) return; - - /* Print out information about the XInput Extension. */ - handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); - ext = XGetExtensionVersion(display, INAME); - XSetExtensionErrorHandler(handler); - - if (!ext || ext == (XExtensionVersion *)NoSuchExtension) { - dmxLogInput(dmxInput, "%s is not available\n", INAME); - } else { - dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n", - dmxInput->name, INAME, - ext->major_version, ext->minor_version); - devices = XListInputDevices(display, &num); - - XFree(ext); - ext = NULL; - - /* Print a list of all devices */ - for (i = 0; i < num; i++) { - const char *use = "Unknown"; - switch (devices[i].use) { - case IsXPointer: use = "XPointer"; break; - case IsXKeyboard: use = "XKeyboard"; break; - case IsXExtensionDevice: use = "XExtensionDevice"; break; - case IsXExtensionPointer: use = "XExtensionPointer"; break; - case IsXExtensionKeyboard: use = "XExtensionKeyboard"; break; - } - dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n", - devices[i].id, - devices[i].name ? devices[i].name : "", - use); - } - - /* Search for extensions */ - for (i = 0; i < num; i++) { - switch (devices[i].use) { - case IsXKeyboard: - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; - if (dmxL->type == DMX_LOCAL_KEYBOARD - && dmxL->deviceId < 0) { - dmxL->deviceId = devices[i].id; - dmxL->deviceName = (devices[i].name - ? xstrdup(devices[i].name) - : NULL); - } - } - break; - case IsXPointer: - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; - if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) { - dmxL->deviceId = devices[i].id; - dmxL->deviceName = (devices[i].name - ? xstrdup(devices[i].name) - : NULL); - } - } - break; -#if 0 - case IsXExtensionDevice: - case IsXExtensionKeyboard: - case IsXExtensionPointer: - if (doXI) { - if (!dmxInput->numDevs) { - dmxLog(dmxWarning, - "Cannot use remote (%s) XInput devices if" - " not also using core devices\n", - dmxInput->name); - } else { - dmxLocal = dmxInputCopyLocal(dmxInput, - &DMXCommonOth); - dmxLocal->isCore = FALSE; - dmxLocal->sendsCore = FALSE; - dmxLocal->deviceId = devices[i].id; - dmxLocal->deviceName = (devices[i].name - ? xstrdup(devices[i].name) - : NULL); - } - } - break; -#endif - } - } - XFreeDeviceList(devices); - } - XCloseDisplay(display); -} - -/** Re-initialize all the devices described in \a dmxInput. Called from - #dmxAdjustCursorBoundaries before the cursor is redisplayed. */ -void dmxInputReInit(DMXInputInfo *dmxInput) -{ - int i; - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - if (dmxLocal->reinit) - dmxLocal->reinit(&dmxLocal->pDevice->public); - } -} - -/** Re-initialize all the devices described in \a dmxInput. Called from - #dmxAdjustCursorBoundaries after the cursor is redisplayed. */ -void dmxInputLateReInit(DMXInputInfo *dmxInput) -{ - int i; - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - if (dmxLocal->latereinit) - dmxLocal->latereinit(&dmxLocal->pDevice->public); - } -} - -/** Initialize all of the devices described in \a dmxInput. */ -void dmxInputInit(DMXInputInfo *dmxInput) -{ - DeviceIntPtr pPointer = NULL, pKeyboard = NULL; - dmxArg a; - const char *name; - int i; - int doXI = 1; /* Include by default */ - int forceConsole = 0; - int doWindows = 1; /* On by default */ - int hasXkb = 0; - - a = dmxArgParse(dmxInput->name); - - for (i = 1; i < dmxArgC(a); i++) { - switch (hasXkb) { - case 1: - dmxInput->keycodes = xstrdup(dmxArgV(a, i)); - ++hasXkb; - break; - case 2: - dmxInput->symbols = xstrdup(dmxArgV(a, i)); - ++hasXkb; - break; - case 3: - dmxInput->geometry = xstrdup(dmxArgV(a, i)); - hasXkb = 0; - break; - case 0: - if (!strcmp(dmxArgV(a, i), "noxi")) doXI = 0; - else if (!strcmp(dmxArgV(a, i), "xi")) doXI = 1; - else if (!strcmp(dmxArgV(a, i), "console")) forceConsole = 1; - else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0; - else if (!strcmp(dmxArgV(a, i), "windows")) doWindows = 1; - else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows = 0; - else if (!strcmp(dmxArgV(a, i), "xkb")) hasXkb = 1; - else { - dmxLog(dmxFatal, - "Unknown input argument: %s\n", dmxArgV(a, i)); - } - } - } - - name = dmxArgV(a, 0); - - if (!strcmp(name, "local")) { - dmxPopulateLocal(dmxInput, a); - } else if (!strcmp(name, "dummy")) { - dmxInputCopyLocal(dmxInput, &DMXDummyMou); - dmxInputCopyLocal(dmxInput, &DMXDummyKbd); - dmxLogInput(dmxInput, "Using dummy input\n"); - } else { - int found; - - for (found = 0, i = 0; i < dmxNumScreens; i++) { - if (dmxPropertySameDisplay(&dmxScreens[i], name)) { - if (dmxScreens[i].shared) - dmxLog(dmxFatal, - "Cannot take input from shared backend (%s)\n", - name); - if (!dmxInput->core) { - dmxLog(dmxWarning, - "Cannot use core devices on a backend (%s)" - " as XInput devices\n", name); - } else { - char *pt; - for (pt = (char *)dmxInput->name; pt && *pt; pt++) - if (*pt == ',') *pt = '\0'; - dmxInputCopyLocal(dmxInput, &DMXBackendMou); - dmxInputCopyLocal(dmxInput, &DMXBackendKbd); - dmxInput->scrnIdx = i; - dmxLogInput(dmxInput, - "Using backend input from %s\n", name); - } - ++found; - break; - } - } - if (!found || forceConsole) { - char *pt; - if (found) dmxInput->console = TRUE; - for (pt = (char *)dmxInput->name; pt && *pt; pt++) - if (*pt == ',') *pt = '\0'; - dmxInputCopyLocal(dmxInput, &DMXConsoleMou); - dmxInputCopyLocal(dmxInput, &DMXConsoleKbd); - if (doWindows) { - dmxInput->windows = TRUE; - dmxInput->updateWindowInfo = dmxUpdateWindowInformation; - } - dmxLogInput(dmxInput, - "Using console input from %s (%s windows)\n", - name, doWindows ? "with" : "without"); - } - } - - dmxArgFree(a); - - /* Locate extensions we may be interested in */ - dmxInputScanForExtensions(dmxInput, doXI); - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - dmxLocal->pDevice = dmxAddDevice(dmxLocal); - if (dmxLocal->isCore) { - if (dmxLocal->type == DMX_LOCAL_MOUSE) - pPointer = dmxLocal->pDevice; - if (dmxLocal->type == DMX_LOCAL_KEYBOARD) - pKeyboard = dmxLocal->pDevice; - } - } - - dmxInput->processInputEvents = dmxProcessInputEvents; - dmxInput->detached = False; - - RegisterBlockAndWakeupHandlers(dmxBlockHandler, - dmxWakeupHandler, - (void *)dmxInput->inputIdx); -} - -static void dmxInputFreeLocal(DMXLocalInputInfoRec *local) -{ - if (!local) return; - if (local->isCore && local->type == DMX_LOCAL_MOUSE) - dmxLocalCorePointer = NULL; - if (local->isCore && local->type == DMX_LOCAL_KEYBOARD) - dmxLocalCoreKeyboard = NULL; - if (local->destroy_private) local->destroy_private(local->private); - if (local->history) xfree(local->history); - if (local->valuators) xfree(local->valuators); - if (local->deviceName) xfree(local->deviceName); - local->private = NULL; - local->history = NULL; - local->deviceName = NULL; - xfree(local); -} - -/** Free all of the memory associated with \a dmxInput */ -void dmxInputFree(DMXInputInfo *dmxInput) -{ - int i; - - if (!dmxInput) return; - - if (dmxInput->keycodes) xfree(dmxInput->keycodes); - if (dmxInput->symbols) xfree(dmxInput->symbols); - if (dmxInput->geometry) xfree(dmxInput->geometry); - - for (i = 0; i < dmxInput->numDevs; i++) { - dmxInputFreeLocal(dmxInput->devs[i]); - dmxInput->devs[i] = NULL; - } - xfree(dmxInput->devs); - dmxInput->devs = NULL; - dmxInput->numDevs = 0; - if (dmxInput->freename) xfree(dmxInput->name); - dmxInput->name = NULL; -} - -/** Log information about all of the known devices using #dmxLog(). */ -void dmxInputLogDevices(void) -{ - int i, j; - - dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount()); - dmxLog(dmxInfo, " Id Name Classes\n"); - for (j = 0; j < dmxNumInputs; j++) { - DMXInputInfo *dmxInput = &dmxInputs[j]; - const char *pt = strchr(dmxInput->name, ','); - int len = (pt - ? (size_t)(pt-dmxInput->name) - : strlen(dmxInput->name)); - - for (i = 0; i < dmxInput->numDevs; i++) { - DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice; - if (pDevice) { - dmxLog(dmxInfo, " %2d%c %-20.20s", - pDevice->id, - dmxInput->detached ? 'D' : ' ', - pDevice->name); - if (pDevice->key) dmxLogCont(dmxInfo, " key"); - if (pDevice->valuator) dmxLogCont(dmxInfo, " val"); - if (pDevice->button) dmxLogCont(dmxInfo, " btn"); - if (pDevice->focus) dmxLogCont(dmxInfo, " foc"); - if (pDevice->kbdfeed) dmxLogCont(dmxInfo, " fb/kbd"); - if (pDevice->ptrfeed) dmxLogCont(dmxInfo, " fb/ptr"); - if (pDevice->intfeed) dmxLogCont(dmxInfo, " fb/int"); - if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str"); - if (pDevice->bell) dmxLogCont(dmxInfo, " fb/bel"); - if (pDevice->leds) dmxLogCont(dmxInfo, " fb/led"); - if (!pDevice->key && !pDevice->valuator && !pDevice->button - && !pDevice->focus && !pDevice->kbdfeed - && !pDevice->ptrfeed && !pDevice->intfeed - && !pDevice->stringfeed && !pDevice->bell - && !pDevice->leds) dmxLogCont(dmxInfo, " (none)"); - - dmxLogCont(dmxInfo, "\t[i%d/%*.*s", - dmxInput->inputIdx, len, len, dmxInput->name); - if (dmxInput->devs[i]->deviceId >= 0) - dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId); - if (dmxInput->devs[i]->deviceName) - dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName); - dmxLogCont(dmxInfo, "] %s\n", - dmxInput->devs[i]->isCore - ? "core" - : (dmxInput->devs[i]->sendsCore - ? "extension (sends core events)" - : "extension")); - } - } - } -} - -/** Detach an input */ -int dmxInputDetach(DMXInputInfo *dmxInput) -{ - int i; - - if (dmxInput->detached) return BadAccess; - - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n", - dmxLocal->pDevice->id, - dmxLocal->pDevice->name, - dmxLocal->isCore - ? " [core]" - : (dmxLocal->sendsCore - ? " [sends core events]" - : "")); - DisableDevice(dmxLocal->pDevice, TRUE); - } - dmxInput->detached = True; - dmxInputLogDevices(); - return 0; -} - -/** Search for input associated with \a dmxScreen, and detach. */ -void dmxInputDetachAll(DMXScreenInfo *dmxScreen) -{ - int i; - - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput); - } -} - -/** Search for input associated with \a deviceId, and detach. */ -int dmxInputDetachId(int id) -{ - DMXInputInfo *dmxInput = dmxInputLocateId(id); - - if (!dmxInput) return BadValue; - - return dmxInputDetach(dmxInput); -} - -DMXInputInfo *dmxInputLocateId(int id) -{ - int i, j; - - for (i = 0; i < dmxNumInputs; i++) { - DMXInputInfo *dmxInput = &dmxInputs[i]; - for (j = 0; j < dmxInput->numDevs; j++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; - if (dmxLocal->pDevice->id == id) return dmxInput; - } - } - return NULL; -} - -static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id) -{ - dmxInputInit(dmxInput); - InitAndStartDevices(); - if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id; - dmxInputLogDevices(); - return 0; -} - -static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id) -{ - int i; - - dmxInput->detached = False; - for (i = 0; i < dmxInput->numDevs; i++) { - DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; - if (id) *id = dmxLocal->pDevice->id; - dmxLogInput(dmxInput, - "Attaching device id %d: %s%s\n", - dmxLocal->pDevice->id, - dmxLocal->pDevice->name, - dmxLocal->isCore - ? " [core]" - : (dmxLocal->sendsCore - ? " [sends core events]" - : "")); - EnableDevice(dmxLocal->pDevice, TRUE); - } - dmxInputLogDevices(); - return 0; -} - -int dmxInputAttachConsole(const char *name, int isCore, int *id) -{ - DMXInputInfo *dmxInput; - int i; - - for (i = 0; i < dmxNumInputs; i++) { - dmxInput = &dmxInputs[i]; - if (dmxInput->scrnIdx == -1 - && dmxInput->detached - && !strcmp(dmxInput->name, name)) { - /* Found match */ - dmxLogInput(dmxInput, "Reattaching detached console input\n"); - return dmxInputAttachOld(dmxInput, id); - } - } - - /* No match found */ - dmxInput = dmxConfigAddInput(xstrdup(name), isCore); - dmxInput->freename = TRUE; - dmxLogInput(dmxInput, "Attaching new console input\n"); - return dmxInputAttachNew(dmxInput, id); -} - -int dmxInputAttachBackend(int physicalScreen, int isCore, int *id) -{ - DMXInputInfo *dmxInput; - DMXScreenInfo *dmxScreen; - int i; - - if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue; - for (i = 0; i < dmxNumInputs; i++) { - dmxInput = &dmxInputs[i]; - if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) { - /* Found match */ - if (!dmxInput->detached) return BadAccess; /* Already attached */ - dmxScreen = &dmxScreens[physicalScreen]; - if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ - dmxLogInput(dmxInput, "Reattaching detached backend input\n"); - return dmxInputAttachOld(dmxInput, id); - } - } - /* No match found */ - dmxScreen = &dmxScreens[physicalScreen]; - if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ - dmxInput = dmxConfigAddInput(dmxScreen->name, isCore); - dmxLogInput(dmxInput, "Attaching new backend input\n"); - return dmxInputAttachNew(dmxInput, id); -} +/* + * Copyright 2002-2003 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: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * This file provides generic input support. Functions here set up + * input and lead to the calling of low-level device drivers for + * input. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#define DMX_WINDOW_DEBUG 0 + +#include "dmxinputinit.h" +#include "dmxextension.h" /* For dmxInputCount */ + +#include "dmxdummy.h" +#include "dmxbackend.h" +#include "dmxconsole.h" +#include "dmxcommon.h" +#include "dmxevents.h" +#include "dmxmotion.h" +#include "dmxprop.h" +#include "config/dmxconfig.h" +#include "dmxcursor.h" + +#include "lnx-keyboard.h" +#include "lnx-ms.h" +#include "lnx-ps2.h" +#include "usb-keyboard.h" +#include "usb-mouse.h" +#include "usb-other.h" +#include "usb-common.h" + +#include "dmxsigio.h" +#include "dmxarg.h" + +#include "inputstr.h" +#include "input.h" +#include "mipointer.h" +#include "windowstr.h" +#include "mi.h" +#include "xkbsrv.h" + +#include <X11/extensions/XI.h> +#include <X11/extensions/XIproto.h> +#include "exevents.h" +#include "extinit.h" + +DMXLocalInputInfoPtr dmxLocalCorePointer, dmxLocalCoreKeyboard; + +static DMXLocalInputInfoRec DMXDummyMou = { + "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo +}; + +static DMXLocalInputInfoRec DMXDummyKbd = { + "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo +}; + +static DMXLocalInputInfoRec DMXBackendMou = { + "backend-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_BACKEND, 2, + dmxBackendCreatePrivate, dmxBackendDestroyPrivate, + dmxBackendInit, NULL, dmxBackendLateReInit, dmxBackendMouGetInfo, + dmxCommonMouOn, dmxCommonMouOff, dmxBackendUpdatePosition, + NULL, NULL, NULL, + dmxBackendCollectEvents, dmxBackendProcessInput, dmxBackendFunctions, NULL, + dmxCommonMouCtrl +}; + +static DMXLocalInputInfoRec DMXBackendKbd = { + "backend-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_BACKEND, + 1, /* With backend-mou or console-mou */ + dmxCommonCopyPrivate, NULL, + dmxBackendInit, NULL, NULL, dmxBackendKbdGetInfo, + dmxCommonKbdOn, dmxCommonKbdOff, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, dmxCommonKbdCtrl, dmxCommonKbdBell +}; + +static DMXLocalInputInfoRec DMXConsoleMou = { + "console-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_CONSOLE, 2, + dmxConsoleCreatePrivate, dmxConsoleDestroyPrivate, + dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleMouGetInfo, + dmxCommonMouOn, dmxCommonMouOff, dmxConsoleUpdatePosition, + NULL, NULL, NULL, + dmxConsoleCollectEvents, NULL, dmxConsoleFunctions, dmxConsoleUpdateInfo, + dmxCommonMouCtrl +}; + +static DMXLocalInputInfoRec DMXConsoleKbd = { + "console-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_CONSOLE, + 1, /* With backend-mou or console-mou */ + dmxCommonCopyPrivate, NULL, + dmxConsoleInit, dmxConsoleReInit, NULL, dmxConsoleKbdGetInfo, + dmxCommonKbdOn, dmxCommonKbdOff, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, dmxCommonKbdCtrl, dmxCommonKbdBell +}; + +static DMXLocalInputInfoRec DMXCommonOth = { + "common-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_COMMON, 1, + dmxCommonCopyPrivate, NULL, + NULL, NULL, NULL, dmxCommonOthGetInfo, + dmxCommonOthOn, dmxCommonOthOff +}; + + +static DMXLocalInputInfoRec DMXLocalDevices[] = { + /* Dummy drivers that can compile on any OS */ +#ifdef __linux__ + /* Linux-specific drivers */ + { + "kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + kbdLinuxCreatePrivate, kbdLinuxDestroyPrivate, + kbdLinuxInit, NULL, NULL, kbdLinuxGetInfo, + kbdLinuxOn, kbdLinuxOff, NULL, + kbdLinuxVTPreSwitch, kbdLinuxVTPostSwitch, kbdLinuxVTSwitch, + kbdLinuxRead, NULL, NULL, NULL, + NULL, kbdLinuxCtrl, kbdLinuxBell + }, + { + "ms", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + msLinuxCreatePrivate, msLinuxDestroyPrivate, + msLinuxInit, NULL, NULL, msLinuxGetInfo, + msLinuxOn, msLinuxOff, NULL, + msLinuxVTPreSwitch, msLinuxVTPostSwitch, NULL, + msLinuxRead + }, + { + "ps2", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + ps2LinuxCreatePrivate, ps2LinuxDestroyPrivate, + ps2LinuxInit, NULL, NULL, ps2LinuxGetInfo, + ps2LinuxOn, ps2LinuxOff, NULL, + ps2LinuxVTPreSwitch, ps2LinuxVTPostSwitch, NULL, + ps2LinuxRead + }, +#endif +#ifdef __linux__ + /* USB drivers, currently only for + Linux, but relatively easy to port to + other OSs */ + { + "usb-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + kbdUSBInit, NULL, NULL, kbdUSBGetInfo, + kbdUSBOn, usbOff, NULL, + NULL, NULL, NULL, + kbdUSBRead, NULL, NULL, NULL, + NULL, kbdUSBCtrl + }, + { + "usb-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + mouUSBInit, NULL, NULL, mouUSBGetInfo, + mouUSBOn, usbOff, NULL, + NULL, NULL, NULL, + mouUSBRead + }, + { + "usb-oth", DMX_LOCAL_OTHER, DMX_LOCAL_TYPE_LOCAL, 1, + usbCreatePrivate, usbDestroyPrivate, + othUSBInit, NULL, NULL, othUSBGetInfo, + othUSBOn, usbOff, NULL, + NULL, NULL, NULL, + othUSBRead + }, +#endif + { + "dummy-mou", DMX_LOCAL_MOUSE, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyMouGetInfo + }, + { + "dummy-kbd", DMX_LOCAL_KEYBOARD, DMX_LOCAL_TYPE_LOCAL, 1, + NULL, NULL, NULL, NULL, NULL, dmxDummyKbdGetInfo + }, + { NULL } /* Must be last */ +}; + + +#if 11 /*BP*/ +void +DDXRingBell(int volume, int pitch, int duration) +{ + /* NO-OP */ +} + +/* taken from kdrive/src/kinput.c: */ +static void +dmxKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ +#if 0 + KdKeyboardInfo *ki; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDevice->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDevice->id || !ki->driver) + return; + + KdSetLeds(ki, ctrl->leds); + ki->bellPitch = ctrl->bell_pitch; + ki->bellDuration = ctrl->bell_duration; +#endif +} + +/* taken from kdrive/src/kinput.c: */ +static void +dmxBell(int volume, DeviceIntPtr pDev, pointer arg, int something) +{ +#if 0 + KeybdCtrl *ctrl = arg; + KdKeyboardInfo *ki = NULL; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev && ki->dixdev->id == pDev->id) + break; + } + + if (!ki || !ki->dixdev || ki->dixdev->id != pDev->id || !ki->driver) + return; + + KdRingBell(ki, volume, ctrl->bell_pitch, ctrl->bell_duration); +#endif +} + +#endif /*BP*/ + +static void _dmxChangePointerControl(DMXLocalInputInfoPtr dmxLocal, + PtrCtrl *ctrl) +{ + if (!dmxLocal) return; + dmxLocal->mctrl = *ctrl; + if (dmxLocal->mCtrl) dmxLocal->mCtrl(&dmxLocal->pDevice->public, ctrl); +} + +/** Change the pointer control information for the \a pDevice. If the + * device sends core events, then also change the control information + * for all of the pointer devices that send core events. */ +void dmxChangePointerControl(DeviceIntPtr pDevice, PtrCtrl *ctrl) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxChangePointerControl(dmxInput->devs[j], ctrl); + } + } else { /* Do for this device only */ + _dmxChangePointerControl(dmxLocal, ctrl); + } +} + +static void _dmxKeyboardKbdCtrlProc(DMXLocalInputInfoPtr dmxLocal, + KeybdCtrl *ctrl) +{ + dmxLocal->kctrl = *ctrl; + if (dmxLocal->kCtrl) { + dmxLocal->kCtrl(&dmxLocal->pDevice->public, ctrl); + if (dmxLocal->pDevice->kbdfeed) { + XkbEventCauseRec cause; + XkbSetCauseUnknown(&cause); + /* Generate XKB events, as necessary */ + XkbUpdateIndicators(dmxLocal->pDevice, XkbAllIndicatorsMask, False, + NULL, &cause); + } + } +} + + +/** Change the keyboard control information for the \a pDevice. If the + * device sends core events, then also change the control information + * for all of the keyboard devices that send core events. */ +void dmxKeyboardKbdCtrlProc(DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxKeyboardKbdCtrlProc(dmxInput->devs[j], ctrl); + } + } else { /* Do for this device only */ + _dmxKeyboardKbdCtrlProc(dmxLocal, ctrl); + } +} + +static void _dmxKeyboardBellProc(DMXLocalInputInfoPtr dmxLocal, int percent) +{ + if (dmxLocal->kBell) dmxLocal->kBell(&dmxLocal->pDevice->public, + percent, + dmxLocal->kctrl.bell, + dmxLocal->kctrl.bell_pitch, + dmxLocal->kctrl.bell_duration); +} + +/** Sound the bell on the device. If the device send core events, then + * sound the bell on all of the devices that send core events. */ +void dmxKeyboardBellProc(int percent, DeviceIntPtr pDevice, + pointer ctrl, int unknown) +{ + GETDMXLOCALFROMPDEVICE; + int i, j; + + if (dmxLocal->sendsCore) { /* Do for all core devices */ + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->detached) continue; + for (j = 0; j < dmxInput->numDevs; j++) + if (dmxInput->devs[j]->sendsCore) + _dmxKeyboardBellProc(dmxInput->devs[j], percent); + } + } else { /* Do for this device only */ + _dmxKeyboardBellProc(dmxLocal, percent); + } +} + +static void dmxKeyboardFreeNames(XkbComponentNamesPtr names) +{ + if (names->keycodes) XFree(names->keycodes); + if (names->types) XFree(names->types); + if (names->compat) XFree(names->compat); + if (names->symbols) XFree(names->symbols); + if (names->geometry) XFree(names->geometry); +} + + +static int dmxKeyboardOn(DeviceIntPtr pDevice, DMXLocalInitInfo *info) +{ + GETDMXINPUTFROMPDEVICE; + XkbRMLVOSet rmlvo; + + rmlvo.rules = dmxConfigGetXkbRules(); + rmlvo.model = dmxConfigGetXkbModel(); + rmlvo.layout = dmxConfigGetXkbLayout(); + rmlvo.variant = dmxConfigGetXkbVariant(); + rmlvo.options = dmxConfigGetXkbOptions(); + + XkbSetRulesDflts(&rmlvo); + if (!info->force && (dmxInput->keycodes + || dmxInput->symbols + || dmxInput->geometry)) { + if (info->freenames) dmxKeyboardFreeNames(&info->names); + info->freenames = 0; + info->names.keycodes = dmxInput->keycodes; + info->names.types = NULL; + info->names.compat = NULL; + info->names.symbols = dmxInput->symbols; + info->names.geometry = dmxInput->geometry; + + dmxLogInput(dmxInput, "XKEYBOARD: From command line: %s", + info->names.keycodes); + if (info->names.symbols && *info->names.symbols) + dmxLogInputCont(dmxInput, " %s", info->names.symbols); + if (info->names.geometry && *info->names.geometry) + dmxLogInputCont(dmxInput, " %s", info->names.geometry); + dmxLogInputCont(dmxInput, "\n"); + } else if (info->names.keycodes) { + dmxLogInput(dmxInput, "XKEYBOARD: From device: %s", + info->names.keycodes); + if (info->names.symbols && *info->names.symbols) + dmxLogInputCont(dmxInput, " %s", info->names.symbols); + if (info->names.geometry && *info->names.geometry) + dmxLogInputCont(dmxInput, " %s", info->names.geometry); + dmxLogInputCont(dmxInput, "\n"); + } else { + dmxLogInput(dmxInput, "XKEYBOARD: Defaults: %s %s %s %s %s\n", + dmxConfigGetXkbRules(), + dmxConfigGetXkbLayout(), + dmxConfigGetXkbModel(), + dmxConfigGetXkbVariant() + ? dmxConfigGetXkbVariant() : "", + dmxConfigGetXkbOptions() + ? dmxConfigGetXkbOptions() : ""); + } + InitKeyboardDeviceStruct(pDevice, &rmlvo, + dmxKeyboardBellProc, + dmxKeyboardKbdCtrlProc); + + if (info->freenames) dmxKeyboardFreeNames(&info->names); + + return Success; +} + + +static int dmxDeviceOnOff(DeviceIntPtr pDevice, int what) +{ + GETDMXINPUTFROMPDEVICE; + int fd; + DMXLocalInitInfo info; + int i; + Atom btn_labels[MAX_BUTTONS] = {0}; /* FIXME */ + Atom axis_labels[MAX_VALUATORS] = {0}; /* FIXME */ + + if (dmxInput->detached) return Success; + + memset(&info, 0, sizeof(info)); + switch (what) { + case DEVICE_INIT: + if (dmxLocal->init) + dmxLocal->init(pDev); + if (dmxLocal->get_info) + dmxLocal->get_info(pDev, &info); + if (info.keyboard) { /* XKEYBOARD makes this a special case */ + dmxKeyboardOn(pDevice, &info); + break; + } + if (info.keyClass) { + XkbRMLVOSet rmlvo; + + rmlvo.rules = dmxConfigGetXkbRules(); + rmlvo.model = dmxConfigGetXkbModel(); + rmlvo.layout = dmxConfigGetXkbLayout(); + rmlvo.variant = dmxConfigGetXkbVariant(); + rmlvo.options = dmxConfigGetXkbOptions(); + + InitKeyboardDeviceStruct(pDevice, + &rmlvo, + dmxBell, dmxKbdCtrl); + } + if (info.buttonClass) { + InitButtonClassDeviceStruct(pDevice, info.numButtons, + btn_labels, info.map); + } + if (info.valuatorClass) { + if (info.numRelAxes && dmxLocal->sendsCore) { + InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, + axis_labels, + GetMaximumEventsNum(), + Relative); + for (i = 0; i < info.numRelAxes; i++) + InitValuatorAxisStruct(pDevice, i, axis_labels[i], + info.minval[i], info.maxval[i], + info.res[i], + info.minres[i], info.maxres[i]); + } else if (info.numRelAxes) { + InitValuatorClassDeviceStruct(pDevice, info.numRelAxes, + axis_labels, + dmxPointerGetMotionBufferSize(), + Relative); + for (i = 0; i < info.numRelAxes; i++) + InitValuatorAxisStruct(pDevice, i, axis_labels[i], + info.minval[i], + info.maxval[i], info.res[i], + info.minres[i], info.maxres[i]); + } else if (info.numAbsAxes) { + InitValuatorClassDeviceStruct(pDevice, info.numAbsAxes, + axis_labels, + dmxPointerGetMotionBufferSize(), + Absolute); + for (i = 0; i < info.numAbsAxes; i++) + InitValuatorAxisStruct(pDevice, i, + axis_labels[i], + info.minval[i], info.maxval[i], + info.res[i], info.minres[i], + info.maxres[i]); + } + } + if (info.focusClass) InitFocusClassDeviceStruct(pDevice); + if (info.proximityClass) InitProximityClassDeviceStruct(pDevice); + if (info.ptrFeedbackClass) + InitPtrFeedbackClassDeviceStruct(pDevice, dmxChangePointerControl); + if (info.intFeedbackClass || info.strFeedbackClass) + dmxLog(dmxWarning, + "Integer and string feedback not supported for %s\n", + pDevice->name); + if (!info.keyboard && (info.ledFeedbackClass || info.belFeedbackClass)) + dmxLog(dmxWarning, + "Led and bel feedback not supported for non-keyboard %s\n", + pDevice->name); + break; + case DEVICE_ON: + if (!pDev->on) { + if (dmxLocal->on && (fd = dmxLocal->on(pDev)) >= 0) + dmxSigioRegister(dmxInput, fd); + pDev->on = TRUE; + } + break; + case DEVICE_OFF: + case DEVICE_CLOSE: + /* This can get called twice consecutively: once for a + * detached screen (DEVICE_OFF), and then again at server + * generation time (DEVICE_CLOSE). */ + if (pDev->on) { + dmxSigioUnregister(dmxInput); + if (dmxLocal->off) dmxLocal->off(pDev); + pDev->on = FALSE; + } + break; + } + if (info.keySyms.map && info.freemap) { + XFree(info.keySyms.map); + info.keySyms.map = NULL; + } + if (info.xkb) XkbFreeKeyboard(info.xkb, 0, True); + return Success; +} + +static void dmxProcessInputEvents(DMXInputInfo *dmxInput) +{ + int i; + + mieqProcessInputEvents(); +#if 00 /*BP*/ + miPointerUpdate(); +#endif + if (dmxInput->detached) + 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); + } + +#if 11 /*BP*/ + mieqProcessInputEvents(); +#endif +} + +static void dmxUpdateWindowInformation(DMXInputInfo *dmxInput, + DMXUpdateType type, + WindowPtr pWindow) +{ + int i; + +#ifdef PANORAMIX + if (!noPanoramiXExtension && pWindow && pWindow->parent != WindowTable[0]) + return; +#endif +#if DMX_WINDOW_DEBUG + { + const char *name = "Unknown"; + switch (type) { + case DMX_UPDATE_REALIZE: name = "Realize"; break; + case DMX_UPDATE_UNREALIZE: name = "Unrealize"; break; + case DMX_UPDATE_RESTACK: name = "Restack"; break; + case DMX_UPDATE_COPY: name = "Copy"; break; + case DMX_UPDATE_RESIZE: name = "Resize"; break; + case DMX_UPDATE_REPARENT: name = "Repaint"; break; + } + dmxLog(dmxDebug, "Window %p changed: %s\n", pWindow, name); + } +#endif + + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->update_info) + dmxInput->devs[i]->update_info(dmxInput->devs[i]->private, + type, pWindow); +} + +static void dmxCollectAll(DMXInputInfo *dmxInput) +{ + int i; + + if (dmxInput->detached) + return; + for (i = 0; i < dmxInput->numDevs; i += dmxInput->devs[i]->binding) + if (dmxInput->devs[i]->collect_events) + dmxInput->devs[i]->collect_events(&dmxInput->devs[i]->pDevice->public, + dmxMotion, + dmxEnqueue, + dmxCheckSpecialKeys, DMX_BLOCK); +} + +static void dmxBlockHandler(pointer blockData, OSTimePtr pTimeout, + pointer pReadMask) +{ + DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; + static unsigned long generation = 0; + + if (generation != serverGeneration) { + generation = serverGeneration; + dmxCollectAll(dmxInput); + } +} + +static void dmxSwitchReturn(pointer p) +{ + DMXInputInfo *dmxInput = p; + int i; + + dmxLog(dmxInfo, "Returning from VT %d\n", dmxInput->vt_switched); + + if (!dmxInput->vt_switched) + dmxLog(dmxFatal, "dmxSwitchReturn called, but not switched\n"); + dmxSigioEnableInput(); + for (i = 0; i < dmxInput->numDevs; i++) + if (dmxInput->devs[i]->vt_post_switch) + dmxInput->devs[i]->vt_post_switch(dmxInput->devs[i]->private); + dmxInput->vt_switched = 0; +} + +static void dmxWakeupHandler(pointer blockData, int result, pointer pReadMask) +{ + DMXInputInfo *dmxInput = &dmxInputs[(int)blockData]; + int i; + + if (dmxInput->vt_switch_pending) { + dmxLog(dmxInfo, "Switching to VT %d\n", dmxInput->vt_switch_pending); + for (i = 0; i < dmxInput->numDevs; i++) + if (dmxInput->devs[i]->vt_pre_switch) + dmxInput->devs[i]->vt_pre_switch(dmxInput->devs[i]->private); + dmxInput->vt_switched = dmxInput->vt_switch_pending; + dmxInput->vt_switch_pending = 0; + for (i = 0; i < dmxInput->numDevs; i++) { + if (dmxInput->devs[i]->vt_switch) { + dmxSigioDisableInput(); + if (!dmxInput->devs[i]->vt_switch(dmxInput->devs[i]->private, + dmxInput->vt_switched, + dmxSwitchReturn, + dmxInput)) + dmxSwitchReturn(dmxInput); + break; /* Only call one vt_switch routine */ + } + } + } + dmxCollectAll(dmxInput); +} + +static char *dmxMakeUniqueDeviceName(DMXLocalInputInfoPtr dmxLocal) +{ + static int k = 0; + static int m = 0; + static int o = 0; + static unsigned long dmxGeneration = 0; +#define LEN 32 + char * buf = malloc(LEN); + + if (dmxGeneration != serverGeneration) { + k = m = o = 0; + dmxGeneration = serverGeneration; + } + + switch (dmxLocal->type) { + case DMX_LOCAL_KEYBOARD: XmuSnprintf(buf, LEN, "Keyboard%d", k++); break; + case DMX_LOCAL_MOUSE: XmuSnprintf(buf, LEN, "Mouse%d", m++); break; + default: XmuSnprintf(buf, LEN, "Other%d", o++); break; + } + + return buf; +} + +static DeviceIntPtr dmxAddDevice(DMXLocalInputInfoPtr dmxLocal) +{ + DeviceIntPtr pDevice; + Atom atom; + const char *name = NULL; + void (*registerProcPtr)(DeviceIntPtr) = NULL; + char *devname; + DMXInputInfo *dmxInput; + + if (!dmxLocal) + return NULL; + dmxInput = &dmxInputs[dmxLocal->inputIdx]; + + if (dmxLocal->sendsCore) { + if (dmxLocal->type == DMX_LOCAL_KEYBOARD && !dmxLocalCoreKeyboard) { + dmxLocal->isCore = 1; + dmxLocalCoreKeyboard = dmxLocal; + name = "keyboard"; + registerProcPtr = RegisterKeyboardDevice; + } + if (dmxLocal->type == DMX_LOCAL_MOUSE && !dmxLocalCorePointer) { + dmxLocal->isCore = 1; + dmxLocalCorePointer = dmxLocal; + name = "pointer"; + registerProcPtr = RegisterPointerDevice; + } + } + + if (!name) { + name = "extension"; + registerProcPtr = RegisterOtherDevice; + } + + if (!name || !registerProcPtr) + dmxLog(dmxFatal, "Cannot add device %s\n", dmxLocal->name); + + pDevice = AddInputDevice(serverClient, dmxDeviceOnOff, TRUE); + if (!pDevice) { + dmxLog(dmxError, "Too many devices -- cannot add device %s\n", + dmxLocal->name); + return NULL; + } + pDevice->public.devicePrivate = dmxLocal; + dmxLocal->pDevice = pDevice; + + devname = dmxMakeUniqueDeviceName(dmxLocal); + atom = MakeAtom((char *)devname, strlen(devname), TRUE); + pDevice->type = atom; + pDevice->name = devname; + + registerProcPtr(pDevice); + + if (dmxLocal->isCore && dmxLocal->type == DMX_LOCAL_MOUSE) { +#if 00 /*BP*/ + miRegisterPointerDevice(screenInfo.screens[0], pDevice); +#else + /* Nothing? dmxDeviceOnOff() should get called to init, right? */ +#endif + } + + if (dmxLocal->create_private) + dmxLocal->private = dmxLocal->create_private(pDevice); + + dmxLogInput(dmxInput, "Added %s as %s device called %s%s\n", + dmxLocal->name, name, devname, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + + return pDevice; +} + +static DMXLocalInputInfoPtr dmxLookupLocal(const char *name) +{ + DMXLocalInputInfoPtr pt; + + for (pt = &DMXLocalDevices[0]; pt->name; ++pt) + if (!strcmp(pt->name, name)) return pt; /* search for device name */ + return NULL; +} + +/** Copy the local input information from \a s into a new \a devs slot + * in \a dmxInput. */ +DMXLocalInputInfoPtr dmxInputCopyLocal(DMXInputInfo *dmxInput, + DMXLocalInputInfoPtr s) +{ + DMXLocalInputInfoPtr dmxLocal = malloc(sizeof(*dmxLocal)); + + if (!dmxLocal) + dmxLog(dmxFatal, "DMXLocalInputInfoPtr: out of memory\n"); + + memcpy(dmxLocal, s, sizeof(*dmxLocal)); + dmxLocal->inputIdx = dmxInput->inputIdx; + dmxLocal->sendsCore = dmxInput->core; + dmxLocal->savedSendsCore = dmxInput->core; + dmxLocal->deviceId = -1; + + ++dmxInput->numDevs; + dmxInput->devs = realloc(dmxInput->devs, + dmxInput->numDevs * sizeof(*dmxInput->devs)); + dmxInput->devs[dmxInput->numDevs-1] = dmxLocal; + + return dmxLocal; +} + +static void dmxPopulateLocal(DMXInputInfo *dmxInput, dmxArg a) +{ + int i; + int help = 0; + DMXLocalInputInfoRec *pt; + + for (i = 1; i < dmxArgC(a); i++) { + const char *name = dmxArgV(a, i); + if ((pt = dmxLookupLocal(name))) { + dmxInputCopyLocal(dmxInput, pt); + } else { + if (strlen(name)) + dmxLog(dmxWarning, + "Could not find a driver called %s\n", name); + ++help; + } + } + if (help) { + dmxLog(dmxInfo, "Available local device drivers:\n"); + for (pt = &DMXLocalDevices[0]; pt->name; ++pt) { + const char *type; + switch (pt->type) { + case DMX_LOCAL_KEYBOARD: type = "keyboard"; break; + case DMX_LOCAL_MOUSE: type = "pointer"; break; + default: type = "unknown"; break; + } + dmxLog(dmxInfo, " %s (%s)\n", pt->name, type); + } + dmxLog(dmxFatal, "Must have valid local device driver\n"); + } +} + +int dmxInputExtensionErrorHandler(Display *dsp, char *name, char *reason) +{ + return 0; +} + +static void dmxInputScanForExtensions(DMXInputInfo *dmxInput, int doXI) +{ + XExtensionVersion *ext; + XDeviceInfo *devices; + Display *display; + int num; + int i, j; + DMXLocalInputInfoPtr dmxLocal; + int (*handler)(Display *, char *, char *); + + if (!(display = XOpenDisplay(dmxInput->name))) return; + + /* Print out information about the XInput Extension. */ + handler = XSetExtensionErrorHandler(dmxInputExtensionErrorHandler); + ext = XGetExtensionVersion(display, INAME); + XSetExtensionErrorHandler(handler); + + if (!ext || ext == (XExtensionVersion *)NoSuchExtension) { + dmxLogInput(dmxInput, "%s is not available\n", INAME); + } else { + dmxLogInput(dmxInput, "Locating devices on %s (%s version %d.%d)\n", + dmxInput->name, INAME, + ext->major_version, ext->minor_version); + devices = XListInputDevices(display, &num); + + XFree(ext); + ext = NULL; + + /* Print a list of all devices */ + for (i = 0; i < num; i++) { + const char *use = "Unknown"; + switch (devices[i].use) { + case IsXPointer: use = "XPointer"; break; + case IsXKeyboard: use = "XKeyboard"; break; + case IsXExtensionDevice: use = "XExtensionDevice"; break; + case IsXExtensionPointer: use = "XExtensionPointer"; break; + case IsXExtensionKeyboard: use = "XExtensionKeyboard"; break; + } + dmxLogInput(dmxInput, " %2d %-10.10s %-16.16s\n", + devices[i].id, + devices[i].name ? devices[i].name : "", + use); + } + + /* Search for extensions */ + for (i = 0; i < num; i++) { + switch (devices[i].use) { + case IsXKeyboard: + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; + if (dmxL->type == DMX_LOCAL_KEYBOARD + && dmxL->deviceId < 0) { + dmxL->deviceId = devices[i].id; + dmxL->deviceName = (devices[i].name + ? xstrdup(devices[i].name) + : NULL); + } + } + break; + case IsXPointer: + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxL = dmxInput->devs[j]; + if (dmxL->type == DMX_LOCAL_MOUSE && dmxL->deviceId < 0) { + dmxL->deviceId = devices[i].id; + dmxL->deviceName = (devices[i].name + ? xstrdup(devices[i].name) + : NULL); + } + } + break; +#if 0 + case IsXExtensionDevice: + case IsXExtensionKeyboard: + case IsXExtensionPointer: + if (doXI) { + if (!dmxInput->numDevs) { + dmxLog(dmxWarning, + "Cannot use remote (%s) XInput devices if" + " not also using core devices\n", + dmxInput->name); + } else { + dmxLocal = dmxInputCopyLocal(dmxInput, + &DMXCommonOth); + dmxLocal->isCore = FALSE; + dmxLocal->sendsCore = FALSE; + dmxLocal->deviceId = devices[i].id; + dmxLocal->deviceName = (devices[i].name + ? xstrdup(devices[i].name) + : NULL); + } + } + break; +#endif + } + } + XFreeDeviceList(devices); + } + XCloseDisplay(display); +} + +/** Re-initialize all the devices described in \a dmxInput. Called from + #dmxAdjustCursorBoundaries before the cursor is redisplayed. */ +void dmxInputReInit(DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (dmxLocal->reinit) + dmxLocal->reinit(&dmxLocal->pDevice->public); + } +} + +/** Re-initialize all the devices described in \a dmxInput. Called from + #dmxAdjustCursorBoundaries after the cursor is redisplayed. */ +void dmxInputLateReInit(DMXInputInfo *dmxInput) +{ + int i; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (dmxLocal->latereinit) + dmxLocal->latereinit(&dmxLocal->pDevice->public); + } +} + +/** Initialize all of the devices described in \a dmxInput. */ +void dmxInputInit(DMXInputInfo *dmxInput) +{ + DeviceIntPtr pPointer = NULL, pKeyboard = NULL; + dmxArg a; + const char *name; + int i; + int doXI = 1; /* Include by default */ + int forceConsole = 0; + int doWindows = 1; /* On by default */ + int hasXkb = 0; + + a = dmxArgParse(dmxInput->name); + + for (i = 1; i < dmxArgC(a); i++) { + switch (hasXkb) { + case 1: + dmxInput->keycodes = xstrdup(dmxArgV(a, i)); + ++hasXkb; + break; + case 2: + dmxInput->symbols = xstrdup(dmxArgV(a, i)); + ++hasXkb; + break; + case 3: + dmxInput->geometry = xstrdup(dmxArgV(a, i)); + hasXkb = 0; + break; + case 0: + if (!strcmp(dmxArgV(a, i), "noxi")) doXI = 0; + else if (!strcmp(dmxArgV(a, i), "xi")) doXI = 1; + else if (!strcmp(dmxArgV(a, i), "console")) forceConsole = 1; + else if (!strcmp(dmxArgV(a, i), "noconsole")) forceConsole = 0; + else if (!strcmp(dmxArgV(a, i), "windows")) doWindows = 1; + else if (!strcmp(dmxArgV(a, i), "nowindows")) doWindows = 0; + else if (!strcmp(dmxArgV(a, i), "xkb")) hasXkb = 1; + else { + dmxLog(dmxFatal, + "Unknown input argument: %s\n", dmxArgV(a, i)); + } + } + } + + name = dmxArgV(a, 0); + + if (!strcmp(name, "local")) { + dmxPopulateLocal(dmxInput, a); + } else if (!strcmp(name, "dummy")) { + dmxInputCopyLocal(dmxInput, &DMXDummyMou); + dmxInputCopyLocal(dmxInput, &DMXDummyKbd); + dmxLogInput(dmxInput, "Using dummy input\n"); + } else { + int found; + + for (found = 0, i = 0; i < dmxNumScreens; i++) { + if (dmxPropertySameDisplay(&dmxScreens[i], name)) { + if (dmxScreens[i].shared) + dmxLog(dmxFatal, + "Cannot take input from shared backend (%s)\n", + name); + if (!dmxInput->core) { + dmxLog(dmxWarning, + "Cannot use core devices on a backend (%s)" + " as XInput devices\n", name); + } else { + char *pt; + for (pt = (char *)dmxInput->name; pt && *pt; pt++) + if (*pt == ',') *pt = '\0'; + dmxInputCopyLocal(dmxInput, &DMXBackendMou); + dmxInputCopyLocal(dmxInput, &DMXBackendKbd); + dmxInput->scrnIdx = i; + dmxLogInput(dmxInput, + "Using backend input from %s\n", name); + } + ++found; + break; + } + } + if (!found || forceConsole) { + char *pt; + if (found) dmxInput->console = TRUE; + for (pt = (char *)dmxInput->name; pt && *pt; pt++) + if (*pt == ',') *pt = '\0'; + dmxInputCopyLocal(dmxInput, &DMXConsoleMou); + dmxInputCopyLocal(dmxInput, &DMXConsoleKbd); + if (doWindows) { + dmxInput->windows = TRUE; + dmxInput->updateWindowInfo = dmxUpdateWindowInformation; + } + dmxLogInput(dmxInput, + "Using console input from %s (%s windows)\n", + name, doWindows ? "with" : "without"); + } + } + + dmxArgFree(a); + + /* Locate extensions we may be interested in */ + dmxInputScanForExtensions(dmxInput, doXI); + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + dmxLocal->pDevice = dmxAddDevice(dmxLocal); + if (dmxLocal->isCore) { + if (dmxLocal->type == DMX_LOCAL_MOUSE) + pPointer = dmxLocal->pDevice; + if (dmxLocal->type == DMX_LOCAL_KEYBOARD) + pKeyboard = dmxLocal->pDevice; + } + } + + dmxInput->processInputEvents = dmxProcessInputEvents; + dmxInput->detached = False; + + RegisterBlockAndWakeupHandlers(dmxBlockHandler, + dmxWakeupHandler, + (void *)dmxInput->inputIdx); +} + +static void dmxInputFreeLocal(DMXLocalInputInfoRec *local) +{ + if (!local) return; + if (local->isCore && local->type == DMX_LOCAL_MOUSE) + dmxLocalCorePointer = NULL; + if (local->isCore && local->type == DMX_LOCAL_KEYBOARD) + dmxLocalCoreKeyboard = NULL; + if (local->destroy_private) local->destroy_private(local->private); + if (local->history) free(local->history); + if (local->valuators) free(local->valuators); + if (local->deviceName) free(local->deviceName); + local->private = NULL; + local->history = NULL; + local->deviceName = NULL; + free(local); +} + +/** Free all of the memory associated with \a dmxInput */ +void dmxInputFree(DMXInputInfo *dmxInput) +{ + int i; + + if (!dmxInput) return; + + if (dmxInput->keycodes) free(dmxInput->keycodes); + if (dmxInput->symbols) free(dmxInput->symbols); + if (dmxInput->geometry) free(dmxInput->geometry); + + for (i = 0; i < dmxInput->numDevs; i++) { + dmxInputFreeLocal(dmxInput->devs[i]); + dmxInput->devs[i] = NULL; + } + free(dmxInput->devs); + dmxInput->devs = NULL; + dmxInput->numDevs = 0; + if (dmxInput->freename) free(dmxInput->name); + dmxInput->name = NULL; +} + +/** Log information about all of the known devices using #dmxLog(). */ +void dmxInputLogDevices(void) +{ + int i, j; + + dmxLog(dmxInfo, "%d devices:\n", dmxGetInputCount()); + dmxLog(dmxInfo, " Id Name Classes\n"); + for (j = 0; j < dmxNumInputs; j++) { + DMXInputInfo *dmxInput = &dmxInputs[j]; + const char *pt = strchr(dmxInput->name, ','); + int len = (pt + ? (size_t)(pt-dmxInput->name) + : strlen(dmxInput->name)); + + for (i = 0; i < dmxInput->numDevs; i++) { + DeviceIntPtr pDevice = dmxInput->devs[i]->pDevice; + if (pDevice) { + dmxLog(dmxInfo, " %2d%c %-20.20s", + pDevice->id, + dmxInput->detached ? 'D' : ' ', + pDevice->name); + if (pDevice->key) dmxLogCont(dmxInfo, " key"); + if (pDevice->valuator) dmxLogCont(dmxInfo, " val"); + if (pDevice->button) dmxLogCont(dmxInfo, " btn"); + if (pDevice->focus) dmxLogCont(dmxInfo, " foc"); + if (pDevice->kbdfeed) dmxLogCont(dmxInfo, " fb/kbd"); + if (pDevice->ptrfeed) dmxLogCont(dmxInfo, " fb/ptr"); + if (pDevice->intfeed) dmxLogCont(dmxInfo, " fb/int"); + if (pDevice->stringfeed) dmxLogCont(dmxInfo, " fb/str"); + if (pDevice->bell) dmxLogCont(dmxInfo, " fb/bel"); + if (pDevice->leds) dmxLogCont(dmxInfo, " fb/led"); + if (!pDevice->key && !pDevice->valuator && !pDevice->button + && !pDevice->focus && !pDevice->kbdfeed + && !pDevice->ptrfeed && !pDevice->intfeed + && !pDevice->stringfeed && !pDevice->bell + && !pDevice->leds) dmxLogCont(dmxInfo, " (none)"); + + dmxLogCont(dmxInfo, "\t[i%d/%*.*s", + dmxInput->inputIdx, len, len, dmxInput->name); + if (dmxInput->devs[i]->deviceId >= 0) + dmxLogCont(dmxInfo, "/id%d", dmxInput->devs[i]->deviceId); + if (dmxInput->devs[i]->deviceName) + dmxLogCont(dmxInfo, "=%s", dmxInput->devs[i]->deviceName); + dmxLogCont(dmxInfo, "] %s\n", + dmxInput->devs[i]->isCore + ? "core" + : (dmxInput->devs[i]->sendsCore + ? "extension (sends core events)" + : "extension")); + } + } + } +} + +/** Detach an input */ +int dmxInputDetach(DMXInputInfo *dmxInput) +{ + int i; + + if (dmxInput->detached) return BadAccess; + + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + dmxLogInput(dmxInput, "Detaching device id %d: %s%s\n", + dmxLocal->pDevice->id, + dmxLocal->pDevice->name, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + DisableDevice(dmxLocal->pDevice, TRUE); + } + dmxInput->detached = True; + dmxInputLogDevices(); + return 0; +} + +/** Search for input associated with \a dmxScreen, and detach. */ +void dmxInputDetachAll(DMXScreenInfo *dmxScreen) +{ + int i; + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx == dmxScreen->index) dmxInputDetach(dmxInput); + } +} + +/** Search for input associated with \a deviceId, and detach. */ +int dmxInputDetachId(int id) +{ + DMXInputInfo *dmxInput = dmxInputLocateId(id); + + if (!dmxInput) return BadValue; + + return dmxInputDetach(dmxInput); +} + +DMXInputInfo *dmxInputLocateId(int id) +{ + int i, j; + + for (i = 0; i < dmxNumInputs; i++) { + DMXInputInfo *dmxInput = &dmxInputs[i]; + for (j = 0; j < dmxInput->numDevs; j++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; + if (dmxLocal->pDevice->id == id) return dmxInput; + } + } + return NULL; +} + +static int dmxInputAttachNew(DMXInputInfo *dmxInput, int *id) +{ + dmxInputInit(dmxInput); + InitAndStartDevices(); + if (id && dmxInput->devs) *id = dmxInput->devs[0]->pDevice->id; + dmxInputLogDevices(); + return 0; +} + +static int dmxInputAttachOld(DMXInputInfo *dmxInput, int *id) +{ + int i; + + dmxInput->detached = False; + for (i = 0; i < dmxInput->numDevs; i++) { + DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[i]; + if (id) *id = dmxLocal->pDevice->id; + dmxLogInput(dmxInput, + "Attaching device id %d: %s%s\n", + dmxLocal->pDevice->id, + dmxLocal->pDevice->name, + dmxLocal->isCore + ? " [core]" + : (dmxLocal->sendsCore + ? " [sends core events]" + : "")); + EnableDevice(dmxLocal->pDevice, TRUE); + } + dmxInputLogDevices(); + return 0; +} + +int dmxInputAttachConsole(const char *name, int isCore, int *id) +{ + DMXInputInfo *dmxInput; + int i; + + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx == -1 + && dmxInput->detached + && !strcmp(dmxInput->name, name)) { + /* Found match */ + dmxLogInput(dmxInput, "Reattaching detached console input\n"); + return dmxInputAttachOld(dmxInput, id); + } + } + + /* No match found */ + dmxInput = dmxConfigAddInput(xstrdup(name), isCore); + dmxInput->freename = TRUE; + dmxLogInput(dmxInput, "Attaching new console input\n"); + return dmxInputAttachNew(dmxInput, id); +} + +int dmxInputAttachBackend(int physicalScreen, int isCore, int *id) +{ + DMXInputInfo *dmxInput; + DMXScreenInfo *dmxScreen; + int i; + + if (physicalScreen < 0 || physicalScreen >= dmxNumScreens) return BadValue; + for (i = 0; i < dmxNumInputs; i++) { + dmxInput = &dmxInputs[i]; + if (dmxInput->scrnIdx != -1 && dmxInput->scrnIdx == physicalScreen) { + /* Found match */ + if (!dmxInput->detached) return BadAccess; /* Already attached */ + dmxScreen = &dmxScreens[physicalScreen]; + if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ + dmxLogInput(dmxInput, "Reattaching detached backend input\n"); + return dmxInputAttachOld(dmxInput, id); + } + } + /* No match found */ + dmxScreen = &dmxScreens[physicalScreen]; + if (!dmxScreen->beDisplay) return BadAccess; /* Screen detached */ + dmxInput = dmxConfigAddInput(dmxScreen->name, isCore); + dmxLogInput(dmxInput, "Attaching new backend input\n"); + return dmxInputAttachNew(dmxInput, id); +} diff --git a/xorg-server/hw/dmx/input/dmxmotion.c b/xorg-server/hw/dmx/input/dmxmotion.c index 73580a215..d1c79f126 100644 --- a/xorg-server/hw/dmx/input/dmxmotion.c +++ b/xorg-server/hw/dmx/input/dmxmotion.c @@ -1,142 +1,142 @@ -/* - * Copyright 2002-2003 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: - * Rickard E. (Rik) Faith <faith@redhat.com> - * - */ - -/** \file - * This file provides functions similar to miPointerGetMotionEvents and - * miPointerPutMotionEvents, with the exception that devices with more - * than two axes are fully supported. These routines may be used only - * for motion buffers for extension devices, and are \a not compatible - * replacements for the mi routines. */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "inputstr.h" -#include "dmxinputinit.h" -#include "dmxcommon.h" -#include "dmxmotion.h" - -#define OFFSET(offset,element) ((offset) * (numAxes + 1) + (element)) - -/** Return size of motion buffer. \see DMX_MOTION_SIZE */ -int dmxPointerGetMotionBufferSize(void) -{ - return DMX_MOTION_SIZE; -} - -/** This routine performs the same function as \a miPointerGetMotionEvents: - * the events in the motion history that are between the start and stop - * times (in mS) are placed in the coords vector, and the count of the - * number of items so placed is returned. This routine is called from - * dix/devices.c so that coords can hold valuator->numMotionEvents - * events. This routine is called from \a Xi/gtmotion.c with coords large - * enough to hold the same number of events in a variable-length - * extended \a xTimecoord structure. This provides sufficient data for the - * \a XGetDeviceMotionEvents library call, and would be identical to - * \a miPointerGetMotionEvents for devices with only 2 axes (i.e., core - * pointers) if \a xTimecoord used 32bit integers. - * - * Because DMX uses the mi* routines for all core devices, this routine - * only has to support extension devices using the polymorphic coords. - * Because compatibility with miPointerGetMotionEvents is not possible, - * it is not provided. */ -int dmxPointerGetMotionEvents(DeviceIntPtr pDevice, - xTimecoord *coords, - unsigned long start, - unsigned long stop, - ScreenPtr pScreen) -{ - GETDMXLOCALFROMPDEVICE; - int numAxes = pDevice->valuator->numAxes; - unsigned long *c = (unsigned long *)coords; - int count = 0; - int i, j; - - if (!dmxLocal->history) return 0; - for (i = dmxLocal->head; i != dmxLocal->tail;) { - if (dmxLocal->history[OFFSET(i,0)] >= stop) break; - if (dmxLocal->history[OFFSET(i,0)] >= start) { - for (j = 0; j < numAxes + 1; j++) - c[OFFSET(count,j)] = dmxLocal->history[OFFSET(i,j)]; - ++count; - } - if (++i >= DMX_MOTION_SIZE) i = 0; - } - return count; -} - -/** This routine adds an event to the motion history. A similar - * function is performed by miPointerMove for the mi versions of these - * routines. */ -void dmxPointerPutMotionEvent(DeviceIntPtr pDevice, - int firstAxis, int axesCount, int *v, - unsigned long time) -{ - GETDMXLOCALFROMPDEVICE; - int numAxes = pDevice->valuator->numAxes; - int i; - - if (!dmxLocal->history) { - dmxLocal->history = xalloc(sizeof(*dmxLocal->history) - * (numAxes + 1) - * DMX_MOTION_SIZE); - dmxLocal->head = 0; - dmxLocal->tail = 0; - dmxLocal->valuators = calloc(sizeof(*dmxLocal->valuators), numAxes); - } else { - if (++dmxLocal->tail >= DMX_MOTION_SIZE) dmxLocal->tail = 0; - if (dmxLocal->head == dmxLocal->tail) - if (++dmxLocal->head >= DMX_MOTION_SIZE) dmxLocal->head = 0; - } - - dmxLocal->history[OFFSET(dmxLocal->tail,0)] = time; - - /* Initialize the data from the known - * values (if Absolute) or to zero (if - * Relative) */ - if (pDevice->valuator->mode == Absolute) { - for (i = 0; i < numAxes; i++) - dmxLocal->history[OFFSET(dmxLocal->tail,i+1)] - = dmxLocal->valuators[i]; - } else { - for (i = 0; i < numAxes; i++) - dmxLocal->history[OFFSET(dmxLocal->tail,i+1)] = 0; - } - - for (i = firstAxis; i < axesCount; i++) { - dmxLocal->history[OFFSET(dmxLocal->tail,i+i)] - = (unsigned long)v[i-firstAxis]; - dmxLocal->valuators[i] = v[i-firstAxis]; - } -} +/* + * Copyright 2002-2003 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: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * This file provides functions similar to miPointerGetMotionEvents and + * miPointerPutMotionEvents, with the exception that devices with more + * than two axes are fully supported. These routines may be used only + * for motion buffers for extension devices, and are \a not compatible + * replacements for the mi routines. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "inputstr.h" +#include "dmxinputinit.h" +#include "dmxcommon.h" +#include "dmxmotion.h" + +#define OFFSET(offset,element) ((offset) * (numAxes + 1) + (element)) + +/** Return size of motion buffer. \see DMX_MOTION_SIZE */ +int dmxPointerGetMotionBufferSize(void) +{ + return DMX_MOTION_SIZE; +} + +/** This routine performs the same function as \a miPointerGetMotionEvents: + * the events in the motion history that are between the start and stop + * times (in mS) are placed in the coords vector, and the count of the + * number of items so placed is returned. This routine is called from + * dix/devices.c so that coords can hold valuator->numMotionEvents + * events. This routine is called from \a Xi/gtmotion.c with coords large + * enough to hold the same number of events in a variable-length + * extended \a xTimecoord structure. This provides sufficient data for the + * \a XGetDeviceMotionEvents library call, and would be identical to + * \a miPointerGetMotionEvents for devices with only 2 axes (i.e., core + * pointers) if \a xTimecoord used 32bit integers. + * + * Because DMX uses the mi* routines for all core devices, this routine + * only has to support extension devices using the polymorphic coords. + * Because compatibility with miPointerGetMotionEvents is not possible, + * it is not provided. */ +int dmxPointerGetMotionEvents(DeviceIntPtr pDevice, + xTimecoord *coords, + unsigned long start, + unsigned long stop, + ScreenPtr pScreen) +{ + GETDMXLOCALFROMPDEVICE; + int numAxes = pDevice->valuator->numAxes; + unsigned long *c = (unsigned long *)coords; + int count = 0; + int i, j; + + if (!dmxLocal->history) return 0; + for (i = dmxLocal->head; i != dmxLocal->tail;) { + if (dmxLocal->history[OFFSET(i,0)] >= stop) break; + if (dmxLocal->history[OFFSET(i,0)] >= start) { + for (j = 0; j < numAxes + 1; j++) + c[OFFSET(count,j)] = dmxLocal->history[OFFSET(i,j)]; + ++count; + } + if (++i >= DMX_MOTION_SIZE) i = 0; + } + return count; +} + +/** This routine adds an event to the motion history. A similar + * function is performed by miPointerMove for the mi versions of these + * routines. */ +void dmxPointerPutMotionEvent(DeviceIntPtr pDevice, + int firstAxis, int axesCount, int *v, + unsigned long time) +{ + GETDMXLOCALFROMPDEVICE; + int numAxes = pDevice->valuator->numAxes; + int i; + + if (!dmxLocal->history) { + dmxLocal->history = malloc(sizeof(*dmxLocal->history) + * (numAxes + 1) + * DMX_MOTION_SIZE); + dmxLocal->head = 0; + dmxLocal->tail = 0; + dmxLocal->valuators = calloc(sizeof(*dmxLocal->valuators), numAxes); + } else { + if (++dmxLocal->tail >= DMX_MOTION_SIZE) dmxLocal->tail = 0; + if (dmxLocal->head == dmxLocal->tail) + if (++dmxLocal->head >= DMX_MOTION_SIZE) dmxLocal->head = 0; + } + + dmxLocal->history[OFFSET(dmxLocal->tail,0)] = time; + + /* Initialize the data from the known + * values (if Absolute) or to zero (if + * Relative) */ + if (pDevice->valuator->mode == Absolute) { + for (i = 0; i < numAxes; i++) + dmxLocal->history[OFFSET(dmxLocal->tail,i+1)] + = dmxLocal->valuators[i]; + } else { + for (i = 0; i < numAxes; i++) + dmxLocal->history[OFFSET(dmxLocal->tail,i+1)] = 0; + } + + for (i = firstAxis; i < axesCount; i++) { + dmxLocal->history[OFFSET(dmxLocal->tail,i+i)] + = (unsigned long)v[i-firstAxis]; + dmxLocal->valuators[i] = v[i-firstAxis]; + } +} diff --git a/xorg-server/hw/dmx/input/lnx-keyboard.c b/xorg-server/hw/dmx/input/lnx-keyboard.c index 939a32f07..11f21e25c 100644 --- a/xorg-server/hw/dmx/input/lnx-keyboard.c +++ b/xorg-server/hw/dmx/input/lnx-keyboard.c @@ -1,990 +1,990 @@ -/* Portions of this file were derived from the following files: - * - ********************************************************************** - * - * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c} - * - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * - * 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 Thomas Roell not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Thomas Roell makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THOMAS ROELL 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. - * - ********************************************************************** - * - * xfree86/common/xf86KbdLnx.c - * - * Linux version of keymapping setup. The kernel (since 0.99.14) has support - * for fully remapping the keyboard, but there are some differences between - * the Linux map and the SVR4 map (esp. in the extended keycodes). We also - * remove the restriction on what keycodes can be remapped. - * Orest Zborowski. - * - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * - * 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 Thomas Roell not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Thomas Roell makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THOMAS ROELL 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. - * - ********************************************************************** - * - * xfree86/os-support/linux/lnx_io.c - * - * Copyright 1992 by Orest Zborowski <obz@Kodak.com> - * Copyright 1993 by David Dawes <dawes@xfree86.org> - * - * 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 names of Orest Zborowski and David Dawes - * not be used in advertising or publicity pertaining to distribution of - * the software without specific, written prior permission. Orest Zborowski - * and David Dawes make no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * OREST ZBOROWSKI AND DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID DAWES 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. - * - */ - -/* - * Copyright 2001-2003 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: - * Rickard E. (Rik) Faith <faith@redhat.com> - * - */ - -/** \file - * - * This code implements a low-level device driver for the Linux - * keyboard. The code is derived from code by Thomas Roell, Orest - * Zborowski, and David Dawes (see the source code for complete - * references). */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -/*****************************************************************************/ -/* Define some macros to make it easier to move this file to another - * part of the Xserver tree. All calls to the dmx* layer are #defined - * here for the .c file. The .h file will also have to be edited. */ -#include "dmxinputinit.h" -#include "lnx-keyboard.h" - -#define GETPRIV myPrivate *priv \ - = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private - -#define LOG0(f) dmxLog(dmxDebug,f) -#define LOG1(f,a) dmxLog(dmxDebug,f,a) -#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define FATAL0(f) dmxLog(dmxFatal,f) -#define FATAL1(f,a) dmxLog(dmxFatal,f,a) -#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) -#define MOTIONPROC dmxMotionProcPtr -#define ENQUEUEPROC dmxEnqueueProcPtr -#define CHECKPROC dmxCheckSpecialProcPtr -#define SWITCHRETPROC dmxVTSwitchReturnProcPtr -#define BLOCK DMXBlockType -#define MESSAGE "\033c\n\n\nDMX taking input from this console..." -#define FINALMESSAGE "\033cDMX terminated." - -/* End of interface definitions. */ -/*****************************************************************************/ - -#include "inputstr.h" -#include <X11/Xos.h> -#include <sys/ioctl.h> -#include <errno.h> -#include <signal.h> -#include <sys/vt.h> -#include <sys/kd.h> -#include <termios.h> -#include "atKeynames.h" -#if 00 -#include "xf86Keymap.h" -#endif -#include <linux/keyboard.h> -#include <xkbsrv.h> - -#define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0])) -#define NUM_STATE_ENTRIES (256/32) - - -/* Private area for Linux-style keyboards. */ -typedef struct _myPrivate { - int fd; - int vtno; - int vtcurrent; - int kbdtrans; - struct termios kbdtty; - int kbdType; - CARD32 kbdState[NUM_STATE_ENTRIES]; - DeviceIntPtr pKeyboard; - unsigned char prefix; - - int switched; - SWITCHRETPROC switch_return; - void *switch_return_data; - - /* For bell */ - int pitch; - unsigned long duration; -} myPrivate; - -static myPrivate *PRIV = NULL; - -#undef SYSCALL -#define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) - -static int kbdLinuxKeyDown(myPrivate *priv, int keyCode) -{ - CARD8 byte = keyCode >> 5; - CARD32 bit = 1 << (keyCode & 0x1f); - - if (byte > NUM_STATE_ENTRIES) return 0; - return priv->kbdState[byte] & bit; -} - -static void kbdLinuxKeyState(myPrivate *priv, int type, int keyCode) -{ - CARD8 byte = keyCode >> 5; - CARD32 bit = 1 << (keyCode & 0x1f); - - if (byte > NUM_STATE_ENTRIES) return; - if (type == KeyPress) priv->kbdState[byte] |= bit; - else priv->kbdState[byte] &= ~bit; -} - -static 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 -}; - -/* - * Maps the AT keycodes to Linux keycodes - */ -static unsigned char at2lnx[NUM_KEYCODES] = -{ - 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 */ -}; - -/** Create a private structure for use within this file. */ -pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard) -{ - myPrivate *priv = calloc(1, sizeof(*priv)); - priv->fd = -1; - priv->pKeyboard = pKeyboard; - return priv; -} - -/** Destroy a private structure. */ -void kbdLinuxDestroyPrivate(pointer priv) -{ - if (priv) free(priv); -} - -/** Ring the bell. - * - * Note: we completely ignore the \a volume, since Linux's ioctl() - * interface does not provide a way to control it. If it did, the XBell - * manpage tells how the actual volume is a function of the percent and - * the (base) volume. - * - * Note that most of the other PC-based bell drivers compute the - * duration for KDMKTONE as a function of the volume and the duration. - * For some drivers, the duration is only measured in mS if the volume - * is 50, and is scaled by the volume for other values. This seems - * confusing and possibly incorrect (the xset man page says that the - * bell will be "as closely as it can to the user's specifications" -- - * if we ignore the volume and set the duration correctly, then we'll - * get one parameter "wrong" -- but if we use the volume to scale the - * duration, then we'll get both parameters "wrong"). */ -void kbdLinuxBell(DevicePtr pDev, int percent, - int volume, int pitch, int duration) -{ - GETPRIV; - - if (duration && pitch) { - ioctl(priv->fd, - KDMKTONE, - ((1193190 / pitch) & 0xffff) /* Low bits specify cycle time */ - | (duration << 16)); /* High bits are duration in msec */ - } -} - -/** Set the LEDs. */ -void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl) -{ - GETPRIV; - - ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07); -} - -static int kbdLinuxGetFreeVTNumber(void) -{ - int fd = -1; - int vtno; - int i; - const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; - - for (i = 0; tty0[i]; i++) - if ((fd = open(tty0[i], O_WRONLY, 0)) >= 0) break; - if (fd < 0) - FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n", - strerror(errno)); - if (ioctl(fd, VT_OPENQRY, &vtno) < 0 || vtno < 0) - FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n"); - return vtno; -} - -static int kbdLinuxOpenVT(int vtno) -{ - int fd = -1; - int i; - const char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL }; - char name[64]; /* RATS: Only used in XmuSnprintf */ - - for (i = 0; vcs[i]; i++) { - XmuSnprintf(name, sizeof(name), vcs[i], vtno); - if ((fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) break; - } - if (fd < 0) - FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n", - vtno, strerror(errno)); - return fd; -} - -static int kbdLinuxGetCurrentVTNumber(int fd) -{ - struct vt_stat vts; - - if (!ioctl(fd, VT_GETSTATE, &vts)) return vts.v_active; - return -1; -} - -static int kbdLinuxActivate(int fd, int vtno, int setSig); - -/** Currently unused hook called prior to an VT switch. */ -void kbdLinuxVTPreSwitch(pointer p) -{ -} - -/** Currently unused hook called after returning from a VT switch. */ -void kbdLinuxVTPostSwitch(pointer p) -{ -} - -/** Tell the operating system to switch to \a vt. The \a switch_return - * function is called with the \a switch_return_data when the VT is - * switched back to the pre-switch VT (i.e., the user returns to the DMX - * session). */ -int kbdLinuxVTSwitch(pointer p, int vt, - void (*switch_return)(pointer), - pointer switch_return_data) -{ - myPrivate *priv = p; - - if (priv->switched) FATAL0("kbdLinuxVTSwitch: already switched...\n"); - if (priv->vtno == vt) return 0; - - PRIV = priv; - priv->switched = 0; /* Will switch to 1 in handler */ - priv->switch_return = switch_return; - priv->switch_return_data = switch_return_data; - kbdLinuxActivate(priv->fd, vt, 0); - return 1; -} - -/* RATS: This function is only ever used to handle SIGUSR1. */ -static void kbdLinuxVTSignalHandler(int sig) -{ - myPrivate *priv = PRIV; - - signal(sig, kbdLinuxVTSignalHandler); - if (priv) { - ioctl(priv->fd, VT_RELDISP, VT_ACKACQ); - priv->switched = !priv->switched; - LOG2("kbdLinuxVTSignalHandler: got signal %d, switched = %d\n", - sig, priv->switched); - if (!priv->switched && priv->switch_return) - priv->switch_return(priv->switch_return_data); - } -} - -static int kbdLinuxActivate(int fd, int vtno, int setSig) -{ - int result; - struct vt_mode VT; - - SYSCALL(result = ioctl(fd, VT_ACTIVATE, vtno)); - if (result) FATAL0("kbdLinuxActivate: VT_ACTIVATE failed\n"); - SYSCALL(result = ioctl(fd, VT_WAITACTIVE, vtno)); - if (result) FATAL0("kbdLinuxActivate: VT_WAITACTIVE failed\n"); - if (setSig) { - SYSCALL(result = ioctl(fd, VT_GETMODE, &VT)); - if (result < 0) FATAL0("kbdLinuxActivate: VT_GETMODE failed\n"); - VT.mode = VT_PROCESS; - VT.relsig = SIGUSR1; - VT.acqsig = SIGUSR1; - if (ioctl(fd, VT_SETMODE, &VT)) - FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n"); - signal(SIGUSR1, kbdLinuxVTSignalHandler); - } - return Success; -} - -static void kbdLinuxOpenConsole(DevicePtr pDev) -{ - GETPRIV; - const char *msg = MESSAGE; - - if (priv->fd >= 0) return; - priv->vtno = kbdLinuxGetFreeVTNumber(); - priv->fd = kbdLinuxOpenVT(priv->vtno); - priv->vtcurrent = kbdLinuxGetCurrentVTNumber(priv->fd); - LOG2("kbdLinuxOpenConsole: current VT %d; using free VT %d\n", - priv->vtcurrent, priv->vtno); - kbdLinuxActivate(priv->fd, priv->vtno, 1); - ioctl(priv->fd, KDSETMODE, KD_GRAPHICS); /* To turn off gpm */ - if (msg) write(priv->fd, msg, strlen(msg)); -} - -static void kbdLinuxCloseConsole(DevicePtr pDev) -{ - GETPRIV; - struct vt_mode VT; - const char *msg = FINALMESSAGE; - - if (priv->fd < 0) return; - - ioctl(priv->fd, KDSETMODE, KD_TEXT); - if (msg) write(priv->fd, msg, strlen(msg)); - if (ioctl(priv->fd, VT_GETMODE, &VT) != -1) { - VT.mode = VT_AUTO; - ioctl(priv->fd, VT_SETMODE, &VT); - } - - LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent); - if (priv->vtcurrent >= 0) kbdLinuxActivate(priv->fd, priv->vtcurrent, 0); - - close(priv->fd); - priv->fd = -1; -} - -/** Initialize the \a pDev as a Linux keyboard. */ -void kbdLinuxInit(DevicePtr pDev) -{ - GETPRIV; - - if (priv->fd <= 0) kbdLinuxOpenConsole(pDev); - - ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans); - if (tcgetattr(priv->fd, &priv->kbdtty) < 0) - FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno)); -} - -static int kbdLinuxPrefix0Mapping(unsigned char *scanCode) -{ - /* Table from xfree86/common/xf86Events.c */ - 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: - return 1; - 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; - } - return 0; -} - -static int kbdLinuxPrefixMapping(myPrivate *priv, unsigned char *scanCode) -{ - int pressed = *scanCode & 0x80; - unsigned char code = *scanCode & 0x7f; - - /* If we don't have a prefix, check for one */ - if (!priv->prefix) { - switch (code) { - case KEY_Prefix0: - case KEY_Prefix1: - priv->prefix = code; - return 1; - } - return 0; /* No change */ - } - - /* We have a prefix from the last scanCode */ - switch (priv->prefix) { - case KEY_Prefix0: - priv->prefix = 0; - if (kbdLinuxPrefix0Mapping(&code)) return 1; /* Skip sequence */ - break; - case KEY_Prefix1: - priv->prefix = (code = KEY_LCtrl) ? KEY_LCtrl : 0; - return 1; /* Use new prefix */ - case KEY_LCtrl: - priv->prefix = 0; - if (code != KEY_NumLock) return 1; /* Skip sequence*/ - code = KEY_Pause; - break; - } - - *scanCode = code | (pressed ? 0x80 : 0x00); - return 0; /* Use old scanCode */ -} - -static void kbdLinuxConvert(DevicePtr pDev, - unsigned char scanCode, - ENQUEUEPROC enqueue, - CHECKPROC checkspecial, - BLOCK block) -{ - GETPRIV; - XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo; - int type; - KeySym keySym = NoSymbol; - int keyCode; - int switching; - - /* Do special PC/AT prefix mapping -- may change scanCode! */ - if (kbdLinuxPrefixMapping(priv, &scanCode)) return; - - type = (scanCode & 0x80) ? KeyRelease : KeyPress; - keyCode = (scanCode & 0x7f) + MIN_KEYCODE; - - /* Handle repeats */ - - if (keyCode >= xkbi->desc->min_key_code && - keyCode <= xkbi->desc->max_key_code) { - - int effectiveGroup = XkbGetEffectiveGroup(xkbi, - &xkbi->state, - scanCode); - keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup); -#if 0 - switch (keySym) { - case XK_Num_Lock: - case XK_Scroll_Lock: - case XK_Shift_Lock: - case XK_Caps_Lock: - /* Ignore releases and all but first press */ - if (kbdLinuxModIgnore(priv, &xE, keySym)) return; - if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; - else xE.u.u.type = KeyPress; - break; - } -#endif - - /* If key is already down, ignore or autorepeat */ - if (type == KeyPress && kbdLinuxKeyDown(priv, keyCode)) { - KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed; - - /* No auto-repeat? */ - if ((feed && !feed->ctrl.autoRepeat) - || priv->pKeyboard->key->xkbInfo->desc->map->modmap[keyCode] - || (feed - && !(feed->ctrl.autoRepeats[keyCode >> 3] - & (1 << (keyCode & 7))))) return; /* Ignore */ - - /* Do auto-repeat */ - enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); - type = KeyPress; - } - - /* If key is already up, ignore */ - if (type == KeyRelease && !kbdLinuxKeyDown(priv, keyCode)) return; - } - - switching = 0; - if (checkspecial && type == KeyPress) - switching = checkspecial(pDev, keySym); - if (!switching) { - if (enqueue) - enqueue(pDev, type, keyCode, keySym, NULL, block); - kbdLinuxKeyState(priv, type, keyCode); /* Update our state bitmap */ - } -} - -/** Read an event from the \a pDev device. If the event is a motion - * event, enqueue it with the \a motion function. Otherwise, check for - * special keys with the \a checkspecial function and enqueue the event - * with the \a enqueue function. The \a block type is passed to the - * functions so that they may block SIGIO handling as appropriate to the - * caller of this function. */ -void kbdLinuxRead(DevicePtr pDev, - MOTIONPROC motion, - ENQUEUEPROC enqueue, - CHECKPROC checkspecial, - BLOCK block) -{ - GETPRIV; - unsigned char buf[256]; /* RATS: Only used in length-limited call */ - unsigned char *pt; - int n; - - while ((n = read(priv->fd, buf, sizeof(buf))) > 0) - for (pt = buf; n; --n, ++pt) - kbdLinuxConvert(pDev, *pt, enqueue, checkspecial, block); -} - -/** Turn \a pDev on (i.e., take input from \a pDev). */ -int kbdLinuxOn(DevicePtr pDev) -{ - GETPRIV; - struct termios nTty; - - ioctl(priv->fd, KDSKBMODE, K_RAW); - - nTty = priv->kbdtty; - 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, B9600); - cfsetospeed(&nTty, B9600); - if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0) - FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno)); - return priv->fd; -} - -/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ -void kbdLinuxOff(DevicePtr pDev) -{ - GETPRIV; - - ioctl(priv->fd, KDSKBMODE, priv->kbdtrans); - tcsetattr(priv->fd, TCSANOW, &priv->kbdtty); - kbdLinuxCloseConsole(pDev); -} - - -static void kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms) -{ - KeySym *k; - int i; - int maxkey; - static unsigned char tbl[GLYPHS_PER_KEY] = { /* RATS: Use ok */ - 0, /* unshifted */ - 1, /* shifted */ - 0, /* modeswitch unshifted */ - 0 /* modeswitch shifted */ - }; - - /* - * Read the mapping from the kernel. - * Since we're still using the XFree86 scancode->AT keycode mapping - * routines, we need to convert the AT keycodes to Linux keycodes, - * then translate the Linux keysyms into X keysyms. - * - * First, figure out which tables to use for the modeswitch columns - * above, from the XF86Config fields. - */ - tbl[2] = 8; /* alt */ - tbl[3] = tbl[2] | 1; - -#if 00/*BP*/ - k = map+GLYPHS_PER_KEY; -#else - ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n"); - return; -#endif - maxkey = NUM_AT2LNX; - - for (i = 0; i < maxkey; ++i) { - struct kbentry kbe; - int j; - - kbe.kb_index = at2lnx[i]; - - for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) { - unsigned short kval; - - *k = NoSymbol; - - kbe.kb_table = tbl[j]; - if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe)) continue; - - kval = KVAL(kbe.kb_value); - switch (KTYP(kbe.kb_value)) { - case KT_LATIN: - case KT_LETTER: *k = linux_to_x[kval]; break; - case KT_FN: - if (kval <= 19) *k = XK_F1 + kval; - else switch (kbe.kb_value) { - case K_FIND: *k = XK_Home; /* or XK_Find */ break; - case K_INSERT: *k = XK_Insert; break; - case K_REMOVE: *k = XK_Delete; break; - case K_SELECT: *k = XK_End; /* or XK_Select */ break; - case K_PGUP: *k = XK_Prior; break; - case K_PGDN: *k = XK_Next; break; - case K_HELP: *k = XK_Help; break; - case K_DO: *k = XK_Execute; break; - case K_PAUSE: *k = XK_Pause; break; - case K_MACRO: *k = XK_Menu; break; - default: break; - } - break; - case KT_SPEC: - switch (kbe.kb_value) { - case K_ENTER: *k = XK_Return; break; - case K_BREAK: *k = XK_Break; break; - case K_CAPS: *k = XK_Caps_Lock; break; - case K_NUM: *k = XK_Num_Lock; break; - case K_HOLD: *k = XK_Scroll_Lock; break; - case K_COMPOSE: *k = XK_Multi_key; break; - default: break; - } - break; - case KT_PAD: - switch (kbe.kb_value) { - case K_PPLUS: *k = XK_KP_Add; break; - case K_PMINUS: *k = XK_KP_Subtract; break; - case K_PSTAR: *k = XK_KP_Multiply; break; - case K_PSLASH: *k = XK_KP_Divide; break; - case K_PENTER: *k = XK_KP_Enter; break; - case K_PCOMMA: *k = XK_KP_Separator; break; - case K_PDOT: *k = XK_KP_Decimal; break; - case K_PPLUSMINUS: *k = XK_KP_Subtract; break; - default: if (kval <= 9) *k = XK_KP_0 + kval; break; - } - break; - case KT_DEAD: - /* KT_DEAD keys are for accelerated diacritical creation. */ - switch (kbe.kb_value) { - case K_DGRAVE: *k = XK_dead_grave; break; - case K_DACUTE: *k = XK_dead_acute; break; - case K_DCIRCM: *k = XK_dead_circumflex; break; - case K_DTILDE: *k = XK_dead_tilde; break; - case K_DDIERE: *k = XK_dead_diaeresis; break; - } - break; - case KT_CUR: - switch (kbe.kb_value) { - case K_DOWN: *k = XK_Down; break; - case K_LEFT: *k = XK_Left; break; - case K_RIGHT: *k = XK_Right; break; - case K_UP: *k = XK_Up; break; - } - break; - case KT_SHIFT: - switch (kbe.kb_value) { - case K_ALTGR: *k = XK_Alt_R; break; - case K_ALT: - *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L); - break; - case K_CTRL: - *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L); - break; - case K_CTRLL: *k = XK_Control_L; break; - case K_CTRLR: *k = XK_Control_R; break; - case K_SHIFT: - *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L); - break; - case K_SHIFTL: *k = XK_Shift_L; break; - case K_SHIFTR: *k = XK_Shift_R; break; - default: break; - } - break; - case KT_ASCII: - /* KT_ASCII keys accumulate a 3 digit decimal number that - * gets emitted when the shift state changes. We can't - * emulate that. - */ - break; - case KT_LOCK: - if (kbe.kb_value == K_SHIFTLOCK) *k = XK_Shift_Lock; - break; - default: break; - } - } - - if (k[-1] == k[-2]) k[-1] = NoSymbol; - if (k[-2] == k[-3]) k[-2] = NoSymbol; - if (k[-3] == k[-4]) k[-3] = NoSymbol; - if (k[-4] == k[-2] && k[-3] == k[-1]) k[-2] = k[-1] = NoSymbol; - if (k[-1] == k[-4] && k[-2] == k[-3] - && k[-2] == NoSymbol) k[-1] = NoSymbol; - } -} - -static void kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) -{ - GETPRIV; - KeySym *k, *mapCopy; - char type; - int i; - -#if 00/*BP*/ - mapCopy = xalloc(sizeof(map)); - memcpy(mapCopy, map, sizeof(map)); -#else - ErrorF("kbdLinuxGetMap() is broken/no-op'd\n"); - return; -#endif - - kbdLinuxReadKernelMapping(priv->fd, pKeySyms); - - /* compute the modifier map */ - for (i = 0; i < MAP_LENGTH; i++) - pModMap[i] = NoSymbol; /* make sure it is restored */ - - for (k = mapCopy, i = MIN_KEYCODE; - i < NUM_KEYCODES + MIN_KEYCODE; - i++, k += 4) { - switch(*k) { - case XK_Shift_L: - case XK_Shift_R: pModMap[i] = ShiftMask; break; - case XK_Control_L: - case XK_Control_R: pModMap[i] = ControlMask; break; - case XK_Caps_Lock: pModMap[i] = LockMask; break; - case XK_Alt_L: - case XK_Alt_R: pModMap[i] = AltMask; break; - case XK_Num_Lock: pModMap[i] = NumLockMask; break; - case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; - case XK_Kana_Lock: - case XK_Kana_Shift: pModMap[i] = KanaMask; break; - case XK_Mode_switch: pModMap[i] = AltLangMask; break; - } - } - - priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type; - - pKeySyms->map = mapCopy; /* Must be XFree'able */ - pKeySyms->mapWidth = GLYPHS_PER_KEY; - pKeySyms->minKeyCode = MIN_KEYCODE; - pKeySyms->maxKeyCode = MAX_KEYCODE; -} - -/** Fill the \a info structure with information needed to initialize \a - * pDev. */ -void kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) -{ - info->keyboard = 1; - info->keyClass = 1; - kbdLinuxGetMap(pDev, &info->keySyms, info->modMap); - info->focusClass = 1; - info->kbdFeedbackClass = 1; -} +/* Portions of this file were derived from the following files: + * + ********************************************************************** + * + * xfree86/common/{xf86Io.c,xf86Kbd.c,xf86Events.c} + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * 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 Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL 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. + * + ********************************************************************** + * + * xfree86/common/xf86KbdLnx.c + * + * Linux version of keymapping setup. The kernel (since 0.99.14) has support + * for fully remapping the keyboard, but there are some differences between + * the Linux map and the SVR4 map (esp. in the extended keycodes). We also + * remove the restriction on what keycodes can be remapped. + * Orest Zborowski. + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * 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 Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL 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. + * + ********************************************************************** + * + * xfree86/os-support/linux/lnx_io.c + * + * Copyright 1992 by Orest Zborowski <obz@Kodak.com> + * Copyright 1993 by David Dawes <dawes@xfree86.org> + * + * 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 names of Orest Zborowski and David Dawes + * not be used in advertising or publicity pertaining to distribution of + * the software without specific, written prior permission. Orest Zborowski + * and David Dawes make no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * OREST ZBOROWSKI AND DAVID DAWES DISCLAIMS ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL OREST ZBOROWSKI OR DAVID DAWES 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. + * + */ + +/* + * Copyright 2001-2003 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: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This code implements a low-level device driver for the Linux + * keyboard. The code is derived from code by Thomas Roell, Orest + * Zborowski, and David Dawes (see the source code for complete + * references). */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "dmxinputinit.h" +#include "lnx-keyboard.h" + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define SWITCHRETPROC dmxVTSwitchReturnProcPtr +#define BLOCK DMXBlockType +#define MESSAGE "\033c\n\n\nDMX taking input from this console..." +#define FINALMESSAGE "\033cDMX terminated." + +/* End of interface definitions. */ +/*****************************************************************************/ + +#include "inputstr.h" +#include <X11/Xos.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <signal.h> +#include <sys/vt.h> +#include <sys/kd.h> +#include <termios.h> +#include "atKeynames.h" +#if 00 +#include "xf86Keymap.h" +#endif +#include <linux/keyboard.h> +#include <xkbsrv.h> + +#define NUM_AT2LNX (sizeof(at2lnx) / sizeof(at2lnx[0])) +#define NUM_STATE_ENTRIES (256/32) + + +/* Private area for Linux-style keyboards. */ +typedef struct _myPrivate { + int fd; + int vtno; + int vtcurrent; + int kbdtrans; + struct termios kbdtty; + int kbdType; + CARD32 kbdState[NUM_STATE_ENTRIES]; + DeviceIntPtr pKeyboard; + unsigned char prefix; + + int switched; + SWITCHRETPROC switch_return; + void *switch_return_data; + + /* For bell */ + int pitch; + unsigned long duration; +} myPrivate; + +static myPrivate *PRIV = NULL; + +#undef SYSCALL +#define SYSCALL(call) while(((call) == -1) && (errno == EINTR)) + +static int kbdLinuxKeyDown(myPrivate *priv, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return 0; + return priv->kbdState[byte] & bit; +} + +static void kbdLinuxKeyState(myPrivate *priv, int type, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return; + if (type == KeyPress) priv->kbdState[byte] |= bit; + else priv->kbdState[byte] &= ~bit; +} + +static 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 +}; + +/* + * Maps the AT keycodes to Linux keycodes + */ +static unsigned char at2lnx[NUM_KEYCODES] = +{ + 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 */ +}; + +/** Create a private structure for use within this file. */ +pointer kbdLinuxCreatePrivate(DeviceIntPtr pKeyboard) +{ + myPrivate *priv = calloc(1, sizeof(*priv)); + priv->fd = -1; + priv->pKeyboard = pKeyboard; + return priv; +} + +/** Destroy a private structure. */ +void kbdLinuxDestroyPrivate(pointer priv) +{ + if (priv) free(priv); +} + +/** Ring the bell. + * + * Note: we completely ignore the \a volume, since Linux's ioctl() + * interface does not provide a way to control it. If it did, the XBell + * manpage tells how the actual volume is a function of the percent and + * the (base) volume. + * + * Note that most of the other PC-based bell drivers compute the + * duration for KDMKTONE as a function of the volume and the duration. + * For some drivers, the duration is only measured in mS if the volume + * is 50, and is scaled by the volume for other values. This seems + * confusing and possibly incorrect (the xset man page says that the + * bell will be "as closely as it can to the user's specifications" -- + * if we ignore the volume and set the duration correctly, then we'll + * get one parameter "wrong" -- but if we use the volume to scale the + * duration, then we'll get both parameters "wrong"). */ +void kbdLinuxBell(DevicePtr pDev, int percent, + int volume, int pitch, int duration) +{ + GETPRIV; + + if (duration && pitch) { + ioctl(priv->fd, + KDMKTONE, + ((1193190 / pitch) & 0xffff) /* Low bits specify cycle time */ + | (duration << 16)); /* High bits are duration in msec */ + } +} + +/** Set the LEDs. */ +void kbdLinuxCtrl(DevicePtr pDev, KeybdCtrl *ctrl) +{ + GETPRIV; + + ioctl(priv->fd, KDSETLED, ctrl->leds & 0x07); +} + +static int kbdLinuxGetFreeVTNumber(void) +{ + int fd = -1; + int vtno; + int i; + const char *tty0[] = { "/dev/tty0", "/dev/vc/0", NULL }; + + for (i = 0; tty0[i]; i++) + if ((fd = open(tty0[i], O_WRONLY, 0)) >= 0) break; + if (fd < 0) + FATAL1("kbdLinuxGetFreeVTNumber: Cannot open tty0 (%s)\n", + strerror(errno)); + if (ioctl(fd, VT_OPENQRY, &vtno) < 0 || vtno < 0) + FATAL0("kbdLinuxGetFreeVTNumber: Cannot find a free VT\n"); + return vtno; +} + +static int kbdLinuxOpenVT(int vtno) +{ + int fd = -1; + int i; + const char *vcs[] = { "/dev/vc/%d", "/dev/tty%d", NULL }; + char name[64]; /* RATS: Only used in XmuSnprintf */ + + for (i = 0; vcs[i]; i++) { + XmuSnprintf(name, sizeof(name), vcs[i], vtno); + if ((fd = open(name, O_RDWR | O_NONBLOCK, 0)) >= 0) break; + } + if (fd < 0) + FATAL2("kbdLinuxOpenVT: Cannot open VT %d (%s)\n", + vtno, strerror(errno)); + return fd; +} + +static int kbdLinuxGetCurrentVTNumber(int fd) +{ + struct vt_stat vts; + + if (!ioctl(fd, VT_GETSTATE, &vts)) return vts.v_active; + return -1; +} + +static int kbdLinuxActivate(int fd, int vtno, int setSig); + +/** Currently unused hook called prior to an VT switch. */ +void kbdLinuxVTPreSwitch(pointer p) +{ +} + +/** Currently unused hook called after returning from a VT switch. */ +void kbdLinuxVTPostSwitch(pointer p) +{ +} + +/** Tell the operating system to switch to \a vt. The \a switch_return + * function is called with the \a switch_return_data when the VT is + * switched back to the pre-switch VT (i.e., the user returns to the DMX + * session). */ +int kbdLinuxVTSwitch(pointer p, int vt, + void (*switch_return)(pointer), + pointer switch_return_data) +{ + myPrivate *priv = p; + + if (priv->switched) FATAL0("kbdLinuxVTSwitch: already switched...\n"); + if (priv->vtno == vt) return 0; + + PRIV = priv; + priv->switched = 0; /* Will switch to 1 in handler */ + priv->switch_return = switch_return; + priv->switch_return_data = switch_return_data; + kbdLinuxActivate(priv->fd, vt, 0); + return 1; +} + +/* RATS: This function is only ever used to handle SIGUSR1. */ +static void kbdLinuxVTSignalHandler(int sig) +{ + myPrivate *priv = PRIV; + + signal(sig, kbdLinuxVTSignalHandler); + if (priv) { + ioctl(priv->fd, VT_RELDISP, VT_ACKACQ); + priv->switched = !priv->switched; + LOG2("kbdLinuxVTSignalHandler: got signal %d, switched = %d\n", + sig, priv->switched); + if (!priv->switched && priv->switch_return) + priv->switch_return(priv->switch_return_data); + } +} + +static int kbdLinuxActivate(int fd, int vtno, int setSig) +{ + int result; + struct vt_mode VT; + + SYSCALL(result = ioctl(fd, VT_ACTIVATE, vtno)); + if (result) FATAL0("kbdLinuxActivate: VT_ACTIVATE failed\n"); + SYSCALL(result = ioctl(fd, VT_WAITACTIVE, vtno)); + if (result) FATAL0("kbdLinuxActivate: VT_WAITACTIVE failed\n"); + if (setSig) { + SYSCALL(result = ioctl(fd, VT_GETMODE, &VT)); + if (result < 0) FATAL0("kbdLinuxActivate: VT_GETMODE failed\n"); + VT.mode = VT_PROCESS; + VT.relsig = SIGUSR1; + VT.acqsig = SIGUSR1; + if (ioctl(fd, VT_SETMODE, &VT)) + FATAL0("kbdLinuxActivate: VT_SETMODE VT_PROCESS failed\n"); + signal(SIGUSR1, kbdLinuxVTSignalHandler); + } + return Success; +} + +static void kbdLinuxOpenConsole(DevicePtr pDev) +{ + GETPRIV; + const char *msg = MESSAGE; + + if (priv->fd >= 0) return; + priv->vtno = kbdLinuxGetFreeVTNumber(); + priv->fd = kbdLinuxOpenVT(priv->vtno); + priv->vtcurrent = kbdLinuxGetCurrentVTNumber(priv->fd); + LOG2("kbdLinuxOpenConsole: current VT %d; using free VT %d\n", + priv->vtcurrent, priv->vtno); + kbdLinuxActivate(priv->fd, priv->vtno, 1); + ioctl(priv->fd, KDSETMODE, KD_GRAPHICS); /* To turn off gpm */ + if (msg) write(priv->fd, msg, strlen(msg)); +} + +static void kbdLinuxCloseConsole(DevicePtr pDev) +{ + GETPRIV; + struct vt_mode VT; + const char *msg = FINALMESSAGE; + + if (priv->fd < 0) return; + + ioctl(priv->fd, KDSETMODE, KD_TEXT); + if (msg) write(priv->fd, msg, strlen(msg)); + if (ioctl(priv->fd, VT_GETMODE, &VT) != -1) { + VT.mode = VT_AUTO; + ioctl(priv->fd, VT_SETMODE, &VT); + } + + LOG1("kbdLinuxCloseConsole: switching to VT %d\n", priv->vtcurrent); + if (priv->vtcurrent >= 0) kbdLinuxActivate(priv->fd, priv->vtcurrent, 0); + + close(priv->fd); + priv->fd = -1; +} + +/** Initialize the \a pDev as a Linux keyboard. */ +void kbdLinuxInit(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd <= 0) kbdLinuxOpenConsole(pDev); + + ioctl(priv->fd, KDGKBMODE, &priv->kbdtrans); + if (tcgetattr(priv->fd, &priv->kbdtty) < 0) + FATAL1("kbdLinuxInit: tcgetattr failed (%s)\n", strerror(errno)); +} + +static int kbdLinuxPrefix0Mapping(unsigned char *scanCode) +{ + /* Table from xfree86/common/xf86Events.c */ + 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: + return 1; + 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; + } + return 0; +} + +static int kbdLinuxPrefixMapping(myPrivate *priv, unsigned char *scanCode) +{ + int pressed = *scanCode & 0x80; + unsigned char code = *scanCode & 0x7f; + + /* If we don't have a prefix, check for one */ + if (!priv->prefix) { + switch (code) { + case KEY_Prefix0: + case KEY_Prefix1: + priv->prefix = code; + return 1; + } + return 0; /* No change */ + } + + /* We have a prefix from the last scanCode */ + switch (priv->prefix) { + case KEY_Prefix0: + priv->prefix = 0; + if (kbdLinuxPrefix0Mapping(&code)) return 1; /* Skip sequence */ + break; + case KEY_Prefix1: + priv->prefix = (code = KEY_LCtrl) ? KEY_LCtrl : 0; + return 1; /* Use new prefix */ + case KEY_LCtrl: + priv->prefix = 0; + if (code != KEY_NumLock) return 1; /* Skip sequence*/ + code = KEY_Pause; + break; + } + + *scanCode = code | (pressed ? 0x80 : 0x00); + return 0; /* Use old scanCode */ +} + +static void kbdLinuxConvert(DevicePtr pDev, + unsigned char scanCode, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo; + int type; + KeySym keySym = NoSymbol; + int keyCode; + int switching; + + /* Do special PC/AT prefix mapping -- may change scanCode! */ + if (kbdLinuxPrefixMapping(priv, &scanCode)) return; + + type = (scanCode & 0x80) ? KeyRelease : KeyPress; + keyCode = (scanCode & 0x7f) + MIN_KEYCODE; + + /* Handle repeats */ + + if (keyCode >= xkbi->desc->min_key_code && + keyCode <= xkbi->desc->max_key_code) { + + int effectiveGroup = XkbGetEffectiveGroup(xkbi, + &xkbi->state, + scanCode); + keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup); +#if 0 + switch (keySym) { + case XK_Num_Lock: + case XK_Scroll_Lock: + case XK_Shift_Lock: + case XK_Caps_Lock: + /* Ignore releases and all but first press */ + if (kbdLinuxModIgnore(priv, &xE, keySym)) return; + if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; + else xE.u.u.type = KeyPress; + break; + } +#endif + + /* If key is already down, ignore or autorepeat */ + if (type == KeyPress && kbdLinuxKeyDown(priv, keyCode)) { + KbdFeedbackClassRec *feed = priv->pKeyboard->kbdfeed; + + /* No auto-repeat? */ + if ((feed && !feed->ctrl.autoRepeat) + || priv->pKeyboard->key->xkbInfo->desc->map->modmap[keyCode] + || (feed + && !(feed->ctrl.autoRepeats[keyCode >> 3] + & (1 << (keyCode & 7))))) return; /* Ignore */ + + /* Do auto-repeat */ + enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); + type = KeyPress; + } + + /* If key is already up, ignore */ + if (type == KeyRelease && !kbdLinuxKeyDown(priv, keyCode)) return; + } + + switching = 0; + if (checkspecial && type == KeyPress) + switching = checkspecial(pDev, keySym); + if (!switching) { + if (enqueue) + enqueue(pDev, type, keyCode, keySym, NULL, block); + kbdLinuxKeyState(priv, type, keyCode); /* Update our state bitmap */ + } +} + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, check for + * special keys with the \a checkspecial function and enqueue the event + * with the \a enqueue function. The \a block type is passed to the + * functions so that they may block SIGIO handling as appropriate to the + * caller of this function. */ +void kbdLinuxRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + unsigned char buf[256]; /* RATS: Only used in length-limited call */ + unsigned char *pt; + int n; + + while ((n = read(priv->fd, buf, sizeof(buf))) > 0) + for (pt = buf; n; --n, ++pt) + kbdLinuxConvert(pDev, *pt, enqueue, checkspecial, block); +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int kbdLinuxOn(DevicePtr pDev) +{ + GETPRIV; + struct termios nTty; + + ioctl(priv->fd, KDSKBMODE, K_RAW); + + nTty = priv->kbdtty; + 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, B9600); + cfsetospeed(&nTty, B9600); + if (tcsetattr(priv->fd, TCSANOW, &nTty) < 0) + FATAL1("kbdLinuxOn: tcsetattr failed (%s)\n", strerror(errno)); + return priv->fd; +} + +/** Turn \a pDev off (i.e., stop taking input from \a pDev). */ +void kbdLinuxOff(DevicePtr pDev) +{ + GETPRIV; + + ioctl(priv->fd, KDSKBMODE, priv->kbdtrans); + tcsetattr(priv->fd, TCSANOW, &priv->kbdtty); + kbdLinuxCloseConsole(pDev); +} + + +static void kbdLinuxReadKernelMapping(int fd, KeySymsPtr pKeySyms) +{ + KeySym *k; + int i; + int maxkey; + static unsigned char tbl[GLYPHS_PER_KEY] = { /* RATS: Use ok */ + 0, /* unshifted */ + 1, /* shifted */ + 0, /* modeswitch unshifted */ + 0 /* modeswitch shifted */ + }; + + /* + * Read the mapping from the kernel. + * Since we're still using the XFree86 scancode->AT keycode mapping + * routines, we need to convert the AT keycodes to Linux keycodes, + * then translate the Linux keysyms into X keysyms. + * + * First, figure out which tables to use for the modeswitch columns + * above, from the XF86Config fields. + */ + tbl[2] = 8; /* alt */ + tbl[3] = tbl[2] | 1; + +#if 00/*BP*/ + k = map+GLYPHS_PER_KEY; +#else + ErrorF("kbdLinuxReadKernelMapping() is broken/no-op'd\n"); + return; +#endif + maxkey = NUM_AT2LNX; + + for (i = 0; i < maxkey; ++i) { + struct kbentry kbe; + int j; + + kbe.kb_index = at2lnx[i]; + + for (j = 0; j < GLYPHS_PER_KEY; ++j, ++k) { + unsigned short kval; + + *k = NoSymbol; + + kbe.kb_table = tbl[j]; + if (kbe.kb_index == 0 || ioctl(fd, KDGKBENT, &kbe)) continue; + + kval = KVAL(kbe.kb_value); + switch (KTYP(kbe.kb_value)) { + case KT_LATIN: + case KT_LETTER: *k = linux_to_x[kval]; break; + case KT_FN: + if (kval <= 19) *k = XK_F1 + kval; + else switch (kbe.kb_value) { + case K_FIND: *k = XK_Home; /* or XK_Find */ break; + case K_INSERT: *k = XK_Insert; break; + case K_REMOVE: *k = XK_Delete; break; + case K_SELECT: *k = XK_End; /* or XK_Select */ break; + case K_PGUP: *k = XK_Prior; break; + case K_PGDN: *k = XK_Next; break; + case K_HELP: *k = XK_Help; break; + case K_DO: *k = XK_Execute; break; + case K_PAUSE: *k = XK_Pause; break; + case K_MACRO: *k = XK_Menu; break; + default: break; + } + break; + case KT_SPEC: + switch (kbe.kb_value) { + case K_ENTER: *k = XK_Return; break; + case K_BREAK: *k = XK_Break; break; + case K_CAPS: *k = XK_Caps_Lock; break; + case K_NUM: *k = XK_Num_Lock; break; + case K_HOLD: *k = XK_Scroll_Lock; break; + case K_COMPOSE: *k = XK_Multi_key; break; + default: break; + } + break; + case KT_PAD: + switch (kbe.kb_value) { + case K_PPLUS: *k = XK_KP_Add; break; + case K_PMINUS: *k = XK_KP_Subtract; break; + case K_PSTAR: *k = XK_KP_Multiply; break; + case K_PSLASH: *k = XK_KP_Divide; break; + case K_PENTER: *k = XK_KP_Enter; break; + case K_PCOMMA: *k = XK_KP_Separator; break; + case K_PDOT: *k = XK_KP_Decimal; break; + case K_PPLUSMINUS: *k = XK_KP_Subtract; break; + default: if (kval <= 9) *k = XK_KP_0 + kval; break; + } + break; + case KT_DEAD: + /* KT_DEAD keys are for accelerated diacritical creation. */ + switch (kbe.kb_value) { + case K_DGRAVE: *k = XK_dead_grave; break; + case K_DACUTE: *k = XK_dead_acute; break; + case K_DCIRCM: *k = XK_dead_circumflex; break; + case K_DTILDE: *k = XK_dead_tilde; break; + case K_DDIERE: *k = XK_dead_diaeresis; break; + } + break; + case KT_CUR: + switch (kbe.kb_value) { + case K_DOWN: *k = XK_Down; break; + case K_LEFT: *k = XK_Left; break; + case K_RIGHT: *k = XK_Right; break; + case K_UP: *k = XK_Up; break; + } + break; + case KT_SHIFT: + switch (kbe.kb_value) { + case K_ALTGR: *k = XK_Alt_R; break; + case K_ALT: + *k = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L); + break; + case K_CTRL: + *k = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L); + break; + case K_CTRLL: *k = XK_Control_L; break; + case K_CTRLR: *k = XK_Control_R; break; + case K_SHIFT: + *k = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L); + break; + case K_SHIFTL: *k = XK_Shift_L; break; + case K_SHIFTR: *k = XK_Shift_R; break; + default: break; + } + break; + case KT_ASCII: + /* KT_ASCII keys accumulate a 3 digit decimal number that + * gets emitted when the shift state changes. We can't + * emulate that. + */ + break; + case KT_LOCK: + if (kbe.kb_value == K_SHIFTLOCK) *k = XK_Shift_Lock; + break; + default: break; + } + } + + if (k[-1] == k[-2]) k[-1] = NoSymbol; + if (k[-2] == k[-3]) k[-2] = NoSymbol; + if (k[-3] == k[-4]) k[-3] = NoSymbol; + if (k[-4] == k[-2] && k[-3] == k[-1]) k[-2] = k[-1] = NoSymbol; + if (k[-1] == k[-4] && k[-2] == k[-3] + && k[-2] == NoSymbol) k[-1] = NoSymbol; + } +} + +static void kbdLinuxGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) +{ + GETPRIV; + KeySym *k, *mapCopy; + char type; + int i; + +#if 00/*BP*/ + mapCopy = malloc(sizeof(map)); + memcpy(mapCopy, map, sizeof(map)); +#else + ErrorF("kbdLinuxGetMap() is broken/no-op'd\n"); + return; +#endif + + kbdLinuxReadKernelMapping(priv->fd, pKeySyms); + + /* compute the modifier map */ + for (i = 0; i < MAP_LENGTH; i++) + pModMap[i] = NoSymbol; /* make sure it is restored */ + + for (k = mapCopy, i = MIN_KEYCODE; + i < NUM_KEYCODES + MIN_KEYCODE; + i++, k += 4) { + switch(*k) { + case XK_Shift_L: + case XK_Shift_R: pModMap[i] = ShiftMask; break; + case XK_Control_L: + case XK_Control_R: pModMap[i] = ControlMask; break; + case XK_Caps_Lock: pModMap[i] = LockMask; break; + case XK_Alt_L: + case XK_Alt_R: pModMap[i] = AltMask; break; + case XK_Num_Lock: pModMap[i] = NumLockMask; break; + case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; + case XK_Kana_Lock: + case XK_Kana_Shift: pModMap[i] = KanaMask; break; + case XK_Mode_switch: pModMap[i] = AltLangMask; break; + } + } + + priv->kbdType = (ioctl(priv->fd, KDGKBTYPE, &type) < 0) ? KB_101 : type; + + pKeySyms->map = mapCopy; /* Must be XFree'able */ + pKeySyms->mapWidth = GLYPHS_PER_KEY; + pKeySyms->minKeyCode = MIN_KEYCODE; + pKeySyms->maxKeyCode = MAX_KEYCODE; +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void kbdLinuxGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->keyboard = 1; + info->keyClass = 1; + kbdLinuxGetMap(pDev, &info->keySyms, info->modMap); + info->focusClass = 1; + info->kbdFeedbackClass = 1; +} diff --git a/xorg-server/hw/dmx/input/usb-keyboard.c b/xorg-server/hw/dmx/input/usb-keyboard.c index c4667a3c3..fcbea47f9 100644 --- a/xorg-server/hw/dmx/input/usb-keyboard.c +++ b/xorg-server/hw/dmx/input/usb-keyboard.c @@ -1,444 +1,444 @@ -/* Portions of this file were derived from the following files: - * - ********************************************************************** - * - * xfree86/common/xf86KbdLnx.c - * - * Linux version of keymapping setup. The kernel (since 0.99.14) has support - * for fully remapping the keyboard, but there are some differences between - * the Linux map and the SVR4 map (esp. in the extended keycodes). We also - * remove the restriction on what keycodes can be remapped. - * Orest Zborowski. - * - * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * - * 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 Thomas Roell not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Thomas Roell makes no representations - * about the suitability of this software for any purpose. It is provided - * "as is" without express or implied warranty. - * - * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THOMAS ROELL 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. - * - */ - -/* - * 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: - * Rickard E. (Rik) Faith <faith@redhat.com> - * - */ - -/** \file - * - * This code implements a low-level device driver for a USB keyboard - * under Linux. The keymap description is derived from code by Thomas - * Roell, Orest Zborowski. */ - -#ifdef HAVE_DMX_CONFIG_H -#include <dmx-config.h> -#endif - -#include "atKeynames.h" -#include "usb-private.h" - -#define USB_KEYBOARD_DEBUG 0 - -/*****************************************************************************/ -/* Define some macros to make it easier to move this file to another - * part of the Xserver tree. All calls to the dmx* layer are #defined - * here for the .c file. The .h file will also have to be edited. */ -#include "usb-keyboard.h" -#include <xkbsrv.h> - -#define GETPRIV myPrivate *priv \ - = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private - -#define LOG0(f) dmxLog(dmxDebug,f) -#define LOG1(f,a) dmxLog(dmxDebug,f,a) -#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) -#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) -#define FATAL0(f) dmxLog(dmxFatal,f) -#define FATAL1(f,a) dmxLog(dmxFatal,f,a) -#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) -#define MOTIONPROC dmxMotionProcPtr -#define ENQUEUEPROC dmxEnqueueProcPtr -#define CHECKPROC dmxCheckSpecialProcPtr -#define BLOCK DMXBlockType - -/* End of interface definitions. */ -/*****************************************************************************/ - -#define GLYPHS_PER_KEY 4 -#define NUM_KEYCODES 248 -#define MIN_KEYCODE 8 -#define MAX_KEYCODE (NUM_KEYCODES + MIN_KEYCODE - 1) - -static KeySym map[NUM_KEYCODES * GLYPHS_PER_KEY] = { -/* Table modified from xc/programs/Xserver/hw/xfree86/common/xf86Keymap.h */ - /* 0x00 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x01 */ XK_Escape, NoSymbol, NoSymbol, NoSymbol, - /* 0x02 */ XK_1, XK_exclam, NoSymbol, NoSymbol, - /* 0x03 */ XK_2, XK_at, NoSymbol, NoSymbol, - /* 0x04 */ XK_3, XK_numbersign, NoSymbol, NoSymbol, - /* 0x05 */ XK_4, XK_dollar, NoSymbol, NoSymbol, - /* 0x06 */ XK_5, XK_percent, NoSymbol, NoSymbol, - /* 0x07 */ XK_6, XK_asciicircum, NoSymbol, NoSymbol, - /* 0x08 */ XK_7, XK_ampersand, NoSymbol, NoSymbol, - /* 0x09 */ XK_8, XK_asterisk, NoSymbol, NoSymbol, - /* 0x0a */ XK_9, XK_parenleft, NoSymbol, NoSymbol, - /* 0x0b */ XK_0, XK_parenright, NoSymbol, NoSymbol, - /* 0x0c */ XK_minus, XK_underscore, NoSymbol, NoSymbol, - /* 0x0d */ XK_equal, XK_plus, NoSymbol, NoSymbol, - /* 0x0e */ XK_BackSpace, NoSymbol, NoSymbol, NoSymbol, - /* 0x0f */ XK_Tab, XK_ISO_Left_Tab,NoSymbol, NoSymbol, - /* 0x10 */ XK_Q, NoSymbol, NoSymbol, NoSymbol, - /* 0x11 */ XK_W, NoSymbol, NoSymbol, NoSymbol, - /* 0x12 */ XK_E, NoSymbol, NoSymbol, NoSymbol, - /* 0x13 */ XK_R, NoSymbol, NoSymbol, NoSymbol, - /* 0x14 */ XK_T, NoSymbol, NoSymbol, NoSymbol, - /* 0x15 */ XK_Y, NoSymbol, NoSymbol, NoSymbol, - /* 0x16 */ XK_U, NoSymbol, NoSymbol, NoSymbol, - /* 0x17 */ XK_I, NoSymbol, NoSymbol, NoSymbol, - /* 0x18 */ XK_O, NoSymbol, NoSymbol, NoSymbol, - /* 0x19 */ XK_P, NoSymbol, NoSymbol, NoSymbol, - /* 0x1a */ XK_bracketleft, XK_braceleft, NoSymbol, NoSymbol, - /* 0x1b */ XK_bracketright,XK_braceright, NoSymbol, NoSymbol, - /* 0x1c */ XK_Return, NoSymbol, NoSymbol, NoSymbol, - /* 0x1d */ XK_Control_L, NoSymbol, NoSymbol, NoSymbol, - /* 0x1e */ XK_A, NoSymbol, NoSymbol, NoSymbol, - /* 0x1f */ XK_S, NoSymbol, NoSymbol, NoSymbol, - /* 0x20 */ XK_D, NoSymbol, NoSymbol, NoSymbol, - /* 0x21 */ XK_F, NoSymbol, NoSymbol, NoSymbol, - /* 0x22 */ XK_G, NoSymbol, NoSymbol, NoSymbol, - /* 0x23 */ XK_H, NoSymbol, NoSymbol, NoSymbol, - /* 0x24 */ XK_J, NoSymbol, NoSymbol, NoSymbol, - /* 0x25 */ XK_K, NoSymbol, NoSymbol, NoSymbol, - /* 0x26 */ XK_L, NoSymbol, NoSymbol, NoSymbol, - /* 0x27 */ XK_semicolon, XK_colon, NoSymbol, NoSymbol, - /* 0x28 */ XK_quoteright, XK_quotedbl, NoSymbol, NoSymbol, - /* 0x29 */ XK_quoteleft, XK_asciitilde, NoSymbol, NoSymbol, - /* 0x2a */ XK_Shift_L, NoSymbol, NoSymbol, NoSymbol, - /* 0x2b */ XK_backslash, XK_bar, NoSymbol, NoSymbol, - /* 0x2c */ XK_Z, NoSymbol, NoSymbol, NoSymbol, - /* 0x2d */ XK_X, NoSymbol, NoSymbol, NoSymbol, - /* 0x2e */ XK_C, NoSymbol, NoSymbol, NoSymbol, - /* 0x2f */ XK_V, NoSymbol, NoSymbol, NoSymbol, - /* 0x30 */ XK_B, NoSymbol, NoSymbol, NoSymbol, - /* 0x31 */ XK_N, NoSymbol, NoSymbol, NoSymbol, - /* 0x32 */ XK_M, NoSymbol, NoSymbol, NoSymbol, - /* 0x33 */ XK_comma, XK_less, NoSymbol, NoSymbol, - /* 0x34 */ XK_period, XK_greater, NoSymbol, NoSymbol, - /* 0x35 */ XK_slash, XK_question, NoSymbol, NoSymbol, - /* 0x36 */ XK_Shift_R, NoSymbol, NoSymbol, NoSymbol, - /* 0x37 */ XK_KP_Multiply, NoSymbol, NoSymbol, NoSymbol, - /* 0x38 */ XK_Alt_L, XK_Meta_L, NoSymbol, NoSymbol, - /* 0x39 */ XK_space, NoSymbol, NoSymbol, NoSymbol, - /* 0x3a */ XK_Caps_Lock, NoSymbol, NoSymbol, NoSymbol, - /* 0x3b */ XK_F1, NoSymbol, NoSymbol, NoSymbol, - /* 0x3c */ XK_F2, NoSymbol, NoSymbol, NoSymbol, - /* 0x3d */ XK_F3, NoSymbol, NoSymbol, NoSymbol, - /* 0x3e */ XK_F4, NoSymbol, NoSymbol, NoSymbol, - /* 0x3f */ XK_F5, NoSymbol, NoSymbol, NoSymbol, - /* 0x40 */ XK_F6, NoSymbol, NoSymbol, NoSymbol, - /* 0x41 */ XK_F7, NoSymbol, NoSymbol, NoSymbol, - /* 0x42 */ XK_F8, NoSymbol, NoSymbol, NoSymbol, - /* 0x43 */ XK_F9, NoSymbol, NoSymbol, NoSymbol, - /* 0x44 */ XK_F10, NoSymbol, NoSymbol, NoSymbol, - /* 0x45 */ XK_Num_Lock, NoSymbol, NoSymbol, NoSymbol, - /* 0x46 */ XK_Scroll_Lock, NoSymbol, NoSymbol, NoSymbol, - /* 0x47 */ XK_KP_Home, XK_KP_7, NoSymbol, NoSymbol, - /* 0x48 */ XK_KP_Up, XK_KP_8, NoSymbol, NoSymbol, - /* 0x49 */ XK_KP_Prior, XK_KP_9, NoSymbol, NoSymbol, - /* 0x4a */ XK_KP_Subtract, NoSymbol, NoSymbol, NoSymbol, - /* 0x4b */ XK_KP_Left, XK_KP_4, NoSymbol, NoSymbol, - /* 0x4c */ XK_KP_Begin, XK_KP_5, NoSymbol, NoSymbol, - /* 0x4d */ XK_KP_Right, XK_KP_6, NoSymbol, NoSymbol, - /* 0x4e */ XK_KP_Add, NoSymbol, NoSymbol, NoSymbol, - /* 0x4f */ XK_KP_End, XK_KP_1, NoSymbol, NoSymbol, - /* 0x50 */ XK_KP_Down, XK_KP_2, NoSymbol, NoSymbol, - /* 0x51 */ XK_KP_Next, XK_KP_3, NoSymbol, NoSymbol, - /* 0x52 */ XK_KP_Insert, XK_KP_0, NoSymbol, NoSymbol, - /* 0x53 */ XK_KP_Delete, XK_KP_Decimal, NoSymbol, NoSymbol, - /* 0x54 */ XK_Sys_Req, NoSymbol, NoSymbol, NoSymbol, - /* 0x55 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x56 */ XK_less, XK_greater, NoSymbol, NoSymbol, - /* 0x57 */ XK_F11, NoSymbol, NoSymbol, NoSymbol, - /* 0x58 */ XK_F12, NoSymbol, NoSymbol, NoSymbol, - /* 0x59 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x5a */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x5b */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x5c */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x5d */ XK_Begin, NoSymbol, NoSymbol, NoSymbol, - /* 0x5e */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x5f */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x60 */ XK_KP_Enter, NoSymbol, NoSymbol, NoSymbol, - /* 0x61 */ XK_Control_R, NoSymbol, NoSymbol, NoSymbol, - /* 0x62 */ XK_KP_Divide, NoSymbol, NoSymbol, NoSymbol, - /* 0x63 */ XK_Print, NoSymbol, NoSymbol, NoSymbol, - /* 0x64 */ XK_Alt_R, XK_Meta_R, NoSymbol, NoSymbol, - /* 0x65 */ XK_Break, NoSymbol, NoSymbol, NoSymbol, - /* 0x66 */ XK_Home, NoSymbol, NoSymbol, NoSymbol, - /* 0x67 */ XK_Up, NoSymbol, NoSymbol, NoSymbol, - /* 0x68 */ XK_Prior, NoSymbol, NoSymbol, NoSymbol, - /* 0x69 */ XK_Left, NoSymbol, NoSymbol, NoSymbol, - /* 0x6a */ XK_Right, NoSymbol, NoSymbol, NoSymbol, - /* 0x6b */ XK_End, NoSymbol, NoSymbol, NoSymbol, - /* 0x6c */ XK_Down, NoSymbol, NoSymbol, NoSymbol, - /* 0x6d */ XK_Next, NoSymbol, NoSymbol, NoSymbol, - /* 0x6e */ XK_Insert, NoSymbol, NoSymbol, NoSymbol, - /* 0x6f */ XK_Delete, NoSymbol, NoSymbol, NoSymbol, - /* 0x70 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x71 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x72 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x73 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x74 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x75 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x76 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x77 */ XK_Pause, NoSymbol, NoSymbol, NoSymbol, - /* 0x78 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x79 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x7a */ XK_Menu, NoSymbol, NoSymbol, NoSymbol, - /* 0x7b */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x7c */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, - /* 0x7d */ XK_Super_L, NoSymbol, NoSymbol, NoSymbol, - /* 0x7e */ XK_Super_R, NoSymbol, NoSymbol, NoSymbol, - /* 0x7f */ XK_Menu, NoSymbol, NoSymbol, NoSymbol, -}; - -static int kbdUSBKeyDown(myPrivate *priv, int keyCode) -{ - CARD8 byte = keyCode >> 5; - CARD32 bit = 1 << (keyCode & 0x1f); - - if (byte > NUM_STATE_ENTRIES) return 0; - return priv->kbdState[byte] & bit; -} - -static void kbdUSBKeyState(myPrivate *priv, int type, int keyCode) -{ - CARD8 byte = keyCode >> 5; - CARD32 bit = 1 << (keyCode & 0x1f); - - if (byte > NUM_STATE_ENTRIES) return; - if (type == KeyPress) priv->kbdState[byte] |= bit; - else priv->kbdState[byte] &= ~bit; -} - -/** Set the LEDs. */ -void kbdUSBCtrl(DevicePtr pDev, KeybdCtrl *ctrl) -{ - GETPRIV; - struct timeval tv; - struct input_event event; - int i, led; - - gettimeofday(&tv, NULL); - for (i = 0; i < 5; i++) { - event.time.tv_sec = tv.tv_sec; - event.time.tv_usec = tv.tv_usec; - event.type = EV_LED; - if (i == 0) led = 1; /* LED_CAPSL == 0x01 */ - else if (i == 1) led = 0; /* LED_NUML == 0x00 */ - else led = i; - event.code = led; - event.value = !!(ctrl->leds & (1 << led)); - write(priv->fd, &event, sizeof(event)); - } -} - -/** Initialize \a pDev using #usbInit. */ -void kbdUSBInit(DevicePtr pDev) -{ - usbInit(pDev, usbKeyboard); -} - -static void kbdUSBConvert(DevicePtr pDev, - unsigned int scanCode, - int value, - ENQUEUEPROC enqueue, - CHECKPROC checkspecial, - BLOCK block) -{ - GETPRIV; - XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo; - int type; - int keyCode; - KeySym keySym = NoSymbol; - int switching; - - /* Set up xEvent information */ - type = value ? KeyPress : KeyRelease; - keyCode = (scanCode & 0xff) + MIN_KEYCODE; - - /* Handle repeats */ - - if (keyCode >= xkbi->desc->min_key_code && - keyCode <= xkbi->desc->max_key_code) { - - int effectiveGroup = XkbGetEffectiveGroup(xkbi, - &xkbi->state, - scanCode); - keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup); -#if 0 - switch (keySym) { - case XK_Num_Lock: - case XK_Scroll_Lock: - case XK_Shift_Lock: - case XK_Caps_Lock: - /* Ignore releases and all but first press */ - if (kbdLinuxModIgnore(priv, &xE, keySym)) return; - if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; - else xE.u.u.type = KeyPress; - break; - } -#endif - - /* If key is already down, ignore or autorepeat */ - if (type == KeyPress && kbdUSBKeyDown(priv, keyCode)) { - KbdFeedbackClassRec *feed = priv->pDevice->kbdfeed; - - /* No auto-repeat? */ - if ((feed && !feed->ctrl.autoRepeat) - || priv->pDevice->key->xkbInfo->desc->map->modmap[keyCode] - || (feed - && !(feed->ctrl.autoRepeats[keyCode >> 3] - & (1 << (keyCode & 7))))) return; /* Ignore */ - - /* Do auto-repeat */ - enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); - type = KeyPress; - } - - /* If key is already up, ignore */ - if (type == KeyRelease && !kbdUSBKeyDown(priv, keyCode)) return; - } - - switching = 0; - if (checkspecial && type == KeyPress) - switching = checkspecial(pDev, keySym); - if (!switching) { - if (enqueue) - enqueue(pDev, type, keyCode, keySym, NULL, block); - kbdUSBKeyState(priv, type, keyCode); /* Update our state bitmap */ - } -} - -/** Read an event from the \a pDev device. If the event is a motion - * event, enqueue it with the \a motion function. Otherwise, check for - * special keys with the \a checkspecial function and enqueue the event - * with the \a enqueue function. The \a block type is passed to the - * functions so that they may block SIGIO handling as appropriate to the - * caller of this function. */ -void kbdUSBRead(DevicePtr pDev, - MOTIONPROC motion, - ENQUEUEPROC enqueue, - CHECKPROC checkspecial, - BLOCK block) -{ - GETPRIV; - struct input_event raw; - - while (read(priv->fd, &raw, sizeof(raw)) > 0) { -#if USB_KEYBOARD_DEBUG - LOG3("KBD: type = %d, code = 0x%02x, value = %d\n", - raw.type, raw.code, raw.value); -#endif - kbdUSBConvert(pDev, raw.code, raw.value, enqueue, checkspecial, block); - } -} - -/** Turn \a pDev on (i.e., take input from \a pDev). */ -int kbdUSBOn(DevicePtr pDev) -{ - GETPRIV; - - if (priv->fd < 0) kbdUSBInit(pDev); - return priv->fd; -} - -static void kbdUSBGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) -{ - KeySym *k, *mapCopy; - int i; - - mapCopy = xalloc(sizeof(map)); - memcpy(mapCopy, map, sizeof(map)); - - /* compute the modifier map */ - for (i = 0; i < MAP_LENGTH; i++) - pModMap[i] = NoSymbol; /* make sure it is restored */ - - for (k = mapCopy, i = MIN_KEYCODE; - i < NUM_KEYCODES + MIN_KEYCODE; - i++, k += 4) { - switch(*k) { - case XK_Shift_L: - case XK_Shift_R: pModMap[i] = ShiftMask; break; - case XK_Control_L: - case XK_Control_R: pModMap[i] = ControlMask; break; - case XK_Caps_Lock: pModMap[i] = LockMask; break; - case XK_Alt_L: - case XK_Alt_R: pModMap[i] = AltMask; break; - case XK_Num_Lock: pModMap[i] = NumLockMask; break; - case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; - case XK_Kana_Lock: - case XK_Kana_Shift: pModMap[i] = KanaMask; break; - case XK_Mode_switch: pModMap[i] = AltLangMask; break; - } - } - - pKeySyms->map = mapCopy; /* Must be XFree'able */ - pKeySyms->mapWidth = GLYPHS_PER_KEY; - pKeySyms->minKeyCode = MIN_KEYCODE; - pKeySyms->maxKeyCode = MAX_KEYCODE; -} - -/** Fill the \a info structure with information needed to initialize \a - * pDev. */ -void kbdUSBGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) -{ - info->keyboard = 1; - info->keyClass = 1; - kbdUSBGetMap(pDev, &info->keySyms, info->modMap); - info->focusClass = 1; - info->kbdFeedbackClass = 1; - info->names.keycodes = xstrdup("powerpcps2"); - info->force = 1; -} +/* Portions of this file were derived from the following files: + * + ********************************************************************** + * + * xfree86/common/xf86KbdLnx.c + * + * Linux version of keymapping setup. The kernel (since 0.99.14) has support + * for fully remapping the keyboard, but there are some differences between + * the Linux map and the SVR4 map (esp. in the extended keycodes). We also + * remove the restriction on what keycodes can be remapped. + * Orest Zborowski. + * + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * 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 Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL 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. + * + */ + +/* + * 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: + * Rickard E. (Rik) Faith <faith@redhat.com> + * + */ + +/** \file + * + * This code implements a low-level device driver for a USB keyboard + * under Linux. The keymap description is derived from code by Thomas + * Roell, Orest Zborowski. */ + +#ifdef HAVE_DMX_CONFIG_H +#include <dmx-config.h> +#endif + +#include "atKeynames.h" +#include "usb-private.h" + +#define USB_KEYBOARD_DEBUG 0 + +/*****************************************************************************/ +/* Define some macros to make it easier to move this file to another + * part of the Xserver tree. All calls to the dmx* layer are #defined + * here for the .c file. The .h file will also have to be edited. */ +#include "usb-keyboard.h" +#include <xkbsrv.h> + +#define GETPRIV myPrivate *priv \ + = ((DMXLocalInputInfoPtr)(pDev->devicePrivate))->private + +#define LOG0(f) dmxLog(dmxDebug,f) +#define LOG1(f,a) dmxLog(dmxDebug,f,a) +#define LOG2(f,a,b) dmxLog(dmxDebug,f,a,b) +#define LOG3(f,a,b,c) dmxLog(dmxDebug,f,a,b,c) +#define FATAL0(f) dmxLog(dmxFatal,f) +#define FATAL1(f,a) dmxLog(dmxFatal,f,a) +#define FATAL2(f,a,b) dmxLog(dmxFatal,f,a,b) +#define MOTIONPROC dmxMotionProcPtr +#define ENQUEUEPROC dmxEnqueueProcPtr +#define CHECKPROC dmxCheckSpecialProcPtr +#define BLOCK DMXBlockType + +/* End of interface definitions. */ +/*****************************************************************************/ + +#define GLYPHS_PER_KEY 4 +#define NUM_KEYCODES 248 +#define MIN_KEYCODE 8 +#define MAX_KEYCODE (NUM_KEYCODES + MIN_KEYCODE - 1) + +static KeySym map[NUM_KEYCODES * GLYPHS_PER_KEY] = { +/* Table modified from xc/programs/Xserver/hw/xfree86/common/xf86Keymap.h */ + /* 0x00 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x01 */ XK_Escape, NoSymbol, NoSymbol, NoSymbol, + /* 0x02 */ XK_1, XK_exclam, NoSymbol, NoSymbol, + /* 0x03 */ XK_2, XK_at, NoSymbol, NoSymbol, + /* 0x04 */ XK_3, XK_numbersign, NoSymbol, NoSymbol, + /* 0x05 */ XK_4, XK_dollar, NoSymbol, NoSymbol, + /* 0x06 */ XK_5, XK_percent, NoSymbol, NoSymbol, + /* 0x07 */ XK_6, XK_asciicircum, NoSymbol, NoSymbol, + /* 0x08 */ XK_7, XK_ampersand, NoSymbol, NoSymbol, + /* 0x09 */ XK_8, XK_asterisk, NoSymbol, NoSymbol, + /* 0x0a */ XK_9, XK_parenleft, NoSymbol, NoSymbol, + /* 0x0b */ XK_0, XK_parenright, NoSymbol, NoSymbol, + /* 0x0c */ XK_minus, XK_underscore, NoSymbol, NoSymbol, + /* 0x0d */ XK_equal, XK_plus, NoSymbol, NoSymbol, + /* 0x0e */ XK_BackSpace, NoSymbol, NoSymbol, NoSymbol, + /* 0x0f */ XK_Tab, XK_ISO_Left_Tab,NoSymbol, NoSymbol, + /* 0x10 */ XK_Q, NoSymbol, NoSymbol, NoSymbol, + /* 0x11 */ XK_W, NoSymbol, NoSymbol, NoSymbol, + /* 0x12 */ XK_E, NoSymbol, NoSymbol, NoSymbol, + /* 0x13 */ XK_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x14 */ XK_T, NoSymbol, NoSymbol, NoSymbol, + /* 0x15 */ XK_Y, NoSymbol, NoSymbol, NoSymbol, + /* 0x16 */ XK_U, NoSymbol, NoSymbol, NoSymbol, + /* 0x17 */ XK_I, NoSymbol, NoSymbol, NoSymbol, + /* 0x18 */ XK_O, NoSymbol, NoSymbol, NoSymbol, + /* 0x19 */ XK_P, NoSymbol, NoSymbol, NoSymbol, + /* 0x1a */ XK_bracketleft, XK_braceleft, NoSymbol, NoSymbol, + /* 0x1b */ XK_bracketright,XK_braceright, NoSymbol, NoSymbol, + /* 0x1c */ XK_Return, NoSymbol, NoSymbol, NoSymbol, + /* 0x1d */ XK_Control_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x1e */ XK_A, NoSymbol, NoSymbol, NoSymbol, + /* 0x1f */ XK_S, NoSymbol, NoSymbol, NoSymbol, + /* 0x20 */ XK_D, NoSymbol, NoSymbol, NoSymbol, + /* 0x21 */ XK_F, NoSymbol, NoSymbol, NoSymbol, + /* 0x22 */ XK_G, NoSymbol, NoSymbol, NoSymbol, + /* 0x23 */ XK_H, NoSymbol, NoSymbol, NoSymbol, + /* 0x24 */ XK_J, NoSymbol, NoSymbol, NoSymbol, + /* 0x25 */ XK_K, NoSymbol, NoSymbol, NoSymbol, + /* 0x26 */ XK_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x27 */ XK_semicolon, XK_colon, NoSymbol, NoSymbol, + /* 0x28 */ XK_quoteright, XK_quotedbl, NoSymbol, NoSymbol, + /* 0x29 */ XK_quoteleft, XK_asciitilde, NoSymbol, NoSymbol, + /* 0x2a */ XK_Shift_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x2b */ XK_backslash, XK_bar, NoSymbol, NoSymbol, + /* 0x2c */ XK_Z, NoSymbol, NoSymbol, NoSymbol, + /* 0x2d */ XK_X, NoSymbol, NoSymbol, NoSymbol, + /* 0x2e */ XK_C, NoSymbol, NoSymbol, NoSymbol, + /* 0x2f */ XK_V, NoSymbol, NoSymbol, NoSymbol, + /* 0x30 */ XK_B, NoSymbol, NoSymbol, NoSymbol, + /* 0x31 */ XK_N, NoSymbol, NoSymbol, NoSymbol, + /* 0x32 */ XK_M, NoSymbol, NoSymbol, NoSymbol, + /* 0x33 */ XK_comma, XK_less, NoSymbol, NoSymbol, + /* 0x34 */ XK_period, XK_greater, NoSymbol, NoSymbol, + /* 0x35 */ XK_slash, XK_question, NoSymbol, NoSymbol, + /* 0x36 */ XK_Shift_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x37 */ XK_KP_Multiply, NoSymbol, NoSymbol, NoSymbol, + /* 0x38 */ XK_Alt_L, XK_Meta_L, NoSymbol, NoSymbol, + /* 0x39 */ XK_space, NoSymbol, NoSymbol, NoSymbol, + /* 0x3a */ XK_Caps_Lock, NoSymbol, NoSymbol, NoSymbol, + /* 0x3b */ XK_F1, NoSymbol, NoSymbol, NoSymbol, + /* 0x3c */ XK_F2, NoSymbol, NoSymbol, NoSymbol, + /* 0x3d */ XK_F3, NoSymbol, NoSymbol, NoSymbol, + /* 0x3e */ XK_F4, NoSymbol, NoSymbol, NoSymbol, + /* 0x3f */ XK_F5, NoSymbol, NoSymbol, NoSymbol, + /* 0x40 */ XK_F6, NoSymbol, NoSymbol, NoSymbol, + /* 0x41 */ XK_F7, NoSymbol, NoSymbol, NoSymbol, + /* 0x42 */ XK_F8, NoSymbol, NoSymbol, NoSymbol, + /* 0x43 */ XK_F9, NoSymbol, NoSymbol, NoSymbol, + /* 0x44 */ XK_F10, NoSymbol, NoSymbol, NoSymbol, + /* 0x45 */ XK_Num_Lock, NoSymbol, NoSymbol, NoSymbol, + /* 0x46 */ XK_Scroll_Lock, NoSymbol, NoSymbol, NoSymbol, + /* 0x47 */ XK_KP_Home, XK_KP_7, NoSymbol, NoSymbol, + /* 0x48 */ XK_KP_Up, XK_KP_8, NoSymbol, NoSymbol, + /* 0x49 */ XK_KP_Prior, XK_KP_9, NoSymbol, NoSymbol, + /* 0x4a */ XK_KP_Subtract, NoSymbol, NoSymbol, NoSymbol, + /* 0x4b */ XK_KP_Left, XK_KP_4, NoSymbol, NoSymbol, + /* 0x4c */ XK_KP_Begin, XK_KP_5, NoSymbol, NoSymbol, + /* 0x4d */ XK_KP_Right, XK_KP_6, NoSymbol, NoSymbol, + /* 0x4e */ XK_KP_Add, NoSymbol, NoSymbol, NoSymbol, + /* 0x4f */ XK_KP_End, XK_KP_1, NoSymbol, NoSymbol, + /* 0x50 */ XK_KP_Down, XK_KP_2, NoSymbol, NoSymbol, + /* 0x51 */ XK_KP_Next, XK_KP_3, NoSymbol, NoSymbol, + /* 0x52 */ XK_KP_Insert, XK_KP_0, NoSymbol, NoSymbol, + /* 0x53 */ XK_KP_Delete, XK_KP_Decimal, NoSymbol, NoSymbol, + /* 0x54 */ XK_Sys_Req, NoSymbol, NoSymbol, NoSymbol, + /* 0x55 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x56 */ XK_less, XK_greater, NoSymbol, NoSymbol, + /* 0x57 */ XK_F11, NoSymbol, NoSymbol, NoSymbol, + /* 0x58 */ XK_F12, NoSymbol, NoSymbol, NoSymbol, + /* 0x59 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5a */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5b */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5c */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5d */ XK_Begin, NoSymbol, NoSymbol, NoSymbol, + /* 0x5e */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x5f */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x60 */ XK_KP_Enter, NoSymbol, NoSymbol, NoSymbol, + /* 0x61 */ XK_Control_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x62 */ XK_KP_Divide, NoSymbol, NoSymbol, NoSymbol, + /* 0x63 */ XK_Print, NoSymbol, NoSymbol, NoSymbol, + /* 0x64 */ XK_Alt_R, XK_Meta_R, NoSymbol, NoSymbol, + /* 0x65 */ XK_Break, NoSymbol, NoSymbol, NoSymbol, + /* 0x66 */ XK_Home, NoSymbol, NoSymbol, NoSymbol, + /* 0x67 */ XK_Up, NoSymbol, NoSymbol, NoSymbol, + /* 0x68 */ XK_Prior, NoSymbol, NoSymbol, NoSymbol, + /* 0x69 */ XK_Left, NoSymbol, NoSymbol, NoSymbol, + /* 0x6a */ XK_Right, NoSymbol, NoSymbol, NoSymbol, + /* 0x6b */ XK_End, NoSymbol, NoSymbol, NoSymbol, + /* 0x6c */ XK_Down, NoSymbol, NoSymbol, NoSymbol, + /* 0x6d */ XK_Next, NoSymbol, NoSymbol, NoSymbol, + /* 0x6e */ XK_Insert, NoSymbol, NoSymbol, NoSymbol, + /* 0x6f */ XK_Delete, NoSymbol, NoSymbol, NoSymbol, + /* 0x70 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x71 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x72 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x73 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x74 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x75 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x76 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x77 */ XK_Pause, NoSymbol, NoSymbol, NoSymbol, + /* 0x78 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x79 */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x7a */ XK_Menu, NoSymbol, NoSymbol, NoSymbol, + /* 0x7b */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x7c */ NoSymbol, NoSymbol, NoSymbol, NoSymbol, + /* 0x7d */ XK_Super_L, NoSymbol, NoSymbol, NoSymbol, + /* 0x7e */ XK_Super_R, NoSymbol, NoSymbol, NoSymbol, + /* 0x7f */ XK_Menu, NoSymbol, NoSymbol, NoSymbol, +}; + +static int kbdUSBKeyDown(myPrivate *priv, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return 0; + return priv->kbdState[byte] & bit; +} + +static void kbdUSBKeyState(myPrivate *priv, int type, int keyCode) +{ + CARD8 byte = keyCode >> 5; + CARD32 bit = 1 << (keyCode & 0x1f); + + if (byte > NUM_STATE_ENTRIES) return; + if (type == KeyPress) priv->kbdState[byte] |= bit; + else priv->kbdState[byte] &= ~bit; +} + +/** Set the LEDs. */ +void kbdUSBCtrl(DevicePtr pDev, KeybdCtrl *ctrl) +{ + GETPRIV; + struct timeval tv; + struct input_event event; + int i, led; + + gettimeofday(&tv, NULL); + for (i = 0; i < 5; i++) { + event.time.tv_sec = tv.tv_sec; + event.time.tv_usec = tv.tv_usec; + event.type = EV_LED; + if (i == 0) led = 1; /* LED_CAPSL == 0x01 */ + else if (i == 1) led = 0; /* LED_NUML == 0x00 */ + else led = i; + event.code = led; + event.value = !!(ctrl->leds & (1 << led)); + write(priv->fd, &event, sizeof(event)); + } +} + +/** Initialize \a pDev using #usbInit. */ +void kbdUSBInit(DevicePtr pDev) +{ + usbInit(pDev, usbKeyboard); +} + +static void kbdUSBConvert(DevicePtr pDev, + unsigned int scanCode, + int value, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + XkbSrvInfoPtr xkbi = priv->pKeyboard->key->xkbInfo; + int type; + int keyCode; + KeySym keySym = NoSymbol; + int switching; + + /* Set up xEvent information */ + type = value ? KeyPress : KeyRelease; + keyCode = (scanCode & 0xff) + MIN_KEYCODE; + + /* Handle repeats */ + + if (keyCode >= xkbi->desc->min_key_code && + keyCode <= xkbi->desc->max_key_code) { + + int effectiveGroup = XkbGetEffectiveGroup(xkbi, + &xkbi->state, + scanCode); + keySym = XkbKeySym(xkbi->desc, scanCode, effectiveGroup); +#if 0 + switch (keySym) { + case XK_Num_Lock: + case XK_Scroll_Lock: + case XK_Shift_Lock: + case XK_Caps_Lock: + /* Ignore releases and all but first press */ + if (kbdLinuxModIgnore(priv, &xE, keySym)) return; + if (kbdLinuxKeyDown(priv, &xE)) xE.u.u.type = KeyRelease; + else xE.u.u.type = KeyPress; + break; + } +#endif + + /* If key is already down, ignore or autorepeat */ + if (type == KeyPress && kbdUSBKeyDown(priv, keyCode)) { + KbdFeedbackClassRec *feed = priv->pDevice->kbdfeed; + + /* No auto-repeat? */ + if ((feed && !feed->ctrl.autoRepeat) + || priv->pDevice->key->xkbInfo->desc->map->modmap[keyCode] + || (feed + && !(feed->ctrl.autoRepeats[keyCode >> 3] + & (1 << (keyCode & 7))))) return; /* Ignore */ + + /* Do auto-repeat */ + enqueue(pDev, KeyRelease, keyCode, keySym, NULL, block); + type = KeyPress; + } + + /* If key is already up, ignore */ + if (type == KeyRelease && !kbdUSBKeyDown(priv, keyCode)) return; + } + + switching = 0; + if (checkspecial && type == KeyPress) + switching = checkspecial(pDev, keySym); + if (!switching) { + if (enqueue) + enqueue(pDev, type, keyCode, keySym, NULL, block); + kbdUSBKeyState(priv, type, keyCode); /* Update our state bitmap */ + } +} + +/** Read an event from the \a pDev device. If the event is a motion + * event, enqueue it with the \a motion function. Otherwise, check for + * special keys with the \a checkspecial function and enqueue the event + * with the \a enqueue function. The \a block type is passed to the + * functions so that they may block SIGIO handling as appropriate to the + * caller of this function. */ +void kbdUSBRead(DevicePtr pDev, + MOTIONPROC motion, + ENQUEUEPROC enqueue, + CHECKPROC checkspecial, + BLOCK block) +{ + GETPRIV; + struct input_event raw; + + while (read(priv->fd, &raw, sizeof(raw)) > 0) { +#if USB_KEYBOARD_DEBUG + LOG3("KBD: type = %d, code = 0x%02x, value = %d\n", + raw.type, raw.code, raw.value); +#endif + kbdUSBConvert(pDev, raw.code, raw.value, enqueue, checkspecial, block); + } +} + +/** Turn \a pDev on (i.e., take input from \a pDev). */ +int kbdUSBOn(DevicePtr pDev) +{ + GETPRIV; + + if (priv->fd < 0) kbdUSBInit(pDev); + return priv->fd; +} + +static void kbdUSBGetMap(DevicePtr pDev, KeySymsPtr pKeySyms, CARD8 *pModMap) +{ + KeySym *k, *mapCopy; + int i; + + mapCopy = malloc(sizeof(map)); + memcpy(mapCopy, map, sizeof(map)); + + /* compute the modifier map */ + for (i = 0; i < MAP_LENGTH; i++) + pModMap[i] = NoSymbol; /* make sure it is restored */ + + for (k = mapCopy, i = MIN_KEYCODE; + i < NUM_KEYCODES + MIN_KEYCODE; + i++, k += 4) { + switch(*k) { + case XK_Shift_L: + case XK_Shift_R: pModMap[i] = ShiftMask; break; + case XK_Control_L: + case XK_Control_R: pModMap[i] = ControlMask; break; + case XK_Caps_Lock: pModMap[i] = LockMask; break; + case XK_Alt_L: + case XK_Alt_R: pModMap[i] = AltMask; break; + case XK_Num_Lock: pModMap[i] = NumLockMask; break; + case XK_Scroll_Lock: pModMap[i] = ScrollLockMask; break; + case XK_Kana_Lock: + case XK_Kana_Shift: pModMap[i] = KanaMask; break; + case XK_Mode_switch: pModMap[i] = AltLangMask; break; + } + } + + pKeySyms->map = mapCopy; /* Must be XFree'able */ + pKeySyms->mapWidth = GLYPHS_PER_KEY; + pKeySyms->minKeyCode = MIN_KEYCODE; + pKeySyms->maxKeyCode = MAX_KEYCODE; +} + +/** Fill the \a info structure with information needed to initialize \a + * pDev. */ +void kbdUSBGetInfo(DevicePtr pDev, DMXLocalInitInfoPtr info) +{ + info->keyboard = 1; + info->keyClass = 1; + kbdUSBGetMap(pDev, &info->keySyms, info->modMap); + info->focusClass = 1; + info->kbdFeedbackClass = 1; + info->names.keycodes = xstrdup("powerpcps2"); + info->force = 1; +} -- cgit v1.2.3