From c38dead3ea7e177728d90cd815cf4eead0c9f534 Mon Sep 17 00:00:00 2001 From: marha Date: Sat, 15 May 2010 16:28:11 +0000 Subject: xserver git update 15/5/2010 --- xorg-server/hw/kdrive/ephyr/ephyr.c | 2358 ++++++------- xorg-server/hw/kdrive/ephyr/ephyr_draw.c | 1047 +++--- xorg-server/hw/kdrive/ephyr/ephyrdriext.c | 2858 ++++++++-------- xorg-server/hw/kdrive/ephyr/ephyrglxext.c | 1446 ++++---- xorg-server/hw/kdrive/ephyr/ephyrhostvideo.c | 2024 +++++------ xorg-server/hw/kdrive/ephyr/ephyrvideo.c | 2546 +++++++------- xorg-server/hw/kdrive/fake/fake.c | 952 +++--- xorg-server/hw/kdrive/fbdev/fbdev.c | 1652 ++++----- xorg-server/hw/kdrive/linux/evdev.c | 1078 +++--- xorg-server/hw/kdrive/linux/keyboard.c | 1530 ++++----- xorg-server/hw/kdrive/linux/mouse.c | 2060 +++++------ xorg-server/hw/kdrive/linux/tslib.c | 380 +-- xorg-server/hw/kdrive/src/kcmap.c | 492 +-- xorg-server/hw/kdrive/src/kdrive.c | 2566 +++++++------- xorg-server/hw/kdrive/src/kinfo.c | 326 +- xorg-server/hw/kdrive/src/kinput.c | 4720 +++++++++++++------------- xorg-server/hw/kdrive/src/kshadow.c | 162 +- xorg-server/hw/kdrive/src/kxv.c | 3814 ++++++++++----------- 18 files changed, 16005 insertions(+), 16006 deletions(-) (limited to 'xorg-server/hw/kdrive') diff --git a/xorg-server/hw/kdrive/ephyr/ephyr.c b/xorg-server/hw/kdrive/ephyr/ephyr.c index b21559bba..439a2b274 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyr.c +++ b/xorg-server/hw/kdrive/ephyr/ephyr.c @@ -1,1179 +1,1179 @@ -/* - * Xephyr - A kdrive X server thats runs in a host X window. - * Authored by Matthew Allum - * - * Copyright © 2004 Nokia - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Nokia not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Nokia makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "ephyr.h" - -#include "inputstr.h" -#include "scrnintstr.h" -#include "ephyrlog.h" - -#ifdef XF86DRI -#include "ephyrdri.h" -#include "ephyrdriext.h" -#include "ephyrglxext.h" -#endif /* XF86DRI */ - -extern int KdTsPhyScreen; -#ifdef GLXEXT -extern Bool noGlxVisualInit; -#endif - -KdKeyboardInfo *ephyrKbd; -KdPointerInfo *ephyrMouse; -EphyrKeySyms ephyrKeySyms; -Bool ephyrNoDRI=FALSE ; -Bool ephyrNoXV=FALSE ; - -static int mouseState = 0; - -typedef struct _EphyrInputPrivate { - Bool enabled; -} EphyrKbdPrivate, EphyrPointerPrivate; - -Bool EphyrWantGrayScale = 0; - - -Bool -ephyrInitialize (KdCardInfo *card, EphyrPriv *priv) -{ - OsSignal(SIGUSR1, hostx_handle_signal); - - priv->base = 0; - priv->bytes_per_line = 0; - return TRUE; -} - -Bool -ephyrCardInit (KdCardInfo *card) -{ - EphyrPriv *priv; - - priv = (EphyrPriv *) xalloc (sizeof (EphyrPriv)); - if (!priv) - return FALSE; - - if (!ephyrInitialize (card, priv)) - { - xfree (priv); - return FALSE; - } - card->driver = priv; - - return TRUE; -} - -Bool -ephyrScreenInitialize (KdScreenInfo *screen, EphyrScrPriv *scrpriv) -{ - int width = 640, height = 480; - CARD32 redMask, greenMask, blueMask; - - if (hostx_want_screen_size(screen, &width, &height) - || !screen->width || !screen->height) - { - screen->width = width; - screen->height = height; - } - - if (EphyrWantGrayScale) - screen->fb.depth = 8; - - if (screen->fb.depth && screen->fb.depth != hostx_get_depth()) - { - if (screen->fb.depth < hostx_get_depth() - && (screen->fb.depth == 24 || screen->fb.depth == 16 - || screen->fb.depth == 8)) - { - hostx_set_server_depth(screen, screen->fb.depth); - } - else - ErrorF("\nXephyr: requested screen depth not supported, setting to match hosts.\n"); - } - - screen->fb.depth = hostx_get_server_depth(screen); - screen->rate = 72; - - if (screen->fb.depth <= 8) - { - if (EphyrWantGrayScale) - screen->fb.visuals = ((1 << StaticGray) | (1 << GrayScale)); - else - screen->fb.visuals = ((1 << StaticGray) | - (1 << GrayScale) | - (1 << StaticColor) | - (1 << PseudoColor) | - (1 << TrueColor) | - (1 << DirectColor)); - - screen->fb.redMask = 0x00; - screen->fb.greenMask = 0x00; - screen->fb.blueMask = 0x00; - screen->fb.depth = 8; - screen->fb.bitsPerPixel = 8; - } - else - { - screen->fb.visuals = (1 << TrueColor); - - if (screen->fb.depth <= 15) - { - screen->fb.depth = 15; - screen->fb.bitsPerPixel = 16; - } - else if (screen->fb.depth <= 16) - { - screen->fb.depth = 16; - screen->fb.bitsPerPixel = 16; - } - else if (screen->fb.depth <= 24) - { - screen->fb.depth = 24; - screen->fb.bitsPerPixel = 32; - } - else if (screen->fb.depth <= 30) - { - screen->fb.depth = 30; - screen->fb.bitsPerPixel = 32; - } - else - { - ErrorF("\nXephyr: Unsupported screen depth %d\n", - screen->fb.depth); - return FALSE; - } - - hostx_get_visual_masks (screen, &redMask, &greenMask, &blueMask); - - screen->fb.redMask = (Pixel) redMask; - screen->fb.greenMask = (Pixel) greenMask; - screen->fb.blueMask = (Pixel) blueMask; - - } - - scrpriv->randr = screen->randr; - - return ephyrMapFramebuffer (screen); -} - -Bool -ephyrScreenInit (KdScreenInfo *screen) -{ - EphyrScrPriv *scrpriv; - - scrpriv = xcalloc (1, sizeof (EphyrScrPriv)); - - if (!scrpriv) - return FALSE; - - screen->driver = scrpriv; - - if (!ephyrScreenInitialize (screen, scrpriv)) - { - screen->driver = 0; - xfree (scrpriv); - return FALSE; - } - - return TRUE; -} - -void* -ephyrWindowLinear (ScreenPtr pScreen, - CARD32 row, - CARD32 offset, - int mode, - CARD32 *size, - void *closure) -{ - KdScreenPriv(pScreen); - EphyrPriv *priv = pScreenPriv->card->driver; - - if (!pScreenPriv->enabled) - return 0; - - *size = priv->bytes_per_line; - return priv->base + row * priv->bytes_per_line + offset; -} - -/** - * Figure out display buffer size. If fakexa is enabled, allocate a larger - * buffer so that fakexa has space to put offscreen pixmaps. - */ -int -ephyrBufferHeight(KdScreenInfo *screen) -{ - int buffer_height; - if (ephyrFuncs.initAccel == NULL) - buffer_height = screen->height; - else - buffer_height = 3 * screen->height; - return buffer_height; -} - - -Bool -ephyrMapFramebuffer (KdScreenInfo *screen) -{ - EphyrScrPriv *scrpriv = screen->driver; - EphyrPriv *priv = screen->card->driver; - KdPointerMatrix m; - int buffer_height; - - EPHYR_LOG("screen->width: %d, screen->height: %d index=%d", - screen->width, screen->height, screen->mynum); - - KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); - KdSetPointerMatrix (&m); - - priv->bytes_per_line = ((screen->width * screen->fb.bitsPerPixel + 31) >> 5) << 2; - - buffer_height = ephyrBufferHeight(screen); - - priv->base = hostx_screen_init (screen, screen->width, screen->height, buffer_height); - - if ((scrpriv->randr & RR_Rotate_0) && !(scrpriv->randr & RR_Reflect_All)) - { - scrpriv->shadow = FALSE; - - screen->fb.byteStride = priv->bytes_per_line; - screen->fb.pixelStride = screen->width; - screen->fb.frameBuffer = (CARD8 *) (priv->base); - } - else - { - /* Rotated/Reflected so we need to use shadow fb */ - scrpriv->shadow = TRUE; - - EPHYR_LOG("allocing shadow"); - - KdShadowFbAlloc (screen, - scrpriv->randr & (RR_Rotate_90|RR_Rotate_270)); - } - - return TRUE; -} - -void -ephyrSetScreenSizes (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - - if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) - { - pScreen->width = screen->width; - pScreen->height = screen->height; - pScreen->mmWidth = screen->width_mm; - pScreen->mmHeight = screen->height_mm; - } - else - { - pScreen->width = screen->height; - pScreen->height = screen->width; - pScreen->mmWidth = screen->height_mm; - pScreen->mmHeight = screen->width_mm; - } -} - -Bool -ephyrUnmapFramebuffer (KdScreenInfo *screen) -{ - EphyrScrPriv *scrpriv = screen->driver; - - if (scrpriv->shadow) - KdShadowFbFree (screen); - - /* Note, priv->base will get freed when XImage recreated */ - - return TRUE; -} - -void -ephyrShadowUpdate (ScreenPtr pScreen, shadowBufPtr pBuf) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - - EPHYR_LOG("slow paint"); - - /* FIXME: Slow Rotated/Reflected updates could be much - * much faster efficiently updating via tranforming - * pBuf->pDamage regions - */ - shadowUpdateRotatePacked(pScreen, pBuf); - hostx_paint_rect(screen, 0,0,0,0, screen->width, screen->height); -} - -static void -ephyrInternalDamageRedisplay (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - RegionPtr pRegion; - - if (!scrpriv || !scrpriv->pDamage) - return; - - pRegion = DamageRegion (scrpriv->pDamage); - - if (REGION_NOTEMPTY (pScreen, pRegion)) - { - int nbox; - BoxPtr pbox; - - nbox = REGION_NUM_RECTS (pRegion); - pbox = REGION_RECTS (pRegion); - - while (nbox--) - { - hostx_paint_rect(screen, - pbox->x1, pbox->y1, - pbox->x1, pbox->y1, - pbox->x2 - pbox->x1, - pbox->y2 - pbox->y1); - pbox++; - } - DamageEmpty (scrpriv->pDamage); - } -} - -static void -ephyrInternalDamageBlockHandler (pointer data, - OSTimePtr pTimeout, - pointer pRead) -{ - ScreenPtr pScreen = (ScreenPtr) data; - - ephyrInternalDamageRedisplay (pScreen); -} - -static void -ephyrInternalDamageWakeupHandler (pointer data, int i, pointer LastSelectMask) -{ - /* FIXME: Not needed ? */ -} - -Bool -ephyrSetInternalDamage (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - PixmapPtr pPixmap = NULL; - - scrpriv->pDamage = DamageCreate ((DamageReportFunc) 0, - (DamageDestroyFunc) 0, - DamageReportNone, - TRUE, - pScreen, - pScreen); - - if (!RegisterBlockAndWakeupHandlers (ephyrInternalDamageBlockHandler, - ephyrInternalDamageWakeupHandler, - (pointer) pScreen)) - return FALSE; - - pPixmap = (*pScreen->GetScreenPixmap) (pScreen); - - DamageRegister (&pPixmap->drawable, scrpriv->pDamage); - - return TRUE; -} - -void -ephyrUnsetInternalDamage (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - PixmapPtr pPixmap = NULL; - - pPixmap = (*pScreen->GetScreenPixmap) (pScreen); - DamageUnregister (&pPixmap->drawable, scrpriv->pDamage); - DamageDestroy (scrpriv->pDamage); - - RemoveBlockAndWakeupHandlers (ephyrInternalDamageBlockHandler, - ephyrInternalDamageWakeupHandler, - (pointer) pScreen); -} - -#ifdef RANDR -Bool -ephyrRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - RRScreenSizePtr pSize; - Rotation randr; - int n = 0; - - struct { int width, height; } sizes[] = - { - { 1600, 1200 }, - { 1400, 1050 }, - { 1280, 960 }, - { 1280, 1024 }, - { 1152, 864 }, - { 1024, 768 }, - { 832, 624 }, - { 800, 600 }, - { 720, 400 }, - { 480, 640 }, - { 640, 480 }, - { 640, 400 }, - { 320, 240 }, - { 240, 320 }, - { 160, 160 }, - { 0, 0 } - }; - - EPHYR_LOG("mark"); - - *rotations = RR_Rotate_All|RR_Reflect_All; - - if (!hostx_want_preexisting_window (screen) - && !hostx_want_fullscreen ()) /* only if no -parent switch */ - { - while (sizes[n].width != 0 && sizes[n].height != 0) - { - RRRegisterSize (pScreen, - sizes[n].width, - sizes[n].height, - (sizes[n].width * screen->width_mm)/screen->width, - (sizes[n].height *screen->height_mm)/screen->height - ); - n++; - } - } - - pSize = RRRegisterSize (pScreen, - screen->width, - screen->height, - screen->width_mm, - screen->height_mm); - - randr = KdSubRotation (scrpriv->randr, screen->randr); - - RRSetCurrentConfig (pScreen, randr, 0, pSize); - - return TRUE; -} - -Bool -ephyrRandRSetConfig (ScreenPtr pScreen, - Rotation randr, - int rate, - RRScreenSizePtr pSize) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - Bool wasEnabled = pScreenPriv->enabled; - EphyrScrPriv oldscr; - int oldwidth, oldheight, oldmmwidth, oldmmheight; - Bool oldshadow; - int newwidth, newheight; - - if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) - { - newwidth = pSize->width; - newheight = pSize->height; - } - else - { - newwidth = pSize->height; - newheight = pSize->width; - } - - if (wasEnabled) - KdDisableScreen (pScreen); - - oldscr = *scrpriv; - - oldwidth = screen->width; - oldheight = screen->height; - oldmmwidth = pScreen->mmWidth; - oldmmheight = pScreen->mmHeight; - oldshadow = scrpriv->shadow; - - /* - * Set new configuration - */ - - scrpriv->randr = KdAddRotation (screen->randr, randr); - - ephyrUnmapFramebuffer (screen); - - screen->width = newwidth; - screen->height = newheight; - - if (!ephyrMapFramebuffer (screen)) - goto bail4; - - /* FIXME below should go in own call */ - - if (oldshadow) - KdShadowUnset (screen->pScreen); - else - ephyrUnsetInternalDamage(screen->pScreen); - - if (scrpriv->shadow) - { - if (!KdShadowSet (screen->pScreen, - scrpriv->randr, - ephyrShadowUpdate, - ephyrWindowLinear)) - goto bail4; - } - else - { - /* Without shadow fb ( non rotated ) we need - * to use damage to efficiently update display - * via signal regions what to copy from 'fb'. - */ - if (!ephyrSetInternalDamage(screen->pScreen)) - goto bail4; - } - - ephyrSetScreenSizes (screen->pScreen); - - /* - * Set frame buffer mapping - */ - (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), - pScreen->width, - pScreen->height, - screen->fb.depth, - screen->fb.bitsPerPixel, - screen->fb.byteStride, - screen->fb.frameBuffer); - - /* set the subpixel order */ - - KdSetSubpixelOrder (pScreen, scrpriv->randr); - - if (wasEnabled) - KdEnableScreen (pScreen); - - return TRUE; - - bail4: - EPHYR_LOG("bailed"); - - ephyrUnmapFramebuffer (screen); - *scrpriv = oldscr; - (void) ephyrMapFramebuffer (screen); - - pScreen->width = oldwidth; - pScreen->height = oldheight; - pScreen->mmWidth = oldmmwidth; - pScreen->mmHeight = oldmmheight; - - if (wasEnabled) - KdEnableScreen (pScreen); - return FALSE; -} - -Bool -ephyrRandRInit (ScreenPtr pScreen) -{ - rrScrPrivPtr pScrPriv; - - if (!RRScreenInit (pScreen)) - return FALSE; - - pScrPriv = rrGetScrPriv(pScreen); - pScrPriv->rrGetInfo = ephyrRandRGetInfo; - pScrPriv->rrSetConfig = ephyrRandRSetConfig; - return TRUE; -} -#endif - -Bool -ephyrCreateColormap (ColormapPtr pmap) -{ - return fbInitializeColormap (pmap); -} - -Bool -ephyrInitScreen (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - - EPHYR_LOG ("pScreen->myNum:%d\n", pScreen->myNum) ; - hostx_set_screen_number (screen, pScreen->myNum); - hostx_set_win_title (screen, "(ctrl+shift grabs mouse and keyboard)") ; - pScreen->CreateColormap = ephyrCreateColormap; - -#ifdef XV - if (!ephyrNoXV) { - if (!ephyrInitVideo (pScreen)) { - EPHYR_LOG_ERROR ("failed to initialize xvideo\n") ; - } else { - EPHYR_LOG ("initialized xvideo okay\n") ; - } - } -#endif /*XV*/ - -#ifdef XF86DRI - if (!ephyrNoDRI && !hostx_has_dri ()) { - EPHYR_LOG ("host x does not support DRI. Disabling DRI forwarding\n") ; - ephyrNoDRI = TRUE ; -#ifdef GLXEXT - noGlxVisualInit = FALSE ; -#endif - } - if (!ephyrNoDRI) { - ephyrDRIExtensionInit (pScreen) ; - ephyrHijackGLXExtension () ; - } -#endif - -#ifdef GLXEXT - if (ephyrNoDRI) { - noGlxVisualInit = FALSE ; - } -#endif - - return TRUE; -} - -Bool -ephyrFinishInitScreen (ScreenPtr pScreen) -{ - /* FIXME: Calling this even if not using shadow. - * Seems harmless enough. But may be safer elsewhere. - */ - if (!shadowSetup (pScreen)) - return FALSE; - -#ifdef RANDR - if (!ephyrRandRInit (pScreen)) - return FALSE; -#endif - - return TRUE; -} - -Bool -ephyrCreateResources (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - - EPHYR_LOG("mark pScreen=%p mynum=%d shadow=%d", - pScreen, pScreen->myNum, scrpriv->shadow); - - if (scrpriv->shadow) - return KdShadowSet (pScreen, - scrpriv->randr, - ephyrShadowUpdate, - ephyrWindowLinear); - else - return ephyrSetInternalDamage(pScreen); -} - -void -ephyrPreserve (KdCardInfo *card) -{ -} - -Bool -ephyrEnable (ScreenPtr pScreen) -{ - return TRUE; -} - -Bool -ephyrDPMS (ScreenPtr pScreen, int mode) -{ - return TRUE; -} - -void -ephyrDisable (ScreenPtr pScreen) -{ -} - -void -ephyrRestore (KdCardInfo *card) -{ -} - -void -ephyrScreenFini (KdScreenInfo *screen) -{ - EphyrScrPriv *scrpriv = screen->driver; - if (scrpriv->shadow) { - KdShadowFbFree (screen); - } - xfree(screen->driver); - screen->driver = NULL; -} - -/* - * Port of Mark McLoughlin's Xnest fix for focus in + modifier bug. - * See https://bugs.freedesktop.org/show_bug.cgi?id=3030 - */ -void -ephyrUpdateModifierState(unsigned int state) -{ -#if 0 - DeviceIntPtr pkeydev; - KeyClassPtr keyc; - int i; - CARD8 mask; - - pkeydev = inputInfo.keyboard; - - if (!pkeydev) - return; - -/* This is pretty broken. - * - * What should happen is that focus out should do as a VT switch does in - * traditional servers: fake releases for all keys (and buttons too, come - * to think of it) currently down. Then, on focus in, get the state from - * the host, and fake keypresses for everything currently down. - * - * So I'm leaving this broken for a little while. Sorry, folks. - * - * -daniels - */ - - keyc = pkeydev->key; - - state = state & 0xff; - - if (keyc->state == state) - return; - - for (i = 0, mask = 1; i < 8; i++, mask <<= 1) - { - int key; - - /* Modifier is down, but shouldn't be */ - if ((keyc->state & mask) && !(state & mask)) - { - int count = keyc->modifierKeyCount[i]; - - for (key = 0; key < MAP_LENGTH; key++) - if (keyc->xkbInfo->desc->map->modmap[key] & mask) - { - int bit; - BYTE *kptr; - - kptr = &keyc->down[key >> 3]; - bit = 1 << (key & 7); - - if (*kptr & bit && ephyrKbd && - ((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) - KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE); /* release */ - - if (--count == 0) - break; - } - } - - /* Modifier shoud be down, but isn't */ - if (!(keyc->state & mask) && (state & mask)) - for (key = 0; key < MAP_LENGTH; key++) - if (keyc->xkbInfo->desc->map->modmap[key] & mask) - { - if (keyc->xkbInfo->desc->map->modmap[key] & mask && ephyrKbd && - ((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) - KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE); /* press */ - break; - } - } -#endif -} - -static void -ephyrBlockSigio (void) -{ - sigset_t set; - - sigemptyset (&set); - sigaddset (&set, SIGIO); - sigprocmask (SIG_BLOCK, &set, 0); -} - -static void -ephyrUnblockSigio (void) -{ - sigset_t set; - - sigemptyset (&set); - sigaddset (&set, SIGIO); - sigprocmask (SIG_UNBLOCK, &set, 0); -} - -static Bool -ephyrCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) -{ - return FALSE; -} - -static void -ephyrCrossScreen (ScreenPtr pScreen, Bool entering) -{ -} - -int ephyrCurScreen; /*current event screen*/ - -static void -ephyrWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - ephyrBlockSigio (); - ephyrCurScreen = pScreen->myNum; - miPointerWarpCursor (inputInfo.pointer, pScreen, x, y); - ephyrUnblockSigio (); -} - -miPointerScreenFuncRec ephyrPointerScreenFuncs = -{ - ephyrCursorOffScreen, - ephyrCrossScreen, - ephyrWarpCursor, - NULL, - NULL -}; - -#ifdef XF86DRI -/** - * find if the remote window denoted by a_remote - * is paired with an internal Window within the Xephyr server. - * If the remove window is paired with an internal window, send an - * expose event to the client insterested in the internal window expose event. - * - * Pairing happens when a drawable inside Xephyr is associated with - * a GL surface in a DRI environment. - * Look at the function ProcXF86DRICreateDrawable in ephyrdriext.c to - * know a paired window is created. - * - * This is useful to make GL drawables (only windows for now) handle - * expose events and send those events to clients. - */ -static void -ephyrExposePairedWindow (int a_remote) -{ - EphyrWindowPair *pair = NULL; - RegionRec reg; - ScreenPtr screen; - - if (!findWindowPairFromRemote (a_remote, &pair)) { - EPHYR_LOG ("did not find a pair for this window\n"); - return; - } - screen = pair->local->drawable.pScreen; - REGION_NULL (screen, ®); - REGION_COPY (screen, ®, &pair->local->clipList); - screen->WindowExposures (pair->local, ®, NullRegion); - REGION_UNINIT (screen, ®); -} -#endif /* XF86DRI */ - -void -ephyrPoll(void) -{ - EphyrHostXEvent ev; - - while (hostx_get_event(&ev)) - { - switch (ev.type) - { - case EPHYR_EV_MOUSE_MOTION: - if (!ephyrMouse || - !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) { - EPHYR_LOG ("skipping mouse motion:%d\n", ephyrCurScreen) ; - continue; - } - { - if (ev.data.mouse_motion.screen >=0 - && (ephyrCurScreen != ev.data.mouse_motion.screen)) - { - EPHYR_LOG ("warping mouse cursor. " - "cur_screen%d, motion_screen:%d\n", - ephyrCurScreen, ev.data.mouse_motion.screen) ; - if (ev.data.mouse_motion.screen >= 0) - { - ephyrWarpCursor - (inputInfo.pointer, screenInfo.screens[ev.data.mouse_motion.screen], - ev.data.mouse_motion.x, - ev.data.mouse_motion.y ); - } - } - else - { - int x=0, y=0; -#ifdef XF86DRI - EphyrWindowPair *pair = NULL; -#endif - EPHYR_LOG ("enqueuing mouse motion:%d\n", ephyrCurScreen) ; - x = ev.data.mouse_motion.x; - y = ev.data.mouse_motion.y; - EPHYR_LOG ("initial (x,y):(%d,%d)\n", x, y) ; -#ifdef XF86DRI - EPHYR_LOG ("is this window peered by a gl drawable ?\n") ; - if (findWindowPairFromRemote (ev.data.mouse_motion.window, - &pair)) - { - EPHYR_LOG ("yes, it is peered\n") ; - x += pair->local->drawable.x; - y += pair->local->drawable.y; - } - else - { - EPHYR_LOG ("no, it is not peered\n") ; - } - EPHYR_LOG ("final (x,y):(%d,%d)\n", x, y) ; -#endif - KdEnqueuePointerEvent(ephyrMouse, mouseState, x, y, 0); - } - } - break; - - case EPHYR_EV_MOUSE_PRESS: - if (!ephyrMouse || - !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) { - EPHYR_LOG ("skipping mouse press:%d\n", ephyrCurScreen) ; - continue; - } - EPHYR_LOG ("enqueuing mouse press:%d\n", ephyrCurScreen) ; - ephyrUpdateModifierState(ev.key_state); - mouseState |= ev.data.mouse_down.button_num; - KdEnqueuePointerEvent(ephyrMouse, mouseState|KD_MOUSE_DELTA, 0, 0, 0); - break; - - case EPHYR_EV_MOUSE_RELEASE: - if (!ephyrMouse || - !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) - continue; - ephyrUpdateModifierState(ev.key_state); - mouseState &= ~ev.data.mouse_up.button_num; - EPHYR_LOG ("enqueuing mouse release:%d\n", ephyrCurScreen) ; - KdEnqueuePointerEvent(ephyrMouse, mouseState|KD_MOUSE_DELTA, 0, 0, 0); - break; - - case EPHYR_EV_KEY_PRESS: - if (!ephyrKbd || - !((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) - continue; - ephyrUpdateModifierState(ev.key_state); - KdEnqueueKeyboardEvent (ephyrKbd, ev.data.key_down.scancode, FALSE); - break; - - case EPHYR_EV_KEY_RELEASE: - if (!ephyrKbd || - !((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) - continue; - KdEnqueueKeyboardEvent (ephyrKbd, ev.data.key_up.scancode, TRUE); - break; - -#ifdef XF86DRI - case EPHYR_EV_EXPOSE: - /* - * We only receive expose events when the expose event have - * be generated for a drawable that is a host X window managed - * by Xephyr. Host X windows managed by Xephyr exists for instance - * when Xephyr is asked to create a GL drawable in a DRI environment. - */ - ephyrExposePairedWindow (ev.data.expose.window); - break; -#endif /* XF86DRI */ - - default: - break; - } - } -} - -void -ephyrCardFini (KdCardInfo *card) -{ - EphyrPriv *priv = card->driver; - xfree (priv); -} - -void -ephyrGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ - /* XXX Not sure if this is right */ - - EPHYR_LOG("mark"); - - while (n--) - { - pdefs->red = 0; - pdefs->green = 0; - pdefs->blue = 0; - pdefs++; - } - -} - -void -ephyrPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ - int min, max, p; - - /* XXX Not sure if this is right */ - - min = 256; - max = 0; - - while (n--) - { - p = pdefs->pixel; - if (p < min) - min = p; - if (p > max) - max = p; - - hostx_set_cmap_entry(p, - pdefs->red >> 8, - pdefs->green >> 8, - pdefs->blue >> 8); - pdefs++; - } -} - -/* Mouse calls */ - -static Status -MouseInit (KdPointerInfo *pi) -{ - pi->driverPrivate = (EphyrPointerPrivate *) - xcalloc(sizeof(EphyrPointerPrivate), 1); - ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = FALSE; - pi->nAxes = 3; - pi->nButtons = 32; - xfree(pi->name); - pi->name = strdup("Xephyr virtual mouse"); - ephyrMouse = pi; - return Success; -} - -static Status -MouseEnable (KdPointerInfo *pi) -{ - ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = TRUE; - return Success; -} - -static void -MouseDisable (KdPointerInfo *pi) -{ - ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = FALSE; - return; -} - -static void -MouseFini (KdPointerInfo *pi) -{ - ephyrMouse = NULL; - return; -} - -KdPointerDriver EphyrMouseDriver = { - "ephyr", - MouseInit, - MouseEnable, - MouseDisable, - MouseFini, - NULL, -}; - -/* Keyboard */ - -static Status -EphyrKeyboardInit (KdKeyboardInfo *ki) -{ - ki->driverPrivate = (EphyrKbdPrivate *) - xcalloc(sizeof(EphyrKbdPrivate), 1); - hostx_load_keymap(); - if (!ephyrKeySyms.map) { - ErrorF("Couldn't load keymap from host\n"); - return BadAlloc; - } - ki->minScanCode = ephyrKeySyms.minKeyCode; - ki->maxScanCode = ephyrKeySyms.maxKeyCode; - xfree(ki->name); - ki->name = strdup("Xephyr virtual keyboard"); - ephyrKbd = ki; - return Success; -} - -static Status -EphyrKeyboardEnable (KdKeyboardInfo *ki) -{ - ((EphyrKbdPrivate *)ki->driverPrivate)->enabled = TRUE; - - return Success; -} - -static void -EphyrKeyboardDisable (KdKeyboardInfo *ki) -{ - ((EphyrKbdPrivate *)ki->driverPrivate)->enabled = FALSE; -} - -static void -EphyrKeyboardFini (KdKeyboardInfo *ki) -{ - ephyrKbd = NULL; - return; -} - -static void -EphyrKeyboardLeds (KdKeyboardInfo *ki, int leds) -{ -} - -static void -EphyrKeyboardBell (KdKeyboardInfo *ki, int volume, int frequency, int duration) -{ -} - - -KdKeyboardDriver EphyrKeyboardDriver = { - "ephyr", - EphyrKeyboardInit, - EphyrKeyboardEnable, - EphyrKeyboardLeds, - EphyrKeyboardBell, - EphyrKeyboardDisable, - EphyrKeyboardFini, - NULL, -}; +/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum + * + * Copyright © 2004 Nokia + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Nokia not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Nokia makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "ephyr.h" + +#include "inputstr.h" +#include "scrnintstr.h" +#include "ephyrlog.h" + +#ifdef XF86DRI +#include "ephyrdri.h" +#include "ephyrdriext.h" +#include "ephyrglxext.h" +#endif /* XF86DRI */ + +extern int KdTsPhyScreen; +#ifdef GLXEXT +extern Bool noGlxVisualInit; +#endif + +KdKeyboardInfo *ephyrKbd; +KdPointerInfo *ephyrMouse; +EphyrKeySyms ephyrKeySyms; +Bool ephyrNoDRI=FALSE ; +Bool ephyrNoXV=FALSE ; + +static int mouseState = 0; + +typedef struct _EphyrInputPrivate { + Bool enabled; +} EphyrKbdPrivate, EphyrPointerPrivate; + +Bool EphyrWantGrayScale = 0; + + +Bool +ephyrInitialize (KdCardInfo *card, EphyrPriv *priv) +{ + OsSignal(SIGUSR1, hostx_handle_signal); + + priv->base = 0; + priv->bytes_per_line = 0; + return TRUE; +} + +Bool +ephyrCardInit (KdCardInfo *card) +{ + EphyrPriv *priv; + + priv = (EphyrPriv *) malloc(sizeof (EphyrPriv)); + if (!priv) + return FALSE; + + if (!ephyrInitialize (card, priv)) + { + free(priv); + return FALSE; + } + card->driver = priv; + + return TRUE; +} + +Bool +ephyrScreenInitialize (KdScreenInfo *screen, EphyrScrPriv *scrpriv) +{ + int width = 640, height = 480; + CARD32 redMask, greenMask, blueMask; + + if (hostx_want_screen_size(screen, &width, &height) + || !screen->width || !screen->height) + { + screen->width = width; + screen->height = height; + } + + if (EphyrWantGrayScale) + screen->fb.depth = 8; + + if (screen->fb.depth && screen->fb.depth != hostx_get_depth()) + { + if (screen->fb.depth < hostx_get_depth() + && (screen->fb.depth == 24 || screen->fb.depth == 16 + || screen->fb.depth == 8)) + { + hostx_set_server_depth(screen, screen->fb.depth); + } + else + ErrorF("\nXephyr: requested screen depth not supported, setting to match hosts.\n"); + } + + screen->fb.depth = hostx_get_server_depth(screen); + screen->rate = 72; + + if (screen->fb.depth <= 8) + { + if (EphyrWantGrayScale) + screen->fb.visuals = ((1 << StaticGray) | (1 << GrayScale)); + else + screen->fb.visuals = ((1 << StaticGray) | + (1 << GrayScale) | + (1 << StaticColor) | + (1 << PseudoColor) | + (1 << TrueColor) | + (1 << DirectColor)); + + screen->fb.redMask = 0x00; + screen->fb.greenMask = 0x00; + screen->fb.blueMask = 0x00; + screen->fb.depth = 8; + screen->fb.bitsPerPixel = 8; + } + else + { + screen->fb.visuals = (1 << TrueColor); + + if (screen->fb.depth <= 15) + { + screen->fb.depth = 15; + screen->fb.bitsPerPixel = 16; + } + else if (screen->fb.depth <= 16) + { + screen->fb.depth = 16; + screen->fb.bitsPerPixel = 16; + } + else if (screen->fb.depth <= 24) + { + screen->fb.depth = 24; + screen->fb.bitsPerPixel = 32; + } + else if (screen->fb.depth <= 30) + { + screen->fb.depth = 30; + screen->fb.bitsPerPixel = 32; + } + else + { + ErrorF("\nXephyr: Unsupported screen depth %d\n", + screen->fb.depth); + return FALSE; + } + + hostx_get_visual_masks (screen, &redMask, &greenMask, &blueMask); + + screen->fb.redMask = (Pixel) redMask; + screen->fb.greenMask = (Pixel) greenMask; + screen->fb.blueMask = (Pixel) blueMask; + + } + + scrpriv->randr = screen->randr; + + return ephyrMapFramebuffer (screen); +} + +Bool +ephyrScreenInit (KdScreenInfo *screen) +{ + EphyrScrPriv *scrpriv; + + scrpriv = calloc(1, sizeof (EphyrScrPriv)); + + if (!scrpriv) + return FALSE; + + screen->driver = scrpriv; + + if (!ephyrScreenInitialize (screen, scrpriv)) + { + screen->driver = 0; + free(scrpriv); + return FALSE; + } + + return TRUE; +} + +void* +ephyrWindowLinear (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size, + void *closure) +{ + KdScreenPriv(pScreen); + EphyrPriv *priv = pScreenPriv->card->driver; + + if (!pScreenPriv->enabled) + return 0; + + *size = priv->bytes_per_line; + return priv->base + row * priv->bytes_per_line + offset; +} + +/** + * Figure out display buffer size. If fakexa is enabled, allocate a larger + * buffer so that fakexa has space to put offscreen pixmaps. + */ +int +ephyrBufferHeight(KdScreenInfo *screen) +{ + int buffer_height; + if (ephyrFuncs.initAccel == NULL) + buffer_height = screen->height; + else + buffer_height = 3 * screen->height; + return buffer_height; +} + + +Bool +ephyrMapFramebuffer (KdScreenInfo *screen) +{ + EphyrScrPriv *scrpriv = screen->driver; + EphyrPriv *priv = screen->card->driver; + KdPointerMatrix m; + int buffer_height; + + EPHYR_LOG("screen->width: %d, screen->height: %d index=%d", + screen->width, screen->height, screen->mynum); + + KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); + KdSetPointerMatrix (&m); + + priv->bytes_per_line = ((screen->width * screen->fb.bitsPerPixel + 31) >> 5) << 2; + + buffer_height = ephyrBufferHeight(screen); + + priv->base = hostx_screen_init (screen, screen->width, screen->height, buffer_height); + + if ((scrpriv->randr & RR_Rotate_0) && !(scrpriv->randr & RR_Reflect_All)) + { + scrpriv->shadow = FALSE; + + screen->fb.byteStride = priv->bytes_per_line; + screen->fb.pixelStride = screen->width; + screen->fb.frameBuffer = (CARD8 *) (priv->base); + } + else + { + /* Rotated/Reflected so we need to use shadow fb */ + scrpriv->shadow = TRUE; + + EPHYR_LOG("allocing shadow"); + + KdShadowFbAlloc (screen, + scrpriv->randr & (RR_Rotate_90|RR_Rotate_270)); + } + + return TRUE; +} + +void +ephyrSetScreenSizes (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + + if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) + { + pScreen->width = screen->width; + pScreen->height = screen->height; + pScreen->mmWidth = screen->width_mm; + pScreen->mmHeight = screen->height_mm; + } + else + { + pScreen->width = screen->height; + pScreen->height = screen->width; + pScreen->mmWidth = screen->height_mm; + pScreen->mmHeight = screen->width_mm; + } +} + +Bool +ephyrUnmapFramebuffer (KdScreenInfo *screen) +{ + EphyrScrPriv *scrpriv = screen->driver; + + if (scrpriv->shadow) + KdShadowFbFree (screen); + + /* Note, priv->base will get freed when XImage recreated */ + + return TRUE; +} + +void +ephyrShadowUpdate (ScreenPtr pScreen, shadowBufPtr pBuf) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + + EPHYR_LOG("slow paint"); + + /* FIXME: Slow Rotated/Reflected updates could be much + * much faster efficiently updating via tranforming + * pBuf->pDamage regions + */ + shadowUpdateRotatePacked(pScreen, pBuf); + hostx_paint_rect(screen, 0,0,0,0, screen->width, screen->height); +} + +static void +ephyrInternalDamageRedisplay (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + RegionPtr pRegion; + + if (!scrpriv || !scrpriv->pDamage) + return; + + pRegion = DamageRegion (scrpriv->pDamage); + + if (REGION_NOTEMPTY (pScreen, pRegion)) + { + int nbox; + BoxPtr pbox; + + nbox = REGION_NUM_RECTS (pRegion); + pbox = REGION_RECTS (pRegion); + + while (nbox--) + { + hostx_paint_rect(screen, + pbox->x1, pbox->y1, + pbox->x1, pbox->y1, + pbox->x2 - pbox->x1, + pbox->y2 - pbox->y1); + pbox++; + } + DamageEmpty (scrpriv->pDamage); + } +} + +static void +ephyrInternalDamageBlockHandler (pointer data, + OSTimePtr pTimeout, + pointer pRead) +{ + ScreenPtr pScreen = (ScreenPtr) data; + + ephyrInternalDamageRedisplay (pScreen); +} + +static void +ephyrInternalDamageWakeupHandler (pointer data, int i, pointer LastSelectMask) +{ + /* FIXME: Not needed ? */ +} + +Bool +ephyrSetInternalDamage (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + PixmapPtr pPixmap = NULL; + + scrpriv->pDamage = DamageCreate ((DamageReportFunc) 0, + (DamageDestroyFunc) 0, + DamageReportNone, + TRUE, + pScreen, + pScreen); + + if (!RegisterBlockAndWakeupHandlers (ephyrInternalDamageBlockHandler, + ephyrInternalDamageWakeupHandler, + (pointer) pScreen)) + return FALSE; + + pPixmap = (*pScreen->GetScreenPixmap) (pScreen); + + DamageRegister (&pPixmap->drawable, scrpriv->pDamage); + + return TRUE; +} + +void +ephyrUnsetInternalDamage (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + PixmapPtr pPixmap = NULL; + + pPixmap = (*pScreen->GetScreenPixmap) (pScreen); + DamageUnregister (&pPixmap->drawable, scrpriv->pDamage); + DamageDestroy (scrpriv->pDamage); + + RemoveBlockAndWakeupHandlers (ephyrInternalDamageBlockHandler, + ephyrInternalDamageWakeupHandler, + (pointer) pScreen); +} + +#ifdef RANDR +Bool +ephyrRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + RRScreenSizePtr pSize; + Rotation randr; + int n = 0; + + struct { int width, height; } sizes[] = + { + { 1600, 1200 }, + { 1400, 1050 }, + { 1280, 960 }, + { 1280, 1024 }, + { 1152, 864 }, + { 1024, 768 }, + { 832, 624 }, + { 800, 600 }, + { 720, 400 }, + { 480, 640 }, + { 640, 480 }, + { 640, 400 }, + { 320, 240 }, + { 240, 320 }, + { 160, 160 }, + { 0, 0 } + }; + + EPHYR_LOG("mark"); + + *rotations = RR_Rotate_All|RR_Reflect_All; + + if (!hostx_want_preexisting_window (screen) + && !hostx_want_fullscreen ()) /* only if no -parent switch */ + { + while (sizes[n].width != 0 && sizes[n].height != 0) + { + RRRegisterSize (pScreen, + sizes[n].width, + sizes[n].height, + (sizes[n].width * screen->width_mm)/screen->width, + (sizes[n].height *screen->height_mm)/screen->height + ); + n++; + } + } + + pSize = RRRegisterSize (pScreen, + screen->width, + screen->height, + screen->width_mm, + screen->height_mm); + + randr = KdSubRotation (scrpriv->randr, screen->randr); + + RRSetCurrentConfig (pScreen, randr, 0, pSize); + + return TRUE; +} + +Bool +ephyrRandRSetConfig (ScreenPtr pScreen, + Rotation randr, + int rate, + RRScreenSizePtr pSize) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + Bool wasEnabled = pScreenPriv->enabled; + EphyrScrPriv oldscr; + int oldwidth, oldheight, oldmmwidth, oldmmheight; + Bool oldshadow; + int newwidth, newheight; + + if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) + { + newwidth = pSize->width; + newheight = pSize->height; + } + else + { + newwidth = pSize->height; + newheight = pSize->width; + } + + if (wasEnabled) + KdDisableScreen (pScreen); + + oldscr = *scrpriv; + + oldwidth = screen->width; + oldheight = screen->height; + oldmmwidth = pScreen->mmWidth; + oldmmheight = pScreen->mmHeight; + oldshadow = scrpriv->shadow; + + /* + * Set new configuration + */ + + scrpriv->randr = KdAddRotation (screen->randr, randr); + + ephyrUnmapFramebuffer (screen); + + screen->width = newwidth; + screen->height = newheight; + + if (!ephyrMapFramebuffer (screen)) + goto bail4; + + /* FIXME below should go in own call */ + + if (oldshadow) + KdShadowUnset (screen->pScreen); + else + ephyrUnsetInternalDamage(screen->pScreen); + + if (scrpriv->shadow) + { + if (!KdShadowSet (screen->pScreen, + scrpriv->randr, + ephyrShadowUpdate, + ephyrWindowLinear)) + goto bail4; + } + else + { + /* Without shadow fb ( non rotated ) we need + * to use damage to efficiently update display + * via signal regions what to copy from 'fb'. + */ + if (!ephyrSetInternalDamage(screen->pScreen)) + goto bail4; + } + + ephyrSetScreenSizes (screen->pScreen); + + /* + * Set frame buffer mapping + */ + (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), + pScreen->width, + pScreen->height, + screen->fb.depth, + screen->fb.bitsPerPixel, + screen->fb.byteStride, + screen->fb.frameBuffer); + + /* set the subpixel order */ + + KdSetSubpixelOrder (pScreen, scrpriv->randr); + + if (wasEnabled) + KdEnableScreen (pScreen); + + return TRUE; + + bail4: + EPHYR_LOG("bailed"); + + ephyrUnmapFramebuffer (screen); + *scrpriv = oldscr; + (void) ephyrMapFramebuffer (screen); + + pScreen->width = oldwidth; + pScreen->height = oldheight; + pScreen->mmWidth = oldmmwidth; + pScreen->mmHeight = oldmmheight; + + if (wasEnabled) + KdEnableScreen (pScreen); + return FALSE; +} + +Bool +ephyrRandRInit (ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + + if (!RRScreenInit (pScreen)) + return FALSE; + + pScrPriv = rrGetScrPriv(pScreen); + pScrPriv->rrGetInfo = ephyrRandRGetInfo; + pScrPriv->rrSetConfig = ephyrRandRSetConfig; + return TRUE; +} +#endif + +Bool +ephyrCreateColormap (ColormapPtr pmap) +{ + return fbInitializeColormap (pmap); +} + +Bool +ephyrInitScreen (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + + EPHYR_LOG ("pScreen->myNum:%d\n", pScreen->myNum) ; + hostx_set_screen_number (screen, pScreen->myNum); + hostx_set_win_title (screen, "(ctrl+shift grabs mouse and keyboard)") ; + pScreen->CreateColormap = ephyrCreateColormap; + +#ifdef XV + if (!ephyrNoXV) { + if (!ephyrInitVideo (pScreen)) { + EPHYR_LOG_ERROR ("failed to initialize xvideo\n") ; + } else { + EPHYR_LOG ("initialized xvideo okay\n") ; + } + } +#endif /*XV*/ + +#ifdef XF86DRI + if (!ephyrNoDRI && !hostx_has_dri ()) { + EPHYR_LOG ("host x does not support DRI. Disabling DRI forwarding\n") ; + ephyrNoDRI = TRUE ; +#ifdef GLXEXT + noGlxVisualInit = FALSE ; +#endif + } + if (!ephyrNoDRI) { + ephyrDRIExtensionInit (pScreen) ; + ephyrHijackGLXExtension () ; + } +#endif + +#ifdef GLXEXT + if (ephyrNoDRI) { + noGlxVisualInit = FALSE ; + } +#endif + + return TRUE; +} + +Bool +ephyrFinishInitScreen (ScreenPtr pScreen) +{ + /* FIXME: Calling this even if not using shadow. + * Seems harmless enough. But may be safer elsewhere. + */ + if (!shadowSetup (pScreen)) + return FALSE; + +#ifdef RANDR + if (!ephyrRandRInit (pScreen)) + return FALSE; +#endif + + return TRUE; +} + +Bool +ephyrCreateResources (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + + EPHYR_LOG("mark pScreen=%p mynum=%d shadow=%d", + pScreen, pScreen->myNum, scrpriv->shadow); + + if (scrpriv->shadow) + return KdShadowSet (pScreen, + scrpriv->randr, + ephyrShadowUpdate, + ephyrWindowLinear); + else + return ephyrSetInternalDamage(pScreen); +} + +void +ephyrPreserve (KdCardInfo *card) +{ +} + +Bool +ephyrEnable (ScreenPtr pScreen) +{ + return TRUE; +} + +Bool +ephyrDPMS (ScreenPtr pScreen, int mode) +{ + return TRUE; +} + +void +ephyrDisable (ScreenPtr pScreen) +{ +} + +void +ephyrRestore (KdCardInfo *card) +{ +} + +void +ephyrScreenFini (KdScreenInfo *screen) +{ + EphyrScrPriv *scrpriv = screen->driver; + if (scrpriv->shadow) { + KdShadowFbFree (screen); + } + free(screen->driver); + screen->driver = NULL; +} + +/* + * Port of Mark McLoughlin's Xnest fix for focus in + modifier bug. + * See https://bugs.freedesktop.org/show_bug.cgi?id=3030 + */ +void +ephyrUpdateModifierState(unsigned int state) +{ +#if 0 + DeviceIntPtr pkeydev; + KeyClassPtr keyc; + int i; + CARD8 mask; + + pkeydev = inputInfo.keyboard; + + if (!pkeydev) + return; + +/* This is pretty broken. + * + * What should happen is that focus out should do as a VT switch does in + * traditional servers: fake releases for all keys (and buttons too, come + * to think of it) currently down. Then, on focus in, get the state from + * the host, and fake keypresses for everything currently down. + * + * So I'm leaving this broken for a little while. Sorry, folks. + * + * -daniels + */ + + keyc = pkeydev->key; + + state = state & 0xff; + + if (keyc->state == state) + return; + + for (i = 0, mask = 1; i < 8; i++, mask <<= 1) + { + int key; + + /* Modifier is down, but shouldn't be */ + if ((keyc->state & mask) && !(state & mask)) + { + int count = keyc->modifierKeyCount[i]; + + for (key = 0; key < MAP_LENGTH; key++) + if (keyc->xkbInfo->desc->map->modmap[key] & mask) + { + int bit; + BYTE *kptr; + + kptr = &keyc->down[key >> 3]; + bit = 1 << (key & 7); + + if (*kptr & bit && ephyrKbd && + ((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) + KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE); /* release */ + + if (--count == 0) + break; + } + } + + /* Modifier shoud be down, but isn't */ + if (!(keyc->state & mask) && (state & mask)) + for (key = 0; key < MAP_LENGTH; key++) + if (keyc->xkbInfo->desc->map->modmap[key] & mask) + { + if (keyc->xkbInfo->desc->map->modmap[key] & mask && ephyrKbd && + ((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) + KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE); /* press */ + break; + } + } +#endif +} + +static void +ephyrBlockSigio (void) +{ + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGIO); + sigprocmask (SIG_BLOCK, &set, 0); +} + +static void +ephyrUnblockSigio (void) +{ + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGIO); + sigprocmask (SIG_UNBLOCK, &set, 0); +} + +static Bool +ephyrCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) +{ + return FALSE; +} + +static void +ephyrCrossScreen (ScreenPtr pScreen, Bool entering) +{ +} + +int ephyrCurScreen; /*current event screen*/ + +static void +ephyrWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + ephyrBlockSigio (); + ephyrCurScreen = pScreen->myNum; + miPointerWarpCursor (inputInfo.pointer, pScreen, x, y); + ephyrUnblockSigio (); +} + +miPointerScreenFuncRec ephyrPointerScreenFuncs = +{ + ephyrCursorOffScreen, + ephyrCrossScreen, + ephyrWarpCursor, + NULL, + NULL +}; + +#ifdef XF86DRI +/** + * find if the remote window denoted by a_remote + * is paired with an internal Window within the Xephyr server. + * If the remove window is paired with an internal window, send an + * expose event to the client insterested in the internal window expose event. + * + * Pairing happens when a drawable inside Xephyr is associated with + * a GL surface in a DRI environment. + * Look at the function ProcXF86DRICreateDrawable in ephyrdriext.c to + * know a paired window is created. + * + * This is useful to make GL drawables (only windows for now) handle + * expose events and send those events to clients. + */ +static void +ephyrExposePairedWindow (int a_remote) +{ + EphyrWindowPair *pair = NULL; + RegionRec reg; + ScreenPtr screen; + + if (!findWindowPairFromRemote (a_remote, &pair)) { + EPHYR_LOG ("did not find a pair for this window\n"); + return; + } + screen = pair->local->drawable.pScreen; + REGION_NULL (screen, ®); + REGION_COPY (screen, ®, &pair->local->clipList); + screen->WindowExposures (pair->local, ®, NullRegion); + REGION_UNINIT (screen, ®); +} +#endif /* XF86DRI */ + +void +ephyrPoll(void) +{ + EphyrHostXEvent ev; + + while (hostx_get_event(&ev)) + { + switch (ev.type) + { + case EPHYR_EV_MOUSE_MOTION: + if (!ephyrMouse || + !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) { + EPHYR_LOG ("skipping mouse motion:%d\n", ephyrCurScreen) ; + continue; + } + { + if (ev.data.mouse_motion.screen >=0 + && (ephyrCurScreen != ev.data.mouse_motion.screen)) + { + EPHYR_LOG ("warping mouse cursor. " + "cur_screen%d, motion_screen:%d\n", + ephyrCurScreen, ev.data.mouse_motion.screen) ; + if (ev.data.mouse_motion.screen >= 0) + { + ephyrWarpCursor + (inputInfo.pointer, screenInfo.screens[ev.data.mouse_motion.screen], + ev.data.mouse_motion.x, + ev.data.mouse_motion.y ); + } + } + else + { + int x=0, y=0; +#ifdef XF86DRI + EphyrWindowPair *pair = NULL; +#endif + EPHYR_LOG ("enqueuing mouse motion:%d\n", ephyrCurScreen) ; + x = ev.data.mouse_motion.x; + y = ev.data.mouse_motion.y; + EPHYR_LOG ("initial (x,y):(%d,%d)\n", x, y) ; +#ifdef XF86DRI + EPHYR_LOG ("is this window peered by a gl drawable ?\n") ; + if (findWindowPairFromRemote (ev.data.mouse_motion.window, + &pair)) + { + EPHYR_LOG ("yes, it is peered\n") ; + x += pair->local->drawable.x; + y += pair->local->drawable.y; + } + else + { + EPHYR_LOG ("no, it is not peered\n") ; + } + EPHYR_LOG ("final (x,y):(%d,%d)\n", x, y) ; +#endif + KdEnqueuePointerEvent(ephyrMouse, mouseState, x, y, 0); + } + } + break; + + case EPHYR_EV_MOUSE_PRESS: + if (!ephyrMouse || + !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) { + EPHYR_LOG ("skipping mouse press:%d\n", ephyrCurScreen) ; + continue; + } + EPHYR_LOG ("enqueuing mouse press:%d\n", ephyrCurScreen) ; + ephyrUpdateModifierState(ev.key_state); + mouseState |= ev.data.mouse_down.button_num; + KdEnqueuePointerEvent(ephyrMouse, mouseState|KD_MOUSE_DELTA, 0, 0, 0); + break; + + case EPHYR_EV_MOUSE_RELEASE: + if (!ephyrMouse || + !((EphyrPointerPrivate *)ephyrMouse->driverPrivate)->enabled) + continue; + ephyrUpdateModifierState(ev.key_state); + mouseState &= ~ev.data.mouse_up.button_num; + EPHYR_LOG ("enqueuing mouse release:%d\n", ephyrCurScreen) ; + KdEnqueuePointerEvent(ephyrMouse, mouseState|KD_MOUSE_DELTA, 0, 0, 0); + break; + + case EPHYR_EV_KEY_PRESS: + if (!ephyrKbd || + !((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) + continue; + ephyrUpdateModifierState(ev.key_state); + KdEnqueueKeyboardEvent (ephyrKbd, ev.data.key_down.scancode, FALSE); + break; + + case EPHYR_EV_KEY_RELEASE: + if (!ephyrKbd || + !((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled) + continue; + KdEnqueueKeyboardEvent (ephyrKbd, ev.data.key_up.scancode, TRUE); + break; + +#ifdef XF86DRI + case EPHYR_EV_EXPOSE: + /* + * We only receive expose events when the expose event have + * be generated for a drawable that is a host X window managed + * by Xephyr. Host X windows managed by Xephyr exists for instance + * when Xephyr is asked to create a GL drawable in a DRI environment. + */ + ephyrExposePairedWindow (ev.data.expose.window); + break; +#endif /* XF86DRI */ + + default: + break; + } + } +} + +void +ephyrCardFini (KdCardInfo *card) +{ + EphyrPriv *priv = card->driver; + free(priv); +} + +void +ephyrGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + /* XXX Not sure if this is right */ + + EPHYR_LOG("mark"); + + while (n--) + { + pdefs->red = 0; + pdefs->green = 0; + pdefs->blue = 0; + pdefs++; + } + +} + +void +ephyrPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + int min, max, p; + + /* XXX Not sure if this is right */ + + min = 256; + max = 0; + + while (n--) + { + p = pdefs->pixel; + if (p < min) + min = p; + if (p > max) + max = p; + + hostx_set_cmap_entry(p, + pdefs->red >> 8, + pdefs->green >> 8, + pdefs->blue >> 8); + pdefs++; + } +} + +/* Mouse calls */ + +static Status +MouseInit (KdPointerInfo *pi) +{ + pi->driverPrivate = (EphyrPointerPrivate *) + calloc(sizeof(EphyrPointerPrivate), 1); + ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = FALSE; + pi->nAxes = 3; + pi->nButtons = 32; + free(pi->name); + pi->name = strdup("Xephyr virtual mouse"); + ephyrMouse = pi; + return Success; +} + +static Status +MouseEnable (KdPointerInfo *pi) +{ + ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = TRUE; + return Success; +} + +static void +MouseDisable (KdPointerInfo *pi) +{ + ((EphyrPointerPrivate *)pi->driverPrivate)->enabled = FALSE; + return; +} + +static void +MouseFini (KdPointerInfo *pi) +{ + ephyrMouse = NULL; + return; +} + +KdPointerDriver EphyrMouseDriver = { + "ephyr", + MouseInit, + MouseEnable, + MouseDisable, + MouseFini, + NULL, +}; + +/* Keyboard */ + +static Status +EphyrKeyboardInit (KdKeyboardInfo *ki) +{ + ki->driverPrivate = (EphyrKbdPrivate *) + calloc(sizeof(EphyrKbdPrivate), 1); + hostx_load_keymap(); + if (!ephyrKeySyms.map) { + ErrorF("Couldn't load keymap from host\n"); + return BadAlloc; + } + ki->minScanCode = ephyrKeySyms.minKeyCode; + ki->maxScanCode = ephyrKeySyms.maxKeyCode; + free(ki->name); + ki->name = strdup("Xephyr virtual keyboard"); + ephyrKbd = ki; + return Success; +} + +static Status +EphyrKeyboardEnable (KdKeyboardInfo *ki) +{ + ((EphyrKbdPrivate *)ki->driverPrivate)->enabled = TRUE; + + return Success; +} + +static void +EphyrKeyboardDisable (KdKeyboardInfo *ki) +{ + ((EphyrKbdPrivate *)ki->driverPrivate)->enabled = FALSE; +} + +static void +EphyrKeyboardFini (KdKeyboardInfo *ki) +{ + ephyrKbd = NULL; + return; +} + +static void +EphyrKeyboardLeds (KdKeyboardInfo *ki, int leds) +{ +} + +static void +EphyrKeyboardBell (KdKeyboardInfo *ki, int volume, int frequency, int duration) +{ +} + + +KdKeyboardDriver EphyrKeyboardDriver = { + "ephyr", + EphyrKeyboardInit, + EphyrKeyboardEnable, + EphyrKeyboardLeds, + EphyrKeyboardBell, + EphyrKeyboardDisable, + EphyrKeyboardFini, + NULL, +}; diff --git a/xorg-server/hw/kdrive/ephyr/ephyr_draw.c b/xorg-server/hw/kdrive/ephyr/ephyr_draw.c index f9fac8007..f3e2be6eb 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyr_draw.c +++ b/xorg-server/hw/kdrive/ephyr/ephyr_draw.c @@ -1,524 +1,523 @@ -/* - * Copyright © 2006 Intel Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Authors: - * Eric Anholt - * - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "ephyr.h" -#include "exa_priv.h" -#include "fbpict.h" - -#define EPHYR_TRACE_DRAW 0 - -#if EPHYR_TRACE_DRAW -#define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__); -#else -#define TRACE_DRAW() do { } while (0) -#endif - -/* Use some oddball alignments, to expose issues in alignment handling in EXA. */ -#define EPHYR_OFFSET_ALIGN 24 -#define EPHYR_PITCH_ALIGN 24 - -#define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024) -#define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024) - -/** - * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to - * fb functions. - */ -static void -ephyrPreparePipelinedAccess(PixmapPtr pPix, int index) -{ - KdScreenPriv(pPix->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - assert(fakexa->saved_ptrs[index] == NULL); - fakexa->saved_ptrs[index] = pPix->devPrivate.ptr; - - if (pPix->devPrivate.ptr != NULL) - return; - - pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix); -} - -/** - * Restores the original devPrivate.ptr of the pixmap from before we messed with - * it. - */ -static void -ephyrFinishPipelinedAccess(PixmapPtr pPix, int index) -{ - KdScreenPriv(pPix->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - pPix->devPrivate.ptr = fakexa->saved_ptrs[index]; - fakexa->saved_ptrs[index] = NULL; -} - -/** - * Sets up a scratch GC for fbFill, and saves other parameters for the - * ephyrSolid implementation. - */ -static Bool -ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg) -{ - ScreenPtr pScreen = pPix->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - CARD32 tmpval[3]; - - ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST); - - fakexa->pDst = pPix; - fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen); - - tmpval[0] = alu; - tmpval[1] = pm; - tmpval[2] = fg; - ChangeGC(fakexa->pGC, GCFunction | GCPlaneMask | GCForeground, - tmpval); - - ValidateGC(&pPix->drawable, fakexa->pGC); - - TRACE_DRAW(); - - return TRUE; -} - -/** - * Does an fbFill of the rectangle to be drawn. - */ -static void -ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2) -{ - ScreenPtr pScreen = pPix->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1); -} - -/** - * Cleans up the scratch GC created in ephyrPrepareSolid. - */ -static void -ephyrDoneSolid(PixmapPtr pPix) -{ - ScreenPtr pScreen = pPix->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - FreeScratchGC(fakexa->pGC); - - ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST); -} - -/** - * Sets up a scratch GC for fbCopyArea, and saves other parameters for the - * ephyrCopy implementation. - */ -static Bool -ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu, - Pixel pm) -{ - ScreenPtr pScreen = pDst->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - CARD32 tmpval[2]; - - ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); - ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); - - fakexa->pSrc = pSrc; - fakexa->pDst = pDst; - fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen); - - tmpval[0] = alu; - tmpval[1] = pm; - ChangeGC (fakexa->pGC, GCFunction | GCPlaneMask, tmpval); - - ValidateGC(&pDst->drawable, fakexa->pGC); - - TRACE_DRAW(); - - return TRUE; -} - -/** - * Does an fbCopyArea to take care of the requested copy. - */ -static void -ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h) -{ - ScreenPtr pScreen = pDst->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC, - srcX, srcY, w, h, dstX, dstY); -} - -/** - * Cleans up the scratch GC created in ephyrPrepareCopy. - */ -static void -ephyrDoneCopy(PixmapPtr pDst) -{ - ScreenPtr pScreen = pDst->drawable.pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - FreeScratchGC (fakexa->pGC); - - ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); - ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); -} - -/** - * Reports that we can always accelerate the given operation. This may not be - * desirable from an EXA testing standpoint -- testing the fallback paths would - * be useful, too. - */ -static Bool -ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, - PicturePtr pDstPicture) -{ - /* Exercise the component alpha helper, so fail on this case like a normal - * driver - */ - if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver) - return FALSE; - - return TRUE; -} - -/** - * Saves off the parameters for ephyrComposite. - */ -static Bool -ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, - PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, - PixmapPtr pDst) -{ - KdScreenPriv(pDst->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); - ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); - if (pMask != NULL) - ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK); - - fakexa->op = op; - fakexa->pSrcPicture = pSrcPicture; - fakexa->pMaskPicture = pMaskPicture; - fakexa->pDstPicture = pDstPicture; - fakexa->pSrc = pSrc; - fakexa->pMask = pMask; - fakexa->pDst = pDst; - - TRACE_DRAW(); - - return TRUE; -} - -/** - * Does an fbComposite to complete the requested drawing operation. - */ -static void -ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, - int dstX, int dstY, int w, int h) -{ - KdScreenPriv(pDst->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture, - fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY, - w, h); -} - -static void -ephyrDoneComposite(PixmapPtr pDst) -{ - KdScreenPriv(pDst->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - if (fakexa->pMask != NULL) - ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK); - ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); - ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); -} - -/** - * Does fake acceleration of DownloadFromScren using memcpy. - */ -static Bool -ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst, - int dst_pitch) -{ - KdScreenPriv(pSrc->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - unsigned char *src; - int src_pitch, cpp; - - if (pSrc->drawable.bitsPerPixel < 8) - return FALSE; - - ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); - - cpp = pSrc->drawable.bitsPerPixel / 8; - src_pitch = exaGetPixmapPitch(pSrc); - src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc); - src += y * src_pitch + x * cpp; - - for (; h > 0; h--) { - memcpy(dst, src, w * cpp); - dst += dst_pitch; - src += src_pitch; - } - - exaMarkSync(pSrc->drawable.pScreen); - - ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC); - - return TRUE; -} - -/** - * Does fake acceleration of UploadToScreen using memcpy. - */ -static Bool -ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src, - int src_pitch) -{ - KdScreenPriv(pDst->drawable.pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - unsigned char *dst; - int dst_pitch, cpp; - - if (pDst->drawable.bitsPerPixel < 8) - return FALSE; - - ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); - - cpp = pDst->drawable.bitsPerPixel / 8; - dst_pitch = exaGetPixmapPitch(pDst); - dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst); - dst += y * dst_pitch + x * cpp; - - for (; h > 0; h--) { - memcpy(dst, src, w * cpp); - dst += dst_pitch; - src += src_pitch; - } - - exaMarkSync(pDst->drawable.pScreen); - - ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST); - - return TRUE; -} - -static Bool -ephyrPrepareAccess(PixmapPtr pPix, int index) -{ - /* Make sure we don't somehow end up with a pointer that is in framebuffer - * and hasn't been readied for us. - */ - assert(pPix->devPrivate.ptr != NULL); - - return TRUE; -} - -/** - * In fakexa, we currently only track whether we have synced to the latest - * "accelerated" drawing that has happened or not. It's not used for anything - * yet. - */ -static int -ephyrMarkSync(ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - fakexa->is_synced = FALSE; - - return 0; -} - -/** - * Assumes that we're waiting on the latest marker. When EXA gets smarter and - * starts using markers in a fine-grained way (for example, waiting on drawing - * to required pixmaps to complete, rather than waiting for all drawing to - * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker - * implementation fine-grained as well. - */ -static void -ephyrWaitMarker(ScreenPtr pScreen, int marker) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrFakexaPriv *fakexa = scrpriv->fakexa; - - fakexa->is_synced = TRUE; -} - -/** - * This function initializes EXA to use the fake acceleration implementation - * which just falls through to software. The purpose is to have a reliable, - * correct driver with which to test changes to the EXA core. - */ -Bool -ephyrDrawInit(ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - EphyrScrPriv *scrpriv = screen->driver; - EphyrPriv *priv = screen->card->driver; - EphyrFakexaPriv *fakexa; - Bool success; - - fakexa = xcalloc(1, sizeof(*fakexa)); - if (fakexa == NULL) - return FALSE; - - fakexa->exa = exaDriverAlloc(); - if (fakexa->exa == NULL) { - xfree(fakexa); - return FALSE; - } - - fakexa->exa->memoryBase = (CARD8 *) (priv->base); - fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen); - fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height; - - /* Since we statically link against EXA, we shouldn't have to be smart about - * versioning. - */ - fakexa->exa->exa_major = 2; - fakexa->exa->exa_minor = 0; - - fakexa->exa->PrepareSolid = ephyrPrepareSolid; - fakexa->exa->Solid = ephyrSolid; - fakexa->exa->DoneSolid = ephyrDoneSolid; - - fakexa->exa->PrepareCopy = ephyrPrepareCopy; - fakexa->exa->Copy = ephyrCopy; - fakexa->exa->DoneCopy = ephyrDoneCopy; - - fakexa->exa->CheckComposite = ephyrCheckComposite; - fakexa->exa->PrepareComposite = ephyrPrepareComposite; - fakexa->exa->Composite = ephyrComposite; - fakexa->exa->DoneComposite = ephyrDoneComposite; - - fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen; - fakexa->exa->UploadToScreen = ephyrUploadToScreen; - - fakexa->exa->MarkSync = ephyrMarkSync; - fakexa->exa->WaitMarker = ephyrWaitMarker; - - fakexa->exa->PrepareAccess = ephyrPrepareAccess; - - fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN; - fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN; - - fakexa->exa->maxX = 1023; - fakexa->exa->maxY = 1023; - - fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS; - - success = exaDriverInit(pScreen, fakexa->exa); - if (success) { - ErrorF("Initialized fake EXA acceleration\n"); - scrpriv->fakexa = fakexa; - } else { - ErrorF("Failed to initialize EXA\n"); - xfree(fakexa->exa); - xfree(fakexa); - } - - return success; -} - -void -ephyrDrawEnable(ScreenPtr pScreen) -{ -} - -void -ephyrDrawDisable(ScreenPtr pScreen) -{ -} - -void -ephyrDrawFini(ScreenPtr pScreen) -{ -} - -/** - * exaDDXDriverInit is required by the top-level EXA module, and is used by - * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since - * we won't be enabling/disabling the FB. - */ -void -exaDDXDriverInit(ScreenPtr pScreen) -{ - ExaScreenPriv(pScreen); - - pExaScr->migration = ExaMigrationSmart; - pExaScr->checkDirtyCorrectness = TRUE; -} +/* + * Copyright © 2006 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ephyr.h" +#include "exa_priv.h" +#include "fbpict.h" + +#define EPHYR_TRACE_DRAW 0 + +#if EPHYR_TRACE_DRAW +#define TRACE_DRAW() ErrorF("%s\n", __FUNCTION__); +#else +#define TRACE_DRAW() do { } while (0) +#endif + +/* Use some oddball alignments, to expose issues in alignment handling in EXA. */ +#define EPHYR_OFFSET_ALIGN 24 +#define EPHYR_PITCH_ALIGN 24 + +#define EPHYR_OFFSCREEN_SIZE (16 * 1024 * 1024) +#define EPHYR_OFFSCREEN_BASE (1 * 1024 * 1024) + +/** + * Forces a real devPrivate.ptr for hidden pixmaps, so that we can call down to + * fb functions. + */ +static void +ephyrPreparePipelinedAccess(PixmapPtr pPix, int index) +{ + KdScreenPriv(pPix->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + assert(fakexa->saved_ptrs[index] == NULL); + fakexa->saved_ptrs[index] = pPix->devPrivate.ptr; + + if (pPix->devPrivate.ptr != NULL) + return; + + pPix->devPrivate.ptr = fakexa->exa->memoryBase + exaGetPixmapOffset(pPix); +} + +/** + * Restores the original devPrivate.ptr of the pixmap from before we messed with + * it. + */ +static void +ephyrFinishPipelinedAccess(PixmapPtr pPix, int index) +{ + KdScreenPriv(pPix->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + pPix->devPrivate.ptr = fakexa->saved_ptrs[index]; + fakexa->saved_ptrs[index] = NULL; +} + +/** + * Sets up a scratch GC for fbFill, and saves other parameters for the + * ephyrSolid implementation. + */ +static Bool +ephyrPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + ChangeGCVal tmpval[3]; + + ephyrPreparePipelinedAccess(pPix, EXA_PREPARE_DEST); + + fakexa->pDst = pPix; + fakexa->pGC = GetScratchGC(pPix->drawable.depth, pScreen); + + tmpval[0].val = alu; + tmpval[1].val = pm; + tmpval[2].val = fg; + ChangeGC(NullClient, fakexa->pGC, GCFunction | GCPlaneMask | GCForeground, tmpval); + + ValidateGC(&pPix->drawable, fakexa->pGC); + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbFill of the rectangle to be drawn. + */ +static void +ephyrSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbFill(&fakexa->pDst->drawable, fakexa->pGC, x1, y1, x2 - x1, y2 - y1); +} + +/** + * Cleans up the scratch GC created in ephyrPrepareSolid. + */ +static void +ephyrDoneSolid(PixmapPtr pPix) +{ + ScreenPtr pScreen = pPix->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + FreeScratchGC(fakexa->pGC); + + ephyrFinishPipelinedAccess(pPix, EXA_PREPARE_DEST); +} + +/** + * Sets up a scratch GC for fbCopyArea, and saves other parameters for the + * ephyrCopy implementation. + */ +static Bool +ephyrPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst, int dx, int dy, int alu, + Pixel pm) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + ChangeGCVal tmpval[2]; + + ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); + ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); + + fakexa->pSrc = pSrc; + fakexa->pDst = pDst; + fakexa->pGC = GetScratchGC(pDst->drawable.depth, pScreen); + + tmpval[0].val = alu; + tmpval[1].val = pm; + ChangeGC (NullClient, fakexa->pGC, GCFunction | GCPlaneMask, tmpval); + + ValidateGC(&pDst->drawable, fakexa->pGC); + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbCopyArea to take care of the requested copy. + */ +static void +ephyrCopy(PixmapPtr pDst, int srcX, int srcY, int dstX, int dstY, int w, int h) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbCopyArea(&fakexa->pSrc->drawable, &fakexa->pDst->drawable, fakexa->pGC, + srcX, srcY, w, h, dstX, dstY); +} + +/** + * Cleans up the scratch GC created in ephyrPrepareCopy. + */ +static void +ephyrDoneCopy(PixmapPtr pDst) +{ + ScreenPtr pScreen = pDst->drawable.pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + FreeScratchGC (fakexa->pGC); + + ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); + ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); +} + +/** + * Reports that we can always accelerate the given operation. This may not be + * desirable from an EXA testing standpoint -- testing the fallback paths would + * be useful, too. + */ +static Bool +ephyrCheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture) +{ + /* Exercise the component alpha helper, so fail on this case like a normal + * driver + */ + if (pMaskPicture && pMaskPicture->componentAlpha && op == PictOpOver) + return FALSE; + + return TRUE; +} + +/** + * Saves off the parameters for ephyrComposite. + */ +static Bool +ephyrPrepareComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskPicture, + PicturePtr pDstPicture, PixmapPtr pSrc, PixmapPtr pMask, + PixmapPtr pDst) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); + ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); + if (pMask != NULL) + ephyrPreparePipelinedAccess(pMask, EXA_PREPARE_MASK); + + fakexa->op = op; + fakexa->pSrcPicture = pSrcPicture; + fakexa->pMaskPicture = pMaskPicture; + fakexa->pDstPicture = pDstPicture; + fakexa->pSrc = pSrc; + fakexa->pMask = pMask; + fakexa->pDst = pDst; + + TRACE_DRAW(); + + return TRUE; +} + +/** + * Does an fbComposite to complete the requested drawing operation. + */ +static void +ephyrComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, + int dstX, int dstY, int w, int h) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fbComposite(fakexa->op, fakexa->pSrcPicture, fakexa->pMaskPicture, + fakexa->pDstPicture, srcX, srcY, maskX, maskY, dstX, dstY, + w, h); +} + +static void +ephyrDoneComposite(PixmapPtr pDst) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + if (fakexa->pMask != NULL) + ephyrFinishPipelinedAccess(fakexa->pMask, EXA_PREPARE_MASK); + ephyrFinishPipelinedAccess(fakexa->pSrc, EXA_PREPARE_SRC); + ephyrFinishPipelinedAccess(fakexa->pDst, EXA_PREPARE_DEST); +} + +/** + * Does fake acceleration of DownloadFromScren using memcpy. + */ +static Bool +ephyrDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w, int h, char *dst, + int dst_pitch) +{ + KdScreenPriv(pSrc->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + unsigned char *src; + int src_pitch, cpp; + + if (pSrc->drawable.bitsPerPixel < 8) + return FALSE; + + ephyrPreparePipelinedAccess(pSrc, EXA_PREPARE_SRC); + + cpp = pSrc->drawable.bitsPerPixel / 8; + src_pitch = exaGetPixmapPitch(pSrc); + src = fakexa->exa->memoryBase + exaGetPixmapOffset(pSrc); + src += y * src_pitch + x * cpp; + + for (; h > 0; h--) { + memcpy(dst, src, w * cpp); + dst += dst_pitch; + src += src_pitch; + } + + exaMarkSync(pSrc->drawable.pScreen); + + ephyrFinishPipelinedAccess(pSrc, EXA_PREPARE_SRC); + + return TRUE; +} + +/** + * Does fake acceleration of UploadToScreen using memcpy. + */ +static Bool +ephyrUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src, + int src_pitch) +{ + KdScreenPriv(pDst->drawable.pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + unsigned char *dst; + int dst_pitch, cpp; + + if (pDst->drawable.bitsPerPixel < 8) + return FALSE; + + ephyrPreparePipelinedAccess(pDst, EXA_PREPARE_DEST); + + cpp = pDst->drawable.bitsPerPixel / 8; + dst_pitch = exaGetPixmapPitch(pDst); + dst = fakexa->exa->memoryBase + exaGetPixmapOffset(pDst); + dst += y * dst_pitch + x * cpp; + + for (; h > 0; h--) { + memcpy(dst, src, w * cpp); + dst += dst_pitch; + src += src_pitch; + } + + exaMarkSync(pDst->drawable.pScreen); + + ephyrFinishPipelinedAccess(pDst, EXA_PREPARE_DEST); + + return TRUE; +} + +static Bool +ephyrPrepareAccess(PixmapPtr pPix, int index) +{ + /* Make sure we don't somehow end up with a pointer that is in framebuffer + * and hasn't been readied for us. + */ + assert(pPix->devPrivate.ptr != NULL); + + return TRUE; +} + +/** + * In fakexa, we currently only track whether we have synced to the latest + * "accelerated" drawing that has happened or not. It's not used for anything + * yet. + */ +static int +ephyrMarkSync(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fakexa->is_synced = FALSE; + + return 0; +} + +/** + * Assumes that we're waiting on the latest marker. When EXA gets smarter and + * starts using markers in a fine-grained way (for example, waiting on drawing + * to required pixmaps to complete, rather than waiting for all drawing to + * complete), we'll want to make the ephyrMarkSync/ephyrWaitMarker + * implementation fine-grained as well. + */ +static void +ephyrWaitMarker(ScreenPtr pScreen, int marker) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrFakexaPriv *fakexa = scrpriv->fakexa; + + fakexa->is_synced = TRUE; +} + +/** + * This function initializes EXA to use the fake acceleration implementation + * which just falls through to software. The purpose is to have a reliable, + * correct driver with which to test changes to the EXA core. + */ +Bool +ephyrDrawInit(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + EphyrScrPriv *scrpriv = screen->driver; + EphyrPriv *priv = screen->card->driver; + EphyrFakexaPriv *fakexa; + Bool success; + + fakexa = calloc(1, sizeof(*fakexa)); + if (fakexa == NULL) + return FALSE; + + fakexa->exa = exaDriverAlloc(); + if (fakexa->exa == NULL) { + free(fakexa); + return FALSE; + } + + fakexa->exa->memoryBase = (CARD8 *) (priv->base); + fakexa->exa->memorySize = priv->bytes_per_line * ephyrBufferHeight(screen); + fakexa->exa->offScreenBase = priv->bytes_per_line * screen->height; + + /* Since we statically link against EXA, we shouldn't have to be smart about + * versioning. + */ + fakexa->exa->exa_major = 2; + fakexa->exa->exa_minor = 0; + + fakexa->exa->PrepareSolid = ephyrPrepareSolid; + fakexa->exa->Solid = ephyrSolid; + fakexa->exa->DoneSolid = ephyrDoneSolid; + + fakexa->exa->PrepareCopy = ephyrPrepareCopy; + fakexa->exa->Copy = ephyrCopy; + fakexa->exa->DoneCopy = ephyrDoneCopy; + + fakexa->exa->CheckComposite = ephyrCheckComposite; + fakexa->exa->PrepareComposite = ephyrPrepareComposite; + fakexa->exa->Composite = ephyrComposite; + fakexa->exa->DoneComposite = ephyrDoneComposite; + + fakexa->exa->DownloadFromScreen = ephyrDownloadFromScreen; + fakexa->exa->UploadToScreen = ephyrUploadToScreen; + + fakexa->exa->MarkSync = ephyrMarkSync; + fakexa->exa->WaitMarker = ephyrWaitMarker; + + fakexa->exa->PrepareAccess = ephyrPrepareAccess; + + fakexa->exa->pixmapOffsetAlign = EPHYR_OFFSET_ALIGN; + fakexa->exa->pixmapPitchAlign = EPHYR_PITCH_ALIGN; + + fakexa->exa->maxX = 1023; + fakexa->exa->maxY = 1023; + + fakexa->exa->flags = EXA_OFFSCREEN_PIXMAPS; + + success = exaDriverInit(pScreen, fakexa->exa); + if (success) { + ErrorF("Initialized fake EXA acceleration\n"); + scrpriv->fakexa = fakexa; + } else { + ErrorF("Failed to initialize EXA\n"); + free(fakexa->exa); + free(fakexa); + } + + return success; +} + +void +ephyrDrawEnable(ScreenPtr pScreen) +{ +} + +void +ephyrDrawDisable(ScreenPtr pScreen) +{ +} + +void +ephyrDrawFini(ScreenPtr pScreen) +{ +} + +/** + * exaDDXDriverInit is required by the top-level EXA module, and is used by + * the xorg DDX to hook in its EnableDisableFB wrapper. We don't need it, since + * we won't be enabling/disabling the FB. + */ +void +exaDDXDriverInit(ScreenPtr pScreen) +{ + ExaScreenPriv(pScreen); + + pExaScr->migration = ExaMigrationSmart; + pExaScr->checkDirtyCorrectness = TRUE; +} diff --git a/xorg-server/hw/kdrive/ephyr/ephyrdriext.c b/xorg-server/hw/kdrive/ephyr/ephyrdriext.c index 5f5fd3bff..3d3d18a39 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyrdriext.c +++ b/xorg-server/hw/kdrive/ephyr/ephyrdriext.c @@ -1,1429 +1,1429 @@ -/* - * Xephyr - A kdrive X server thats runs in a host X window. - * Authored by Matthew Allum - * - * Copyright © 2007 OpenedHand Ltd - * - * 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 OpenedHand Ltd not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. OpenedHand Ltd makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OpenedHand Ltd 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. - * - * This file is heavily copied from hw/xfree86/dri/xf86dri.c - * - * Authors: - * Dodji Seketeli - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include -#include -#define _XF86DRI_SERVER_ -#include -#include -#include "misc.h" -#include "privates.h" -#include "dixstruct.h" -#include "extnsionst.h" -#include "colormapst.h" -#include "cursorstr.h" -#include "scrnintstr.h" -#include "windowstr.h" -#include "servermd.h" -#include "swaprep.h" -#include "ephyrdri.h" -#include "ephyrdriext.h" -#include "hostx.h" -#define _HAVE_XALLOC_DECLS -#include "ephyrlog.h" -#include "protocol-versions.h" - -typedef struct { - int foo; -} EphyrDRIWindowPrivRec; -typedef EphyrDRIWindowPrivRec* EphyrDRIWindowPrivPtr; - -typedef struct { - CreateWindowProcPtr CreateWindow ; - DestroyWindowProcPtr DestroyWindow ; - MoveWindowProcPtr MoveWindow ; - PositionWindowProcPtr PositionWindow ; - ClipNotifyProcPtr ClipNotify ; -} EphyrDRIScreenPrivRec; -typedef EphyrDRIScreenPrivRec* EphyrDRIScreenPrivPtr; - -static int DRIErrorBase; - -static DISPATCH_PROC(ProcXF86DRIQueryVersion); -static DISPATCH_PROC(ProcXF86DRIQueryDirectRenderingCapable); -static DISPATCH_PROC(ProcXF86DRIOpenConnection); -static DISPATCH_PROC(ProcXF86DRICloseConnection); -static DISPATCH_PROC(ProcXF86DRIGetClientDriverName); -static DISPATCH_PROC(ProcXF86DRICreateContext); -static DISPATCH_PROC(ProcXF86DRIDestroyContext); -static DISPATCH_PROC(ProcXF86DRICreateDrawable); -static DISPATCH_PROC(ProcXF86DRIDestroyDrawable); -static DISPATCH_PROC(ProcXF86DRIGetDrawableInfo); -static DISPATCH_PROC(ProcXF86DRIGetDeviceInfo); -static DISPATCH_PROC(ProcXF86DRIDispatch); -static DISPATCH_PROC(ProcXF86DRIAuthConnection); - -static DISPATCH_PROC(SProcXF86DRIQueryVersion); -static DISPATCH_PROC(SProcXF86DRIQueryDirectRenderingCapable); -static DISPATCH_PROC(SProcXF86DRIDispatch); - -static Bool ephyrDRIScreenInit (ScreenPtr a_screen) ; -static Bool ephyrDRICreateWindow (WindowPtr a_win) ; -static Bool ephyrDRIDestroyWindow (WindowPtr a_win) ; -static void ephyrDRIMoveWindow (WindowPtr a_win, - int a_x, int a_y, - WindowPtr a_siblings, - VTKind a_kind); -static Bool ephyrDRIPositionWindow (WindowPtr a_win, - int x, int y) ; -static void ephyrDRIClipNotify (WindowPtr a_win, - int a_x, int a_y) ; - -static Bool EphyrMirrorHostVisuals (ScreenPtr a_screen) ; -static Bool destroyHostPeerWindow (const WindowPtr a_win) ; -static Bool findWindowPairFromLocal (WindowPtr a_local, - EphyrWindowPair **a_pair); - -static unsigned char DRIReqCode = 0; - -static int ephyrDRIWindowKeyIndex; -static DevPrivateKey ephyrDRIWindowKey = &ephyrDRIWindowKeyIndex; -static int ephyrDRIScreenKeyIndex; -static DevPrivateKey ephyrDRIScreenKey = &ephyrDRIScreenKeyIndex; - -#define GET_EPHYR_DRI_WINDOW_PRIV(win) ((EphyrDRIWindowPrivPtr) \ - dixLookupPrivate(&(win)->devPrivates, ephyrDRIWindowKey)) -#define GET_EPHYR_DRI_SCREEN_PRIV(screen) ((EphyrDRIScreenPrivPtr) \ - dixLookupPrivate(&(screen)->devPrivates, ephyrDRIScreenKey)) - - -Bool -ephyrDRIExtensionInit (ScreenPtr a_screen) -{ - Bool is_ok=FALSE ; - ExtensionEntry* extEntry=NULL; - EphyrDRIScreenPrivPtr screen_priv=NULL ; - - EPHYR_LOG ("enter\n") ; - if (!hostx_has_dri ()) { - EPHYR_LOG ("host does not have DRI extension\n") ; - goto out ; - } - EPHYR_LOG ("host X does have DRI extension\n") ; - if (!hostx_has_xshape ()) { - EPHYR_LOG ("host does not have XShape extension\n") ; - goto out ; - } - EPHYR_LOG ("host X does have XShape extension\n") ; - -#ifdef XF86DRI_EVENTS - EventType = CreateNewResourceType (XF86DRIFreeEvents, "DRIEvents"); - if (!EventType) { - EPHYR_LOG_ERROR ("failed to register DRI event resource type\n") ; - goto out ; - } -#endif - - if ((extEntry = AddExtension(XF86DRINAME, - XF86DRINumberEvents, - XF86DRINumberErrors, - ProcXF86DRIDispatch, - SProcXF86DRIDispatch, - NULL, - StandardMinorOpcode))) { - DRIReqCode = (unsigned char)extEntry->base; - DRIErrorBase = extEntry->errorBase; - } else { - EPHYR_LOG_ERROR ("failed to register DRI extension\n") ; - goto out ; - } - screen_priv = xcalloc (1, sizeof (EphyrDRIScreenPrivRec)) ; - if (!screen_priv) { - EPHYR_LOG_ERROR ("failed to allocate screen_priv\n") ; - goto out ; - } - dixSetPrivate(&a_screen->devPrivates, ephyrDRIScreenKey, screen_priv); - - if (!ephyrDRIScreenInit (a_screen)) { - EPHYR_LOG_ERROR ("ephyrDRIScreenInit() failed\n") ; - goto out ; - } - EphyrMirrorHostVisuals (a_screen) ; - is_ok=TRUE ; -out: - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -static Bool -ephyrDRIScreenInit (ScreenPtr a_screen) -{ - Bool is_ok=FALSE ; - EphyrDRIScreenPrivPtr screen_priv=NULL ; - - EPHYR_RETURN_VAL_IF_FAIL (a_screen, FALSE) ; - - screen_priv=GET_EPHYR_DRI_SCREEN_PRIV (a_screen) ; - EPHYR_RETURN_VAL_IF_FAIL (screen_priv, FALSE) ; - - screen_priv->CreateWindow = a_screen->CreateWindow ; - screen_priv->DestroyWindow = a_screen->DestroyWindow ; - screen_priv->MoveWindow = a_screen->MoveWindow ; - screen_priv->PositionWindow = a_screen->PositionWindow ; - screen_priv->ClipNotify = a_screen->ClipNotify ; - - a_screen->CreateWindow = ephyrDRICreateWindow ; - a_screen->DestroyWindow = ephyrDRIDestroyWindow ; - a_screen->MoveWindow = ephyrDRIMoveWindow ; - a_screen->PositionWindow = ephyrDRIPositionWindow ; - a_screen->ClipNotify = ephyrDRIClipNotify ; - - is_ok = TRUE ; - - return is_ok ; -} - -static Bool -ephyrDRICreateWindow (WindowPtr a_win) -{ - Bool is_ok=FALSE ; - ScreenPtr screen=NULL ; - EphyrDRIScreenPrivPtr screen_priv =NULL; - - EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; - screen = a_win->drawable.pScreen ; - EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; - screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; - EPHYR_RETURN_VAL_IF_FAIL (screen_priv - && screen_priv->CreateWindow, - FALSE) ; - - EPHYR_LOG ("enter. win:%p\n", a_win) ; - - screen->CreateWindow = screen_priv->CreateWindow ; - is_ok = (*screen->CreateWindow) (a_win) ; - screen->CreateWindow = ephyrDRICreateWindow ; - - if (is_ok) { - dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL); - } - return is_ok ; -} - -static Bool -ephyrDRIDestroyWindow (WindowPtr a_win) -{ - Bool is_ok=FALSE ; - ScreenPtr screen=NULL ; - EphyrDRIScreenPrivPtr screen_priv =NULL; - - EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; - screen = a_win->drawable.pScreen ; - EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; - screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; - EPHYR_RETURN_VAL_IF_FAIL (screen_priv - && screen_priv->DestroyWindow, - FALSE) ; - - screen->DestroyWindow = screen_priv->DestroyWindow ; - if (screen->DestroyWindow) { - is_ok = (*screen->DestroyWindow) (a_win) ; - } - screen->DestroyWindow = ephyrDRIDestroyWindow ; - - if (is_ok) { - EphyrDRIWindowPrivPtr win_priv=GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; - if (win_priv) { - destroyHostPeerWindow (a_win) ; - xfree (win_priv) ; - dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL); - EPHYR_LOG ("destroyed the remote peer window\n") ; - } - } - return is_ok ; -} - -static void -ephyrDRIMoveWindow (WindowPtr a_win, - int a_x, int a_y, - WindowPtr a_siblings, - VTKind a_kind) -{ - Bool is_ok=FALSE ; - ScreenPtr screen=NULL ; - EphyrDRIScreenPrivPtr screen_priv =NULL; - EphyrDRIWindowPrivPtr win_priv=NULL ; - EphyrWindowPair *pair=NULL ; - EphyrBox geo; - int x=0,y=0;/*coords relative to parent window*/ - - EPHYR_RETURN_IF_FAIL (a_win) ; - - EPHYR_LOG ("enter\n") ; - screen = a_win->drawable.pScreen ; - EPHYR_RETURN_IF_FAIL (screen) ; - screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; - EPHYR_RETURN_IF_FAIL (screen_priv - && screen_priv->MoveWindow) ; - - screen->MoveWindow = screen_priv->MoveWindow ; - if (screen->MoveWindow) { - (*screen->MoveWindow) (a_win, a_x, a_y, a_siblings, a_kind) ; - } - screen->MoveWindow = ephyrDRIMoveWindow ; - - EPHYR_LOG ("window: %p\n", a_win) ; - if (!a_win->parent) { - EPHYR_LOG ("cannot move root window\n") ; - is_ok = TRUE ; - goto out ; - } - win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; - if (!win_priv) { - EPHYR_LOG ("not a DRI peered window\n") ; - is_ok = TRUE ; - goto out ; - } - if (!findWindowPairFromLocal (a_win, &pair) || !pair) { - EPHYR_LOG_ERROR ("failed to get window pair\n") ; - goto out ; - } - /*compute position relative to parent window*/ - x = a_win->drawable.x - a_win->parent->drawable.x ; - y = a_win->drawable.y - a_win->parent->drawable.y ; - /*set the geometry to pass to hostx_set_window_geometry*/ - memset (&geo, 0, sizeof (geo)) ; - geo.x = x ; - geo.y = y ; - geo.width = a_win->drawable.width ; - geo.height = a_win->drawable.height ; - hostx_set_window_geometry (pair->remote, &geo) ; - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; - /*do cleanup here*/ -} - -static Bool -ephyrDRIPositionWindow (WindowPtr a_win, - int a_x, int a_y) -{ - Bool is_ok=FALSE ; - ScreenPtr screen=NULL ; - EphyrDRIScreenPrivPtr screen_priv =NULL; - EphyrDRIWindowPrivPtr win_priv=NULL ; - EphyrWindowPair *pair=NULL ; - EphyrBox geo; - - EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; - - EPHYR_LOG ("enter\n") ; - screen = a_win->drawable.pScreen ; - EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; - screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; - EPHYR_RETURN_VAL_IF_FAIL (screen_priv - && screen_priv->PositionWindow, - FALSE) ; - - screen->PositionWindow = screen_priv->PositionWindow ; - if (screen->PositionWindow) { - (*screen->PositionWindow) (a_win, a_x, a_y) ; - } - screen->PositionWindow = ephyrDRIPositionWindow ; - - EPHYR_LOG ("window: %p\n", a_win) ; - win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; - if (!win_priv) { - EPHYR_LOG ("not a DRI peered window\n") ; - is_ok = TRUE ; - goto out ; - } - if (!findWindowPairFromLocal (a_win, &pair) || !pair) { - EPHYR_LOG_ERROR ("failed to get window pair\n") ; - goto out ; - } - /*set the geometry to pass to hostx_set_window_geometry*/ - memset (&geo, 0, sizeof (geo)) ; - geo.x = a_x ; - geo.y = a_y ; - geo.width = a_win->drawable.width ; - geo.height = a_win->drawable.height ; - hostx_set_window_geometry (pair->remote, &geo) ; - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; - /*do cleanup here*/ - return is_ok ; -} - -static void -ephyrDRIClipNotify (WindowPtr a_win, - int a_x, int a_y) -{ - Bool is_ok=FALSE ; - ScreenPtr screen=NULL ; - EphyrDRIScreenPrivPtr screen_priv =NULL; - EphyrDRIWindowPrivPtr win_priv=NULL ; - EphyrWindowPair *pair=NULL ; - EphyrRect *rects=NULL; - int i=0 ; - - EPHYR_RETURN_IF_FAIL (a_win) ; - - EPHYR_LOG ("enter\n") ; - screen = a_win->drawable.pScreen ; - EPHYR_RETURN_IF_FAIL (screen) ; - screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; - EPHYR_RETURN_IF_FAIL (screen_priv && screen_priv->ClipNotify) ; - - screen->ClipNotify = screen_priv->ClipNotify ; - if (screen->ClipNotify) { - (*screen->ClipNotify) (a_win, a_x, a_y) ; - } - screen->ClipNotify = ephyrDRIClipNotify ; - - EPHYR_LOG ("window: %p\n", a_win) ; - win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; - if (!win_priv) { - EPHYR_LOG ("not a DRI peered window\n") ; - is_ok = TRUE ; - goto out ; - } - if (!findWindowPairFromLocal (a_win, &pair) || !pair) { - EPHYR_LOG_ERROR ("failed to get window pair\n") ; - goto out ; - } - rects = xcalloc (REGION_NUM_RECTS (&a_win->clipList), - sizeof (EphyrRect)) ; - for (i=0; i < REGION_NUM_RECTS (&a_win->clipList); i++) { - memmove (&rects[i], - ®ION_RECTS (&a_win->clipList)[i], - sizeof (EphyrRect)) ; - rects[i].x1 -= a_win->drawable.x; - rects[i].x2 -= a_win->drawable.x; - rects[i].y1 -= a_win->drawable.y; - rects[i].y2 -= a_win->drawable.y; - } - /* - * push the clipping region of this window - * to the peer window in the host - */ - is_ok = hostx_set_window_bounding_rectangles - (pair->remote, - rects, - REGION_NUM_RECTS (&a_win->clipList)) ; - is_ok = TRUE ; - -out: - xfree (rects) ; - rects = NULL ; - - EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; - /*do cleanup here*/ -} - -/** - * Duplicates a visual of a_screen - * In screen a_screen, for depth a_depth, find a visual which - * bitsPerRGBValue and colormap size equal - * a_bits_per_rgb_values and a_colormap_entries. - * The ID of that duplicated visual is set to a_new_id. - * That duplicated visual is then added to the list of visuals - * of the screen. - */ -static Bool -EphyrDuplicateVisual (unsigned int a_screen, - short a_depth, - short a_class, - short a_bits_per_rgb_values, - short a_colormap_entries, - unsigned int a_red_mask, - unsigned int a_green_mask, - unsigned int a_blue_mask, - unsigned int a_new_id) -{ - Bool is_ok = FALSE, found_visual=FALSE, found_depth=FALSE ; - ScreenPtr screen=NULL ; - VisualRec new_visual, *new_visuals=NULL ; - int i=0 ; - - EPHYR_LOG ("enter\n") ; - if (a_screen > screenInfo.numScreens) { - EPHYR_LOG_ERROR ("bad screen number\n") ; - goto out; - } - memset (&new_visual, 0, sizeof (VisualRec)) ; - - /*get the screen pointed to by a_screen*/ - screen = screenInfo.screens[a_screen] ; - EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; - - /* - * In that screen, first look for an existing visual that has the - * same characteristics as those passed in parameter - * to this function and copy it. - */ - for (i=0; i < screen->numVisuals; i++) { - if (screen->visuals[i].bitsPerRGBValue == a_bits_per_rgb_values && - screen->visuals[i].ColormapEntries == a_colormap_entries ) { - /*copy the visual found*/ - memcpy (&new_visual, &screen->visuals[i], sizeof (new_visual)) ; - new_visual.vid = a_new_id ; - new_visual.class = a_class ; - new_visual.redMask = a_red_mask ; - new_visual.greenMask = a_green_mask ; - new_visual.blueMask = a_blue_mask ; - found_visual = TRUE ; - EPHYR_LOG ("found a visual that matches visual id: %d\n", - a_new_id) ; - break; - } - } - if (!found_visual) { - EPHYR_LOG ("did not find any visual matching %d\n", a_new_id) ; - goto out ; - } - /* - * be prepare to extend screen->visuals to add new_visual to it - */ - new_visuals = xcalloc (screen->numVisuals+1, sizeof (VisualRec)) ; - memmove (new_visuals, - screen->visuals, - screen->numVisuals*sizeof (VisualRec)) ; - memmove (&new_visuals[screen->numVisuals], - &new_visual, - sizeof (VisualRec)) ; - /* - * Now, in that same screen, update the screen->allowedDepths member. - * In that array, each element represents the visuals applicable to - * a given depth. So we need to add an entry matching the new visual - * that we are going to add to screen->visuals - */ - for (i=0; inumDepths; i++) { - VisualID *vids=NULL; - DepthPtr cur_depth=NULL ; - /*find the entry matching a_depth*/ - if (screen->allowedDepths[i].depth != a_depth) - continue ; - cur_depth = &screen->allowedDepths[i]; - /* - * extend the list of visual IDs in that entry, - * so to add a_new_id in there. - */ - vids = xrealloc (cur_depth->vids, - (cur_depth->numVids+1)*sizeof (VisualID)); - if (!vids) { - EPHYR_LOG_ERROR ("failed to realloc numids\n") ; - goto out ; - } - vids[cur_depth->numVids] = a_new_id ; - /* - * Okay now commit our change. - * Do really update screen->allowedDepths[i] - */ - cur_depth->numVids++ ; - cur_depth->vids = vids ; - found_depth=TRUE; - } - if (!found_depth) { - EPHYR_LOG_ERROR ("failed to update screen[%d]->allowedDepth\n", - a_screen) ; - goto out ; - } - /* - * Commit our change to screen->visuals - */ - xfree (screen->visuals) ; - screen->visuals = new_visuals ; - screen->numVisuals++ ; - new_visuals = NULL ; - - is_ok = TRUE ; -out: - xfree (new_visuals) ; - new_visuals = NULL ; - - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -/** - * Duplicates the visuals of the host X server. - * This is necessary to have visuals that have the same - * ID as those of the host X. It is important to have that for - * GLX. - */ -static Bool -EphyrMirrorHostVisuals (ScreenPtr a_screen) -{ - Bool is_ok=FALSE; - EphyrHostVisualInfo *visuals=NULL; - int nb_visuals=0, i=0; - - EPHYR_LOG ("enter\n") ; - if (!hostx_get_visuals_info (&visuals, &nb_visuals)) { - EPHYR_LOG_ERROR ("failed to get host visuals\n") ; - goto out ; - } - for (i=0; imyNum, - visuals[i].depth, - visuals[i].class, - visuals[i].bits_per_rgb, - visuals[i].colormap_size, - visuals[i].red_mask, - visuals[i].green_mask, - visuals[i].blue_mask, - visuals[i].visualid)) { - EPHYR_LOG_ERROR ("failed to duplicate host visual %d\n", - (int)visuals[i].visualid) ; - } - } - - is_ok = TRUE ; -out: - EPHYR_LOG ("leave\n") ; - return is_ok; -} - - -static int -ProcXF86DRIQueryVersion (register ClientPtr client) -{ - xXF86DRIQueryVersionReply rep; - register int n; - REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq); - - EPHYR_LOG ("enter\n") ; - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.majorVersion = SERVER_XF86DRI_MAJOR_VERSION; - rep.minorVersion = SERVER_XF86DRI_MINOR_VERSION; - rep.patchVersion = SERVER_XF86DRI_PATCH_VERSION; - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - swaps(&rep.majorVersion, n); - swaps(&rep.minorVersion, n); - swapl(&rep.patchVersion, n); - } - WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) -{ - xXF86DRIQueryDirectRenderingCapableReply rep; - Bool isCapable; - register int n; - REQUEST(xXF86DRIQueryDirectRenderingCapableReq); - REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if (!ephyrDRIQueryDirectRenderingCapable (stuff->screen, &isCapable)) { - return BadValue; - } - rep.isCapable = isCapable; - - if (!LocalClient(client) || client->swapped) - rep.isCapable = 0; - - if (client->swapped) { - swaps(&rep.sequenceNumber, n); - swapl(&rep.length, n); - } - - WriteToClient(client, sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep); - EPHYR_LOG ("leave\n") ; - - return (client->noClientException); -} - -static int -ProcXF86DRIOpenConnection (register ClientPtr client) -{ - xXF86DRIOpenConnectionReply rep; - drm_handle_t hSAREA; - char* busIdString; - REQUEST(xXF86DRIOpenConnectionReq); - REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - if (!ephyrDRIOpenConnection(stuff->screen, - &hSAREA, - &busIdString)) { - return BadValue; - } - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.busIdStringLength = 0; - if (busIdString) - rep.busIdStringLength = strlen(busIdString); - rep.length = bytes_to_int32(SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) + - pad_to_int32(rep.busIdStringLength)); - - rep.hSAREALow = (CARD32)(hSAREA & 0xffffffff); -#if defined(LONG64) && !defined(__linux__) - rep.hSAREAHigh = (CARD32)(hSAREA >> 32); -#else - rep.hSAREAHigh = 0; -#endif - - WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep); - if (rep.busIdStringLength) - WriteToClient(client, rep.busIdStringLength, busIdString); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIAuthConnection (register ClientPtr client) -{ - xXF86DRIAuthConnectionReply rep; - REQUEST(xXF86DRIAuthConnectionReq); - REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - rep.authenticated = 1; - - if (!ephyrDRIAuthConnection (stuff->screen, stuff->magic)) { - ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic); - rep.authenticated = 0; - } - WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRICloseConnection (register ClientPtr client) -{ - REQUEST(xXF86DRICloseConnectionReq); - REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq); - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - /* - DRICloseConnection( screenInfo.screens[stuff->screen]); - */ - - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIGetClientDriverName (register ClientPtr client) -{ - xXF86DRIGetClientDriverNameReply rep; - char* clientDriverName; - REQUEST(xXF86DRIGetClientDriverNameReq); - REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - ephyrDRIGetClientDriverName (stuff->screen, - (int *)&rep.ddxDriverMajorVersion, - (int *)&rep.ddxDriverMinorVersion, - (int *)&rep.ddxDriverPatchVersion, - &clientDriverName); - - rep.type = X_Reply; - rep.sequenceNumber = client->sequence; - rep.clientDriverNameLength = 0; - if (clientDriverName) - rep.clientDriverNameLength = strlen(clientDriverName); - rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetClientDriverNameReply) - - SIZEOF(xGenericReply) + - pad_to_int32(rep.clientDriverNameLength)); - - WriteToClient(client, - sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep); - if (rep.clientDriverNameLength) - WriteToClient(client, - rep.clientDriverNameLength, - clientDriverName); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRICreateContext (register ClientPtr client) -{ - xXF86DRICreateContextReply rep; - ScreenPtr pScreen; - VisualPtr visual; - int i=0; - unsigned long context_id=0; - REQUEST(xXF86DRICreateContextReq); - REQUEST_SIZE_MATCH(xXF86DRICreateContextReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - pScreen = screenInfo.screens[stuff->screen]; - visual = pScreen->visuals; - - /* Find the requested X visual */ - for (i = 0; i < pScreen->numVisuals; i++, visual++) - if (visual->vid == stuff->visual) - break; - if (i == pScreen->numVisuals) { - /* No visual found */ - return BadValue; - } - - context_id = stuff->context ; - if (!ephyrDRICreateContext (stuff->screen, - stuff->visual, - &context_id, - (drm_context_t *)&rep.hHWContext)) { - return BadValue; - } - - WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIDestroyContext (register ClientPtr client) -{ - REQUEST(xXF86DRIDestroyContextReq); - REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq); - EPHYR_LOG ("enter\n") ; - - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - if (!ephyrDRIDestroyContext (stuff->screen, stuff->context)) { - return BadValue; - } - - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static Bool -getWindowVisual (const WindowPtr a_win, - VisualPtr *a_visual) -{ - int i=0, visual_id=0 ; - EPHYR_RETURN_VAL_IF_FAIL (a_win - && a_win->drawable.pScreen - && a_win->drawable.pScreen->visuals, - FALSE) ; - - visual_id = wVisual (a_win) ; - for (i=0; i < a_win->drawable.pScreen->numVisuals; i++) { - if (a_win->drawable.pScreen->visuals[i].vid == visual_id) { - *a_visual = &a_win->drawable.pScreen->visuals[i] ; - return TRUE ; - } - } - return FALSE ; -} - - -#define NUM_WINDOW_PAIRS 256 -static EphyrWindowPair window_pairs[NUM_WINDOW_PAIRS] ; - -static Bool -appendWindowPairToList (WindowPtr a_local, - int a_remote) -{ - int i=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_local, FALSE) ; - - EPHYR_LOG ("(local,remote):(%p, %d)\n", a_local, a_remote) ; - - for (i=0; i < NUM_WINDOW_PAIRS; i++) { - if (window_pairs[i].local == NULL) { - window_pairs[i].local = a_local ; - window_pairs[i].remote = a_remote ; - return TRUE ; - } - } - return FALSE ; -} - -static Bool -findWindowPairFromLocal (WindowPtr a_local, - EphyrWindowPair **a_pair) -{ - int i=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_pair && a_local, FALSE) ; - - for (i=0; i < NUM_WINDOW_PAIRS; i++) { - if (window_pairs[i].local == a_local) { - *a_pair = &window_pairs[i] ; - EPHYR_LOG ("found (%p, %d)\n", - (*a_pair)->local, - (*a_pair)->remote) ; - return TRUE ; - } - } - return FALSE ; -} - -Bool -findWindowPairFromRemote (int a_remote, - EphyrWindowPair **a_pair) -{ - int i=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_pair, FALSE) ; - - for (i=0; i < NUM_WINDOW_PAIRS; i++) { - if (window_pairs[i].remote == a_remote) { - *a_pair = &window_pairs[i] ; - EPHYR_LOG ("found (%p, %d)\n", - (*a_pair)->local, - (*a_pair)->remote) ; - return TRUE ; - } - } - return FALSE ; -} - -static Bool -createHostPeerWindow (const WindowPtr a_win, - int *a_peer_win) -{ - Bool is_ok=FALSE ; - VisualPtr visual=NULL; - EphyrBox geo ; - - EPHYR_RETURN_VAL_IF_FAIL (a_win && a_peer_win, FALSE) ; - EPHYR_RETURN_VAL_IF_FAIL (a_win->drawable.pScreen, - FALSE) ; - - EPHYR_LOG ("enter. a_win '%p'\n", a_win) ; - if (!getWindowVisual (a_win, &visual)) { - EPHYR_LOG_ERROR ("failed to get window visual\n") ; - goto out ; - } - if (!visual) { - EPHYR_LOG_ERROR ("failed to create visual\n") ; - goto out ; - } - memset (&geo, 0, sizeof (geo)) ; - geo.x = a_win->drawable.x ; - geo.y = a_win->drawable.y ; - geo.width = a_win->drawable.width ; - geo.height = a_win->drawable.height ; - if (!hostx_create_window (a_win->drawable.pScreen->myNum, - &geo, visual->vid, a_peer_win)) { - EPHYR_LOG_ERROR ("failed to create host peer window\n") ; - goto out ; - } - if (!appendWindowPairToList (a_win, *a_peer_win)) { - EPHYR_LOG_ERROR ("failed to append window to pair list\n") ; - goto out ; - } - is_ok = TRUE ; -out: - EPHYR_LOG ("leave:remote win%d\n", *a_peer_win) ; - return is_ok ; -} - -static Bool -destroyHostPeerWindow (const WindowPtr a_win) -{ - Bool is_ok = FALSE ; - EphyrWindowPair *pair=NULL ; - EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - if (!findWindowPairFromLocal (a_win, &pair) || !pair) { - EPHYR_LOG_ERROR ("failed to find peer to local window\n") ; - goto out; - } - hostx_destroy_window (pair->remote) ; - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave\n") ; - return is_ok; -} - -static int -ProcXF86DRICreateDrawable (ClientPtr client) -{ - xXF86DRICreateDrawableReply rep; - DrawablePtr drawable=NULL; - WindowPtr window=NULL ; - EphyrWindowPair *pair=NULL ; - EphyrDRIWindowPrivPtr win_priv=NULL; - int rc=0, remote_win=0; - REQUEST(xXF86DRICreateDrawableReq); - REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rc = dixLookupDrawable (&drawable, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success) - return rc; - if (drawable->type != DRAWABLE_WINDOW) { - EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ; - return BadImplementation ; - } - EPHYR_LOG ("lookedup drawable %p\n", drawable) ; - window = (WindowPtr)drawable; - if (findWindowPairFromLocal (window, &pair) && pair) { - remote_win = pair->remote ; - EPHYR_LOG ("found window '%p' paire with remote '%d'\n", - window, remote_win) ; - } else if (!createHostPeerWindow (window, &remote_win)) { - EPHYR_LOG_ERROR ("failed to create host peer window\n") ; - return BadAlloc ; - } - - if (!ephyrDRICreateDrawable (stuff->screen, - remote_win, - (drm_drawable_t *)&rep.hHWDrawable)) { - EPHYR_LOG_ERROR ("failed to create dri drawable\n") ; - return BadValue; - } - - win_priv = GET_EPHYR_DRI_WINDOW_PRIV (window) ; - if (!win_priv) { - win_priv = xcalloc (1, sizeof (EphyrDRIWindowPrivRec)) ; - if (!win_priv) { - EPHYR_LOG_ERROR ("failed to allocate window private\n") ; - return BadAlloc ; - } - dixSetPrivate(&window->devPrivates, ephyrDRIWindowKey, win_priv); - EPHYR_LOG ("paired window '%p' with remote '%d'\n", - window, remote_win) ; - } - - WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep); - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIDestroyDrawable (register ClientPtr client) -{ - DrawablePtr drawable=NULL; - WindowPtr window=NULL; - EphyrWindowPair *pair=NULL; - int rc=0; - REQUEST(xXF86DRIDestroyDrawableReq); - REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rc = dixLookupDrawable(&drawable, - stuff->drawable, - client, - 0, - DixReadAccess); - if (rc != Success) - return rc; - if (drawable->type != DRAWABLE_WINDOW) { - EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ; - return BadImplementation ; - } - window = (WindowPtr)drawable; - if (!findWindowPairFromLocal (window, &pair) && pair) { - EPHYR_LOG_ERROR ("failed to find pair window\n") ; - return BadImplementation; - } - if (!ephyrDRIDestroyDrawable(stuff->screen, - pair->remote/*drawable in host x*/)) { - EPHYR_LOG_ERROR ("failed to destroy dri drawable\n") ; - return BadImplementation; - } - pair->local=NULL ; - pair->remote=0; - - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIGetDrawableInfo (register ClientPtr client) -{ - xXF86DRIGetDrawableInfoReply rep; - DrawablePtr drawable; - WindowPtr window=NULL; - EphyrWindowPair *pair=NULL; - int X=0, Y=0, W=0, H=0, backX=0, backY=0, rc=0, i=0; - drm_clip_rect_t *clipRects=NULL; - drm_clip_rect_t *backClipRects=NULL; - REQUEST(xXF86DRIGetDrawableInfoReq); - REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq); - - EPHYR_LOG ("enter\n") ; - memset (&rep, 0, sizeof (rep)) ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0, - DixReadAccess); - if (rc != Success || !drawable) { - EPHYR_LOG_ERROR ("could not get drawable\n") ; - return rc; - } - - if (drawable->type != DRAWABLE_WINDOW) { - EPHYR_LOG_ERROR ("non windows type drawables are not yes supported\n") ; - return BadImplementation ; - } - window = (WindowPtr)drawable ; - memset (&pair, 0, sizeof (pair)) ; - if (!findWindowPairFromLocal (window, &pair) || !pair) { - EPHYR_LOG_ERROR ("failed to find remote peer drawable\n") ; - return BadMatch ; - } - EPHYR_LOG ("clip list of xephyr gl drawable:\n") ; - for (i=0; i < REGION_NUM_RECTS (&window->clipList); i++) { - EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n", - REGION_RECTS (&window->clipList)[i].x1, - REGION_RECTS (&window->clipList)[i].y1, - REGION_RECTS (&window->clipList)[i].x2, - REGION_RECTS (&window->clipList)[i].y2) ; - } - - if (!ephyrDRIGetDrawableInfo (stuff->screen, - pair->remote/*the drawable in hostx*/, - (unsigned int*)&rep.drawableTableIndex, - (unsigned int*)&rep.drawableTableStamp, - (int*)&X, - (int*)&Y, - (int*)&W, - (int*)&H, - (int*)&rep.numClipRects, - &clipRects, - &backX, - &backY, - (int*)&rep.numBackClipRects, - &backClipRects)) { - return BadValue; - } - EPHYR_LOG ("num clip rects:%d, num back clip rects:%d\n", - (int)rep.numClipRects, (int)rep.numBackClipRects) ; - - rep.drawableX = X; - rep.drawableY = Y; - rep.drawableWidth = W; - rep.drawableHeight = H; - rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) - - SIZEOF(xGenericReply)); - - rep.backX = backX; - rep.backY = backY; - - - if (rep.numClipRects) { - if (clipRects) { - ScreenPtr pScreen = screenInfo.screens[stuff->screen]; - int i=0; - EPHYR_LOG ("clip list of host gl drawable:\n") ; - for (i = 0; i < rep.numClipRects; i++) { - clipRects[i].x1 = max (clipRects[i].x1, 0); - clipRects[i].y1 = max (clipRects[i].y1, 0); - clipRects[i].x2 = min (clipRects[i].x2, - pScreen->width + clipRects[i].x1) ; - clipRects[i].y2 = min (clipRects[i].y2, - pScreen->width + clipRects[i].y1) ; - - EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n", - clipRects[i].x1, clipRects[i].y1, - clipRects[i].x2, clipRects[i].y2) ; - } - } else { - rep.numClipRects = 0; - } - } else { - EPHYR_LOG ("got zero host gl drawable clipping rects\n") ; - } - rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects; - backClipRects = clipRects ; - rep.numBackClipRects = rep.numClipRects ; - if (rep.numBackClipRects) - rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects; - EPHYR_LOG ("num host clip rects:%d\n", (int)rep.numClipRects) ; - EPHYR_LOG ("num host back clip rects:%d\n", (int)rep.numBackClipRects) ; - - rep.length = bytes_to_int32(rep.length); - - WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep); - - if (rep.numClipRects) { - WriteToClient(client, - sizeof(drm_clip_rect_t) * rep.numClipRects, - (char *)clipRects); - } - - if (rep.numBackClipRects) { - WriteToClient(client, - sizeof(drm_clip_rect_t) * rep.numBackClipRects, - (char *)backClipRects); - } - xfree(clipRects); - clipRects = NULL ; - - EPHYR_LOG ("leave\n") ; - - return (client->noClientException); -} - -static int -ProcXF86DRIGetDeviceInfo (register ClientPtr client) -{ - xXF86DRIGetDeviceInfoReply rep; - drm_handle_t hFrameBuffer; - void *pDevPrivate; - REQUEST(xXF86DRIGetDeviceInfoReq); - REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq); - - EPHYR_LOG ("enter\n") ; - if (stuff->screen >= screenInfo.numScreens) { - client->errorValue = stuff->screen; - return BadValue; - } - - rep.type = X_Reply; - rep.length = 0; - rep.sequenceNumber = client->sequence; - - if (!ephyrDRIGetDeviceInfo (stuff->screen, - &hFrameBuffer, - (int*)&rep.framebufferOrigin, - (int*)&rep.framebufferSize, - (int*)&rep.framebufferStride, - (int*)&rep.devPrivateSize, - &pDevPrivate)) { - return BadValue; - } - - rep.hFrameBufferLow = (CARD32)(hFrameBuffer & 0xffffffff); -#if defined(LONG64) && !defined(__linux__) - rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32); -#else - rep.hFrameBufferHigh = 0; -#endif - - rep.length = 0; - if (rep.devPrivateSize) { - rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetDeviceInfoReply) - - SIZEOF(xGenericReply) + - pad_to_int32(rep.devPrivateSize)); - } - - WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep); - if (rep.length) { - WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate); - } - EPHYR_LOG ("leave\n") ; - return (client->noClientException); -} - -static int -ProcXF86DRIDispatch (register ClientPtr client) -{ - REQUEST(xReq); - EPHYR_LOG ("enter\n") ; - - switch (stuff->data) - { - case X_XF86DRIQueryVersion: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIQueryVersion(client); - } - case X_XF86DRIQueryDirectRenderingCapable: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIQueryDirectRenderingCapable(client); - } - } - - if (!LocalClient(client)) - return DRIErrorBase + XF86DRIClientNotLocal; - - switch (stuff->data) - { - case X_XF86DRIOpenConnection: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIOpenConnection(client); - } - case X_XF86DRICloseConnection: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRICloseConnection(client); - } - case X_XF86DRIGetClientDriverName: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIGetClientDriverName(client); - } - case X_XF86DRICreateContext: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRICreateContext(client); - } - case X_XF86DRIDestroyContext: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIDestroyContext(client); - } - case X_XF86DRICreateDrawable: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRICreateDrawable(client); - } - case X_XF86DRIDestroyDrawable: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIDestroyDrawable(client); - } - case X_XF86DRIGetDrawableInfo: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIGetDrawableInfo(client); - } - case X_XF86DRIGetDeviceInfo: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIGetDeviceInfo(client); - } - case X_XF86DRIAuthConnection: { - EPHYR_LOG ("leave\n") ; - return ProcXF86DRIAuthConnection(client); - } - /* {Open,Close}FullScreen are deprecated now */ - default: { - EPHYR_LOG ("leave\n") ; - return BadRequest; - } - } -} - -static int -SProcXF86DRIQueryVersion (register ClientPtr client) -{ - register int n; - REQUEST(xXF86DRIQueryVersionReq); - swaps(&stuff->length, n); - return ProcXF86DRIQueryVersion(client); -} - -static int -SProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) -{ - register int n; - REQUEST(xXF86DRIQueryDirectRenderingCapableReq); - swaps(&stuff->length, n); - swapl(&stuff->screen, n); - return ProcXF86DRIQueryDirectRenderingCapable(client); -} - -static int -SProcXF86DRIDispatch (register ClientPtr client) -{ - REQUEST(xReq); - - EPHYR_LOG ("enter\n") ; - /* - * Only local clients are allowed DRI access, but remote clients still need - * these requests to find out cleanly. - */ - switch (stuff->data) - { - case X_XF86DRIQueryVersion: { - EPHYR_LOG ("leave\n") ; - return SProcXF86DRIQueryVersion(client); - } - case X_XF86DRIQueryDirectRenderingCapable: { - EPHYR_LOG ("leave\n") ; - return SProcXF86DRIQueryDirectRenderingCapable(client); - } - default: { - EPHYR_LOG ("leave\n") ; - return DRIErrorBase + XF86DRIClientNotLocal; - } - } -} +/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum + * + * Copyright © 2007 OpenedHand Ltd + * + * 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 OpenedHand Ltd not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. OpenedHand Ltd makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OpenedHand Ltd 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. + * + * This file is heavily copied from hw/xfree86/dri/xf86dri.c + * + * Authors: + * Dodji Seketeli + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#define _XF86DRI_SERVER_ +#include +#include +#include "misc.h" +#include "privates.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "colormapst.h" +#include "cursorstr.h" +#include "scrnintstr.h" +#include "windowstr.h" +#include "servermd.h" +#include "swaprep.h" +#include "ephyrdri.h" +#include "ephyrdriext.h" +#include "hostx.h" +#define _HAVE_XALLOC_DECLS +#include "ephyrlog.h" +#include "protocol-versions.h" + +typedef struct { + int foo; +} EphyrDRIWindowPrivRec; +typedef EphyrDRIWindowPrivRec* EphyrDRIWindowPrivPtr; + +typedef struct { + CreateWindowProcPtr CreateWindow ; + DestroyWindowProcPtr DestroyWindow ; + MoveWindowProcPtr MoveWindow ; + PositionWindowProcPtr PositionWindow ; + ClipNotifyProcPtr ClipNotify ; +} EphyrDRIScreenPrivRec; +typedef EphyrDRIScreenPrivRec* EphyrDRIScreenPrivPtr; + +static int DRIErrorBase; + +static DISPATCH_PROC(ProcXF86DRIQueryVersion); +static DISPATCH_PROC(ProcXF86DRIQueryDirectRenderingCapable); +static DISPATCH_PROC(ProcXF86DRIOpenConnection); +static DISPATCH_PROC(ProcXF86DRICloseConnection); +static DISPATCH_PROC(ProcXF86DRIGetClientDriverName); +static DISPATCH_PROC(ProcXF86DRICreateContext); +static DISPATCH_PROC(ProcXF86DRIDestroyContext); +static DISPATCH_PROC(ProcXF86DRICreateDrawable); +static DISPATCH_PROC(ProcXF86DRIDestroyDrawable); +static DISPATCH_PROC(ProcXF86DRIGetDrawableInfo); +static DISPATCH_PROC(ProcXF86DRIGetDeviceInfo); +static DISPATCH_PROC(ProcXF86DRIDispatch); +static DISPATCH_PROC(ProcXF86DRIAuthConnection); + +static DISPATCH_PROC(SProcXF86DRIQueryVersion); +static DISPATCH_PROC(SProcXF86DRIQueryDirectRenderingCapable); +static DISPATCH_PROC(SProcXF86DRIDispatch); + +static Bool ephyrDRIScreenInit (ScreenPtr a_screen) ; +static Bool ephyrDRICreateWindow (WindowPtr a_win) ; +static Bool ephyrDRIDestroyWindow (WindowPtr a_win) ; +static void ephyrDRIMoveWindow (WindowPtr a_win, + int a_x, int a_y, + WindowPtr a_siblings, + VTKind a_kind); +static Bool ephyrDRIPositionWindow (WindowPtr a_win, + int x, int y) ; +static void ephyrDRIClipNotify (WindowPtr a_win, + int a_x, int a_y) ; + +static Bool EphyrMirrorHostVisuals (ScreenPtr a_screen) ; +static Bool destroyHostPeerWindow (const WindowPtr a_win) ; +static Bool findWindowPairFromLocal (WindowPtr a_local, + EphyrWindowPair **a_pair); + +static unsigned char DRIReqCode = 0; + +static int ephyrDRIWindowKeyIndex; +static DevPrivateKey ephyrDRIWindowKey = &ephyrDRIWindowKeyIndex; +static int ephyrDRIScreenKeyIndex; +static DevPrivateKey ephyrDRIScreenKey = &ephyrDRIScreenKeyIndex; + +#define GET_EPHYR_DRI_WINDOW_PRIV(win) ((EphyrDRIWindowPrivPtr) \ + dixLookupPrivate(&(win)->devPrivates, ephyrDRIWindowKey)) +#define GET_EPHYR_DRI_SCREEN_PRIV(screen) ((EphyrDRIScreenPrivPtr) \ + dixLookupPrivate(&(screen)->devPrivates, ephyrDRIScreenKey)) + + +Bool +ephyrDRIExtensionInit (ScreenPtr a_screen) +{ + Bool is_ok=FALSE ; + ExtensionEntry* extEntry=NULL; + EphyrDRIScreenPrivPtr screen_priv=NULL ; + + EPHYR_LOG ("enter\n") ; + if (!hostx_has_dri ()) { + EPHYR_LOG ("host does not have DRI extension\n") ; + goto out ; + } + EPHYR_LOG ("host X does have DRI extension\n") ; + if (!hostx_has_xshape ()) { + EPHYR_LOG ("host does not have XShape extension\n") ; + goto out ; + } + EPHYR_LOG ("host X does have XShape extension\n") ; + +#ifdef XF86DRI_EVENTS + EventType = CreateNewResourceType (XF86DRIFreeEvents, "DRIEvents"); + if (!EventType) { + EPHYR_LOG_ERROR ("failed to register DRI event resource type\n") ; + goto out ; + } +#endif + + if ((extEntry = AddExtension(XF86DRINAME, + XF86DRINumberEvents, + XF86DRINumberErrors, + ProcXF86DRIDispatch, + SProcXF86DRIDispatch, + NULL, + StandardMinorOpcode))) { + DRIReqCode = (unsigned char)extEntry->base; + DRIErrorBase = extEntry->errorBase; + } else { + EPHYR_LOG_ERROR ("failed to register DRI extension\n") ; + goto out ; + } + screen_priv = calloc(1, sizeof (EphyrDRIScreenPrivRec)) ; + if (!screen_priv) { + EPHYR_LOG_ERROR ("failed to allocate screen_priv\n") ; + goto out ; + } + dixSetPrivate(&a_screen->devPrivates, ephyrDRIScreenKey, screen_priv); + + if (!ephyrDRIScreenInit (a_screen)) { + EPHYR_LOG_ERROR ("ephyrDRIScreenInit() failed\n") ; + goto out ; + } + EphyrMirrorHostVisuals (a_screen) ; + is_ok=TRUE ; +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +static Bool +ephyrDRIScreenInit (ScreenPtr a_screen) +{ + Bool is_ok=FALSE ; + EphyrDRIScreenPrivPtr screen_priv=NULL ; + + EPHYR_RETURN_VAL_IF_FAIL (a_screen, FALSE) ; + + screen_priv=GET_EPHYR_DRI_SCREEN_PRIV (a_screen) ; + EPHYR_RETURN_VAL_IF_FAIL (screen_priv, FALSE) ; + + screen_priv->CreateWindow = a_screen->CreateWindow ; + screen_priv->DestroyWindow = a_screen->DestroyWindow ; + screen_priv->MoveWindow = a_screen->MoveWindow ; + screen_priv->PositionWindow = a_screen->PositionWindow ; + screen_priv->ClipNotify = a_screen->ClipNotify ; + + a_screen->CreateWindow = ephyrDRICreateWindow ; + a_screen->DestroyWindow = ephyrDRIDestroyWindow ; + a_screen->MoveWindow = ephyrDRIMoveWindow ; + a_screen->PositionWindow = ephyrDRIPositionWindow ; + a_screen->ClipNotify = ephyrDRIClipNotify ; + + is_ok = TRUE ; + + return is_ok ; +} + +static Bool +ephyrDRICreateWindow (WindowPtr a_win) +{ + Bool is_ok=FALSE ; + ScreenPtr screen=NULL ; + EphyrDRIScreenPrivPtr screen_priv =NULL; + + EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; + screen = a_win->drawable.pScreen ; + EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; + screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; + EPHYR_RETURN_VAL_IF_FAIL (screen_priv + && screen_priv->CreateWindow, + FALSE) ; + + EPHYR_LOG ("enter. win:%p\n", a_win) ; + + screen->CreateWindow = screen_priv->CreateWindow ; + is_ok = (*screen->CreateWindow) (a_win) ; + screen->CreateWindow = ephyrDRICreateWindow ; + + if (is_ok) { + dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL); + } + return is_ok ; +} + +static Bool +ephyrDRIDestroyWindow (WindowPtr a_win) +{ + Bool is_ok=FALSE ; + ScreenPtr screen=NULL ; + EphyrDRIScreenPrivPtr screen_priv =NULL; + + EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; + screen = a_win->drawable.pScreen ; + EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; + screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; + EPHYR_RETURN_VAL_IF_FAIL (screen_priv + && screen_priv->DestroyWindow, + FALSE) ; + + screen->DestroyWindow = screen_priv->DestroyWindow ; + if (screen->DestroyWindow) { + is_ok = (*screen->DestroyWindow) (a_win) ; + } + screen->DestroyWindow = ephyrDRIDestroyWindow ; + + if (is_ok) { + EphyrDRIWindowPrivPtr win_priv=GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; + if (win_priv) { + destroyHostPeerWindow (a_win) ; + free(win_priv) ; + dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL); + EPHYR_LOG ("destroyed the remote peer window\n") ; + } + } + return is_ok ; +} + +static void +ephyrDRIMoveWindow (WindowPtr a_win, + int a_x, int a_y, + WindowPtr a_siblings, + VTKind a_kind) +{ + Bool is_ok=FALSE ; + ScreenPtr screen=NULL ; + EphyrDRIScreenPrivPtr screen_priv =NULL; + EphyrDRIWindowPrivPtr win_priv=NULL ; + EphyrWindowPair *pair=NULL ; + EphyrBox geo; + int x=0,y=0;/*coords relative to parent window*/ + + EPHYR_RETURN_IF_FAIL (a_win) ; + + EPHYR_LOG ("enter\n") ; + screen = a_win->drawable.pScreen ; + EPHYR_RETURN_IF_FAIL (screen) ; + screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; + EPHYR_RETURN_IF_FAIL (screen_priv + && screen_priv->MoveWindow) ; + + screen->MoveWindow = screen_priv->MoveWindow ; + if (screen->MoveWindow) { + (*screen->MoveWindow) (a_win, a_x, a_y, a_siblings, a_kind) ; + } + screen->MoveWindow = ephyrDRIMoveWindow ; + + EPHYR_LOG ("window: %p\n", a_win) ; + if (!a_win->parent) { + EPHYR_LOG ("cannot move root window\n") ; + is_ok = TRUE ; + goto out ; + } + win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; + if (!win_priv) { + EPHYR_LOG ("not a DRI peered window\n") ; + is_ok = TRUE ; + goto out ; + } + if (!findWindowPairFromLocal (a_win, &pair) || !pair) { + EPHYR_LOG_ERROR ("failed to get window pair\n") ; + goto out ; + } + /*compute position relative to parent window*/ + x = a_win->drawable.x - a_win->parent->drawable.x ; + y = a_win->drawable.y - a_win->parent->drawable.y ; + /*set the geometry to pass to hostx_set_window_geometry*/ + memset (&geo, 0, sizeof (geo)) ; + geo.x = x ; + geo.y = y ; + geo.width = a_win->drawable.width ; + geo.height = a_win->drawable.height ; + hostx_set_window_geometry (pair->remote, &geo) ; + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; + /*do cleanup here*/ +} + +static Bool +ephyrDRIPositionWindow (WindowPtr a_win, + int a_x, int a_y) +{ + Bool is_ok=FALSE ; + ScreenPtr screen=NULL ; + EphyrDRIScreenPrivPtr screen_priv =NULL; + EphyrDRIWindowPrivPtr win_priv=NULL ; + EphyrWindowPair *pair=NULL ; + EphyrBox geo; + + EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; + + EPHYR_LOG ("enter\n") ; + screen = a_win->drawable.pScreen ; + EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; + screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; + EPHYR_RETURN_VAL_IF_FAIL (screen_priv + && screen_priv->PositionWindow, + FALSE) ; + + screen->PositionWindow = screen_priv->PositionWindow ; + if (screen->PositionWindow) { + (*screen->PositionWindow) (a_win, a_x, a_y) ; + } + screen->PositionWindow = ephyrDRIPositionWindow ; + + EPHYR_LOG ("window: %p\n", a_win) ; + win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; + if (!win_priv) { + EPHYR_LOG ("not a DRI peered window\n") ; + is_ok = TRUE ; + goto out ; + } + if (!findWindowPairFromLocal (a_win, &pair) || !pair) { + EPHYR_LOG_ERROR ("failed to get window pair\n") ; + goto out ; + } + /*set the geometry to pass to hostx_set_window_geometry*/ + memset (&geo, 0, sizeof (geo)) ; + geo.x = a_x ; + geo.y = a_y ; + geo.width = a_win->drawable.width ; + geo.height = a_win->drawable.height ; + hostx_set_window_geometry (pair->remote, &geo) ; + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; + /*do cleanup here*/ + return is_ok ; +} + +static void +ephyrDRIClipNotify (WindowPtr a_win, + int a_x, int a_y) +{ + Bool is_ok=FALSE ; + ScreenPtr screen=NULL ; + EphyrDRIScreenPrivPtr screen_priv =NULL; + EphyrDRIWindowPrivPtr win_priv=NULL ; + EphyrWindowPair *pair=NULL ; + EphyrRect *rects=NULL; + int i=0 ; + + EPHYR_RETURN_IF_FAIL (a_win) ; + + EPHYR_LOG ("enter\n") ; + screen = a_win->drawable.pScreen ; + EPHYR_RETURN_IF_FAIL (screen) ; + screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; + EPHYR_RETURN_IF_FAIL (screen_priv && screen_priv->ClipNotify) ; + + screen->ClipNotify = screen_priv->ClipNotify ; + if (screen->ClipNotify) { + (*screen->ClipNotify) (a_win, a_x, a_y) ; + } + screen->ClipNotify = ephyrDRIClipNotify ; + + EPHYR_LOG ("window: %p\n", a_win) ; + win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; + if (!win_priv) { + EPHYR_LOG ("not a DRI peered window\n") ; + is_ok = TRUE ; + goto out ; + } + if (!findWindowPairFromLocal (a_win, &pair) || !pair) { + EPHYR_LOG_ERROR ("failed to get window pair\n") ; + goto out ; + } + rects = calloc(REGION_NUM_RECTS (&a_win->clipList), + sizeof (EphyrRect)) ; + for (i=0; i < REGION_NUM_RECTS (&a_win->clipList); i++) { + memmove (&rects[i], + ®ION_RECTS (&a_win->clipList)[i], + sizeof (EphyrRect)) ; + rects[i].x1 -= a_win->drawable.x; + rects[i].x2 -= a_win->drawable.x; + rects[i].y1 -= a_win->drawable.y; + rects[i].y2 -= a_win->drawable.y; + } + /* + * push the clipping region of this window + * to the peer window in the host + */ + is_ok = hostx_set_window_bounding_rectangles + (pair->remote, + rects, + REGION_NUM_RECTS (&a_win->clipList)) ; + is_ok = TRUE ; + +out: + free(rects) ; + rects = NULL ; + + EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; + /*do cleanup here*/ +} + +/** + * Duplicates a visual of a_screen + * In screen a_screen, for depth a_depth, find a visual which + * bitsPerRGBValue and colormap size equal + * a_bits_per_rgb_values and a_colormap_entries. + * The ID of that duplicated visual is set to a_new_id. + * That duplicated visual is then added to the list of visuals + * of the screen. + */ +static Bool +EphyrDuplicateVisual (unsigned int a_screen, + short a_depth, + short a_class, + short a_bits_per_rgb_values, + short a_colormap_entries, + unsigned int a_red_mask, + unsigned int a_green_mask, + unsigned int a_blue_mask, + unsigned int a_new_id) +{ + Bool is_ok = FALSE, found_visual=FALSE, found_depth=FALSE ; + ScreenPtr screen=NULL ; + VisualRec new_visual, *new_visuals=NULL ; + int i=0 ; + + EPHYR_LOG ("enter\n") ; + if (a_screen > screenInfo.numScreens) { + EPHYR_LOG_ERROR ("bad screen number\n") ; + goto out; + } + memset (&new_visual, 0, sizeof (VisualRec)) ; + + /*get the screen pointed to by a_screen*/ + screen = screenInfo.screens[a_screen] ; + EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; + + /* + * In that screen, first look for an existing visual that has the + * same characteristics as those passed in parameter + * to this function and copy it. + */ + for (i=0; i < screen->numVisuals; i++) { + if (screen->visuals[i].bitsPerRGBValue == a_bits_per_rgb_values && + screen->visuals[i].ColormapEntries == a_colormap_entries ) { + /*copy the visual found*/ + memcpy (&new_visual, &screen->visuals[i], sizeof (new_visual)) ; + new_visual.vid = a_new_id ; + new_visual.class = a_class ; + new_visual.redMask = a_red_mask ; + new_visual.greenMask = a_green_mask ; + new_visual.blueMask = a_blue_mask ; + found_visual = TRUE ; + EPHYR_LOG ("found a visual that matches visual id: %d\n", + a_new_id) ; + break; + } + } + if (!found_visual) { + EPHYR_LOG ("did not find any visual matching %d\n", a_new_id) ; + goto out ; + } + /* + * be prepare to extend screen->visuals to add new_visual to it + */ + new_visuals = calloc(screen->numVisuals+1, sizeof (VisualRec)) ; + memmove (new_visuals, + screen->visuals, + screen->numVisuals*sizeof (VisualRec)) ; + memmove (&new_visuals[screen->numVisuals], + &new_visual, + sizeof (VisualRec)) ; + /* + * Now, in that same screen, update the screen->allowedDepths member. + * In that array, each element represents the visuals applicable to + * a given depth. So we need to add an entry matching the new visual + * that we are going to add to screen->visuals + */ + for (i=0; inumDepths; i++) { + VisualID *vids=NULL; + DepthPtr cur_depth=NULL ; + /*find the entry matching a_depth*/ + if (screen->allowedDepths[i].depth != a_depth) + continue ; + cur_depth = &screen->allowedDepths[i]; + /* + * extend the list of visual IDs in that entry, + * so to add a_new_id in there. + */ + vids = realloc(cur_depth->vids, + (cur_depth->numVids+1)*sizeof (VisualID)); + if (!vids) { + EPHYR_LOG_ERROR ("failed to realloc numids\n") ; + goto out ; + } + vids[cur_depth->numVids] = a_new_id ; + /* + * Okay now commit our change. + * Do really update screen->allowedDepths[i] + */ + cur_depth->numVids++ ; + cur_depth->vids = vids ; + found_depth=TRUE; + } + if (!found_depth) { + EPHYR_LOG_ERROR ("failed to update screen[%d]->allowedDepth\n", + a_screen) ; + goto out ; + } + /* + * Commit our change to screen->visuals + */ + free(screen->visuals) ; + screen->visuals = new_visuals ; + screen->numVisuals++ ; + new_visuals = NULL ; + + is_ok = TRUE ; +out: + free(new_visuals) ; + new_visuals = NULL ; + + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +/** + * Duplicates the visuals of the host X server. + * This is necessary to have visuals that have the same + * ID as those of the host X. It is important to have that for + * GLX. + */ +static Bool +EphyrMirrorHostVisuals (ScreenPtr a_screen) +{ + Bool is_ok=FALSE; + EphyrHostVisualInfo *visuals=NULL; + int nb_visuals=0, i=0; + + EPHYR_LOG ("enter\n") ; + if (!hostx_get_visuals_info (&visuals, &nb_visuals)) { + EPHYR_LOG_ERROR ("failed to get host visuals\n") ; + goto out ; + } + for (i=0; imyNum, + visuals[i].depth, + visuals[i].class, + visuals[i].bits_per_rgb, + visuals[i].colormap_size, + visuals[i].red_mask, + visuals[i].green_mask, + visuals[i].blue_mask, + visuals[i].visualid)) { + EPHYR_LOG_ERROR ("failed to duplicate host visual %d\n", + (int)visuals[i].visualid) ; + } + } + + is_ok = TRUE ; +out: + EPHYR_LOG ("leave\n") ; + return is_ok; +} + + +static int +ProcXF86DRIQueryVersion (register ClientPtr client) +{ + xXF86DRIQueryVersionReply rep; + register int n; + REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq); + + EPHYR_LOG ("enter\n") ; + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.majorVersion = SERVER_XF86DRI_MAJOR_VERSION; + rep.minorVersion = SERVER_XF86DRI_MINOR_VERSION; + rep.patchVersion = SERVER_XF86DRI_PATCH_VERSION; + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + swaps(&rep.majorVersion, n); + swaps(&rep.minorVersion, n); + swapl(&rep.patchVersion, n); + } + WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) +{ + xXF86DRIQueryDirectRenderingCapableReply rep; + Bool isCapable; + register int n; + REQUEST(xXF86DRIQueryDirectRenderingCapableReq); + REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!ephyrDRIQueryDirectRenderingCapable (stuff->screen, &isCapable)) { + return BadValue; + } + rep.isCapable = isCapable; + + if (!LocalClient(client) || client->swapped) + rep.isCapable = 0; + + if (client->swapped) { + swaps(&rep.sequenceNumber, n); + swapl(&rep.length, n); + } + + WriteToClient(client, sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep); + EPHYR_LOG ("leave\n") ; + + return Success; +} + +static int +ProcXF86DRIOpenConnection (register ClientPtr client) +{ + xXF86DRIOpenConnectionReply rep; + drm_handle_t hSAREA; + char* busIdString; + REQUEST(xXF86DRIOpenConnectionReq); + REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + if (!ephyrDRIOpenConnection(stuff->screen, + &hSAREA, + &busIdString)) { + return BadValue; + } + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.busIdStringLength = 0; + if (busIdString) + rep.busIdStringLength = strlen(busIdString); + rep.length = bytes_to_int32(SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) + + pad_to_int32(rep.busIdStringLength)); + + rep.hSAREALow = (CARD32)(hSAREA & 0xffffffff); +#if defined(LONG64) && !defined(__linux__) + rep.hSAREAHigh = (CARD32)(hSAREA >> 32); +#else + rep.hSAREAHigh = 0; +#endif + + WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep); + if (rep.busIdStringLength) + WriteToClient(client, rep.busIdStringLength, busIdString); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIAuthConnection (register ClientPtr client) +{ + xXF86DRIAuthConnectionReply rep; + REQUEST(xXF86DRIAuthConnectionReq); + REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + rep.authenticated = 1; + + if (!ephyrDRIAuthConnection (stuff->screen, stuff->magic)) { + ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic); + rep.authenticated = 0; + } + WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRICloseConnection (register ClientPtr client) +{ + REQUEST(xXF86DRICloseConnectionReq); + REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq); + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + /* + DRICloseConnection( screenInfo.screens[stuff->screen]); + */ + + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIGetClientDriverName (register ClientPtr client) +{ + xXF86DRIGetClientDriverNameReply rep; + char* clientDriverName; + REQUEST(xXF86DRIGetClientDriverNameReq); + REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + ephyrDRIGetClientDriverName (stuff->screen, + (int *)&rep.ddxDriverMajorVersion, + (int *)&rep.ddxDriverMinorVersion, + (int *)&rep.ddxDriverPatchVersion, + &clientDriverName); + + rep.type = X_Reply; + rep.sequenceNumber = client->sequence; + rep.clientDriverNameLength = 0; + if (clientDriverName) + rep.clientDriverNameLength = strlen(clientDriverName); + rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetClientDriverNameReply) - + SIZEOF(xGenericReply) + + pad_to_int32(rep.clientDriverNameLength)); + + WriteToClient(client, + sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep); + if (rep.clientDriverNameLength) + WriteToClient(client, + rep.clientDriverNameLength, + clientDriverName); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRICreateContext (register ClientPtr client) +{ + xXF86DRICreateContextReply rep; + ScreenPtr pScreen; + VisualPtr visual; + int i=0; + unsigned long context_id=0; + REQUEST(xXF86DRICreateContextReq); + REQUEST_SIZE_MATCH(xXF86DRICreateContextReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + pScreen = screenInfo.screens[stuff->screen]; + visual = pScreen->visuals; + + /* Find the requested X visual */ + for (i = 0; i < pScreen->numVisuals; i++, visual++) + if (visual->vid == stuff->visual) + break; + if (i == pScreen->numVisuals) { + /* No visual found */ + return BadValue; + } + + context_id = stuff->context ; + if (!ephyrDRICreateContext (stuff->screen, + stuff->visual, + &context_id, + (drm_context_t *)&rep.hHWContext)) { + return BadValue; + } + + WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIDestroyContext (register ClientPtr client) +{ + REQUEST(xXF86DRIDestroyContextReq); + REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq); + EPHYR_LOG ("enter\n") ; + + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + if (!ephyrDRIDestroyContext (stuff->screen, stuff->context)) { + return BadValue; + } + + EPHYR_LOG ("leave\n") ; + return Success; +} + +static Bool +getWindowVisual (const WindowPtr a_win, + VisualPtr *a_visual) +{ + int i=0, visual_id=0 ; + EPHYR_RETURN_VAL_IF_FAIL (a_win + && a_win->drawable.pScreen + && a_win->drawable.pScreen->visuals, + FALSE) ; + + visual_id = wVisual (a_win) ; + for (i=0; i < a_win->drawable.pScreen->numVisuals; i++) { + if (a_win->drawable.pScreen->visuals[i].vid == visual_id) { + *a_visual = &a_win->drawable.pScreen->visuals[i] ; + return TRUE ; + } + } + return FALSE ; +} + + +#define NUM_WINDOW_PAIRS 256 +static EphyrWindowPair window_pairs[NUM_WINDOW_PAIRS] ; + +static Bool +appendWindowPairToList (WindowPtr a_local, + int a_remote) +{ + int i=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_local, FALSE) ; + + EPHYR_LOG ("(local,remote):(%p, %d)\n", a_local, a_remote) ; + + for (i=0; i < NUM_WINDOW_PAIRS; i++) { + if (window_pairs[i].local == NULL) { + window_pairs[i].local = a_local ; + window_pairs[i].remote = a_remote ; + return TRUE ; + } + } + return FALSE ; +} + +static Bool +findWindowPairFromLocal (WindowPtr a_local, + EphyrWindowPair **a_pair) +{ + int i=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_pair && a_local, FALSE) ; + + for (i=0; i < NUM_WINDOW_PAIRS; i++) { + if (window_pairs[i].local == a_local) { + *a_pair = &window_pairs[i] ; + EPHYR_LOG ("found (%p, %d)\n", + (*a_pair)->local, + (*a_pair)->remote) ; + return TRUE ; + } + } + return FALSE ; +} + +Bool +findWindowPairFromRemote (int a_remote, + EphyrWindowPair **a_pair) +{ + int i=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_pair, FALSE) ; + + for (i=0; i < NUM_WINDOW_PAIRS; i++) { + if (window_pairs[i].remote == a_remote) { + *a_pair = &window_pairs[i] ; + EPHYR_LOG ("found (%p, %d)\n", + (*a_pair)->local, + (*a_pair)->remote) ; + return TRUE ; + } + } + return FALSE ; +} + +static Bool +createHostPeerWindow (const WindowPtr a_win, + int *a_peer_win) +{ + Bool is_ok=FALSE ; + VisualPtr visual=NULL; + EphyrBox geo ; + + EPHYR_RETURN_VAL_IF_FAIL (a_win && a_peer_win, FALSE) ; + EPHYR_RETURN_VAL_IF_FAIL (a_win->drawable.pScreen, + FALSE) ; + + EPHYR_LOG ("enter. a_win '%p'\n", a_win) ; + if (!getWindowVisual (a_win, &visual)) { + EPHYR_LOG_ERROR ("failed to get window visual\n") ; + goto out ; + } + if (!visual) { + EPHYR_LOG_ERROR ("failed to create visual\n") ; + goto out ; + } + memset (&geo, 0, sizeof (geo)) ; + geo.x = a_win->drawable.x ; + geo.y = a_win->drawable.y ; + geo.width = a_win->drawable.width ; + geo.height = a_win->drawable.height ; + if (!hostx_create_window (a_win->drawable.pScreen->myNum, + &geo, visual->vid, a_peer_win)) { + EPHYR_LOG_ERROR ("failed to create host peer window\n") ; + goto out ; + } + if (!appendWindowPairToList (a_win, *a_peer_win)) { + EPHYR_LOG_ERROR ("failed to append window to pair list\n") ; + goto out ; + } + is_ok = TRUE ; +out: + EPHYR_LOG ("leave:remote win%d\n", *a_peer_win) ; + return is_ok ; +} + +static Bool +destroyHostPeerWindow (const WindowPtr a_win) +{ + Bool is_ok = FALSE ; + EphyrWindowPair *pair=NULL ; + EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + if (!findWindowPairFromLocal (a_win, &pair) || !pair) { + EPHYR_LOG_ERROR ("failed to find peer to local window\n") ; + goto out; + } + hostx_destroy_window (pair->remote) ; + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave\n") ; + return is_ok; +} + +static int +ProcXF86DRICreateDrawable (ClientPtr client) +{ + xXF86DRICreateDrawableReply rep; + DrawablePtr drawable=NULL; + WindowPtr window=NULL ; + EphyrWindowPair *pair=NULL ; + EphyrDRIWindowPrivPtr win_priv=NULL; + int rc=0, remote_win=0; + REQUEST(xXF86DRICreateDrawableReq); + REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = dixLookupDrawable (&drawable, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success) + return rc; + if (drawable->type != DRAWABLE_WINDOW) { + EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ; + return BadImplementation ; + } + EPHYR_LOG ("lookedup drawable %p\n", drawable) ; + window = (WindowPtr)drawable; + if (findWindowPairFromLocal (window, &pair) && pair) { + remote_win = pair->remote ; + EPHYR_LOG ("found window '%p' paire with remote '%d'\n", + window, remote_win) ; + } else if (!createHostPeerWindow (window, &remote_win)) { + EPHYR_LOG_ERROR ("failed to create host peer window\n") ; + return BadAlloc ; + } + + if (!ephyrDRICreateDrawable (stuff->screen, + remote_win, + (drm_drawable_t *)&rep.hHWDrawable)) { + EPHYR_LOG_ERROR ("failed to create dri drawable\n") ; + return BadValue; + } + + win_priv = GET_EPHYR_DRI_WINDOW_PRIV (window) ; + if (!win_priv) { + win_priv = calloc(1, sizeof (EphyrDRIWindowPrivRec)) ; + if (!win_priv) { + EPHYR_LOG_ERROR ("failed to allocate window private\n") ; + return BadAlloc ; + } + dixSetPrivate(&window->devPrivates, ephyrDRIWindowKey, win_priv); + EPHYR_LOG ("paired window '%p' with remote '%d'\n", + window, remote_win) ; + } + + WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep); + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIDestroyDrawable (register ClientPtr client) +{ + DrawablePtr drawable=NULL; + WindowPtr window=NULL; + EphyrWindowPair *pair=NULL; + int rc=0; + REQUEST(xXF86DRIDestroyDrawableReq); + REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rc = dixLookupDrawable(&drawable, + stuff->drawable, + client, + 0, + DixReadAccess); + if (rc != Success) + return rc; + if (drawable->type != DRAWABLE_WINDOW) { + EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ; + return BadImplementation ; + } + window = (WindowPtr)drawable; + if (!findWindowPairFromLocal (window, &pair) && pair) { + EPHYR_LOG_ERROR ("failed to find pair window\n") ; + return BadImplementation; + } + if (!ephyrDRIDestroyDrawable(stuff->screen, + pair->remote/*drawable in host x*/)) { + EPHYR_LOG_ERROR ("failed to destroy dri drawable\n") ; + return BadImplementation; + } + pair->local=NULL ; + pair->remote=0; + + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIGetDrawableInfo (register ClientPtr client) +{ + xXF86DRIGetDrawableInfoReply rep; + DrawablePtr drawable; + WindowPtr window=NULL; + EphyrWindowPair *pair=NULL; + int X=0, Y=0, W=0, H=0, backX=0, backY=0, rc=0, i=0; + drm_clip_rect_t *clipRects=NULL; + drm_clip_rect_t *backClipRects=NULL; + REQUEST(xXF86DRIGetDrawableInfoReq); + REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq); + + EPHYR_LOG ("enter\n") ; + memset (&rep, 0, sizeof (rep)) ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0, + DixReadAccess); + if (rc != Success || !drawable) { + EPHYR_LOG_ERROR ("could not get drawable\n") ; + return rc; + } + + if (drawable->type != DRAWABLE_WINDOW) { + EPHYR_LOG_ERROR ("non windows type drawables are not yes supported\n") ; + return BadImplementation ; + } + window = (WindowPtr)drawable ; + memset (&pair, 0, sizeof (pair)) ; + if (!findWindowPairFromLocal (window, &pair) || !pair) { + EPHYR_LOG_ERROR ("failed to find remote peer drawable\n") ; + return BadMatch ; + } + EPHYR_LOG ("clip list of xephyr gl drawable:\n") ; + for (i=0; i < REGION_NUM_RECTS (&window->clipList); i++) { + EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n", + REGION_RECTS (&window->clipList)[i].x1, + REGION_RECTS (&window->clipList)[i].y1, + REGION_RECTS (&window->clipList)[i].x2, + REGION_RECTS (&window->clipList)[i].y2) ; + } + + if (!ephyrDRIGetDrawableInfo (stuff->screen, + pair->remote/*the drawable in hostx*/, + (unsigned int*)&rep.drawableTableIndex, + (unsigned int*)&rep.drawableTableStamp, + (int*)&X, + (int*)&Y, + (int*)&W, + (int*)&H, + (int*)&rep.numClipRects, + &clipRects, + &backX, + &backY, + (int*)&rep.numBackClipRects, + &backClipRects)) { + return BadValue; + } + EPHYR_LOG ("num clip rects:%d, num back clip rects:%d\n", + (int)rep.numClipRects, (int)rep.numBackClipRects) ; + + rep.drawableX = X; + rep.drawableY = Y; + rep.drawableWidth = W; + rep.drawableHeight = H; + rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) - + SIZEOF(xGenericReply)); + + rep.backX = backX; + rep.backY = backY; + + + if (rep.numClipRects) { + if (clipRects) { + ScreenPtr pScreen = screenInfo.screens[stuff->screen]; + int i=0; + EPHYR_LOG ("clip list of host gl drawable:\n") ; + for (i = 0; i < rep.numClipRects; i++) { + clipRects[i].x1 = max (clipRects[i].x1, 0); + clipRects[i].y1 = max (clipRects[i].y1, 0); + clipRects[i].x2 = min (clipRects[i].x2, + pScreen->width + clipRects[i].x1) ; + clipRects[i].y2 = min (clipRects[i].y2, + pScreen->width + clipRects[i].y1) ; + + EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n", + clipRects[i].x1, clipRects[i].y1, + clipRects[i].x2, clipRects[i].y2) ; + } + } else { + rep.numClipRects = 0; + } + } else { + EPHYR_LOG ("got zero host gl drawable clipping rects\n") ; + } + rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects; + backClipRects = clipRects ; + rep.numBackClipRects = rep.numClipRects ; + if (rep.numBackClipRects) + rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects; + EPHYR_LOG ("num host clip rects:%d\n", (int)rep.numClipRects) ; + EPHYR_LOG ("num host back clip rects:%d\n", (int)rep.numBackClipRects) ; + + rep.length = bytes_to_int32(rep.length); + + WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep); + + if (rep.numClipRects) { + WriteToClient(client, + sizeof(drm_clip_rect_t) * rep.numClipRects, + (char *)clipRects); + } + + if (rep.numBackClipRects) { + WriteToClient(client, + sizeof(drm_clip_rect_t) * rep.numBackClipRects, + (char *)backClipRects); + } + free(clipRects); + clipRects = NULL ; + + EPHYR_LOG ("leave\n") ; + + return Success; +} + +static int +ProcXF86DRIGetDeviceInfo (register ClientPtr client) +{ + xXF86DRIGetDeviceInfoReply rep; + drm_handle_t hFrameBuffer; + void *pDevPrivate; + REQUEST(xXF86DRIGetDeviceInfoReq); + REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq); + + EPHYR_LOG ("enter\n") ; + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + rep.type = X_Reply; + rep.length = 0; + rep.sequenceNumber = client->sequence; + + if (!ephyrDRIGetDeviceInfo (stuff->screen, + &hFrameBuffer, + (int*)&rep.framebufferOrigin, + (int*)&rep.framebufferSize, + (int*)&rep.framebufferStride, + (int*)&rep.devPrivateSize, + &pDevPrivate)) { + return BadValue; + } + + rep.hFrameBufferLow = (CARD32)(hFrameBuffer & 0xffffffff); +#if defined(LONG64) && !defined(__linux__) + rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32); +#else + rep.hFrameBufferHigh = 0; +#endif + + rep.length = 0; + if (rep.devPrivateSize) { + rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetDeviceInfoReply) - + SIZEOF(xGenericReply) + + pad_to_int32(rep.devPrivateSize)); + } + + WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep); + if (rep.length) { + WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate); + } + EPHYR_LOG ("leave\n") ; + return Success; +} + +static int +ProcXF86DRIDispatch (register ClientPtr client) +{ + REQUEST(xReq); + EPHYR_LOG ("enter\n") ; + + switch (stuff->data) + { + case X_XF86DRIQueryVersion: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIQueryVersion(client); + } + case X_XF86DRIQueryDirectRenderingCapable: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIQueryDirectRenderingCapable(client); + } + } + + if (!LocalClient(client)) + return DRIErrorBase + XF86DRIClientNotLocal; + + switch (stuff->data) + { + case X_XF86DRIOpenConnection: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIOpenConnection(client); + } + case X_XF86DRICloseConnection: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRICloseConnection(client); + } + case X_XF86DRIGetClientDriverName: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIGetClientDriverName(client); + } + case X_XF86DRICreateContext: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRICreateContext(client); + } + case X_XF86DRIDestroyContext: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIDestroyContext(client); + } + case X_XF86DRICreateDrawable: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRICreateDrawable(client); + } + case X_XF86DRIDestroyDrawable: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIDestroyDrawable(client); + } + case X_XF86DRIGetDrawableInfo: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIGetDrawableInfo(client); + } + case X_XF86DRIGetDeviceInfo: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIGetDeviceInfo(client); + } + case X_XF86DRIAuthConnection: { + EPHYR_LOG ("leave\n") ; + return ProcXF86DRIAuthConnection(client); + } + /* {Open,Close}FullScreen are deprecated now */ + default: { + EPHYR_LOG ("leave\n") ; + return BadRequest; + } + } +} + +static int +SProcXF86DRIQueryVersion (register ClientPtr client) +{ + register int n; + REQUEST(xXF86DRIQueryVersionReq); + swaps(&stuff->length, n); + return ProcXF86DRIQueryVersion(client); +} + +static int +SProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) +{ + register int n; + REQUEST(xXF86DRIQueryDirectRenderingCapableReq); + swaps(&stuff->length, n); + swapl(&stuff->screen, n); + return ProcXF86DRIQueryDirectRenderingCapable(client); +} + +static int +SProcXF86DRIDispatch (register ClientPtr client) +{ + REQUEST(xReq); + + EPHYR_LOG ("enter\n") ; + /* + * Only local clients are allowed DRI access, but remote clients still need + * these requests to find out cleanly. + */ + switch (stuff->data) + { + case X_XF86DRIQueryVersion: { + EPHYR_LOG ("leave\n") ; + return SProcXF86DRIQueryVersion(client); + } + case X_XF86DRIQueryDirectRenderingCapable: { + EPHYR_LOG ("leave\n") ; + return SProcXF86DRIQueryDirectRenderingCapable(client); + } + default: { + EPHYR_LOG ("leave\n") ; + return DRIErrorBase + XF86DRIClientNotLocal; + } + } +} diff --git a/xorg-server/hw/kdrive/ephyr/ephyrglxext.c b/xorg-server/hw/kdrive/ephyr/ephyrglxext.c index a0278cc2b..d6b8ca66d 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyrglxext.c +++ b/xorg-server/hw/kdrive/ephyr/ephyrglxext.c @@ -1,723 +1,723 @@ -/* - * Xephyr - A kdrive X server thats runs in a host X window. - * Authored by Matthew Allum - * - * Copyright © 2007 OpenedHand Ltd - * - * 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 OpenedHand Ltd not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. OpenedHand Ltd makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - * Authors: - * Dodji Seketeli - */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "extnsionst.h" -#include "ephyrglxext.h" -#include "ephyrhostglx.h" -#define _HAVE_XALLOC_DECLS -#include "ephyrlog.h" -#include -#include "glx/glxserver.h" -#include "glx/indirect_table.h" -#include "glx/indirect_util.h" -#include "glx/unpack.h" -#include "hostx.h" - - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - - -int ephyrGLXQueryVersion (__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXQueryVersionSwap (__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXGetVisualConfigs (__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXGetVisualConfigsSwap (__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXClientInfo(__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXClientInfoSwap(__GLXclientState *cl, GLbyte *pc) ; -int ephyrGLXQueryServerString(__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXQueryServerStringSwap(__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXGetFBConfigsSGIX (__GLXclientState *a_cl, GLbyte *a_pc); -int ephyrGLXGetFBConfigsSGIXSwap (__GLXclientState *a_cl, GLbyte *a_pc); -int ephyrGLXCreateContext (__GLXclientState *a_cl, GLbyte *a_pc); -int ephyrGLXCreateContextSwap (__GLXclientState *a_cl, GLbyte *a_pc); -int ephyrGLXDestroyContext (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXDestroyContextSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXMakeCurrent (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXMakeCurrentSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXGetString (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXGetStringSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXGetIntegerv (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXGetIntegervSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXIsDirect (__GLXclientState *a_cl, GLbyte *a_pc) ; -int ephyrGLXIsDirectSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; - -Bool -ephyrHijackGLXExtension (void) -{ - const void *(*dispatch_functions)[2]; - - if (!hostx_has_glx ()) { - EPHYR_LOG ("host X does not have GLX\n") ; - return FALSE ; - } - EPHYR_LOG ("host X does have GLX\n") ; - - if (!Single_dispatch_info.dispatch_functions) { - EPHYR_LOG_ERROR ("could not get dispatch functions table\n") ; - return FALSE ; - } - /* - * hijack some single entry point dispatch functions - */ - dispatch_functions = Single_dispatch_info.dispatch_functions ; - EPHYR_RETURN_VAL_IF_FAIL (dispatch_functions, FALSE) ; - - dispatch_functions[X_GLXQueryVersion][0] = ephyrGLXQueryVersion ; - dispatch_functions[X_GLXQueryVersion][1] = ephyrGLXQueryVersionSwap ; - - dispatch_functions[X_GLXGetVisualConfigs][0] = ephyrGLXGetVisualConfigs ; - dispatch_functions[X_GLXGetVisualConfigs][1] = ephyrGLXGetVisualConfigsSwap ; - dispatch_functions[X_GLXClientInfo][0] = ephyrGLXClientInfo ; - dispatch_functions[X_GLXClientInfo][1] = ephyrGLXClientInfoSwap ; - - dispatch_functions[X_GLXQueryServerString][0] = ephyrGLXQueryServerString ; - dispatch_functions[X_GLXQueryServerString][1] = - ephyrGLXQueryServerStringSwap ; - - dispatch_functions[X_GLXCreateContext][0] = ephyrGLXCreateContext ; - dispatch_functions[X_GLXCreateContext][1] = ephyrGLXCreateContextSwap ; - - dispatch_functions[X_GLXDestroyContext][0] = ephyrGLXDestroyContext ; - dispatch_functions[X_GLXDestroyContext][1] = ephyrGLXDestroyContextSwap ; - - dispatch_functions[X_GLXMakeCurrent][0] = ephyrGLXMakeCurrent ; - dispatch_functions[X_GLXMakeCurrent][1] = ephyrGLXMakeCurrentSwap ; - - dispatch_functions[X_GLXIsDirect][0] = ephyrGLXIsDirect ; - dispatch_functions[X_GLXIsDirect][1] = ephyrGLXIsDirectSwap ; - - dispatch_functions[73][0] = ephyrGLXGetString ; - dispatch_functions[73][1] = ephyrGLXGetStringSwap ; - - dispatch_functions[61][0] = ephyrGLXGetIntegerv ; - dispatch_functions[61][1] = ephyrGLXGetIntegervSwap ; - - /* - * hijack some vendor priv entry point dispatch functions - */ - dispatch_functions = VendorPriv_dispatch_info.dispatch_functions ; - dispatch_functions[92][0] = ephyrGLXGetFBConfigsSGIX; - dispatch_functions[92][1] = ephyrGLXGetFBConfigsSGIXSwap; - EPHYR_LOG ("hijacked glx entry points to forward requests to host X\n") ; - - return TRUE ; -} - -/********************* - * implementation of - * hijacked GLX entry - * points - ********************/ - -int -ephyrGLXQueryVersion(__GLXclientState *a_cl, GLbyte *a_pc) -{ - ClientPtr client = a_cl->client; - xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) a_pc; - xGLXQueryVersionReply reply; - int major, minor; - int res = BadImplementation ; - - EPHYR_LOG ("enter\n") ; - - major = req->majorVersion ; - minor = req->minorVersion ; - - if (!ephyrHostGLXQueryVersion (&major, &minor)) { - EPHYR_LOG_ERROR ("ephyrHostGLXQueryVersion() failed\n") ; - goto out ; - } - EPHYR_LOG ("major:%d, minor:%d\n", - major, minor); - reply.majorVersion = major ; - reply.minorVersion = minor ; - reply.length = 0 ; - reply.type = X_Reply ; - reply.sequenceNumber = client->sequence ; - - if (client->swapped) { - __glXSwapQueryVersionReply(client, &reply); - } else { - WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply); - } - - res = Success ; -out: - EPHYR_LOG ("leave\n") ; - return res; -} - -int -ephyrGLXQueryVersionSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) a_pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT (&req->length); - __GLX_SWAP_INT (&req->majorVersion); - __GLX_SWAP_INT (&req->minorVersion); - return ephyrGLXQueryVersion (a_cl, a_pc) ; -} - -static int -ephyrGLXGetVisualConfigsReal (__GLXclientState *a_cl, - GLbyte *a_pc, - Bool a_do_swap) -{ - xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) a_pc; - ClientPtr client = a_cl->client; - xGLXGetVisualConfigsReply reply; - int32_t *props_buf=NULL, num_visuals=0, - num_props=0, res=BadImplementation, i=0, - props_per_visual_size=0, - props_buf_size=0; - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_DECLARE_SWAP_ARRAY_VARIABLES; - - EPHYR_LOG ("enter\n") ; - - if (!ephyrHostGLXGetVisualConfigs (req->screen, - &num_visuals, - &num_props, - &props_buf_size, - &props_buf)) { - EPHYR_LOG_ERROR ("ephyrHostGLXGetVisualConfigs() failed\n") ; - goto out ; - } - EPHYR_LOG ("num_visuals:%d, num_props:%d\n", num_visuals, num_props) ; - - reply.numVisuals = num_visuals; - reply.numProps = num_props; - reply.length = (num_visuals *__GLX_SIZE_CARD32 * num_props) >> 2; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (a_do_swap) { - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - __GLX_SWAP_INT(&reply.numVisuals); - __GLX_SWAP_INT(&reply.numProps); - __GLX_SWAP_INT_ARRAY (props_buf, num_props) ; - } - WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char*)&reply); - props_per_visual_size = props_buf_size/num_visuals ; - for (i=0; i < num_visuals; i++) { - WriteToClient (client, - props_per_visual_size, - (char*)props_buf +i*props_per_visual_size); - } - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - xfree (props_buf) ; - props_buf = NULL ; - - return res ; -} - -static int -ephyrGLXGetFBConfigsSGIXReal (__GLXclientState *a_cl, - GLbyte *a_pc, - Bool a_do_swap) -{ - xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *)a_pc; - ClientPtr client = a_cl->client; - xGLXGetVisualConfigsReply reply; - int32_t *props_buf=NULL, num_visuals=0, - num_props=0, res=BadImplementation, i=0, - props_per_visual_size=0, - props_buf_size=0; - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_DECLARE_SWAP_ARRAY_VARIABLES; - - EPHYR_LOG ("enter\n") ; - - if (!ephyrHostGLXVendorPrivGetFBConfigsSGIX (req->screen, - &num_visuals, - &num_props, - &props_buf_size, - &props_buf)) { - EPHYR_LOG_ERROR ("ephyrHostGLXGetVisualConfigs() failed\n") ; - goto out ; - } - EPHYR_LOG ("num_visuals:%d, num_props:%d\n", num_visuals, num_props) ; - - reply.numVisuals = num_visuals; - reply.numProps = num_props; - reply.length = props_buf_size >> 2; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - - if (a_do_swap) { - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - __GLX_SWAP_INT(&reply.numVisuals); - __GLX_SWAP_INT(&reply.numProps); - __GLX_SWAP_INT_ARRAY (props_buf, num_props) ; - } - WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char*)&reply); - props_per_visual_size = props_buf_size/num_visuals ; - for (i=0; i < num_visuals; i++) { - WriteToClient (client, - props_per_visual_size, - &((char*)props_buf)[i*props_per_visual_size]); - } - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - xfree (props_buf) ; - props_buf = NULL ; - - return res ; -} - -int -ephyrGLXGetVisualConfigs (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetVisualConfigsReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXGetVisualConfigsSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetVisualConfigsReal (a_cl, a_pc, TRUE) ; -} - - -int -ephyrGLXClientInfo(__GLXclientState *a_cl, GLbyte *a_pc) -{ - int res=BadImplementation ; - xGLXClientInfoReq *req = (xGLXClientInfoReq *) a_pc; - - EPHYR_LOG ("enter\n") ; - if (!ephyrHostGLXSendClientInfo (req->major, req->minor, (char*)req+1)) { - EPHYR_LOG_ERROR ("failed to send client info to host\n") ; - goto out ; - } - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXClientInfoSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - xGLXClientInfoReq *req = (xGLXClientInfoReq *)a_pc; - __GLX_DECLARE_SWAP_VARIABLES; - - __GLX_SWAP_SHORT (&req->length); - __GLX_SWAP_INT (&req->major); - __GLX_SWAP_INT (&req->minor); - __GLX_SWAP_INT (&req->numbytes); - - return ephyrGLXClientInfo (a_cl, a_pc) ; -} - -int -ephyrGLXQueryServerString(__GLXclientState *a_cl, GLbyte *a_pc) -{ - int res = BadImplementation ; - ClientPtr client = a_cl->client; - xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) a_pc; - xGLXQueryServerStringReply reply; - char *server_string=NULL, *buf=NULL; - int length=0 ; - - EPHYR_LOG ("enter\n") ; - if (!ephyrHostGLXGetStringFromServer (req->screen, - req->name, - EPHYR_HOST_GLX_QueryServerString, - &server_string)) { - EPHYR_LOG_ERROR ("failed to query string from host\n") ; - goto out ; - } - EPHYR_LOG ("string: %s\n", server_string) ; - length= strlen (server_string) + 1; - reply.type = X_Reply ; - reply.sequenceNumber = client->sequence ; - reply.length = __GLX_PAD (length) >> 2 ; - reply.n = length ; - buf = xcalloc (reply.length << 2, 1); - if (!buf) { - EPHYR_LOG_ERROR ("failed to allocate string\n;"); - return BadAlloc; - } - memcpy (buf, server_string, length); - - WriteToClient(client, sz_xGLXQueryServerStringReply, (char*)&reply); - WriteToClient(client, (int)(reply.length << 2), server_string); - - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - xfree (server_string) ; - server_string = NULL; - - xfree (buf); - buf = NULL; - - return res ; -} - -int -ephyrGLXQueryServerStringSwap(__GLXclientState *a_cl, GLbyte *a_pc) -{ - EPHYR_LOG_ERROR ("not yet implemented\n") ; - return BadImplementation ; -} - - -int -ephyrGLXGetFBConfigsSGIX (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetFBConfigsSGIXReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXGetFBConfigsSGIXSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetFBConfigsSGIXReal (a_cl, a_pc, TRUE) ; -} - -static int -ephyrGLXCreateContextReal (xGLXCreateContextReq *a_req, Bool a_do_swap) -{ - int res=BadImplementation; - EphyrHostWindowAttributes host_w_attrs ; - __GLX_DECLARE_SWAP_VARIABLES; - - EPHYR_RETURN_VAL_IF_FAIL (a_req, BadValue) ; - EPHYR_LOG ("enter\n") ; - - if (a_do_swap) { - __GLX_SWAP_SHORT(&a_req->length); - __GLX_SWAP_INT(&a_req->context); - __GLX_SWAP_INT(&a_req->visual); - __GLX_SWAP_INT(&a_req->screen); - __GLX_SWAP_INT(&a_req->shareList); - } - - EPHYR_LOG ("context creation requested. localid:%d, " - "screen:%d, visual:%d, direct:%d\n", - (int)a_req->context, (int)a_req->screen, - (int)a_req->visual, (int)a_req->isDirect) ; - - memset (&host_w_attrs, 0, sizeof (host_w_attrs)) ; - if (!hostx_get_window_attributes (hostx_get_window (a_req->screen), - &host_w_attrs)) { - EPHYR_LOG_ERROR ("failed to get host window attrs\n") ; - goto out ; - } - - EPHYR_LOG ("host window visual id: %d\n", host_w_attrs.visualid) ; - - if (!ephyrHostGLXCreateContext (a_req->screen, - host_w_attrs.visualid, - a_req->context, - a_req->shareList, - a_req->isDirect)) { - EPHYR_LOG_ERROR ("ephyrHostGLXCreateContext() failed\n") ; - goto out ; - } - res = Success; -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXCreateContext (__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; - - return ephyrGLXCreateContextReal (req, FALSE) ; -} - -int ephyrGLXCreateContextSwap (__GLXclientState *cl, GLbyte *pc) -{ - xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; - return ephyrGLXCreateContextReal (req, TRUE) ; -} - -static int -ephyrGLXDestroyContextReal (__GLXclientState *a_cl, - GLbyte *a_pc, - Bool a_do_swap) -{ - int res=BadImplementation; - ClientPtr client = a_cl->client; - xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) a_pc; - - EPHYR_LOG ("enter. id:%d\n", (int)req->context) ; - if (!ephyrHostDestroyContext (req->context)) { - EPHYR_LOG_ERROR ("ephyrHostDestroyContext() failed\n") ; - client->errorValue = req->context ; - goto out ; - } - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXDestroyContext (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXDestroyContextReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXDestroyContextSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXDestroyContextReal (a_cl, a_pc, TRUE) ; -} - -static int -ephyrGLXMakeCurrentReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) -{ - int res=BadImplementation; - xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) a_pc; - xGLXMakeCurrentReply reply ; - DrawablePtr drawable=NULL; - int rc=0; - - EPHYR_LOG ("enter\n") ; - rc = dixLookupDrawable (&drawable, - req->drawable, - a_cl->client, - 0, - DixReadAccess); - EPHYR_RETURN_VAL_IF_FAIL (drawable, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (drawable->pScreen, BadValue) ; - EPHYR_LOG ("screen nummber requested:%d\n", - drawable->pScreen->myNum) ; - - memset (&reply, 0, sizeof (reply)) ; - if (!ephyrHostGLXMakeCurrent (hostx_get_window (drawable->pScreen->myNum), - req->context, - req->oldContextTag, - (int*)&reply.contextTag)) { - EPHYR_LOG_ERROR ("ephyrHostGLXMakeCurrent() failed\n") ; - goto out; - } - reply.length = 0; - reply.type = X_Reply; - reply.sequenceNumber = a_cl->client->sequence; - if (a_do_swap) { - __GLX_DECLARE_SWAP_VARIABLES; - __GLX_SWAP_SHORT(&reply.sequenceNumber); - __GLX_SWAP_INT(&reply.length); - __GLX_SWAP_INT(&reply.contextTag); - } - WriteToClient(a_cl->client, sz_xGLXMakeCurrentReply, (char *)&reply); - - res = Success ; -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXMakeCurrent (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXMakeCurrentReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXMakeCurrentSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXMakeCurrentReal (a_cl, a_pc, TRUE) ; -} - -static int -ephyrGLXGetStringReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) -{ - ClientPtr client=NULL ; - int context_tag=0, name=0, res=BadImplementation, length=0 ; - char *string=NULL; - __GLX_DECLARE_SWAP_VARIABLES; - - EPHYR_RETURN_VAL_IF_FAIL (a_cl && a_pc, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - client = a_cl->client ; - - if (a_do_swap) { - __GLX_SWAP_INT (a_pc + 4); - __GLX_SWAP_INT (a_pc + __GLX_SINGLE_HDR_SIZE); - } - context_tag = __GLX_GET_SINGLE_CONTEXT_TAG (a_pc) ; - a_pc += __GLX_SINGLE_HDR_SIZE; - name = *(GLenum*)(a_pc + 0); - EPHYR_LOG ("context_tag:%d, name:%d\n", context_tag, name) ; - if (!ephyrHostGLXGetStringFromServer (context_tag, - name, - EPHYR_HOST_GLX_GetString, - &string)) { - EPHYR_LOG_ERROR ("failed to get string from server\n") ; - goto out ; - } - if (string) { - length = strlen (string) + 1; - EPHYR_LOG ("got string:'%s', size:%d\n", string, length) ; - } else { - EPHYR_LOG ("got string: string (null)\n") ; - } - __GLX_BEGIN_REPLY (length); - __GLX_PUT_SIZE (length); - __GLX_SEND_HEADER (); - if (a_do_swap) { - __GLX_SWAP_REPLY_SIZE (); - __GLX_SWAP_REPLY_HEADER (); - } - WriteToClient (client, length, (char *)string); - - res = Success ; -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXGetString (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetStringReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXGetStringSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetStringReal (a_cl, a_pc, TRUE) ; -} - -static int -ephyrGLXGetIntegervReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) -{ - int res=BadImplementation; - xGLXSingleReq * const req = (xGLXSingleReq *) a_pc; - GLenum int_name ; - int value=0 ; - GLint answer_buf_room[200]; - GLint *buf=NULL ; - - EPHYR_LOG ("enter\n") ; - - a_pc += __GLX_SINGLE_HDR_SIZE; - - int_name = *(GLenum*) (a_pc+0) ; - if (!ephyrHostGetIntegerValue (req->contextTag, int_name, &value)) { - EPHYR_LOG_ERROR ("ephyrHostGetIntegerValue() failed\n") ; - goto out ; - } - buf = __glXGetAnswerBuffer (a_cl, sizeof (value), - answer_buf_room, - sizeof (answer_buf_room), - 4) ; - - if (!buf) { - EPHYR_LOG_ERROR ("failed to allocate reply buffer\n") ; - res = BadAlloc ; - goto out ; - } - __glXSendReply (a_cl->client, buf, 1, sizeof (value), GL_FALSE, 0) ; - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXGetIntegerv (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetIntegervReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXGetIntegervSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXGetIntegervReal (a_cl, a_pc, TRUE) ; -} - -static int -ephyrGLXIsDirectReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) -{ - int res=BadImplementation; - ClientPtr client = a_cl->client; - xGLXIsDirectReq *req = (xGLXIsDirectReq *) a_pc; - xGLXIsDirectReply reply; - int is_direct=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_cl && a_pc, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - memset (&reply, 0, sizeof (reply)) ; - if (!ephyrHostIsContextDirect (req->context, (int*)&is_direct)) { - EPHYR_LOG_ERROR ("ephyrHostIsContextDirect() failed\n") ; - goto out ; - } - reply.isDirect = is_direct ; - reply.length = 0; - reply.type = X_Reply; - reply.sequenceNumber = client->sequence; - WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply); - res = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -int -ephyrGLXIsDirect (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXIsDirectReal (a_cl, a_pc, FALSE) ; -} - -int -ephyrGLXIsDirectSwap (__GLXclientState *a_cl, GLbyte *a_pc) -{ - return ephyrGLXIsDirectReal (a_cl, a_pc, TRUE) ; -} +/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum + * + * Copyright © 2007 OpenedHand Ltd + * + * 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 OpenedHand Ltd not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. OpenedHand Ltd makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Dodji Seketeli + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "extnsionst.h" +#include "ephyrglxext.h" +#include "ephyrhostglx.h" +#define _HAVE_XALLOC_DECLS +#include "ephyrlog.h" +#include +#include "glx/glxserver.h" +#include "glx/indirect_table.h" +#include "glx/indirect_util.h" +#include "glx/unpack.h" +#include "hostx.h" + + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + + +int ephyrGLXQueryVersion (__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXQueryVersionSwap (__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXGetVisualConfigs (__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXGetVisualConfigsSwap (__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXClientInfo(__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXClientInfoSwap(__GLXclientState *cl, GLbyte *pc) ; +int ephyrGLXQueryServerString(__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXQueryServerStringSwap(__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXGetFBConfigsSGIX (__GLXclientState *a_cl, GLbyte *a_pc); +int ephyrGLXGetFBConfigsSGIXSwap (__GLXclientState *a_cl, GLbyte *a_pc); +int ephyrGLXCreateContext (__GLXclientState *a_cl, GLbyte *a_pc); +int ephyrGLXCreateContextSwap (__GLXclientState *a_cl, GLbyte *a_pc); +int ephyrGLXDestroyContext (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXDestroyContextSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXMakeCurrent (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXMakeCurrentSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXGetString (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXGetStringSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXGetIntegerv (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXGetIntegervSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXIsDirect (__GLXclientState *a_cl, GLbyte *a_pc) ; +int ephyrGLXIsDirectSwap (__GLXclientState *a_cl, GLbyte *a_pc) ; + +Bool +ephyrHijackGLXExtension (void) +{ + const void *(*dispatch_functions)[2]; + + if (!hostx_has_glx ()) { + EPHYR_LOG ("host X does not have GLX\n") ; + return FALSE ; + } + EPHYR_LOG ("host X does have GLX\n") ; + + if (!Single_dispatch_info.dispatch_functions) { + EPHYR_LOG_ERROR ("could not get dispatch functions table\n") ; + return FALSE ; + } + /* + * hijack some single entry point dispatch functions + */ + dispatch_functions = Single_dispatch_info.dispatch_functions ; + EPHYR_RETURN_VAL_IF_FAIL (dispatch_functions, FALSE) ; + + dispatch_functions[X_GLXQueryVersion][0] = ephyrGLXQueryVersion ; + dispatch_functions[X_GLXQueryVersion][1] = ephyrGLXQueryVersionSwap ; + + dispatch_functions[X_GLXGetVisualConfigs][0] = ephyrGLXGetVisualConfigs ; + dispatch_functions[X_GLXGetVisualConfigs][1] = ephyrGLXGetVisualConfigsSwap ; + dispatch_functions[X_GLXClientInfo][0] = ephyrGLXClientInfo ; + dispatch_functions[X_GLXClientInfo][1] = ephyrGLXClientInfoSwap ; + + dispatch_functions[X_GLXQueryServerString][0] = ephyrGLXQueryServerString ; + dispatch_functions[X_GLXQueryServerString][1] = + ephyrGLXQueryServerStringSwap ; + + dispatch_functions[X_GLXCreateContext][0] = ephyrGLXCreateContext ; + dispatch_functions[X_GLXCreateContext][1] = ephyrGLXCreateContextSwap ; + + dispatch_functions[X_GLXDestroyContext][0] = ephyrGLXDestroyContext ; + dispatch_functions[X_GLXDestroyContext][1] = ephyrGLXDestroyContextSwap ; + + dispatch_functions[X_GLXMakeCurrent][0] = ephyrGLXMakeCurrent ; + dispatch_functions[X_GLXMakeCurrent][1] = ephyrGLXMakeCurrentSwap ; + + dispatch_functions[X_GLXIsDirect][0] = ephyrGLXIsDirect ; + dispatch_functions[X_GLXIsDirect][1] = ephyrGLXIsDirectSwap ; + + dispatch_functions[73][0] = ephyrGLXGetString ; + dispatch_functions[73][1] = ephyrGLXGetStringSwap ; + + dispatch_functions[61][0] = ephyrGLXGetIntegerv ; + dispatch_functions[61][1] = ephyrGLXGetIntegervSwap ; + + /* + * hijack some vendor priv entry point dispatch functions + */ + dispatch_functions = VendorPriv_dispatch_info.dispatch_functions ; + dispatch_functions[92][0] = ephyrGLXGetFBConfigsSGIX; + dispatch_functions[92][1] = ephyrGLXGetFBConfigsSGIXSwap; + EPHYR_LOG ("hijacked glx entry points to forward requests to host X\n") ; + + return TRUE ; +} + +/********************* + * implementation of + * hijacked GLX entry + * points + ********************/ + +int +ephyrGLXQueryVersion(__GLXclientState *a_cl, GLbyte *a_pc) +{ + ClientPtr client = a_cl->client; + xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) a_pc; + xGLXQueryVersionReply reply; + int major, minor; + int res = BadImplementation ; + + EPHYR_LOG ("enter\n") ; + + major = req->majorVersion ; + minor = req->minorVersion ; + + if (!ephyrHostGLXQueryVersion (&major, &minor)) { + EPHYR_LOG_ERROR ("ephyrHostGLXQueryVersion() failed\n") ; + goto out ; + } + EPHYR_LOG ("major:%d, minor:%d\n", + major, minor); + reply.majorVersion = major ; + reply.minorVersion = minor ; + reply.length = 0 ; + reply.type = X_Reply ; + reply.sequenceNumber = client->sequence ; + + if (client->swapped) { + __glXSwapQueryVersionReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply); + } + + res = Success ; +out: + EPHYR_LOG ("leave\n") ; + return res; +} + +int +ephyrGLXQueryVersionSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) a_pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT (&req->length); + __GLX_SWAP_INT (&req->majorVersion); + __GLX_SWAP_INT (&req->minorVersion); + return ephyrGLXQueryVersion (a_cl, a_pc) ; +} + +static int +ephyrGLXGetVisualConfigsReal (__GLXclientState *a_cl, + GLbyte *a_pc, + Bool a_do_swap) +{ + xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) a_pc; + ClientPtr client = a_cl->client; + xGLXGetVisualConfigsReply reply; + int32_t *props_buf=NULL, num_visuals=0, + num_props=0, res=BadImplementation, i=0, + props_per_visual_size=0, + props_buf_size=0; + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_DECLARE_SWAP_ARRAY_VARIABLES; + + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostGLXGetVisualConfigs (req->screen, + &num_visuals, + &num_props, + &props_buf_size, + &props_buf)) { + EPHYR_LOG_ERROR ("ephyrHostGLXGetVisualConfigs() failed\n") ; + goto out ; + } + EPHYR_LOG ("num_visuals:%d, num_props:%d\n", num_visuals, num_props) ; + + reply.numVisuals = num_visuals; + reply.numProps = num_props; + reply.length = (num_visuals *__GLX_SIZE_CARD32 * num_props) >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (a_do_swap) { + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + __GLX_SWAP_INT(&reply.numVisuals); + __GLX_SWAP_INT(&reply.numProps); + __GLX_SWAP_INT_ARRAY (props_buf, num_props) ; + } + WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char*)&reply); + props_per_visual_size = props_buf_size/num_visuals ; + for (i=0; i < num_visuals; i++) { + WriteToClient (client, + props_per_visual_size, + (char*)props_buf +i*props_per_visual_size); + } + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + free(props_buf) ; + props_buf = NULL ; + + return res ; +} + +static int +ephyrGLXGetFBConfigsSGIXReal (__GLXclientState *a_cl, + GLbyte *a_pc, + Bool a_do_swap) +{ + xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *)a_pc; + ClientPtr client = a_cl->client; + xGLXGetVisualConfigsReply reply; + int32_t *props_buf=NULL, num_visuals=0, + num_props=0, res=BadImplementation, i=0, + props_per_visual_size=0, + props_buf_size=0; + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_DECLARE_SWAP_ARRAY_VARIABLES; + + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostGLXVendorPrivGetFBConfigsSGIX (req->screen, + &num_visuals, + &num_props, + &props_buf_size, + &props_buf)) { + EPHYR_LOG_ERROR ("ephyrHostGLXGetVisualConfigs() failed\n") ; + goto out ; + } + EPHYR_LOG ("num_visuals:%d, num_props:%d\n", num_visuals, num_props) ; + + reply.numVisuals = num_visuals; + reply.numProps = num_props; + reply.length = props_buf_size >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (a_do_swap) { + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + __GLX_SWAP_INT(&reply.numVisuals); + __GLX_SWAP_INT(&reply.numProps); + __GLX_SWAP_INT_ARRAY (props_buf, num_props) ; + } + WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char*)&reply); + props_per_visual_size = props_buf_size/num_visuals ; + for (i=0; i < num_visuals; i++) { + WriteToClient (client, + props_per_visual_size, + &((char*)props_buf)[i*props_per_visual_size]); + } + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + free(props_buf) ; + props_buf = NULL ; + + return res ; +} + +int +ephyrGLXGetVisualConfigs (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetVisualConfigsReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXGetVisualConfigsSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetVisualConfigsReal (a_cl, a_pc, TRUE) ; +} + + +int +ephyrGLXClientInfo(__GLXclientState *a_cl, GLbyte *a_pc) +{ + int res=BadImplementation ; + xGLXClientInfoReq *req = (xGLXClientInfoReq *) a_pc; + + EPHYR_LOG ("enter\n") ; + if (!ephyrHostGLXSendClientInfo (req->major, req->minor, (char*)req+1)) { + EPHYR_LOG_ERROR ("failed to send client info to host\n") ; + goto out ; + } + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXClientInfoSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + xGLXClientInfoReq *req = (xGLXClientInfoReq *)a_pc; + __GLX_DECLARE_SWAP_VARIABLES; + + __GLX_SWAP_SHORT (&req->length); + __GLX_SWAP_INT (&req->major); + __GLX_SWAP_INT (&req->minor); + __GLX_SWAP_INT (&req->numbytes); + + return ephyrGLXClientInfo (a_cl, a_pc) ; +} + +int +ephyrGLXQueryServerString(__GLXclientState *a_cl, GLbyte *a_pc) +{ + int res = BadImplementation ; + ClientPtr client = a_cl->client; + xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) a_pc; + xGLXQueryServerStringReply reply; + char *server_string=NULL, *buf=NULL; + int length=0 ; + + EPHYR_LOG ("enter\n") ; + if (!ephyrHostGLXGetStringFromServer (req->screen, + req->name, + EPHYR_HOST_GLX_QueryServerString, + &server_string)) { + EPHYR_LOG_ERROR ("failed to query string from host\n") ; + goto out ; + } + EPHYR_LOG ("string: %s\n", server_string) ; + length= strlen (server_string) + 1; + reply.type = X_Reply ; + reply.sequenceNumber = client->sequence ; + reply.length = __GLX_PAD (length) >> 2 ; + reply.n = length ; + buf = calloc(reply.length << 2, 1); + if (!buf) { + EPHYR_LOG_ERROR ("failed to allocate string\n;"); + return BadAlloc; + } + memcpy (buf, server_string, length); + + WriteToClient(client, sz_xGLXQueryServerStringReply, (char*)&reply); + WriteToClient(client, (int)(reply.length << 2), server_string); + + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + free(server_string) ; + server_string = NULL; + + free(buf); + buf = NULL; + + return res ; +} + +int +ephyrGLXQueryServerStringSwap(__GLXclientState *a_cl, GLbyte *a_pc) +{ + EPHYR_LOG_ERROR ("not yet implemented\n") ; + return BadImplementation ; +} + + +int +ephyrGLXGetFBConfigsSGIX (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetFBConfigsSGIXReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXGetFBConfigsSGIXSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetFBConfigsSGIXReal (a_cl, a_pc, TRUE) ; +} + +static int +ephyrGLXCreateContextReal (xGLXCreateContextReq *a_req, Bool a_do_swap) +{ + int res=BadImplementation; + EphyrHostWindowAttributes host_w_attrs ; + __GLX_DECLARE_SWAP_VARIABLES; + + EPHYR_RETURN_VAL_IF_FAIL (a_req, BadValue) ; + EPHYR_LOG ("enter\n") ; + + if (a_do_swap) { + __GLX_SWAP_SHORT(&a_req->length); + __GLX_SWAP_INT(&a_req->context); + __GLX_SWAP_INT(&a_req->visual); + __GLX_SWAP_INT(&a_req->screen); + __GLX_SWAP_INT(&a_req->shareList); + } + + EPHYR_LOG ("context creation requested. localid:%d, " + "screen:%d, visual:%d, direct:%d\n", + (int)a_req->context, (int)a_req->screen, + (int)a_req->visual, (int)a_req->isDirect) ; + + memset (&host_w_attrs, 0, sizeof (host_w_attrs)) ; + if (!hostx_get_window_attributes (hostx_get_window (a_req->screen), + &host_w_attrs)) { + EPHYR_LOG_ERROR ("failed to get host window attrs\n") ; + goto out ; + } + + EPHYR_LOG ("host window visual id: %d\n", host_w_attrs.visualid) ; + + if (!ephyrHostGLXCreateContext (a_req->screen, + host_w_attrs.visualid, + a_req->context, + a_req->shareList, + a_req->isDirect)) { + EPHYR_LOG_ERROR ("ephyrHostGLXCreateContext() failed\n") ; + goto out ; + } + res = Success; +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXCreateContext (__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; + + return ephyrGLXCreateContextReal (req, FALSE) ; +} + +int ephyrGLXCreateContextSwap (__GLXclientState *cl, GLbyte *pc) +{ + xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; + return ephyrGLXCreateContextReal (req, TRUE) ; +} + +static int +ephyrGLXDestroyContextReal (__GLXclientState *a_cl, + GLbyte *a_pc, + Bool a_do_swap) +{ + int res=BadImplementation; + ClientPtr client = a_cl->client; + xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) a_pc; + + EPHYR_LOG ("enter. id:%d\n", (int)req->context) ; + if (!ephyrHostDestroyContext (req->context)) { + EPHYR_LOG_ERROR ("ephyrHostDestroyContext() failed\n") ; + client->errorValue = req->context ; + goto out ; + } + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXDestroyContext (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXDestroyContextReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXDestroyContextSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXDestroyContextReal (a_cl, a_pc, TRUE) ; +} + +static int +ephyrGLXMakeCurrentReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) +{ + int res=BadImplementation; + xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) a_pc; + xGLXMakeCurrentReply reply ; + DrawablePtr drawable=NULL; + int rc=0; + + EPHYR_LOG ("enter\n") ; + rc = dixLookupDrawable (&drawable, + req->drawable, + a_cl->client, + 0, + DixReadAccess); + EPHYR_RETURN_VAL_IF_FAIL (drawable, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (drawable->pScreen, BadValue) ; + EPHYR_LOG ("screen nummber requested:%d\n", + drawable->pScreen->myNum) ; + + memset (&reply, 0, sizeof (reply)) ; + if (!ephyrHostGLXMakeCurrent (hostx_get_window (drawable->pScreen->myNum), + req->context, + req->oldContextTag, + (int*)&reply.contextTag)) { + EPHYR_LOG_ERROR ("ephyrHostGLXMakeCurrent() failed\n") ; + goto out; + } + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = a_cl->client->sequence; + if (a_do_swap) { + __GLX_DECLARE_SWAP_VARIABLES; + __GLX_SWAP_SHORT(&reply.sequenceNumber); + __GLX_SWAP_INT(&reply.length); + __GLX_SWAP_INT(&reply.contextTag); + } + WriteToClient(a_cl->client, sz_xGLXMakeCurrentReply, (char *)&reply); + + res = Success ; +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXMakeCurrent (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXMakeCurrentReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXMakeCurrentSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXMakeCurrentReal (a_cl, a_pc, TRUE) ; +} + +static int +ephyrGLXGetStringReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) +{ + ClientPtr client=NULL ; + int context_tag=0, name=0, res=BadImplementation, length=0 ; + char *string=NULL; + __GLX_DECLARE_SWAP_VARIABLES; + + EPHYR_RETURN_VAL_IF_FAIL (a_cl && a_pc, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + client = a_cl->client ; + + if (a_do_swap) { + __GLX_SWAP_INT (a_pc + 4); + __GLX_SWAP_INT (a_pc + __GLX_SINGLE_HDR_SIZE); + } + context_tag = __GLX_GET_SINGLE_CONTEXT_TAG (a_pc) ; + a_pc += __GLX_SINGLE_HDR_SIZE; + name = *(GLenum*)(a_pc + 0); + EPHYR_LOG ("context_tag:%d, name:%d\n", context_tag, name) ; + if (!ephyrHostGLXGetStringFromServer (context_tag, + name, + EPHYR_HOST_GLX_GetString, + &string)) { + EPHYR_LOG_ERROR ("failed to get string from server\n") ; + goto out ; + } + if (string) { + length = strlen (string) + 1; + EPHYR_LOG ("got string:'%s', size:%d\n", string, length) ; + } else { + EPHYR_LOG ("got string: string (null)\n") ; + } + __GLX_BEGIN_REPLY (length); + __GLX_PUT_SIZE (length); + __GLX_SEND_HEADER (); + if (a_do_swap) { + __GLX_SWAP_REPLY_SIZE (); + __GLX_SWAP_REPLY_HEADER (); + } + WriteToClient (client, length, (char *)string); + + res = Success ; +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXGetString (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetStringReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXGetStringSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetStringReal (a_cl, a_pc, TRUE) ; +} + +static int +ephyrGLXGetIntegervReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) +{ + int res=BadImplementation; + xGLXSingleReq * const req = (xGLXSingleReq *) a_pc; + GLenum int_name ; + int value=0 ; + GLint answer_buf_room[200]; + GLint *buf=NULL ; + + EPHYR_LOG ("enter\n") ; + + a_pc += __GLX_SINGLE_HDR_SIZE; + + int_name = *(GLenum*) (a_pc+0) ; + if (!ephyrHostGetIntegerValue (req->contextTag, int_name, &value)) { + EPHYR_LOG_ERROR ("ephyrHostGetIntegerValue() failed\n") ; + goto out ; + } + buf = __glXGetAnswerBuffer (a_cl, sizeof (value), + answer_buf_room, + sizeof (answer_buf_room), + 4) ; + + if (!buf) { + EPHYR_LOG_ERROR ("failed to allocate reply buffer\n") ; + res = BadAlloc ; + goto out ; + } + __glXSendReply (a_cl->client, buf, 1, sizeof (value), GL_FALSE, 0) ; + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXGetIntegerv (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetIntegervReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXGetIntegervSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXGetIntegervReal (a_cl, a_pc, TRUE) ; +} + +static int +ephyrGLXIsDirectReal (__GLXclientState *a_cl, GLbyte *a_pc, Bool a_do_swap) +{ + int res=BadImplementation; + ClientPtr client = a_cl->client; + xGLXIsDirectReq *req = (xGLXIsDirectReq *) a_pc; + xGLXIsDirectReply reply; + int is_direct=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_cl && a_pc, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + memset (&reply, 0, sizeof (reply)) ; + if (!ephyrHostIsContextDirect (req->context, (int*)&is_direct)) { + EPHYR_LOG_ERROR ("ephyrHostIsContextDirect() failed\n") ; + goto out ; + } + reply.isDirect = is_direct ; + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply); + res = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +int +ephyrGLXIsDirect (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXIsDirectReal (a_cl, a_pc, FALSE) ; +} + +int +ephyrGLXIsDirectSwap (__GLXclientState *a_cl, GLbyte *a_pc) +{ + return ephyrGLXIsDirectReal (a_cl, a_pc, TRUE) ; +} diff --git a/xorg-server/hw/kdrive/ephyr/ephyrhostvideo.c b/xorg-server/hw/kdrive/ephyr/ephyrhostvideo.c index f4a1b9d17..60f200629 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyrhostvideo.c +++ b/xorg-server/hw/kdrive/ephyr/ephyrhostvideo.c @@ -1,1012 +1,1012 @@ -/* - * Xephyr - A kdrive X server thats runs in a host X window. - * Authored by Matthew Allum - * - * Copyright © 2007 OpenedHand Ltd - * - * 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 OpenedHand Ltd not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. OpenedHand Ltd makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - * Authors: - * Dodji Seketeli - */ -#ifdef HAVE_CONFIG_H -#include -#endif -/* - * including some server headers (like kdrive-config.h) - * might define the macro _XSERVER64 - * on 64 bits machines. That macro must _NOT_ be defined for Xlib - * client code, otherwise bad things happen. - * So let's undef that macro if necessary. - */ -#ifdef _XSERVER64 -#undef _XSERVER64 -#endif -#include -#include -#include -#include -#include -#include -#define _HAVE_XALLOC_DECLS - -#include "hostx.h" -#include "ephyrhostvideo.h" -#include "ephyrlog.h" - -#ifndef TRUE -#define TRUE 1 -#endif /*TRUE*/ - -#ifndef FALSE -#define FALSE 0 -#endif /*FALSE*/ - -static XExtensionInfo _xv_info_data; -static XExtensionInfo *xv_info = &_xv_info_data; -static char *xv_extension_name = XvName; -static char *xv_error_string(Display *dpy, int code, XExtCodes *codes, - char * buf, int n); -static int xv_close_display(Display *dpy, XExtCodes *codes); -static Bool xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire); - -static XExtensionHooks xv_extension_hooks = { - NULL, /* create_gc */ - NULL, /* copy_gc */ - NULL, /* flush_gc */ - NULL, /* free_gc */ - NULL, /* create_font */ - NULL, /* free_font */ - xv_close_display, /* close_display */ - xv_wire_to_event, /* wire_to_event */ - NULL, /* event_to_wire */ - NULL, /* error */ - xv_error_string /* error_string */ -}; - - -static char *xv_error_list[] = -{ - "BadPort", /* XvBadPort */ - "BadEncoding", /* XvBadEncoding */ - "BadControl" /* XvBadControl */ -}; - - -#define XvCheckExtension(dpy, i, val) \ - XextCheckExtension(dpy, i, xv_extension_name, val) -#define XvGetReq(name, req) \ - WORD64ALIGN\ - if ((dpy->bufptr + SIZEOF(xv##name##Req)) > dpy->bufmax)\ - _XFlush(dpy);\ - req = (xv##name##Req *)(dpy->last_req = dpy->bufptr);\ - req->reqType = info->codes->major_opcode;\ - req->xvReqType = xv_##name; \ - req->length = (SIZEOF(xv##name##Req))>>2;\ - dpy->bufptr += SIZEOF(xv##name##Req);\ - dpy->request++ - -static XEXT_GENERATE_CLOSE_DISPLAY (xv_close_display, xv_info) - - -static XEXT_GENERATE_FIND_DISPLAY (xv_find_display, xv_info, - xv_extension_name, - &xv_extension_hooks, - XvNumEvents, NULL) - -static XEXT_GENERATE_ERROR_STRING (xv_error_string, xv_extension_name, - XvNumErrors, xv_error_list) - -struct _EphyrHostXVAdaptorArray { - XvAdaptorInfo *adaptors ; - unsigned int nb_adaptors ; -}; - -/*heavily copied from libx11*/ -#define BUFSIZE 2048 -static void -ephyrHostXVLogXErrorEvent (Display *a_display, - XErrorEvent *a_err_event, - FILE *a_fp) -{ - char buffer[BUFSIZ]; - char mesg[BUFSIZ]; - char number[32]; - const char *mtype = "XlibMessage"; - register _XExtension *ext = (_XExtension *)NULL; - _XExtension *bext = (_XExtension *)NULL; - Display *dpy = a_display ; - - XGetErrorText(dpy, a_err_event->error_code, buffer, BUFSIZ); - XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ); - (void) fprintf(a_fp, "%s: %s\n ", mesg, buffer); - XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", - mesg, BUFSIZ); - (void) fprintf(a_fp, mesg, a_err_event->request_code); - if (a_err_event->request_code < 128) { - sprintf(number, "%d", a_err_event->request_code); - XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ); - } else { - for (ext = dpy->ext_procs; - ext && (ext->codes.major_opcode != a_err_event->request_code); - ext = ext->next) - ; - if (ext) - strcpy(buffer, ext->name); - else - buffer[0] = '\0'; - } - (void) fprintf(a_fp, " (%s)\n", buffer); - if (a_err_event->request_code >= 128) { - XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d", - mesg, BUFSIZ); - fputs(" ", a_fp); - (void) fprintf(a_fp, mesg, a_err_event->minor_code); - if (ext) { - sprintf(mesg, "%s.%d", ext->name, a_err_event->minor_code); - XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ); - (void) fprintf(a_fp, " (%s)", buffer); - } - fputs("\n", a_fp); - } - if (a_err_event->error_code >= 128) { - /* kludge, try to find the extension that caused it */ - buffer[0] = '\0'; - for (ext = dpy->ext_procs; ext; ext = ext->next) { - if (ext->error_string) - (*ext->error_string)(dpy, a_err_event->error_code, &ext->codes, - buffer, BUFSIZ); - if (buffer[0]) { - bext = ext; - break; - } - if (ext->codes.first_error && - ext->codes.first_error < (int)a_err_event->error_code && - (!bext || ext->codes.first_error > bext->codes.first_error)) - bext = ext; - } - if (bext) - sprintf(buffer, "%s.%d", bext->name, - a_err_event->error_code - bext->codes.first_error); - else - strcpy(buffer, "Value"); - XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ); - if (mesg[0]) { - fputs(" ", a_fp); - (void) fprintf(a_fp, mesg, a_err_event->resourceid); - fputs("\n", a_fp); - } - /* let extensions try to print the values */ - for (ext = dpy->ext_procs; ext; ext = ext->next) { - if (ext->error_values) - (*ext->error_values)(dpy, a_err_event, a_fp); - } - } else if ((a_err_event->error_code == BadWindow) || - (a_err_event->error_code == BadPixmap) || - (a_err_event->error_code == BadCursor) || - (a_err_event->error_code == BadFont) || - (a_err_event->error_code == BadDrawable) || - (a_err_event->error_code == BadColor) || - (a_err_event->error_code == BadGC) || - (a_err_event->error_code == BadIDChoice) || - (a_err_event->error_code == BadValue) || - (a_err_event->error_code == BadAtom)) { - if (a_err_event->error_code == BadValue) - XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x", - mesg, BUFSIZ); - else if (a_err_event->error_code == BadAtom) - XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x", - mesg, BUFSIZ); - else - XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x", - mesg, BUFSIZ); - fputs(" ", a_fp); - (void) fprintf(a_fp, mesg, a_err_event->resourceid); - fputs("\n", a_fp); - } - XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", - mesg, BUFSIZ); - fputs(" ", a_fp); - (void) fprintf(a_fp, mesg, a_err_event->serial); - XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d", - mesg, BUFSIZ); - fputs("\n ", a_fp); - (void) fprintf(a_fp, mesg, dpy->request); - fputs("\n", a_fp); -} - -static int -ephyrHostXVErrorHandler (Display *a_display, - XErrorEvent *a_error_event) -{ - EPHYR_LOG_ERROR ("got an error from the host xserver:\n") ; - ephyrHostXVLogXErrorEvent (a_display, a_error_event, stderr) ; - return Success ; -} - -void -ephyrHostXVInit (void) -{ - static Bool s_initialized ; - - if (s_initialized) - return ; - XSetErrorHandler (ephyrHostXVErrorHandler) ; - s_initialized = TRUE ; -} - -Bool -ephyrHostXVQueryAdaptors (EphyrHostXVAdaptorArray **a_adaptors) -{ - EphyrHostXVAdaptorArray *result=NULL ; - int ret=0 ; - Bool is_ok=FALSE ; - - EPHYR_RETURN_VAL_IF_FAIL (a_adaptors, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - result = Xcalloc (1, sizeof (EphyrHostXVAdaptorArray)) ; - if (!result) - goto out ; - - ret = XvQueryAdaptors (hostx_get_display (), - DefaultRootWindow (hostx_get_display ()), - &result->nb_adaptors, - &result->adaptors) ; - if (ret != Success) { - EPHYR_LOG_ERROR ("failed to query host adaptors: %d\n", ret) ; - goto out ; - } - *a_adaptors = result ; - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -void -ephyrHostXVAdaptorArrayDelete (EphyrHostXVAdaptorArray *a_adaptors) -{ - if (!a_adaptors) - return ; - if (a_adaptors->adaptors) { - XvFreeAdaptorInfo (a_adaptors->adaptors) ; - a_adaptors->adaptors = NULL ; - a_adaptors->nb_adaptors = 0 ; - } - XFree (a_adaptors) ; -} - -int -ephyrHostXVAdaptorArrayGetSize (const EphyrHostXVAdaptorArray *a_this) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; - return a_this->nb_adaptors ; -} - -EphyrHostXVAdaptor* -ephyrHostXVAdaptorArrayAt (const EphyrHostXVAdaptorArray *a_this, - int a_index) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; - - if (a_index >= a_this->nb_adaptors) - return NULL ; - return (EphyrHostXVAdaptor*)&a_this->adaptors[a_index] ; -} - -char -ephyrHostXVAdaptorGetType (const EphyrHostXVAdaptor *a_this) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; - return ((XvAdaptorInfo*)a_this)->type ; -} - -const char* -ephyrHostXVAdaptorGetName (const EphyrHostXVAdaptor *a_this) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; - - return ((XvAdaptorInfo*)a_this)->name ; -} - -EphyrHostVideoFormat* -ephyrHostXVAdaptorGetVideoFormats (const EphyrHostXVAdaptor *a_this, - int *a_nb_formats) -{ - EphyrHostVideoFormat *formats=NULL ; - int nb_formats=0, i=0 ; - XVisualInfo *visual_info, visual_info_template ; - int nb_visual_info ; - - EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; - - nb_formats = ((XvAdaptorInfo*)a_this)->num_formats ; - formats = Xcalloc (nb_formats, sizeof (EphyrHostVideoFormat)) ; - for (i=0; i < nb_formats; i++) { - memset (&visual_info_template, 0, sizeof (visual_info_template)) ; - visual_info_template.visualid = - ((XvAdaptorInfo*)a_this)->formats[i].visual_id; - visual_info = XGetVisualInfo (hostx_get_display (), - VisualIDMask, - &visual_info_template, - &nb_visual_info) ; - formats[i].depth = ((XvAdaptorInfo*)a_this)->formats[i].depth ; - formats[i].visual_class = visual_info->class ; - XFree (visual_info) ; - } - if (a_nb_formats) - *a_nb_formats = nb_formats ; - return formats ; -} - -int -ephyrHostXVAdaptorGetNbPorts (const EphyrHostXVAdaptor *a_this) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; - - return ((XvAdaptorInfo*)a_this)->num_ports ; -} - -int -ephyrHostXVAdaptorGetFirstPortID (const EphyrHostXVAdaptor *a_this) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; - - return ((XvAdaptorInfo*)a_this)->base_id ; -} - -Bool -ephyrHostXVAdaptorHasPutVideo (const EphyrHostXVAdaptor *a_this, - Bool *a_result) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; - - if (((XvAdaptorInfo*)a_this)->type & XvVideoMask & XvInputMask) - *a_result = TRUE ; - else - *a_result = FALSE ; - return TRUE ; -} - -Bool -ephyrHostXVAdaptorHasGetVideo (const EphyrHostXVAdaptor *a_this, - Bool *a_result) -{ - if (((XvAdaptorInfo*)a_this)->type & XvVideoMask & XvOutputMask) - *a_result = TRUE ; - else - *a_result = FALSE ; - return TRUE ; -} - -Bool -ephyrHostXVAdaptorHasPutStill (const EphyrHostXVAdaptor *a_this, - Bool *a_result) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; - - if (((XvAdaptorInfo*)a_this)->type & XvStillMask && XvInputMask) - *a_result = TRUE ; - else - *a_result = FALSE ; - return TRUE ; -} - -Bool -ephyrHostXVAdaptorHasGetStill (const EphyrHostXVAdaptor *a_this, - Bool *a_result) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; - - if (((XvAdaptorInfo*)a_this)->type & XvStillMask && XvOutputMask) - *a_result = TRUE ; - else - *a_result = FALSE ; - return TRUE ; -} - -Bool -ephyrHostXVAdaptorHasPutImage (const EphyrHostXVAdaptor *a_this, - Bool *a_result) -{ - EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; - - if (((XvAdaptorInfo*)a_this)->type & XvImageMask && XvInputMask) - *a_result = TRUE ; - else - *a_result = FALSE ; - return TRUE ; -} - -Bool -ephyrHostXVQueryEncodings (int a_port_id, - EphyrHostEncoding **a_encodings, - unsigned int *a_num_encodings) -{ - EphyrHostEncoding *encodings=NULL ; - XvEncodingInfo *encoding_info=NULL ; - unsigned int num_encodings=0, i; - int ret=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, FALSE) ; - - ret = XvQueryEncodings (hostx_get_display (), - a_port_id, - &num_encodings, - &encoding_info) ; - if (num_encodings && encoding_info) { - encodings = Xcalloc (num_encodings, sizeof (EphyrHostEncoding)) ; - for (i=0; iu.u.type & 0x7F) - info->codes->first_event) { - case XvVideoNotify: - re->xvvideo.type = event->u.u.type & 0x7f; - re->xvvideo.serial = - _XSetLastRequestRead(dpy, (xGenericReply *)event); - re->xvvideo.send_event = ((event->u.u.type & 0x80) != 0); - re->xvvideo.display = dpy; - re->xvvideo.time = event->u.videoNotify.time; - re->xvvideo.reason = event->u.videoNotify.reason; - re->xvvideo.drawable = event->u.videoNotify.drawable; - re->xvvideo.port_id = event->u.videoNotify.port; - break; - case XvPortNotify: - re->xvport.type = event->u.u.type & 0x7f; - re->xvport.serial = - _XSetLastRequestRead(dpy, (xGenericReply *)event); - re->xvport.send_event = ((event->u.u.type & 0x80) != 0); - re->xvport.display = dpy; - re->xvport.time = event->u.portNotify.time; - re->xvport.port_id = event->u.portNotify.port; - re->xvport.attribute = event->u.portNotify.attribute; - re->xvport.value = event->u.portNotify.value; - break; - default: - return False; - } - - return True ; -} - -Bool -ephyrHostXVQueryImageAttributes (int a_port_id, - int a_image_id /*image fourcc code*/, - unsigned short *a_width, - unsigned short *a_height, - int *a_image_size, - int *a_pitches, - int *a_offsets) -{ - Display *dpy = hostx_get_display () ; - Bool ret=FALSE ; - XExtDisplayInfo *info = xv_find_display (dpy); - xvQueryImageAttributesReq *req=NULL; - xvQueryImageAttributesReply rep; - - EPHYR_RETURN_VAL_IF_FAIL (a_width, FALSE) ; - EPHYR_RETURN_VAL_IF_FAIL (a_height, FALSE) ; - EPHYR_RETURN_VAL_IF_FAIL (a_image_size, FALSE) ; - - XvCheckExtension (dpy, info, FALSE); - - LockDisplay (dpy); - - XvGetReq (QueryImageAttributes, req); - req->id = a_image_id; - req->port = a_port_id; - req->width = *a_width; - req->height = *a_height; - /* - * read the reply - */ - if (!_XReply (dpy, (xReply *)&rep, 0, xFalse)) { - EPHYR_LOG_ERROR ("QeryImageAttribute req failed\n") ; - goto out ; - } - if (a_pitches && a_offsets) { - _XRead (dpy, - (char*)a_pitches, - rep.num_planes << 2); - _XRead (dpy, - (char*)a_offsets, - rep.num_planes << 2); - } else { - _XEatData(dpy, rep.length << 2); - } - *a_width = rep.width ; - *a_height = rep.height ; - *a_image_size = rep.data_size ; - - ret = TRUE ; - -out: - UnlockDisplay (dpy) ; - SyncHandle (); - return ret ; -} - -Bool -ephyrHostGetAtom (const char* a_name, - Bool a_create_if_not_exists, - int *a_atom) -{ - int atom=None ; - - EPHYR_RETURN_VAL_IF_FAIL (a_atom, FALSE) ; - - atom = XInternAtom (hostx_get_display (), a_name, a_create_if_not_exists); - if (atom == None) { - return FALSE ; - } - *a_atom = atom ; - return TRUE ; -} - -char* -ephyrHostGetAtomName (int a_atom) -{ - return XGetAtomName (hostx_get_display (), a_atom) ; -} - -void -ephyrHostFree (void *a_pointer) -{ - if (a_pointer) - XFree (a_pointer) ; -} - -Bool -ephyrHostXVPutImage (int a_screen_num, - int a_port_id, - int a_image_id, - int a_drw_x, - int a_drw_y, - int a_drw_w, - int a_drw_h, - int a_src_x, - int a_src_y, - int a_src_w, - int a_src_h, - int a_image_width, - int a_image_height, - unsigned char *a_buf, - EphyrHostBox *a_clip_rects, - int a_clip_rect_nums ) -{ - Bool is_ok=TRUE ; - XvImage *xv_image=NULL ; - GC gc=0 ; - XGCValues gc_values; - Display *dpy = hostx_get_display () ; - XRectangle *rects=NULL ; - int res = 0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_buf, FALSE) ; - - EPHYR_LOG ("enter, num_clip_rects: %d\n", a_clip_rect_nums) ; - - memset (&gc_values, 0, sizeof (gc_values)) ; - gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); - if (!gc) { - EPHYR_LOG_ERROR ("failed to create gc \n") ; - goto out ; - } - xv_image = (XvImage*) XvCreateImage (hostx_get_display (), - a_port_id, a_image_id, - NULL, a_image_width, a_image_height) ; - if (!xv_image) { - EPHYR_LOG_ERROR ("failed to create image\n") ; - goto out ; - } - xv_image->data = (char*)a_buf ; - if (a_clip_rect_nums) { - int i=0 ; - rects = calloc (a_clip_rect_nums, sizeof (XRectangle)) ; - for (i=0; i < a_clip_rect_nums; i++) { - rects[i].x = a_clip_rects[i].x1 ; - rects[i].y = a_clip_rects[i].y1 ; - rects[i].width = a_clip_rects[i].x2 - a_clip_rects[i].x1; - rects[i].height = a_clip_rects[i].y2 - a_clip_rects[i].y1; - EPHYR_LOG ("(x,y,w,h): (%d,%d,%d,%d)\n", - rects[i].x, rects[i].y, - rects[i].width, rects[i].height) ; - } - XSetClipRectangles (dpy, gc, 0, 0, rects, a_clip_rect_nums, YXBanded) ; - /*this always returns 1*/ - } - res = XvPutImage (dpy, a_port_id, - hostx_get_window (a_screen_num), - gc, xv_image, - a_src_x, a_src_y, a_src_w, a_src_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; - if (res != Success) { - EPHYR_LOG_ERROR ("XvPutImage() failed: %d\n", res) ; - goto out ; - } - is_ok = TRUE ; - -out: - if (xv_image) { - XFree (xv_image) ; - xv_image = NULL ; - } - if (gc) { - XFreeGC (dpy, gc) ; - gc = NULL ; - } - if (rects) { - free (rects) ; - rects = NULL ; - } - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -Bool -ephyrHostXVPutVideo (int a_screen_num, int a_port_id, - int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, - int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) -{ - Bool is_ok=FALSE ; - int res=FALSE ; - GC gc=0 ; - XGCValues gc_values; - Display *dpy=hostx_get_display () ; - - EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; - - gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); - if (!gc) { - EPHYR_LOG_ERROR ("failed to create gc \n") ; - goto out ; - } - res = XvPutVideo (dpy, a_port_id, hostx_get_window (a_screen_num), gc, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; - - if (res != Success) { - EPHYR_LOG_ERROR ("XvPutVideo() failed: %d\n", res) ; - goto out ; - } - - is_ok = TRUE ; - -out: - if (gc) { - XFreeGC (dpy, gc) ; - gc = NULL ; - } - return is_ok ; -} - -Bool -ephyrHostXVGetVideo (int a_screen_num, int a_port_id, - int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, - int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) -{ - Bool is_ok=FALSE ; - int res=FALSE ; - GC gc=0 ; - XGCValues gc_values; - Display *dpy=hostx_get_display () ; - - EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; - - gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); - if (!gc) { - EPHYR_LOG_ERROR ("failed to create gc \n") ; - goto out ; - } - res = XvGetVideo (dpy, a_port_id, hostx_get_window (a_screen_num), gc, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; - - if (res != Success) { - EPHYR_LOG_ERROR ("XvGetVideo() failed: %d\n", res) ; - goto out ; - } - - is_ok = TRUE ; - -out: - if (gc) { - XFreeGC (dpy, gc) ; - gc = NULL ; - } - return is_ok ; -} - -Bool -ephyrHostXVPutStill (int a_screen_num, int a_port_id, - int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, - int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) -{ - Bool is_ok=FALSE ; - int res=FALSE ; - GC gc=0 ; - XGCValues gc_values; - Display *dpy=hostx_get_display () ; - - EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; - - gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); - if (!gc) { - EPHYR_LOG_ERROR ("failed to create gc \n") ; - goto out ; - } - res = XvPutStill (dpy, a_port_id, hostx_get_window (a_screen_num), gc, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; - - if (res != Success) { - EPHYR_LOG_ERROR ("XvPutStill() failed: %d\n", res) ; - goto out ; - } - - is_ok = TRUE ; - -out: - if (gc) { - XFreeGC (dpy, gc) ; - gc = NULL ; - } - return is_ok ; -} - -Bool -ephyrHostXVGetStill (int a_screen_num, int a_port_id, - int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, - int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) -{ - Bool is_ok=FALSE ; - int res=FALSE ; - GC gc=0 ; - XGCValues gc_values; - Display *dpy=hostx_get_display () ; - - EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; - - gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); - if (!gc) { - EPHYR_LOG_ERROR ("failed to create gc \n") ; - goto out ; - } - res = XvGetStill (dpy, a_port_id, hostx_get_window (a_screen_num), gc, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; - - if (res != Success) { - EPHYR_LOG_ERROR ("XvGetStill() failed: %d\n", res) ; - goto out ; - } - - is_ok = TRUE ; - -out: - if (gc) { - XFreeGC (dpy, gc) ; - gc = NULL ; - } - return is_ok ; -} - -Bool -ephyrHostXVStopVideo (int a_screen_num, int a_port_id) -{ - int ret=0 ; - Bool is_ok=FALSE ; - Display *dpy = hostx_get_display () ; - - EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - ret = XvStopVideo (dpy, a_port_id, hostx_get_window (a_screen_num)) ; - if (ret != Success) { - EPHYR_LOG_ERROR ("XvStopVideo() failed: %d \n", ret) ; - goto out ; - } - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - +/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum + * + * Copyright © 2007 OpenedHand Ltd + * + * 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 OpenedHand Ltd not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. OpenedHand Ltd makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Dodji Seketeli + */ +#ifdef HAVE_CONFIG_H +#include +#endif +/* + * including some server headers (like kdrive-config.h) + * might define the macro _XSERVER64 + * on 64 bits machines. That macro must _NOT_ be defined for Xlib + * client code, otherwise bad things happen. + * So let's undef that macro if necessary. + */ +#ifdef _XSERVER64 +#undef _XSERVER64 +#endif +#include +#include +#include +#include +#include +#include +#define _HAVE_XALLOC_DECLS + +#include "hostx.h" +#include "ephyrhostvideo.h" +#include "ephyrlog.h" + +#ifndef TRUE +#define TRUE 1 +#endif /*TRUE*/ + +#ifndef FALSE +#define FALSE 0 +#endif /*FALSE*/ + +static XExtensionInfo _xv_info_data; +static XExtensionInfo *xv_info = &_xv_info_data; +static char *xv_extension_name = XvName; +static char *xv_error_string(Display *dpy, int code, XExtCodes *codes, + char * buf, int n); +static int xv_close_display(Display *dpy, XExtCodes *codes); +static Bool xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire); + +static XExtensionHooks xv_extension_hooks = { + NULL, /* create_gc */ + NULL, /* copy_gc */ + NULL, /* flush_gc */ + NULL, /* free_gc */ + NULL, /* create_font */ + NULL, /* free_font */ + xv_close_display, /* close_display */ + xv_wire_to_event, /* wire_to_event */ + NULL, /* event_to_wire */ + NULL, /* error */ + xv_error_string /* error_string */ +}; + + +static char *xv_error_list[] = +{ + "BadPort", /* XvBadPort */ + "BadEncoding", /* XvBadEncoding */ + "BadControl" /* XvBadControl */ +}; + + +#define XvCheckExtension(dpy, i, val) \ + XextCheckExtension(dpy, i, xv_extension_name, val) +#define XvGetReq(name, req) \ + WORD64ALIGN\ + if ((dpy->bufptr + SIZEOF(xv##name##Req)) > dpy->bufmax)\ + _XFlush(dpy);\ + req = (xv##name##Req *)(dpy->last_req = dpy->bufptr);\ + req->reqType = info->codes->major_opcode;\ + req->xvReqType = xv_##name; \ + req->length = (SIZEOF(xv##name##Req))>>2;\ + dpy->bufptr += SIZEOF(xv##name##Req);\ + dpy->request++ + +static XEXT_GENERATE_CLOSE_DISPLAY (xv_close_display, xv_info) + + +static XEXT_GENERATE_FIND_DISPLAY (xv_find_display, xv_info, + xv_extension_name, + &xv_extension_hooks, + XvNumEvents, NULL) + +static XEXT_GENERATE_ERROR_STRING (xv_error_string, xv_extension_name, + XvNumErrors, xv_error_list) + +struct _EphyrHostXVAdaptorArray { + XvAdaptorInfo *adaptors ; + unsigned int nb_adaptors ; +}; + +/*heavily copied from libx11*/ +#define BUFSIZE 2048 +static void +ephyrHostXVLogXErrorEvent (Display *a_display, + XErrorEvent *a_err_event, + FILE *a_fp) +{ + char buffer[BUFSIZ]; + char mesg[BUFSIZ]; + char number[32]; + const char *mtype = "XlibMessage"; + register _XExtension *ext = (_XExtension *)NULL; + _XExtension *bext = (_XExtension *)NULL; + Display *dpy = a_display ; + + XGetErrorText(dpy, a_err_event->error_code, buffer, BUFSIZ); + XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ); + (void) fprintf(a_fp, "%s: %s\n ", mesg, buffer); + XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", + mesg, BUFSIZ); + (void) fprintf(a_fp, mesg, a_err_event->request_code); + if (a_err_event->request_code < 128) { + sprintf(number, "%d", a_err_event->request_code); + XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ); + } else { + for (ext = dpy->ext_procs; + ext && (ext->codes.major_opcode != a_err_event->request_code); + ext = ext->next) + ; + if (ext) + strcpy(buffer, ext->name); + else + buffer[0] = '\0'; + } + (void) fprintf(a_fp, " (%s)\n", buffer); + if (a_err_event->request_code >= 128) { + XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d", + mesg, BUFSIZ); + fputs(" ", a_fp); + (void) fprintf(a_fp, mesg, a_err_event->minor_code); + if (ext) { + sprintf(mesg, "%s.%d", ext->name, a_err_event->minor_code); + XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ); + (void) fprintf(a_fp, " (%s)", buffer); + } + fputs("\n", a_fp); + } + if (a_err_event->error_code >= 128) { + /* kludge, try to find the extension that caused it */ + buffer[0] = '\0'; + for (ext = dpy->ext_procs; ext; ext = ext->next) { + if (ext->error_string) + (*ext->error_string)(dpy, a_err_event->error_code, &ext->codes, + buffer, BUFSIZ); + if (buffer[0]) { + bext = ext; + break; + } + if (ext->codes.first_error && + ext->codes.first_error < (int)a_err_event->error_code && + (!bext || ext->codes.first_error > bext->codes.first_error)) + bext = ext; + } + if (bext) + sprintf(buffer, "%s.%d", bext->name, + a_err_event->error_code - bext->codes.first_error); + else + strcpy(buffer, "Value"); + XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ); + if (mesg[0]) { + fputs(" ", a_fp); + (void) fprintf(a_fp, mesg, a_err_event->resourceid); + fputs("\n", a_fp); + } + /* let extensions try to print the values */ + for (ext = dpy->ext_procs; ext; ext = ext->next) { + if (ext->error_values) + (*ext->error_values)(dpy, a_err_event, a_fp); + } + } else if ((a_err_event->error_code == BadWindow) || + (a_err_event->error_code == BadPixmap) || + (a_err_event->error_code == BadCursor) || + (a_err_event->error_code == BadFont) || + (a_err_event->error_code == BadDrawable) || + (a_err_event->error_code == BadColor) || + (a_err_event->error_code == BadGC) || + (a_err_event->error_code == BadIDChoice) || + (a_err_event->error_code == BadValue) || + (a_err_event->error_code == BadAtom)) { + if (a_err_event->error_code == BadValue) + XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x", + mesg, BUFSIZ); + else if (a_err_event->error_code == BadAtom) + XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x", + mesg, BUFSIZ); + else + XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x", + mesg, BUFSIZ); + fputs(" ", a_fp); + (void) fprintf(a_fp, mesg, a_err_event->resourceid); + fputs("\n", a_fp); + } + XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", + mesg, BUFSIZ); + fputs(" ", a_fp); + (void) fprintf(a_fp, mesg, a_err_event->serial); + XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d", + mesg, BUFSIZ); + fputs("\n ", a_fp); + (void) fprintf(a_fp, mesg, dpy->request); + fputs("\n", a_fp); +} + +static int +ephyrHostXVErrorHandler (Display *a_display, + XErrorEvent *a_error_event) +{ + EPHYR_LOG_ERROR ("got an error from the host xserver:\n") ; + ephyrHostXVLogXErrorEvent (a_display, a_error_event, stderr) ; + return Success ; +} + +void +ephyrHostXVInit (void) +{ + static Bool s_initialized ; + + if (s_initialized) + return ; + XSetErrorHandler (ephyrHostXVErrorHandler) ; + s_initialized = TRUE ; +} + +Bool +ephyrHostXVQueryAdaptors (EphyrHostXVAdaptorArray **a_adaptors) +{ + EphyrHostXVAdaptorArray *result=NULL ; + int ret=0 ; + Bool is_ok=FALSE ; + + EPHYR_RETURN_VAL_IF_FAIL (a_adaptors, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + result = Xcalloc (1, sizeof (EphyrHostXVAdaptorArray)) ; + if (!result) + goto out ; + + ret = XvQueryAdaptors (hostx_get_display (), + DefaultRootWindow (hostx_get_display ()), + &result->nb_adaptors, + &result->adaptors) ; + if (ret != Success) { + EPHYR_LOG_ERROR ("failed to query host adaptors: %d\n", ret) ; + goto out ; + } + *a_adaptors = result ; + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +void +ephyrHostXVAdaptorArrayDelete (EphyrHostXVAdaptorArray *a_adaptors) +{ + if (!a_adaptors) + return ; + if (a_adaptors->adaptors) { + XvFreeAdaptorInfo (a_adaptors->adaptors) ; + a_adaptors->adaptors = NULL ; + a_adaptors->nb_adaptors = 0 ; + } + XFree (a_adaptors) ; +} + +int +ephyrHostXVAdaptorArrayGetSize (const EphyrHostXVAdaptorArray *a_this) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; + return a_this->nb_adaptors ; +} + +EphyrHostXVAdaptor* +ephyrHostXVAdaptorArrayAt (const EphyrHostXVAdaptorArray *a_this, + int a_index) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; + + if (a_index >= a_this->nb_adaptors) + return NULL ; + return (EphyrHostXVAdaptor*)&a_this->adaptors[a_index] ; +} + +char +ephyrHostXVAdaptorGetType (const EphyrHostXVAdaptor *a_this) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; + return ((XvAdaptorInfo*)a_this)->type ; +} + +const char* +ephyrHostXVAdaptorGetName (const EphyrHostXVAdaptor *a_this) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; + + return ((XvAdaptorInfo*)a_this)->name ; +} + +EphyrHostVideoFormat* +ephyrHostXVAdaptorGetVideoFormats (const EphyrHostXVAdaptor *a_this, + int *a_nb_formats) +{ + EphyrHostVideoFormat *formats=NULL ; + int nb_formats=0, i=0 ; + XVisualInfo *visual_info, visual_info_template ; + int nb_visual_info ; + + EPHYR_RETURN_VAL_IF_FAIL (a_this, NULL) ; + + nb_formats = ((XvAdaptorInfo*)a_this)->num_formats ; + formats = Xcalloc (nb_formats, sizeof (EphyrHostVideoFormat)) ; + for (i=0; i < nb_formats; i++) { + memset (&visual_info_template, 0, sizeof (visual_info_template)) ; + visual_info_template.visualid = + ((XvAdaptorInfo*)a_this)->formats[i].visual_id; + visual_info = XGetVisualInfo (hostx_get_display (), + VisualIDMask, + &visual_info_template, + &nb_visual_info) ; + formats[i].depth = ((XvAdaptorInfo*)a_this)->formats[i].depth ; + formats[i].visual_class = visual_info->class ; + XFree (visual_info) ; + } + if (a_nb_formats) + *a_nb_formats = nb_formats ; + return formats ; +} + +int +ephyrHostXVAdaptorGetNbPorts (const EphyrHostXVAdaptor *a_this) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; + + return ((XvAdaptorInfo*)a_this)->num_ports ; +} + +int +ephyrHostXVAdaptorGetFirstPortID (const EphyrHostXVAdaptor *a_this) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this, -1) ; + + return ((XvAdaptorInfo*)a_this)->base_id ; +} + +Bool +ephyrHostXVAdaptorHasPutVideo (const EphyrHostXVAdaptor *a_this, + Bool *a_result) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; + + if (((XvAdaptorInfo*)a_this)->type & XvVideoMask & XvInputMask) + *a_result = TRUE ; + else + *a_result = FALSE ; + return TRUE ; +} + +Bool +ephyrHostXVAdaptorHasGetVideo (const EphyrHostXVAdaptor *a_this, + Bool *a_result) +{ + if (((XvAdaptorInfo*)a_this)->type & XvVideoMask & XvOutputMask) + *a_result = TRUE ; + else + *a_result = FALSE ; + return TRUE ; +} + +Bool +ephyrHostXVAdaptorHasPutStill (const EphyrHostXVAdaptor *a_this, + Bool *a_result) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; + + if (((XvAdaptorInfo*)a_this)->type & XvStillMask && XvInputMask) + *a_result = TRUE ; + else + *a_result = FALSE ; + return TRUE ; +} + +Bool +ephyrHostXVAdaptorHasGetStill (const EphyrHostXVAdaptor *a_this, + Bool *a_result) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; + + if (((XvAdaptorInfo*)a_this)->type & XvStillMask && XvOutputMask) + *a_result = TRUE ; + else + *a_result = FALSE ; + return TRUE ; +} + +Bool +ephyrHostXVAdaptorHasPutImage (const EphyrHostXVAdaptor *a_this, + Bool *a_result) +{ + EPHYR_RETURN_VAL_IF_FAIL (a_this && a_result, FALSE) ; + + if (((XvAdaptorInfo*)a_this)->type & XvImageMask && XvInputMask) + *a_result = TRUE ; + else + *a_result = FALSE ; + return TRUE ; +} + +Bool +ephyrHostXVQueryEncodings (int a_port_id, + EphyrHostEncoding **a_encodings, + unsigned int *a_num_encodings) +{ + EphyrHostEncoding *encodings=NULL ; + XvEncodingInfo *encoding_info=NULL ; + unsigned int num_encodings=0, i; + int ret=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, FALSE) ; + + ret = XvQueryEncodings (hostx_get_display (), + a_port_id, + &num_encodings, + &encoding_info) ; + if (num_encodings && encoding_info) { + encodings = Xcalloc (num_encodings, sizeof (EphyrHostEncoding)) ; + for (i=0; iu.u.type & 0x7F) - info->codes->first_event) { + case XvVideoNotify: + re->xvvideo.type = event->u.u.type & 0x7f; + re->xvvideo.serial = + _XSetLastRequestRead(dpy, (xGenericReply *)event); + re->xvvideo.send_event = ((event->u.u.type & 0x80) != 0); + re->xvvideo.display = dpy; + re->xvvideo.time = event->u.videoNotify.time; + re->xvvideo.reason = event->u.videoNotify.reason; + re->xvvideo.drawable = event->u.videoNotify.drawable; + re->xvvideo.port_id = event->u.videoNotify.port; + break; + case XvPortNotify: + re->xvport.type = event->u.u.type & 0x7f; + re->xvport.serial = + _XSetLastRequestRead(dpy, (xGenericReply *)event); + re->xvport.send_event = ((event->u.u.type & 0x80) != 0); + re->xvport.display = dpy; + re->xvport.time = event->u.portNotify.time; + re->xvport.port_id = event->u.portNotify.port; + re->xvport.attribute = event->u.portNotify.attribute; + re->xvport.value = event->u.portNotify.value; + break; + default: + return False; + } + + return True ; +} + +Bool +ephyrHostXVQueryImageAttributes (int a_port_id, + int a_image_id /*image fourcc code*/, + unsigned short *a_width, + unsigned short *a_height, + int *a_image_size, + int *a_pitches, + int *a_offsets) +{ + Display *dpy = hostx_get_display () ; + Bool ret=FALSE ; + XExtDisplayInfo *info = xv_find_display (dpy); + xvQueryImageAttributesReq *req=NULL; + xvQueryImageAttributesReply rep; + + EPHYR_RETURN_VAL_IF_FAIL (a_width, FALSE) ; + EPHYR_RETURN_VAL_IF_FAIL (a_height, FALSE) ; + EPHYR_RETURN_VAL_IF_FAIL (a_image_size, FALSE) ; + + XvCheckExtension (dpy, info, FALSE); + + LockDisplay (dpy); + + XvGetReq (QueryImageAttributes, req); + req->id = a_image_id; + req->port = a_port_id; + req->width = *a_width; + req->height = *a_height; + /* + * read the reply + */ + if (!_XReply (dpy, (xReply *)&rep, 0, xFalse)) { + EPHYR_LOG_ERROR ("QeryImageAttribute req failed\n") ; + goto out ; + } + if (a_pitches && a_offsets) { + _XRead (dpy, + (char*)a_pitches, + rep.num_planes << 2); + _XRead (dpy, + (char*)a_offsets, + rep.num_planes << 2); + } else { + _XEatData(dpy, rep.length << 2); + } + *a_width = rep.width ; + *a_height = rep.height ; + *a_image_size = rep.data_size ; + + ret = TRUE ; + +out: + UnlockDisplay (dpy) ; + SyncHandle (); + return ret ; +} + +Bool +ephyrHostGetAtom (const char* a_name, + Bool a_create_if_not_exists, + int *a_atom) +{ + int atom=None ; + + EPHYR_RETURN_VAL_IF_FAIL (a_atom, FALSE) ; + + atom = XInternAtom (hostx_get_display (), a_name, a_create_if_not_exists); + if (atom == None) { + return FALSE ; + } + *a_atom = atom ; + return TRUE ; +} + +char* +ephyrHostGetAtomName (int a_atom) +{ + return XGetAtomName (hostx_get_display (), a_atom) ; +} + +void +ephyrHostFree (void *a_pointer) +{ + if (a_pointer) + XFree (a_pointer) ; +} + +Bool +ephyrHostXVPutImage (int a_screen_num, + int a_port_id, + int a_image_id, + int a_drw_x, + int a_drw_y, + int a_drw_w, + int a_drw_h, + int a_src_x, + int a_src_y, + int a_src_w, + int a_src_h, + int a_image_width, + int a_image_height, + unsigned char *a_buf, + EphyrHostBox *a_clip_rects, + int a_clip_rect_nums ) +{ + Bool is_ok=TRUE ; + XvImage *xv_image=NULL ; + GC gc=0 ; + XGCValues gc_values; + Display *dpy = hostx_get_display () ; + XRectangle *rects=NULL ; + int res = 0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_buf, FALSE) ; + + EPHYR_LOG ("enter, num_clip_rects: %d\n", a_clip_rect_nums) ; + + memset (&gc_values, 0, sizeof (gc_values)) ; + gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); + if (!gc) { + EPHYR_LOG_ERROR ("failed to create gc \n") ; + goto out ; + } + xv_image = (XvImage*) XvCreateImage (hostx_get_display (), + a_port_id, a_image_id, + NULL, a_image_width, a_image_height) ; + if (!xv_image) { + EPHYR_LOG_ERROR ("failed to create image\n") ; + goto out ; + } + xv_image->data = (char*)a_buf ; + if (a_clip_rect_nums) { + int i=0 ; + rects = calloc (a_clip_rect_nums, sizeof (XRectangle)) ; + for (i=0; i < a_clip_rect_nums; i++) { + rects[i].x = a_clip_rects[i].x1 ; + rects[i].y = a_clip_rects[i].y1 ; + rects[i].width = a_clip_rects[i].x2 - a_clip_rects[i].x1; + rects[i].height = a_clip_rects[i].y2 - a_clip_rects[i].y1; + EPHYR_LOG ("(x,y,w,h): (%d,%d,%d,%d)\n", + rects[i].x, rects[i].y, + rects[i].width, rects[i].height) ; + } + XSetClipRectangles (dpy, gc, 0, 0, rects, a_clip_rect_nums, YXBanded) ; + /*this always returns 1*/ + } + res = XvPutImage (dpy, a_port_id, + hostx_get_window (a_screen_num), + gc, xv_image, + a_src_x, a_src_y, a_src_w, a_src_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; + if (res != Success) { + EPHYR_LOG_ERROR ("XvPutImage() failed: %d\n", res) ; + goto out ; + } + is_ok = TRUE ; + +out: + if (xv_image) { + XFree (xv_image) ; + xv_image = NULL ; + } + if (gc) { + XFreeGC (dpy, gc) ; + gc = NULL ; + } + if (rects) { + free (rects) ; + rects = NULL ; + } + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +Bool +ephyrHostXVPutVideo (int a_screen_num, int a_port_id, + int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, + int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) +{ + Bool is_ok=FALSE ; + int res=FALSE ; + GC gc=0 ; + XGCValues gc_values; + Display *dpy=hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + + gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); + if (!gc) { + EPHYR_LOG_ERROR ("failed to create gc \n") ; + goto out ; + } + res = XvPutVideo (dpy, a_port_id, hostx_get_window (a_screen_num), gc, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; + + if (res != Success) { + EPHYR_LOG_ERROR ("XvPutVideo() failed: %d\n", res) ; + goto out ; + } + + is_ok = TRUE ; + +out: + if (gc) { + XFreeGC (dpy, gc) ; + gc = NULL ; + } + return is_ok ; +} + +Bool +ephyrHostXVGetVideo (int a_screen_num, int a_port_id, + int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, + int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) +{ + Bool is_ok=FALSE ; + int res=FALSE ; + GC gc=0 ; + XGCValues gc_values; + Display *dpy=hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + + gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); + if (!gc) { + EPHYR_LOG_ERROR ("failed to create gc \n") ; + goto out ; + } + res = XvGetVideo (dpy, a_port_id, hostx_get_window (a_screen_num), gc, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; + + if (res != Success) { + EPHYR_LOG_ERROR ("XvGetVideo() failed: %d\n", res) ; + goto out ; + } + + is_ok = TRUE ; + +out: + if (gc) { + XFreeGC (dpy, gc) ; + gc = NULL ; + } + return is_ok ; +} + +Bool +ephyrHostXVPutStill (int a_screen_num, int a_port_id, + int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, + int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) +{ + Bool is_ok=FALSE ; + int res=FALSE ; + GC gc=0 ; + XGCValues gc_values; + Display *dpy=hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + + gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); + if (!gc) { + EPHYR_LOG_ERROR ("failed to create gc \n") ; + goto out ; + } + res = XvPutStill (dpy, a_port_id, hostx_get_window (a_screen_num), gc, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; + + if (res != Success) { + EPHYR_LOG_ERROR ("XvPutStill() failed: %d\n", res) ; + goto out ; + } + + is_ok = TRUE ; + +out: + if (gc) { + XFreeGC (dpy, gc) ; + gc = NULL ; + } + return is_ok ; +} + +Bool +ephyrHostXVGetStill (int a_screen_num, int a_port_id, + int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h, + int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h) +{ + Bool is_ok=FALSE ; + int res=FALSE ; + GC gc=0 ; + XGCValues gc_values; + Display *dpy=hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + + gc = XCreateGC (dpy, hostx_get_window (a_screen_num), 0L, &gc_values); + if (!gc) { + EPHYR_LOG_ERROR ("failed to create gc \n") ; + goto out ; + } + res = XvGetStill (dpy, a_port_id, hostx_get_window (a_screen_num), gc, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h) ; + + if (res != Success) { + EPHYR_LOG_ERROR ("XvGetStill() failed: %d\n", res) ; + goto out ; + } + + is_ok = TRUE ; + +out: + if (gc) { + XFreeGC (dpy, gc) ; + gc = NULL ; + } + return is_ok ; +} + +Bool +ephyrHostXVStopVideo (int a_screen_num, int a_port_id) +{ + int ret=0 ; + Bool is_ok=FALSE ; + Display *dpy = hostx_get_display () ; + + EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + ret = XvStopVideo (dpy, a_port_id, hostx_get_window (a_screen_num)) ; + if (ret != Success) { + EPHYR_LOG_ERROR ("XvStopVideo() failed: %d \n", ret) ; + goto out ; + } + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + diff --git a/xorg-server/hw/kdrive/ephyr/ephyrvideo.c b/xorg-server/hw/kdrive/ephyr/ephyrvideo.c index 6624ab98a..14213c966 100644 --- a/xorg-server/hw/kdrive/ephyr/ephyrvideo.c +++ b/xorg-server/hw/kdrive/ephyr/ephyrvideo.c @@ -1,1273 +1,1273 @@ -/* - * Xephyr - A kdrive X server thats runs in a host X window. - * Authored by Matthew Allum - * - * Copyright © 2007 OpenedHand Ltd - * - * 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 OpenedHand Ltd not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. OpenedHand Ltd makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - * - * Authors: - * Dodji Seketeli - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#include -#include "ephyrlog.h" -#include "kdrive.h" -#include "kxv.h" -#include "ephyr.h" -#include "hostx.h" -#include "ephyrhostvideo.h" - -struct _EphyrXVPriv { - EphyrHostXVAdaptorArray *host_adaptors ; - KdVideoAdaptorPtr adaptors ; - int num_adaptors ; -}; -typedef struct _EphyrXVPriv EphyrXVPriv ; - -struct _EphyrPortPriv { - int port_number ; - KdVideoAdaptorPtr current_adaptor ; - EphyrXVPriv *xv_priv; - unsigned char *image_buf ; - int image_buf_size ; - int image_id ; - int drw_x, drw_y, drw_w, drw_h ; - int src_x, src_y, src_w, src_h ; - int image_width, image_height ; -}; -typedef struct _EphyrPortPriv EphyrPortPriv ; - -static Bool DoSimpleClip (BoxPtr a_dst_drw, - BoxPtr a_clipper, - BoxPtr a_result) ; - -static Bool ephyrLocalAtomToHost (int a_local_atom, int *a_host_atom) ; - -/* -static Bool ephyrHostAtomToLocal (int a_host_atom, int *a_local_atom) ; -*/ - -static EphyrXVPriv* ephyrXVPrivNew (void) ; -static void ephyrXVPrivDelete (EphyrXVPriv *a_this) ; -static Bool ephyrXVPrivQueryHostAdaptors (EphyrXVPriv *a_this) ; -static Bool ephyrXVPrivSetAdaptorsHooks (EphyrXVPriv *a_this) ; -static Bool ephyrXVPrivRegisterAdaptors (EphyrXVPriv *a_this, - ScreenPtr a_screen) ; - -static Bool ephyrXVPrivIsAttrValueValid (KdAttributePtr a_attrs, - int a_attrs_len, - const char *a_attr_name, - int a_attr_value, - Bool *a_is_valid) ; - -static Bool ephyrXVPrivGetImageBufSize (int a_port_id, - int a_image_id, - unsigned short a_width, - unsigned short a_height, - int *a_size) ; - -static Bool ephyrXVPrivSaveImageToPortPriv (EphyrPortPriv *a_port_priv, - const unsigned char *a_image, - int a_image_len) ; - -static void ephyrStopVideo (KdScreenInfo *a_info, - pointer a_xv_priv, - Bool a_exit); - -static int ephyrSetPortAttribute (KdScreenInfo *a_info, - Atom a_attr_name, - int a_attr_value, - pointer a_port_priv); - -static int ephyrGetPortAttribute (KdScreenInfo *a_screen_info, - Atom a_attr_name, - int *a_attr_value, - pointer a_port_priv); - -static void ephyrQueryBestSize (KdScreenInfo *a_info, - Bool a_motion, - short a_src_w, - short a_src_h, - short a_drw_w, - short a_drw_h, - unsigned int *a_prefered_w, - unsigned int *a_prefered_h, - pointer a_port_priv); - -static int ephyrPutImage (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_src_x, - short a_src_y, - short a_drw_x, - short a_drw_y, - short a_src_w, - short a_src_h, - short a_drw_w, - short a_drw_h, - int a_id, - unsigned char *a_buf, - short a_width, - short a_height, - Bool a_sync, - RegionPtr a_clipping_region, - pointer a_port_priv); - -static int ephyrReputImage (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_drw_x, - short a_drw_y, - RegionPtr a_clipping_region, - pointer a_port_priv) ; - -static int ephyrPutVideo (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clip_region, - pointer a_port_priv) ; - -static int ephyrGetVideo (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clip_region, - pointer a_port_priv) ; - -static int ephyrPutStill (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clip_region, - pointer a_port_priv) ; - -static int ephyrGetStill (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clip_region, - pointer a_port_priv) ; - -static int ephyrQueryImageAttributes (KdScreenInfo *a_info, - int a_id, - unsigned short *a_w, - unsigned short *a_h, - int *a_pitches, - int *a_offsets); -static int s_base_port_id ; - -/************** - * - * ************/ - -static Bool -DoSimpleClip (BoxPtr a_dst_box, - BoxPtr a_clipper, - BoxPtr a_result) -{ - BoxRec dstClippedBox ; - - EPHYR_RETURN_VAL_IF_FAIL (a_dst_box && a_clipper && a_result, FALSE) ; - - /* - * setup the clipbox inside the destination. - */ - dstClippedBox.x1 = a_dst_box->x1 ; - dstClippedBox.x2 = a_dst_box->x2 ; - dstClippedBox.y1 = a_dst_box->y1 ; - dstClippedBox.y2 = a_dst_box->y2 ; - - /* - * if the cliper leftmost edge is inside - * the destination area then the leftmost edge of the resulting - * clipped box is the leftmost edge of the cliper. - */ - if (a_clipper->x1 > dstClippedBox.x1) - dstClippedBox.x1 = a_clipper->x1 ; - - /* - * if the cliper top edge is inside the destination area - * then the bottom horizontal edge of the resulting clipped box - * is the bottom edge of the cliper - */ - if (a_clipper->y1 > dstClippedBox.y1) - dstClippedBox.y1 = a_clipper->y1 ; - - /*ditto for right edge*/ - if (a_clipper->x2 < dstClippedBox.x2) - dstClippedBox.x2 = a_clipper->x2 ; - - /*ditto for bottom edge*/ - if (a_clipper->y2 < dstClippedBox.y2) - dstClippedBox.y2 = a_clipper->y2 ; - - memcpy (a_result, &dstClippedBox, sizeof (dstClippedBox)) ; - return TRUE ; -} - -static Bool -ephyrLocalAtomToHost (int a_local_atom, int *a_host_atom) -{ - const char *atom_name=NULL; - int host_atom=None ; - - EPHYR_RETURN_VAL_IF_FAIL (a_host_atom, FALSE) ; - - if (!ValidAtom (a_local_atom)) - return FALSE ; - - atom_name = NameForAtom (a_local_atom) ; - - if (!atom_name) - return FALSE ; - - if (!ephyrHostGetAtom (atom_name, FALSE, &host_atom) || host_atom == None) { - EPHYR_LOG_ERROR ("no atom for string %s defined in host X\n", - atom_name) ; - return FALSE ; - } - *a_host_atom = host_atom ; - return TRUE ; -} - -/* - Not used yed. -static Bool -ephyrHostAtomToLocal (int a_host_atom, int *a_local_atom) -{ - Bool is_ok=FALSE ; - char *atom_name=NULL ; - int atom=None ; - - EPHYR_RETURN_VAL_IF_FAIL (a_local_atom, FALSE) ; - - atom_name = ephyrHostGetAtomName (a_host_atom) ; - if (!atom_name) - goto out ; - - atom = MakeAtom (atom_name, strlen (atom_name), TRUE) ; - if (atom == None) - goto out ; - - *a_local_atom = atom ; - is_ok = TRUE ; - -out: - if (atom_name) { - ephyrHostFree (atom_name) ; - } - return is_ok ; -} -*/ - -/************** - * - * ************/ - -Bool -ephyrInitVideo (ScreenPtr pScreen) -{ - Bool is_ok = FALSE ; - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - static EphyrXVPriv *xv_priv; - - EPHYR_LOG ("enter\n") ; - - if (screen->fb.bitsPerPixel == 8) { - EPHYR_LOG_ERROR ("8 bits depth not supported\n") ; - return FALSE ; - } - - if (!xv_priv) { - xv_priv = ephyrXVPrivNew () ; - } - if (!xv_priv) { - EPHYR_LOG_ERROR ("failed to create xv_priv\n") ; - goto out ; - } - - if (!ephyrXVPrivRegisterAdaptors (xv_priv, pScreen)) { - EPHYR_LOG_ERROR ("failed to register adaptors\n") ; - goto out ; - } - is_ok = TRUE ; - -out: - return is_ok ; -} - -static EphyrXVPriv* -ephyrXVPrivNew (void) -{ - EphyrXVPriv *xv_priv=NULL ; - - EPHYR_LOG ("enter\n") ; - - xv_priv = xcalloc (1, sizeof (EphyrXVPriv)) ; - if (!xv_priv) { - EPHYR_LOG_ERROR ("failed to create EphyrXVPriv\n") ; - goto error ; - } - - ephyrHostXVInit () ; - - if (!ephyrXVPrivQueryHostAdaptors (xv_priv)) { - EPHYR_LOG_ERROR ("failed to query the host x for xv properties\n") ; - goto error ; - } - if (!ephyrXVPrivSetAdaptorsHooks (xv_priv)) { - EPHYR_LOG_ERROR ("failed to set xv_priv hooks\n") ; - goto error ; - } - - EPHYR_LOG ("leave\n") ; - return xv_priv ; - -error: - if (xv_priv) { - ephyrXVPrivDelete (xv_priv) ; - xv_priv = NULL ; - } - return NULL ; -} - -static void -ephyrXVPrivDelete (EphyrXVPriv *a_this) -{ - EPHYR_LOG ("enter\n") ; - - if (!a_this) - return ; - if (a_this->host_adaptors) { - ephyrHostXVAdaptorArrayDelete (a_this->host_adaptors) ; - a_this->host_adaptors = NULL ; - } - xfree (a_this->adaptors) ; - a_this->adaptors = NULL ; - xfree (a_this) ; - EPHYR_LOG ("leave\n") ; -} - -static KdVideoEncodingPtr -videoEncodingDup (EphyrHostEncoding *a_encodings, - int a_num_encodings) -{ - KdVideoEncodingPtr result = NULL ; - int i=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, NULL) ; - - result = xcalloc (a_num_encodings, sizeof (KdVideoEncodingRec)) ; - for (i=0 ; i < a_num_encodings; i++) { - result[i].id = a_encodings[i].id ; - result[i].name = strdup (a_encodings[i].name) ; - result[i].width = a_encodings[i].width ; - result[i].height = a_encodings[i].height ; - result[i].rate.numerator = a_encodings[i].rate.numerator ; - result[i].rate.denominator = a_encodings[i].rate.denominator ; - } - return result ; -} - -static KdAttributePtr -portAttributesDup (EphyrHostAttribute *a_encodings, - int a_num_encodings) -{ - int i=0 ; - KdAttributePtr result=NULL ; - - EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, NULL) ; - - result = xcalloc (a_num_encodings, sizeof (KdAttributeRec)) ; - if (!result) { - EPHYR_LOG_ERROR ("failed to allocate attributes\n") ; - return NULL ; - } - for (i=0; i < a_num_encodings; i++) { - result[i].flags = a_encodings[i].flags ; - result[i].min_value = a_encodings[i].min_value ; - result[i].max_value = a_encodings[i].max_value ; - result[i].name = strdup (a_encodings[i].name) ; - } - return result ; -} - -static Bool -ephyrXVPrivQueryHostAdaptors (EphyrXVPriv *a_this) -{ - EphyrHostXVAdaptor *cur_host_adaptor=NULL ; - EphyrHostVideoFormat *video_formats=NULL ; - EphyrHostEncoding *encodings=NULL ; - EphyrHostAttribute *attributes=NULL ; - EphyrHostImageFormat *image_formats=NULL ; - int num_video_formats=0, base_port_id=0, - num_attributes=0, num_formats=0, i=0, - port_priv_offset=0; - unsigned num_encodings=0 ; - Bool is_ok = FALSE ; - - EPHYR_RETURN_VAL_IF_FAIL (a_this, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - if (!ephyrHostXVQueryAdaptors (&a_this->host_adaptors)) { - EPHYR_LOG_ERROR ("failed to query host adaptors\n") ; - goto out ; - } - if (a_this->host_adaptors) - a_this->num_adaptors = - ephyrHostXVAdaptorArrayGetSize (a_this->host_adaptors) ; - if (a_this->num_adaptors < 0) { - EPHYR_LOG_ERROR ("failed to get number of host adaptors\n") ; - goto out ; - } - EPHYR_LOG ("host has %d adaptors\n", a_this->num_adaptors) ; - /* - * copy what we can from adaptors into a_this->adaptors - */ - if (a_this->num_adaptors) { - a_this->adaptors = xcalloc (a_this->num_adaptors, - sizeof (KdVideoAdaptorRec)) ; - if (!a_this->adaptors) { - EPHYR_LOG_ERROR ("failed to create internal adaptors\n") ; - goto out ; - } - } - for (i=0; i < a_this->num_adaptors; i++) { - int j=0 ; - cur_host_adaptor = - ephyrHostXVAdaptorArrayAt (a_this->host_adaptors, i) ; - if (!cur_host_adaptor) - continue ; - a_this->adaptors[i].nPorts = - ephyrHostXVAdaptorGetNbPorts (cur_host_adaptor) ; - if (a_this->adaptors[i].nPorts <=0) { - EPHYR_LOG_ERROR ("Could not find any port of adaptor %d\n", i) ; - continue ; - } - a_this->adaptors[i].type = - ephyrHostXVAdaptorGetType (cur_host_adaptor) ; - a_this->adaptors[i].type |= XvWindowMask ; - a_this->adaptors[i].flags = - VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; - if (ephyrHostXVAdaptorGetName (cur_host_adaptor)) - a_this->adaptors[i].name = - strdup (ephyrHostXVAdaptorGetName (cur_host_adaptor)) ; - else - a_this->adaptors[i].name = strdup ("Xephyr Video Overlay"); - base_port_id = ephyrHostXVAdaptorGetFirstPortID (cur_host_adaptor) ; - if (base_port_id < 0) { - EPHYR_LOG_ERROR ("failed to get port id for adaptor %d\n", i) ; - continue ; - } - if (!s_base_port_id) - s_base_port_id = base_port_id ; - - if (!ephyrHostXVQueryEncodings (base_port_id, - &encodings, - &num_encodings)) { - EPHYR_LOG_ERROR ("failed to get encodings for port port id %d," - " adaptors %d\n", - base_port_id, i) ; - continue ; - } - a_this->adaptors[i].nEncodings = num_encodings ; - a_this->adaptors[i].pEncodings = - videoEncodingDup (encodings, num_encodings) ; - video_formats = (EphyrHostVideoFormat*) - ephyrHostXVAdaptorGetVideoFormats (cur_host_adaptor, - &num_video_formats); - a_this->adaptors[i].pFormats = (KdVideoFormatPtr) video_formats ; - a_this->adaptors[i].nFormats = num_video_formats ; - /* got a_this->adaptors[i].nPorts already - a_this->adaptors[i].nPorts = - ephyrHostXVAdaptorGetNbPorts (cur_host_adaptor) ; - */ - a_this->adaptors[i].pPortPrivates = - xcalloc (a_this->adaptors[i].nPorts, - sizeof (DevUnion) + sizeof (EphyrPortPriv)) ; - port_priv_offset = a_this->adaptors[i].nPorts; - for (j=0; j < a_this->adaptors[i].nPorts; j++) { - EphyrPortPriv *port_privs_base = - (EphyrPortPriv*)&a_this->adaptors[i].pPortPrivates[port_priv_offset]; - EphyrPortPriv *port_priv = &port_privs_base[j] ; - port_priv->port_number = base_port_id + j; - port_priv->current_adaptor = &a_this->adaptors[i] ; - port_priv->xv_priv = a_this ; - a_this->adaptors[i].pPortPrivates[j].ptr = port_priv; - } - if (!ephyrHostXVQueryPortAttributes (base_port_id, - &attributes, - &num_attributes)) { - EPHYR_LOG_ERROR ("failed to get port attribute " - "for adaptor %d\n", i) ; - continue ; - } - a_this->adaptors[i].pAttributes = - portAttributesDup (attributes, num_attributes); - a_this->adaptors[i].nAttributes = num_attributes ; - /*make sure atoms of attrs names are created in xephyr*/ - for (j=0; j < a_this->adaptors[i].nAttributes; j++) { - if (a_this->adaptors[i].pAttributes[j].name) - MakeAtom (a_this->adaptors[i].pAttributes[j].name, - strlen (a_this->adaptors[i].pAttributes[j].name), - TRUE) ; - } - if (!ephyrHostXVQueryImageFormats (base_port_id, - &image_formats, - &num_formats)) { - EPHYR_LOG_ERROR ("failed to get image formats " - "for adaptor %d\n", i) ; - continue ; - } - a_this->adaptors[i].pImages = (KdImagePtr) image_formats ; - a_this->adaptors[i].nImages = num_formats ; - } - is_ok = TRUE ; - -out: - if (encodings) { - ephyrHostEncodingsDelete (encodings, num_encodings) ; - encodings = NULL ; - } - if (attributes) { - ephyrHostAttributesDelete (attributes) ; - attributes = NULL ; - } - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -static Bool -ephyrXVPrivSetAdaptorsHooks (EphyrXVPriv *a_this) -{ - int i=0 ; - Bool has_it=FALSE ; - EphyrHostXVAdaptor *cur_host_adaptor=NULL ; - - EPHYR_RETURN_VAL_IF_FAIL (a_this, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - for (i=0; i < a_this->num_adaptors; i++) { - a_this->adaptors[i].ReputImage = ephyrReputImage ; - a_this->adaptors[i].StopVideo = ephyrStopVideo ; - a_this->adaptors[i].SetPortAttribute = ephyrSetPortAttribute ; - a_this->adaptors[i].GetPortAttribute = ephyrGetPortAttribute ; - a_this->adaptors[i].QueryBestSize = ephyrQueryBestSize ; - a_this->adaptors[i].QueryImageAttributes = ephyrQueryImageAttributes ; - - cur_host_adaptor = - ephyrHostXVAdaptorArrayAt (a_this->host_adaptors, i) ; - if (!cur_host_adaptor) { - EPHYR_LOG_ERROR ("failed to get host adaptor at index %d\n", i) ; - continue ; - } - has_it = FALSE ; - if (!ephyrHostXVAdaptorHasPutImage (cur_host_adaptor, &has_it)) { - EPHYR_LOG_ERROR ("error\n") ; - } - if (has_it) { - a_this->adaptors[i].PutImage = ephyrPutImage; - } - - has_it = FALSE ; - if (!ephyrHostXVAdaptorHasPutVideo (cur_host_adaptor, &has_it)) { - EPHYR_LOG_ERROR ("error\n") ; - } - if (has_it) { - a_this->adaptors[i].PutVideo = ephyrPutVideo; - } - - has_it = FALSE ; - if (!ephyrHostXVAdaptorHasGetVideo (cur_host_adaptor, &has_it)) { - EPHYR_LOG_ERROR ("error\n") ; - } - if (has_it) { - a_this->adaptors[i].GetVideo = ephyrGetVideo; - } - - has_it = FALSE ; - if (!ephyrHostXVAdaptorHasPutStill (cur_host_adaptor, &has_it)) { - EPHYR_LOG_ERROR ("error\n") ; - } - if (has_it) { - a_this->adaptors[i].PutStill = ephyrPutStill; - } - - has_it = FALSE ; - if (!ephyrHostXVAdaptorHasGetStill (cur_host_adaptor, &has_it)) { - EPHYR_LOG_ERROR ("error\n") ; - } - if (has_it) { - a_this->adaptors[i].GetStill = ephyrGetStill; - } - } - EPHYR_LOG ("leave\n") ; - return TRUE ; -} - -static Bool -ephyrXVPrivRegisterAdaptors (EphyrXVPriv *a_this, - ScreenPtr a_screen) -{ - KdScreenPriv(a_screen); - KdScreenInfo *screen = pScreenPriv->screen; - Bool is_ok = FALSE ; - KdVideoAdaptorPtr *adaptors=NULL, *registered_adaptors=NULL ; - int num_registered_adaptors=0, i=0, num_adaptors=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_this && a_screen, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - if (!a_this->num_adaptors) - goto out ; - num_registered_adaptors = - KdXVListGenericAdaptors (screen, ®istered_adaptors); - - num_adaptors = num_registered_adaptors + a_this->num_adaptors ; - adaptors = xcalloc (num_adaptors, sizeof (KdVideoAdaptorPtr)) ; - if (!adaptors) { - EPHYR_LOG_ERROR ("failed to allocate adaptors tab\n") ; - goto out ; - } - memmove (adaptors, registered_adaptors, num_registered_adaptors) ; - for (i=0 ; i < a_this->num_adaptors; i++) { - *(adaptors + num_registered_adaptors + i) = &a_this->adaptors[i] ; - } - if (!KdXVScreenInit (a_screen, adaptors, num_adaptors)) { - EPHYR_LOG_ERROR ("failed to register adaptors\n"); - goto out ; - } - EPHYR_LOG ("there are %d registered adaptors\n", num_adaptors) ; - is_ok = TRUE ; - -out: - xfree (registered_adaptors) ; - registered_adaptors = NULL ; - xfree (adaptors) ; - adaptors = NULL ; - - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -static Bool -ephyrXVPrivIsAttrValueValid (KdAttributePtr a_attrs, - int a_attrs_len, - const char *a_attr_name, - int a_attr_value, - Bool *a_is_valid) -{ - int i=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_attrs && a_attr_name && a_is_valid, - FALSE) ; - - for (i=0; i < a_attrs_len; i++) { - if (a_attrs[i].name && strcmp (a_attrs[i].name, a_attr_name)) - continue ; - if (a_attrs[i].min_value > a_attr_value || - a_attrs[i].max_value < a_attr_value) { - *a_is_valid = FALSE ; - EPHYR_LOG_ERROR ("attribute was not valid\n" - "value:%d. min:%d. max:%d\n", - a_attr_value, - a_attrs[i].min_value, - a_attrs[i].max_value) ; - } else { - *a_is_valid = TRUE ; - } - return TRUE ; - } - return FALSE ; -} - -static Bool -ephyrXVPrivGetImageBufSize (int a_port_id, - int a_image_id, - unsigned short a_width, - unsigned short a_height, - int *a_size) -{ - Bool is_ok=FALSE ; - unsigned short width=a_width, height=a_height ; - - EPHYR_RETURN_VAL_IF_FAIL (a_size, FALSE) ; - - EPHYR_LOG ("enter\n") ; - - if (!ephyrHostXVQueryImageAttributes (a_port_id, a_image_id, - &width, &height, a_size, NULL, NULL)) { - EPHYR_LOG_ERROR ("failed to get image attributes\n") ; - goto out ; - } - is_ok = TRUE ; - -out: - EPHYR_LOG ("leave\n") ; - return is_ok ; -} - -static Bool -ephyrXVPrivSaveImageToPortPriv (EphyrPortPriv *a_port_priv, - const unsigned char *a_image_buf, - int a_image_len) -{ - Bool is_ok=FALSE ; - - EPHYR_LOG ("enter\n") ; - - if (a_port_priv->image_buf_size < a_image_len) { - unsigned char *buf=NULL ; - buf = realloc (a_port_priv->image_buf, a_image_len) ; - if (!buf) { - EPHYR_LOG_ERROR ("failed to realloc image buffer\n") ; - goto out ; - } - a_port_priv->image_buf = buf ; - a_port_priv->image_buf_size = a_image_len; - } - memmove (a_port_priv->image_buf, a_image_buf, a_image_len) ; - is_ok = TRUE ; - -out: - return is_ok ; - EPHYR_LOG ("leave\n") ; -} - -static void -ephyrStopVideo (KdScreenInfo *a_info, pointer a_port_priv, Bool a_exit) -{ - EphyrPortPriv *port_priv = a_port_priv ; - - EPHYR_RETURN_IF_FAIL (a_info && a_info->pScreen) ; - EPHYR_RETURN_IF_FAIL (port_priv) ; - - EPHYR_LOG ("enter\n") ; - if (!ephyrHostXVStopVideo (a_info->pScreen->myNum, - port_priv->port_number)) { - EPHYR_LOG_ERROR ("XvStopVideo() failed\n") ; - } - EPHYR_LOG ("leave\n") ; -} - -static int -ephyrSetPortAttribute (KdScreenInfo *a_info, - Atom a_attr_name, - int a_attr_value, - pointer a_port_priv) -{ - int res=Success, host_atom=0 ; - EphyrPortPriv *port_priv = a_port_priv ; - Bool is_attr_valid=FALSE ; - - EPHYR_RETURN_VAL_IF_FAIL (port_priv, BadMatch) ; - EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor, BadMatch) ; - EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor->pAttributes, - BadMatch) ; - EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor->nAttributes, - BadMatch) ; - EPHYR_RETURN_VAL_IF_FAIL (ValidAtom (a_attr_name), BadMatch) ; - - EPHYR_LOG ("enter, portnum:%d, atomid:%d, attr_name:%s, attr_val:%d\n", - port_priv->port_number, - (int)a_attr_name, - NameForAtom (a_attr_name), - a_attr_value) ; - - if (!ephyrLocalAtomToHost (a_attr_name, &host_atom)) { - EPHYR_LOG_ERROR ("failed to convert local atom to host atom\n") ; - res = BadMatch ; - goto out ; - } - - if (!ephyrXVPrivIsAttrValueValid (port_priv->current_adaptor->pAttributes, - port_priv->current_adaptor->nAttributes, - NameForAtom (a_attr_name), - a_attr_value, - &is_attr_valid)) { - EPHYR_LOG_ERROR ("failed to validate attribute %s\n", - NameForAtom (a_attr_name)) ; - /* - res = BadMatch ; - goto out ; - */ - } - if (!is_attr_valid) { - EPHYR_LOG_ERROR ("attribute %s is not valid\n", - NameForAtom (a_attr_name)) ; - /* - res = BadMatch ; - goto out ; - */ - } - - if (!ephyrHostXVSetPortAttribute (port_priv->port_number, - host_atom, - a_attr_value)) { - EPHYR_LOG_ERROR ("failed to set port attribute\n") ; - res = BadMatch ; - goto out ; - } - - res = Success ; -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -static int -ephyrGetPortAttribute (KdScreenInfo *a_screen_info, - Atom a_attr_name, - int *a_attr_value, - pointer a_port_priv) -{ - int res=Success, host_atom=0 ; - EphyrPortPriv *port_priv = a_port_priv ; - - EPHYR_RETURN_VAL_IF_FAIL (port_priv, BadMatch) ; - EPHYR_RETURN_VAL_IF_FAIL (ValidAtom (a_attr_name), BadMatch) ; - - EPHYR_LOG ("enter, portnum:%d, atomid:%d, attr_name:%s\n", - port_priv->port_number, - (int)a_attr_name, - NameForAtom (a_attr_name)) ; - - if (!ephyrLocalAtomToHost (a_attr_name, &host_atom)) { - EPHYR_LOG_ERROR ("failed to convert local atom to host atom\n") ; - res = BadMatch ; - goto out ; - } - - if (!ephyrHostXVGetPortAttribute (port_priv->port_number, - host_atom, - a_attr_value)) { - EPHYR_LOG_ERROR ("failed to get port attribute\n") ; - res = BadMatch ; - goto out ; - } - - res = Success ; -out: - EPHYR_LOG ("leave\n") ; - return res ; -} - -static void -ephyrQueryBestSize (KdScreenInfo *a_info, - Bool a_motion, - short a_src_w, - short a_src_h, - short a_drw_w, - short a_drw_h, - unsigned int *a_prefered_w, - unsigned int *a_prefered_h, - pointer a_port_priv) -{ - int res=0 ; - EphyrPortPriv *port_priv = a_port_priv ; - - EPHYR_RETURN_IF_FAIL (port_priv) ; - - EPHYR_LOG ("enter\n") ; - res = ephyrHostXVQueryBestSize (port_priv->port_number, - a_motion, - a_src_w, a_src_h, - a_drw_w, a_drw_h, - a_prefered_w, a_prefered_h) ; - if (!res) { - EPHYR_LOG_ERROR ("Failed to query best size\n") ; - } - EPHYR_LOG ("leave\n") ; -} - -static int -ephyrPutImage (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_src_x, - short a_src_y, - short a_drw_x, - short a_drw_y, - short a_src_w, - short a_src_h, - short a_drw_w, - short a_drw_h, - int a_id, - unsigned char *a_buf, - short a_width, - short a_height, - Bool a_sync, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - Bool is_ok=FALSE ; - int result=BadImplementation, image_size=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - if (!ephyrHostXVPutImage (a_info->pScreen->myNum, - port_priv->port_number, - a_id, - a_drw_x, a_drw_y, a_drw_w, a_drw_h, - a_src_x, a_src_y, a_src_w, a_src_h, - a_width, a_height, a_buf, - (EphyrHostBox*)REGION_RECTS (a_clipping_region), - REGION_NUM_RECTS (a_clipping_region))) { - EPHYR_LOG_ERROR ("EphyrHostXVPutImage() failed\n") ; - goto out ; - } - - /* - * Now save the image so that we can resend it to host it - * later, in ReputImage. - */ - if (!ephyrXVPrivGetImageBufSize (port_priv->port_number, - a_id, a_width, a_height, &image_size)) { - EPHYR_LOG_ERROR ("failed to get image size\n") ; - /*this is a minor error so we won't get bail out abruptly*/ - is_ok = FALSE ; - } else { - is_ok = TRUE ; - } - if (is_ok) { - if (!ephyrXVPrivSaveImageToPortPriv (port_priv, a_buf, image_size)) { - is_ok=FALSE ; - } else { - port_priv->image_id = a_id; - port_priv->drw_x = a_drw_x; - port_priv->drw_y = a_drw_y; - port_priv->drw_w = a_drw_w ; - port_priv->drw_h = a_drw_h ; - port_priv->src_x = a_src_x; - port_priv->src_y = a_src_y ; - port_priv->src_w = a_src_w ; - port_priv->src_h = a_src_h ; - port_priv->image_width = a_width ; - port_priv->image_height = a_height ; - } - } - if (!is_ok) { - if (port_priv->image_buf) { - free (port_priv->image_buf) ; - port_priv->image_buf = NULL ; - port_priv->image_buf_size = 0 ; - } - } - - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrReputImage (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_drw_x, - short a_drw_y, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - int result=BadImplementation ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info->pScreen, FALSE) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - if (!port_priv->image_buf_size || !port_priv->image_buf) { - EPHYR_LOG_ERROR ("has null image buf in cache\n") ; - goto out ; - } - if (!ephyrHostXVPutImage (a_info->pScreen->myNum, - port_priv->port_number, - port_priv->image_id, - a_drw_x, a_drw_y, - port_priv->drw_w, port_priv->drw_h, - port_priv->src_x, port_priv->src_y, - port_priv->src_w, port_priv->src_h, - port_priv->image_width, port_priv->image_height, - port_priv->image_buf, - (EphyrHostBox*)REGION_RECTS (a_clipping_region), - REGION_NUM_RECTS (a_clipping_region))) { - EPHYR_LOG_ERROR ("ephyrHostXVPutImage() failed\n") ; - goto out ; - } - - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrPutVideo (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - BoxRec clipped_area, dst_box ; - int result=BadImplementation ; - int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info->pScreen, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - dst_box.x1 = a_drw_x ; - dst_box.x2 = a_drw_x + a_drw_w; - dst_box.y1 = a_drw_y ; - dst_box.y2 = a_drw_y + a_drw_h; - - if (!DoSimpleClip (&dst_box, - REGION_EXTENTS (pScreen->pScreen, a_clipping_region), - &clipped_area)) { - EPHYR_LOG_ERROR ("failed to simple clip\n") ; - goto out ; - } - - drw_x = clipped_area.x1 ; - drw_y = clipped_area.y1 ; - drw_w = clipped_area.x2 - clipped_area.x1 ; - drw_h = clipped_area.y2 - clipped_area.y1 ; - - if (!ephyrHostXVPutVideo (a_info->pScreen->myNum, - port_priv->port_number, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { - EPHYR_LOG_ERROR ("ephyrHostXVPutVideo() failed\n") ; - goto out ; - } - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrGetVideo (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - BoxRec clipped_area, dst_box ; - int result=BadImplementation ; - int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - dst_box.x1 = a_drw_x ; - dst_box.x2 = a_drw_x + a_drw_w; - dst_box.y1 = a_drw_y ; - dst_box.y2 = a_drw_y + a_drw_h; - - if (!DoSimpleClip (&dst_box, - REGION_EXTENTS (pScreen->pScreen, a_clipping_region), - &clipped_area)) { - EPHYR_LOG_ERROR ("failed to simple clip\n") ; - goto out ; - } - - drw_x = clipped_area.x1 ; - drw_y = clipped_area.y1 ; - drw_w = clipped_area.x2 - clipped_area.x1 ; - drw_h = clipped_area.y2 - clipped_area.y1 ; - - if (!ephyrHostXVGetVideo (a_info->pScreen->myNum, - port_priv->port_number, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { - EPHYR_LOG_ERROR ("ephyrHostXVGetVideo() failed\n") ; - goto out ; - } - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrPutStill (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - BoxRec clipped_area, dst_box ; - int result=BadImplementation ; - int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - dst_box.x1 = a_drw_x ; - dst_box.x2 = a_drw_x + a_drw_w; - dst_box.y1 = a_drw_y ; - dst_box.y2 = a_drw_y + a_drw_h; - - if (!DoSimpleClip (&dst_box, - REGION_EXTENTS (pScreen->pScreen, a_clipping_region), - &clipped_area)) { - EPHYR_LOG_ERROR ("failed to simple clip\n") ; - goto out ; - } - - drw_x = clipped_area.x1 ; - drw_y = clipped_area.y1 ; - drw_w = clipped_area.x2 - clipped_area.x1 ; - drw_h = clipped_area.y2 - clipped_area.y1 ; - - if (!ephyrHostXVPutStill (a_info->pScreen->myNum, - port_priv->port_number, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { - EPHYR_LOG_ERROR ("ephyrHostXVPutStill() failed\n") ; - goto out ; - } - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrGetStill (KdScreenInfo *a_info, - DrawablePtr a_drawable, - short a_vid_x, short a_vid_y, - short a_drw_x, short a_drw_y, - short a_vid_w, short a_vid_h, - short a_drw_w, short a_drw_h, - RegionPtr a_clipping_region, - pointer a_port_priv) -{ - EphyrPortPriv *port_priv = a_port_priv ; - BoxRec clipped_area, dst_box ; - int result=BadImplementation ; - int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; - EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; - - EPHYR_LOG ("enter\n") ; - - dst_box.x1 = a_drw_x ; - dst_box.x2 = a_drw_x + a_drw_w; - dst_box.y1 = a_drw_y ; - dst_box.y2 = a_drw_y + a_drw_h; - - if (!DoSimpleClip (&dst_box, - REGION_EXTENTS (pScreen->pScreen, a_clipping_region), - &clipped_area)) { - EPHYR_LOG_ERROR ("failed to simple clip\n") ; - goto out ; - } - - drw_x = clipped_area.x1 ; - drw_y = clipped_area.y1 ; - drw_w = clipped_area.x2 - clipped_area.x1 ; - drw_h = clipped_area.y2 - clipped_area.y1 ; - - if (!ephyrHostXVGetStill (a_info->pScreen->myNum, - port_priv->port_number, - a_vid_x, a_vid_y, a_vid_w, a_vid_h, - a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { - EPHYR_LOG_ERROR ("ephyrHostXVGetStill() failed\n") ; - goto out ; - } - result = Success ; - -out: - EPHYR_LOG ("leave\n") ; - return result ; -} - -static int -ephyrQueryImageAttributes (KdScreenInfo *a_info, - int a_id, - unsigned short *a_w, - unsigned short *a_h, - int *a_pitches, - int *a_offsets) -{ - int image_size=0 ; - - EPHYR_RETURN_VAL_IF_FAIL (a_w && a_h, FALSE) ; - - EPHYR_LOG ("enter: dim (%dx%d), pitches: %p, offsets: %p\n", - *a_w, *a_h, a_pitches, a_offsets) ; - - if (!ephyrHostXVQueryImageAttributes (s_base_port_id, - a_id, - a_w, a_h, - &image_size, - a_pitches, a_offsets)) { - EPHYR_LOG_ERROR ("EphyrHostXVQueryImageAttributes() failed\n") ; - goto out ; - } - EPHYR_LOG ("image size: %d, dim (%dx%d)\n", image_size, *a_w, *a_h) ; - -out: - EPHYR_LOG ("leave\n") ; - return image_size ; -} +/* + * Xephyr - A kdrive X server thats runs in a host X window. + * Authored by Matthew Allum + * + * Copyright © 2007 OpenedHand Ltd + * + * 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 OpenedHand Ltd not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. OpenedHand Ltd makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Dodji Seketeli + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include "ephyrlog.h" +#include "kdrive.h" +#include "kxv.h" +#include "ephyr.h" +#include "hostx.h" +#include "ephyrhostvideo.h" + +struct _EphyrXVPriv { + EphyrHostXVAdaptorArray *host_adaptors ; + KdVideoAdaptorPtr adaptors ; + int num_adaptors ; +}; +typedef struct _EphyrXVPriv EphyrXVPriv ; + +struct _EphyrPortPriv { + int port_number ; + KdVideoAdaptorPtr current_adaptor ; + EphyrXVPriv *xv_priv; + unsigned char *image_buf ; + int image_buf_size ; + int image_id ; + int drw_x, drw_y, drw_w, drw_h ; + int src_x, src_y, src_w, src_h ; + int image_width, image_height ; +}; +typedef struct _EphyrPortPriv EphyrPortPriv ; + +static Bool DoSimpleClip (BoxPtr a_dst_drw, + BoxPtr a_clipper, + BoxPtr a_result) ; + +static Bool ephyrLocalAtomToHost (int a_local_atom, int *a_host_atom) ; + +/* +static Bool ephyrHostAtomToLocal (int a_host_atom, int *a_local_atom) ; +*/ + +static EphyrXVPriv* ephyrXVPrivNew (void) ; +static void ephyrXVPrivDelete (EphyrXVPriv *a_this) ; +static Bool ephyrXVPrivQueryHostAdaptors (EphyrXVPriv *a_this) ; +static Bool ephyrXVPrivSetAdaptorsHooks (EphyrXVPriv *a_this) ; +static Bool ephyrXVPrivRegisterAdaptors (EphyrXVPriv *a_this, + ScreenPtr a_screen) ; + +static Bool ephyrXVPrivIsAttrValueValid (KdAttributePtr a_attrs, + int a_attrs_len, + const char *a_attr_name, + int a_attr_value, + Bool *a_is_valid) ; + +static Bool ephyrXVPrivGetImageBufSize (int a_port_id, + int a_image_id, + unsigned short a_width, + unsigned short a_height, + int *a_size) ; + +static Bool ephyrXVPrivSaveImageToPortPriv (EphyrPortPriv *a_port_priv, + const unsigned char *a_image, + int a_image_len) ; + +static void ephyrStopVideo (KdScreenInfo *a_info, + pointer a_xv_priv, + Bool a_exit); + +static int ephyrSetPortAttribute (KdScreenInfo *a_info, + Atom a_attr_name, + int a_attr_value, + pointer a_port_priv); + +static int ephyrGetPortAttribute (KdScreenInfo *a_screen_info, + Atom a_attr_name, + int *a_attr_value, + pointer a_port_priv); + +static void ephyrQueryBestSize (KdScreenInfo *a_info, + Bool a_motion, + short a_src_w, + short a_src_h, + short a_drw_w, + short a_drw_h, + unsigned int *a_prefered_w, + unsigned int *a_prefered_h, + pointer a_port_priv); + +static int ephyrPutImage (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_src_x, + short a_src_y, + short a_drw_x, + short a_drw_y, + short a_src_w, + short a_src_h, + short a_drw_w, + short a_drw_h, + int a_id, + unsigned char *a_buf, + short a_width, + short a_height, + Bool a_sync, + RegionPtr a_clipping_region, + pointer a_port_priv); + +static int ephyrReputImage (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_drw_x, + short a_drw_y, + RegionPtr a_clipping_region, + pointer a_port_priv) ; + +static int ephyrPutVideo (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clip_region, + pointer a_port_priv) ; + +static int ephyrGetVideo (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clip_region, + pointer a_port_priv) ; + +static int ephyrPutStill (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clip_region, + pointer a_port_priv) ; + +static int ephyrGetStill (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clip_region, + pointer a_port_priv) ; + +static int ephyrQueryImageAttributes (KdScreenInfo *a_info, + int a_id, + unsigned short *a_w, + unsigned short *a_h, + int *a_pitches, + int *a_offsets); +static int s_base_port_id ; + +/************** + * + * ************/ + +static Bool +DoSimpleClip (BoxPtr a_dst_box, + BoxPtr a_clipper, + BoxPtr a_result) +{ + BoxRec dstClippedBox ; + + EPHYR_RETURN_VAL_IF_FAIL (a_dst_box && a_clipper && a_result, FALSE) ; + + /* + * setup the clipbox inside the destination. + */ + dstClippedBox.x1 = a_dst_box->x1 ; + dstClippedBox.x2 = a_dst_box->x2 ; + dstClippedBox.y1 = a_dst_box->y1 ; + dstClippedBox.y2 = a_dst_box->y2 ; + + /* + * if the cliper leftmost edge is inside + * the destination area then the leftmost edge of the resulting + * clipped box is the leftmost edge of the cliper. + */ + if (a_clipper->x1 > dstClippedBox.x1) + dstClippedBox.x1 = a_clipper->x1 ; + + /* + * if the cliper top edge is inside the destination area + * then the bottom horizontal edge of the resulting clipped box + * is the bottom edge of the cliper + */ + if (a_clipper->y1 > dstClippedBox.y1) + dstClippedBox.y1 = a_clipper->y1 ; + + /*ditto for right edge*/ + if (a_clipper->x2 < dstClippedBox.x2) + dstClippedBox.x2 = a_clipper->x2 ; + + /*ditto for bottom edge*/ + if (a_clipper->y2 < dstClippedBox.y2) + dstClippedBox.y2 = a_clipper->y2 ; + + memcpy (a_result, &dstClippedBox, sizeof (dstClippedBox)) ; + return TRUE ; +} + +static Bool +ephyrLocalAtomToHost (int a_local_atom, int *a_host_atom) +{ + const char *atom_name=NULL; + int host_atom=None ; + + EPHYR_RETURN_VAL_IF_FAIL (a_host_atom, FALSE) ; + + if (!ValidAtom (a_local_atom)) + return FALSE ; + + atom_name = NameForAtom (a_local_atom) ; + + if (!atom_name) + return FALSE ; + + if (!ephyrHostGetAtom (atom_name, FALSE, &host_atom) || host_atom == None) { + EPHYR_LOG_ERROR ("no atom for string %s defined in host X\n", + atom_name) ; + return FALSE ; + } + *a_host_atom = host_atom ; + return TRUE ; +} + +/* + Not used yed. +static Bool +ephyrHostAtomToLocal (int a_host_atom, int *a_local_atom) +{ + Bool is_ok=FALSE ; + char *atom_name=NULL ; + int atom=None ; + + EPHYR_RETURN_VAL_IF_FAIL (a_local_atom, FALSE) ; + + atom_name = ephyrHostGetAtomName (a_host_atom) ; + if (!atom_name) + goto out ; + + atom = MakeAtom (atom_name, strlen (atom_name), TRUE) ; + if (atom == None) + goto out ; + + *a_local_atom = atom ; + is_ok = TRUE ; + +out: + if (atom_name) { + ephyrHostFree (atom_name) ; + } + return is_ok ; +} +*/ + +/************** + * + * ************/ + +Bool +ephyrInitVideo (ScreenPtr pScreen) +{ + Bool is_ok = FALSE ; + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + static EphyrXVPriv *xv_priv; + + EPHYR_LOG ("enter\n") ; + + if (screen->fb.bitsPerPixel == 8) { + EPHYR_LOG_ERROR ("8 bits depth not supported\n") ; + return FALSE ; + } + + if (!xv_priv) { + xv_priv = ephyrXVPrivNew () ; + } + if (!xv_priv) { + EPHYR_LOG_ERROR ("failed to create xv_priv\n") ; + goto out ; + } + + if (!ephyrXVPrivRegisterAdaptors (xv_priv, pScreen)) { + EPHYR_LOG_ERROR ("failed to register adaptors\n") ; + goto out ; + } + is_ok = TRUE ; + +out: + return is_ok ; +} + +static EphyrXVPriv* +ephyrXVPrivNew (void) +{ + EphyrXVPriv *xv_priv=NULL ; + + EPHYR_LOG ("enter\n") ; + + xv_priv = calloc(1, sizeof (EphyrXVPriv)) ; + if (!xv_priv) { + EPHYR_LOG_ERROR ("failed to create EphyrXVPriv\n") ; + goto error ; + } + + ephyrHostXVInit () ; + + if (!ephyrXVPrivQueryHostAdaptors (xv_priv)) { + EPHYR_LOG_ERROR ("failed to query the host x for xv properties\n") ; + goto error ; + } + if (!ephyrXVPrivSetAdaptorsHooks (xv_priv)) { + EPHYR_LOG_ERROR ("failed to set xv_priv hooks\n") ; + goto error ; + } + + EPHYR_LOG ("leave\n") ; + return xv_priv ; + +error: + if (xv_priv) { + ephyrXVPrivDelete (xv_priv) ; + xv_priv = NULL ; + } + return NULL ; +} + +static void +ephyrXVPrivDelete (EphyrXVPriv *a_this) +{ + EPHYR_LOG ("enter\n") ; + + if (!a_this) + return ; + if (a_this->host_adaptors) { + ephyrHostXVAdaptorArrayDelete (a_this->host_adaptors) ; + a_this->host_adaptors = NULL ; + } + free(a_this->adaptors) ; + a_this->adaptors = NULL ; + free(a_this) ; + EPHYR_LOG ("leave\n") ; +} + +static KdVideoEncodingPtr +videoEncodingDup (EphyrHostEncoding *a_encodings, + int a_num_encodings) +{ + KdVideoEncodingPtr result = NULL ; + int i=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, NULL) ; + + result = calloc(a_num_encodings, sizeof (KdVideoEncodingRec)) ; + for (i=0 ; i < a_num_encodings; i++) { + result[i].id = a_encodings[i].id ; + result[i].name = strdup (a_encodings[i].name) ; + result[i].width = a_encodings[i].width ; + result[i].height = a_encodings[i].height ; + result[i].rate.numerator = a_encodings[i].rate.numerator ; + result[i].rate.denominator = a_encodings[i].rate.denominator ; + } + return result ; +} + +static KdAttributePtr +portAttributesDup (EphyrHostAttribute *a_encodings, + int a_num_encodings) +{ + int i=0 ; + KdAttributePtr result=NULL ; + + EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, NULL) ; + + result = calloc(a_num_encodings, sizeof (KdAttributeRec)) ; + if (!result) { + EPHYR_LOG_ERROR ("failed to allocate attributes\n") ; + return NULL ; + } + for (i=0; i < a_num_encodings; i++) { + result[i].flags = a_encodings[i].flags ; + result[i].min_value = a_encodings[i].min_value ; + result[i].max_value = a_encodings[i].max_value ; + result[i].name = strdup (a_encodings[i].name) ; + } + return result ; +} + +static Bool +ephyrXVPrivQueryHostAdaptors (EphyrXVPriv *a_this) +{ + EphyrHostXVAdaptor *cur_host_adaptor=NULL ; + EphyrHostVideoFormat *video_formats=NULL ; + EphyrHostEncoding *encodings=NULL ; + EphyrHostAttribute *attributes=NULL ; + EphyrHostImageFormat *image_formats=NULL ; + int num_video_formats=0, base_port_id=0, + num_attributes=0, num_formats=0, i=0, + port_priv_offset=0; + unsigned num_encodings=0 ; + Bool is_ok = FALSE ; + + EPHYR_RETURN_VAL_IF_FAIL (a_this, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostXVQueryAdaptors (&a_this->host_adaptors)) { + EPHYR_LOG_ERROR ("failed to query host adaptors\n") ; + goto out ; + } + if (a_this->host_adaptors) + a_this->num_adaptors = + ephyrHostXVAdaptorArrayGetSize (a_this->host_adaptors) ; + if (a_this->num_adaptors < 0) { + EPHYR_LOG_ERROR ("failed to get number of host adaptors\n") ; + goto out ; + } + EPHYR_LOG ("host has %d adaptors\n", a_this->num_adaptors) ; + /* + * copy what we can from adaptors into a_this->adaptors + */ + if (a_this->num_adaptors) { + a_this->adaptors = calloc(a_this->num_adaptors, + sizeof (KdVideoAdaptorRec)) ; + if (!a_this->adaptors) { + EPHYR_LOG_ERROR ("failed to create internal adaptors\n") ; + goto out ; + } + } + for (i=0; i < a_this->num_adaptors; i++) { + int j=0 ; + cur_host_adaptor = + ephyrHostXVAdaptorArrayAt (a_this->host_adaptors, i) ; + if (!cur_host_adaptor) + continue ; + a_this->adaptors[i].nPorts = + ephyrHostXVAdaptorGetNbPorts (cur_host_adaptor) ; + if (a_this->adaptors[i].nPorts <=0) { + EPHYR_LOG_ERROR ("Could not find any port of adaptor %d\n", i) ; + continue ; + } + a_this->adaptors[i].type = + ephyrHostXVAdaptorGetType (cur_host_adaptor) ; + a_this->adaptors[i].type |= XvWindowMask ; + a_this->adaptors[i].flags = + VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; + if (ephyrHostXVAdaptorGetName (cur_host_adaptor)) + a_this->adaptors[i].name = + strdup (ephyrHostXVAdaptorGetName (cur_host_adaptor)) ; + else + a_this->adaptors[i].name = strdup ("Xephyr Video Overlay"); + base_port_id = ephyrHostXVAdaptorGetFirstPortID (cur_host_adaptor) ; + if (base_port_id < 0) { + EPHYR_LOG_ERROR ("failed to get port id for adaptor %d\n", i) ; + continue ; + } + if (!s_base_port_id) + s_base_port_id = base_port_id ; + + if (!ephyrHostXVQueryEncodings (base_port_id, + &encodings, + &num_encodings)) { + EPHYR_LOG_ERROR ("failed to get encodings for port port id %d," + " adaptors %d\n", + base_port_id, i) ; + continue ; + } + a_this->adaptors[i].nEncodings = num_encodings ; + a_this->adaptors[i].pEncodings = + videoEncodingDup (encodings, num_encodings) ; + video_formats = (EphyrHostVideoFormat*) + ephyrHostXVAdaptorGetVideoFormats (cur_host_adaptor, + &num_video_formats); + a_this->adaptors[i].pFormats = (KdVideoFormatPtr) video_formats ; + a_this->adaptors[i].nFormats = num_video_formats ; + /* got a_this->adaptors[i].nPorts already + a_this->adaptors[i].nPorts = + ephyrHostXVAdaptorGetNbPorts (cur_host_adaptor) ; + */ + a_this->adaptors[i].pPortPrivates = + calloc(a_this->adaptors[i].nPorts, + sizeof (DevUnion) + sizeof (EphyrPortPriv)) ; + port_priv_offset = a_this->adaptors[i].nPorts; + for (j=0; j < a_this->adaptors[i].nPorts; j++) { + EphyrPortPriv *port_privs_base = + (EphyrPortPriv*)&a_this->adaptors[i].pPortPrivates[port_priv_offset]; + EphyrPortPriv *port_priv = &port_privs_base[j] ; + port_priv->port_number = base_port_id + j; + port_priv->current_adaptor = &a_this->adaptors[i] ; + port_priv->xv_priv = a_this ; + a_this->adaptors[i].pPortPrivates[j].ptr = port_priv; + } + if (!ephyrHostXVQueryPortAttributes (base_port_id, + &attributes, + &num_attributes)) { + EPHYR_LOG_ERROR ("failed to get port attribute " + "for adaptor %d\n", i) ; + continue ; + } + a_this->adaptors[i].pAttributes = + portAttributesDup (attributes, num_attributes); + a_this->adaptors[i].nAttributes = num_attributes ; + /*make sure atoms of attrs names are created in xephyr*/ + for (j=0; j < a_this->adaptors[i].nAttributes; j++) { + if (a_this->adaptors[i].pAttributes[j].name) + MakeAtom (a_this->adaptors[i].pAttributes[j].name, + strlen (a_this->adaptors[i].pAttributes[j].name), + TRUE) ; + } + if (!ephyrHostXVQueryImageFormats (base_port_id, + &image_formats, + &num_formats)) { + EPHYR_LOG_ERROR ("failed to get image formats " + "for adaptor %d\n", i) ; + continue ; + } + a_this->adaptors[i].pImages = (KdImagePtr) image_formats ; + a_this->adaptors[i].nImages = num_formats ; + } + is_ok = TRUE ; + +out: + if (encodings) { + ephyrHostEncodingsDelete (encodings, num_encodings) ; + encodings = NULL ; + } + if (attributes) { + ephyrHostAttributesDelete (attributes) ; + attributes = NULL ; + } + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +static Bool +ephyrXVPrivSetAdaptorsHooks (EphyrXVPriv *a_this) +{ + int i=0 ; + Bool has_it=FALSE ; + EphyrHostXVAdaptor *cur_host_adaptor=NULL ; + + EPHYR_RETURN_VAL_IF_FAIL (a_this, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + for (i=0; i < a_this->num_adaptors; i++) { + a_this->adaptors[i].ReputImage = ephyrReputImage ; + a_this->adaptors[i].StopVideo = ephyrStopVideo ; + a_this->adaptors[i].SetPortAttribute = ephyrSetPortAttribute ; + a_this->adaptors[i].GetPortAttribute = ephyrGetPortAttribute ; + a_this->adaptors[i].QueryBestSize = ephyrQueryBestSize ; + a_this->adaptors[i].QueryImageAttributes = ephyrQueryImageAttributes ; + + cur_host_adaptor = + ephyrHostXVAdaptorArrayAt (a_this->host_adaptors, i) ; + if (!cur_host_adaptor) { + EPHYR_LOG_ERROR ("failed to get host adaptor at index %d\n", i) ; + continue ; + } + has_it = FALSE ; + if (!ephyrHostXVAdaptorHasPutImage (cur_host_adaptor, &has_it)) { + EPHYR_LOG_ERROR ("error\n") ; + } + if (has_it) { + a_this->adaptors[i].PutImage = ephyrPutImage; + } + + has_it = FALSE ; + if (!ephyrHostXVAdaptorHasPutVideo (cur_host_adaptor, &has_it)) { + EPHYR_LOG_ERROR ("error\n") ; + } + if (has_it) { + a_this->adaptors[i].PutVideo = ephyrPutVideo; + } + + has_it = FALSE ; + if (!ephyrHostXVAdaptorHasGetVideo (cur_host_adaptor, &has_it)) { + EPHYR_LOG_ERROR ("error\n") ; + } + if (has_it) { + a_this->adaptors[i].GetVideo = ephyrGetVideo; + } + + has_it = FALSE ; + if (!ephyrHostXVAdaptorHasPutStill (cur_host_adaptor, &has_it)) { + EPHYR_LOG_ERROR ("error\n") ; + } + if (has_it) { + a_this->adaptors[i].PutStill = ephyrPutStill; + } + + has_it = FALSE ; + if (!ephyrHostXVAdaptorHasGetStill (cur_host_adaptor, &has_it)) { + EPHYR_LOG_ERROR ("error\n") ; + } + if (has_it) { + a_this->adaptors[i].GetStill = ephyrGetStill; + } + } + EPHYR_LOG ("leave\n") ; + return TRUE ; +} + +static Bool +ephyrXVPrivRegisterAdaptors (EphyrXVPriv *a_this, + ScreenPtr a_screen) +{ + KdScreenPriv(a_screen); + KdScreenInfo *screen = pScreenPriv->screen; + Bool is_ok = FALSE ; + KdVideoAdaptorPtr *adaptors=NULL, *registered_adaptors=NULL ; + int num_registered_adaptors=0, i=0, num_adaptors=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_this && a_screen, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + if (!a_this->num_adaptors) + goto out ; + num_registered_adaptors = + KdXVListGenericAdaptors (screen, ®istered_adaptors); + + num_adaptors = num_registered_adaptors + a_this->num_adaptors ; + adaptors = calloc(num_adaptors, sizeof (KdVideoAdaptorPtr)) ; + if (!adaptors) { + EPHYR_LOG_ERROR ("failed to allocate adaptors tab\n") ; + goto out ; + } + memmove (adaptors, registered_adaptors, num_registered_adaptors) ; + for (i=0 ; i < a_this->num_adaptors; i++) { + *(adaptors + num_registered_adaptors + i) = &a_this->adaptors[i] ; + } + if (!KdXVScreenInit (a_screen, adaptors, num_adaptors)) { + EPHYR_LOG_ERROR ("failed to register adaptors\n"); + goto out ; + } + EPHYR_LOG ("there are %d registered adaptors\n", num_adaptors) ; + is_ok = TRUE ; + +out: + free(registered_adaptors) ; + registered_adaptors = NULL ; + free(adaptors) ; + adaptors = NULL ; + + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +static Bool +ephyrXVPrivIsAttrValueValid (KdAttributePtr a_attrs, + int a_attrs_len, + const char *a_attr_name, + int a_attr_value, + Bool *a_is_valid) +{ + int i=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_attrs && a_attr_name && a_is_valid, + FALSE) ; + + for (i=0; i < a_attrs_len; i++) { + if (a_attrs[i].name && strcmp (a_attrs[i].name, a_attr_name)) + continue ; + if (a_attrs[i].min_value > a_attr_value || + a_attrs[i].max_value < a_attr_value) { + *a_is_valid = FALSE ; + EPHYR_LOG_ERROR ("attribute was not valid\n" + "value:%d. min:%d. max:%d\n", + a_attr_value, + a_attrs[i].min_value, + a_attrs[i].max_value) ; + } else { + *a_is_valid = TRUE ; + } + return TRUE ; + } + return FALSE ; +} + +static Bool +ephyrXVPrivGetImageBufSize (int a_port_id, + int a_image_id, + unsigned short a_width, + unsigned short a_height, + int *a_size) +{ + Bool is_ok=FALSE ; + unsigned short width=a_width, height=a_height ; + + EPHYR_RETURN_VAL_IF_FAIL (a_size, FALSE) ; + + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostXVQueryImageAttributes (a_port_id, a_image_id, + &width, &height, a_size, NULL, NULL)) { + EPHYR_LOG_ERROR ("failed to get image attributes\n") ; + goto out ; + } + is_ok = TRUE ; + +out: + EPHYR_LOG ("leave\n") ; + return is_ok ; +} + +static Bool +ephyrXVPrivSaveImageToPortPriv (EphyrPortPriv *a_port_priv, + const unsigned char *a_image_buf, + int a_image_len) +{ + Bool is_ok=FALSE ; + + EPHYR_LOG ("enter\n") ; + + if (a_port_priv->image_buf_size < a_image_len) { + unsigned char *buf=NULL ; + buf = realloc (a_port_priv->image_buf, a_image_len) ; + if (!buf) { + EPHYR_LOG_ERROR ("failed to realloc image buffer\n") ; + goto out ; + } + a_port_priv->image_buf = buf ; + a_port_priv->image_buf_size = a_image_len; + } + memmove (a_port_priv->image_buf, a_image_buf, a_image_len) ; + is_ok = TRUE ; + +out: + return is_ok ; + EPHYR_LOG ("leave\n") ; +} + +static void +ephyrStopVideo (KdScreenInfo *a_info, pointer a_port_priv, Bool a_exit) +{ + EphyrPortPriv *port_priv = a_port_priv ; + + EPHYR_RETURN_IF_FAIL (a_info && a_info->pScreen) ; + EPHYR_RETURN_IF_FAIL (port_priv) ; + + EPHYR_LOG ("enter\n") ; + if (!ephyrHostXVStopVideo (a_info->pScreen->myNum, + port_priv->port_number)) { + EPHYR_LOG_ERROR ("XvStopVideo() failed\n") ; + } + EPHYR_LOG ("leave\n") ; +} + +static int +ephyrSetPortAttribute (KdScreenInfo *a_info, + Atom a_attr_name, + int a_attr_value, + pointer a_port_priv) +{ + int res=Success, host_atom=0 ; + EphyrPortPriv *port_priv = a_port_priv ; + Bool is_attr_valid=FALSE ; + + EPHYR_RETURN_VAL_IF_FAIL (port_priv, BadMatch) ; + EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor, BadMatch) ; + EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor->pAttributes, + BadMatch) ; + EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor->nAttributes, + BadMatch) ; + EPHYR_RETURN_VAL_IF_FAIL (ValidAtom (a_attr_name), BadMatch) ; + + EPHYR_LOG ("enter, portnum:%d, atomid:%d, attr_name:%s, attr_val:%d\n", + port_priv->port_number, + (int)a_attr_name, + NameForAtom (a_attr_name), + a_attr_value) ; + + if (!ephyrLocalAtomToHost (a_attr_name, &host_atom)) { + EPHYR_LOG_ERROR ("failed to convert local atom to host atom\n") ; + res = BadMatch ; + goto out ; + } + + if (!ephyrXVPrivIsAttrValueValid (port_priv->current_adaptor->pAttributes, + port_priv->current_adaptor->nAttributes, + NameForAtom (a_attr_name), + a_attr_value, + &is_attr_valid)) { + EPHYR_LOG_ERROR ("failed to validate attribute %s\n", + NameForAtom (a_attr_name)) ; + /* + res = BadMatch ; + goto out ; + */ + } + if (!is_attr_valid) { + EPHYR_LOG_ERROR ("attribute %s is not valid\n", + NameForAtom (a_attr_name)) ; + /* + res = BadMatch ; + goto out ; + */ + } + + if (!ephyrHostXVSetPortAttribute (port_priv->port_number, + host_atom, + a_attr_value)) { + EPHYR_LOG_ERROR ("failed to set port attribute\n") ; + res = BadMatch ; + goto out ; + } + + res = Success ; +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +static int +ephyrGetPortAttribute (KdScreenInfo *a_screen_info, + Atom a_attr_name, + int *a_attr_value, + pointer a_port_priv) +{ + int res=Success, host_atom=0 ; + EphyrPortPriv *port_priv = a_port_priv ; + + EPHYR_RETURN_VAL_IF_FAIL (port_priv, BadMatch) ; + EPHYR_RETURN_VAL_IF_FAIL (ValidAtom (a_attr_name), BadMatch) ; + + EPHYR_LOG ("enter, portnum:%d, atomid:%d, attr_name:%s\n", + port_priv->port_number, + (int)a_attr_name, + NameForAtom (a_attr_name)) ; + + if (!ephyrLocalAtomToHost (a_attr_name, &host_atom)) { + EPHYR_LOG_ERROR ("failed to convert local atom to host atom\n") ; + res = BadMatch ; + goto out ; + } + + if (!ephyrHostXVGetPortAttribute (port_priv->port_number, + host_atom, + a_attr_value)) { + EPHYR_LOG_ERROR ("failed to get port attribute\n") ; + res = BadMatch ; + goto out ; + } + + res = Success ; +out: + EPHYR_LOG ("leave\n") ; + return res ; +} + +static void +ephyrQueryBestSize (KdScreenInfo *a_info, + Bool a_motion, + short a_src_w, + short a_src_h, + short a_drw_w, + short a_drw_h, + unsigned int *a_prefered_w, + unsigned int *a_prefered_h, + pointer a_port_priv) +{ + int res=0 ; + EphyrPortPriv *port_priv = a_port_priv ; + + EPHYR_RETURN_IF_FAIL (port_priv) ; + + EPHYR_LOG ("enter\n") ; + res = ephyrHostXVQueryBestSize (port_priv->port_number, + a_motion, + a_src_w, a_src_h, + a_drw_w, a_drw_h, + a_prefered_w, a_prefered_h) ; + if (!res) { + EPHYR_LOG_ERROR ("Failed to query best size\n") ; + } + EPHYR_LOG ("leave\n") ; +} + +static int +ephyrPutImage (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_src_x, + short a_src_y, + short a_drw_x, + short a_drw_y, + short a_src_w, + short a_src_h, + short a_drw_w, + short a_drw_h, + int a_id, + unsigned char *a_buf, + short a_width, + short a_height, + Bool a_sync, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + Bool is_ok=FALSE ; + int result=BadImplementation, image_size=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + if (!ephyrHostXVPutImage (a_info->pScreen->myNum, + port_priv->port_number, + a_id, + a_drw_x, a_drw_y, a_drw_w, a_drw_h, + a_src_x, a_src_y, a_src_w, a_src_h, + a_width, a_height, a_buf, + (EphyrHostBox*)REGION_RECTS (a_clipping_region), + REGION_NUM_RECTS (a_clipping_region))) { + EPHYR_LOG_ERROR ("EphyrHostXVPutImage() failed\n") ; + goto out ; + } + + /* + * Now save the image so that we can resend it to host it + * later, in ReputImage. + */ + if (!ephyrXVPrivGetImageBufSize (port_priv->port_number, + a_id, a_width, a_height, &image_size)) { + EPHYR_LOG_ERROR ("failed to get image size\n") ; + /*this is a minor error so we won't get bail out abruptly*/ + is_ok = FALSE ; + } else { + is_ok = TRUE ; + } + if (is_ok) { + if (!ephyrXVPrivSaveImageToPortPriv (port_priv, a_buf, image_size)) { + is_ok=FALSE ; + } else { + port_priv->image_id = a_id; + port_priv->drw_x = a_drw_x; + port_priv->drw_y = a_drw_y; + port_priv->drw_w = a_drw_w ; + port_priv->drw_h = a_drw_h ; + port_priv->src_x = a_src_x; + port_priv->src_y = a_src_y ; + port_priv->src_w = a_src_w ; + port_priv->src_h = a_src_h ; + port_priv->image_width = a_width ; + port_priv->image_height = a_height ; + } + } + if (!is_ok) { + if (port_priv->image_buf) { + free (port_priv->image_buf) ; + port_priv->image_buf = NULL ; + port_priv->image_buf_size = 0 ; + } + } + + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrReputImage (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_drw_x, + short a_drw_y, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + int result=BadImplementation ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info->pScreen, FALSE) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + if (!port_priv->image_buf_size || !port_priv->image_buf) { + EPHYR_LOG_ERROR ("has null image buf in cache\n") ; + goto out ; + } + if (!ephyrHostXVPutImage (a_info->pScreen->myNum, + port_priv->port_number, + port_priv->image_id, + a_drw_x, a_drw_y, + port_priv->drw_w, port_priv->drw_h, + port_priv->src_x, port_priv->src_y, + port_priv->src_w, port_priv->src_h, + port_priv->image_width, port_priv->image_height, + port_priv->image_buf, + (EphyrHostBox*)REGION_RECTS (a_clipping_region), + REGION_NUM_RECTS (a_clipping_region))) { + EPHYR_LOG_ERROR ("ephyrHostXVPutImage() failed\n") ; + goto out ; + } + + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrPutVideo (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + BoxRec clipped_area, dst_box ; + int result=BadImplementation ; + int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info->pScreen, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + dst_box.x1 = a_drw_x ; + dst_box.x2 = a_drw_x + a_drw_w; + dst_box.y1 = a_drw_y ; + dst_box.y2 = a_drw_y + a_drw_h; + + if (!DoSimpleClip (&dst_box, + REGION_EXTENTS (pScreen->pScreen, a_clipping_region), + &clipped_area)) { + EPHYR_LOG_ERROR ("failed to simple clip\n") ; + goto out ; + } + + drw_x = clipped_area.x1 ; + drw_y = clipped_area.y1 ; + drw_w = clipped_area.x2 - clipped_area.x1 ; + drw_h = clipped_area.y2 - clipped_area.y1 ; + + if (!ephyrHostXVPutVideo (a_info->pScreen->myNum, + port_priv->port_number, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { + EPHYR_LOG_ERROR ("ephyrHostXVPutVideo() failed\n") ; + goto out ; + } + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrGetVideo (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + BoxRec clipped_area, dst_box ; + int result=BadImplementation ; + int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + dst_box.x1 = a_drw_x ; + dst_box.x2 = a_drw_x + a_drw_w; + dst_box.y1 = a_drw_y ; + dst_box.y2 = a_drw_y + a_drw_h; + + if (!DoSimpleClip (&dst_box, + REGION_EXTENTS (pScreen->pScreen, a_clipping_region), + &clipped_area)) { + EPHYR_LOG_ERROR ("failed to simple clip\n") ; + goto out ; + } + + drw_x = clipped_area.x1 ; + drw_y = clipped_area.y1 ; + drw_w = clipped_area.x2 - clipped_area.x1 ; + drw_h = clipped_area.y2 - clipped_area.y1 ; + + if (!ephyrHostXVGetVideo (a_info->pScreen->myNum, + port_priv->port_number, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { + EPHYR_LOG_ERROR ("ephyrHostXVGetVideo() failed\n") ; + goto out ; + } + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrPutStill (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + BoxRec clipped_area, dst_box ; + int result=BadImplementation ; + int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + dst_box.x1 = a_drw_x ; + dst_box.x2 = a_drw_x + a_drw_w; + dst_box.y1 = a_drw_y ; + dst_box.y2 = a_drw_y + a_drw_h; + + if (!DoSimpleClip (&dst_box, + REGION_EXTENTS (pScreen->pScreen, a_clipping_region), + &clipped_area)) { + EPHYR_LOG_ERROR ("failed to simple clip\n") ; + goto out ; + } + + drw_x = clipped_area.x1 ; + drw_y = clipped_area.y1 ; + drw_w = clipped_area.x2 - clipped_area.x1 ; + drw_h = clipped_area.y2 - clipped_area.y1 ; + + if (!ephyrHostXVPutStill (a_info->pScreen->myNum, + port_priv->port_number, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { + EPHYR_LOG_ERROR ("ephyrHostXVPutStill() failed\n") ; + goto out ; + } + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrGetStill (KdScreenInfo *a_info, + DrawablePtr a_drawable, + short a_vid_x, short a_vid_y, + short a_drw_x, short a_drw_y, + short a_vid_w, short a_vid_h, + short a_drw_w, short a_drw_h, + RegionPtr a_clipping_region, + pointer a_port_priv) +{ + EphyrPortPriv *port_priv = a_port_priv ; + BoxRec clipped_area, dst_box ; + int result=BadImplementation ; + int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; + EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; + + EPHYR_LOG ("enter\n") ; + + dst_box.x1 = a_drw_x ; + dst_box.x2 = a_drw_x + a_drw_w; + dst_box.y1 = a_drw_y ; + dst_box.y2 = a_drw_y + a_drw_h; + + if (!DoSimpleClip (&dst_box, + REGION_EXTENTS (pScreen->pScreen, a_clipping_region), + &clipped_area)) { + EPHYR_LOG_ERROR ("failed to simple clip\n") ; + goto out ; + } + + drw_x = clipped_area.x1 ; + drw_y = clipped_area.y1 ; + drw_w = clipped_area.x2 - clipped_area.x1 ; + drw_h = clipped_area.y2 - clipped_area.y1 ; + + if (!ephyrHostXVGetStill (a_info->pScreen->myNum, + port_priv->port_number, + a_vid_x, a_vid_y, a_vid_w, a_vid_h, + a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { + EPHYR_LOG_ERROR ("ephyrHostXVGetStill() failed\n") ; + goto out ; + } + result = Success ; + +out: + EPHYR_LOG ("leave\n") ; + return result ; +} + +static int +ephyrQueryImageAttributes (KdScreenInfo *a_info, + int a_id, + unsigned short *a_w, + unsigned short *a_h, + int *a_pitches, + int *a_offsets) +{ + int image_size=0 ; + + EPHYR_RETURN_VAL_IF_FAIL (a_w && a_h, FALSE) ; + + EPHYR_LOG ("enter: dim (%dx%d), pitches: %p, offsets: %p\n", + *a_w, *a_h, a_pitches, a_offsets) ; + + if (!ephyrHostXVQueryImageAttributes (s_base_port_id, + a_id, + a_w, a_h, + &image_size, + a_pitches, a_offsets)) { + EPHYR_LOG_ERROR ("EphyrHostXVQueryImageAttributes() failed\n") ; + goto out ; + } + EPHYR_LOG ("image size: %d, dim (%dx%d)\n", image_size, *a_w, *a_h) ; + +out: + EPHYR_LOG ("leave\n") ; + return image_size ; +} diff --git a/xorg-server/hw/kdrive/fake/fake.c b/xorg-server/hw/kdrive/fake/fake.c index 809e309a6..9f2327d94 100644 --- a/xorg-server/hw/kdrive/fake/fake.c +++ b/xorg-server/hw/kdrive/fake/fake.c @@ -1,476 +1,476 @@ -/* - * Copyright © 2004 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "fake.h" - -extern int KdTsPhyScreen; - -Bool -fakeInitialize (KdCardInfo *card, FakePriv *priv) -{ - priv->base = 0; - priv->bytes_per_line = 0; - return TRUE; -} - -Bool -fakeCardInit (KdCardInfo *card) -{ - FakePriv *priv; - - priv = (FakePriv *) xalloc (sizeof (FakePriv)); - if (!priv) - return FALSE; - - if (!fakeInitialize (card, priv)) - { - xfree (priv); - return FALSE; - } - card->driver = priv; - - return TRUE; -} - -Bool -fakeScreenInitialize (KdScreenInfo *screen, FakeScrPriv *scrpriv) -{ - if (!screen->width || !screen->height) - { - screen->width = 1024; - screen->height = 768; - screen->rate = 72; - } - - if (screen->width <= 0) - screen->width = 1; - if (screen->height <= 0) - screen->height = 1; - - if (!screen->fb.depth) - screen->fb.depth = 16; - - if (screen->fb.depth <= 8) - { - screen->fb.visuals = ((1 << StaticGray) | - (1 << GrayScale) | - (1 << StaticColor) | - (1 << PseudoColor) | - (1 << TrueColor) | - (1 << DirectColor)); - } - else - { - screen->fb.visuals = (1 << TrueColor); -#define Mask(o,l) (((1 << l) - 1) << o) - if (screen->fb.depth <= 15) - { - screen->fb.depth = 15; - screen->fb.bitsPerPixel = 16; - screen->fb.redMask = Mask (10, 5); - screen->fb.greenMask = Mask (5, 5); - screen->fb.blueMask = Mask (0, 5); - } - else if (screen->fb.depth <= 16) - { - screen->fb.depth = 16; - screen->fb.bitsPerPixel = 16; - screen->fb.redMask = Mask (11, 5); - screen->fb.greenMask = Mask (5, 6); - screen->fb.blueMask = Mask (0, 5); - } - else - { - screen->fb.depth = 24; - screen->fb.bitsPerPixel = 32; - screen->fb.redMask = Mask (16, 8); - screen->fb.greenMask = Mask (8, 8); - screen->fb.blueMask = Mask (0, 8); - } - } - - scrpriv->randr = screen->randr; - - return fakeMapFramebuffer (screen); -} - -Bool -fakeScreenInit (KdScreenInfo *screen) -{ - FakeScrPriv *scrpriv; - - scrpriv = xcalloc (1, sizeof (FakeScrPriv)); - if (!scrpriv) - return FALSE; - screen->driver = scrpriv; - if (!fakeScreenInitialize (screen, scrpriv)) - { - screen->driver = 0; - xfree (scrpriv); - return FALSE; - } - return TRUE; -} - -void * -fakeWindowLinear (ScreenPtr pScreen, - CARD32 row, - CARD32 offset, - int mode, - CARD32 *size, - void *closure) -{ - KdScreenPriv(pScreen); - FakePriv *priv = pScreenPriv->card->driver; - - if (!pScreenPriv->enabled) - return 0; - *size = priv->bytes_per_line; - return priv->base + row * priv->bytes_per_line; -} - -Bool -fakeMapFramebuffer (KdScreenInfo *screen) -{ - FakeScrPriv *scrpriv = screen->driver; - KdPointerMatrix m; - FakePriv *priv = screen->card->driver; - - if (scrpriv->randr != RR_Rotate_0) - scrpriv->shadow = TRUE; - else - scrpriv->shadow = FALSE; - - KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); - - KdSetPointerMatrix (&m); - - priv->bytes_per_line = ((screen->width * screen->fb.bitsPerPixel + 31) >> 5) << 2; - if (priv->base) - free (priv->base); - priv->base = malloc (priv->bytes_per_line * screen->height); - - if (scrpriv->shadow) - { - if (!KdShadowFbAlloc (screen, scrpriv->randr & (RR_Rotate_90|RR_Rotate_270))) - return FALSE; - } - else - { - screen->fb.byteStride = priv->bytes_per_line; - screen->fb.pixelStride = (priv->bytes_per_line * 8/ - screen->fb.bitsPerPixel); - screen->fb.frameBuffer = (CARD8 *) (priv->base); - } - - return TRUE; -} - -void -fakeSetScreenSizes (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FakeScrPriv *scrpriv = screen->driver; - - if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) - { - pScreen->width = screen->width; - pScreen->height = screen->height; - pScreen->mmWidth = screen->width_mm; - pScreen->mmHeight = screen->height_mm; - } - else - { - pScreen->width = screen->width; - pScreen->height = screen->height; - pScreen->mmWidth = screen->height_mm; - pScreen->mmHeight = screen->width_mm; - } -} - -Bool -fakeUnmapFramebuffer (KdScreenInfo *screen) -{ - FakePriv *priv = screen->card->driver; - KdShadowFbFree (screen); - if (priv->base) - { - free (priv->base); - priv->base = 0; - } - return TRUE; -} - -Bool -fakeSetShadow (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FakeScrPriv *scrpriv = screen->driver; - ShadowUpdateProc update; - ShadowWindowProc window; - - window = fakeWindowLinear; - update = 0; - if (scrpriv->randr) - update = shadowUpdateRotatePacked; - else - update = shadowUpdatePacked; - return KdShadowSet (pScreen, scrpriv->randr, update, window); -} - - -#ifdef RANDR -Bool -fakeRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FakeScrPriv *scrpriv = screen->driver; - RRScreenSizePtr pSize; - Rotation randr; - int n; - - *rotations = RR_Rotate_All|RR_Reflect_All; - - for (n = 0; n < pScreen->numDepths; n++) - if (pScreen->allowedDepths[n].numVids) - break; - if (n == pScreen->numDepths) - return FALSE; - - pSize = RRRegisterSize (pScreen, - screen->width, - screen->height, - screen->width_mm, - screen->height_mm); - - randr = KdSubRotation (scrpriv->randr, screen->randr); - - RRSetCurrentConfig (pScreen, randr, 0, pSize); - - return TRUE; -} - -Bool -fakeRandRSetConfig (ScreenPtr pScreen, - Rotation randr, - int rate, - RRScreenSizePtr pSize) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FakeScrPriv *scrpriv = screen->driver; - Bool wasEnabled = pScreenPriv->enabled; - FakeScrPriv oldscr; - int oldwidth; - int oldheight; - int oldmmwidth; - int oldmmheight; - int newwidth, newheight; - - if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) - { - newwidth = pSize->width; - newheight = pSize->height; - } - else - { - newwidth = pSize->height; - newheight = pSize->width; - } - - if (wasEnabled) - KdDisableScreen (pScreen); - - oldscr = *scrpriv; - - oldwidth = screen->width; - oldheight = screen->height; - oldmmwidth = pScreen->mmWidth; - oldmmheight = pScreen->mmHeight; - - /* - * Set new configuration - */ - - scrpriv->randr = KdAddRotation (screen->randr, randr); - - fakeUnmapFramebuffer (screen); - - if (!fakeMapFramebuffer (screen)) - goto bail4; - - KdShadowUnset (screen->pScreen); - - if (!fakeSetShadow (screen->pScreen)) - goto bail4; - - fakeSetScreenSizes (screen->pScreen); - - /* - * Set frame buffer mapping - */ - (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), - pScreen->width, - pScreen->height, - screen->fb.depth, - screen->fb.bitsPerPixel, - screen->fb.byteStride, - screen->fb.frameBuffer); - - /* set the subpixel order */ - - KdSetSubpixelOrder (pScreen, scrpriv->randr); - if (wasEnabled) - KdEnableScreen (pScreen); - - return TRUE; - -bail4: - fakeUnmapFramebuffer (screen); - *scrpriv = oldscr; - (void) fakeMapFramebuffer (screen); - pScreen->width = oldwidth; - pScreen->height = oldheight; - pScreen->mmWidth = oldmmwidth; - pScreen->mmHeight = oldmmheight; - - if (wasEnabled) - KdEnableScreen (pScreen); - return FALSE; -} - -Bool -fakeRandRInit (ScreenPtr pScreen) -{ - rrScrPrivPtr pScrPriv; - - if (!RRScreenInit (pScreen)) - return FALSE; - - pScrPriv = rrGetScrPriv(pScreen); - pScrPriv->rrGetInfo = fakeRandRGetInfo; - pScrPriv->rrSetConfig = fakeRandRSetConfig; - return TRUE; -} -#endif - -Bool -fakeCreateColormap (ColormapPtr pmap) -{ - return fbInitializeColormap (pmap); -} - -Bool -fakeInitScreen (ScreenPtr pScreen) -{ -#ifdef TOUCHSCREEN - KdTsPhyScreen = pScreen->myNum; -#endif - - pScreen->CreateColormap = fakeCreateColormap; - return TRUE; -} - -Bool -fakeFinishInitScreen (ScreenPtr pScreen) -{ - if (!shadowSetup (pScreen)) - return FALSE; - -#ifdef RANDR - if (!fakeRandRInit (pScreen)) - return FALSE; -#endif - - return TRUE; -} - - -Bool -fakeCreateResources (ScreenPtr pScreen) -{ - return fakeSetShadow (pScreen); -} - -void -fakePreserve (KdCardInfo *card) -{ -} - -Bool -fakeEnable (ScreenPtr pScreen) -{ - return TRUE; -} - -Bool -fakeDPMS (ScreenPtr pScreen, int mode) -{ - return TRUE; -} - -void -fakeDisable (ScreenPtr pScreen) -{ -} - -void -fakeRestore (KdCardInfo *card) -{ -} - -void -fakeScreenFini (KdScreenInfo *screen) -{ -} - -void -fakeCardFini (KdCardInfo *card) -{ - FakePriv *priv = card->driver; - - free (priv->base); - xfree (priv); -} - -void -fakeGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ - while (n--) - { - pdefs->red = 0; - pdefs->green = 0; - pdefs->blue = 0; - pdefs++; - } -} - -void -fakePutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ -} +/* + * Copyright © 2004 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "fake.h" + +extern int KdTsPhyScreen; + +Bool +fakeInitialize (KdCardInfo *card, FakePriv *priv) +{ + priv->base = 0; + priv->bytes_per_line = 0; + return TRUE; +} + +Bool +fakeCardInit (KdCardInfo *card) +{ + FakePriv *priv; + + priv = (FakePriv *) malloc(sizeof (FakePriv)); + if (!priv) + return FALSE; + + if (!fakeInitialize (card, priv)) + { + free(priv); + return FALSE; + } + card->driver = priv; + + return TRUE; +} + +Bool +fakeScreenInitialize (KdScreenInfo *screen, FakeScrPriv *scrpriv) +{ + if (!screen->width || !screen->height) + { + screen->width = 1024; + screen->height = 768; + screen->rate = 72; + } + + if (screen->width <= 0) + screen->width = 1; + if (screen->height <= 0) + screen->height = 1; + + if (!screen->fb.depth) + screen->fb.depth = 16; + + if (screen->fb.depth <= 8) + { + screen->fb.visuals = ((1 << StaticGray) | + (1 << GrayScale) | + (1 << StaticColor) | + (1 << PseudoColor) | + (1 << TrueColor) | + (1 << DirectColor)); + } + else + { + screen->fb.visuals = (1 << TrueColor); +#define Mask(o,l) (((1 << l) - 1) << o) + if (screen->fb.depth <= 15) + { + screen->fb.depth = 15; + screen->fb.bitsPerPixel = 16; + screen->fb.redMask = Mask (10, 5); + screen->fb.greenMask = Mask (5, 5); + screen->fb.blueMask = Mask (0, 5); + } + else if (screen->fb.depth <= 16) + { + screen->fb.depth = 16; + screen->fb.bitsPerPixel = 16; + screen->fb.redMask = Mask (11, 5); + screen->fb.greenMask = Mask (5, 6); + screen->fb.blueMask = Mask (0, 5); + } + else + { + screen->fb.depth = 24; + screen->fb.bitsPerPixel = 32; + screen->fb.redMask = Mask (16, 8); + screen->fb.greenMask = Mask (8, 8); + screen->fb.blueMask = Mask (0, 8); + } + } + + scrpriv->randr = screen->randr; + + return fakeMapFramebuffer (screen); +} + +Bool +fakeScreenInit (KdScreenInfo *screen) +{ + FakeScrPriv *scrpriv; + + scrpriv = calloc(1, sizeof (FakeScrPriv)); + if (!scrpriv) + return FALSE; + screen->driver = scrpriv; + if (!fakeScreenInitialize (screen, scrpriv)) + { + screen->driver = 0; + free(scrpriv); + return FALSE; + } + return TRUE; +} + +void * +fakeWindowLinear (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size, + void *closure) +{ + KdScreenPriv(pScreen); + FakePriv *priv = pScreenPriv->card->driver; + + if (!pScreenPriv->enabled) + return 0; + *size = priv->bytes_per_line; + return priv->base + row * priv->bytes_per_line; +} + +Bool +fakeMapFramebuffer (KdScreenInfo *screen) +{ + FakeScrPriv *scrpriv = screen->driver; + KdPointerMatrix m; + FakePriv *priv = screen->card->driver; + + if (scrpriv->randr != RR_Rotate_0) + scrpriv->shadow = TRUE; + else + scrpriv->shadow = FALSE; + + KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); + + KdSetPointerMatrix (&m); + + priv->bytes_per_line = ((screen->width * screen->fb.bitsPerPixel + 31) >> 5) << 2; + if (priv->base) + free (priv->base); + priv->base = malloc (priv->bytes_per_line * screen->height); + + if (scrpriv->shadow) + { + if (!KdShadowFbAlloc (screen, scrpriv->randr & (RR_Rotate_90|RR_Rotate_270))) + return FALSE; + } + else + { + screen->fb.byteStride = priv->bytes_per_line; + screen->fb.pixelStride = (priv->bytes_per_line * 8/ + screen->fb.bitsPerPixel); + screen->fb.frameBuffer = (CARD8 *) (priv->base); + } + + return TRUE; +} + +void +fakeSetScreenSizes (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FakeScrPriv *scrpriv = screen->driver; + + if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) + { + pScreen->width = screen->width; + pScreen->height = screen->height; + pScreen->mmWidth = screen->width_mm; + pScreen->mmHeight = screen->height_mm; + } + else + { + pScreen->width = screen->width; + pScreen->height = screen->height; + pScreen->mmWidth = screen->height_mm; + pScreen->mmHeight = screen->width_mm; + } +} + +Bool +fakeUnmapFramebuffer (KdScreenInfo *screen) +{ + FakePriv *priv = screen->card->driver; + KdShadowFbFree (screen); + if (priv->base) + { + free (priv->base); + priv->base = 0; + } + return TRUE; +} + +Bool +fakeSetShadow (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FakeScrPriv *scrpriv = screen->driver; + ShadowUpdateProc update; + ShadowWindowProc window; + + window = fakeWindowLinear; + update = 0; + if (scrpriv->randr) + update = shadowUpdateRotatePacked; + else + update = shadowUpdatePacked; + return KdShadowSet (pScreen, scrpriv->randr, update, window); +} + + +#ifdef RANDR +Bool +fakeRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FakeScrPriv *scrpriv = screen->driver; + RRScreenSizePtr pSize; + Rotation randr; + int n; + + *rotations = RR_Rotate_All|RR_Reflect_All; + + for (n = 0; n < pScreen->numDepths; n++) + if (pScreen->allowedDepths[n].numVids) + break; + if (n == pScreen->numDepths) + return FALSE; + + pSize = RRRegisterSize (pScreen, + screen->width, + screen->height, + screen->width_mm, + screen->height_mm); + + randr = KdSubRotation (scrpriv->randr, screen->randr); + + RRSetCurrentConfig (pScreen, randr, 0, pSize); + + return TRUE; +} + +Bool +fakeRandRSetConfig (ScreenPtr pScreen, + Rotation randr, + int rate, + RRScreenSizePtr pSize) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FakeScrPriv *scrpriv = screen->driver; + Bool wasEnabled = pScreenPriv->enabled; + FakeScrPriv oldscr; + int oldwidth; + int oldheight; + int oldmmwidth; + int oldmmheight; + int newwidth, newheight; + + if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) + { + newwidth = pSize->width; + newheight = pSize->height; + } + else + { + newwidth = pSize->height; + newheight = pSize->width; + } + + if (wasEnabled) + KdDisableScreen (pScreen); + + oldscr = *scrpriv; + + oldwidth = screen->width; + oldheight = screen->height; + oldmmwidth = pScreen->mmWidth; + oldmmheight = pScreen->mmHeight; + + /* + * Set new configuration + */ + + scrpriv->randr = KdAddRotation (screen->randr, randr); + + fakeUnmapFramebuffer (screen); + + if (!fakeMapFramebuffer (screen)) + goto bail4; + + KdShadowUnset (screen->pScreen); + + if (!fakeSetShadow (screen->pScreen)) + goto bail4; + + fakeSetScreenSizes (screen->pScreen); + + /* + * Set frame buffer mapping + */ + (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), + pScreen->width, + pScreen->height, + screen->fb.depth, + screen->fb.bitsPerPixel, + screen->fb.byteStride, + screen->fb.frameBuffer); + + /* set the subpixel order */ + + KdSetSubpixelOrder (pScreen, scrpriv->randr); + if (wasEnabled) + KdEnableScreen (pScreen); + + return TRUE; + +bail4: + fakeUnmapFramebuffer (screen); + *scrpriv = oldscr; + (void) fakeMapFramebuffer (screen); + pScreen->width = oldwidth; + pScreen->height = oldheight; + pScreen->mmWidth = oldmmwidth; + pScreen->mmHeight = oldmmheight; + + if (wasEnabled) + KdEnableScreen (pScreen); + return FALSE; +} + +Bool +fakeRandRInit (ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + + if (!RRScreenInit (pScreen)) + return FALSE; + + pScrPriv = rrGetScrPriv(pScreen); + pScrPriv->rrGetInfo = fakeRandRGetInfo; + pScrPriv->rrSetConfig = fakeRandRSetConfig; + return TRUE; +} +#endif + +Bool +fakeCreateColormap (ColormapPtr pmap) +{ + return fbInitializeColormap (pmap); +} + +Bool +fakeInitScreen (ScreenPtr pScreen) +{ +#ifdef TOUCHSCREEN + KdTsPhyScreen = pScreen->myNum; +#endif + + pScreen->CreateColormap = fakeCreateColormap; + return TRUE; +} + +Bool +fakeFinishInitScreen (ScreenPtr pScreen) +{ + if (!shadowSetup (pScreen)) + return FALSE; + +#ifdef RANDR + if (!fakeRandRInit (pScreen)) + return FALSE; +#endif + + return TRUE; +} + + +Bool +fakeCreateResources (ScreenPtr pScreen) +{ + return fakeSetShadow (pScreen); +} + +void +fakePreserve (KdCardInfo *card) +{ +} + +Bool +fakeEnable (ScreenPtr pScreen) +{ + return TRUE; +} + +Bool +fakeDPMS (ScreenPtr pScreen, int mode) +{ + return TRUE; +} + +void +fakeDisable (ScreenPtr pScreen) +{ +} + +void +fakeRestore (KdCardInfo *card) +{ +} + +void +fakeScreenFini (KdScreenInfo *screen) +{ +} + +void +fakeCardFini (KdCardInfo *card) +{ + FakePriv *priv = card->driver; + + free (priv->base); + free(priv); +} + +void +fakeGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + while (n--) + { + pdefs->red = 0; + pdefs->green = 0; + pdefs->blue = 0; + pdefs++; + } +} + +void +fakePutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ +} diff --git a/xorg-server/hw/kdrive/fbdev/fbdev.c b/xorg-server/hw/kdrive/fbdev/fbdev.c index d4604ad29..b127ab89b 100644 --- a/xorg-server/hw/kdrive/fbdev/fbdev.c +++ b/xorg-server/hw/kdrive/fbdev/fbdev.c @@ -1,826 +1,826 @@ -/* - * Copyright © 1999 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "fbdev.h" -#include - -#include - -extern int KdTsPhyScreen; - -char *fbdevDevicePath = NULL; - -static Bool -fbdevInitialize (KdCardInfo *card, FbdevPriv *priv) -{ - unsigned long off; - - if (fbdevDevicePath == NULL) - fbdevDevicePath = "/dev/fb0"; - - if ((priv->fd = open(fbdevDevicePath, O_RDWR)) < 0) - { - ErrorF("Error opening framebuffer %s: %s\n", - fbdevDevicePath, strerror(errno)); - return FALSE; - } - - /* quiet valgrind */ - memset (&priv->fix, '\0', sizeof (priv->fix)); - if (ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix) < 0) { - perror("Error with /dev/fb ioctl FIOGET_FSCREENINFO"); - close (priv->fd); - return FALSE; - } - /* quiet valgrind */ - memset (&priv->var, '\0', sizeof (priv->var)); - if (ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var) < 0) { - perror("Error with /dev/fb ioctl FIOGET_VSCREENINFO"); - close (priv->fd); - return FALSE; - } - - priv->fb_base = (char *) mmap ((caddr_t) NULL, - priv->fix.smem_len, - PROT_READ|PROT_WRITE, - MAP_SHARED, - priv->fd, 0); - - if (priv->fb_base == (char *)-1) - { - perror("ERROR: mmap framebuffer fails!"); - close (priv->fd); - return FALSE; - } - off = (unsigned long) priv->fix.smem_start % (unsigned long) getpagesize(); - priv->fb = priv->fb_base + off; - return TRUE; -} - -Bool -fbdevCardInit (KdCardInfo *card) -{ - FbdevPriv *priv; - - priv = (FbdevPriv *) xalloc (sizeof (FbdevPriv)); - if (!priv) - return FALSE; - - if (!fbdevInitialize (card, priv)) - { - xfree (priv); - return FALSE; - } - card->driver = priv; - - return TRUE; -} - -static Pixel -fbdevMakeContig (Pixel orig, Pixel others) -{ - Pixel low; - - low = lowbit (orig) >> 1; - while (low && (others & low) == 0) - { - orig |= low; - low >>= 1; - } - return orig; -} - -static Bool -fbdevModeSupported (KdScreenInfo *screen, - const KdMonitorTiming *t) -{ - return TRUE; -} - -static void -fbdevConvertMonitorTiming (const KdMonitorTiming *t, struct fb_var_screeninfo *var) -{ - memset (var, 0, sizeof (struct fb_var_screeninfo)); - - var->xres = t->horizontal; - var->yres = t->vertical; - var->xres_virtual = t->horizontal; - var->yres_virtual = t->vertical; - var->xoffset = 0; - var->yoffset = 0; - var->pixclock = t->clock ? 1000000000 / t->clock : 0; - var->left_margin = t->hbp; - var->right_margin = t->hfp; - var->upper_margin = t->vbp; - var->lower_margin = t->vfp; - var->hsync_len = t->hblank - t->hfp - t->hbp; - var->vsync_len = t->vblank - t->vfp - t->vbp; - - var->sync = 0; - var->vmode = 0; - - if (t->hpol == KdSyncPositive) - var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (t->vpol == KdSyncPositive) - var->sync |= FB_SYNC_VERT_HIGH_ACT; -} - -static Bool -fbdevScreenInitialize (KdScreenInfo *screen, FbdevScrPriv *scrpriv) -{ - FbdevPriv *priv = screen->card->driver; - Pixel allbits; - int depth; - Bool gray; - struct fb_var_screeninfo var; - const KdMonitorTiming *t; - int k; - - k = ioctl (priv->fd, FBIOGET_VSCREENINFO, &var); - - if (!screen->width || !screen->height) - { - if (k >= 0) - { - screen->width = var.xres; - screen->height = var.yres; - } - else - { - screen->width = 1024; - screen->height = 768; - } - screen->rate = 103; /* FIXME: should get proper value from fb driver */ - } - if (!screen->fb.depth) - { - if (k >= 0) - screen->fb.depth = var.bits_per_pixel; - else - screen->fb.depth = 16; - } - - if ((screen->width != var.xres) || (screen->height != var.yres)) - { - t = KdFindMode (screen, fbdevModeSupported); - screen->rate = t->rate; - screen->width = t->horizontal; - screen->height = t->vertical; - - /* Now try setting the mode */ - if (k < 0 || (t->horizontal != var.xres || t->vertical != var.yres)) - fbdevConvertMonitorTiming (t, &var); - } - - var.activate = FB_ACTIVATE_NOW; - var.bits_per_pixel = screen->fb.depth; - var.nonstd = 0; - var.grayscale = 0; - - k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &var); - - if (k < 0) - { - fprintf (stderr, "error: %s\n", strerror (errno)); - return FALSE; - } - - /* Re-get the "fixed" parameters since they might have changed */ - k = ioctl (priv->fd, FBIOGET_FSCREENINFO, &priv->fix); - if (k < 0) - perror ("FBIOGET_FSCREENINFO"); - - /* Now get the new screeninfo */ - ioctl (priv->fd, FBIOGET_VSCREENINFO, &priv->var); - depth = priv->var.bits_per_pixel; - gray = priv->var.grayscale; - - switch (priv->fix.visual) { - case FB_VISUAL_PSEUDOCOLOR: - if (gray) - { - screen->fb.visuals = (1 << StaticGray); - /* could also support GrayScale, but what's the point? */ - } - else - { - screen->fb.visuals = ((1 << StaticGray) | - (1 << GrayScale) | - (1 << StaticColor) | - (1 << PseudoColor) | - (1 << TrueColor) | - (1 << DirectColor)); - } - screen->fb.blueMask = 0x00; - screen->fb.greenMask = 0x00; - screen->fb.redMask = 0x00; - break; - case FB_VISUAL_STATIC_PSEUDOCOLOR: - if (gray) - { - screen->fb.visuals = (1 << StaticGray); - } - else - { - screen->fb.visuals = (1 << StaticColor); - } - screen->fb.blueMask = 0x00; - screen->fb.greenMask = 0x00; - screen->fb.redMask = 0x00; - break; - case FB_VISUAL_TRUECOLOR: - case FB_VISUAL_DIRECTCOLOR: - screen->fb.visuals = (1 << TrueColor); -#define Mask(o,l) (((1 << l) - 1) << o) - screen->fb.redMask = Mask (priv->var.red.offset, priv->var.red.length); - screen->fb.greenMask = Mask (priv->var.green.offset, priv->var.green.length); - screen->fb.blueMask = Mask (priv->var.blue.offset, priv->var.blue.length); - - /* - * This is a kludge so that Render will work -- fill in the gaps - * in the pixel - */ - screen->fb.redMask = fbdevMakeContig (screen->fb.redMask, - screen->fb.greenMask| - screen->fb.blueMask); - - screen->fb.greenMask = fbdevMakeContig (screen->fb.greenMask, - screen->fb.redMask| - screen->fb.blueMask); - - screen->fb.blueMask = fbdevMakeContig (screen->fb.blueMask, - screen->fb.redMask| - screen->fb.greenMask); - - allbits = screen->fb.redMask | screen->fb.greenMask | screen->fb.blueMask; - depth = 32; - while (depth && !(allbits & (1 << (depth - 1)))) - depth--; - break; - default: - return FALSE; - break; - } - screen->fb.depth = depth; - screen->fb.bitsPerPixel = priv->var.bits_per_pixel; - - scrpriv->randr = screen->randr; - - return fbdevMapFramebuffer (screen); -} - -Bool -fbdevScreenInit (KdScreenInfo *screen) -{ - FbdevScrPriv *scrpriv; - - scrpriv = xcalloc (1, sizeof (FbdevScrPriv)); - if (!scrpriv) - return FALSE; - screen->driver = scrpriv; - if (!fbdevScreenInitialize (screen, scrpriv)) - { - screen->driver = 0; - xfree (scrpriv); - return FALSE; - } - return TRUE; -} - -static void * -fbdevWindowLinear (ScreenPtr pScreen, - CARD32 row, - CARD32 offset, - int mode, - CARD32 *size, - void *closure) -{ - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - - if (!pScreenPriv->enabled) - return 0; - *size = priv->fix.line_length; - return (CARD8 *) priv->fb + row * priv->fix.line_length + offset; -} - -Bool -fbdevMapFramebuffer (KdScreenInfo *screen) -{ - FbdevScrPriv *scrpriv = screen->driver; - KdPointerMatrix m; - FbdevPriv *priv = screen->card->driver; - - if (scrpriv->randr != RR_Rotate_0) - scrpriv->shadow = TRUE; - else - scrpriv->shadow = FALSE; - - KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); - - KdSetPointerMatrix (&m); - - screen->width = priv->var.xres; - screen->height = priv->var.yres; - - if (scrpriv->shadow) - { - if (!KdShadowFbAlloc (screen, - scrpriv->randr & (RR_Rotate_90|RR_Rotate_270))) - return FALSE; - } - else - { - screen->fb.byteStride = priv->fix.line_length; - screen->fb.pixelStride = (priv->fix.line_length * 8 / - priv->var.bits_per_pixel); - screen->fb.frameBuffer = (CARD8 *) (priv->fb); - } - - return TRUE; -} - -static void -fbdevSetScreenSizes (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FbdevScrPriv *scrpriv = screen->driver; - FbdevPriv *priv = screen->card->driver; - - if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) - { - pScreen->width = priv->var.xres; - pScreen->height = priv->var.yres; - pScreen->mmWidth = screen->width_mm; - pScreen->mmHeight = screen->height_mm; - } - else - { - pScreen->width = priv->var.yres; - pScreen->height = priv->var.xres; - pScreen->mmWidth = screen->height_mm; - pScreen->mmHeight = screen->width_mm; - } -} - -static Bool -fbdevUnmapFramebuffer (KdScreenInfo *screen) -{ - KdShadowFbFree (screen); - return TRUE; -} - -static Bool -fbdevSetShadow (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FbdevScrPriv *scrpriv = screen->driver; - FbdevPriv *priv = screen->card->driver; - ShadowUpdateProc update; - ShadowWindowProc window; - int useYX = 0; - -#ifdef __arm__ - /* Use variant copy routines that always read left to right in the - shadow framebuffer. Reading vertical strips is exceptionally - slow on XScale due to cache effects. */ - useYX = 1; -#endif - - window = fbdevWindowLinear; - update = 0; - if (scrpriv->randr) - if (priv->var.bits_per_pixel == 16) { - switch (scrpriv->randr) { - case RR_Rotate_90: - if (useYX) - update = shadowUpdateRotate16_90YX; - else - update = shadowUpdateRotate16_90; - break; - case RR_Rotate_180: - update = shadowUpdateRotate16_180; - break; - case RR_Rotate_270: - if (useYX) - update = shadowUpdateRotate16_270YX; - else - update = shadowUpdateRotate16_270; - break; - default: - update = shadowUpdateRotate16; - break; - } - } else - update = shadowUpdateRotatePacked; - else - update = shadowUpdatePacked; - return KdShadowSet (pScreen, scrpriv->randr, update, window); -} - - -#ifdef RANDR -static Bool -fbdevRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FbdevScrPriv *scrpriv = screen->driver; - RRScreenSizePtr pSize; - Rotation randr; - int n; - - *rotations = RR_Rotate_All|RR_Reflect_All; - - for (n = 0; n < pScreen->numDepths; n++) - if (pScreen->allowedDepths[n].numVids) - break; - if (n == pScreen->numDepths) - return FALSE; - - pSize = RRRegisterSize (pScreen, - screen->width, - screen->height, - screen->width_mm, - screen->height_mm); - - randr = KdSubRotation (scrpriv->randr, screen->randr); - - RRSetCurrentConfig (pScreen, randr, 0, pSize); - - return TRUE; -} - -static Bool -fbdevRandRSetConfig (ScreenPtr pScreen, - Rotation randr, - int rate, - RRScreenSizePtr pSize) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - FbdevScrPriv *scrpriv = screen->driver; - Bool wasEnabled = pScreenPriv->enabled; - FbdevScrPriv oldscr; - int oldwidth; - int oldheight; - int oldmmwidth; - int oldmmheight; - int newwidth, newheight; - - if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) - { - newwidth = pSize->width; - newheight = pSize->height; - } - else - { - newwidth = pSize->height; - newheight = pSize->width; - } - - if (wasEnabled) - KdDisableScreen (pScreen); - - oldscr = *scrpriv; - - oldwidth = screen->width; - oldheight = screen->height; - oldmmwidth = pScreen->mmWidth; - oldmmheight = pScreen->mmHeight; - - /* - * Set new configuration - */ - - scrpriv->randr = KdAddRotation (screen->randr, randr); - - fbdevUnmapFramebuffer (screen); - - if (!fbdevMapFramebuffer (screen)) - goto bail4; - - KdShadowUnset (screen->pScreen); - - if (!fbdevSetShadow (screen->pScreen)) - goto bail4; - - fbdevSetScreenSizes (screen->pScreen); - - /* - * Set frame buffer mapping - */ - (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), - pScreen->width, - pScreen->height, - screen->fb.depth, - screen->fb.bitsPerPixel, - screen->fb.byteStride, - screen->fb.frameBuffer); - - /* set the subpixel order */ - - KdSetSubpixelOrder (pScreen, scrpriv->randr); - if (wasEnabled) - KdEnableScreen (pScreen); - - return TRUE; - -bail4: - fbdevUnmapFramebuffer (screen); - *scrpriv = oldscr; - (void) fbdevMapFramebuffer (screen); - pScreen->width = oldwidth; - pScreen->height = oldheight; - pScreen->mmWidth = oldmmwidth; - pScreen->mmHeight = oldmmheight; - - if (wasEnabled) - KdEnableScreen (pScreen); - return FALSE; -} - -static Bool -fbdevRandRInit (ScreenPtr pScreen) -{ - rrScrPrivPtr pScrPriv; - - if (!RRScreenInit (pScreen)) - return FALSE; - - pScrPriv = rrGetScrPriv(pScreen); - pScrPriv->rrGetInfo = fbdevRandRGetInfo; - pScrPriv->rrSetConfig = fbdevRandRSetConfig; - return TRUE; -} -#endif - -static Bool -fbdevCreateColormap (ColormapPtr pmap) -{ - ScreenPtr pScreen = pmap->pScreen; - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - VisualPtr pVisual; - int i; - int nent; - xColorItem *pdefs; - - switch (priv->fix.visual) { - case FB_VISUAL_STATIC_PSEUDOCOLOR: - pVisual = pmap->pVisual; - nent = pVisual->ColormapEntries; - pdefs = xalloc (nent * sizeof (xColorItem)); - if (!pdefs) - return FALSE; - for (i = 0; i < nent; i++) - pdefs[i].pixel = i; - fbdevGetColors (pScreen, nent, pdefs); - for (i = 0; i < nent; i++) - { - pmap->red[i].co.local.red = pdefs[i].red; - pmap->red[i].co.local.green = pdefs[i].green; - pmap->red[i].co.local.blue = pdefs[i].blue; - } - xfree (pdefs); - return TRUE; - default: - return fbInitializeColormap (pmap); - } -} - -Bool -fbdevInitScreen (ScreenPtr pScreen) -{ -#ifdef TOUCHSCREEN - KdTsPhyScreen = pScreen->myNum; -#endif - - pScreen->CreateColormap = fbdevCreateColormap; - return TRUE; -} - -Bool -fbdevFinishInitScreen (ScreenPtr pScreen) -{ - if (!shadowSetup (pScreen)) - return FALSE; - -#ifdef RANDR - if (!fbdevRandRInit (pScreen)) - return FALSE; -#endif - - return TRUE; -} - - -Bool -fbdevCreateResources (ScreenPtr pScreen) -{ - return fbdevSetShadow (pScreen); -} - -void -fbdevPreserve (KdCardInfo *card) -{ -} - -static int -fbdevUpdateFbColormap(FbdevPriv *priv, int minidx, int maxidx) -{ - struct fb_cmap cmap; - - cmap.start = minidx; - cmap.len = maxidx - minidx + 1; - cmap.red = &priv->red[minidx]; - cmap.green = &priv->green[minidx]; - cmap.blue = &priv->blue[minidx]; - cmap.transp = 0; - - return ioctl(priv->fd, FBIOPUTCMAP, &cmap); -} - -Bool -fbdevEnable (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - int k; - - priv->var.activate = FB_ACTIVATE_NOW|FB_CHANGE_CMAP_VBL; - - /* display it on the LCD */ - k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &priv->var); - if (k < 0) - { - perror ("FBIOPUT_VSCREENINFO"); - return FALSE; - } - - if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR) - { - int i; - - for (i = 0; - i < (1 << priv->var.red.length) || - i < (1 << priv->var.green.length) || - i < (1 << priv->var.blue.length); i++) - { - priv->red[i] = i * 65535 / ((1 << priv->var.red.length) - 1); - priv->green[i] = i * 65535 / ((1 << priv->var.green.length) - 1); - priv->blue[i] = i * 65535 / ((1 << priv->var.blue.length) - 1); - } - - fbdevUpdateFbColormap(priv, 0, i); - } - return TRUE; -} - -Bool -fbdevDPMS (ScreenPtr pScreen, int mode) -{ - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - static int oldmode = -1; - - if (mode == oldmode) - return TRUE; -#ifdef FBIOPUT_POWERMODE - if (ioctl (priv->fd, FBIOPUT_POWERMODE, &mode) >= 0) - { - oldmode = mode; - return TRUE; - } -#endif -#ifdef FBIOBLANK - if (ioctl (priv->fd, FBIOBLANK, mode ? mode + 1 : 0) >= 0) - { - oldmode = mode; - return TRUE; - } -#endif - return FALSE; -} - -void -fbdevDisable (ScreenPtr pScreen) -{ -} - -void -fbdevRestore (KdCardInfo *card) -{ -} - -void -fbdevScreenFini (KdScreenInfo *screen) -{ -} - -void -fbdevCardFini (KdCardInfo *card) -{ - FbdevPriv *priv = card->driver; - - munmap (priv->fb_base, priv->fix.smem_len); - close (priv->fd); - xfree (priv); -} - -/* - * Retrieve actual colormap and return selected n entries in pdefs. - */ -void -fbdevGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - struct fb_cmap cmap; - int p; - int k; - int min, max; - - min = 256; - max = 0; - for (k = 0; k < n; k++) - { - if (pdefs[k].pixel < min) - min = pdefs[k].pixel; - if (pdefs[k].pixel > max) - max = pdefs[k].pixel; - } - cmap.start = min; - cmap.len = max - min + 1; - cmap.red = &priv->red[min]; - cmap.green = &priv->green[min]; - cmap.blue = &priv->blue[min]; - cmap.transp = 0; - k = ioctl (priv->fd, FBIOGETCMAP, &cmap); - if (k < 0) - { - perror ("can't get colormap"); - return; - } - while (n--) - { - p = pdefs->pixel; - pdefs->red = priv->red[p]; - pdefs->green = priv->green[p]; - pdefs->blue = priv->blue[p]; - pdefs++; - } -} - -/* - * Change colormap by updating n entries described in pdefs. - */ -void -fbdevPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) -{ - KdScreenPriv(pScreen); - FbdevPriv *priv = pScreenPriv->card->driver; - int p; - int min, max; - - min = 256; - max = 0; - while (n--) - { - p = pdefs->pixel; - priv->red[p] = pdefs->red; - priv->green[p] = pdefs->green; - priv->blue[p] = pdefs->blue; - if (p < min) - min = p; - if (p > max) - max = p; - pdefs++; - } - - fbdevUpdateFbColormap(priv, min, max); -} +/* + * Copyright © 1999 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "fbdev.h" +#include + +#include + +extern int KdTsPhyScreen; + +char *fbdevDevicePath = NULL; + +static Bool +fbdevInitialize (KdCardInfo *card, FbdevPriv *priv) +{ + unsigned long off; + + if (fbdevDevicePath == NULL) + fbdevDevicePath = "/dev/fb0"; + + if ((priv->fd = open(fbdevDevicePath, O_RDWR)) < 0) + { + ErrorF("Error opening framebuffer %s: %s\n", + fbdevDevicePath, strerror(errno)); + return FALSE; + } + + /* quiet valgrind */ + memset (&priv->fix, '\0', sizeof (priv->fix)); + if (ioctl(priv->fd, FBIOGET_FSCREENINFO, &priv->fix) < 0) { + perror("Error with /dev/fb ioctl FIOGET_FSCREENINFO"); + close (priv->fd); + return FALSE; + } + /* quiet valgrind */ + memset (&priv->var, '\0', sizeof (priv->var)); + if (ioctl(priv->fd, FBIOGET_VSCREENINFO, &priv->var) < 0) { + perror("Error with /dev/fb ioctl FIOGET_VSCREENINFO"); + close (priv->fd); + return FALSE; + } + + priv->fb_base = (char *) mmap ((caddr_t) NULL, + priv->fix.smem_len, + PROT_READ|PROT_WRITE, + MAP_SHARED, + priv->fd, 0); + + if (priv->fb_base == (char *)-1) + { + perror("ERROR: mmap framebuffer fails!"); + close (priv->fd); + return FALSE; + } + off = (unsigned long) priv->fix.smem_start % (unsigned long) getpagesize(); + priv->fb = priv->fb_base + off; + return TRUE; +} + +Bool +fbdevCardInit (KdCardInfo *card) +{ + FbdevPriv *priv; + + priv = (FbdevPriv *) malloc(sizeof (FbdevPriv)); + if (!priv) + return FALSE; + + if (!fbdevInitialize (card, priv)) + { + free(priv); + return FALSE; + } + card->driver = priv; + + return TRUE; +} + +static Pixel +fbdevMakeContig (Pixel orig, Pixel others) +{ + Pixel low; + + low = lowbit (orig) >> 1; + while (low && (others & low) == 0) + { + orig |= low; + low >>= 1; + } + return orig; +} + +static Bool +fbdevModeSupported (KdScreenInfo *screen, + const KdMonitorTiming *t) +{ + return TRUE; +} + +static void +fbdevConvertMonitorTiming (const KdMonitorTiming *t, struct fb_var_screeninfo *var) +{ + memset (var, 0, sizeof (struct fb_var_screeninfo)); + + var->xres = t->horizontal; + var->yres = t->vertical; + var->xres_virtual = t->horizontal; + var->yres_virtual = t->vertical; + var->xoffset = 0; + var->yoffset = 0; + var->pixclock = t->clock ? 1000000000 / t->clock : 0; + var->left_margin = t->hbp; + var->right_margin = t->hfp; + var->upper_margin = t->vbp; + var->lower_margin = t->vfp; + var->hsync_len = t->hblank - t->hfp - t->hbp; + var->vsync_len = t->vblank - t->vfp - t->vbp; + + var->sync = 0; + var->vmode = 0; + + if (t->hpol == KdSyncPositive) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (t->vpol == KdSyncPositive) + var->sync |= FB_SYNC_VERT_HIGH_ACT; +} + +static Bool +fbdevScreenInitialize (KdScreenInfo *screen, FbdevScrPriv *scrpriv) +{ + FbdevPriv *priv = screen->card->driver; + Pixel allbits; + int depth; + Bool gray; + struct fb_var_screeninfo var; + const KdMonitorTiming *t; + int k; + + k = ioctl (priv->fd, FBIOGET_VSCREENINFO, &var); + + if (!screen->width || !screen->height) + { + if (k >= 0) + { + screen->width = var.xres; + screen->height = var.yres; + } + else + { + screen->width = 1024; + screen->height = 768; + } + screen->rate = 103; /* FIXME: should get proper value from fb driver */ + } + if (!screen->fb.depth) + { + if (k >= 0) + screen->fb.depth = var.bits_per_pixel; + else + screen->fb.depth = 16; + } + + if ((screen->width != var.xres) || (screen->height != var.yres)) + { + t = KdFindMode (screen, fbdevModeSupported); + screen->rate = t->rate; + screen->width = t->horizontal; + screen->height = t->vertical; + + /* Now try setting the mode */ + if (k < 0 || (t->horizontal != var.xres || t->vertical != var.yres)) + fbdevConvertMonitorTiming (t, &var); + } + + var.activate = FB_ACTIVATE_NOW; + var.bits_per_pixel = screen->fb.depth; + var.nonstd = 0; + var.grayscale = 0; + + k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &var); + + if (k < 0) + { + fprintf (stderr, "error: %s\n", strerror (errno)); + return FALSE; + } + + /* Re-get the "fixed" parameters since they might have changed */ + k = ioctl (priv->fd, FBIOGET_FSCREENINFO, &priv->fix); + if (k < 0) + perror ("FBIOGET_FSCREENINFO"); + + /* Now get the new screeninfo */ + ioctl (priv->fd, FBIOGET_VSCREENINFO, &priv->var); + depth = priv->var.bits_per_pixel; + gray = priv->var.grayscale; + + switch (priv->fix.visual) { + case FB_VISUAL_PSEUDOCOLOR: + if (gray) + { + screen->fb.visuals = (1 << StaticGray); + /* could also support GrayScale, but what's the point? */ + } + else + { + screen->fb.visuals = ((1 << StaticGray) | + (1 << GrayScale) | + (1 << StaticColor) | + (1 << PseudoColor) | + (1 << TrueColor) | + (1 << DirectColor)); + } + screen->fb.blueMask = 0x00; + screen->fb.greenMask = 0x00; + screen->fb.redMask = 0x00; + break; + case FB_VISUAL_STATIC_PSEUDOCOLOR: + if (gray) + { + screen->fb.visuals = (1 << StaticGray); + } + else + { + screen->fb.visuals = (1 << StaticColor); + } + screen->fb.blueMask = 0x00; + screen->fb.greenMask = 0x00; + screen->fb.redMask = 0x00; + break; + case FB_VISUAL_TRUECOLOR: + case FB_VISUAL_DIRECTCOLOR: + screen->fb.visuals = (1 << TrueColor); +#define Mask(o,l) (((1 << l) - 1) << o) + screen->fb.redMask = Mask (priv->var.red.offset, priv->var.red.length); + screen->fb.greenMask = Mask (priv->var.green.offset, priv->var.green.length); + screen->fb.blueMask = Mask (priv->var.blue.offset, priv->var.blue.length); + + /* + * This is a kludge so that Render will work -- fill in the gaps + * in the pixel + */ + screen->fb.redMask = fbdevMakeContig (screen->fb.redMask, + screen->fb.greenMask| + screen->fb.blueMask); + + screen->fb.greenMask = fbdevMakeContig (screen->fb.greenMask, + screen->fb.redMask| + screen->fb.blueMask); + + screen->fb.blueMask = fbdevMakeContig (screen->fb.blueMask, + screen->fb.redMask| + screen->fb.greenMask); + + allbits = screen->fb.redMask | screen->fb.greenMask | screen->fb.blueMask; + depth = 32; + while (depth && !(allbits & (1 << (depth - 1)))) + depth--; + break; + default: + return FALSE; + break; + } + screen->fb.depth = depth; + screen->fb.bitsPerPixel = priv->var.bits_per_pixel; + + scrpriv->randr = screen->randr; + + return fbdevMapFramebuffer (screen); +} + +Bool +fbdevScreenInit (KdScreenInfo *screen) +{ + FbdevScrPriv *scrpriv; + + scrpriv = calloc(1, sizeof (FbdevScrPriv)); + if (!scrpriv) + return FALSE; + screen->driver = scrpriv; + if (!fbdevScreenInitialize (screen, scrpriv)) + { + screen->driver = 0; + free(scrpriv); + return FALSE; + } + return TRUE; +} + +static void * +fbdevWindowLinear (ScreenPtr pScreen, + CARD32 row, + CARD32 offset, + int mode, + CARD32 *size, + void *closure) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + + if (!pScreenPriv->enabled) + return 0; + *size = priv->fix.line_length; + return (CARD8 *) priv->fb + row * priv->fix.line_length + offset; +} + +Bool +fbdevMapFramebuffer (KdScreenInfo *screen) +{ + FbdevScrPriv *scrpriv = screen->driver; + KdPointerMatrix m; + FbdevPriv *priv = screen->card->driver; + + if (scrpriv->randr != RR_Rotate_0) + scrpriv->shadow = TRUE; + else + scrpriv->shadow = FALSE; + + KdComputePointerMatrix (&m, scrpriv->randr, screen->width, screen->height); + + KdSetPointerMatrix (&m); + + screen->width = priv->var.xres; + screen->height = priv->var.yres; + + if (scrpriv->shadow) + { + if (!KdShadowFbAlloc (screen, + scrpriv->randr & (RR_Rotate_90|RR_Rotate_270))) + return FALSE; + } + else + { + screen->fb.byteStride = priv->fix.line_length; + screen->fb.pixelStride = (priv->fix.line_length * 8 / + priv->var.bits_per_pixel); + screen->fb.frameBuffer = (CARD8 *) (priv->fb); + } + + return TRUE; +} + +static void +fbdevSetScreenSizes (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + FbdevPriv *priv = screen->card->driver; + + if (scrpriv->randr & (RR_Rotate_0|RR_Rotate_180)) + { + pScreen->width = priv->var.xres; + pScreen->height = priv->var.yres; + pScreen->mmWidth = screen->width_mm; + pScreen->mmHeight = screen->height_mm; + } + else + { + pScreen->width = priv->var.yres; + pScreen->height = priv->var.xres; + pScreen->mmWidth = screen->height_mm; + pScreen->mmHeight = screen->width_mm; + } +} + +static Bool +fbdevUnmapFramebuffer (KdScreenInfo *screen) +{ + KdShadowFbFree (screen); + return TRUE; +} + +static Bool +fbdevSetShadow (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + FbdevPriv *priv = screen->card->driver; + ShadowUpdateProc update; + ShadowWindowProc window; + int useYX = 0; + +#ifdef __arm__ + /* Use variant copy routines that always read left to right in the + shadow framebuffer. Reading vertical strips is exceptionally + slow on XScale due to cache effects. */ + useYX = 1; +#endif + + window = fbdevWindowLinear; + update = 0; + if (scrpriv->randr) + if (priv->var.bits_per_pixel == 16) { + switch (scrpriv->randr) { + case RR_Rotate_90: + if (useYX) + update = shadowUpdateRotate16_90YX; + else + update = shadowUpdateRotate16_90; + break; + case RR_Rotate_180: + update = shadowUpdateRotate16_180; + break; + case RR_Rotate_270: + if (useYX) + update = shadowUpdateRotate16_270YX; + else + update = shadowUpdateRotate16_270; + break; + default: + update = shadowUpdateRotate16; + break; + } + } else + update = shadowUpdateRotatePacked; + else + update = shadowUpdatePacked; + return KdShadowSet (pScreen, scrpriv->randr, update, window); +} + + +#ifdef RANDR +static Bool +fbdevRandRGetInfo (ScreenPtr pScreen, Rotation *rotations) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + RRScreenSizePtr pSize; + Rotation randr; + int n; + + *rotations = RR_Rotate_All|RR_Reflect_All; + + for (n = 0; n < pScreen->numDepths; n++) + if (pScreen->allowedDepths[n].numVids) + break; + if (n == pScreen->numDepths) + return FALSE; + + pSize = RRRegisterSize (pScreen, + screen->width, + screen->height, + screen->width_mm, + screen->height_mm); + + randr = KdSubRotation (scrpriv->randr, screen->randr); + + RRSetCurrentConfig (pScreen, randr, 0, pSize); + + return TRUE; +} + +static Bool +fbdevRandRSetConfig (ScreenPtr pScreen, + Rotation randr, + int rate, + RRScreenSizePtr pSize) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + FbdevScrPriv *scrpriv = screen->driver; + Bool wasEnabled = pScreenPriv->enabled; + FbdevScrPriv oldscr; + int oldwidth; + int oldheight; + int oldmmwidth; + int oldmmheight; + int newwidth, newheight; + + if (screen->randr & (RR_Rotate_0|RR_Rotate_180)) + { + newwidth = pSize->width; + newheight = pSize->height; + } + else + { + newwidth = pSize->height; + newheight = pSize->width; + } + + if (wasEnabled) + KdDisableScreen (pScreen); + + oldscr = *scrpriv; + + oldwidth = screen->width; + oldheight = screen->height; + oldmmwidth = pScreen->mmWidth; + oldmmheight = pScreen->mmHeight; + + /* + * Set new configuration + */ + + scrpriv->randr = KdAddRotation (screen->randr, randr); + + fbdevUnmapFramebuffer (screen); + + if (!fbdevMapFramebuffer (screen)) + goto bail4; + + KdShadowUnset (screen->pScreen); + + if (!fbdevSetShadow (screen->pScreen)) + goto bail4; + + fbdevSetScreenSizes (screen->pScreen); + + /* + * Set frame buffer mapping + */ + (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap (pScreen), + pScreen->width, + pScreen->height, + screen->fb.depth, + screen->fb.bitsPerPixel, + screen->fb.byteStride, + screen->fb.frameBuffer); + + /* set the subpixel order */ + + KdSetSubpixelOrder (pScreen, scrpriv->randr); + if (wasEnabled) + KdEnableScreen (pScreen); + + return TRUE; + +bail4: + fbdevUnmapFramebuffer (screen); + *scrpriv = oldscr; + (void) fbdevMapFramebuffer (screen); + pScreen->width = oldwidth; + pScreen->height = oldheight; + pScreen->mmWidth = oldmmwidth; + pScreen->mmHeight = oldmmheight; + + if (wasEnabled) + KdEnableScreen (pScreen); + return FALSE; +} + +static Bool +fbdevRandRInit (ScreenPtr pScreen) +{ + rrScrPrivPtr pScrPriv; + + if (!RRScreenInit (pScreen)) + return FALSE; + + pScrPriv = rrGetScrPriv(pScreen); + pScrPriv->rrGetInfo = fbdevRandRGetInfo; + pScrPriv->rrSetConfig = fbdevRandRSetConfig; + return TRUE; +} +#endif + +static Bool +fbdevCreateColormap (ColormapPtr pmap) +{ + ScreenPtr pScreen = pmap->pScreen; + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + VisualPtr pVisual; + int i; + int nent; + xColorItem *pdefs; + + switch (priv->fix.visual) { + case FB_VISUAL_STATIC_PSEUDOCOLOR: + pVisual = pmap->pVisual; + nent = pVisual->ColormapEntries; + pdefs = malloc(nent * sizeof (xColorItem)); + if (!pdefs) + return FALSE; + for (i = 0; i < nent; i++) + pdefs[i].pixel = i; + fbdevGetColors (pScreen, nent, pdefs); + for (i = 0; i < nent; i++) + { + pmap->red[i].co.local.red = pdefs[i].red; + pmap->red[i].co.local.green = pdefs[i].green; + pmap->red[i].co.local.blue = pdefs[i].blue; + } + free(pdefs); + return TRUE; + default: + return fbInitializeColormap (pmap); + } +} + +Bool +fbdevInitScreen (ScreenPtr pScreen) +{ +#ifdef TOUCHSCREEN + KdTsPhyScreen = pScreen->myNum; +#endif + + pScreen->CreateColormap = fbdevCreateColormap; + return TRUE; +} + +Bool +fbdevFinishInitScreen (ScreenPtr pScreen) +{ + if (!shadowSetup (pScreen)) + return FALSE; + +#ifdef RANDR + if (!fbdevRandRInit (pScreen)) + return FALSE; +#endif + + return TRUE; +} + + +Bool +fbdevCreateResources (ScreenPtr pScreen) +{ + return fbdevSetShadow (pScreen); +} + +void +fbdevPreserve (KdCardInfo *card) +{ +} + +static int +fbdevUpdateFbColormap(FbdevPriv *priv, int minidx, int maxidx) +{ + struct fb_cmap cmap; + + cmap.start = minidx; + cmap.len = maxidx - minidx + 1; + cmap.red = &priv->red[minidx]; + cmap.green = &priv->green[minidx]; + cmap.blue = &priv->blue[minidx]; + cmap.transp = 0; + + return ioctl(priv->fd, FBIOPUTCMAP, &cmap); +} + +Bool +fbdevEnable (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + int k; + + priv->var.activate = FB_ACTIVATE_NOW|FB_CHANGE_CMAP_VBL; + + /* display it on the LCD */ + k = ioctl (priv->fd, FBIOPUT_VSCREENINFO, &priv->var); + if (k < 0) + { + perror ("FBIOPUT_VSCREENINFO"); + return FALSE; + } + + if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR) + { + int i; + + for (i = 0; + i < (1 << priv->var.red.length) || + i < (1 << priv->var.green.length) || + i < (1 << priv->var.blue.length); i++) + { + priv->red[i] = i * 65535 / ((1 << priv->var.red.length) - 1); + priv->green[i] = i * 65535 / ((1 << priv->var.green.length) - 1); + priv->blue[i] = i * 65535 / ((1 << priv->var.blue.length) - 1); + } + + fbdevUpdateFbColormap(priv, 0, i); + } + return TRUE; +} + +Bool +fbdevDPMS (ScreenPtr pScreen, int mode) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + static int oldmode = -1; + + if (mode == oldmode) + return TRUE; +#ifdef FBIOPUT_POWERMODE + if (ioctl (priv->fd, FBIOPUT_POWERMODE, &mode) >= 0) + { + oldmode = mode; + return TRUE; + } +#endif +#ifdef FBIOBLANK + if (ioctl (priv->fd, FBIOBLANK, mode ? mode + 1 : 0) >= 0) + { + oldmode = mode; + return TRUE; + } +#endif + return FALSE; +} + +void +fbdevDisable (ScreenPtr pScreen) +{ +} + +void +fbdevRestore (KdCardInfo *card) +{ +} + +void +fbdevScreenFini (KdScreenInfo *screen) +{ +} + +void +fbdevCardFini (KdCardInfo *card) +{ + FbdevPriv *priv = card->driver; + + munmap (priv->fb_base, priv->fix.smem_len); + close (priv->fd); + free(priv); +} + +/* + * Retrieve actual colormap and return selected n entries in pdefs. + */ +void +fbdevGetColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + struct fb_cmap cmap; + int p; + int k; + int min, max; + + min = 256; + max = 0; + for (k = 0; k < n; k++) + { + if (pdefs[k].pixel < min) + min = pdefs[k].pixel; + if (pdefs[k].pixel > max) + max = pdefs[k].pixel; + } + cmap.start = min; + cmap.len = max - min + 1; + cmap.red = &priv->red[min]; + cmap.green = &priv->green[min]; + cmap.blue = &priv->blue[min]; + cmap.transp = 0; + k = ioctl (priv->fd, FBIOGETCMAP, &cmap); + if (k < 0) + { + perror ("can't get colormap"); + return; + } + while (n--) + { + p = pdefs->pixel; + pdefs->red = priv->red[p]; + pdefs->green = priv->green[p]; + pdefs->blue = priv->blue[p]; + pdefs++; + } +} + +/* + * Change colormap by updating n entries described in pdefs. + */ +void +fbdevPutColors (ScreenPtr pScreen, int n, xColorItem *pdefs) +{ + KdScreenPriv(pScreen); + FbdevPriv *priv = pScreenPriv->card->driver; + int p; + int min, max; + + min = 256; + max = 0; + while (n--) + { + p = pdefs->pixel; + priv->red[p] = pdefs->red; + priv->green[p] = pdefs->green; + priv->blue[p] = pdefs->blue; + if (p < min) + min = p; + if (p > max) + max = p; + pdefs++; + } + + fbdevUpdateFbColormap(priv, min, max); +} diff --git a/xorg-server/hw/kdrive/linux/evdev.c b/xorg-server/hw/kdrive/linux/evdev.c index 0e4c9f735..20df77b99 100644 --- a/xorg-server/hw/kdrive/linux/evdev.c +++ b/xorg-server/hw/kdrive/linux/evdev.c @@ -1,539 +1,539 @@ -/* - * Copyright © 2004 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#include -#include -#include -#include -#include "inputstr.h" -#include "scrnintstr.h" -#include "kdrive.h" - -#define NUM_EVENTS 128 -#define ABS_UNSET -65535 - -#define BITS_PER_LONG (sizeof(long) * 8) -#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) -#define ISBITSET(x,y) ((x)[LONG(y)] & BIT(y)) -#define OFF(x) ((x)%BITS_PER_LONG) -#define LONG(x) ((x)/BITS_PER_LONG) -#define BIT(x) (1 << OFF(x)) - -typedef struct _kevdev { - /* current device state */ - int rel[REL_MAX + 1]; - int abs[ABS_MAX + 1]; - int prevabs[ABS_MAX + 1]; - long key[NBITS(KEY_MAX + 1)]; - - /* supported device info */ - long relbits[NBITS(REL_MAX + 1)]; - long absbits[NBITS(ABS_MAX + 1)]; - long keybits[NBITS(KEY_MAX + 1)]; - struct input_absinfo absinfo[ABS_MAX + 1]; - int max_rel; - int max_abs; - - int fd; -} Kevdev; - -static void -EvdevPtrBtn (KdPointerInfo *pi, struct input_event *ev) -{ - int flags = KD_MOUSE_DELTA | pi->buttonState; - - if (ev->code >= BTN_MOUSE && ev->code < BTN_JOYSTICK) { - switch (ev->code) { - case BTN_LEFT: - if (ev->value == 1) - flags |= KD_BUTTON_1; - else - flags &= ~KD_BUTTON_1; - break; - case BTN_MIDDLE: - if (ev->value == 1) - flags |= KD_BUTTON_2; - else - flags &= ~KD_BUTTON_2; - break; - case BTN_RIGHT: - if (ev->value == 1) - flags |= KD_BUTTON_3; - else - flags &= ~KD_BUTTON_3; - break; - default: - /* Unknow button */ - break; - } - - KdEnqueuePointerEvent (pi, flags, 0, 0, 0); - } -} -static void -EvdevPtrMotion (KdPointerInfo *pi, struct input_event *ev) -{ - Kevdev *ke = pi->driverPrivate; - int i; - int flags = KD_MOUSE_DELTA | pi->buttonState; - - for (i = 0; i <= ke->max_rel; i++) - if (ke->rel[i]) - { - int a; - for (a = 0; a <= ke->max_rel; a++) - { - if (ISBITSET (ke->relbits, a)) - { - if (a == 0) - KdEnqueuePointerEvent(pi, flags, ke->rel[a], 0, 0); - else if (a == 1) - KdEnqueuePointerEvent(pi, flags, 0, ke->rel[a], 0); - } - ke->rel[a] = 0; - } - break; - } - for (i = 0; i < ke->max_abs; i++) - if (ke->abs[i] != ke->prevabs[i]) - { - int a; - ErrorF ("abs"); - for (a = 0; a <= ke->max_abs; a++) - { - if (ISBITSET (ke->absbits, a)) - ErrorF (" %d=%d", a, ke->abs[a]); - ke->prevabs[a] = ke->abs[a]; - } - ErrorF ("\n"); - break; - } - - if (ev->code == REL_WHEEL) { - for (i = 0; i < abs (ev->value); i++) - { - if (ev->value > 0) - flags |= KD_BUTTON_4; - else - flags |= KD_BUTTON_5; - - KdEnqueuePointerEvent (pi, flags, 0, 0, 0); - - if (ev->value > 0) - flags &= ~KD_BUTTON_4; - else - flags &= ~KD_BUTTON_5; - - KdEnqueuePointerEvent (pi, flags, 0, 0, 0); - } - } - -} - -static void -EvdevPtrRead (int evdevPort, void *closure) -{ - KdPointerInfo *pi = closure; - Kevdev *ke = pi->driverPrivate; - int i; - struct input_event events[NUM_EVENTS]; - int n; - - n = read (evdevPort, &events, NUM_EVENTS * sizeof (struct input_event)); - if (n <= 0) { - if (errno == ENODEV) - DeleteInputDeviceRequest(pi->dixdev); - return; - } - - n /= sizeof (struct input_event); - for (i = 0; i < n; i++) - { - switch (events[i].type) { - case EV_SYN: - break; - case EV_KEY: - EvdevPtrBtn (pi, &events[i]); - break; - case EV_REL: - ke->rel[events[i].code] += events[i].value; - EvdevPtrMotion (pi, &events[i]); - break; - case EV_ABS: - ke->abs[events[i].code] = events[i].value; - EvdevPtrMotion (pi, &events[i]); - break; - } - } -} - -char *kdefaultEvdev[] = { - "/dev/input/event0", - "/dev/input/event1", - "/dev/input/event2", - "/dev/input/event3", -}; - -#define NUM_DEFAULT_EVDEV (sizeof (kdefaultEvdev) / sizeof (kdefaultEvdev[0])) - -static Status -EvdevPtrInit (KdPointerInfo *pi) -{ - int i; - int fd; - - if (!pi->path) { - for (i = 0; i < NUM_DEFAULT_EVDEV; i++) { - fd = open (kdefaultEvdev[i], 2); - if (fd >= 0) { - pi->path = strdup (kdefaultEvdev[i]); - break; - } - } - } - else { - fd = open (pi->path, O_RDWR); - if (fd < 0) { - ErrorF("Failed to open evdev device %s\n", pi->path); - return BadMatch; - } - } - - close(fd); - - pi->name = strdup("Evdev mouse"); - - return Success; -} - -static Status -EvdevPtrEnable (KdPointerInfo *pi) -{ - int fd; - unsigned long ev[NBITS(EV_MAX)]; - Kevdev *ke; - - if (!pi || !pi->path) - return BadImplementation; - - fd = open(pi->path, 2); - if (fd < 0) - return BadMatch; - - if (ioctl (fd, EVIOCGRAB, 1) < 0) - perror ("Grabbing evdev mouse device failed"); - - if (ioctl (fd, EVIOCGBIT(0 /*EV*/, sizeof (ev)), ev) < 0) - { - perror ("EVIOCGBIT 0"); - close (fd); - return BadMatch; - } - ke = xcalloc (1, sizeof (Kevdev)); - if (!ke) - { - close (fd); - return BadAlloc; - } - if (ISBITSET (ev, EV_KEY)) - { - if (ioctl (fd, EVIOCGBIT (EV_KEY, sizeof (ke->keybits)), - ke->keybits) < 0) - { - perror ("EVIOCGBIT EV_KEY"); - xfree (ke); - close (fd); - return BadMatch; - } - } - if (ISBITSET (ev, EV_REL)) - { - if (ioctl (fd, EVIOCGBIT (EV_REL, sizeof (ke->relbits)), - ke->relbits) < 0) - { - perror ("EVIOCGBIT EV_REL"); - xfree (ke); - close (fd); - return BadMatch; - } - for (ke->max_rel = REL_MAX; ke->max_rel >= 0; ke->max_rel--) - if (ISBITSET(ke->relbits, ke->max_rel)) - break; - } - if (ISBITSET (ev, EV_ABS)) - { - int i; - - if (ioctl (fd, EVIOCGBIT (EV_ABS, sizeof (ke->absbits)), - ke->absbits) < 0) - { - perror ("EVIOCGBIT EV_ABS"); - xfree (ke); - close (fd); - return BadMatch; - } - for (ke->max_abs = ABS_MAX; ke->max_abs >= 0; ke->max_abs--) - if (ISBITSET(ke->absbits, ke->max_abs)) - break; - for (i = 0; i <= ke->max_abs; i++) - { - if (ISBITSET (ke->absbits, i)) - if (ioctl (fd, EVIOCGABS(i), &ke->absinfo[i]) < 0) - { - perror ("EVIOCGABS"); - break; - } - ke->prevabs[i] = ABS_UNSET; - } - if (i <= ke->max_abs) - { - xfree (ke); - close (fd); - return BadValue; - } - } - if (!KdRegisterFd (fd, EvdevPtrRead, pi)) { - xfree (ke); - close (fd); - return BadAlloc; - } - pi->driverPrivate = ke; - ke->fd = fd; - - return Success; -} - -static void -EvdevPtrDisable (KdPointerInfo *pi) -{ - Kevdev *ke; - - ke = pi->driverPrivate; - - if (!pi || !pi->driverPrivate) - return; - - KdUnregisterFd (pi, ke->fd, TRUE); - - if (ioctl (ke->fd, EVIOCGRAB, 0) < 0) - perror ("Ungrabbing evdev mouse device failed"); - - xfree (ke); - pi->driverPrivate = 0; -} - -static void -EvdevPtrFini (KdPointerInfo *pi) -{ -} - - -/* - * Evdev keyboard functions - */ - -static void -readMapping (KdKeyboardInfo *ki) -{ - if (!ki) - return; - - ki->minScanCode = 0; - ki->maxScanCode = 247; -} - -static void -EvdevKbdRead (int evdevPort, void *closure) -{ - KdKeyboardInfo *ki = closure; - struct input_event events[NUM_EVENTS]; - int i, n; - - n = read (evdevPort, &events, NUM_EVENTS * sizeof (struct input_event)); - if (n <= 0) { - if (errno == ENODEV) - DeleteInputDeviceRequest(ki->dixdev); - return; - } - - n /= sizeof (struct input_event); - for (i = 0; i < n; i++) - { - if (events[i].type == EV_KEY) - KdEnqueueKeyboardEvent (ki, events[i].code, !events[i].value); -/* FIXME: must implement other types of events - else - ErrorF("Event type (%d) not delivered\n", events[i].type); -*/ - } -} - -static Status -EvdevKbdInit (KdKeyboardInfo *ki) -{ - int fd; - - if (!ki->path) { - ErrorF("Couldn't find evdev device path\n"); - return BadValue; - } - else { - fd = open (ki->path, O_RDWR); - if (fd < 0) { - ErrorF("Failed to open evdev device %s\n", ki->path); - return BadMatch; - } - } - - close (fd); - - ki->name = strdup("Evdev keyboard"); - - readMapping(ki); - - return Success; -} - -static Status -EvdevKbdEnable (KdKeyboardInfo *ki) -{ - unsigned long ev[NBITS(EV_MAX)]; - Kevdev *ke; - int fd; - - if (!ki || !ki->path) - return BadImplementation; - - fd = open(ki->path, O_RDWR); - if (fd < 0) - return BadMatch; - - if (ioctl (fd, EVIOCGRAB, 1) < 0) - perror ("Grabbing evdev keyboard device failed"); - - if (ioctl (fd, EVIOCGBIT(0 /*EV*/, sizeof (ev)), ev) < 0) { - perror ("EVIOCGBIT 0"); - close (fd); - return BadMatch; - } - - ke = xcalloc (1, sizeof (Kevdev)); - if (!ke) { - close (fd); - return BadAlloc; - } - - if (!KdRegisterFd (fd, EvdevKbdRead, ki)) { - xfree (ke); - close (fd); - return BadAlloc; - } - ki->driverPrivate = ke; - ke->fd = fd; - - return Success; -} - -static void -EvdevKbdLeds (KdKeyboardInfo *ki, int leds) -{ -/* struct input_event event; - Kevdev *ke; - - ki->driverPrivate = ke; - - memset(&event, 0, sizeof(event)); - - event.type = EV_LED; - event.code = LED_CAPSL; - event.value = leds & (1 << 0) ? 1 : 0; - write(ke->fd, (char *) &event, sizeof(event)); - - event.type = EV_LED; - event.code = LED_NUML; - event.value = leds & (1 << 1) ? 1 : 0; - write(ke->fd, (char *) &event, sizeof(event)); - - event.type = EV_LED; - event.code = LED_SCROLLL; - event.value = leds & (1 << 2) ? 1 : 0; - write(ke->fd, (char *) &event, sizeof(event)); - - event.type = EV_LED; - event.code = LED_COMPOSE; - event.value = leds & (1 << 3) ? 1 : 0; - write(ke->fd, (char *) &event, sizeof(event)); -*/ -} - -static void -EvdevKbdBell (KdKeyboardInfo *ki, int volume, int frequency, int duration) -{ -} - -static void -EvdevKbdDisable (KdKeyboardInfo *ki) -{ - Kevdev *ke; - - ke = ki->driverPrivate; - - if (!ki || !ki->driverPrivate) - return; - - KdUnregisterFd (ki, ke->fd, TRUE); - - if (ioctl (ke->fd, EVIOCGRAB, 0) < 0) - perror ("Ungrabbing evdev keyboard device failed"); - - xfree (ke); - ki->driverPrivate = 0; -} - -static void -EvdevKbdFini (KdKeyboardInfo *ki) -{ -} - -KdPointerDriver LinuxEvdevMouseDriver = { - "evdev", - EvdevPtrInit, - EvdevPtrEnable, - EvdevPtrDisable, - EvdevPtrFini, - NULL, -}; - -KdKeyboardDriver LinuxEvdevKeyboardDriver = { - "evdev", - EvdevKbdInit, - EvdevKbdEnable, - EvdevKbdLeds, - EvdevKbdBell, - EvdevKbdDisable, - EvdevKbdFini, - NULL, -}; +/* + * Copyright © 2004 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include "inputstr.h" +#include "scrnintstr.h" +#include "kdrive.h" + +#define NUM_EVENTS 128 +#define ABS_UNSET -65535 + +#define BITS_PER_LONG (sizeof(long) * 8) +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define ISBITSET(x,y) ((x)[LONG(y)] & BIT(y)) +#define OFF(x) ((x)%BITS_PER_LONG) +#define LONG(x) ((x)/BITS_PER_LONG) +#define BIT(x) (1 << OFF(x)) + +typedef struct _kevdev { + /* current device state */ + int rel[REL_MAX + 1]; + int abs[ABS_MAX + 1]; + int prevabs[ABS_MAX + 1]; + long key[NBITS(KEY_MAX + 1)]; + + /* supported device info */ + long relbits[NBITS(REL_MAX + 1)]; + long absbits[NBITS(ABS_MAX + 1)]; + long keybits[NBITS(KEY_MAX + 1)]; + struct input_absinfo absinfo[ABS_MAX + 1]; + int max_rel; + int max_abs; + + int fd; +} Kevdev; + +static void +EvdevPtrBtn (KdPointerInfo *pi, struct input_event *ev) +{ + int flags = KD_MOUSE_DELTA | pi->buttonState; + + if (ev->code >= BTN_MOUSE && ev->code < BTN_JOYSTICK) { + switch (ev->code) { + case BTN_LEFT: + if (ev->value == 1) + flags |= KD_BUTTON_1; + else + flags &= ~KD_BUTTON_1; + break; + case BTN_MIDDLE: + if (ev->value == 1) + flags |= KD_BUTTON_2; + else + flags &= ~KD_BUTTON_2; + break; + case BTN_RIGHT: + if (ev->value == 1) + flags |= KD_BUTTON_3; + else + flags &= ~KD_BUTTON_3; + break; + default: + /* Unknow button */ + break; + } + + KdEnqueuePointerEvent (pi, flags, 0, 0, 0); + } +} +static void +EvdevPtrMotion (KdPointerInfo *pi, struct input_event *ev) +{ + Kevdev *ke = pi->driverPrivate; + int i; + int flags = KD_MOUSE_DELTA | pi->buttonState; + + for (i = 0; i <= ke->max_rel; i++) + if (ke->rel[i]) + { + int a; + for (a = 0; a <= ke->max_rel; a++) + { + if (ISBITSET (ke->relbits, a)) + { + if (a == 0) + KdEnqueuePointerEvent(pi, flags, ke->rel[a], 0, 0); + else if (a == 1) + KdEnqueuePointerEvent(pi, flags, 0, ke->rel[a], 0); + } + ke->rel[a] = 0; + } + break; + } + for (i = 0; i < ke->max_abs; i++) + if (ke->abs[i] != ke->prevabs[i]) + { + int a; + ErrorF ("abs"); + for (a = 0; a <= ke->max_abs; a++) + { + if (ISBITSET (ke->absbits, a)) + ErrorF (" %d=%d", a, ke->abs[a]); + ke->prevabs[a] = ke->abs[a]; + } + ErrorF ("\n"); + break; + } + + if (ev->code == REL_WHEEL) { + for (i = 0; i < abs (ev->value); i++) + { + if (ev->value > 0) + flags |= KD_BUTTON_4; + else + flags |= KD_BUTTON_5; + + KdEnqueuePointerEvent (pi, flags, 0, 0, 0); + + if (ev->value > 0) + flags &= ~KD_BUTTON_4; + else + flags &= ~KD_BUTTON_5; + + KdEnqueuePointerEvent (pi, flags, 0, 0, 0); + } + } + +} + +static void +EvdevPtrRead (int evdevPort, void *closure) +{ + KdPointerInfo *pi = closure; + Kevdev *ke = pi->driverPrivate; + int i; + struct input_event events[NUM_EVENTS]; + int n; + + n = read (evdevPort, &events, NUM_EVENTS * sizeof (struct input_event)); + if (n <= 0) { + if (errno == ENODEV) + DeleteInputDeviceRequest(pi->dixdev); + return; + } + + n /= sizeof (struct input_event); + for (i = 0; i < n; i++) + { + switch (events[i].type) { + case EV_SYN: + break; + case EV_KEY: + EvdevPtrBtn (pi, &events[i]); + break; + case EV_REL: + ke->rel[events[i].code] += events[i].value; + EvdevPtrMotion (pi, &events[i]); + break; + case EV_ABS: + ke->abs[events[i].code] = events[i].value; + EvdevPtrMotion (pi, &events[i]); + break; + } + } +} + +char *kdefaultEvdev[] = { + "/dev/input/event0", + "/dev/input/event1", + "/dev/input/event2", + "/dev/input/event3", +}; + +#define NUM_DEFAULT_EVDEV (sizeof (kdefaultEvdev) / sizeof (kdefaultEvdev[0])) + +static Status +EvdevPtrInit (KdPointerInfo *pi) +{ + int i; + int fd; + + if (!pi->path) { + for (i = 0; i < NUM_DEFAULT_EVDEV; i++) { + fd = open (kdefaultEvdev[i], 2); + if (fd >= 0) { + pi->path = strdup (kdefaultEvdev[i]); + break; + } + } + } + else { + fd = open (pi->path, O_RDWR); + if (fd < 0) { + ErrorF("Failed to open evdev device %s\n", pi->path); + return BadMatch; + } + } + + close(fd); + + pi->name = strdup("Evdev mouse"); + + return Success; +} + +static Status +EvdevPtrEnable (KdPointerInfo *pi) +{ + int fd; + unsigned long ev[NBITS(EV_MAX)]; + Kevdev *ke; + + if (!pi || !pi->path) + return BadImplementation; + + fd = open(pi->path, 2); + if (fd < 0) + return BadMatch; + + if (ioctl (fd, EVIOCGRAB, 1) < 0) + perror ("Grabbing evdev mouse device failed"); + + if (ioctl (fd, EVIOCGBIT(0 /*EV*/, sizeof (ev)), ev) < 0) + { + perror ("EVIOCGBIT 0"); + close (fd); + return BadMatch; + } + ke = calloc(1, sizeof (Kevdev)); + if (!ke) + { + close (fd); + return BadAlloc; + } + if (ISBITSET (ev, EV_KEY)) + { + if (ioctl (fd, EVIOCGBIT (EV_KEY, sizeof (ke->keybits)), + ke->keybits) < 0) + { + perror ("EVIOCGBIT EV_KEY"); + free(ke); + close (fd); + return BadMatch; + } + } + if (ISBITSET (ev, EV_REL)) + { + if (ioctl (fd, EVIOCGBIT (EV_REL, sizeof (ke->relbits)), + ke->relbits) < 0) + { + perror ("EVIOCGBIT EV_REL"); + free(ke); + close (fd); + return BadMatch; + } + for (ke->max_rel = REL_MAX; ke->max_rel >= 0; ke->max_rel--) + if (ISBITSET(ke->relbits, ke->max_rel)) + break; + } + if (ISBITSET (ev, EV_ABS)) + { + int i; + + if (ioctl (fd, EVIOCGBIT (EV_ABS, sizeof (ke->absbits)), + ke->absbits) < 0) + { + perror ("EVIOCGBIT EV_ABS"); + free(ke); + close (fd); + return BadMatch; + } + for (ke->max_abs = ABS_MAX; ke->max_abs >= 0; ke->max_abs--) + if (ISBITSET(ke->absbits, ke->max_abs)) + break; + for (i = 0; i <= ke->max_abs; i++) + { + if (ISBITSET (ke->absbits, i)) + if (ioctl (fd, EVIOCGABS(i), &ke->absinfo[i]) < 0) + { + perror ("EVIOCGABS"); + break; + } + ke->prevabs[i] = ABS_UNSET; + } + if (i <= ke->max_abs) + { + free(ke); + close (fd); + return BadValue; + } + } + if (!KdRegisterFd (fd, EvdevPtrRead, pi)) { + free(ke); + close (fd); + return BadAlloc; + } + pi->driverPrivate = ke; + ke->fd = fd; + + return Success; +} + +static void +EvdevPtrDisable (KdPointerInfo *pi) +{ + Kevdev *ke; + + ke = pi->driverPrivate; + + if (!pi || !pi->driverPrivate) + return; + + KdUnregisterFd (pi, ke->fd, TRUE); + + if (ioctl (ke->fd, EVIOCGRAB, 0) < 0) + perror ("Ungrabbing evdev mouse device failed"); + + free(ke); + pi->driverPrivate = 0; +} + +static void +EvdevPtrFini (KdPointerInfo *pi) +{ +} + + +/* + * Evdev keyboard functions + */ + +static void +readMapping (KdKeyboardInfo *ki) +{ + if (!ki) + return; + + ki->minScanCode = 0; + ki->maxScanCode = 247; +} + +static void +EvdevKbdRead (int evdevPort, void *closure) +{ + KdKeyboardInfo *ki = closure; + struct input_event events[NUM_EVENTS]; + int i, n; + + n = read (evdevPort, &events, NUM_EVENTS * sizeof (struct input_event)); + if (n <= 0) { + if (errno == ENODEV) + DeleteInputDeviceRequest(ki->dixdev); + return; + } + + n /= sizeof (struct input_event); + for (i = 0; i < n; i++) + { + if (events[i].type == EV_KEY) + KdEnqueueKeyboardEvent (ki, events[i].code, !events[i].value); +/* FIXME: must implement other types of events + else + ErrorF("Event type (%d) not delivered\n", events[i].type); +*/ + } +} + +static Status +EvdevKbdInit (KdKeyboardInfo *ki) +{ + int fd; + + if (!ki->path) { + ErrorF("Couldn't find evdev device path\n"); + return BadValue; + } + else { + fd = open (ki->path, O_RDWR); + if (fd < 0) { + ErrorF("Failed to open evdev device %s\n", ki->path); + return BadMatch; + } + } + + close (fd); + + ki->name = strdup("Evdev keyboard"); + + readMapping(ki); + + return Success; +} + +static Status +EvdevKbdEnable (KdKeyboardInfo *ki) +{ + unsigned long ev[NBITS(EV_MAX)]; + Kevdev *ke; + int fd; + + if (!ki || !ki->path) + return BadImplementation; + + fd = open(ki->path, O_RDWR); + if (fd < 0) + return BadMatch; + + if (ioctl (fd, EVIOCGRAB, 1) < 0) + perror ("Grabbing evdev keyboard device failed"); + + if (ioctl (fd, EVIOCGBIT(0 /*EV*/, sizeof (ev)), ev) < 0) { + perror ("EVIOCGBIT 0"); + close (fd); + return BadMatch; + } + + ke = calloc(1, sizeof (Kevdev)); + if (!ke) { + close (fd); + return BadAlloc; + } + + if (!KdRegisterFd (fd, EvdevKbdRead, ki)) { + free(ke); + close (fd); + return BadAlloc; + } + ki->driverPrivate = ke; + ke->fd = fd; + + return Success; +} + +static void +EvdevKbdLeds (KdKeyboardInfo *ki, int leds) +{ +/* struct input_event event; + Kevdev *ke; + + ki->driverPrivate = ke; + + memset(&event, 0, sizeof(event)); + + event.type = EV_LED; + event.code = LED_CAPSL; + event.value = leds & (1 << 0) ? 1 : 0; + write(ke->fd, (char *) &event, sizeof(event)); + + event.type = EV_LED; + event.code = LED_NUML; + event.value = leds & (1 << 1) ? 1 : 0; + write(ke->fd, (char *) &event, sizeof(event)); + + event.type = EV_LED; + event.code = LED_SCROLLL; + event.value = leds & (1 << 2) ? 1 : 0; + write(ke->fd, (char *) &event, sizeof(event)); + + event.type = EV_LED; + event.code = LED_COMPOSE; + event.value = leds & (1 << 3) ? 1 : 0; + write(ke->fd, (char *) &event, sizeof(event)); +*/ +} + +static void +EvdevKbdBell (KdKeyboardInfo *ki, int volume, int frequency, int duration) +{ +} + +static void +EvdevKbdDisable (KdKeyboardInfo *ki) +{ + Kevdev *ke; + + ke = ki->driverPrivate; + + if (!ki || !ki->driverPrivate) + return; + + KdUnregisterFd (ki, ke->fd, TRUE); + + if (ioctl (ke->fd, EVIOCGRAB, 0) < 0) + perror ("Ungrabbing evdev keyboard device failed"); + + free(ke); + ki->driverPrivate = 0; +} + +static void +EvdevKbdFini (KdKeyboardInfo *ki) +{ +} + +KdPointerDriver LinuxEvdevMouseDriver = { + "evdev", + EvdevPtrInit, + EvdevPtrEnable, + EvdevPtrDisable, + EvdevPtrFini, + NULL, +}; + +KdKeyboardDriver LinuxEvdevKeyboardDriver = { + "evdev", + EvdevKbdInit, + EvdevKbdEnable, + EvdevKbdLeds, + EvdevKbdBell, + EvdevKbdDisable, + EvdevKbdFini, + NULL, +}; diff --git a/xorg-server/hw/kdrive/linux/keyboard.c b/xorg-server/hw/kdrive/linux/keyboard.c index 6eed7aed3..c888d14dc 100644 --- a/xorg-server/hw/kdrive/linux/keyboard.c +++ b/xorg-server/hw/kdrive/linux/keyboard.c @@ -1,765 +1,765 @@ -/* - * Copyright © 1999 Keith Packard - * XKB integration © 2006 Nokia Corporation, author: Tomas Frydrych - * - * LinuxKeyboardRead() XKB code based on xf86KbdLnx.c: - * Copyright © 1990,91 by Thomas Roell, Dinkelscherben, Germany. - * Copyright © 1994-2001 by The XFree86 Project, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of the copyright holder(s) - * and author(s) shall not be used in advertising or otherwise to promote - * the sale, use or other dealings in this Software without prior written - * authorization from the copyright holder(s) and author(s). - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "kdrive.h" -#include -#include -#define XK_PUBLISHING -#include -#include -#include - -extern int LinuxConsoleFd; - -static const KeySym linux_to_x[256] = { - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, XK_Escape, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - XK_space, XK_exclam, XK_quotedbl, XK_numbersign, - XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, - XK_parenleft, XK_parenright, XK_asterisk, XK_plus, - XK_comma, XK_minus, XK_period, XK_slash, - XK_0, XK_1, XK_2, XK_3, - XK_4, XK_5, XK_6, XK_7, - XK_8, XK_9, XK_colon, XK_semicolon, - XK_less, XK_equal, XK_greater, XK_question, - XK_at, XK_A, XK_B, XK_C, - XK_D, XK_E, XK_F, XK_G, - XK_H, XK_I, XK_J, XK_K, - XK_L, XK_M, XK_N, XK_O, - XK_P, XK_Q, XK_R, XK_S, - XK_T, XK_U, XK_V, XK_W, - XK_X, XK_Y, XK_Z, XK_bracketleft, - XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore, - XK_grave, XK_a, XK_b, XK_c, - XK_d, XK_e, XK_f, XK_g, - XK_h, XK_i, XK_j, XK_k, - XK_l, XK_m, XK_n, XK_o, - XK_p, XK_q, XK_r, XK_s, - XK_t, XK_u, XK_v, XK_w, - XK_x, XK_y, XK_z, XK_braceleft, - XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - NoSymbol, NoSymbol, NoSymbol, NoSymbol, - XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling, - XK_currency, XK_yen, XK_brokenbar, XK_section, - XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, - XK_notsign, XK_hyphen, XK_registered, XK_macron, - XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, - XK_acute, XK_mu, XK_paragraph, XK_periodcentered, - XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, - XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown, - XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, - XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, - XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, - XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, - XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, - XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, - XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, - XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, - XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, - XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, - XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, - XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, - XK_eth, XK_ntilde, XK_ograve, XK_oacute, - XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, - XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, - XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis -}; - -/* - * Getting a keycode from scancode - * - * With XKB - * -------- - * - * We have to enqueue keyboard events using standard X keycodes which correspond - * to AT scancode + 8; this means that we need to translate the Linux scancode - * provided by the kernel to an AT scancode -- this translation is not linear - * and requires that we use a LUT. - * - * - * Without XKB - * ----------- - * - * We can use custom keycodes, which makes things simpler; we define our custom - * keycodes as Linux scancodes + KD_KEY_OFFSET -*/ - -/* - This LUT translates AT scancodes into Linux ones -- the keymap we create - for the core X keyboard protocol has to be AT-scancode based so that it - corresponds to the Xkb keymap. -*/ -#if 0 -static unsigned char at2lnx[] = -{ - 0x0, /* no valid scancode */ - 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ - 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ - 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ - 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ - 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ - 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ - 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ - 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ - 0x11, /* KEY_W */ 0x12, /* KEY_E */ - 0x13, /* KEY_R */ 0x14, /* KEY_T */ - 0x15, /* KEY_Y */ 0x16, /* KEY_U */ - 0x17, /* KEY_I */ 0x18, /* KEY_O */ - 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ - 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ - 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ - 0x1f, /* KEY_S */ 0x20, /* KEY_D */ - 0x21, /* KEY_F */ 0x22, /* KEY_G */ - 0x23, /* KEY_H */ 0x24, /* KEY_J */ - 0x25, /* KEY_K */ 0x26, /* KEY_L */ - 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ - 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ - 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ - 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ - 0x2f, /* KEY_V */ 0x30, /* KEY_B */ - 0x31, /* KEY_N */ 0x32, /* KEY_M */ - 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ - 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ - 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ - 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ - 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ - 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ - 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ - 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ - 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ - 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ - 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ - 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ - 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ - 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ - 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ - 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ - 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ - 0x00, /* 0x55 */ 0x56, /* KEY_Less */ - 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ - 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ - 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ - 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ - 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ - 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ - 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ - 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ - 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ - 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ - 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ - 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */ - 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ - 0x00, /* 0x71 */ 0x00, /* 0x72 */ - 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ - 0x00, /* 0x75 */ 0x00, /* 0x76 */ - 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ - 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ - 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ - 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ - 0x00, /* 0x7f */ -}; - -#define NUM_AT_KEYS (sizeof(at2lnx)/sizeof(at2lnx[0])) -#define LNX_KEY_INDEX(n) n < NUM_AT_KEYS ? at2lnx[n] : 0 - -static unsigned char tbl[KD_MAX_WIDTH] = -{ - 0, - 1 << KG_SHIFT, - (1 << KG_ALTGR), - (1 << KG_ALTGR) | (1 << KG_SHIFT) -}; -#endif - -static void -readKernelMapping(KdKeyboardInfo *ki) -{ -#if 0 - KeySym *k; - int i, j; - struct kbentry kbe; - int minKeyCode, maxKeyCode; - int row; - int fd; - - if (!ki) - return; - - fd = LinuxConsoleFd; - - minKeyCode = NR_KEYS; - maxKeyCode = 0; - row = 0; - ki->keySyms.mapWidth = KD_MAX_WIDTH; - for (i = 0; i < NR_KEYS && row < KD_MAX_LENGTH; ++i) - { - kbe.kb_index = LNX_KEY_INDEX(i); - - k = ki->keySyms.map + row * ki->keySyms.mapWidth; - - for (j = 0; j < ki->keySyms.mapWidth; ++j) - { - unsigned short kval; - - k[j] = NoSymbol; - - kbe.kb_table = tbl[j]; - kbe.kb_value = 0; - if (ioctl(fd, KDGKBENT, &kbe)) - continue; - - kval = KVAL(kbe.kb_value); - switch (KTYP(kbe.kb_value)) - { - case KT_LATIN: - case KT_LETTER: - k[j] = linux_to_x[kval]; - break; - - case KT_FN: - if (kval <= 19) - k[j] = XK_F1 + kval; - else switch (kbe.kb_value) - { - case K_FIND: - k[j] = XK_Home; /* or XK_Find */ - break; - case K_INSERT: - k[j] = XK_Insert; - break; - case K_REMOVE: - k[j] = XK_Delete; - break; - case K_SELECT: - k[j] = XK_End; /* or XK_Select */ - break; - case K_PGUP: - k[j] = XK_Prior; - break; - case K_PGDN: - k[j] = XK_Next; - break; - case K_HELP: - k[j] = XK_Help; - break; - case K_DO: - k[j] = XK_Execute; - break; - case K_PAUSE: - k[j] = XK_Pause; - break; - case K_MACRO: - k[j] = XK_Menu; - break; - default: - break; - } - break; - - case KT_SPEC: - switch (kbe.kb_value) - { - case K_ENTER: - k[j] = XK_Return; - break; - case K_BREAK: - k[j] = XK_Break; - break; - case K_CAPS: - k[j] = XK_Caps_Lock; - break; - case K_NUM: - k[j] = XK_Num_Lock; - break; - case K_HOLD: - k[j] = XK_Scroll_Lock; - break; - case K_COMPOSE: - k[j] = XK_Multi_key; - break; - default: - break; - } - break; - - case KT_PAD: - switch (kbe.kb_value) - { - case K_PPLUS: - k[j] = XK_KP_Add; - break; - case K_PMINUS: - k[j] = XK_KP_Subtract; - break; - case K_PSTAR: - k[j] = XK_KP_Multiply; - break; - case K_PSLASH: - k[j] = XK_KP_Divide; - break; - case K_PENTER: - k[j] = XK_KP_Enter; - break; - case K_PCOMMA: - k[j] = XK_KP_Separator; - break; - case K_PDOT: - k[j] = XK_KP_Decimal; - break; - case K_PPLUSMINUS: - k[j] = XK_KP_Subtract; - break; - default: - if (kval <= 9) - k[j] = XK_KP_0 + kval; - break; - } - break; - - /* - * KT_DEAD keys are for accelerated diacritical creation. - */ - case KT_DEAD: - switch (kbe.kb_value) - { - case K_DGRAVE: - k[j] = XK_dead_grave; - break; - case K_DACUTE: - k[j] = XK_dead_acute; - break; - case K_DCIRCM: - k[j] = XK_dead_circumflex; - break; - case K_DTILDE: - k[j] = XK_dead_tilde; - break; - case K_DDIERE: - k[j] = XK_dead_diaeresis; - break; - } - break; - - case KT_CUR: - switch (kbe.kb_value) - { - case K_DOWN: - k[j] = XK_Down; - break; - case K_LEFT: - k[j] = XK_Left; - break; - case K_RIGHT: - k[j] = XK_Right; - break; - case K_UP: - k[j] = XK_Up; - break; - } - break; - - case KT_SHIFT: - switch (kbe.kb_value) - { - case K_ALTGR: - k[j] = XK_Mode_switch; - break; - case K_ALT: - k[j] = (kbe.kb_index == 0x64 ? - XK_Alt_R : XK_Alt_L); - break; - case K_CTRL: - k[j] = (kbe.kb_index == 0x61 ? - XK_Control_R : XK_Control_L); - break; - case K_CTRLL: - k[j] = XK_Control_L; - break; - case K_CTRLR: - k[j] = XK_Control_R; - break; - case K_SHIFT: - k[j] = (kbe.kb_index == 0x36 ? - XK_Shift_R : XK_Shift_L); - break; - case K_SHIFTL: - k[j] = XK_Shift_L; - break; - case K_SHIFTR: - k[j] = XK_Shift_R; - break; - default: - break; - } - break; - - /* - * KT_ASCII keys accumulate a 3 digit decimal number that gets - * emitted when the shift state changes. We can't emulate that. - */ - case KT_ASCII: - break; - - case KT_LOCK: - if (kbe.kb_value == K_SHIFTLOCK) - k[j] = XK_Shift_Lock; - break; - -#ifdef KT_X - case KT_X: - /* depends on new keyboard symbols in file linux/keyboard.h */ - if(kbe.kb_value == K_XMENU) k[j] = XK_Menu; - if(kbe.kb_value == K_XTELEPHONE) k[j] = XK_telephone; - break; -#endif -#ifdef KT_XF - case KT_XF: - /* special linux keysyms which map directly to XF86 keysyms */ - k[j] = (kbe.kb_value & 0xFF) + 0x1008FF00; - break; -#endif - - default: - break; - } - if (i < minKeyCode) - minKeyCode = i; - if (i > maxKeyCode) - maxKeyCode = i; - } - - if (minKeyCode == NR_KEYS) - continue; - - if (k[3] == k[2]) k[3] = NoSymbol; - if (k[2] == k[1]) k[2] = NoSymbol; - if (k[1] == k[0]) k[1] = NoSymbol; - if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; - if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] =NoSymbol; - row++; - } - ki->minScanCode = minKeyCode; - ki->maxScanCode = maxKeyCode; -#endif -} - -/* - * We need these to handle extended scancodes correctly (I could just use the - * numbers below, but this makes the code more readable - */ - -/* The prefix codes */ -#define KEY_Prefix0 /* special 0x60 */ 96 -#define KEY_Prefix1 /* special 0x61 */ 97 - -/* The raw scancodes */ -#define KEY_Enter /* Enter 0x1c */ 28 -#define KEY_LCtrl /* Ctrl(left) 0x1d */ 29 -#define KEY_Slash /* / (Slash) ? 0x35 */ 53 -#define KEY_KP_Multiply /* * 0x37 */ 55 -#define KEY_Alt /* Alt(left) 0x38 */ 56 -#define KEY_F3 /* F3 0x3d */ 61 -#define KEY_F4 /* F4 0x3e */ 62 -#define KEY_F5 /* F5 0x3f */ 63 -#define KEY_F6 /* F6 0x40 */ 64 -#define KEY_F7 /* F7 0x41 */ 65 -#define KEY_ScrollLock /* ScrollLock 0x46 */ 70 -#define KEY_KP_7 /* 7 Home 0x47 */ 71 -#define KEY_KP_8 /* 8 Up 0x48 */ 72 -#define KEY_KP_9 /* 9 PgUp 0x49 */ 73 -#define KEY_KP_Minus /* - (Minus) 0x4a */ 74 -#define KEY_KP_4 /* 4 Left 0x4b */ 75 -#define KEY_KP_5 /* 5 0x4c */ 76 -#define KEY_KP_6 /* 6 Right 0x4d */ 77 -#define KEY_KP_Plus /* + (Plus) 0x4e */ 78 -#define KEY_KP_1 /* 1 End 0x4f */ 79 -#define KEY_KP_2 /* 2 Down 0x50 */ 80 -#define KEY_KP_3 /* 3 PgDown 0x51 */ 81 -#define KEY_KP_0 /* 0 Insert 0x52 */ 82 -#define KEY_KP_Decimal /* . (Decimal) Delete 0x53 */ 83 -#define KEY_Home /* Home 0x59 */ 89 -#define KEY_Up /* Up 0x5a */ 90 -#define KEY_PgUp /* PgUp 0x5b */ 91 -#define KEY_Left /* Left 0x5c */ 92 -#define KEY_Begin /* Begin 0x5d */ 93 -#define KEY_Right /* Right 0x5e */ 94 -#define KEY_End /* End 0x5f */ 95 -#define KEY_Down /* Down 0x60 */ 96 -#define KEY_PgDown /* PgDown 0x61 */ 97 -#define KEY_Insert /* Insert 0x62 */ 98 -#define KEY_Delete /* Delete 0x63 */ 99 -#define KEY_KP_Enter /* Enter 0x64 */ 100 -#define KEY_RCtrl /* Ctrl(right) 0x65 */ 101 -#define KEY_Pause /* Pause 0x66 */ 102 -#define KEY_Print /* Print 0x67 */ 103 -#define KEY_KP_Divide /* Divide 0x68 */ 104 -#define KEY_AltLang /* AtlLang(right) 0x69 */ 105 -#define KEY_Break /* Break 0x6a */ 106 -#define KEY_LMeta /* Left Meta 0x6b */ 107 -#define KEY_RMeta /* Right Meta 0x6c */ 108 -#define KEY_Menu /* Menu 0x6d */ 109 -#define KEY_F13 /* F13 0x6e */ 110 -#define KEY_F14 /* F14 0x6f */ 111 -#define KEY_F15 /* F15 0x70 */ 112 -#define KEY_F16 /* F16 0x71 */ 113 -#define KEY_F17 /* F17 0x72 */ 114 -#define KEY_KP_DEC /* KP_DEC 0x73 */ 115 - -static void -LinuxKeyboardRead (int fd, void *closure) -{ - unsigned char buf[256], *b; - int n; - unsigned char prefix = 0, scancode = 0; - - while ((n = read (fd, buf, sizeof (buf))) > 0) { - b = buf; - while (n--) { - /* - * With xkb we use RAW mode for reading the console, which allows us - * process extended scancodes. - * - * See if this is a prefix extending the following keycode - */ - if (!prefix && ((b[0] & 0x7f) == KEY_Prefix0)) - { - prefix = KEY_Prefix0; - /* swallow this up */ - b++; - continue; - } - else if (!prefix && ((b[0] & 0x7f) == KEY_Prefix1)) - { - prefix = KEY_Prefix1; - /* swallow this up */ - b++; - continue; - } - scancode = b[0] & 0x7f; - - switch (prefix) { - /* from xf86Events.c */ - case KEY_Prefix0: - { - switch (scancode) { - case KEY_KP_7: - scancode = KEY_Home; break; /* curs home */ - case KEY_KP_8: - scancode = KEY_Up; break; /* curs up */ - case KEY_KP_9: - scancode = KEY_PgUp; break; /* curs pgup */ - case KEY_KP_4: - scancode = KEY_Left; break; /* curs left */ - case KEY_KP_5: - scancode = KEY_Begin; break; /* curs begin */ - case KEY_KP_6: - scancode = KEY_Right; break; /* curs right */ - case KEY_KP_1: - scancode = KEY_End; break; /* curs end */ - case KEY_KP_2: - scancode = KEY_Down; break; /* curs down */ - case KEY_KP_3: - scancode = KEY_PgDown; break; /* curs pgdown */ - case KEY_KP_0: - scancode = KEY_Insert; break; /* curs insert */ - case KEY_KP_Decimal: - scancode = KEY_Delete; break; /* curs delete */ - case KEY_Enter: - scancode = KEY_KP_Enter; break; /* keypad enter */ - case KEY_LCtrl: - scancode = KEY_RCtrl; break; /* right ctrl */ - case KEY_KP_Multiply: - scancode = KEY_Print; break; /* print */ - case KEY_Slash: - scancode = KEY_KP_Divide; break; /* keyp divide */ - case KEY_Alt: - scancode = KEY_AltLang; break; /* right alt */ - case KEY_ScrollLock: - scancode = KEY_Break; break; /* curs break */ - case 0x5b: - scancode = KEY_LMeta; break; - case 0x5c: - scancode = KEY_RMeta; break; - case 0x5d: - scancode = KEY_Menu; break; - case KEY_F3: - scancode = KEY_F13; break; - case KEY_F4: - scancode = KEY_F14; break; - case KEY_F5: - scancode = KEY_F15; break; - case KEY_F6: - scancode = KEY_F16; break; - case KEY_F7: - scancode = KEY_F17; break; - case KEY_KP_Plus: - scancode = KEY_KP_DEC; break; - /* Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) */ - case 0x2A: - case 0x36: - b++; - prefix = 0; - continue; - default: - /* - * "Internet" keyboards are generating lots of new - * codes. Let them pass. There is little consistency - * between them, so don't bother with symbolic names at - * this level. - */ - scancode += 0x78; - } - break; - } - - case KEY_Prefix1: - { - /* we do no handle these */ - b++; - prefix = 0; - continue; - } - - default: /* should not happen*/ - case 0: /* do nothing */ - ; - } - - prefix = 0; - KdEnqueueKeyboardEvent (closure, scancode, b[0] & 0x80); - b++; - } - } -} - -static int LinuxKbdTrans; -static struct termios LinuxTermios; - -static Status -LinuxKeyboardEnable (KdKeyboardInfo *ki) -{ - struct termios nTty; - unsigned char buf[256]; - int n; - int fd; - - if (!ki) - return !Success; - - fd = LinuxConsoleFd; - ki->driverPrivate = (void *) fd; - - ioctl (fd, KDGKBMODE, &LinuxKbdTrans); - tcgetattr (fd, &LinuxTermios); - ioctl(fd, KDSKBMODE, K_RAW); - nTty = LinuxTermios; - nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); - nTty.c_oflag = 0; - nTty.c_cflag = CREAD | CS8; - nTty.c_lflag = 0; - nTty.c_cc[VTIME]=0; - nTty.c_cc[VMIN]=1; - cfsetispeed(&nTty, 9600); - cfsetospeed(&nTty, 9600); - tcsetattr(fd, TCSANOW, &nTty); - /* - * Flush any pending keystrokes - */ - while ((n = read (fd, buf, sizeof (buf))) > 0) - ; - KdRegisterFd (fd, LinuxKeyboardRead, ki); - return Success; -} - -static void -LinuxKeyboardDisable (KdKeyboardInfo *ki) -{ - int fd; - - if (!ki) - return; - - fd = (int) ki->driverPrivate; - - KdUnregisterFd(ki, fd, FALSE); - ioctl(fd, KDSKBMODE, LinuxKbdTrans); - tcsetattr(fd, TCSANOW, &LinuxTermios); -} - -static Status -LinuxKeyboardInit (KdKeyboardInfo *ki) -{ - if (!ki) - return !Success; - - xfree(ki->path); - ki->path = strdup("console"); - xfree(ki->name); - ki->name = strdup("Linux console keyboard"); - - readKernelMapping (ki); - - return Success; -} - -static void -LinuxKeyboardLeds (KdKeyboardInfo *ki, int leds) -{ - if (!ki) - return; - - ioctl ((int)ki->driverPrivate, KDSETLED, leds & 7); -} - -KdKeyboardDriver LinuxKeyboardDriver = { - "keyboard", - .Init = LinuxKeyboardInit, - .Enable = LinuxKeyboardEnable, - .Leds = LinuxKeyboardLeds, - .Disable = LinuxKeyboardDisable, -}; +/* + * Copyright © 1999 Keith Packard + * XKB integration © 2006 Nokia Corporation, author: Tomas Frydrych + * + * LinuxKeyboardRead() XKB code based on xf86KbdLnx.c: + * Copyright © 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * Copyright © 1994-2001 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "kdrive.h" +#include +#include +#define XK_PUBLISHING +#include +#include +#include + +extern int LinuxConsoleFd; + +static const KeySym linux_to_x[256] = { + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, XK_Escape, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_space, XK_exclam, XK_quotedbl, XK_numbersign, + XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, + XK_parenleft, XK_parenright, XK_asterisk, XK_plus, + XK_comma, XK_minus, XK_period, XK_slash, + XK_0, XK_1, XK_2, XK_3, + XK_4, XK_5, XK_6, XK_7, + XK_8, XK_9, XK_colon, XK_semicolon, + XK_less, XK_equal, XK_greater, XK_question, + XK_at, XK_A, XK_B, XK_C, + XK_D, XK_E, XK_F, XK_G, + XK_H, XK_I, XK_J, XK_K, + XK_L, XK_M, XK_N, XK_O, + XK_P, XK_Q, XK_R, XK_S, + XK_T, XK_U, XK_V, XK_W, + XK_X, XK_Y, XK_Z, XK_bracketleft, + XK_backslash, XK_bracketright,XK_asciicircum, XK_underscore, + XK_grave, XK_a, XK_b, XK_c, + XK_d, XK_e, XK_f, XK_g, + XK_h, XK_i, XK_j, XK_k, + XK_l, XK_m, XK_n, XK_o, + XK_p, XK_q, XK_r, XK_s, + XK_t, XK_u, XK_v, XK_w, + XK_x, XK_y, XK_z, XK_braceleft, + XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, + XK_nobreakspace,XK_exclamdown, XK_cent, XK_sterling, + XK_currency, XK_yen, XK_brokenbar, XK_section, + XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, + XK_notsign, XK_hyphen, XK_registered, XK_macron, + XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, + XK_acute, XK_mu, XK_paragraph, XK_periodcentered, + XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, + XK_onequarter, XK_onehalf, XK_threequarters,XK_questiondown, + XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, + XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, + XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, + XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, + XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, + XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, + XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, + XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, + XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, + XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, + XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, + XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, + XK_eth, XK_ntilde, XK_ograve, XK_oacute, + XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, + XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, + XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis +}; + +/* + * Getting a keycode from scancode + * + * With XKB + * -------- + * + * We have to enqueue keyboard events using standard X keycodes which correspond + * to AT scancode + 8; this means that we need to translate the Linux scancode + * provided by the kernel to an AT scancode -- this translation is not linear + * and requires that we use a LUT. + * + * + * Without XKB + * ----------- + * + * We can use custom keycodes, which makes things simpler; we define our custom + * keycodes as Linux scancodes + KD_KEY_OFFSET +*/ + +/* + This LUT translates AT scancodes into Linux ones -- the keymap we create + for the core X keyboard protocol has to be AT-scancode based so that it + corresponds to the Xkb keymap. +*/ +#if 0 +static unsigned char at2lnx[] = +{ + 0x0, /* no valid scancode */ + 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ + 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ + 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ + 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ + 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ + 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ + 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ + 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ + 0x11, /* KEY_W */ 0x12, /* KEY_E */ + 0x13, /* KEY_R */ 0x14, /* KEY_T */ + 0x15, /* KEY_Y */ 0x16, /* KEY_U */ + 0x17, /* KEY_I */ 0x18, /* KEY_O */ + 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ + 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ + 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ + 0x1f, /* KEY_S */ 0x20, /* KEY_D */ + 0x21, /* KEY_F */ 0x22, /* KEY_G */ + 0x23, /* KEY_H */ 0x24, /* KEY_J */ + 0x25, /* KEY_K */ 0x26, /* KEY_L */ + 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ + 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ + 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ + 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ + 0x2f, /* KEY_V */ 0x30, /* KEY_B */ + 0x31, /* KEY_N */ 0x32, /* KEY_M */ + 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ + 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ + 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ + 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ + 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ + 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ + 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ + 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ + 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ + 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ + 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ + 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ + 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ + 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ + 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ + 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ + 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ + 0x00, /* 0x55 */ 0x56, /* KEY_Less */ + 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ + 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ + 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ + 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ + 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ + 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ + 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ + 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ + 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ + 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ + 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ + 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */ + 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ + 0x00, /* 0x71 */ 0x00, /* 0x72 */ + 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ + 0x00, /* 0x75 */ 0x00, /* 0x76 */ + 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ + 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ + 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ + 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ + 0x00, /* 0x7f */ +}; + +#define NUM_AT_KEYS (sizeof(at2lnx)/sizeof(at2lnx[0])) +#define LNX_KEY_INDEX(n) n < NUM_AT_KEYS ? at2lnx[n] : 0 + +static unsigned char tbl[KD_MAX_WIDTH] = +{ + 0, + 1 << KG_SHIFT, + (1 << KG_ALTGR), + (1 << KG_ALTGR) | (1 << KG_SHIFT) +}; +#endif + +static void +readKernelMapping(KdKeyboardInfo *ki) +{ +#if 0 + KeySym *k; + int i, j; + struct kbentry kbe; + int minKeyCode, maxKeyCode; + int row; + int fd; + + if (!ki) + return; + + fd = LinuxConsoleFd; + + minKeyCode = NR_KEYS; + maxKeyCode = 0; + row = 0; + ki->keySyms.mapWidth = KD_MAX_WIDTH; + for (i = 0; i < NR_KEYS && row < KD_MAX_LENGTH; ++i) + { + kbe.kb_index = LNX_KEY_INDEX(i); + + k = ki->keySyms.map + row * ki->keySyms.mapWidth; + + for (j = 0; j < ki->keySyms.mapWidth; ++j) + { + unsigned short kval; + + k[j] = NoSymbol; + + kbe.kb_table = tbl[j]; + kbe.kb_value = 0; + if (ioctl(fd, KDGKBENT, &kbe)) + continue; + + kval = KVAL(kbe.kb_value); + switch (KTYP(kbe.kb_value)) + { + case KT_LATIN: + case KT_LETTER: + k[j] = linux_to_x[kval]; + break; + + case KT_FN: + if (kval <= 19) + k[j] = XK_F1 + kval; + else switch (kbe.kb_value) + { + case K_FIND: + k[j] = XK_Home; /* or XK_Find */ + break; + case K_INSERT: + k[j] = XK_Insert; + break; + case K_REMOVE: + k[j] = XK_Delete; + break; + case K_SELECT: + k[j] = XK_End; /* or XK_Select */ + break; + case K_PGUP: + k[j] = XK_Prior; + break; + case K_PGDN: + k[j] = XK_Next; + break; + case K_HELP: + k[j] = XK_Help; + break; + case K_DO: + k[j] = XK_Execute; + break; + case K_PAUSE: + k[j] = XK_Pause; + break; + case K_MACRO: + k[j] = XK_Menu; + break; + default: + break; + } + break; + + case KT_SPEC: + switch (kbe.kb_value) + { + case K_ENTER: + k[j] = XK_Return; + break; + case K_BREAK: + k[j] = XK_Break; + break; + case K_CAPS: + k[j] = XK_Caps_Lock; + break; + case K_NUM: + k[j] = XK_Num_Lock; + break; + case K_HOLD: + k[j] = XK_Scroll_Lock; + break; + case K_COMPOSE: + k[j] = XK_Multi_key; + break; + default: + break; + } + break; + + case KT_PAD: + switch (kbe.kb_value) + { + case K_PPLUS: + k[j] = XK_KP_Add; + break; + case K_PMINUS: + k[j] = XK_KP_Subtract; + break; + case K_PSTAR: + k[j] = XK_KP_Multiply; + break; + case K_PSLASH: + k[j] = XK_KP_Divide; + break; + case K_PENTER: + k[j] = XK_KP_Enter; + break; + case K_PCOMMA: + k[j] = XK_KP_Separator; + break; + case K_PDOT: + k[j] = XK_KP_Decimal; + break; + case K_PPLUSMINUS: + k[j] = XK_KP_Subtract; + break; + default: + if (kval <= 9) + k[j] = XK_KP_0 + kval; + break; + } + break; + + /* + * KT_DEAD keys are for accelerated diacritical creation. + */ + case KT_DEAD: + switch (kbe.kb_value) + { + case K_DGRAVE: + k[j] = XK_dead_grave; + break; + case K_DACUTE: + k[j] = XK_dead_acute; + break; + case K_DCIRCM: + k[j] = XK_dead_circumflex; + break; + case K_DTILDE: + k[j] = XK_dead_tilde; + break; + case K_DDIERE: + k[j] = XK_dead_diaeresis; + break; + } + break; + + case KT_CUR: + switch (kbe.kb_value) + { + case K_DOWN: + k[j] = XK_Down; + break; + case K_LEFT: + k[j] = XK_Left; + break; + case K_RIGHT: + k[j] = XK_Right; + break; + case K_UP: + k[j] = XK_Up; + break; + } + break; + + case KT_SHIFT: + switch (kbe.kb_value) + { + case K_ALTGR: + k[j] = XK_Mode_switch; + break; + case K_ALT: + k[j] = (kbe.kb_index == 0x64 ? + XK_Alt_R : XK_Alt_L); + break; + case K_CTRL: + k[j] = (kbe.kb_index == 0x61 ? + XK_Control_R : XK_Control_L); + break; + case K_CTRLL: + k[j] = XK_Control_L; + break; + case K_CTRLR: + k[j] = XK_Control_R; + break; + case K_SHIFT: + k[j] = (kbe.kb_index == 0x36 ? + XK_Shift_R : XK_Shift_L); + break; + case K_SHIFTL: + k[j] = XK_Shift_L; + break; + case K_SHIFTR: + k[j] = XK_Shift_R; + break; + default: + break; + } + break; + + /* + * KT_ASCII keys accumulate a 3 digit decimal number that gets + * emitted when the shift state changes. We can't emulate that. + */ + case KT_ASCII: + break; + + case KT_LOCK: + if (kbe.kb_value == K_SHIFTLOCK) + k[j] = XK_Shift_Lock; + break; + +#ifdef KT_X + case KT_X: + /* depends on new keyboard symbols in file linux/keyboard.h */ + if(kbe.kb_value == K_XMENU) k[j] = XK_Menu; + if(kbe.kb_value == K_XTELEPHONE) k[j] = XK_telephone; + break; +#endif +#ifdef KT_XF + case KT_XF: + /* special linux keysyms which map directly to XF86 keysyms */ + k[j] = (kbe.kb_value & 0xFF) + 0x1008FF00; + break; +#endif + + default: + break; + } + if (i < minKeyCode) + minKeyCode = i; + if (i > maxKeyCode) + maxKeyCode = i; + } + + if (minKeyCode == NR_KEYS) + continue; + + if (k[3] == k[2]) k[3] = NoSymbol; + if (k[2] == k[1]) k[2] = NoSymbol; + if (k[1] == k[0]) k[1] = NoSymbol; + if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; + if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] =NoSymbol; + row++; + } + ki->minScanCode = minKeyCode; + ki->maxScanCode = maxKeyCode; +#endif +} + +/* + * We need these to handle extended scancodes correctly (I could just use the + * numbers below, but this makes the code more readable + */ + +/* The prefix codes */ +#define KEY_Prefix0 /* special 0x60 */ 96 +#define KEY_Prefix1 /* special 0x61 */ 97 + +/* The raw scancodes */ +#define KEY_Enter /* Enter 0x1c */ 28 +#define KEY_LCtrl /* Ctrl(left) 0x1d */ 29 +#define KEY_Slash /* / (Slash) ? 0x35 */ 53 +#define KEY_KP_Multiply /* * 0x37 */ 55 +#define KEY_Alt /* Alt(left) 0x38 */ 56 +#define KEY_F3 /* F3 0x3d */ 61 +#define KEY_F4 /* F4 0x3e */ 62 +#define KEY_F5 /* F5 0x3f */ 63 +#define KEY_F6 /* F6 0x40 */ 64 +#define KEY_F7 /* F7 0x41 */ 65 +#define KEY_ScrollLock /* ScrollLock 0x46 */ 70 +#define KEY_KP_7 /* 7 Home 0x47 */ 71 +#define KEY_KP_8 /* 8 Up 0x48 */ 72 +#define KEY_KP_9 /* 9 PgUp 0x49 */ 73 +#define KEY_KP_Minus /* - (Minus) 0x4a */ 74 +#define KEY_KP_4 /* 4 Left 0x4b */ 75 +#define KEY_KP_5 /* 5 0x4c */ 76 +#define KEY_KP_6 /* 6 Right 0x4d */ 77 +#define KEY_KP_Plus /* + (Plus) 0x4e */ 78 +#define KEY_KP_1 /* 1 End 0x4f */ 79 +#define KEY_KP_2 /* 2 Down 0x50 */ 80 +#define KEY_KP_3 /* 3 PgDown 0x51 */ 81 +#define KEY_KP_0 /* 0 Insert 0x52 */ 82 +#define KEY_KP_Decimal /* . (Decimal) Delete 0x53 */ 83 +#define KEY_Home /* Home 0x59 */ 89 +#define KEY_Up /* Up 0x5a */ 90 +#define KEY_PgUp /* PgUp 0x5b */ 91 +#define KEY_Left /* Left 0x5c */ 92 +#define KEY_Begin /* Begin 0x5d */ 93 +#define KEY_Right /* Right 0x5e */ 94 +#define KEY_End /* End 0x5f */ 95 +#define KEY_Down /* Down 0x60 */ 96 +#define KEY_PgDown /* PgDown 0x61 */ 97 +#define KEY_Insert /* Insert 0x62 */ 98 +#define KEY_Delete /* Delete 0x63 */ 99 +#define KEY_KP_Enter /* Enter 0x64 */ 100 +#define KEY_RCtrl /* Ctrl(right) 0x65 */ 101 +#define KEY_Pause /* Pause 0x66 */ 102 +#define KEY_Print /* Print 0x67 */ 103 +#define KEY_KP_Divide /* Divide 0x68 */ 104 +#define KEY_AltLang /* AtlLang(right) 0x69 */ 105 +#define KEY_Break /* Break 0x6a */ 106 +#define KEY_LMeta /* Left Meta 0x6b */ 107 +#define KEY_RMeta /* Right Meta 0x6c */ 108 +#define KEY_Menu /* Menu 0x6d */ 109 +#define KEY_F13 /* F13 0x6e */ 110 +#define KEY_F14 /* F14 0x6f */ 111 +#define KEY_F15 /* F15 0x70 */ 112 +#define KEY_F16 /* F16 0x71 */ 113 +#define KEY_F17 /* F17 0x72 */ 114 +#define KEY_KP_DEC /* KP_DEC 0x73 */ 115 + +static void +LinuxKeyboardRead (int fd, void *closure) +{ + unsigned char buf[256], *b; + int n; + unsigned char prefix = 0, scancode = 0; + + while ((n = read (fd, buf, sizeof (buf))) > 0) { + b = buf; + while (n--) { + /* + * With xkb we use RAW mode for reading the console, which allows us + * process extended scancodes. + * + * See if this is a prefix extending the following keycode + */ + if (!prefix && ((b[0] & 0x7f) == KEY_Prefix0)) + { + prefix = KEY_Prefix0; + /* swallow this up */ + b++; + continue; + } + else if (!prefix && ((b[0] & 0x7f) == KEY_Prefix1)) + { + prefix = KEY_Prefix1; + /* swallow this up */ + b++; + continue; + } + scancode = b[0] & 0x7f; + + switch (prefix) { + /* from xf86Events.c */ + case KEY_Prefix0: + { + switch (scancode) { + case KEY_KP_7: + scancode = KEY_Home; break; /* curs home */ + case KEY_KP_8: + scancode = KEY_Up; break; /* curs up */ + case KEY_KP_9: + scancode = KEY_PgUp; break; /* curs pgup */ + case KEY_KP_4: + scancode = KEY_Left; break; /* curs left */ + case KEY_KP_5: + scancode = KEY_Begin; break; /* curs begin */ + case KEY_KP_6: + scancode = KEY_Right; break; /* curs right */ + case KEY_KP_1: + scancode = KEY_End; break; /* curs end */ + case KEY_KP_2: + scancode = KEY_Down; break; /* curs down */ + case KEY_KP_3: + scancode = KEY_PgDown; break; /* curs pgdown */ + case KEY_KP_0: + scancode = KEY_Insert; break; /* curs insert */ + case KEY_KP_Decimal: + scancode = KEY_Delete; break; /* curs delete */ + case KEY_Enter: + scancode = KEY_KP_Enter; break; /* keypad enter */ + case KEY_LCtrl: + scancode = KEY_RCtrl; break; /* right ctrl */ + case KEY_KP_Multiply: + scancode = KEY_Print; break; /* print */ + case KEY_Slash: + scancode = KEY_KP_Divide; break; /* keyp divide */ + case KEY_Alt: + scancode = KEY_AltLang; break; /* right alt */ + case KEY_ScrollLock: + scancode = KEY_Break; break; /* curs break */ + case 0x5b: + scancode = KEY_LMeta; break; + case 0x5c: + scancode = KEY_RMeta; break; + case 0x5d: + scancode = KEY_Menu; break; + case KEY_F3: + scancode = KEY_F13; break; + case KEY_F4: + scancode = KEY_F14; break; + case KEY_F5: + scancode = KEY_F15; break; + case KEY_F6: + scancode = KEY_F16; break; + case KEY_F7: + scancode = KEY_F17; break; + case KEY_KP_Plus: + scancode = KEY_KP_DEC; break; + /* Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) */ + case 0x2A: + case 0x36: + b++; + prefix = 0; + continue; + default: + /* + * "Internet" keyboards are generating lots of new + * codes. Let them pass. There is little consistency + * between them, so don't bother with symbolic names at + * this level. + */ + scancode += 0x78; + } + break; + } + + case KEY_Prefix1: + { + /* we do no handle these */ + b++; + prefix = 0; + continue; + } + + default: /* should not happen*/ + case 0: /* do nothing */ + ; + } + + prefix = 0; + KdEnqueueKeyboardEvent (closure, scancode, b[0] & 0x80); + b++; + } + } +} + +static int LinuxKbdTrans; +static struct termios LinuxTermios; + +static Status +LinuxKeyboardEnable (KdKeyboardInfo *ki) +{ + struct termios nTty; + unsigned char buf[256]; + int n; + int fd; + + if (!ki) + return !Success; + + fd = LinuxConsoleFd; + ki->driverPrivate = (void *) fd; + + ioctl (fd, KDGKBMODE, &LinuxKbdTrans); + tcgetattr (fd, &LinuxTermios); + ioctl(fd, KDSKBMODE, K_RAW); + nTty = LinuxTermios; + nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); + nTty.c_oflag = 0; + nTty.c_cflag = CREAD | CS8; + nTty.c_lflag = 0; + nTty.c_cc[VTIME]=0; + nTty.c_cc[VMIN]=1; + cfsetispeed(&nTty, 9600); + cfsetospeed(&nTty, 9600); + tcsetattr(fd, TCSANOW, &nTty); + /* + * Flush any pending keystrokes + */ + while ((n = read (fd, buf, sizeof (buf))) > 0) + ; + KdRegisterFd (fd, LinuxKeyboardRead, ki); + return Success; +} + +static void +LinuxKeyboardDisable (KdKeyboardInfo *ki) +{ + int fd; + + if (!ki) + return; + + fd = (int) ki->driverPrivate; + + KdUnregisterFd(ki, fd, FALSE); + ioctl(fd, KDSKBMODE, LinuxKbdTrans); + tcsetattr(fd, TCSANOW, &LinuxTermios); +} + +static Status +LinuxKeyboardInit (KdKeyboardInfo *ki) +{ + if (!ki) + return !Success; + + free(ki->path); + ki->path = strdup("console"); + free(ki->name); + ki->name = strdup("Linux console keyboard"); + + readKernelMapping (ki); + + return Success; +} + +static void +LinuxKeyboardLeds (KdKeyboardInfo *ki, int leds) +{ + if (!ki) + return; + + ioctl ((int)ki->driverPrivate, KDSETLED, leds & 7); +} + +KdKeyboardDriver LinuxKeyboardDriver = { + "keyboard", + .Init = LinuxKeyboardInit, + .Enable = LinuxKeyboardEnable, + .Leds = LinuxKeyboardLeds, + .Disable = LinuxKeyboardDisable, +}; diff --git a/xorg-server/hw/kdrive/linux/mouse.c b/xorg-server/hw/kdrive/linux/mouse.c index 007263e4b..2e39d240e 100644 --- a/xorg-server/hw/kdrive/linux/mouse.c +++ b/xorg-server/hw/kdrive/linux/mouse.c @@ -1,1030 +1,1030 @@ -/* - * Copyright © 2001 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#include -#include -#include -#include -#include "inputstr.h" -#include "scrnintstr.h" -#include "kdrive.h" - -#undef DEBUG -#undef DEBUG_BYTES -#define KBUFIO_SIZE 256 -#define MOUSE_TIMEOUT 100 - -typedef struct _kbufio { - int fd; - unsigned char buf[KBUFIO_SIZE]; - int avail; - int used; -} Kbufio; - -static Bool -MouseWaitForReadable (int fd, int timeout) -{ - fd_set set; - struct timeval tv, *tp; - int n; - CARD32 done; - - done = GetTimeInMillis () + timeout; - for (;;) - { - FD_ZERO (&set); - FD_SET (fd, &set); - if (timeout == -1) - tp = 0; - else - { - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - tp = &tv; - } - n = select (fd + 1, &set, 0, 0, tp); - if (n > 0) - return TRUE; - if (n < 0 && (errno == EAGAIN || errno == EINTR)) - { - timeout = (int) (done - GetTimeInMillis ()); - if (timeout > 0) - continue; - } - break; - } - return FALSE; -} - -static int -MouseReadByte (Kbufio *b, int timeout) -{ - int n; - if (b->avail <= b->used) - { - if (timeout && !MouseWaitForReadable (b->fd, timeout)) - { -#ifdef DEBUG_BYTES - ErrorF ("\tTimeout %d\n", timeout); -#endif - return -1; - } - n = read (b->fd, b->buf, KBUFIO_SIZE); - if (n <= 0) - return -1; - b->avail = n; - b->used = 0; - } -#ifdef DEBUG_BYTES - ErrorF ("\tget %02x\n", b->buf[b->used]); -#endif - return b->buf[b->used++]; -} - -#if NOTUSED -static int -MouseFlush (Kbufio *b, char *buf, int size) -{ - CARD32 now = GetTimeInMillis (); - CARD32 done = now + 100; - int c; - int n = 0; - - while ((c = MouseReadByte (b, done - now)) != -1) - { - if (buf) - { - if (n == size) - { - memmove (buf, buf + 1, size - 1); - n--; - } - buf[n++] = c; - } - now = GetTimeInMillis (); - if ((INT32) (now - done) >= 0) - break; - } - return n; -} - -static int -MousePeekByte (Kbufio *b, int timeout) -{ - int c; - - c = MouseReadByte (b, timeout); - if (c != -1) - --b->used; - return c; -} -#endif /* NOTUSED */ - -static Bool -MouseWaitForWritable (int fd, int timeout) -{ - fd_set set; - struct timeval tv, *tp; - int n; - - FD_ZERO (&set); - FD_SET (fd, &set); - if (timeout == -1) - tp = 0; - else - { - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - tp = &tv; - } - n = select (fd + 1, 0, &set, 0, tp); - if (n > 0) - return TRUE; - return FALSE; -} - -static Bool -MouseWriteByte (int fd, unsigned char c, int timeout) -{ - int ret; - -#ifdef DEBUG_BYTES - ErrorF ("\tput %02x\n", c); -#endif - for (;;) - { - ret = write (fd, &c, 1); - if (ret == 1) - return TRUE; - if (ret == 0) - return FALSE; - if (errno != EWOULDBLOCK) - return FALSE; - if (!MouseWaitForWritable (fd, timeout)) - return FALSE; - } -} - -static Bool -MouseWriteBytes (int fd, unsigned char *c, int n, int timeout) -{ - while (n--) - if (!MouseWriteByte (fd, *c++, timeout)) - return FALSE; - return TRUE; -} - -#define MAX_MOUSE 10 /* maximum length of mouse protocol */ -#define MAX_SKIP 16 /* number of error bytes before switching */ -#define MAX_VALID 4 /* number of valid packets before accepting */ - -typedef struct _kmouseProt { - char *name; - Bool (*Complete) (KdPointerInfo *pi, unsigned char *ev, int ne); - int (*Valid) (KdPointerInfo *pi, unsigned char *ev, int ne); - Bool (*Parse) (KdPointerInfo *pi, unsigned char *ev, int ne); - Bool (*Init) (KdPointerInfo *pi); - unsigned char headerMask, headerValid; - unsigned char dataMask, dataValid; - Bool tty; - unsigned int c_iflag; - unsigned int c_oflag; - unsigned int c_lflag; - unsigned int c_cflag; - unsigned int speed; - unsigned char *init; - unsigned long state; -} KmouseProt; - -typedef enum _kmouseStage { - MouseBroken, MouseTesting, MouseWorking -} KmouseStage; - -typedef struct _kmouse { - Kbufio iob; - const KmouseProt *prot; - int i_prot; - KmouseStage stage; /* protocol verification stage */ - Bool tty; /* mouse device is a tty */ - int valid; /* sequential valid events */ - int tested; /* bytes scanned during Testing phase */ - int invalid;/* total invalid bytes for this protocol */ - unsigned long state; /* private per protocol, init to prot->state */ -} Kmouse; - -static int mouseValid (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - const KmouseProt *prot = km->prot; - int i; - - for (i = 0; i < ne; i++) - if ((ev[i] & prot->headerMask) == prot->headerValid) - break; - if (i != 0) - return i; - for (i = 1; i < ne; i++) - if ((ev[i] & prot->dataMask) != prot->dataValid) - return -1; - return 0; -} - -static Bool threeComplete (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - return ne == 3; -} - -static Bool fourComplete (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - return ne == 4; -} - -static Bool fiveComplete (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - return ne == 5; -} - -static Bool MouseReasonable (KdPointerInfo *pi, unsigned long flags, int dx, int dy) -{ - Kmouse *km = pi->driverPrivate; - - if (km->stage == MouseWorking) - return TRUE; - if (dx < -50 || dx > 50) - { -#ifdef DEBUG - ErrorF ("Large X %d\n", dx); -#endif - return FALSE; - } - if (dy < -50 || dy > 50) - { -#ifdef DEBUG - ErrorF ("Large Y %d\n", dy); -#endif - return FALSE; - } - return TRUE; -} - -/* - * Standard PS/2 mouse protocol - */ -static Bool ps2Parse (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - int dx, dy, dz; - unsigned long flags; - unsigned long flagsrelease = 0; - - flags = KD_MOUSE_DELTA; - if (ev[0] & 4) - flags |= KD_BUTTON_2; - if (ev[0] & 2) - flags |= KD_BUTTON_3; - if (ev[0] & 1) - flags |= KD_BUTTON_1; - - if (ne > 3) - { - dz = (int) (signed char) ev[3]; - if (dz < 0) - { - flags |= KD_BUTTON_4; - flagsrelease = KD_BUTTON_4; - } - else if (dz > 0) - { - flags |= KD_BUTTON_5; - flagsrelease = KD_BUTTON_5; - } - } - - dx = ev[1]; - if (ev[0] & 0x10) - dx -= 256; - dy = ev[2]; - if (ev[0] & 0x20) - dy -= 256; - dy = -dy; - if (!MouseReasonable (pi, flags, dx, dy)) - return FALSE; - if (km->stage == MouseWorking) - { - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - if (flagsrelease) - { - flags &= ~flagsrelease; - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - } - } - return TRUE; -} - -static Bool ps2Init (KdPointerInfo *pi); - -static const KmouseProt ps2Prot = { - "ps/2", - threeComplete, mouseValid, ps2Parse, ps2Init, - 0x08, 0x08, 0x00, 0x00, - FALSE -}; - -static const KmouseProt imps2Prot = { - "imps/2", - fourComplete, mouseValid, ps2Parse, ps2Init, - 0x08, 0x08, 0x00, 0x00, - FALSE -}; - -static const KmouseProt exps2Prot = { - "exps/2", - fourComplete, mouseValid, ps2Parse, ps2Init, - 0x08, 0x08, 0x00, 0x00, - FALSE -}; - -/* - * Once the mouse is known to speak ps/2 protocol, go and find out - * what advanced capabilities it has and turn them on - */ - -/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */ - -/* aux device commands (sent to KBD_DATA_PORT) */ -#define PSMC_SET_SCALING11 0x00e6 -#define PSMC_SET_SCALING21 0x00e7 -#define PSMC_SET_RESOLUTION 0x00e8 -#define PSMC_SEND_DEV_STATUS 0x00e9 -#define PSMC_SET_STREAM_MODE 0x00ea -#define PSMC_SEND_DEV_DATA 0x00eb -#define PSMC_SET_REMOTE_MODE 0x00f0 -#define PSMC_SEND_DEV_ID 0x00f2 -#define PSMC_SET_SAMPLING_RATE 0x00f3 -#define PSMC_ENABLE_DEV 0x00f4 -#define PSMC_DISABLE_DEV 0x00f5 -#define PSMC_SET_DEFAULTS 0x00f6 -#define PSMC_RESET_DEV 0x00ff - -/* PSMC_SET_RESOLUTION argument */ -#define PSMD_RES_LOW 0 /* typically 25ppi */ -#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */ -#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */ -#define PSMD_RES_HIGH 3 /* typically 200ppi */ -#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH - -/* PSMC_SET_SAMPLING_RATE */ -#define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */ - -/* aux device ID */ -#define PSM_MOUSE_ID 0 -#define PSM_BALLPOINT_ID 2 -#define PSM_INTELLI_ID 3 -#define PSM_EXPLORER_ID 4 -#define PSM_4DMOUSE_ID 6 -#define PSM_4DPLUS_ID 8 - -static unsigned char ps2_init[] = { - PSMC_ENABLE_DEV, - 0, -}; - -#define NINIT_PS2 1 - -static unsigned char wheel_3button_init[] = { - PSMC_SET_SAMPLING_RATE, 200, - PSMC_SET_SAMPLING_RATE, 100, - PSMC_SET_SAMPLING_RATE, 80, - PSMC_SEND_DEV_ID, - 0, -}; - -#define NINIT_IMPS2 4 - -static unsigned char wheel_5button_init[] = { - PSMC_SET_SAMPLING_RATE, 200, - PSMC_SET_SAMPLING_RATE, 100, - PSMC_SET_SAMPLING_RATE, 80, - PSMC_SET_SAMPLING_RATE, 200, - PSMC_SET_SAMPLING_RATE, 200, - PSMC_SET_SAMPLING_RATE, 80, - PSMC_SEND_DEV_ID, - 0 -}; - -#define NINIT_EXPS2 7 - -static unsigned char intelli_init[] = { - PSMC_SET_SAMPLING_RATE, 200, - PSMC_SET_SAMPLING_RATE, 100, - PSMC_SET_SAMPLING_RATE, 80, - 0 -}; - -#define NINIT_INTELLI 3 - -static int -ps2SkipInit (KdPointerInfo *pi, int ninit, Bool ret_next) -{ - Kmouse *km = pi->driverPrivate; - int c = -1; - int skipping; - Bool waiting; - - skipping = 0; - waiting = FALSE; - while (ninit || ret_next) - { - c = MouseReadByte (&km->iob, MOUSE_TIMEOUT); - if (c == -1) - break; - /* look for ACK */ - if (c == 0xfa) - { - ninit--; - if (ret_next) - waiting = TRUE; - } - /* look for packet start -- not the response */ - else if ((c & 0x08) == 0x08) - waiting = FALSE; - else if (waiting) - break; - } - return c; -} - -static Bool -ps2Init (KdPointerInfo *pi) -{ - Kmouse *km = pi->driverPrivate; - int skipping; - Bool waiting; - int id; - unsigned char *init; - int ninit; - - /* Send Intellimouse initialization sequence */ - MouseWriteBytes (km->iob.fd, intelli_init, strlen ((char *) intelli_init), 100); - /* - * Send ID command - */ - if (!MouseWriteByte (km->iob.fd, PSMC_SEND_DEV_ID, 100)) - return FALSE; - skipping = 0; - waiting = FALSE; - id = ps2SkipInit (pi, 0, TRUE); - switch (id) { - case 3: - init = wheel_3button_init; - ninit = NINIT_IMPS2; - km->prot = &imps2Prot; - break; - case 4: - init = wheel_5button_init; - ninit = NINIT_EXPS2; - km->prot = &exps2Prot; - break; - default: - init = ps2_init; - ninit = NINIT_PS2; - km->prot = &ps2Prot; - break; - } - if (init) - MouseWriteBytes (km->iob.fd, init, strlen ((char *) init), 100); - /* - * Flush out the available data to eliminate responses to the - * initialization string. Make sure any partial event is - * skipped - */ - (void) ps2SkipInit (pi, ninit, FALSE); - return TRUE; -} - -static Bool busParse (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - int dx, dy; - unsigned long flags; - - flags = KD_MOUSE_DELTA; - dx = (signed char) ev[1]; - dy = -(signed char) ev[2]; - if ((ev[0] & 4) == 0) - flags |= KD_BUTTON_1; - if ((ev[0] & 2) == 0) - flags |= KD_BUTTON_2; - if ((ev[0] & 1) == 0) - flags |= KD_BUTTON_3; - if (!MouseReasonable (pi, flags, dx, dy)) - return FALSE; - if (km->stage == MouseWorking) - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - return TRUE; -} - -static const KmouseProt busProt = { - "bus", - threeComplete, mouseValid, busParse, 0, - 0xf8, 0x00, 0x00, 0x00, - FALSE -}; - -/* - * Standard MS serial protocol, three bytes - */ - -static Bool msParse (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - int dx, dy; - unsigned long flags; - - flags = KD_MOUSE_DELTA; - - if (ev[0] & 0x20) - flags |= KD_BUTTON_1; - if (ev[0] & 0x10) - flags |= KD_BUTTON_3; - - dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); - dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); - if (!MouseReasonable (pi, flags, dx, dy)) - return FALSE; - if (km->stage == MouseWorking) - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - return TRUE; -} - -static const KmouseProt msProt = { - "ms", - threeComplete, mouseValid, msParse, 0, - 0xc0, 0x40, 0xc0, 0x00, - TRUE, - IGNPAR, - 0, - 0, - CS7 | CSTOPB | CREAD | CLOCAL, - B1200, -}; - -/* - * Logitech mice send 3 or 4 bytes, the only way to tell is to look at the - * first byte of a synchronized protocol stream and see if it's got - * any bits turned on that can't occur in that fourth byte - */ -static Bool logiComplete (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - - if ((ev[0] & 0x40) == 0x40) - return ne == 3; - if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0) - return ne == 1; - return FALSE; -} - -static int logiValid (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - const KmouseProt *prot = km->prot; - int i; - - for (i = 0; i < ne; i++) - { - if ((ev[i] & 0x40) == 0x40) - break; - if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0) - break; - } - if (i != 0) - return i; - for (i = 1; i < ne; i++) - if ((ev[i] & prot->dataMask) != prot->dataValid) - return -1; - return 0; -} - -static Bool logiParse (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - int dx, dy; - unsigned long flags; - - flags = KD_MOUSE_DELTA; - - if (ne == 3) - { - if (ev[0] & 0x20) - flags |= KD_BUTTON_1; - if (ev[0] & 0x10) - flags |= KD_BUTTON_3; - - dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); - dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); - flags |= km->state & KD_BUTTON_2; - } - else - { - if (ev[0] & 0x20) - flags |= KD_BUTTON_2; - dx = 0; - dy = 0; - flags |= km->state & (KD_BUTTON_1|KD_BUTTON_3); - } - - if (!MouseReasonable (pi, flags, dx, dy)) - return FALSE; - if (km->stage == MouseWorking) - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - return TRUE; -} - -static const KmouseProt logiProt = { - "logitech", - logiComplete, logiValid, logiParse, 0, - 0xc0, 0x40, 0xc0, 0x00, - TRUE, - IGNPAR, - 0, - 0, - CS7 | CSTOPB | CREAD | CLOCAL, - B1200, -}; - -/* - * Mouse systems protocol, 5 bytes - */ -static Bool mscParse (KdPointerInfo *pi, unsigned char *ev, int ne) -{ - Kmouse *km = pi->driverPrivate; - int dx, dy; - unsigned long flags; - - flags = KD_MOUSE_DELTA; - - if (!(ev[0] & 0x4)) - flags |= KD_BUTTON_1; - if (!(ev[0] & 0x2)) - flags |= KD_BUTTON_2; - if (!(ev[0] & 0x1)) - flags |= KD_BUTTON_3; - dx = (signed char)(ev[1]) + (signed char)(ev[3]); - dy = - ((signed char)(ev[2]) + (signed char)(ev[4])); - - if (!MouseReasonable (pi, flags, dx, dy)) - return FALSE; - if (km->stage == MouseWorking) - KdEnqueuePointerEvent (pi, flags, dx, dy, 0); - return TRUE; -} - -static const KmouseProt mscProt = { - "msc", - fiveComplete, mouseValid, mscParse, 0, - 0xf8, 0x80, 0x00, 0x00, - TRUE, - IGNPAR, - 0, - 0, - CS8 | CSTOPB | CREAD | CLOCAL, - B1200, -}; - -/* - * Use logitech before ms -- they're the same except that - * logitech sometimes has a fourth byte - */ -static const KmouseProt *kmouseProts[] = { - &ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt, -}; - -#define NUM_PROT (sizeof (kmouseProts) / sizeof (kmouseProts[0])) - -static void -MouseInitProtocol (Kmouse *km) -{ - int ret; - struct termios t; - - if (km->prot->tty) - { - ret = tcgetattr (km->iob.fd, &t); - - if (ret >= 0) - { - t.c_iflag = km->prot->c_iflag; - t.c_oflag = km->prot->c_oflag; - t.c_lflag = km->prot->c_lflag; - t.c_cflag = km->prot->c_cflag; - cfsetispeed (&t, km->prot->speed); - cfsetospeed (&t, km->prot->speed); - ret = tcsetattr (km->iob.fd, TCSANOW, &t); - } - } - km->stage = MouseBroken; - km->valid = 0; - km->tested = 0; - km->invalid = 0; - km->state = km->prot->state; -} - -static void -MouseFirstProtocol (Kmouse *km, char *prot) -{ - if (prot) - { - for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++) - if (!strcmp (prot, kmouseProts[km->i_prot]->name)) - break; - if (km->i_prot == NUM_PROT) - { - int i; - ErrorF ("Unknown mouse protocol \"%s\". Pick one of:", prot); - for (i = 0; i < NUM_PROT; i++) - ErrorF (" %s", kmouseProts[i]->name); - ErrorF ("\n"); - } - else - { - km->prot = kmouseProts[km->i_prot]; - if (km->tty && !km->prot->tty) - ErrorF ("Mouse device is serial port, protocol %s is not serial protocol\n", - prot); - else if (!km->tty && km->prot->tty) - ErrorF ("Mouse device is not serial port, protocol %s is serial protocol\n", - prot); - } - } - if (!km->prot) - { - for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty; km->i_prot++) - ; - km->prot = kmouseProts[km->i_prot]; - } - MouseInitProtocol (km); -} - -static void -MouseNextProtocol (Kmouse *km) -{ - do - { - if (!km->prot) - km->i_prot = 0; - else - if (++km->i_prot == NUM_PROT) km->i_prot = 0; - km->prot = kmouseProts[km->i_prot]; - } while (km->prot->tty != km->tty); - MouseInitProtocol (km); - ErrorF ("Switching to mouse protocol \"%s\"\n", km->prot->name); -} - -static void -MouseRead (int mousePort, void *closure) -{ - KdPointerInfo *pi = closure; - Kmouse *km = pi->driverPrivate; - unsigned char event[MAX_MOUSE]; - int ne; - int c; - int i; - int timeout; - - timeout = 0; - ne = 0; - for(;;) - { - c = MouseReadByte (&km->iob, timeout); - if (c == -1) - { - if (ne) - { - km->invalid += ne + km->tested; - km->valid = 0; - km->tested = 0; - km->stage = MouseBroken; - } - break; - } - event[ne++] = c; - i = (*km->prot->Valid) (pi, event, ne); - if (i != 0) - { -#ifdef DEBUG - ErrorF ("Mouse protocol %s broken %d of %d bytes bad\n", - km->prot->name, i > 0 ? i : ne, ne); -#endif - if (i > 0 && i < ne) - { - ne -= i; - memmove (event, event + i, ne); - } - else - { - i = ne; - ne = 0; - } - km->invalid += i + km->tested; - km->valid = 0; - km->tested = 0; - if (km->stage == MouseWorking) - km->i_prot--; - km->stage = MouseBroken; - if (km->invalid > MAX_SKIP) - { - MouseNextProtocol (km); - ne = 0; - } - timeout = 0; - } - else - { - if ((*km->prot->Complete) (pi, event, ne)) - { - if ((*km->prot->Parse) (pi, event, ne)) - { - switch (km->stage) - { - case MouseBroken: -#ifdef DEBUG - ErrorF ("Mouse protocol %s seems OK\n", - km->prot->name); -#endif - /* do not zero invalid to accumulate invalid bytes */ - km->valid = 0; - km->tested = 0; - km->stage = MouseTesting; - /* fall through ... */ - case MouseTesting: - km->valid++; - km->tested += ne; - if (km->valid > MAX_VALID) - { -#ifdef DEBUG - ErrorF ("Mouse protocol %s working\n", - km->prot->name); -#endif - km->stage = MouseWorking; - km->invalid = 0; - km->tested = 0; - km->valid = 0; - if (km->prot->Init && !(*km->prot->Init) (pi)) - km->stage = MouseBroken; - } - break; - case MouseWorking: - break; - } - } - else - { - km->invalid += ne + km->tested; - km->valid = 0; - km->tested = 0; - km->stage = MouseBroken; - } - ne = 0; - timeout = 0; - } - else - timeout = MOUSE_TIMEOUT; - } - } -} - -int MouseInputType; - -char *kdefaultMouse[] = { - "/dev/input/mice", - "/dev/mouse", - "/dev/psaux", - "/dev/adbmouse", - "/dev/ttyS0", - "/dev/ttyS1", -}; - -#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0])) - -static Status -MouseInit (KdPointerInfo *pi) -{ - int i; - int fd; - Kmouse *km; - - if (!pi) - return BadImplementation; - - if (!pi->path || strcmp(pi->path, "auto") == 0) { - for (i = 0; i < NUM_DEFAULT_MOUSE; i++) { - fd = open (kdefaultMouse[i], 2); - if (fd >= 0) { - pi->path = strdup (kdefaultMouse[i]); - break; - } - } - } - else { - fd = open (pi->path, 2); - } - - if (fd < 0) - return BadMatch; - - close(fd); - - km = (Kmouse *) xalloc (sizeof (Kmouse)); - if (km) { - km->iob.avail = km->iob.used = 0; - MouseFirstProtocol(km, pi->protocol ? pi->protocol : "exps/2"); - /* MouseFirstProtocol sets state to MouseBroken for later protocol - * checks. Skip these checks if a protocol was supplied */ - if (pi->protocol) - km->state = MouseWorking; - km->i_prot = 0; - km->tty = isatty (fd); - km->iob.fd = -1; - pi->driverPrivate = km; - } - else { - close (fd); - return BadAlloc; - } - - return Success; -} - -static Status -MouseEnable (KdPointerInfo *pi) -{ - Kmouse *km; - - if (!pi || !pi->driverPrivate || !pi->path) - return BadImplementation; - - km = pi->driverPrivate; - - km->iob.fd = open(pi->path, 2); - if (km->iob.fd < 0) - return BadMatch; - - if (!KdRegisterFd (km->iob.fd, MouseRead, pi)) - { - close(km->iob.fd); - return BadAlloc; - } - - return Success; -} - -static void -MouseDisable (KdPointerInfo *pi) -{ - Kmouse *km; - if (!pi || !pi->driverPrivate) - return; - - km = pi->driverPrivate; - KdUnregisterFd (pi, km->iob.fd, TRUE); -} - -static void -MouseFini (KdPointerInfo *pi) -{ - xfree (pi->driverPrivate); - pi->driverPrivate = NULL; -} - -KdPointerDriver LinuxMouseDriver = { - "mouse", - MouseInit, - MouseEnable, - MouseDisable, - MouseFini, - NULL, -}; +/* + * Copyright © 2001 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include +#include +#include +#include "inputstr.h" +#include "scrnintstr.h" +#include "kdrive.h" + +#undef DEBUG +#undef DEBUG_BYTES +#define KBUFIO_SIZE 256 +#define MOUSE_TIMEOUT 100 + +typedef struct _kbufio { + int fd; + unsigned char buf[KBUFIO_SIZE]; + int avail; + int used; +} Kbufio; + +static Bool +MouseWaitForReadable (int fd, int timeout) +{ + fd_set set; + struct timeval tv, *tp; + int n; + CARD32 done; + + done = GetTimeInMillis () + timeout; + for (;;) + { + FD_ZERO (&set); + FD_SET (fd, &set); + if (timeout == -1) + tp = 0; + else + { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + tp = &tv; + } + n = select (fd + 1, &set, 0, 0, tp); + if (n > 0) + return TRUE; + if (n < 0 && (errno == EAGAIN || errno == EINTR)) + { + timeout = (int) (done - GetTimeInMillis ()); + if (timeout > 0) + continue; + } + break; + } + return FALSE; +} + +static int +MouseReadByte (Kbufio *b, int timeout) +{ + int n; + if (b->avail <= b->used) + { + if (timeout && !MouseWaitForReadable (b->fd, timeout)) + { +#ifdef DEBUG_BYTES + ErrorF ("\tTimeout %d\n", timeout); +#endif + return -1; + } + n = read (b->fd, b->buf, KBUFIO_SIZE); + if (n <= 0) + return -1; + b->avail = n; + b->used = 0; + } +#ifdef DEBUG_BYTES + ErrorF ("\tget %02x\n", b->buf[b->used]); +#endif + return b->buf[b->used++]; +} + +#if NOTUSED +static int +MouseFlush (Kbufio *b, char *buf, int size) +{ + CARD32 now = GetTimeInMillis (); + CARD32 done = now + 100; + int c; + int n = 0; + + while ((c = MouseReadByte (b, done - now)) != -1) + { + if (buf) + { + if (n == size) + { + memmove (buf, buf + 1, size - 1); + n--; + } + buf[n++] = c; + } + now = GetTimeInMillis (); + if ((INT32) (now - done) >= 0) + break; + } + return n; +} + +static int +MousePeekByte (Kbufio *b, int timeout) +{ + int c; + + c = MouseReadByte (b, timeout); + if (c != -1) + --b->used; + return c; +} +#endif /* NOTUSED */ + +static Bool +MouseWaitForWritable (int fd, int timeout) +{ + fd_set set; + struct timeval tv, *tp; + int n; + + FD_ZERO (&set); + FD_SET (fd, &set); + if (timeout == -1) + tp = 0; + else + { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + tp = &tv; + } + n = select (fd + 1, 0, &set, 0, tp); + if (n > 0) + return TRUE; + return FALSE; +} + +static Bool +MouseWriteByte (int fd, unsigned char c, int timeout) +{ + int ret; + +#ifdef DEBUG_BYTES + ErrorF ("\tput %02x\n", c); +#endif + for (;;) + { + ret = write (fd, &c, 1); + if (ret == 1) + return TRUE; + if (ret == 0) + return FALSE; + if (errno != EWOULDBLOCK) + return FALSE; + if (!MouseWaitForWritable (fd, timeout)) + return FALSE; + } +} + +static Bool +MouseWriteBytes (int fd, unsigned char *c, int n, int timeout) +{ + while (n--) + if (!MouseWriteByte (fd, *c++, timeout)) + return FALSE; + return TRUE; +} + +#define MAX_MOUSE 10 /* maximum length of mouse protocol */ +#define MAX_SKIP 16 /* number of error bytes before switching */ +#define MAX_VALID 4 /* number of valid packets before accepting */ + +typedef struct _kmouseProt { + char *name; + Bool (*Complete) (KdPointerInfo *pi, unsigned char *ev, int ne); + int (*Valid) (KdPointerInfo *pi, unsigned char *ev, int ne); + Bool (*Parse) (KdPointerInfo *pi, unsigned char *ev, int ne); + Bool (*Init) (KdPointerInfo *pi); + unsigned char headerMask, headerValid; + unsigned char dataMask, dataValid; + Bool tty; + unsigned int c_iflag; + unsigned int c_oflag; + unsigned int c_lflag; + unsigned int c_cflag; + unsigned int speed; + unsigned char *init; + unsigned long state; +} KmouseProt; + +typedef enum _kmouseStage { + MouseBroken, MouseTesting, MouseWorking +} KmouseStage; + +typedef struct _kmouse { + Kbufio iob; + const KmouseProt *prot; + int i_prot; + KmouseStage stage; /* protocol verification stage */ + Bool tty; /* mouse device is a tty */ + int valid; /* sequential valid events */ + int tested; /* bytes scanned during Testing phase */ + int invalid;/* total invalid bytes for this protocol */ + unsigned long state; /* private per protocol, init to prot->state */ +} Kmouse; + +static int mouseValid (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + const KmouseProt *prot = km->prot; + int i; + + for (i = 0; i < ne; i++) + if ((ev[i] & prot->headerMask) == prot->headerValid) + break; + if (i != 0) + return i; + for (i = 1; i < ne; i++) + if ((ev[i] & prot->dataMask) != prot->dataValid) + return -1; + return 0; +} + +static Bool threeComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + return ne == 3; +} + +static Bool fourComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + return ne == 4; +} + +static Bool fiveComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + return ne == 5; +} + +static Bool MouseReasonable (KdPointerInfo *pi, unsigned long flags, int dx, int dy) +{ + Kmouse *km = pi->driverPrivate; + + if (km->stage == MouseWorking) + return TRUE; + if (dx < -50 || dx > 50) + { +#ifdef DEBUG + ErrorF ("Large X %d\n", dx); +#endif + return FALSE; + } + if (dy < -50 || dy > 50) + { +#ifdef DEBUG + ErrorF ("Large Y %d\n", dy); +#endif + return FALSE; + } + return TRUE; +} + +/* + * Standard PS/2 mouse protocol + */ +static Bool ps2Parse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy, dz; + unsigned long flags; + unsigned long flagsrelease = 0; + + flags = KD_MOUSE_DELTA; + if (ev[0] & 4) + flags |= KD_BUTTON_2; + if (ev[0] & 2) + flags |= KD_BUTTON_3; + if (ev[0] & 1) + flags |= KD_BUTTON_1; + + if (ne > 3) + { + dz = (int) (signed char) ev[3]; + if (dz < 0) + { + flags |= KD_BUTTON_4; + flagsrelease = KD_BUTTON_4; + } + else if (dz > 0) + { + flags |= KD_BUTTON_5; + flagsrelease = KD_BUTTON_5; + } + } + + dx = ev[1]; + if (ev[0] & 0x10) + dx -= 256; + dy = ev[2]; + if (ev[0] & 0x20) + dy -= 256; + dy = -dy; + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + { + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + if (flagsrelease) + { + flags &= ~flagsrelease; + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + } + } + return TRUE; +} + +static Bool ps2Init (KdPointerInfo *pi); + +static const KmouseProt ps2Prot = { + "ps/2", + threeComplete, mouseValid, ps2Parse, ps2Init, + 0x08, 0x08, 0x00, 0x00, + FALSE +}; + +static const KmouseProt imps2Prot = { + "imps/2", + fourComplete, mouseValid, ps2Parse, ps2Init, + 0x08, 0x08, 0x00, 0x00, + FALSE +}; + +static const KmouseProt exps2Prot = { + "exps/2", + fourComplete, mouseValid, ps2Parse, ps2Init, + 0x08, 0x08, 0x00, 0x00, + FALSE +}; + +/* + * Once the mouse is known to speak ps/2 protocol, go and find out + * what advanced capabilities it has and turn them on + */ + +/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */ + +/* aux device commands (sent to KBD_DATA_PORT) */ +#define PSMC_SET_SCALING11 0x00e6 +#define PSMC_SET_SCALING21 0x00e7 +#define PSMC_SET_RESOLUTION 0x00e8 +#define PSMC_SEND_DEV_STATUS 0x00e9 +#define PSMC_SET_STREAM_MODE 0x00ea +#define PSMC_SEND_DEV_DATA 0x00eb +#define PSMC_SET_REMOTE_MODE 0x00f0 +#define PSMC_SEND_DEV_ID 0x00f2 +#define PSMC_SET_SAMPLING_RATE 0x00f3 +#define PSMC_ENABLE_DEV 0x00f4 +#define PSMC_DISABLE_DEV 0x00f5 +#define PSMC_SET_DEFAULTS 0x00f6 +#define PSMC_RESET_DEV 0x00ff + +/* PSMC_SET_RESOLUTION argument */ +#define PSMD_RES_LOW 0 /* typically 25ppi */ +#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */ +#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */ +#define PSMD_RES_HIGH 3 /* typically 200ppi */ +#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH + +/* PSMC_SET_SAMPLING_RATE */ +#define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */ + +/* aux device ID */ +#define PSM_MOUSE_ID 0 +#define PSM_BALLPOINT_ID 2 +#define PSM_INTELLI_ID 3 +#define PSM_EXPLORER_ID 4 +#define PSM_4DMOUSE_ID 6 +#define PSM_4DPLUS_ID 8 + +static unsigned char ps2_init[] = { + PSMC_ENABLE_DEV, + 0, +}; + +#define NINIT_PS2 1 + +static unsigned char wheel_3button_init[] = { + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 100, + PSMC_SET_SAMPLING_RATE, 80, + PSMC_SEND_DEV_ID, + 0, +}; + +#define NINIT_IMPS2 4 + +static unsigned char wheel_5button_init[] = { + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 100, + PSMC_SET_SAMPLING_RATE, 80, + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 80, + PSMC_SEND_DEV_ID, + 0 +}; + +#define NINIT_EXPS2 7 + +static unsigned char intelli_init[] = { + PSMC_SET_SAMPLING_RATE, 200, + PSMC_SET_SAMPLING_RATE, 100, + PSMC_SET_SAMPLING_RATE, 80, + 0 +}; + +#define NINIT_INTELLI 3 + +static int +ps2SkipInit (KdPointerInfo *pi, int ninit, Bool ret_next) +{ + Kmouse *km = pi->driverPrivate; + int c = -1; + int skipping; + Bool waiting; + + skipping = 0; + waiting = FALSE; + while (ninit || ret_next) + { + c = MouseReadByte (&km->iob, MOUSE_TIMEOUT); + if (c == -1) + break; + /* look for ACK */ + if (c == 0xfa) + { + ninit--; + if (ret_next) + waiting = TRUE; + } + /* look for packet start -- not the response */ + else if ((c & 0x08) == 0x08) + waiting = FALSE; + else if (waiting) + break; + } + return c; +} + +static Bool +ps2Init (KdPointerInfo *pi) +{ + Kmouse *km = pi->driverPrivate; + int skipping; + Bool waiting; + int id; + unsigned char *init; + int ninit; + + /* Send Intellimouse initialization sequence */ + MouseWriteBytes (km->iob.fd, intelli_init, strlen ((char *) intelli_init), 100); + /* + * Send ID command + */ + if (!MouseWriteByte (km->iob.fd, PSMC_SEND_DEV_ID, 100)) + return FALSE; + skipping = 0; + waiting = FALSE; + id = ps2SkipInit (pi, 0, TRUE); + switch (id) { + case 3: + init = wheel_3button_init; + ninit = NINIT_IMPS2; + km->prot = &imps2Prot; + break; + case 4: + init = wheel_5button_init; + ninit = NINIT_EXPS2; + km->prot = &exps2Prot; + break; + default: + init = ps2_init; + ninit = NINIT_PS2; + km->prot = &ps2Prot; + break; + } + if (init) + MouseWriteBytes (km->iob.fd, init, strlen ((char *) init), 100); + /* + * Flush out the available data to eliminate responses to the + * initialization string. Make sure any partial event is + * skipped + */ + (void) ps2SkipInit (pi, ninit, FALSE); + return TRUE; +} + +static Bool busParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + dx = (signed char) ev[1]; + dy = -(signed char) ev[2]; + if ((ev[0] & 4) == 0) + flags |= KD_BUTTON_1; + if ((ev[0] & 2) == 0) + flags |= KD_BUTTON_2; + if ((ev[0] & 1) == 0) + flags |= KD_BUTTON_3; + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt busProt = { + "bus", + threeComplete, mouseValid, busParse, 0, + 0xf8, 0x00, 0x00, 0x00, + FALSE +}; + +/* + * Standard MS serial protocol, three bytes + */ + +static Bool msParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + + if (ev[0] & 0x20) + flags |= KD_BUTTON_1; + if (ev[0] & 0x10) + flags |= KD_BUTTON_3; + + dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); + dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt msProt = { + "ms", + threeComplete, mouseValid, msParse, 0, + 0xc0, 0x40, 0xc0, 0x00, + TRUE, + IGNPAR, + 0, + 0, + CS7 | CSTOPB | CREAD | CLOCAL, + B1200, +}; + +/* + * Logitech mice send 3 or 4 bytes, the only way to tell is to look at the + * first byte of a synchronized protocol stream and see if it's got + * any bits turned on that can't occur in that fourth byte + */ +static Bool logiComplete (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + + if ((ev[0] & 0x40) == 0x40) + return ne == 3; + if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0) + return ne == 1; + return FALSE; +} + +static int logiValid (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + const KmouseProt *prot = km->prot; + int i; + + for (i = 0; i < ne; i++) + { + if ((ev[i] & 0x40) == 0x40) + break; + if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0) + break; + } + if (i != 0) + return i; + for (i = 1; i < ne; i++) + if ((ev[i] & prot->dataMask) != prot->dataValid) + return -1; + return 0; +} + +static Bool logiParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + + if (ne == 3) + { + if (ev[0] & 0x20) + flags |= KD_BUTTON_1; + if (ev[0] & 0x10) + flags |= KD_BUTTON_3; + + dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); + dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); + flags |= km->state & KD_BUTTON_2; + } + else + { + if (ev[0] & 0x20) + flags |= KD_BUTTON_2; + dx = 0; + dy = 0; + flags |= km->state & (KD_BUTTON_1|KD_BUTTON_3); + } + + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt logiProt = { + "logitech", + logiComplete, logiValid, logiParse, 0, + 0xc0, 0x40, 0xc0, 0x00, + TRUE, + IGNPAR, + 0, + 0, + CS7 | CSTOPB | CREAD | CLOCAL, + B1200, +}; + +/* + * Mouse systems protocol, 5 bytes + */ +static Bool mscParse (KdPointerInfo *pi, unsigned char *ev, int ne) +{ + Kmouse *km = pi->driverPrivate; + int dx, dy; + unsigned long flags; + + flags = KD_MOUSE_DELTA; + + if (!(ev[0] & 0x4)) + flags |= KD_BUTTON_1; + if (!(ev[0] & 0x2)) + flags |= KD_BUTTON_2; + if (!(ev[0] & 0x1)) + flags |= KD_BUTTON_3; + dx = (signed char)(ev[1]) + (signed char)(ev[3]); + dy = - ((signed char)(ev[2]) + (signed char)(ev[4])); + + if (!MouseReasonable (pi, flags, dx, dy)) + return FALSE; + if (km->stage == MouseWorking) + KdEnqueuePointerEvent (pi, flags, dx, dy, 0); + return TRUE; +} + +static const KmouseProt mscProt = { + "msc", + fiveComplete, mouseValid, mscParse, 0, + 0xf8, 0x80, 0x00, 0x00, + TRUE, + IGNPAR, + 0, + 0, + CS8 | CSTOPB | CREAD | CLOCAL, + B1200, +}; + +/* + * Use logitech before ms -- they're the same except that + * logitech sometimes has a fourth byte + */ +static const KmouseProt *kmouseProts[] = { + &ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt, +}; + +#define NUM_PROT (sizeof (kmouseProts) / sizeof (kmouseProts[0])) + +static void +MouseInitProtocol (Kmouse *km) +{ + int ret; + struct termios t; + + if (km->prot->tty) + { + ret = tcgetattr (km->iob.fd, &t); + + if (ret >= 0) + { + t.c_iflag = km->prot->c_iflag; + t.c_oflag = km->prot->c_oflag; + t.c_lflag = km->prot->c_lflag; + t.c_cflag = km->prot->c_cflag; + cfsetispeed (&t, km->prot->speed); + cfsetospeed (&t, km->prot->speed); + ret = tcsetattr (km->iob.fd, TCSANOW, &t); + } + } + km->stage = MouseBroken; + km->valid = 0; + km->tested = 0; + km->invalid = 0; + km->state = km->prot->state; +} + +static void +MouseFirstProtocol (Kmouse *km, char *prot) +{ + if (prot) + { + for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++) + if (!strcmp (prot, kmouseProts[km->i_prot]->name)) + break; + if (km->i_prot == NUM_PROT) + { + int i; + ErrorF ("Unknown mouse protocol \"%s\". Pick one of:", prot); + for (i = 0; i < NUM_PROT; i++) + ErrorF (" %s", kmouseProts[i]->name); + ErrorF ("\n"); + } + else + { + km->prot = kmouseProts[km->i_prot]; + if (km->tty && !km->prot->tty) + ErrorF ("Mouse device is serial port, protocol %s is not serial protocol\n", + prot); + else if (!km->tty && km->prot->tty) + ErrorF ("Mouse device is not serial port, protocol %s is serial protocol\n", + prot); + } + } + if (!km->prot) + { + for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty; km->i_prot++) + ; + km->prot = kmouseProts[km->i_prot]; + } + MouseInitProtocol (km); +} + +static void +MouseNextProtocol (Kmouse *km) +{ + do + { + if (!km->prot) + km->i_prot = 0; + else + if (++km->i_prot == NUM_PROT) km->i_prot = 0; + km->prot = kmouseProts[km->i_prot]; + } while (km->prot->tty != km->tty); + MouseInitProtocol (km); + ErrorF ("Switching to mouse protocol \"%s\"\n", km->prot->name); +} + +static void +MouseRead (int mousePort, void *closure) +{ + KdPointerInfo *pi = closure; + Kmouse *km = pi->driverPrivate; + unsigned char event[MAX_MOUSE]; + int ne; + int c; + int i; + int timeout; + + timeout = 0; + ne = 0; + for(;;) + { + c = MouseReadByte (&km->iob, timeout); + if (c == -1) + { + if (ne) + { + km->invalid += ne + km->tested; + km->valid = 0; + km->tested = 0; + km->stage = MouseBroken; + } + break; + } + event[ne++] = c; + i = (*km->prot->Valid) (pi, event, ne); + if (i != 0) + { +#ifdef DEBUG + ErrorF ("Mouse protocol %s broken %d of %d bytes bad\n", + km->prot->name, i > 0 ? i : ne, ne); +#endif + if (i > 0 && i < ne) + { + ne -= i; + memmove (event, event + i, ne); + } + else + { + i = ne; + ne = 0; + } + km->invalid += i + km->tested; + km->valid = 0; + km->tested = 0; + if (km->stage == MouseWorking) + km->i_prot--; + km->stage = MouseBroken; + if (km->invalid > MAX_SKIP) + { + MouseNextProtocol (km); + ne = 0; + } + timeout = 0; + } + else + { + if ((*km->prot->Complete) (pi, event, ne)) + { + if ((*km->prot->Parse) (pi, event, ne)) + { + switch (km->stage) + { + case MouseBroken: +#ifdef DEBUG + ErrorF ("Mouse protocol %s seems OK\n", + km->prot->name); +#endif + /* do not zero invalid to accumulate invalid bytes */ + km->valid = 0; + km->tested = 0; + km->stage = MouseTesting; + /* fall through ... */ + case MouseTesting: + km->valid++; + km->tested += ne; + if (km->valid > MAX_VALID) + { +#ifdef DEBUG + ErrorF ("Mouse protocol %s working\n", + km->prot->name); +#endif + km->stage = MouseWorking; + km->invalid = 0; + km->tested = 0; + km->valid = 0; + if (km->prot->Init && !(*km->prot->Init) (pi)) + km->stage = MouseBroken; + } + break; + case MouseWorking: + break; + } + } + else + { + km->invalid += ne + km->tested; + km->valid = 0; + km->tested = 0; + km->stage = MouseBroken; + } + ne = 0; + timeout = 0; + } + else + timeout = MOUSE_TIMEOUT; + } + } +} + +int MouseInputType; + +char *kdefaultMouse[] = { + "/dev/input/mice", + "/dev/mouse", + "/dev/psaux", + "/dev/adbmouse", + "/dev/ttyS0", + "/dev/ttyS1", +}; + +#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0])) + +static Status +MouseInit (KdPointerInfo *pi) +{ + int i; + int fd; + Kmouse *km; + + if (!pi) + return BadImplementation; + + if (!pi->path || strcmp(pi->path, "auto") == 0) { + for (i = 0; i < NUM_DEFAULT_MOUSE; i++) { + fd = open (kdefaultMouse[i], 2); + if (fd >= 0) { + pi->path = strdup (kdefaultMouse[i]); + break; + } + } + } + else { + fd = open (pi->path, 2); + } + + if (fd < 0) + return BadMatch; + + close(fd); + + km = (Kmouse *) malloc(sizeof (Kmouse)); + if (km) { + km->iob.avail = km->iob.used = 0; + MouseFirstProtocol(km, pi->protocol ? pi->protocol : "exps/2"); + /* MouseFirstProtocol sets state to MouseBroken for later protocol + * checks. Skip these checks if a protocol was supplied */ + if (pi->protocol) + km->state = MouseWorking; + km->i_prot = 0; + km->tty = isatty (fd); + km->iob.fd = -1; + pi->driverPrivate = km; + } + else { + close (fd); + return BadAlloc; + } + + return Success; +} + +static Status +MouseEnable (KdPointerInfo *pi) +{ + Kmouse *km; + + if (!pi || !pi->driverPrivate || !pi->path) + return BadImplementation; + + km = pi->driverPrivate; + + km->iob.fd = open(pi->path, 2); + if (km->iob.fd < 0) + return BadMatch; + + if (!KdRegisterFd (km->iob.fd, MouseRead, pi)) + { + close(km->iob.fd); + return BadAlloc; + } + + return Success; +} + +static void +MouseDisable (KdPointerInfo *pi) +{ + Kmouse *km; + if (!pi || !pi->driverPrivate) + return; + + km = pi->driverPrivate; + KdUnregisterFd (pi, km->iob.fd, TRUE); +} + +static void +MouseFini (KdPointerInfo *pi) +{ + free(pi->driverPrivate); + pi->driverPrivate = NULL; +} + +KdPointerDriver LinuxMouseDriver = { + "mouse", + MouseInit, + MouseEnable, + MouseDisable, + MouseFini, + NULL, +}; diff --git a/xorg-server/hw/kdrive/linux/tslib.c b/xorg-server/hw/kdrive/linux/tslib.c index 322ccc7d5..ee0f779f3 100644 --- a/xorg-server/hw/kdrive/linux/tslib.c +++ b/xorg-server/hw/kdrive/linux/tslib.c @@ -1,190 +1,190 @@ -/* - * TSLIB based touchscreen driver for KDrive - * Porting to new input API and event queueing by Daniel Stone. - * Derived from ts.c by Keith Packard - * Derived from ps2.c by Jim Gettys - * - * Copyright © 1999 Keith Packard - * Copyright © 2000 Compaq Computer Corporation - * Copyright © 2002 MontaVista Software Inc. - * Copyright © 2005 OpenedHand Ltd. - * Copyright © 2006 Nokia Corporation - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of the authors and/or copyright holders - * not be used in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. The authors and/or - * copyright holders make no representations about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - * - * THE AUTHORS AND/OR COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD - * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS, IN NO EVENT SHALL THE AUTHORS AND/OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - - -#ifdef HAVE_KDRIVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include "inputstr.h" -#include "scrnintstr.h" -#include "kdrive.h" -#include -#include -#include -#include - -struct TslibPrivate { - int fd; - int lastx, lasty; - struct tsdev *tsDev; - void (*raw_event_hook)(int x, int y, int pressure, void *closure); - void *raw_event_closure; - int phys_screen; -}; - - -static void -TsRead (int fd, void *closure) -{ - KdPointerInfo *pi = closure; - struct TslibPrivate *private = pi->driverPrivate; - struct ts_sample event; - long x = 0, y = 0; - unsigned long flags; - - if (private->raw_event_hook) { - while (ts_read_raw(private->tsDev, &event, 1) == 1) - private->raw_event_hook (event.x, event.y, event.pressure, - private->raw_event_closure); - return; - } - - while (ts_read(private->tsDev, &event, 1) == 1) { - if (event.pressure) { - flags = KD_BUTTON_1; - - /* - * Here we test for the touch screen driver actually being on the - * touch screen, if it is we send absolute coordinates. If not, - * then we send delta's so that we can track the entire vga screen. - */ - if (KdCurScreen == private->phys_screen) { - x = event.x; - y = event.y; - } else { - flags |= KD_MOUSE_DELTA; - if ((private->lastx == 0) || (private->lasty == 0)) { - x = event.x; - y = event.y; - } else { - x = event.x - private->lastx; - y = event.y - private->lasty; - } - } - private->lastx = event.x; - private->lasty = event.y; - } else { - flags = 0; - x = private->lastx; - y = private->lasty; - } - - KdEnqueuePointerEvent (pi, flags, x, y, event.pressure); - } -} - -static Status -TslibEnable (KdPointerInfo *pi) -{ - struct TslibPrivate *private = pi->driverPrivate; - - private->raw_event_hook = NULL; - private->raw_event_closure = NULL; - if (!pi->path) { - pi->path = strdup("/dev/input/touchscreen0"); - ErrorF("[tslib/TslibEnable] no device path given, trying %s\n", pi->path); - } - private->tsDev = ts_open(pi->path, 0); - private->fd = ts_fd(private->tsDev); - if (!private->tsDev || ts_config(private->tsDev) || private->fd < 0) { - ErrorF("[tslib/TslibEnable] failed to open %s\n", pi->path); - if (private->fd >= 0) - close(private->fd); - return BadAlloc; - } - - KdRegisterFd(private->fd, TsRead, pi); - - return Success; -} - - -static void -TslibDisable (KdPointerInfo *pi) -{ - struct TslibPrivate *private = pi->driverPrivate; - - if (private->fd) - KdUnregisterFd(pi, private->fd, TRUE); - - if (private->tsDev) - ts_close(private->tsDev); - - private->fd = 0; - private->tsDev = NULL; -} - - -static Status -TslibInit (KdPointerInfo *pi) -{ - struct TslibPrivate *private = NULL; - - if (!pi || !pi->dixdev) - return !Success; - - pi->driverPrivate = (struct TslibPrivate *) - xcalloc(sizeof(struct TslibPrivate), 1); - if (!pi->driverPrivate) - return !Success; - - private = pi->driverPrivate; - /* hacktastic */ - private->phys_screen = 0; - pi->nAxes = 3; - pi->name = strdup("Touchscreen"); - pi->inputClass = KD_TOUCHSCREEN; - - return Success; -} - - -static void -TslibFini (KdPointerInfo *pi) -{ - xfree(pi->driverPrivate); - pi->driverPrivate = NULL; -} - - -KdPointerDriver TsDriver = { - "tslib", - TslibInit, - TslibEnable, - TslibDisable, - TslibFini, - NULL, -}; +/* + * TSLIB based touchscreen driver for KDrive + * Porting to new input API and event queueing by Daniel Stone. + * Derived from ts.c by Keith Packard + * Derived from ps2.c by Jim Gettys + * + * Copyright © 1999 Keith Packard + * Copyright © 2000 Compaq Computer Corporation + * Copyright © 2002 MontaVista Software Inc. + * Copyright © 2005 OpenedHand Ltd. + * Copyright © 2006 Nokia Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the authors and/or copyright holders + * not be used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. The authors and/or + * copyright holders make no representations about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * THE AUTHORS AND/OR COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD + * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS AND/OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#ifdef HAVE_KDRIVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include "inputstr.h" +#include "scrnintstr.h" +#include "kdrive.h" +#include +#include +#include +#include + +struct TslibPrivate { + int fd; + int lastx, lasty; + struct tsdev *tsDev; + void (*raw_event_hook)(int x, int y, int pressure, void *closure); + void *raw_event_closure; + int phys_screen; +}; + + +static void +TsRead (int fd, void *closure) +{ + KdPointerInfo *pi = closure; + struct TslibPrivate *private = pi->driverPrivate; + struct ts_sample event; + long x = 0, y = 0; + unsigned long flags; + + if (private->raw_event_hook) { + while (ts_read_raw(private->tsDev, &event, 1) == 1) + private->raw_event_hook (event.x, event.y, event.pressure, + private->raw_event_closure); + return; + } + + while (ts_read(private->tsDev, &event, 1) == 1) { + if (event.pressure) { + flags = KD_BUTTON_1; + + /* + * Here we test for the touch screen driver actually being on the + * touch screen, if it is we send absolute coordinates. If not, + * then we send delta's so that we can track the entire vga screen. + */ + if (KdCurScreen == private->phys_screen) { + x = event.x; + y = event.y; + } else { + flags |= KD_MOUSE_DELTA; + if ((private->lastx == 0) || (private->lasty == 0)) { + x = event.x; + y = event.y; + } else { + x = event.x - private->lastx; + y = event.y - private->lasty; + } + } + private->lastx = event.x; + private->lasty = event.y; + } else { + flags = 0; + x = private->lastx; + y = private->lasty; + } + + KdEnqueuePointerEvent (pi, flags, x, y, event.pressure); + } +} + +static Status +TslibEnable (KdPointerInfo *pi) +{ + struct TslibPrivate *private = pi->driverPrivate; + + private->raw_event_hook = NULL; + private->raw_event_closure = NULL; + if (!pi->path) { + pi->path = strdup("/dev/input/touchscreen0"); + ErrorF("[tslib/TslibEnable] no device path given, trying %s\n", pi->path); + } + private->tsDev = ts_open(pi->path, 0); + private->fd = ts_fd(private->tsDev); + if (!private->tsDev || ts_config(private->tsDev) || private->fd < 0) { + ErrorF("[tslib/TslibEnable] failed to open %s\n", pi->path); + if (private->fd >= 0) + close(private->fd); + return BadAlloc; + } + + KdRegisterFd(private->fd, TsRead, pi); + + return Success; +} + + +static void +TslibDisable (KdPointerInfo *pi) +{ + struct TslibPrivate *private = pi->driverPrivate; + + if (private->fd) + KdUnregisterFd(pi, private->fd, TRUE); + + if (private->tsDev) + ts_close(private->tsDev); + + private->fd = 0; + private->tsDev = NULL; +} + + +static Status +TslibInit (KdPointerInfo *pi) +{ + struct TslibPrivate *private = NULL; + + if (!pi || !pi->dixdev) + return !Success; + + pi->driverPrivate = (struct TslibPrivate *) + calloc(sizeof(struct TslibPrivate), 1); + if (!pi->driverPrivate) + return !Success; + + private = pi->driverPrivate; + /* hacktastic */ + private->phys_screen = 0; + pi->nAxes = 3; + pi->name = strdup("Touchscreen"); + pi->inputClass = KD_TOUCHSCREEN; + + return Success; +} + + +static void +TslibFini (KdPointerInfo *pi) +{ + free(pi->driverPrivate); + pi->driverPrivate = NULL; +} + + +KdPointerDriver TsDriver = { + "tslib", + TslibInit, + TslibEnable, + TslibDisable, + TslibFini, + NULL, +}; diff --git a/xorg-server/hw/kdrive/src/kcmap.c b/xorg-server/hw/kdrive/src/kcmap.c index 40697e091..127c7a078 100644 --- a/xorg-server/hw/kdrive/src/kcmap.c +++ b/xorg-server/hw/kdrive/src/kcmap.c @@ -1,246 +1,246 @@ -/* - * Copyright © 1999 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "kdrive.h" - -/* - * Put the entire colormap into the DAC - */ - -void -KdSetColormap (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - ColormapPtr pCmap = pScreenPriv->pInstalledmap; - Pixel pixels[KD_MAX_PSEUDO_SIZE]; - xrgb colors[KD_MAX_PSEUDO_SIZE]; - xColorItem defs[KD_MAX_PSEUDO_SIZE]; - int i; - - if (!pScreenPriv->card->cfuncs->putColors) - return; - if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH) - return; - - if (!pScreenPriv->enabled) - return; - - if (!pCmap) - return; - - /* - * Make DIX convert pixels into RGB values -- this handles - * true/direct as well as pseudo/static visuals - */ - - for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) - pixels[i] = i; - - QueryColors (pCmap, (1 << pScreenPriv->screen->fb.depth), pixels, colors); - - for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) - { - defs[i].pixel = i; - defs[i].red = colors[i].red; - defs[i].green = colors[i].green; - defs[i].blue = colors[i].blue; - defs[i].flags = DoRed|DoGreen|DoBlue; - } - - (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, - (1 << pScreenPriv->screen->fb.depth), - defs); - - /* recolor hardware cursor */ - if (pScreenPriv->card->cfuncs->recolorCursor) - (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, 0, 0); -} - -/* - * When the hardware is enabled, save the hardware colors and store - * the current colormap - */ -void -KdEnableColormap (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - int i; - - if (!pScreenPriv->card->cfuncs->putColors) - return; - - if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) - { - for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) - pScreenPriv->systemPalette[i].pixel = i; - (*pScreenPriv->card->cfuncs->getColors) (pScreen, - (1 << pScreenPriv->screen->fb.depth), - pScreenPriv->systemPalette); - } - KdSetColormap (pScreen); -} - -void -KdDisableColormap (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - - if (!pScreenPriv->card->cfuncs->putColors) - return; - - if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) - { - (*pScreenPriv->card->cfuncs->putColors) (pScreen, - (1 << pScreenPriv->screen->fb.depth), - pScreenPriv->systemPalette); - } -} - -/* - * KdInstallColormap - * - * This function is called when the server receives a request to install a - * colormap or when the server needs to install one on its own, like when - * there's no window manager running and the user has moved the pointer over - * an X client window. It needs to build an identity Windows palette for the - * colormap and realize it into the Windows system palette. - */ -void -KdInstallColormap (ColormapPtr pCmap) -{ - KdScreenPriv(pCmap->pScreen); - - if (pCmap == pScreenPriv->pInstalledmap) - return; - - /* Tell X clients that the installed colormap is going away. */ - if (pScreenPriv->pInstalledmap) - WalkTree(pScreenPriv->pInstalledmap->pScreen, TellLostMap, - (pointer) &(pScreenPriv->pInstalledmap->mid)); - - /* Take note of the new installed colorscreen-> */ - pScreenPriv->pInstalledmap = pCmap; - - KdSetColormap (pCmap->pScreen); - - /* Tell X clients of the new colormap */ - WalkTree(pCmap->pScreen, TellGainedMap, (pointer) &(pCmap->mid)); -} - -/* - * KdUninstallColormap - * - * This function uninstalls a colormap by either installing - * the default X colormap or erasing the installed colormap pointer. - * The default X colormap itself cannot be uninstalled. - */ -void -KdUninstallColormap (ColormapPtr pCmap) -{ - KdScreenPriv(pCmap->pScreen); - Colormap defMapID; - ColormapPtr defMap; - - /* ignore if not installed */ - if (pCmap != pScreenPriv->pInstalledmap) - return; - - /* ignore attempts to uninstall default colormap */ - defMapID = pCmap->pScreen->defColormap; - if ((Colormap) pCmap->mid == defMapID) - return; - - /* install default */ - dixLookupResourceByType((pointer *)&defMap, defMapID, RT_COLORMAP, - serverClient, DixInstallAccess); - if (defMap) - (*pCmap->pScreen->InstallColormap)(defMap); - else - { - /* uninstall and clear colormap pointer */ - WalkTree(pCmap->pScreen, TellLostMap, - (pointer) &(pCmap->mid)); - pScreenPriv->pInstalledmap = 0; - } -} - -int -KdListInstalledColormaps (ScreenPtr pScreen, Colormap *pCmaps) -{ - KdScreenPriv(pScreen); - int n = 0; - - if (pScreenPriv->pInstalledmap) - { - *pCmaps++ = pScreenPriv->pInstalledmap->mid; - n++; - } - return n; -} - -/* - * KdStoreColors - * - * This function is called whenever the server receives a request to store - * color values into one or more entries in the currently installed X - * colormap; it can be either the default colormap or a private colorscreen-> - */ -void -KdStoreColors (ColormapPtr pCmap, int ndef, xColorItem *pdefs) -{ - KdScreenPriv(pCmap->pScreen); - VisualPtr pVisual; - xColorItem expanddefs[KD_MAX_PSEUDO_SIZE]; - - if (pCmap != pScreenPriv->pInstalledmap) - return; - - if (!pScreenPriv->card->cfuncs->putColors) - return; - - if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH) - return; - - if (!pScreenPriv->enabled) - return; - - /* Check for DirectColor or TrueColor being simulated on a PseudoColor device. */ - pVisual = pCmap->pVisual; - if ((pVisual->class | DynamicClass) == DirectColor) - { - /* - * Expand DirectColor or TrueColor color values into a PseudoColor - * format. Defer to the Color Framebuffer (CFB) code to do that. - */ - ndef = fbExpandDirectColors(pCmap, ndef, pdefs, expanddefs); - pdefs = expanddefs; - } - - (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, ndef, pdefs); - - /* recolor hardware cursor */ - if (pScreenPriv->card->cfuncs->recolorCursor) - (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, ndef, pdefs); -} +/* + * Copyright © 1999 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "kdrive.h" + +/* + * Put the entire colormap into the DAC + */ + +void +KdSetColormap (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ColormapPtr pCmap = pScreenPriv->pInstalledmap; + Pixel pixels[KD_MAX_PSEUDO_SIZE]; + xrgb colors[KD_MAX_PSEUDO_SIZE]; + xColorItem defs[KD_MAX_PSEUDO_SIZE]; + int i; + + if (!pScreenPriv->card->cfuncs->putColors) + return; + if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH) + return; + + if (!pScreenPriv->enabled) + return; + + if (!pCmap) + return; + + /* + * Make DIX convert pixels into RGB values -- this handles + * true/direct as well as pseudo/static visuals + */ + + for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) + pixels[i] = i; + + QueryColors (pCmap, (1 << pScreenPriv->screen->fb.depth), pixels, colors, serverClient); + + for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) + { + defs[i].pixel = i; + defs[i].red = colors[i].red; + defs[i].green = colors[i].green; + defs[i].blue = colors[i].blue; + defs[i].flags = DoRed|DoGreen|DoBlue; + } + + (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, + (1 << pScreenPriv->screen->fb.depth), + defs); + + /* recolor hardware cursor */ + if (pScreenPriv->card->cfuncs->recolorCursor) + (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, 0, 0); +} + +/* + * When the hardware is enabled, save the hardware colors and store + * the current colormap + */ +void +KdEnableColormap (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + int i; + + if (!pScreenPriv->card->cfuncs->putColors) + return; + + if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) + { + for (i = 0; i < (1 << pScreenPriv->screen->fb.depth); i++) + pScreenPriv->systemPalette[i].pixel = i; + (*pScreenPriv->card->cfuncs->getColors) (pScreen, + (1 << pScreenPriv->screen->fb.depth), + pScreenPriv->systemPalette); + } + KdSetColormap (pScreen); +} + +void +KdDisableColormap (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + + if (!pScreenPriv->card->cfuncs->putColors) + return; + + if (pScreenPriv->screen->fb.depth <= KD_MAX_PSEUDO_DEPTH) + { + (*pScreenPriv->card->cfuncs->putColors) (pScreen, + (1 << pScreenPriv->screen->fb.depth), + pScreenPriv->systemPalette); + } +} + +/* + * KdInstallColormap + * + * This function is called when the server receives a request to install a + * colormap or when the server needs to install one on its own, like when + * there's no window manager running and the user has moved the pointer over + * an X client window. It needs to build an identity Windows palette for the + * colormap and realize it into the Windows system palette. + */ +void +KdInstallColormap (ColormapPtr pCmap) +{ + KdScreenPriv(pCmap->pScreen); + + if (pCmap == pScreenPriv->pInstalledmap) + return; + + /* Tell X clients that the installed colormap is going away. */ + if (pScreenPriv->pInstalledmap) + WalkTree(pScreenPriv->pInstalledmap->pScreen, TellLostMap, + (pointer) &(pScreenPriv->pInstalledmap->mid)); + + /* Take note of the new installed colorscreen-> */ + pScreenPriv->pInstalledmap = pCmap; + + KdSetColormap (pCmap->pScreen); + + /* Tell X clients of the new colormap */ + WalkTree(pCmap->pScreen, TellGainedMap, (pointer) &(pCmap->mid)); +} + +/* + * KdUninstallColormap + * + * This function uninstalls a colormap by either installing + * the default X colormap or erasing the installed colormap pointer. + * The default X colormap itself cannot be uninstalled. + */ +void +KdUninstallColormap (ColormapPtr pCmap) +{ + KdScreenPriv(pCmap->pScreen); + Colormap defMapID; + ColormapPtr defMap; + + /* ignore if not installed */ + if (pCmap != pScreenPriv->pInstalledmap) + return; + + /* ignore attempts to uninstall default colormap */ + defMapID = pCmap->pScreen->defColormap; + if ((Colormap) pCmap->mid == defMapID) + return; + + /* install default */ + dixLookupResourceByType((pointer *)&defMap, defMapID, RT_COLORMAP, + serverClient, DixInstallAccess); + if (defMap) + (*pCmap->pScreen->InstallColormap)(defMap); + else + { + /* uninstall and clear colormap pointer */ + WalkTree(pCmap->pScreen, TellLostMap, + (pointer) &(pCmap->mid)); + pScreenPriv->pInstalledmap = 0; + } +} + +int +KdListInstalledColormaps (ScreenPtr pScreen, Colormap *pCmaps) +{ + KdScreenPriv(pScreen); + int n = 0; + + if (pScreenPriv->pInstalledmap) + { + *pCmaps++ = pScreenPriv->pInstalledmap->mid; + n++; + } + return n; +} + +/* + * KdStoreColors + * + * This function is called whenever the server receives a request to store + * color values into one or more entries in the currently installed X + * colormap; it can be either the default colormap or a private colorscreen-> + */ +void +KdStoreColors (ColormapPtr pCmap, int ndef, xColorItem *pdefs) +{ + KdScreenPriv(pCmap->pScreen); + VisualPtr pVisual; + xColorItem expanddefs[KD_MAX_PSEUDO_SIZE]; + + if (pCmap != pScreenPriv->pInstalledmap) + return; + + if (!pScreenPriv->card->cfuncs->putColors) + return; + + if (pScreenPriv->screen->fb.depth > KD_MAX_PSEUDO_DEPTH) + return; + + if (!pScreenPriv->enabled) + return; + + /* Check for DirectColor or TrueColor being simulated on a PseudoColor device. */ + pVisual = pCmap->pVisual; + if ((pVisual->class | DynamicClass) == DirectColor) + { + /* + * Expand DirectColor or TrueColor color values into a PseudoColor + * format. Defer to the Color Framebuffer (CFB) code to do that. + */ + ndef = fbExpandDirectColors(pCmap, ndef, pdefs, expanddefs); + pdefs = expanddefs; + } + + (*pScreenPriv->card->cfuncs->putColors) (pCmap->pScreen, ndef, pdefs); + + /* recolor hardware cursor */ + if (pScreenPriv->card->cfuncs->recolorCursor) + (*pScreenPriv->card->cfuncs->recolorCursor) (pCmap->pScreen, ndef, pdefs); +} diff --git a/xorg-server/hw/kdrive/src/kdrive.c b/xorg-server/hw/kdrive/src/kdrive.c index 765bd0ea7..d1f00fc69 100644 --- a/xorg-server/hw/kdrive/src/kdrive.c +++ b/xorg-server/hw/kdrive/src/kdrive.c @@ -1,1283 +1,1283 @@ -/* - * Copyright © 1999 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "kdrive.h" -#include -#include -#include "privates.h" -#ifdef RANDR -#include -#endif - -#ifdef XV -#include "kxv.h" -#endif - -#ifdef DPMSExtension -#include "dpmsproc.h" -#endif - -#ifdef HAVE_EXECINFO_H -#include -#endif - -#include - -typedef struct _kdDepths { - CARD8 depth; - CARD8 bpp; -} KdDepths; - -KdDepths kdDepths[] = { - { 1, 1 }, - { 4, 4 }, - { 8, 8 }, - { 15, 16 }, - { 16, 16 }, - { 24, 32 }, - { 32, 32 } -}; - -#define NUM_KD_DEPTHS (sizeof (kdDepths) / sizeof (kdDepths[0])) - -#define KD_DEFAULT_BUTTONS 5 - -static int kdScreenPrivateKeyIndex; -DevPrivateKey kdScreenPrivateKey = &kdScreenPrivateKeyIndex; -unsigned long kdGeneration; - -Bool kdVideoTest; -unsigned long kdVideoTestTime; -Bool kdEmulateMiddleButton; -Bool kdRawPointerCoordinates; -Bool kdDisableZaphod; -Bool kdAllowZap; -Bool kdEnabled; -int kdSubpixelOrder; -int kdVirtualTerminal = -1; -Bool kdSwitchPending; -char *kdSwitchCmd; -DDXPointRec kdOrigin; -Bool kdHasPointer = FALSE; -Bool kdHasKbd = FALSE; - -static Bool kdCaughtSignal = FALSE; - -/* - * Carry arguments from InitOutput through driver initialization - * to KdScreenInit - */ - -KdOsFuncs *kdOsFuncs; - -void -KdSetRootClip (ScreenPtr pScreen, BOOL enable) -{ - WindowPtr pWin = WindowTable[pScreen->myNum]; - WindowPtr pChild; - Bool WasViewable; - Bool anyMarked = FALSE; - WindowPtr pLayerWin; - BoxRec box; - - if (!pWin) - return; - WasViewable = (Bool)(pWin->viewable); - if (WasViewable) - { - for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) - { - (void) (*pScreen->MarkOverlappedWindows)(pChild, - pChild, - &pLayerWin); - } - (*pScreen->MarkWindow) (pWin); - anyMarked = TRUE; - if (pWin->valdata) - { - if (HasBorder (pWin)) - { - RegionPtr borderVisible; - - borderVisible = REGION_CREATE(pScreen, NullBox, 1); - REGION_SUBTRACT(pScreen, borderVisible, - &pWin->borderClip, &pWin->winSize); - pWin->valdata->before.borderVisible = borderVisible; - } - pWin->valdata->before.resized = TRUE; - } - } - - if (enable) - { - box.x1 = 0; - box.y1 = 0; - box.x2 = pScreen->width; - box.y2 = pScreen->height; - pWin->drawable.width = pScreen->width; - pWin->drawable.height = pScreen->height; - REGION_INIT (pScreen, &pWin->winSize, &box, 1); - REGION_INIT (pScreen, &pWin->borderSize, &box, 1); - REGION_RESET(pScreen, &pWin->borderClip, &box); - REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); - } - else - { - REGION_EMPTY(pScreen, &pWin->borderClip); - REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); - } - - ResizeChildrenWinSize (pWin, 0, 0, 0, 0); - - if (WasViewable) - { - if (pWin->firstChild) - { - anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, - pWin->firstChild, - (WindowPtr *)NULL); - } - else - { - (*pScreen->MarkWindow) (pWin); - anyMarked = TRUE; - } - - - if (anyMarked) - (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); - } - - if (WasViewable) - { - if (anyMarked) - (*pScreen->HandleExposures)(pWin); - if (anyMarked && pScreen->PostValidateTree) - (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); - } - if (pWin->realized) - WindowsRestructured (); -} - -void -KdDisableScreen (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - - if (!pScreenPriv->enabled) - return; - if (!pScreenPriv->closed) - KdSetRootClip (pScreen, FALSE); - KdDisableColormap (pScreen); - if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->disableAccel) - (*pScreenPriv->card->cfuncs->disableAccel) (pScreen); - if (!pScreenPriv->screen->softCursor && pScreenPriv->card->cfuncs->disableCursor) - (*pScreenPriv->card->cfuncs->disableCursor) (pScreen); - if (pScreenPriv->card->cfuncs->dpms) - (*pScreenPriv->card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL); - pScreenPriv->enabled = FALSE; - if(pScreenPriv->card->cfuncs->disable) - (*pScreenPriv->card->cfuncs->disable) (pScreen); -} - -static void -KdDoSwitchCmd (char *reason) -{ - if (kdSwitchCmd) - { - char *command = xalloc (strlen (kdSwitchCmd) + - 1 + - strlen (reason) + - 1); - if (!command) - return; - strcpy (command, kdSwitchCmd); - strcat (command, " "); - strcat (command, reason); - system (command); - xfree (command); - } -} - -void -KdSuspend (void) -{ - KdCardInfo *card; - KdScreenInfo *screen; - - if (kdEnabled) - { - for (card = kdCardInfo; card; card = card->next) - { - for (screen = card->screenList; screen; screen = screen->next) - if (screen->mynum == card->selected && screen->pScreen) - KdDisableScreen (screen->pScreen); - if (card->driver && card->cfuncs->restore) - (*card->cfuncs->restore) (card); - } - KdDisableInput (); - KdDoSwitchCmd ("suspend"); - } -} - -void -KdDisableScreens (void) -{ - KdSuspend (); - if (kdEnabled) - { - if (kdOsFuncs->Disable) - (*kdOsFuncs->Disable) (); - kdEnabled = FALSE; - } -} - -Bool -KdEnableScreen (ScreenPtr pScreen) -{ - KdScreenPriv (pScreen); - - if (pScreenPriv->enabled) - return TRUE; - if(pScreenPriv->card->cfuncs->enable) - if (!(*pScreenPriv->card->cfuncs->enable) (pScreen)) - return FALSE; - pScreenPriv->enabled = TRUE; - pScreenPriv->dpmsState = KD_DPMS_NORMAL; - pScreenPriv->card->selected = pScreenPriv->screen->mynum; - if (!pScreenPriv->screen->softCursor && pScreenPriv->card->cfuncs->enableCursor) - (*pScreenPriv->card->cfuncs->enableCursor) (pScreen); - if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->enableAccel) - (*pScreenPriv->card->cfuncs->enableAccel) (pScreen); - KdEnableColormap (pScreen); - KdSetRootClip (pScreen, TRUE); - if (pScreenPriv->card->cfuncs->dpms) - (*pScreenPriv->card->cfuncs->dpms) (pScreen, pScreenPriv->dpmsState); - return TRUE; -} - -void -KdResume (void) -{ - KdCardInfo *card; - KdScreenInfo *screen; - - if (kdEnabled) - { - KdDoSwitchCmd ("resume"); - for (card = kdCardInfo; card; card = card->next) - { - if(card->cfuncs->preserve) - (*card->cfuncs->preserve) (card); - for (screen = card->screenList; screen; screen = screen->next) - if (screen->mynum == card->selected && screen->pScreen) - KdEnableScreen (screen->pScreen); - } - KdEnableInput (); - KdReleaseAllKeys (); - } -} - -void -KdEnableScreens (void) -{ - if (!kdEnabled) - { - kdEnabled = TRUE; - if (kdOsFuncs->Enable) - (*kdOsFuncs->Enable) (); - } - KdResume (); -} - -void -KdProcessSwitch (void) -{ - if (kdEnabled) - KdDisableScreens (); - else - KdEnableScreens (); -} - -void -AbortDDX(void) -{ - KdDisableScreens (); - if (kdOsFuncs) - { - if (kdEnabled && kdOsFuncs->Disable) - (*kdOsFuncs->Disable) (); - if (kdOsFuncs->Fini) - (*kdOsFuncs->Fini) (); - KdDoSwitchCmd ("stop"); - } - - if (kdCaughtSignal) - OsAbort(); -} - -void -ddxGiveUp (void) -{ - AbortDDX (); -} - -Bool kdDumbDriver; -Bool kdSoftCursor; - -char * -KdParseFindNext (char *cur, char *delim, char *save, char *last) -{ - while (*cur && !strchr (delim, *cur)) - { - *save++ = *cur++; - } - *save = 0; - *last = *cur; - if (*cur) - cur++; - return cur; -} - -Rotation -KdAddRotation (Rotation a, Rotation b) -{ - Rotation rotate = (a & RR_Rotate_All) * (b & RR_Rotate_All); - Rotation reflect = (a & RR_Reflect_All) ^ (b & RR_Reflect_All); - - if (rotate > RR_Rotate_270) - rotate /= (RR_Rotate_270 * RR_Rotate_90); - return reflect | rotate; -} - -Rotation -KdSubRotation (Rotation a, Rotation b) -{ - Rotation rotate = (a & RR_Rotate_All) * 16 / (b & RR_Rotate_All); - Rotation reflect = (a & RR_Reflect_All) ^ (b & RR_Reflect_All); - - if (rotate > RR_Rotate_270) - rotate /= (RR_Rotate_270 * RR_Rotate_90); - return reflect | rotate; -} - -void -KdParseScreen (KdScreenInfo *screen, - char *arg) -{ - char delim; - char save[1024]; - int i; - int pixels, mm; - - screen->dumb = kdDumbDriver; - screen->softCursor = kdSoftCursor; - screen->origin = kdOrigin; - screen->randr = RR_Rotate_0; - screen->width = 0; - screen->height = 0; - screen->width_mm = 0; - screen->height_mm = 0; - screen->subpixel_order = kdSubpixelOrder; - screen->rate = 0; - screen->fb.depth = 0; - if (!arg) - return; - if (strlen (arg) >= sizeof (save)) - return; - - for (i = 0; i < 2; i++) - { - arg = KdParseFindNext (arg, "x/@XY", save, &delim); - if (!save[0]) - return; - - pixels = atoi(save); - mm = 0; - - if (delim == '/') - { - arg = KdParseFindNext (arg, "x@XY", save, &delim); - if (!save[0]) - return; - mm = atoi(save); - } - - if (i == 0) - { - screen->width = pixels; - screen->width_mm = mm; - } - else - { - screen->height = pixels; - screen->height_mm = mm; - } - if (delim != 'x' && delim != '@' && delim != 'X' && delim != 'Y') - return; - } - - kdOrigin.x += screen->width; - kdOrigin.y = 0; - kdDumbDriver = FALSE; - kdSoftCursor = FALSE; - kdSubpixelOrder = SubPixelUnknown; - - if (delim == '@') - { - arg = KdParseFindNext (arg, "xXY", save, &delim); - if (save[0]) - { - int rotate = atoi (save); - if (rotate < 45) - screen->randr = RR_Rotate_0; - else if (rotate < 135) - screen->randr = RR_Rotate_90; - else if (rotate < 225) - screen->randr = RR_Rotate_180; - else if (rotate < 315) - screen->randr = RR_Rotate_270; - else - screen->randr = RR_Rotate_0; - } - } - if (delim == 'X') - { - arg = KdParseFindNext (arg, "xY", save, &delim); - screen->randr |= RR_Reflect_X; - } - - if (delim == 'Y') - { - arg = KdParseFindNext (arg, "xY", save, &delim); - screen->randr |= RR_Reflect_Y; - } - - arg = KdParseFindNext (arg, "x/,", save, &delim); - if (save[0]) - { - screen->fb.depth = atoi(save); - if (delim == '/') - { - arg = KdParseFindNext (arg, "x,", save, &delim); - if (save[0]) - screen->fb.bitsPerPixel = atoi (save); - } - else - screen->fb.bitsPerPixel = 0; - } - - if (delim == 'x') - { - arg = KdParseFindNext (arg, "x", save, &delim); - if (save[0]) - screen->rate = atoi(save); - } -} - -/* - * Mouse argument syntax: - * - * device,protocol,options... - * - * Options are any of: - * 1-5 n button mouse - * 2button emulate middle button - * {NMO} Reorder buttons - */ - -void -KdParseRgba (char *rgba) -{ - if (!strcmp (rgba, "rgb")) - kdSubpixelOrder = SubPixelHorizontalRGB; - else if (!strcmp (rgba, "bgr")) - kdSubpixelOrder = SubPixelHorizontalBGR; - else if (!strcmp (rgba, "vrgb")) - kdSubpixelOrder = SubPixelVerticalRGB; - else if (!strcmp (rgba, "vbgr")) - kdSubpixelOrder = SubPixelVerticalBGR; - else if (!strcmp (rgba, "none")) - kdSubpixelOrder = SubPixelNone; - else - kdSubpixelOrder = SubPixelUnknown; -} - -void -KdUseMsg (void) -{ - ErrorF("\nTinyX Device Dependent Usage:\n"); - ErrorF("-screen WIDTH[/WIDTHMM]xHEIGHT[/HEIGHTMM][@ROTATION][X][Y][xDEPTH/BPP[xFREQ]] Specify screen characteristics\n"); - ErrorF("-rgba rgb/bgr/vrgb/vbgr/none Specify subpixel ordering for LCD panels\n"); - ErrorF("-mouse driver [,n,,options] Specify the pointer driver and its options (n is the number of buttons)\n"); - ErrorF("-keybd driver [,,options] Specify the keyboard driver and its options\n"); - ErrorF("-zaphod Disable cursor screen switching\n"); - ErrorF("-2button Emulate 3 button mouse\n"); - ErrorF("-3button Disable 3 button mouse emulation\n"); - ErrorF("-rawcoord Don't transform pointer coordinates on rotation\n"); - ErrorF("-dumb Disable hardware acceleration\n"); - ErrorF("-softCursor Force software cursor\n"); - ErrorF("-videoTest Start the server, pause momentarily and exit\n"); - ErrorF("-origin X,Y Locates the next screen in the the virtual screen (Xinerama)\n"); - ErrorF("-switchCmd Command to execute on vt switch\n"); - ErrorF("-zap Terminate server on Ctrl+Alt+Backspace\n"); - ErrorF("vtxx Use virtual terminal xx instead of the next available\n"); -} - -int -KdProcessArgument (int argc, char **argv, int i) -{ - KdCardInfo *card; - KdScreenInfo *screen; - - if (!strcmp (argv[i], "-screen")) - { - if ((i+1) < argc) - { - card = KdCardInfoLast (); - if (!card) - { - InitCard (0); - card = KdCardInfoLast (); - } - if (card) { - screen = KdScreenInfoAdd (card); - KdParseScreen (screen, argv[i+1]); - } else - ErrorF("No matching card found!\n"); - } - else - UseMsg (); - return 2; - } - if (!strcmp (argv[i], "-zaphod")) - { - kdDisableZaphod = TRUE; - return 1; - } - if (!strcmp (argv[i], "-zap")) - { - kdAllowZap = TRUE; - return 1; - } - if (!strcmp (argv[i], "-3button")) - { - kdEmulateMiddleButton = FALSE; - return 1; - } - if (!strcmp (argv[i], "-2button")) - { - kdEmulateMiddleButton = TRUE; - return 1; - } - if (!strcmp (argv[i], "-rawcoord")) - { - kdRawPointerCoordinates = 1; - return 1; - } - if (!strcmp (argv[i], "-dumb")) - { - kdDumbDriver = TRUE; - return 1; - } - if (!strcmp (argv[i], "-softCursor")) - { - kdSoftCursor = TRUE; - return 1; - } - if (!strcmp (argv[i], "-videoTest")) - { - kdVideoTest = TRUE; - return 1; - } - if (!strcmp (argv[i], "-origin")) - { - if ((i+1) < argc) - { - char *x = argv[i+1]; - char *y = strchr (x, ','); - if (x) - kdOrigin.x = atoi (x); - else - kdOrigin.x = 0; - if (y) - kdOrigin.y = atoi(y+1); - else - kdOrigin.y = 0; - } - else - UseMsg (); - return 2; - } - if (!strcmp (argv[i], "-rgba")) - { - if ((i+1) < argc) - KdParseRgba (argv[i+1]); - else - UseMsg (); - return 2; - } - if (!strcmp (argv[i], "-switchCmd")) - { - if ((i+1) < argc) - kdSwitchCmd = argv[i+1]; - else - UseMsg (); - return 2; - } - if (!strncmp (argv[i], "vt", 2) && - sscanf (argv[i], "vt%2d", &kdVirtualTerminal) == 1) - { - return 1; - } - if (!strcmp (argv[i], "-mouse") || - !strcmp (argv[i], "-pointer")) { - if (i + 1 >= argc) - UseMsg(); - KdAddConfigPointer(argv[i + 1]); - kdHasPointer = TRUE; - return 2; - } - if (!strcmp (argv[i], "-keybd")) { - if (i + 1 >= argc) - UseMsg(); - KdAddConfigKeyboard(argv[i + 1]); - kdHasKbd = TRUE; - return 2; - } - - return 0; -} - -/* - * These are getting tossed in here until I can think of where - * they really belong - */ - -void -KdOsInit (KdOsFuncs *pOsFuncs) -{ - kdOsFuncs = pOsFuncs; - if (pOsFuncs) - { - if (serverGeneration == 1) - { - KdDoSwitchCmd ("start"); - if (pOsFuncs->Init) - (*pOsFuncs->Init) (); - } - } -} - -Bool -KdAllocatePrivates (ScreenPtr pScreen) -{ - KdPrivScreenPtr pScreenPriv; - - if (kdGeneration != serverGeneration) - kdGeneration = serverGeneration; - - pScreenPriv = xcalloc(1, sizeof (*pScreenPriv)); - if (!pScreenPriv) - return FALSE; - KdSetScreenPriv (pScreen, pScreenPriv); - return TRUE; -} - -Bool -KdCreateScreenResources (ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdCardInfo *card = pScreenPriv->card; - Bool ret; - - pScreen->CreateScreenResources = pScreenPriv->CreateScreenResources; - if(pScreen->CreateScreenResources) - ret = (*pScreen->CreateScreenResources) (pScreen); - else - ret= -1; - pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources; - pScreen->CreateScreenResources = KdCreateScreenResources; - if (ret && card->cfuncs->createRes) - ret = (*card->cfuncs->createRes) (pScreen); - return ret; -} - -Bool -KdCloseScreen (int index, ScreenPtr pScreen) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - KdCardInfo *card = pScreenPriv->card; - Bool ret; - - pScreenPriv->closed = TRUE; - pScreen->CloseScreen = pScreenPriv->CloseScreen; - if(pScreen->CloseScreen) - ret = (*pScreen->CloseScreen) (index, pScreen); - else - ret = TRUE; - - if (pScreenPriv->dpmsState != KD_DPMS_NORMAL) - (*card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL); - - if (screen->mynum == card->selected) - KdDisableScreen (pScreen); - - /* - * Restore video hardware when last screen is closed - */ - if (screen == card->screenList) - { - if (kdEnabled && card->cfuncs->restore) - (*card->cfuncs->restore) (card); - } - - if (!pScreenPriv->screen->dumb && card->cfuncs->finiAccel) - (*card->cfuncs->finiAccel) (pScreen); - - if (!pScreenPriv->screen->softCursor && card->cfuncs->finiCursor) - (*card->cfuncs->finiCursor) (pScreen); - - if(card->cfuncs->scrfini) - (*card->cfuncs->scrfini) (screen); - - /* - * Clean up card when last screen is closed, DIX closes them in - * reverse order, thus we check for when the first in the list is closed - */ - if (screen == card->screenList) - { - if(card->cfuncs->cardfini) - (*card->cfuncs->cardfini) (card); - /* - * Clean up OS when last card is closed - */ - if (card == kdCardInfo) - { - if (kdEnabled) - { - kdEnabled = FALSE; - if(kdOsFuncs->Disable) - (*kdOsFuncs->Disable) (); - } - } - } - - pScreenPriv->screen->pScreen = 0; - - xfree ((pointer) pScreenPriv); - return ret; -} - -Bool -KdSaveScreen (ScreenPtr pScreen, int on) -{ - KdScreenPriv(pScreen); - int dpmsState; - - if (!pScreenPriv->card->cfuncs->dpms) - return FALSE; - - dpmsState = pScreenPriv->dpmsState; - switch (on) { - case SCREEN_SAVER_OFF: - dpmsState = KD_DPMS_NORMAL; - break; - case SCREEN_SAVER_ON: - if (dpmsState == KD_DPMS_NORMAL) - dpmsState = KD_DPMS_NORMAL+1; - break; - case SCREEN_SAVER_CYCLE: - if (dpmsState < KD_DPMS_MAX) - dpmsState++; - break; - case SCREEN_SAVER_FORCER: - break; - } - if (dpmsState != pScreenPriv->dpmsState) - { - if (pScreenPriv->enabled) - (*pScreenPriv->card->cfuncs->dpms) (pScreen, dpmsState); - pScreenPriv->dpmsState = dpmsState; - } - return TRUE; -} - -static Bool -KdCreateWindow (WindowPtr pWin) -{ -#ifndef PHOENIX - if (!pWin->parent) - { - KdScreenPriv(pWin->drawable.pScreen); - - if (!pScreenPriv->enabled) - { - REGION_EMPTY (pWin->drawable.pScreen, &pWin->borderClip); - REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); - } - } -#endif - return fbCreateWindow (pWin); -} - -void -KdSetSubpixelOrder (ScreenPtr pScreen, Rotation randr) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - int subpixel_order = screen->subpixel_order; - Rotation subpixel_dir; - int i; - - static struct { - int subpixel_order; - Rotation direction; - } orders[] = { - { SubPixelHorizontalRGB, RR_Rotate_0 }, - { SubPixelHorizontalBGR, RR_Rotate_180 }, - { SubPixelVerticalRGB, RR_Rotate_270 }, - { SubPixelVerticalBGR, RR_Rotate_90 }, - }; - - static struct { - int bit; - int normal; - int reflect; - } reflects[] = { - { RR_Reflect_X, SubPixelHorizontalRGB, SubPixelHorizontalBGR }, - { RR_Reflect_X, SubPixelHorizontalBGR, SubPixelHorizontalRGB }, - { RR_Reflect_Y, SubPixelVerticalRGB, SubPixelVerticalBGR }, - { RR_Reflect_Y, SubPixelVerticalRGB, SubPixelVerticalRGB }, - }; - - /* map subpixel to direction */ - for (i = 0; i < 4; i++) - if (orders[i].subpixel_order == subpixel_order) - break; - if (i < 4) - { - subpixel_dir = KdAddRotation (randr & RR_Rotate_All, orders[i].direction); - - /* map back to subpixel order */ - for (i = 0; i < 4; i++) - if (orders[i].direction & subpixel_dir) - { - subpixel_order = orders[i].subpixel_order; - break; - } - /* reflect */ - for (i = 0; i < 4; i++) - if ((randr & reflects[i].bit) && - reflects[i].normal == subpixel_order) - { - subpixel_order = reflects[i].reflect; - break; - } - } - PictureSetSubpixelOrder (pScreen, subpixel_order); -} - -/* Pass through AddScreen, which doesn't take any closure */ -static KdScreenInfo *kdCurrentScreen; - -Bool -KdScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) -{ - KdScreenInfo *screen = kdCurrentScreen; - KdCardInfo *card = screen->card; - KdPrivScreenPtr pScreenPriv; - /* - * note that screen->fb is set up for the nominal orientation - * of the screen; that means if randr is rotated, the values - * there should reflect a rotated frame buffer (or shadow). - */ - Bool rotated = (screen->randr & (RR_Rotate_90|RR_Rotate_270)) != 0; - int width, height, *width_mmp, *height_mmp; - - KdAllocatePrivates (pScreen); - - pScreenPriv = KdGetScreenPriv(pScreen); - - if (!rotated) - { - width = screen->width; - height = screen->height; - width_mmp = &screen->width_mm; - height_mmp = &screen->height_mm; - } - else - { - width = screen->height; - height = screen->width; - width_mmp = &screen->height_mm; - height_mmp = &screen->width_mm; - } - screen->pScreen = pScreen; - pScreenPriv->screen = screen; - pScreenPriv->card = card; - pScreenPriv->bytesPerPixel = screen->fb.bitsPerPixel >> 3; - pScreenPriv->dpmsState = KD_DPMS_NORMAL; -#ifdef PANORAMIX - dixScreenOrigins[pScreen->myNum] = screen->origin; -#endif - - if (!monitorResolution) - monitorResolution = 75; - /* - * This is done in this order so that backing store wraps - * our GC functions; fbFinishScreenInit initializes MI - * backing store - */ - if (!fbSetupScreen (pScreen, - screen->fb.frameBuffer, - width, height, - monitorResolution, monitorResolution, - screen->fb.pixelStride, - screen->fb.bitsPerPixel)) - { - return FALSE; - } - - /* - * Set colormap functions - */ - pScreen->InstallColormap = KdInstallColormap; - pScreen->UninstallColormap = KdUninstallColormap; - pScreen->ListInstalledColormaps = KdListInstalledColormaps; - pScreen->StoreColors = KdStoreColors; - - pScreen->SaveScreen = KdSaveScreen; - pScreen->CreateWindow = KdCreateWindow; - - if (!fbFinishScreenInit (pScreen, - screen->fb.frameBuffer, - width, height, - monitorResolution, monitorResolution, - screen->fb.pixelStride, - screen->fb.bitsPerPixel)) - { - return FALSE; - } - - /* - * Fix screen sizes; for some reason mi takes dpi instead of mm. - * Rounding errors are annoying - */ - if (*width_mmp) - pScreen->mmWidth = *width_mmp; - else - *width_mmp = pScreen->mmWidth; - if (*height_mmp) - pScreen->mmHeight = *height_mmp; - else - *height_mmp = pScreen->mmHeight; - - /* - * Plug in our own block/wakeup handlers. - * miScreenInit installs NoopDDA in both places - */ - pScreen->BlockHandler = KdBlockHandler; - pScreen->WakeupHandler = KdWakeupHandler; - - if (!fbPictureInit (pScreen, 0, 0)) - return FALSE; - if (card->cfuncs->initScreen) - if (!(*card->cfuncs->initScreen) (pScreen)) - return FALSE; - - if (!screen->dumb && card->cfuncs->initAccel) - if (!(*card->cfuncs->initAccel) (pScreen)) - screen->dumb = TRUE; - - if (card->cfuncs->finishInitScreen) - if (!(*card->cfuncs->finishInitScreen) (pScreen)) - return FALSE; - -#if 0 - fbInitValidateTree (pScreen); -#endif - -#if 0 - pScreen->backingStoreSupport = Always; - miInitializeBackingStore (pScreen); -#endif - - - /* - * Wrap CloseScreen, the order now is: - * KdCloseScreen - * miBSCloseScreen - * fbCloseScreen - */ - pScreenPriv->CloseScreen = pScreen->CloseScreen; - pScreen->CloseScreen = KdCloseScreen; - - pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources; - pScreen->CreateScreenResources = KdCreateScreenResources; - - if (screen->softCursor || - !card->cfuncs->initCursor || - !(*card->cfuncs->initCursor) (pScreen)) - { - /* Use MI for cursor display and event queueing. */ - screen->softCursor = TRUE; - miDCInitialize(pScreen, &kdPointerScreenFuncs); - } - - - if (!fbCreateDefColormap (pScreen)) - { - return FALSE; - } - - KdSetSubpixelOrder (pScreen, screen->randr); - - /* - * Enable the hardware - */ - if (!kdEnabled) - { - kdEnabled = TRUE; - if(kdOsFuncs->Enable) - (*kdOsFuncs->Enable) (); - } - - if (screen->mynum == card->selected) - { - if(card->cfuncs->preserve) - (*card->cfuncs->preserve) (card); - if(card->cfuncs->enable) - if (!(*card->cfuncs->enable) (pScreen)) - return FALSE; - pScreenPriv->enabled = TRUE; - if (!screen->softCursor && card->cfuncs->enableCursor) - (*card->cfuncs->enableCursor) (pScreen); - KdEnableColormap (pScreen); - if (!screen->dumb && card->cfuncs->enableAccel) - (*card->cfuncs->enableAccel) (pScreen); - } - - return TRUE; -} - -void -KdInitScreen (ScreenInfo *pScreenInfo, - KdScreenInfo *screen, - int argc, - char **argv) -{ - KdCardInfo *card = screen->card; - - (*card->cfuncs->scrinit) (screen); - - if (!card->cfuncs->initAccel) - screen->dumb = TRUE; - if (!card->cfuncs->initCursor) - screen->softCursor = TRUE; -} - -static Bool -KdSetPixmapFormats (ScreenInfo *pScreenInfo) -{ - CARD8 depthToBpp[33]; /* depth -> bpp map */ - KdCardInfo *card; - KdScreenInfo *screen; - int i; - int bpp; - PixmapFormatRec *format; - - for (i = 1; i <= 32; i++) - depthToBpp[i] = 0; - - /* - * Generate mappings between bitsPerPixel and depth, - * also ensure that all screens comply with protocol - * restrictions on equivalent formats for the same - * depth on different screens - */ - for (card = kdCardInfo; card; card = card->next) - { - for (screen = card->screenList; screen; screen = screen->next) - { - bpp = screen->fb.bitsPerPixel; - if (bpp == 24) - bpp = 32; - if (!depthToBpp[screen->fb.depth]) - depthToBpp[screen->fb.depth] = bpp; - else if (depthToBpp[screen->fb.depth] != bpp) - return FALSE; - } - } - - /* - * Fill in additional formats - */ - for (i = 0; i < NUM_KD_DEPTHS; i++) - if (!depthToBpp[kdDepths[i].depth]) - depthToBpp[kdDepths[i].depth] = kdDepths[i].bpp; - - pScreenInfo->imageByteOrder = IMAGE_BYTE_ORDER; - pScreenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; - pScreenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; - pScreenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; - - pScreenInfo->numPixmapFormats = 0; - - for (i = 1; i <= 32; i++) - { - if (depthToBpp[i]) - { - format = &pScreenInfo->formats[pScreenInfo->numPixmapFormats++]; - format->depth = i; - format->bitsPerPixel = depthToBpp[i]; - format->scanlinePad = BITMAP_SCANLINE_PAD; - } - } - - return TRUE; -} - -static void -KdAddScreen (ScreenInfo *pScreenInfo, - KdScreenInfo *screen, - int argc, - char **argv) -{ - int i; - /* - * Fill in fb visual type masks for this screen - */ - for (i = 0; i < pScreenInfo->numPixmapFormats; i++) - { - unsigned long visuals; - Pixel rm, gm, bm; - - visuals = 0; - rm = gm = bm = 0; - if (pScreenInfo->formats[i].depth == screen->fb.depth) - { - visuals = screen->fb.visuals; - rm = screen->fb.redMask; - gm = screen->fb.greenMask; - bm = screen->fb.blueMask; - } - fbSetVisualTypesAndMasks (pScreenInfo->formats[i].depth, - visuals, - 8, - rm, gm, bm); - } - - kdCurrentScreen = screen; - - AddScreen (KdScreenInit, argc, argv); -} - -#if 0 /* This function is not used currently */ - -int -KdDepthToFb (ScreenPtr pScreen, int depth) -{ - KdScreenPriv(pScreen); - - for (fb = 0; fb <= KD_MAX_FB && pScreenPriv->screen->fb.frameBuffer; fb++) - if (pScreenPriv->screen->fb.depth == depth) - return fb; -} - -#endif - -static int -KdSignalWrapper (int signum) -{ - kdCaughtSignal = TRUE; - return 1; /* use generic OS layer cleanup & abort */ -} - -void -KdInitOutput (ScreenInfo *pScreenInfo, - int argc, - char **argv) -{ - KdCardInfo *card; - KdScreenInfo *screen; - - if (!kdCardInfo) - { - InitCard (0); - if (!(card = KdCardInfoLast ())) - FatalError("No matching cards found!\n"); - screen = KdScreenInfoAdd (card); - KdParseScreen (screen, 0); - } - /* - * Initialize all of the screens for all of the cards - */ - for (card = kdCardInfo; card; card = card->next) - { - int ret=1; - if(card->cfuncs->cardinit) - ret=(*card->cfuncs->cardinit) (card); - if (ret) - { - for (screen = card->screenList; screen; screen = screen->next) - KdInitScreen (pScreenInfo, screen, argc, argv); - } - } - - /* - * Merge the various pixmap formats together, this can fail - * when two screens share depth but not bitsPerPixel - */ - if (!KdSetPixmapFormats (pScreenInfo)) - return; - - /* - * Add all of the screens - */ - for (card = kdCardInfo; card; card = card->next) - for (screen = card->screenList; screen; screen = screen->next) - KdAddScreen (pScreenInfo, screen, argc, argv); - - OsRegisterSigWrapper(KdSignalWrapper); -} - -void -OsVendorFatalError(void) -{ -} - -int -DPMSSet(ClientPtr client, int level) -{ - return Success; -} - -Bool -DPMSSupported (void) -{ - return FALSE; -} +/* + * Copyright © 1999 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "kdrive.h" +#include +#include +#include "privates.h" +#ifdef RANDR +#include +#endif + +#ifdef XV +#include "kxv.h" +#endif + +#ifdef DPMSExtension +#include "dpmsproc.h" +#endif + +#ifdef HAVE_EXECINFO_H +#include +#endif + +#include + +typedef struct _kdDepths { + CARD8 depth; + CARD8 bpp; +} KdDepths; + +KdDepths kdDepths[] = { + { 1, 1 }, + { 4, 4 }, + { 8, 8 }, + { 15, 16 }, + { 16, 16 }, + { 24, 32 }, + { 32, 32 } +}; + +#define NUM_KD_DEPTHS (sizeof (kdDepths) / sizeof (kdDepths[0])) + +#define KD_DEFAULT_BUTTONS 5 + +static int kdScreenPrivateKeyIndex; +DevPrivateKey kdScreenPrivateKey = &kdScreenPrivateKeyIndex; +unsigned long kdGeneration; + +Bool kdVideoTest; +unsigned long kdVideoTestTime; +Bool kdEmulateMiddleButton; +Bool kdRawPointerCoordinates; +Bool kdDisableZaphod; +Bool kdAllowZap; +Bool kdEnabled; +int kdSubpixelOrder; +int kdVirtualTerminal = -1; +Bool kdSwitchPending; +char *kdSwitchCmd; +DDXPointRec kdOrigin; +Bool kdHasPointer = FALSE; +Bool kdHasKbd = FALSE; + +static Bool kdCaughtSignal = FALSE; + +/* + * Carry arguments from InitOutput through driver initialization + * to KdScreenInit + */ + +KdOsFuncs *kdOsFuncs; + +void +KdSetRootClip (ScreenPtr pScreen, BOOL enable) +{ + WindowPtr pWin = WindowTable[pScreen->myNum]; + WindowPtr pChild; + Bool WasViewable; + Bool anyMarked = FALSE; + WindowPtr pLayerWin; + BoxRec box; + + if (!pWin) + return; + WasViewable = (Bool)(pWin->viewable); + if (WasViewable) + { + for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib) + { + (void) (*pScreen->MarkOverlappedWindows)(pChild, + pChild, + &pLayerWin); + } + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + if (pWin->valdata) + { + if (HasBorder (pWin)) + { + RegionPtr borderVisible; + + borderVisible = REGION_CREATE(pScreen, NullBox, 1); + REGION_SUBTRACT(pScreen, borderVisible, + &pWin->borderClip, &pWin->winSize); + pWin->valdata->before.borderVisible = borderVisible; + } + pWin->valdata->before.resized = TRUE; + } + } + + if (enable) + { + box.x1 = 0; + box.y1 = 0; + box.x2 = pScreen->width; + box.y2 = pScreen->height; + pWin->drawable.width = pScreen->width; + pWin->drawable.height = pScreen->height; + REGION_INIT (pScreen, &pWin->winSize, &box, 1); + REGION_INIT (pScreen, &pWin->borderSize, &box, 1); + REGION_RESET(pScreen, &pWin->borderClip, &box); + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + else + { + REGION_EMPTY(pScreen, &pWin->borderClip); + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + + ResizeChildrenWinSize (pWin, 0, 0, 0, 0); + + if (WasViewable) + { + if (pWin->firstChild) + { + anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin->firstChild, + pWin->firstChild, + (WindowPtr *)NULL); + } + else + { + (*pScreen->MarkWindow) (pWin); + anyMarked = TRUE; + } + + + if (anyMarked) + (*pScreen->ValidateTree)(pWin, NullWindow, VTOther); + } + + if (WasViewable) + { + if (anyMarked) + (*pScreen->HandleExposures)(pWin); + if (anyMarked && pScreen->PostValidateTree) + (*pScreen->PostValidateTree)(pWin, NullWindow, VTOther); + } + if (pWin->realized) + WindowsRestructured (); +} + +void +KdDisableScreen (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + + if (!pScreenPriv->enabled) + return; + if (!pScreenPriv->closed) + KdSetRootClip (pScreen, FALSE); + KdDisableColormap (pScreen); + if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->disableAccel) + (*pScreenPriv->card->cfuncs->disableAccel) (pScreen); + if (!pScreenPriv->screen->softCursor && pScreenPriv->card->cfuncs->disableCursor) + (*pScreenPriv->card->cfuncs->disableCursor) (pScreen); + if (pScreenPriv->card->cfuncs->dpms) + (*pScreenPriv->card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL); + pScreenPriv->enabled = FALSE; + if(pScreenPriv->card->cfuncs->disable) + (*pScreenPriv->card->cfuncs->disable) (pScreen); +} + +static void +KdDoSwitchCmd (char *reason) +{ + if (kdSwitchCmd) + { + char *command = malloc(strlen (kdSwitchCmd) + + 1 + + strlen (reason) + + 1); + if (!command) + return; + strcpy (command, kdSwitchCmd); + strcat (command, " "); + strcat (command, reason); + system (command); + free(command); + } +} + +void +KdSuspend (void) +{ + KdCardInfo *card; + KdScreenInfo *screen; + + if (kdEnabled) + { + for (card = kdCardInfo; card; card = card->next) + { + for (screen = card->screenList; screen; screen = screen->next) + if (screen->mynum == card->selected && screen->pScreen) + KdDisableScreen (screen->pScreen); + if (card->driver && card->cfuncs->restore) + (*card->cfuncs->restore) (card); + } + KdDisableInput (); + KdDoSwitchCmd ("suspend"); + } +} + +void +KdDisableScreens (void) +{ + KdSuspend (); + if (kdEnabled) + { + if (kdOsFuncs->Disable) + (*kdOsFuncs->Disable) (); + kdEnabled = FALSE; + } +} + +Bool +KdEnableScreen (ScreenPtr pScreen) +{ + KdScreenPriv (pScreen); + + if (pScreenPriv->enabled) + return TRUE; + if(pScreenPriv->card->cfuncs->enable) + if (!(*pScreenPriv->card->cfuncs->enable) (pScreen)) + return FALSE; + pScreenPriv->enabled = TRUE; + pScreenPriv->dpmsState = KD_DPMS_NORMAL; + pScreenPriv->card->selected = pScreenPriv->screen->mynum; + if (!pScreenPriv->screen->softCursor && pScreenPriv->card->cfuncs->enableCursor) + (*pScreenPriv->card->cfuncs->enableCursor) (pScreen); + if (!pScreenPriv->screen->dumb && pScreenPriv->card->cfuncs->enableAccel) + (*pScreenPriv->card->cfuncs->enableAccel) (pScreen); + KdEnableColormap (pScreen); + KdSetRootClip (pScreen, TRUE); + if (pScreenPriv->card->cfuncs->dpms) + (*pScreenPriv->card->cfuncs->dpms) (pScreen, pScreenPriv->dpmsState); + return TRUE; +} + +void +KdResume (void) +{ + KdCardInfo *card; + KdScreenInfo *screen; + + if (kdEnabled) + { + KdDoSwitchCmd ("resume"); + for (card = kdCardInfo; card; card = card->next) + { + if(card->cfuncs->preserve) + (*card->cfuncs->preserve) (card); + for (screen = card->screenList; screen; screen = screen->next) + if (screen->mynum == card->selected && screen->pScreen) + KdEnableScreen (screen->pScreen); + } + KdEnableInput (); + KdReleaseAllKeys (); + } +} + +void +KdEnableScreens (void) +{ + if (!kdEnabled) + { + kdEnabled = TRUE; + if (kdOsFuncs->Enable) + (*kdOsFuncs->Enable) (); + } + KdResume (); +} + +void +KdProcessSwitch (void) +{ + if (kdEnabled) + KdDisableScreens (); + else + KdEnableScreens (); +} + +void +AbortDDX(void) +{ + KdDisableScreens (); + if (kdOsFuncs) + { + if (kdEnabled && kdOsFuncs->Disable) + (*kdOsFuncs->Disable) (); + if (kdOsFuncs->Fini) + (*kdOsFuncs->Fini) (); + KdDoSwitchCmd ("stop"); + } + + if (kdCaughtSignal) + OsAbort(); +} + +void +ddxGiveUp (void) +{ + AbortDDX (); +} + +Bool kdDumbDriver; +Bool kdSoftCursor; + +char * +KdParseFindNext (char *cur, char *delim, char *save, char *last) +{ + while (*cur && !strchr (delim, *cur)) + { + *save++ = *cur++; + } + *save = 0; + *last = *cur; + if (*cur) + cur++; + return cur; +} + +Rotation +KdAddRotation (Rotation a, Rotation b) +{ + Rotation rotate = (a & RR_Rotate_All) * (b & RR_Rotate_All); + Rotation reflect = (a & RR_Reflect_All) ^ (b & RR_Reflect_All); + + if (rotate > RR_Rotate_270) + rotate /= (RR_Rotate_270 * RR_Rotate_90); + return reflect | rotate; +} + +Rotation +KdSubRotation (Rotation a, Rotation b) +{ + Rotation rotate = (a & RR_Rotate_All) * 16 / (b & RR_Rotate_All); + Rotation reflect = (a & RR_Reflect_All) ^ (b & RR_Reflect_All); + + if (rotate > RR_Rotate_270) + rotate /= (RR_Rotate_270 * RR_Rotate_90); + return reflect | rotate; +} + +void +KdParseScreen (KdScreenInfo *screen, + char *arg) +{ + char delim; + char save[1024]; + int i; + int pixels, mm; + + screen->dumb = kdDumbDriver; + screen->softCursor = kdSoftCursor; + screen->origin = kdOrigin; + screen->randr = RR_Rotate_0; + screen->width = 0; + screen->height = 0; + screen->width_mm = 0; + screen->height_mm = 0; + screen->subpixel_order = kdSubpixelOrder; + screen->rate = 0; + screen->fb.depth = 0; + if (!arg) + return; + if (strlen (arg) >= sizeof (save)) + return; + + for (i = 0; i < 2; i++) + { + arg = KdParseFindNext (arg, "x/@XY", save, &delim); + if (!save[0]) + return; + + pixels = atoi(save); + mm = 0; + + if (delim == '/') + { + arg = KdParseFindNext (arg, "x@XY", save, &delim); + if (!save[0]) + return; + mm = atoi(save); + } + + if (i == 0) + { + screen->width = pixels; + screen->width_mm = mm; + } + else + { + screen->height = pixels; + screen->height_mm = mm; + } + if (delim != 'x' && delim != '@' && delim != 'X' && delim != 'Y') + return; + } + + kdOrigin.x += screen->width; + kdOrigin.y = 0; + kdDumbDriver = FALSE; + kdSoftCursor = FALSE; + kdSubpixelOrder = SubPixelUnknown; + + if (delim == '@') + { + arg = KdParseFindNext (arg, "xXY", save, &delim); + if (save[0]) + { + int rotate = atoi (save); + if (rotate < 45) + screen->randr = RR_Rotate_0; + else if (rotate < 135) + screen->randr = RR_Rotate_90; + else if (rotate < 225) + screen->randr = RR_Rotate_180; + else if (rotate < 315) + screen->randr = RR_Rotate_270; + else + screen->randr = RR_Rotate_0; + } + } + if (delim == 'X') + { + arg = KdParseFindNext (arg, "xY", save, &delim); + screen->randr |= RR_Reflect_X; + } + + if (delim == 'Y') + { + arg = KdParseFindNext (arg, "xY", save, &delim); + screen->randr |= RR_Reflect_Y; + } + + arg = KdParseFindNext (arg, "x/,", save, &delim); + if (save[0]) + { + screen->fb.depth = atoi(save); + if (delim == '/') + { + arg = KdParseFindNext (arg, "x,", save, &delim); + if (save[0]) + screen->fb.bitsPerPixel = atoi (save); + } + else + screen->fb.bitsPerPixel = 0; + } + + if (delim == 'x') + { + arg = KdParseFindNext (arg, "x", save, &delim); + if (save[0]) + screen->rate = atoi(save); + } +} + +/* + * Mouse argument syntax: + * + * device,protocol,options... + * + * Options are any of: + * 1-5 n button mouse + * 2button emulate middle button + * {NMO} Reorder buttons + */ + +void +KdParseRgba (char *rgba) +{ + if (!strcmp (rgba, "rgb")) + kdSubpixelOrder = SubPixelHorizontalRGB; + else if (!strcmp (rgba, "bgr")) + kdSubpixelOrder = SubPixelHorizontalBGR; + else if (!strcmp (rgba, "vrgb")) + kdSubpixelOrder = SubPixelVerticalRGB; + else if (!strcmp (rgba, "vbgr")) + kdSubpixelOrder = SubPixelVerticalBGR; + else if (!strcmp (rgba, "none")) + kdSubpixelOrder = SubPixelNone; + else + kdSubpixelOrder = SubPixelUnknown; +} + +void +KdUseMsg (void) +{ + ErrorF("\nTinyX Device Dependent Usage:\n"); + ErrorF("-screen WIDTH[/WIDTHMM]xHEIGHT[/HEIGHTMM][@ROTATION][X][Y][xDEPTH/BPP[xFREQ]] Specify screen characteristics\n"); + ErrorF("-rgba rgb/bgr/vrgb/vbgr/none Specify subpixel ordering for LCD panels\n"); + ErrorF("-mouse driver [,n,,options] Specify the pointer driver and its options (n is the number of buttons)\n"); + ErrorF("-keybd driver [,,options] Specify the keyboard driver and its options\n"); + ErrorF("-zaphod Disable cursor screen switching\n"); + ErrorF("-2button Emulate 3 button mouse\n"); + ErrorF("-3button Disable 3 button mouse emulation\n"); + ErrorF("-rawcoord Don't transform pointer coordinates on rotation\n"); + ErrorF("-dumb Disable hardware acceleration\n"); + ErrorF("-softCursor Force software cursor\n"); + ErrorF("-videoTest Start the server, pause momentarily and exit\n"); + ErrorF("-origin X,Y Locates the next screen in the the virtual screen (Xinerama)\n"); + ErrorF("-switchCmd Command to execute on vt switch\n"); + ErrorF("-zap Terminate server on Ctrl+Alt+Backspace\n"); + ErrorF("vtxx Use virtual terminal xx instead of the next available\n"); +} + +int +KdProcessArgument (int argc, char **argv, int i) +{ + KdCardInfo *card; + KdScreenInfo *screen; + + if (!strcmp (argv[i], "-screen")) + { + if ((i+1) < argc) + { + card = KdCardInfoLast (); + if (!card) + { + InitCard (0); + card = KdCardInfoLast (); + } + if (card) { + screen = KdScreenInfoAdd (card); + KdParseScreen (screen, argv[i+1]); + } else + ErrorF("No matching card found!\n"); + } + else + UseMsg (); + return 2; + } + if (!strcmp (argv[i], "-zaphod")) + { + kdDisableZaphod = TRUE; + return 1; + } + if (!strcmp (argv[i], "-zap")) + { + kdAllowZap = TRUE; + return 1; + } + if (!strcmp (argv[i], "-3button")) + { + kdEmulateMiddleButton = FALSE; + return 1; + } + if (!strcmp (argv[i], "-2button")) + { + kdEmulateMiddleButton = TRUE; + return 1; + } + if (!strcmp (argv[i], "-rawcoord")) + { + kdRawPointerCoordinates = 1; + return 1; + } + if (!strcmp (argv[i], "-dumb")) + { + kdDumbDriver = TRUE; + return 1; + } + if (!strcmp (argv[i], "-softCursor")) + { + kdSoftCursor = TRUE; + return 1; + } + if (!strcmp (argv[i], "-videoTest")) + { + kdVideoTest = TRUE; + return 1; + } + if (!strcmp (argv[i], "-origin")) + { + if ((i+1) < argc) + { + char *x = argv[i+1]; + char *y = strchr (x, ','); + if (x) + kdOrigin.x = atoi (x); + else + kdOrigin.x = 0; + if (y) + kdOrigin.y = atoi(y+1); + else + kdOrigin.y = 0; + } + else + UseMsg (); + return 2; + } + if (!strcmp (argv[i], "-rgba")) + { + if ((i+1) < argc) + KdParseRgba (argv[i+1]); + else + UseMsg (); + return 2; + } + if (!strcmp (argv[i], "-switchCmd")) + { + if ((i+1) < argc) + kdSwitchCmd = argv[i+1]; + else + UseMsg (); + return 2; + } + if (!strncmp (argv[i], "vt", 2) && + sscanf (argv[i], "vt%2d", &kdVirtualTerminal) == 1) + { + return 1; + } + if (!strcmp (argv[i], "-mouse") || + !strcmp (argv[i], "-pointer")) { + if (i + 1 >= argc) + UseMsg(); + KdAddConfigPointer(argv[i + 1]); + kdHasPointer = TRUE; + return 2; + } + if (!strcmp (argv[i], "-keybd")) { + if (i + 1 >= argc) + UseMsg(); + KdAddConfigKeyboard(argv[i + 1]); + kdHasKbd = TRUE; + return 2; + } + + return 0; +} + +/* + * These are getting tossed in here until I can think of where + * they really belong + */ + +void +KdOsInit (KdOsFuncs *pOsFuncs) +{ + kdOsFuncs = pOsFuncs; + if (pOsFuncs) + { + if (serverGeneration == 1) + { + KdDoSwitchCmd ("start"); + if (pOsFuncs->Init) + (*pOsFuncs->Init) (); + } + } +} + +Bool +KdAllocatePrivates (ScreenPtr pScreen) +{ + KdPrivScreenPtr pScreenPriv; + + if (kdGeneration != serverGeneration) + kdGeneration = serverGeneration; + + pScreenPriv = calloc(1, sizeof (*pScreenPriv)); + if (!pScreenPriv) + return FALSE; + KdSetScreenPriv (pScreen, pScreenPriv); + return TRUE; +} + +Bool +KdCreateScreenResources (ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdCardInfo *card = pScreenPriv->card; + Bool ret; + + pScreen->CreateScreenResources = pScreenPriv->CreateScreenResources; + if(pScreen->CreateScreenResources) + ret = (*pScreen->CreateScreenResources) (pScreen); + else + ret= -1; + pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = KdCreateScreenResources; + if (ret && card->cfuncs->createRes) + ret = (*card->cfuncs->createRes) (pScreen); + return ret; +} + +Bool +KdCloseScreen (int index, ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + KdCardInfo *card = pScreenPriv->card; + Bool ret; + + pScreenPriv->closed = TRUE; + pScreen->CloseScreen = pScreenPriv->CloseScreen; + if(pScreen->CloseScreen) + ret = (*pScreen->CloseScreen) (index, pScreen); + else + ret = TRUE; + + if (pScreenPriv->dpmsState != KD_DPMS_NORMAL) + (*card->cfuncs->dpms) (pScreen, KD_DPMS_NORMAL); + + if (screen->mynum == card->selected) + KdDisableScreen (pScreen); + + /* + * Restore video hardware when last screen is closed + */ + if (screen == card->screenList) + { + if (kdEnabled && card->cfuncs->restore) + (*card->cfuncs->restore) (card); + } + + if (!pScreenPriv->screen->dumb && card->cfuncs->finiAccel) + (*card->cfuncs->finiAccel) (pScreen); + + if (!pScreenPriv->screen->softCursor && card->cfuncs->finiCursor) + (*card->cfuncs->finiCursor) (pScreen); + + if(card->cfuncs->scrfini) + (*card->cfuncs->scrfini) (screen); + + /* + * Clean up card when last screen is closed, DIX closes them in + * reverse order, thus we check for when the first in the list is closed + */ + if (screen == card->screenList) + { + if(card->cfuncs->cardfini) + (*card->cfuncs->cardfini) (card); + /* + * Clean up OS when last card is closed + */ + if (card == kdCardInfo) + { + if (kdEnabled) + { + kdEnabled = FALSE; + if(kdOsFuncs->Disable) + (*kdOsFuncs->Disable) (); + } + } + } + + pScreenPriv->screen->pScreen = 0; + + free((pointer) pScreenPriv); + return ret; +} + +Bool +KdSaveScreen (ScreenPtr pScreen, int on) +{ + KdScreenPriv(pScreen); + int dpmsState; + + if (!pScreenPriv->card->cfuncs->dpms) + return FALSE; + + dpmsState = pScreenPriv->dpmsState; + switch (on) { + case SCREEN_SAVER_OFF: + dpmsState = KD_DPMS_NORMAL; + break; + case SCREEN_SAVER_ON: + if (dpmsState == KD_DPMS_NORMAL) + dpmsState = KD_DPMS_NORMAL+1; + break; + case SCREEN_SAVER_CYCLE: + if (dpmsState < KD_DPMS_MAX) + dpmsState++; + break; + case SCREEN_SAVER_FORCER: + break; + } + if (dpmsState != pScreenPriv->dpmsState) + { + if (pScreenPriv->enabled) + (*pScreenPriv->card->cfuncs->dpms) (pScreen, dpmsState); + pScreenPriv->dpmsState = dpmsState; + } + return TRUE; +} + +static Bool +KdCreateWindow (WindowPtr pWin) +{ +#ifndef PHOENIX + if (!pWin->parent) + { + KdScreenPriv(pWin->drawable.pScreen); + + if (!pScreenPriv->enabled) + { + REGION_EMPTY (pWin->drawable.pScreen, &pWin->borderClip); + REGION_BREAK (pWin->drawable.pScreen, &pWin->clipList); + } + } +#endif + return fbCreateWindow (pWin); +} + +void +KdSetSubpixelOrder (ScreenPtr pScreen, Rotation randr) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + int subpixel_order = screen->subpixel_order; + Rotation subpixel_dir; + int i; + + static struct { + int subpixel_order; + Rotation direction; + } orders[] = { + { SubPixelHorizontalRGB, RR_Rotate_0 }, + { SubPixelHorizontalBGR, RR_Rotate_180 }, + { SubPixelVerticalRGB, RR_Rotate_270 }, + { SubPixelVerticalBGR, RR_Rotate_90 }, + }; + + static struct { + int bit; + int normal; + int reflect; + } reflects[] = { + { RR_Reflect_X, SubPixelHorizontalRGB, SubPixelHorizontalBGR }, + { RR_Reflect_X, SubPixelHorizontalBGR, SubPixelHorizontalRGB }, + { RR_Reflect_Y, SubPixelVerticalRGB, SubPixelVerticalBGR }, + { RR_Reflect_Y, SubPixelVerticalRGB, SubPixelVerticalRGB }, + }; + + /* map subpixel to direction */ + for (i = 0; i < 4; i++) + if (orders[i].subpixel_order == subpixel_order) + break; + if (i < 4) + { + subpixel_dir = KdAddRotation (randr & RR_Rotate_All, orders[i].direction); + + /* map back to subpixel order */ + for (i = 0; i < 4; i++) + if (orders[i].direction & subpixel_dir) + { + subpixel_order = orders[i].subpixel_order; + break; + } + /* reflect */ + for (i = 0; i < 4; i++) + if ((randr & reflects[i].bit) && + reflects[i].normal == subpixel_order) + { + subpixel_order = reflects[i].reflect; + break; + } + } + PictureSetSubpixelOrder (pScreen, subpixel_order); +} + +/* Pass through AddScreen, which doesn't take any closure */ +static KdScreenInfo *kdCurrentScreen; + +Bool +KdScreenInit(int index, ScreenPtr pScreen, int argc, char **argv) +{ + KdScreenInfo *screen = kdCurrentScreen; + KdCardInfo *card = screen->card; + KdPrivScreenPtr pScreenPriv; + /* + * note that screen->fb is set up for the nominal orientation + * of the screen; that means if randr is rotated, the values + * there should reflect a rotated frame buffer (or shadow). + */ + Bool rotated = (screen->randr & (RR_Rotate_90|RR_Rotate_270)) != 0; + int width, height, *width_mmp, *height_mmp; + + KdAllocatePrivates (pScreen); + + pScreenPriv = KdGetScreenPriv(pScreen); + + if (!rotated) + { + width = screen->width; + height = screen->height; + width_mmp = &screen->width_mm; + height_mmp = &screen->height_mm; + } + else + { + width = screen->height; + height = screen->width; + width_mmp = &screen->height_mm; + height_mmp = &screen->width_mm; + } + screen->pScreen = pScreen; + pScreenPriv->screen = screen; + pScreenPriv->card = card; + pScreenPriv->bytesPerPixel = screen->fb.bitsPerPixel >> 3; + pScreenPriv->dpmsState = KD_DPMS_NORMAL; +#ifdef PANORAMIX + dixScreenOrigins[pScreen->myNum] = screen->origin; +#endif + + if (!monitorResolution) + monitorResolution = 75; + /* + * This is done in this order so that backing store wraps + * our GC functions; fbFinishScreenInit initializes MI + * backing store + */ + if (!fbSetupScreen (pScreen, + screen->fb.frameBuffer, + width, height, + monitorResolution, monitorResolution, + screen->fb.pixelStride, + screen->fb.bitsPerPixel)) + { + return FALSE; + } + + /* + * Set colormap functions + */ + pScreen->InstallColormap = KdInstallColormap; + pScreen->UninstallColormap = KdUninstallColormap; + pScreen->ListInstalledColormaps = KdListInstalledColormaps; + pScreen->StoreColors = KdStoreColors; + + pScreen->SaveScreen = KdSaveScreen; + pScreen->CreateWindow = KdCreateWindow; + + if (!fbFinishScreenInit (pScreen, + screen->fb.frameBuffer, + width, height, + monitorResolution, monitorResolution, + screen->fb.pixelStride, + screen->fb.bitsPerPixel)) + { + return FALSE; + } + + /* + * Fix screen sizes; for some reason mi takes dpi instead of mm. + * Rounding errors are annoying + */ + if (*width_mmp) + pScreen->mmWidth = *width_mmp; + else + *width_mmp = pScreen->mmWidth; + if (*height_mmp) + pScreen->mmHeight = *height_mmp; + else + *height_mmp = pScreen->mmHeight; + + /* + * Plug in our own block/wakeup handlers. + * miScreenInit installs NoopDDA in both places + */ + pScreen->BlockHandler = KdBlockHandler; + pScreen->WakeupHandler = KdWakeupHandler; + + if (!fbPictureInit (pScreen, 0, 0)) + return FALSE; + if (card->cfuncs->initScreen) + if (!(*card->cfuncs->initScreen) (pScreen)) + return FALSE; + + if (!screen->dumb && card->cfuncs->initAccel) + if (!(*card->cfuncs->initAccel) (pScreen)) + screen->dumb = TRUE; + + if (card->cfuncs->finishInitScreen) + if (!(*card->cfuncs->finishInitScreen) (pScreen)) + return FALSE; + +#if 0 + fbInitValidateTree (pScreen); +#endif + +#if 0 + pScreen->backingStoreSupport = Always; + miInitializeBackingStore (pScreen); +#endif + + + /* + * Wrap CloseScreen, the order now is: + * KdCloseScreen + * miBSCloseScreen + * fbCloseScreen + */ + pScreenPriv->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = KdCloseScreen; + + pScreenPriv->CreateScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = KdCreateScreenResources; + + if (screen->softCursor || + !card->cfuncs->initCursor || + !(*card->cfuncs->initCursor) (pScreen)) + { + /* Use MI for cursor display and event queueing. */ + screen->softCursor = TRUE; + miDCInitialize(pScreen, &kdPointerScreenFuncs); + } + + + if (!fbCreateDefColormap (pScreen)) + { + return FALSE; + } + + KdSetSubpixelOrder (pScreen, screen->randr); + + /* + * Enable the hardware + */ + if (!kdEnabled) + { + kdEnabled = TRUE; + if(kdOsFuncs->Enable) + (*kdOsFuncs->Enable) (); + } + + if (screen->mynum == card->selected) + { + if(card->cfuncs->preserve) + (*card->cfuncs->preserve) (card); + if(card->cfuncs->enable) + if (!(*card->cfuncs->enable) (pScreen)) + return FALSE; + pScreenPriv->enabled = TRUE; + if (!screen->softCursor && card->cfuncs->enableCursor) + (*card->cfuncs->enableCursor) (pScreen); + KdEnableColormap (pScreen); + if (!screen->dumb && card->cfuncs->enableAccel) + (*card->cfuncs->enableAccel) (pScreen); + } + + return TRUE; +} + +void +KdInitScreen (ScreenInfo *pScreenInfo, + KdScreenInfo *screen, + int argc, + char **argv) +{ + KdCardInfo *card = screen->card; + + (*card->cfuncs->scrinit) (screen); + + if (!card->cfuncs->initAccel) + screen->dumb = TRUE; + if (!card->cfuncs->initCursor) + screen->softCursor = TRUE; +} + +static Bool +KdSetPixmapFormats (ScreenInfo *pScreenInfo) +{ + CARD8 depthToBpp[33]; /* depth -> bpp map */ + KdCardInfo *card; + KdScreenInfo *screen; + int i; + int bpp; + PixmapFormatRec *format; + + for (i = 1; i <= 32; i++) + depthToBpp[i] = 0; + + /* + * Generate mappings between bitsPerPixel and depth, + * also ensure that all screens comply with protocol + * restrictions on equivalent formats for the same + * depth on different screens + */ + for (card = kdCardInfo; card; card = card->next) + { + for (screen = card->screenList; screen; screen = screen->next) + { + bpp = screen->fb.bitsPerPixel; + if (bpp == 24) + bpp = 32; + if (!depthToBpp[screen->fb.depth]) + depthToBpp[screen->fb.depth] = bpp; + else if (depthToBpp[screen->fb.depth] != bpp) + return FALSE; + } + } + + /* + * Fill in additional formats + */ + for (i = 0; i < NUM_KD_DEPTHS; i++) + if (!depthToBpp[kdDepths[i].depth]) + depthToBpp[kdDepths[i].depth] = kdDepths[i].bpp; + + pScreenInfo->imageByteOrder = IMAGE_BYTE_ORDER; + pScreenInfo->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + pScreenInfo->bitmapScanlinePad = BITMAP_SCANLINE_PAD; + pScreenInfo->bitmapBitOrder = BITMAP_BIT_ORDER; + + pScreenInfo->numPixmapFormats = 0; + + for (i = 1; i <= 32; i++) + { + if (depthToBpp[i]) + { + format = &pScreenInfo->formats[pScreenInfo->numPixmapFormats++]; + format->depth = i; + format->bitsPerPixel = depthToBpp[i]; + format->scanlinePad = BITMAP_SCANLINE_PAD; + } + } + + return TRUE; +} + +static void +KdAddScreen (ScreenInfo *pScreenInfo, + KdScreenInfo *screen, + int argc, + char **argv) +{ + int i; + /* + * Fill in fb visual type masks for this screen + */ + for (i = 0; i < pScreenInfo->numPixmapFormats; i++) + { + unsigned long visuals; + Pixel rm, gm, bm; + + visuals = 0; + rm = gm = bm = 0; + if (pScreenInfo->formats[i].depth == screen->fb.depth) + { + visuals = screen->fb.visuals; + rm = screen->fb.redMask; + gm = screen->fb.greenMask; + bm = screen->fb.blueMask; + } + fbSetVisualTypesAndMasks (pScreenInfo->formats[i].depth, + visuals, + 8, + rm, gm, bm); + } + + kdCurrentScreen = screen; + + AddScreen (KdScreenInit, argc, argv); +} + +#if 0 /* This function is not used currently */ + +int +KdDepthToFb (ScreenPtr pScreen, int depth) +{ + KdScreenPriv(pScreen); + + for (fb = 0; fb <= KD_MAX_FB && pScreenPriv->screen->fb.frameBuffer; fb++) + if (pScreenPriv->screen->fb.depth == depth) + return fb; +} + +#endif + +static int +KdSignalWrapper (int signum) +{ + kdCaughtSignal = TRUE; + return 1; /* use generic OS layer cleanup & abort */ +} + +void +KdInitOutput (ScreenInfo *pScreenInfo, + int argc, + char **argv) +{ + KdCardInfo *card; + KdScreenInfo *screen; + + if (!kdCardInfo) + { + InitCard (0); + if (!(card = KdCardInfoLast ())) + FatalError("No matching cards found!\n"); + screen = KdScreenInfoAdd (card); + KdParseScreen (screen, 0); + } + /* + * Initialize all of the screens for all of the cards + */ + for (card = kdCardInfo; card; card = card->next) + { + int ret=1; + if(card->cfuncs->cardinit) + ret=(*card->cfuncs->cardinit) (card); + if (ret) + { + for (screen = card->screenList; screen; screen = screen->next) + KdInitScreen (pScreenInfo, screen, argc, argv); + } + } + + /* + * Merge the various pixmap formats together, this can fail + * when two screens share depth but not bitsPerPixel + */ + if (!KdSetPixmapFormats (pScreenInfo)) + return; + + /* + * Add all of the screens + */ + for (card = kdCardInfo; card; card = card->next) + for (screen = card->screenList; screen; screen = screen->next) + KdAddScreen (pScreenInfo, screen, argc, argv); + + OsRegisterSigWrapper(KdSignalWrapper); +} + +void +OsVendorFatalError(void) +{ +} + +int +DPMSSet(ClientPtr client, int level) +{ + return Success; +} + +Bool +DPMSSupported (void) +{ + return FALSE; +} diff --git a/xorg-server/hw/kdrive/src/kinfo.c b/xorg-server/hw/kdrive/src/kinfo.c index 0825ee24f..90fe37ae9 100644 --- a/xorg-server/hw/kdrive/src/kinfo.c +++ b/xorg-server/hw/kdrive/src/kinfo.c @@ -1,163 +1,163 @@ -/* - * Copyright © 1999 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "kdrive.h" - -KdCardInfo *kdCardInfo; - -KdCardInfo * -KdCardInfoAdd (KdCardFuncs *funcs, - void *closure) -{ - KdCardInfo *ci, **prev; - - ci = xcalloc (1, sizeof (KdCardInfo)); - if (!ci) - return 0; - for (prev = &kdCardInfo; *prev; prev = &(*prev)->next); - *prev = ci; - ci->cfuncs = funcs; - ci->closure = closure; - ci->screenList = 0; - ci->selected = 0; - ci->next = 0; - return ci; -} - -KdCardInfo * -KdCardInfoLast (void) -{ - KdCardInfo *ci; - - if (!kdCardInfo) - return 0; - for (ci = kdCardInfo; ci->next; ci = ci->next); - return ci; -} - -void -KdCardInfoDispose (KdCardInfo *ci) -{ - KdCardInfo **prev; - - for (prev = &kdCardInfo; *prev; prev = &(*prev)->next) - if (*prev == ci) - { - *prev = ci->next; - xfree (ci); - break; - } -} - -KdScreenInfo * -KdScreenInfoAdd (KdCardInfo *ci) -{ - KdScreenInfo *si, **prev; - int n; - - si = xcalloc (1, sizeof (KdScreenInfo)); - if (!si) - return 0; - for (prev = &ci->screenList, n = 0; *prev; prev = &(*prev)->next, n++); - *prev = si; - si->next = 0; - si->card = ci; - si->mynum = n; - return si; -} - -void -KdScreenInfoDispose (KdScreenInfo *si) -{ - KdCardInfo *ci = si->card; - KdScreenInfo **prev; - - for (prev = &ci->screenList; *prev; prev = &(*prev)->next) { - if (*prev == si) - { - *prev = si->next; - xfree (si); - if (!ci->screenList) - KdCardInfoDispose (ci); - break; - } - } -} - -KdPointerInfo * -KdNewPointer (void) -{ - KdPointerInfo *pi; - int i; - - pi = (KdPointerInfo *)xcalloc(1, sizeof(KdPointerInfo)); - if (!pi) - return NULL; - - pi->name = strdup("Generic Pointer"); - pi->path = NULL; - pi->inputClass = KD_MOUSE; - pi->driver = NULL; - pi->driverPrivate = NULL; - pi->next = NULL; - pi->options = NULL; - pi->nAxes = 3; - pi->nButtons = KD_MAX_BUTTON; - for (i = 1; i < KD_MAX_BUTTON; i++) - pi->map[i] = i; - - return pi; -} - -void -KdFreePointer(KdPointerInfo *pi) -{ - InputOption *option, *prev = NULL; - - xfree(pi->name); - xfree(pi->path); - - for (option = pi->options; option; option = option->next) { - xfree(prev); - xfree(option->key); - xfree(option->value); - prev = option; - } - - xfree(prev); - xfree(pi); -} - -void -KdFreeKeyboard(KdKeyboardInfo *ki) -{ - xfree(ki->name); - xfree(ki->path); - xfree(ki->xkbRules); - xfree(ki->xkbModel); - xfree(ki->xkbLayout); - ki->next = NULL; - xfree(ki); -} +/* + * Copyright © 1999 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "kdrive.h" + +KdCardInfo *kdCardInfo; + +KdCardInfo * +KdCardInfoAdd (KdCardFuncs *funcs, + void *closure) +{ + KdCardInfo *ci, **prev; + + ci = calloc(1, sizeof (KdCardInfo)); + if (!ci) + return 0; + for (prev = &kdCardInfo; *prev; prev = &(*prev)->next); + *prev = ci; + ci->cfuncs = funcs; + ci->closure = closure; + ci->screenList = 0; + ci->selected = 0; + ci->next = 0; + return ci; +} + +KdCardInfo * +KdCardInfoLast (void) +{ + KdCardInfo *ci; + + if (!kdCardInfo) + return 0; + for (ci = kdCardInfo; ci->next; ci = ci->next); + return ci; +} + +void +KdCardInfoDispose (KdCardInfo *ci) +{ + KdCardInfo **prev; + + for (prev = &kdCardInfo; *prev; prev = &(*prev)->next) + if (*prev == ci) + { + *prev = ci->next; + free(ci); + break; + } +} + +KdScreenInfo * +KdScreenInfoAdd (KdCardInfo *ci) +{ + KdScreenInfo *si, **prev; + int n; + + si = calloc(1, sizeof (KdScreenInfo)); + if (!si) + return 0; + for (prev = &ci->screenList, n = 0; *prev; prev = &(*prev)->next, n++); + *prev = si; + si->next = 0; + si->card = ci; + si->mynum = n; + return si; +} + +void +KdScreenInfoDispose (KdScreenInfo *si) +{ + KdCardInfo *ci = si->card; + KdScreenInfo **prev; + + for (prev = &ci->screenList; *prev; prev = &(*prev)->next) { + if (*prev == si) + { + *prev = si->next; + free(si); + if (!ci->screenList) + KdCardInfoDispose (ci); + break; + } + } +} + +KdPointerInfo * +KdNewPointer (void) +{ + KdPointerInfo *pi; + int i; + + pi = (KdPointerInfo *)calloc(1, sizeof(KdPointerInfo)); + if (!pi) + return NULL; + + pi->name = strdup("Generic Pointer"); + pi->path = NULL; + pi->inputClass = KD_MOUSE; + pi->driver = NULL; + pi->driverPrivate = NULL; + pi->next = NULL; + pi->options = NULL; + pi->nAxes = 3; + pi->nButtons = KD_MAX_BUTTON; + for (i = 1; i < KD_MAX_BUTTON; i++) + pi->map[i] = i; + + return pi; +} + +void +KdFreePointer(KdPointerInfo *pi) +{ + InputOption *option, *prev = NULL; + + free(pi->name); + free(pi->path); + + for (option = pi->options; option; option = option->next) { + free(prev); + free(option->key); + free(option->value); + prev = option; + } + + free(prev); + free(pi); +} + +void +KdFreeKeyboard(KdKeyboardInfo *ki) +{ + free(ki->name); + free(ki->path); + free(ki->xkbRules); + free(ki->xkbModel); + free(ki->xkbLayout); + ki->next = NULL; + free(ki); +} diff --git a/xorg-server/hw/kdrive/src/kinput.c b/xorg-server/hw/kdrive/src/kinput.c index a88f2dc61..024bce6bd 100644 --- a/xorg-server/hw/kdrive/src/kinput.c +++ b/xorg-server/hw/kdrive/src/kinput.c @@ -1,2360 +1,2360 @@ -/* - * Copyright © 1999 Keith Packard - * Copyright © 2006 Nokia Corporation - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of the authors not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. The authors make no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "kdrive.h" -#include "inputstr.h" - -#define XK_PUBLISHING -#include -#if HAVE_X11_XF86KEYSYM_H -#include -#endif -#include -#include -#ifdef sun -#include /* needed for FNONBLOCK & FASYNC */ -#endif - -#include "xkbsrv.h" - -#include -#include -#include "XIstubs.h" /* even though we don't use stubs. cute, no? */ -#include "exevents.h" -#include "extinit.h" -#include "exglobals.h" -#include "eventstr.h" -#include "xserver-properties.h" - -#define AtomFromName(x) MakeAtom(x, strlen(x), 1) - -struct KdConfigDevice { - char *line; - struct KdConfigDevice *next; -}; - -/* kdKeyboards and kdPointers hold all the real devices. */ -static KdKeyboardInfo *kdKeyboards = NULL; -static KdPointerInfo *kdPointers = NULL; -static struct KdConfigDevice *kdConfigKeyboards = NULL; -static struct KdConfigDevice *kdConfigPointers = NULL; - -static KdKeyboardDriver *kdKeyboardDrivers = NULL; -static KdPointerDriver *kdPointerDrivers = NULL; - -static EventListPtr kdEvents = NULL; - -static Bool kdInputEnabled; -static Bool kdOffScreen; -static unsigned long kdOffScreenTime; -static KdPointerMatrix kdPointerMatrix = { - { { 1, 0, 0 }, - { 0, 1, 0 } } -}; - -void KdResetInputMachine (void); - -#define KD_MAX_INPUT_FDS 8 - -typedef struct _kdInputFd { - int fd; - void (*read) (int fd, void *closure); - int (*enable) (int fd, void *closure); - void (*disable) (int fd, void *closure); - void *closure; -} KdInputFd; - -static KdInputFd kdInputFds[KD_MAX_INPUT_FDS]; -static int kdNumInputFds; - -extern Bool kdRawPointerCoordinates; - -static void -KdSigio (int sig) -{ - int i; - - for (i = 0; i < kdNumInputFds; i++) - (*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure); -} - -static void -KdBlockSigio (void) -{ - sigset_t set; - - sigemptyset (&set); - sigaddset (&set, SIGIO); - sigprocmask (SIG_BLOCK, &set, 0); -} - -static void -KdUnblockSigio (void) -{ - sigset_t set; - - sigemptyset (&set); - sigaddset (&set, SIGIO); - sigprocmask (SIG_UNBLOCK, &set, 0); -} - -#ifdef DEBUG_SIGIO - -void -KdAssertSigioBlocked (char *where) -{ - sigset_t set, old; - - sigemptyset (&set); - sigprocmask (SIG_BLOCK, &set, &old); - if (!sigismember (&old, SIGIO)) { - ErrorF ("SIGIO not blocked at %s\n", where); - KdBacktrace(0); - } -} - -#else - -#define KdAssertSigioBlocked(s) - -#endif - -static int kdnFds; - -#ifdef FNONBLOCK -#define NOBLOCK FNONBLOCK -#else -#define NOBLOCK FNDELAY -#endif - -void -KdResetInputMachine (void) -{ - KdPointerInfo *pi; - - for (pi = kdPointers; pi; pi = pi->next) { - pi->mouseState = start; - pi->eventHeld = FALSE; - } -} - -static void -KdNonBlockFd (int fd) -{ - int flags; - flags = fcntl (fd, F_GETFL); - flags |= FASYNC|NOBLOCK; - fcntl (fd, F_SETFL, flags); -} - -static void -KdAddFd (int fd) -{ - struct sigaction act; - sigset_t set; - - kdnFds++; - fcntl (fd, F_SETOWN, getpid()); - KdNonBlockFd (fd); - AddEnabledDevice (fd); - memset (&act, '\0', sizeof act); - act.sa_handler = KdSigio; - sigemptyset (&act.sa_mask); - sigaddset (&act.sa_mask, SIGIO); - sigaddset (&act.sa_mask, SIGALRM); - sigaddset (&act.sa_mask, SIGVTALRM); - sigaction (SIGIO, &act, 0); - sigemptyset (&set); - sigprocmask (SIG_SETMASK, &set, 0); -} - -static void -KdRemoveFd (int fd) -{ - struct sigaction act; - int flags; - - kdnFds--; - RemoveEnabledDevice (fd); - flags = fcntl (fd, F_GETFL); - flags &= ~(FASYNC|NOBLOCK); - fcntl (fd, F_SETFL, flags); - if (kdnFds == 0) - { - memset (&act, '\0', sizeof act); - act.sa_handler = SIG_IGN; - sigemptyset (&act.sa_mask); - sigaction (SIGIO, &act, 0); - } -} - -Bool -KdRegisterFd (int fd, void (*read) (int fd, void *closure), void *closure) -{ - if (kdNumInputFds == KD_MAX_INPUT_FDS) - return FALSE; - kdInputFds[kdNumInputFds].fd = fd; - kdInputFds[kdNumInputFds].read = read; - kdInputFds[kdNumInputFds].enable = 0; - kdInputFds[kdNumInputFds].disable = 0; - kdInputFds[kdNumInputFds].closure = closure; - kdNumInputFds++; - if (kdInputEnabled) - KdAddFd (fd); - return TRUE; -} - -void -KdUnregisterFd (void *closure, int fd, Bool do_close) -{ - int i, j; - - for (i = 0; i < kdNumInputFds; i++) { - if (kdInputFds[i].closure == closure && - (fd == -1 || kdInputFds[i].fd == fd)) { - if (kdInputEnabled) - KdRemoveFd (kdInputFds[i].fd); - if (do_close) - close (kdInputFds[i].fd); - kdNumInputFds--; - for (j = i; j < kdNumInputFds; j++) - kdInputFds[j] = kdInputFds[j+1]; - break; - } - } -} - -void -KdUnregisterFds (void *closure, Bool do_close) -{ - KdUnregisterFd(closure, -1, do_close); -} - -void -KdDisableInput (void) -{ - KdKeyboardInfo *ki; - KdPointerInfo *pi; - int found = 0, i = 0; - - KdBlockSigio(); - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->driver && ki->driver->Disable) - (*ki->driver->Disable) (ki); - } - - for (pi = kdPointers; pi; pi = pi->next) { - if (pi->driver && pi->driver->Disable) - (*pi->driver->Disable) (pi); - } - - if (kdNumInputFds) { - ErrorF("[KdDisableInput] Buggy drivers: still %d input fds left!", - kdNumInputFds); - i = 0; - while (i < kdNumInputFds) { - found = 0; - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki == kdInputFds[i].closure) { - ErrorF(" fd %d belongs to keybd driver %s\n", - kdInputFds[i].fd, - ki->driver && ki->driver->name ? - ki->driver->name : "(unnamed!)"); - found = 1; - break; - } - } - - if (found) { - i++; - continue; - } - - for (pi = kdPointers; pi; pi = pi->next) { - if (pi == kdInputFds[i].closure) { - ErrorF(" fd %d belongs to pointer driver %s\n", - kdInputFds[i].fd, - pi->driver && pi->driver->name ? - pi->driver->name : "(unnamed!)"); - break; - } - } - - if (found) { - i++; - continue; - } - - ErrorF(" fd %d not claimed by any active device!\n", - kdInputFds[i].fd); - KdUnregisterFd(kdInputFds[i].closure, kdInputFds[i].fd, TRUE); - } - } - - kdInputEnabled = FALSE; -} - -void -KdEnableInput (void) -{ - InternalEvent ev; - KdKeyboardInfo *ki; - KdPointerInfo *pi; - - kdInputEnabled = TRUE; - - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->driver && ki->driver->Enable) - (*ki->driver->Enable) (ki); - } - - for (pi = kdPointers; pi; pi = pi->next) { - if (pi->driver && pi->driver->Enable) - (*pi->driver->Enable) (pi); - } - - /* reset screen saver */ - ev.any.time = GetTimeInMillis (); - NoticeEventTime (&ev); - - KdUnblockSigio (); -} - -static KdKeyboardDriver * -KdFindKeyboardDriver (char *name) -{ - KdKeyboardDriver *ret; - - /* ask a stupid question ... */ - if (!name) - return NULL; - - for (ret = kdKeyboardDrivers; ret; ret = ret->next) { - if (strcmp(ret->name, name) == 0) - return ret; - } - - return NULL; -} - -static KdPointerDriver * -KdFindPointerDriver (char *name) -{ - KdPointerDriver *ret; - - /* ask a stupid question ... */ - if (!name) - return NULL; - - for (ret = kdPointerDrivers; ret; ret = ret->next) { - if (strcmp(ret->name, name) == 0) - return ret; - } - - return NULL; -} - -static int -KdPointerProc(DeviceIntPtr pDevice, int onoff) -{ - DevicePtr pDev = (DevicePtr)pDevice; - KdPointerInfo *pi; - Atom xiclass; - Atom *btn_labels; - Atom *axes_labels; - - if (!pDev) - return BadImplementation; - - for (pi = kdPointers; pi; pi = pi->next) { - if (pi->dixdev && pi->dixdev->id == pDevice->id) - break; - } - - if (!pi || !pi->dixdev || pi->dixdev->id != pDevice->id) { - ErrorF("[KdPointerProc] Failed to find pointer for device %d!\n", - pDevice->id); - return BadImplementation; - } - - switch (onoff) - { - case DEVICE_INIT: -#ifdef DEBUG - ErrorF("initialising pointer %s ...\n", pi->name); -#endif - if (!pi->driver) { - if (!pi->driverPrivate) { - ErrorF("no driver specified for %s\n", pi->name); - return BadImplementation; - } - - pi->driver = KdFindPointerDriver(pi->driverPrivate); - if (!pi->driver) { - ErrorF("Couldn't find pointer driver %s\n", - pi->driverPrivate ? (char *) pi->driverPrivate : - "(unnamed)"); - return !Success; - } - xfree(pi->driverPrivate); - pi->driverPrivate = NULL; - } - - if (!pi->driver->Init) { - ErrorF("no init function\n"); - return BadImplementation; - } - - if ((*pi->driver->Init) (pi) != Success) { - return !Success; - } - - btn_labels = xcalloc(pi->nButtons, sizeof(Atom)); - if (!btn_labels) - return BadAlloc; - axes_labels = xcalloc(pi->nAxes, sizeof(Atom)); - if (!axes_labels) { - xfree(btn_labels); - return BadAlloc; - } - - switch(pi->nAxes) - { - default: - case 7: - btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); - case 6: - btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); - case 5: - btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); - case 4: - btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); - case 3: - btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); - case 2: - btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); - case 1: - btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); - case 0: - break; - } - - if (pi->nAxes >= 2) { - axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); - axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); - } - - InitPointerDeviceStruct(pDev, pi->map, pi->nButtons, btn_labels, - (PtrCtrlProcPtr)NoopDDA, - GetMotionHistorySize(), pi->nAxes, axes_labels); - - xfree(btn_labels); - xfree(axes_labels); - - if (pi->inputClass == KD_TOUCHSCREEN) { - InitAbsoluteClassDeviceStruct(pDevice); - xiclass = AtomFromName(XI_TOUCHSCREEN); - } - else { - xiclass = AtomFromName(XI_MOUSE); - } - - AssignTypeAndName(pi->dixdev, xiclass, - pi->name ? pi->name : "Generic KDrive Pointer"); - - return Success; - - case DEVICE_ON: - if (pDev->on == TRUE) - return Success; - - if (!pi->driver->Enable) { - ErrorF("no enable function\n"); - return BadImplementation; - } - - if ((*pi->driver->Enable) (pi) == Success) { - pDev->on = TRUE; - return Success; - } - else { - return BadImplementation; - } - - return Success; - - case DEVICE_OFF: - if (pDev->on == FALSE) { - return Success; - } - - if (!pi->driver->Disable) { - return BadImplementation; - } - else { - (*pi->driver->Disable) (pi); - pDev->on = FALSE; - return Success; - } - - return Success; - - case DEVICE_CLOSE: - if (pDev->on) { - if (!pi->driver->Disable) { - return BadImplementation; - } - (*pi->driver->Disable) (pi); - pDev->on = FALSE; - } - - if (!pi->driver->Fini) - return BadImplementation; - - (*pi->driver->Fini) (pi); - - KdRemovePointer(pi); - - return Success; - } - - /* NOTREACHED */ - return BadImplementation; -} - -Bool -LegalModifier(unsigned int key, DeviceIntPtr pDev) -{ - return TRUE; -} - -static void -KdBell (int volume, DeviceIntPtr pDev, pointer arg, int something) -{ - 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); -} - -void -DDXRingBell(int volume, int pitch, int duration) -{ - KdKeyboardInfo *ki = NULL; - - if (kdOsFuncs->Bell) { - (*kdOsFuncs->Bell)(volume, pitch, duration); - } - else { - for (ki = kdKeyboards; ki; ki = ki->next) { - if (ki->dixdev->coreEvents) - KdRingBell(ki, volume, pitch, duration); - } - } -} - -void -KdRingBell(KdKeyboardInfo *ki, int volume, int pitch, int duration) -{ - if (!ki || !ki->driver || !ki->driver->Bell) - return; - - if (kdInputEnabled) - (*ki->driver->Bell) (ki, volume, pitch, duration); -} - - -static void -KdSetLeds (KdKeyboardInfo *ki, int leds) -{ - if (!ki || !ki->driver) - return; - - if (kdInputEnabled) { - if (ki->driver->Leds) - (*ki->driver->Leds) (ki, leds); - } -} - -void -KdSetLed (KdKeyboardInfo *ki, int led, Bool on) -{ - if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed) - return; - - NoteLedState (ki->dixdev, led, on); - KdSetLeds (ki, ki->dixdev->kbdfeed->ctrl.leds); -} - -void -KdSetPointerMatrix (KdPointerMatrix *matrix) -{ - kdPointerMatrix = *matrix; -} - -void -KdComputePointerMatrix (KdPointerMatrix *m, Rotation randr, int width, - int height) -{ - int x_dir = 1, y_dir = 1; - int i, j; - int size[2]; - - size[0] = width; size[1] = height; - if (randr & RR_Reflect_X) - x_dir = -1; - if (randr & RR_Reflect_Y) - y_dir = -1; - switch (randr & (RR_Rotate_All)) { - case RR_Rotate_0: - m->matrix[0][0] = x_dir; m->matrix[0][1] = 0; - m->matrix[1][0] = 0; m->matrix[1][1] = y_dir; - break; - case RR_Rotate_90: - m->matrix[0][0] = 0; m->matrix[0][1] = -x_dir; - m->matrix[1][0] = y_dir; m->matrix[1][1] = 0; - break; - case RR_Rotate_180: - m->matrix[0][0] = -x_dir; m->matrix[0][1] = 0; - m->matrix[1][0] = 0; m->matrix[1][1] = -y_dir; - break; - case RR_Rotate_270: - m->matrix[0][0] = 0; m->matrix[0][1] = x_dir; - m->matrix[1][0] = -y_dir; m->matrix[1][1] = 0; - break; - } - for (i = 0; i < 2; i++) - { - m->matrix[i][2] = 0; - for (j = 0 ; j < 2; j++) - if (m->matrix[i][j] < 0) - m->matrix[i][2] = size[j] - 1; - } -} - -void -KdScreenToPointerCoords (int *x, int *y) -{ - int (*m)[3] = kdPointerMatrix.matrix; - int div = m[0][1] * m[1][0] - m[1][1] * m[0][0]; - int sx = *x; - int sy = *y; - - *x = (m[0][1] * sy - m[0][1] * m[1][2] + m[1][1] * m[0][2] - m[1][1] * sx) / div; - *y = (m[1][0] * sx + m[0][0] * m[1][2] - m[1][0] * m[0][2] - m[0][0] * sy) / div; -} - -static void -KdKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) -{ - 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; -} - -extern KeybdCtrl defaultKeyboardControl; - -static int -KdKeyboardProc(DeviceIntPtr pDevice, int onoff) -{ - Bool ret; - DevicePtr pDev = (DevicePtr)pDevice; - KdKeyboardInfo *ki; - Atom xiclass; - XkbRMLVOSet rmlvo; - - if (!pDev) - return BadImplementation; - - 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) { - return BadImplementation; - } - - switch (onoff) - { - case DEVICE_INIT: -#ifdef DEBUG - ErrorF("initialising keyboard %s\n", ki->name); -#endif - if (!ki->driver) { - if (!ki->driverPrivate) { - ErrorF("no driver specified!\n"); - return BadImplementation; - } - - ki->driver = KdFindKeyboardDriver(ki->driverPrivate); - if (!ki->driver) { - ErrorF("Couldn't find keyboard driver %s\n", - ki->driverPrivate ? (char *) ki->driverPrivate : - "(unnamed)"); - return !Success; - } - xfree(ki->driverPrivate); - ki->driverPrivate = NULL; - } - - if (!ki->driver->Init) { - ErrorF("Keyboard %s: no init function\n", ki->name); - return BadImplementation; - } - - if ((*ki->driver->Init) (ki) != Success) { - return !Success; - } - - memset(&rmlvo, 0, sizeof(rmlvo)); - rmlvo.rules = ki->xkbRules; - rmlvo.model = ki->xkbModel; - rmlvo.layout = ki->xkbLayout; - rmlvo.variant = ki->xkbVariant; - rmlvo.options = ki->xkbOptions; - ret = InitKeyboardDeviceStruct (pDevice, &rmlvo, KdBell, KdKbdCtrl); - if (!ret) { - ErrorF("Couldn't initialise keyboard %s\n", ki->name); - return BadImplementation; - } - - xiclass = AtomFromName(XI_KEYBOARD); - AssignTypeAndName(pDevice, xiclass, - ki->name ? ki->name : "Generic KDrive Keyboard"); - - KdResetInputMachine(); - - return Success; - - case DEVICE_ON: - if (pDev->on == TRUE) - return Success; - - if (!ki->driver->Enable) - return BadImplementation; - - if ((*ki->driver->Enable) (ki) != Success) { - return BadMatch; - } - - pDev->on = TRUE; - return Success; - - case DEVICE_OFF: - if (pDev->on == FALSE) - return Success; - - if (!ki->driver->Disable) - return BadImplementation; - - (*ki->driver->Disable) (ki); - pDev->on = FALSE; - - return Success; - - break; - - case DEVICE_CLOSE: - if (pDev->on) { - if (!ki->driver->Disable) - return BadImplementation; - - (*ki->driver->Disable) (ki); - pDev->on = FALSE; - } - - if (!ki->driver->Fini) - return BadImplementation; - - (*ki->driver->Fini) (ki); - - KdRemoveKeyboard(ki); - - return Success; - } - - /* NOTREACHED */ - return BadImplementation; -} - -void -KdAddPointerDriver (KdPointerDriver *driver) -{ - KdPointerDriver **prev; - - if (!driver) - return; - - for (prev = &kdPointerDrivers; *prev; prev = &(*prev)->next) { - if (*prev == driver) - return; - } - *prev = driver; -} - -void -KdRemovePointerDriver (KdPointerDriver *driver) -{ - KdPointerDriver *tmp; - - if (!driver) - return; - - /* FIXME remove all pointers using this driver */ - for (tmp = kdPointerDrivers; tmp; tmp = tmp->next) { - if (tmp->next == driver) - tmp->next = driver->next; - } - if (tmp == driver) - tmp = NULL; -} - -void -KdAddKeyboardDriver (KdKeyboardDriver *driver) -{ - KdKeyboardDriver **prev; - - if (!driver) - return; - - for (prev = &kdKeyboardDrivers; *prev; prev = &(*prev)->next) { - if (*prev == driver) - return; - } - *prev = driver; -} - -void -KdRemoveKeyboardDriver (KdKeyboardDriver *driver) -{ - KdKeyboardDriver *tmp; - - if (!driver) - return; - - /* FIXME remove all keyboards using this driver */ - for (tmp = kdKeyboardDrivers; tmp; tmp = tmp->next) { - if (tmp->next == driver) - tmp->next = driver->next; - } - if (tmp == driver) - tmp = NULL; -} - -KdKeyboardInfo * -KdNewKeyboard (void) -{ - KdKeyboardInfo *ki = xcalloc(sizeof(KdKeyboardInfo), 1); - if (!ki) - return NULL; - - ki->minScanCode = 0; - ki->maxScanCode = 0; - ki->leds = 0; - ki->bellPitch = 1000; - ki->bellDuration = 200; - ki->next = NULL; - ki->options = NULL; - ki->xkbRules = strdup(XKB_DFLT_RULES); - ki->xkbModel = strdup(XKB_DFLT_MODEL); - ki->xkbLayout = strdup(XKB_DFLT_LAYOUT); - ki->xkbVariant = strdup(XKB_DFLT_VARIANT); - ki->xkbOptions = strdup(XKB_DFLT_OPTIONS); - - return ki; -} - -int -KdAddConfigKeyboard (char *keyboard) -{ - struct KdConfigDevice **prev, *new; - - if (!keyboard) - return Success; - - new = (struct KdConfigDevice *) xcalloc(sizeof(struct KdConfigDevice), 1); - if (!new) - return BadAlloc; - - new->line = xstrdup(keyboard); - new->next = NULL; - - for (prev = &kdConfigKeyboards; *prev; prev = &(*prev)->next); - *prev = new; - - return Success; -} - -int -KdAddKeyboard (KdKeyboardInfo *ki) -{ - KdKeyboardInfo **prev; - - if (!ki) - return !Success; - - ki->dixdev = AddInputDevice(serverClient, KdKeyboardProc, TRUE); - if (!ki->dixdev) { - ErrorF("Couldn't register keyboard device %s\n", - ki->name ? ki->name : "(unnamed)"); - return !Success; - } - - ki->dixdev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; - ki->dixdev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; - RegisterOtherDevice(ki->dixdev); - -#ifdef DEBUG - ErrorF("added keyboard %s with dix id %d\n", ki->name, ki->dixdev->id); -#endif - - for (prev = &kdKeyboards; *prev; prev = &(*prev)->next); - *prev = ki; - - return Success; -} - -void -KdRemoveKeyboard (KdKeyboardInfo *ki) -{ - KdKeyboardInfo **prev; - - if (!ki) - return; - - for (prev = &kdKeyboards; *prev; prev = &(*prev)->next) { - if (*prev == ki) { - *prev = ki->next; - break; - } - } - - KdFreeKeyboard(ki); -} - -int -KdAddConfigPointer (char *pointer) -{ - struct KdConfigDevice **prev, *new; - - if (!pointer) - return Success; - - new = (struct KdConfigDevice *) xcalloc(sizeof(struct KdConfigDevice), 1); - if (!new) - return BadAlloc; - - new->line = xstrdup(pointer); - new->next = NULL; - - for (prev = &kdConfigPointers; *prev; prev = &(*prev)->next); - *prev = new; - - return Success; -} - -int -KdAddPointer (KdPointerInfo *pi) -{ - KdPointerInfo **prev; - - if (!pi) - return Success; - - pi->mouseState = start; - pi->eventHeld = FALSE; - - pi->dixdev = AddInputDevice(serverClient, KdPointerProc, TRUE); - if (!pi->dixdev) { - ErrorF("Couldn't add pointer device %s\n", - pi->name ? pi->name : "(unnamed)"); - return BadDevice; - } - - pi->dixdev->deviceGrab.ActivateGrab = ActivatePointerGrab; - pi->dixdev->deviceGrab.DeactivateGrab = DeactivatePointerGrab; - RegisterOtherDevice(pi->dixdev); - - for (prev = &kdPointers; *prev; prev = &(*prev)->next); - *prev = pi; - - return Success; -} - -void -KdRemovePointer (KdPointerInfo *pi) -{ - KdPointerInfo **prev; - - if (!pi) - return; - - for (prev = &kdPointers; *prev; prev = &(*prev)->next) { - if (*prev == pi) { - *prev = pi->next; - break; - } - } - - KdFreePointer(pi); -} - -/* - * You can call your kdriver server with something like: - * $ ./hw/kdrive/yourserver/X :1 -mouse evdev,,device=/dev/input/event4 -keybd - * evdev,,device=/dev/input/event1,xkbmodel=abnt2,xkblayout=br - */ -static Bool -KdGetOptions (InputOption **options, char *string) -{ - InputOption *newopt = NULL, **tmpo = NULL; - int tam_key = 0; - - newopt = xcalloc(1, sizeof (InputOption)); - if (!newopt) - return FALSE; - - for (tmpo = options; *tmpo; tmpo = &(*tmpo)->next) - ; /* Hello, I'm here */ - *tmpo = newopt; - - if (strchr(string, '=')) - { - tam_key = (strchr(string, '=') - string); - newopt->key = (char *)xalloc(tam_key); - strncpy(newopt->key, string, tam_key); - newopt->key[tam_key] = '\0'; - newopt->value = xstrdup(strchr(string, '=') + 1); - } - else - { - newopt->key = xstrdup(string); - newopt->value = NULL; - } - newopt->next = NULL; - - return TRUE; -} - -static void -KdParseKbdOptions (KdKeyboardInfo *ki) -{ - InputOption *option = NULL; - - for (option = ki->options; option; option = option->next) - { - if (strcasecmp(option->key, "XkbRules") == 0) - ki->xkbRules = option->value; - else if (strcasecmp(option->key, "XkbModel") == 0) - ki->xkbModel = option->value; - else if (strcasecmp(option->key, "XkbLayout") == 0) - ki->xkbLayout = option->value; - else if (strcasecmp(option->key, "XkbVariant") == 0) - ki->xkbVariant = option->value; - else if (strcasecmp(option->key, "XkbOptions") == 0) - ki->xkbOptions = option->value; - else if (!strcasecmp (option->key, "device")) - ki->path = strdup(option->value); - else - ErrorF("Kbd option key (%s) of value (%s) not assigned!\n", - option->key, option->value); - } -} - -KdKeyboardInfo * -KdParseKeyboard (char *arg) -{ - char save[1024]; - char delim; - InputOption *options = NULL; - KdKeyboardInfo *ki = NULL; - - ki = KdNewKeyboard(); - if (!ki) - return NULL; - - ki->name = strdup("Unknown KDrive Keyboard"); - ki->path = NULL; - ki->driver = NULL; - ki->driverPrivate = NULL; - ki->next = NULL; - - if (!arg) - { - ErrorF("keybd: no arg\n"); - KdFreeKeyboard (ki); - return NULL; - } - - if (strlen (arg) >= sizeof (save)) - { - ErrorF("keybd: arg too long\n"); - KdFreeKeyboard (ki); - return NULL; - } - - arg = KdParseFindNext (arg, ",", save, &delim); - if (!save[0]) - { - ErrorF("keybd: failed on save[0]\n"); - KdFreeKeyboard (ki); - return NULL; - } - - if (strcmp (save, "auto") == 0) - ki->driverPrivate = NULL; - else - ki->driverPrivate = xstrdup(save); - - if (delim != ',') - { - return ki; - } - - arg = KdParseFindNext (arg, ",", save, &delim); - - while (delim == ',') - { - arg = KdParseFindNext (arg, ",", save, &delim); - - if (!KdGetOptions(&options, save)) - { - KdFreeKeyboard(ki); - return NULL; - } - } - - if (options) - { - ki->options = options; - KdParseKbdOptions(ki); - } - - return ki; -} - -static void -KdParsePointerOptions (KdPointerInfo *pi) -{ - InputOption *option = NULL; - - for (option = pi->options; option; option = option->next) - { - if (!strcmp (option->key, "emulatemiddle")) - pi->emulateMiddleButton = TRUE; - else if (!strcmp (option->key, "noemulatemiddle")) - pi->emulateMiddleButton = FALSE; - else if (!strcmp (option->key, "transformcoord")) - pi->transformCoordinates = TRUE; - else if (!strcmp (option->key, "rawcoord")) - pi->transformCoordinates = FALSE; - else if (!strcasecmp (option->key, "device")) - pi->path = strdup(option->value); - else if (!strcasecmp (option->key, "protocol")) - pi->protocol = strdup(option->value); - else - ErrorF("Pointer option key (%s) of value (%s) not assigned!\n", - option->key, option->value); - } -} - -KdPointerInfo * -KdParsePointer (char *arg) -{ - char save[1024]; - char delim; - KdPointerInfo *pi = NULL; - InputOption *options = NULL; - int i = 0; - - pi = KdNewPointer(); - if (!pi) - return NULL; - pi->emulateMiddleButton = kdEmulateMiddleButton; - pi->transformCoordinates = !kdRawPointerCoordinates; - pi->protocol = NULL; - pi->nButtons = 5; /* XXX should not be hardcoded */ - pi->inputClass = KD_MOUSE; - - if (!arg) - { - ErrorF("mouse: no arg\n"); - KdFreePointer (pi); - return NULL; - } - - if (strlen (arg) >= sizeof (save)) - { - ErrorF("mouse: arg too long\n"); - KdFreePointer (pi); - return NULL; - } - arg = KdParseFindNext (arg, ",", save, &delim); - if (!save[0]) - { - ErrorF("failed on save[0]\n"); - KdFreePointer (pi); - return NULL; - } - - if (strcmp(save, "auto") == 0) - pi->driverPrivate = NULL; - else - pi->driverPrivate = xstrdup(save); - - if (delim != ',') - { - return pi; - } - - arg = KdParseFindNext (arg, ",", save, &delim); - - while (delim == ',') - { - arg = KdParseFindNext (arg, ",", save, &delim); - if (save[0] == '{') - { - char *s = save + 1; - i = 0; - while (*s && *s != '}') - { - if ('1' <= *s && *s <= '0' + pi->nButtons) - pi->map[i] = *s - '0'; - else - UseMsg (); - s++; - } - } - else - { - if (!KdGetOptions(&options, save)) - { - KdFreePointer(pi); - return NULL; - } - } - } - - if (options) - { - pi->options = options; - KdParsePointerOptions(pi); - } - - return pi; -} - - -void -KdInitInput (void) -{ - KdPointerInfo *pi; - KdKeyboardInfo *ki; - struct KdConfigDevice *dev; - - kdInputEnabled = TRUE; - - for (dev = kdConfigPointers; dev; dev = dev->next) { - pi = KdParsePointer(dev->line); - if (!pi) - ErrorF("Failed to parse pointer\n"); - if (KdAddPointer(pi) != Success) - ErrorF("Failed to add pointer!\n"); - } - for (dev = kdConfigKeyboards; dev; dev = dev->next) { - ki = KdParseKeyboard(dev->line); - if (!ki) - ErrorF("Failed to parse keyboard\n"); - if (KdAddKeyboard(ki) != Success) - ErrorF("Failed to add keyboard!\n"); - } - - mieqInit(); -} - -/* - * Middle button emulation state machine - * - * Possible transitions: - * Button 1 press v1 - * Button 1 release ^1 - * Button 2 press v2 - * Button 2 release ^2 - * Button 3 press v3 - * Button 3 release ^3 - * Button other press vo - * Button other release ^o - * Mouse motion <> - * Keyboard event k - * timeout ... - * outside box <-> - * - * States: - * start - * button_1_pend - * button_1_down - * button_2_down - * button_3_pend - * button_3_down - * synthetic_2_down_13 - * synthetic_2_down_3 - * synthetic_2_down_1 - * - * Transition diagram - * - * start - * v1 -> (hold) (settimeout) button_1_pend - * ^1 -> (deliver) start - * v2 -> (deliver) button_2_down - * ^2 -> (deliever) start - * v3 -> (hold) (settimeout) button_3_pend - * ^3 -> (deliver) start - * vo -> (deliver) start - * ^o -> (deliver) start - * <> -> (deliver) start - * k -> (deliver) start - * - * button_1_pend (button 1 is down, timeout pending) - * ^1 -> (release) (deliver) start - * v2 -> (release) (deliver) button_1_down - * ^2 -> (release) (deliver) button_1_down - * v3 -> (cleartimeout) (generate v2) synthetic_2_down_13 - * ^3 -> (release) (deliver) button_1_down - * vo -> (release) (deliver) button_1_down - * ^o -> (release) (deliver) button_1_down - * <-> -> (release) (deliver) button_1_down - * <> -> (deliver) button_1_pend - * k -> (release) (deliver) button_1_down - * ... -> (release) button_1_down - * - * button_1_down (button 1 is down) - * ^1 -> (deliver) start - * v2 -> (deliver) button_1_down - * ^2 -> (deliver) button_1_down - * v3 -> (deliver) button_1_down - * ^3 -> (deliver) button_1_down - * vo -> (deliver) button_1_down - * ^o -> (deliver) button_1_down - * <> -> (deliver) button_1_down - * k -> (deliver) button_1_down - * - * button_2_down (button 2 is down) - * v1 -> (deliver) button_2_down - * ^1 -> (deliver) button_2_down - * ^2 -> (deliver) start - * v3 -> (deliver) button_2_down - * ^3 -> (deliver) button_2_down - * vo -> (deliver) button_2_down - * ^o -> (deliver) button_2_down - * <> -> (deliver) button_2_down - * k -> (deliver) button_2_down - * - * button_3_pend (button 3 is down, timeout pending) - * v1 -> (generate v2) synthetic_2_down - * ^1 -> (release) (deliver) button_3_down - * v2 -> (release) (deliver) button_3_down - * ^2 -> (release) (deliver) button_3_down - * ^3 -> (release) (deliver) start - * vo -> (release) (deliver) button_3_down - * ^o -> (release) (deliver) button_3_down - * <-> -> (release) (deliver) button_3_down - * <> -> (deliver) button_3_pend - * k -> (release) (deliver) button_3_down - * ... -> (release) button_3_down - * - * button_3_down (button 3 is down) - * v1 -> (deliver) button_3_down - * ^1 -> (deliver) button_3_down - * v2 -> (deliver) button_3_down - * ^2 -> (deliver) button_3_down - * ^3 -> (deliver) start - * vo -> (deliver) button_3_down - * ^o -> (deliver) button_3_down - * <> -> (deliver) button_3_down - * k -> (deliver) button_3_down - * - * synthetic_2_down_13 (button 1 and 3 are down) - * ^1 -> (generate ^2) synthetic_2_down_3 - * v2 -> synthetic_2_down_13 - * ^2 -> synthetic_2_down_13 - * ^3 -> (generate ^2) synthetic_2_down_1 - * vo -> (deliver) synthetic_2_down_13 - * ^o -> (deliver) synthetic_2_down_13 - * <> -> (deliver) synthetic_2_down_13 - * k -> (deliver) synthetic_2_down_13 - * - * synthetic_2_down_3 (button 3 is down) - * v1 -> (deliver) synthetic_2_down_3 - * ^1 -> (deliver) synthetic_2_down_3 - * v2 -> synthetic_2_down_3 - * ^2 -> synthetic_2_down_3 - * ^3 -> start - * vo -> (deliver) synthetic_2_down_3 - * ^o -> (deliver) synthetic_2_down_3 - * <> -> (deliver) synthetic_2_down_3 - * k -> (deliver) synthetic_2_down_3 - * - * synthetic_2_down_1 (button 1 is down) - * ^1 -> start - * v2 -> synthetic_2_down_1 - * ^2 -> synthetic_2_down_1 - * v3 -> (deliver) synthetic_2_down_1 - * ^3 -> (deliver) synthetic_2_down_1 - * vo -> (deliver) synthetic_2_down_1 - * ^o -> (deliver) synthetic_2_down_1 - * <> -> (deliver) synthetic_2_down_1 - * k -> (deliver) synthetic_2_down_1 - */ - -typedef enum _inputClass { - down_1, up_1, - down_2, up_2, - down_3, up_3, - down_o, up_o, - motion, outside_box, - keyboard, timeout, - num_input_class -} KdInputClass; - -typedef enum _inputAction { - noop, - hold, - setto, - deliver, - release, - clearto, - gen_down_2, - gen_up_2 -} KdInputAction; - -#define MAX_ACTIONS 2 - -typedef struct _inputTransition { - KdInputAction actions[MAX_ACTIONS]; - KdPointerState nextState; -} KdInputTransition; - -static const -KdInputTransition kdInputMachine[num_input_states][num_input_class] = { - /* start */ - { - { { hold, setto }, button_1_pend }, /* v1 */ - { { deliver, noop }, start }, /* ^1 */ - { { deliver, noop }, button_2_down }, /* v2 */ - { { deliver, noop }, start }, /* ^2 */ - { { hold, setto }, button_3_pend }, /* v3 */ - { { deliver, noop }, start }, /* ^3 */ - { { deliver, noop }, start }, /* vo */ - { { deliver, noop }, start }, /* ^o */ - { { deliver, noop }, start }, /* <> */ - { { deliver, noop }, start }, /* <-> */ - { { noop, noop }, start }, /* k */ - { { noop, noop }, start }, /* ... */ - }, - /* button_1_pend */ - { - { { noop, noop }, button_1_pend }, /* v1 */ - { { release, deliver }, start }, /* ^1 */ - { { release, deliver }, button_1_down }, /* v2 */ - { { release, deliver }, button_1_down }, /* ^2 */ - { { clearto, gen_down_2 }, synth_2_down_13 }, /* v3 */ - { { release, deliver }, button_1_down }, /* ^3 */ - { { release, deliver }, button_1_down }, /* vo */ - { { release, deliver }, button_1_down }, /* ^o */ - { { deliver, noop }, button_1_pend }, /* <> */ - { { release, deliver }, button_1_down }, /* <-> */ - { { noop, noop }, button_1_down }, /* k */ - { { release, noop }, button_1_down }, /* ... */ - }, - /* button_1_down */ - { - { { noop, noop }, button_1_down }, /* v1 */ - { { deliver, noop }, start }, /* ^1 */ - { { deliver, noop }, button_1_down }, /* v2 */ - { { deliver, noop }, button_1_down }, /* ^2 */ - { { deliver, noop }, button_1_down }, /* v3 */ - { { deliver, noop }, button_1_down }, /* ^3 */ - { { deliver, noop }, button_1_down }, /* vo */ - { { deliver, noop }, button_1_down }, /* ^o */ - { { deliver, noop }, button_1_down }, /* <> */ - { { deliver, noop }, button_1_down }, /* <-> */ - { { noop, noop }, button_1_down }, /* k */ - { { noop, noop }, button_1_down }, /* ... */ - }, - /* button_2_down */ - { - { { deliver, noop }, button_2_down }, /* v1 */ - { { deliver, noop }, button_2_down }, /* ^1 */ - { { noop, noop }, button_2_down }, /* v2 */ - { { deliver, noop }, start }, /* ^2 */ - { { deliver, noop }, button_2_down }, /* v3 */ - { { deliver, noop }, button_2_down }, /* ^3 */ - { { deliver, noop }, button_2_down }, /* vo */ - { { deliver, noop }, button_2_down }, /* ^o */ - { { deliver, noop }, button_2_down }, /* <> */ - { { deliver, noop }, button_2_down }, /* <-> */ - { { noop, noop }, button_2_down }, /* k */ - { { noop, noop }, button_2_down }, /* ... */ - }, - /* button_3_pend */ - { - { { clearto, gen_down_2 }, synth_2_down_13 }, /* v1 */ - { { release, deliver }, button_3_down }, /* ^1 */ - { { release, deliver }, button_3_down }, /* v2 */ - { { release, deliver }, button_3_down }, /* ^2 */ - { { release, deliver }, button_3_down }, /* v3 */ - { { release, deliver }, start }, /* ^3 */ - { { release, deliver }, button_3_down }, /* vo */ - { { release, deliver }, button_3_down }, /* ^o */ - { { deliver, noop }, button_3_pend }, /* <> */ - { { release, deliver }, button_3_down }, /* <-> */ - { { release, noop }, button_3_down }, /* k */ - { { release, noop }, button_3_down }, /* ... */ - }, - /* button_3_down */ - { - { { deliver, noop }, button_3_down }, /* v1 */ - { { deliver, noop }, button_3_down }, /* ^1 */ - { { deliver, noop }, button_3_down }, /* v2 */ - { { deliver, noop }, button_3_down }, /* ^2 */ - { { noop, noop }, button_3_down }, /* v3 */ - { { deliver, noop }, start }, /* ^3 */ - { { deliver, noop }, button_3_down }, /* vo */ - { { deliver, noop }, button_3_down }, /* ^o */ - { { deliver, noop }, button_3_down }, /* <> */ - { { deliver, noop }, button_3_down }, /* <-> */ - { { noop, noop }, button_3_down }, /* k */ - { { noop, noop }, button_3_down }, /* ... */ - }, - /* synthetic_2_down_13 */ - { - { { noop, noop }, synth_2_down_13 }, /* v1 */ - { { gen_up_2, noop }, synth_2_down_3 }, /* ^1 */ - { { noop, noop }, synth_2_down_13 }, /* v2 */ - { { noop, noop }, synth_2_down_13 }, /* ^2 */ - { { noop, noop }, synth_2_down_13 }, /* v3 */ - { { gen_up_2, noop }, synth_2_down_1 }, /* ^3 */ - { { deliver, noop }, synth_2_down_13 }, /* vo */ - { { deliver, noop }, synth_2_down_13 }, /* ^o */ - { { deliver, noop }, synth_2_down_13 }, /* <> */ - { { deliver, noop }, synth_2_down_13 }, /* <-> */ - { { noop, noop }, synth_2_down_13 }, /* k */ - { { noop, noop }, synth_2_down_13 }, /* ... */ - }, - /* synthetic_2_down_3 */ - { - { { deliver, noop }, synth_2_down_3 }, /* v1 */ - { { deliver, noop }, synth_2_down_3 }, /* ^1 */ - { { deliver, noop }, synth_2_down_3 }, /* v2 */ - { { deliver, noop }, synth_2_down_3 }, /* ^2 */ - { { noop, noop }, synth_2_down_3 }, /* v3 */ - { { noop, noop }, start }, /* ^3 */ - { { deliver, noop }, synth_2_down_3 }, /* vo */ - { { deliver, noop }, synth_2_down_3 }, /* ^o */ - { { deliver, noop }, synth_2_down_3 }, /* <> */ - { { deliver, noop }, synth_2_down_3 }, /* <-> */ - { { noop, noop }, synth_2_down_3 }, /* k */ - { { noop, noop }, synth_2_down_3 }, /* ... */ - }, - /* synthetic_2_down_1 */ - { - { { noop, noop }, synth_2_down_1 }, /* v1 */ - { { noop, noop }, start }, /* ^1 */ - { { deliver, noop }, synth_2_down_1 }, /* v2 */ - { { deliver, noop }, synth_2_down_1 }, /* ^2 */ - { { deliver, noop }, synth_2_down_1 }, /* v3 */ - { { deliver, noop }, synth_2_down_1 }, /* ^3 */ - { { deliver, noop }, synth_2_down_1 }, /* vo */ - { { deliver, noop }, synth_2_down_1 }, /* ^o */ - { { deliver, noop }, synth_2_down_1 }, /* <> */ - { { deliver, noop }, synth_2_down_1 }, /* <-> */ - { { noop, noop }, synth_2_down_1 }, /* k */ - { { noop, noop }, synth_2_down_1 }, /* ... */ - }, -}; - -#define EMULATION_WINDOW 10 -#define EMULATION_TIMEOUT 100 - -static int -KdInsideEmulationWindow (KdPointerInfo *pi, int x, int y, int z) -{ - pi->emulationDx = pi->heldEvent.x - x; - pi->emulationDy = pi->heldEvent.y - y; - - return (abs (pi->emulationDx) < EMULATION_WINDOW && - abs (pi->emulationDy) < EMULATION_WINDOW); -} - -static KdInputClass -KdClassifyInput (KdPointerInfo *pi, int type, int x, int y, int z, int b) -{ - switch (type) { - case ButtonPress: - switch (b) { - case 1: return down_1; - case 2: return down_2; - case 3: return down_3; - default: return down_o; - } - break; - case ButtonRelease: - switch (b) { - case 1: return up_1; - case 2: return up_2; - case 3: return up_3; - default: return up_o; - } - break; - case MotionNotify: - if (pi->eventHeld && !KdInsideEmulationWindow(pi, x, y, z)) - return outside_box; - else - return motion; - default: - return keyboard; - } - return keyboard; -} - -#ifdef DEBUG -char *kdStateNames[] = { - "start", - "button_1_pend", - "button_1_down", - "button_2_down", - "button_3_pend", - "button_3_down", - "synth_2_down_13", - "synth_2_down_3", - "synthetic_2_down_1", - "num_input_states" -}; - -char *kdClassNames[] = { - "down_1", "up_1", - "down_2", "up_2", - "down_3", "up_3", - "motion", "ouside_box", - "keyboard", "timeout", - "num_input_class" -}; - -char *kdActionNames[] = { - "noop", - "hold", - "setto", - "deliver", - "release", - "clearto", - "gen_down_2", - "gen_up_2", -}; -#endif /* DEBUG */ - -static void -KdQueueEvent (DeviceIntPtr pDev, InternalEvent *ev) -{ - KdAssertSigioBlocked ("KdQueueEvent"); - mieqEnqueue (pDev, ev); -} - -/* We return true if we're stealing the event. */ -static Bool -KdRunMouseMachine (KdPointerInfo *pi, KdInputClass c, int type, int x, int y, - int z, int b, int absrel) -{ - const KdInputTransition *t; - int a; - - c = KdClassifyInput(pi, type, x, y, z, b); - t = &kdInputMachine[pi->mouseState][c]; - for (a = 0; a < MAX_ACTIONS; a++) - { - switch (t->actions[a]) { - case noop: - break; - case hold: - pi->eventHeld = TRUE; - pi->emulationDx = 0; - pi->emulationDy = 0; - pi->heldEvent.type = type; - pi->heldEvent.x = x; - pi->heldEvent.y = y; - pi->heldEvent.z = z; - pi->heldEvent.flags = b; - pi->heldEvent.absrel = absrel; - return TRUE; - break; - case setto: - pi->emulationTimeout = GetTimeInMillis () + EMULATION_TIMEOUT; - pi->timeoutPending = TRUE; - break; - case deliver: - _KdEnqueuePointerEvent (pi, pi->heldEvent.type, pi->heldEvent.x, - pi->heldEvent.y, pi->heldEvent.z, - pi->heldEvent.flags, pi->heldEvent.absrel, - TRUE); - break; - case release: - pi->eventHeld = FALSE; - pi->timeoutPending = FALSE; - _KdEnqueuePointerEvent (pi, pi->heldEvent.type, pi->heldEvent.x, - pi->heldEvent.y, pi->heldEvent.z, - pi->heldEvent.flags, pi->heldEvent.absrel, - TRUE); - return TRUE; - break; - case clearto: - pi->timeoutPending = FALSE; - break; - case gen_down_2: - _KdEnqueuePointerEvent (pi, ButtonPress, x, y, z, 2, absrel, - TRUE); - pi->eventHeld = FALSE; - return TRUE; - break; - case gen_up_2: - _KdEnqueuePointerEvent (pi, ButtonRelease, x, y, z, 2, absrel, - TRUE); - return TRUE; - break; - } - } - pi->mouseState = t->nextState; - return FALSE; -} - -static int -KdHandlePointerEvent (KdPointerInfo *pi, int type, int x, int y, int z, int b, - int absrel) -{ - if (pi->emulateMiddleButton) - return KdRunMouseMachine (pi, KdClassifyInput(pi, type, x, y, z, b), - type, x, y, z, b, absrel); - return FALSE; -} - -static void -KdReceiveTimeout (KdPointerInfo *pi) -{ - KdRunMouseMachine (pi, timeout, 0, 0, 0, 0, 0, 0); -} - -/* - * kdCheckTermination - * - * This function checks for the key sequence that terminates the server. When - * detected, it sets the dispatchException flag and returns. The key sequence - * is: - * Control-Alt - * It's assumed that the server will be waken up by the caller when this - * function returns. - */ - -extern int nClients; - -void -KdReleaseAllKeys (void) -{ -#if 0 - int key, nEvents, i; - KdKeyboardInfo *ki; - - KdBlockSigio (); - - for (ki = kdKeyboards; ki; ki = ki->next) { - for (key = ki->keySyms.minKeyCode; key < ki->keySyms.maxKeyCode; - key++) { - if (key_is_down(ki->dixdev, key, KEY_POSTED | KEY_PROCESSED)) { - KdHandleKeyboardEvent(ki, KeyRelease, key); - GetEventList(&kdEvents); - nEvents = GetKeyboardEvents(kdEvents, ki->dixdev, KeyRelease, key); - for (i = 0; i < nEvents; i++) - KdQueueEvent (ki->dixdev, (kdEvents + i)->event); - } - } - } - - KdUnblockSigio (); -#endif -} - -static void -KdCheckLock (void) -{ - KeyClassPtr keyc = NULL; - Bool isSet = FALSE, shouldBeSet = FALSE; - KdKeyboardInfo *tmp = NULL; - - for (tmp = kdKeyboards; tmp; tmp = tmp->next) { - if (tmp->LockLed && tmp->dixdev && tmp->dixdev->key) { - keyc = tmp->dixdev->key; - isSet = (tmp->leds & (1 << (tmp->LockLed-1))) != 0; - /* FIXME: Just use XKB indicators! */ - shouldBeSet = !!(XkbStateFieldFromRec(&keyc->xkbInfo->state) & LockMask); - if (isSet != shouldBeSet) - KdSetLed (tmp, tmp->LockLed, shouldBeSet); - } - } -} - -void -KdEnqueueKeyboardEvent(KdKeyboardInfo *ki, - unsigned char scan_code, - unsigned char is_up) -{ - unsigned char key_code; - KeyClassPtr keyc = NULL; - KeybdCtrl *ctrl = NULL; - int type, nEvents, i; - - if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed || !ki->dixdev->key) - return; - - keyc = ki->dixdev->key; - ctrl = &ki->dixdev->kbdfeed->ctrl; - - if (scan_code >= ki->minScanCode && scan_code <= ki->maxScanCode) - { - key_code = scan_code + KD_MIN_KEYCODE - ki->minScanCode; - - /* - * Set up this event -- the type may be modified below - */ - if (is_up) - type = KeyRelease; - else - type = KeyPress; - - GetEventList(&kdEvents); - - nEvents = GetKeyboardEvents(kdEvents, ki->dixdev, type, key_code); - for (i = 0; i < nEvents; i++) - KdQueueEvent(ki->dixdev, (InternalEvent *)((kdEvents + i)->event)); - } - else { - ErrorF("driver %s wanted to post scancode %d outside of [%d, %d]!\n", - ki->name, scan_code, ki->minScanCode, ki->maxScanCode); - } -} - -/* - * kdEnqueuePointerEvent - * - * This function converts hardware mouse event information into X event - * information. A mouse movement event is passed off to MI to generate - * a MotionNotify event, if appropriate. Button events are created and - * passed off to MI for enqueueing. - */ - -/* FIXME do something a little more clever to deal with multiple axes here */ -void -KdEnqueuePointerEvent(KdPointerInfo *pi, unsigned long flags, int rx, int ry, - int rz) -{ - CARD32 ms; - unsigned char buttons; - int x, y, z; - int (*matrix)[3] = kdPointerMatrix.matrix; - unsigned long button; - int n; - int dixflags = 0; - - if (!pi) - return; - - ms = GetTimeInMillis(); - - /* we don't need to transform z, so we don't. */ - if (flags & KD_MOUSE_DELTA) { - if (pi->transformCoordinates) { - x = matrix[0][0] * rx + matrix[0][1] * ry; - y = matrix[1][0] * rx + matrix[1][1] * ry; - } - else { - x = rx; - y = ry; - } - } - else { - if (pi->transformCoordinates) { - x = matrix[0][0] * rx + matrix[0][1] * ry + matrix[0][2]; - y = matrix[1][0] * rx + matrix[1][1] * ry + matrix[1][2]; - } - else { - x = rx; - y = ry; - } - } - z = rz; - - if (flags & KD_MOUSE_DELTA) - { - if (x || y || z) - { - dixflags = POINTER_RELATIVE | POINTER_ACCELERATE; - _KdEnqueuePointerEvent(pi, MotionNotify, x, y, z, 0, dixflags, FALSE); - } - } else - { - dixflags = POINTER_ABSOLUTE; - if (x != pi->dixdev->last.valuators[0] || - y != pi->dixdev->last.valuators[1]) - _KdEnqueuePointerEvent(pi, MotionNotify, x, y, z, 0, dixflags, FALSE); - } - - buttons = flags; - - for (button = KD_BUTTON_1, n = 1; n <= pi->nButtons; - button <<= 1, n++) { - if (((pi->buttonState & button) ^ (buttons & button)) && - !(buttons & button)) { - _KdEnqueuePointerEvent(pi, ButtonRelease, x, y, z, n, - dixflags, FALSE); - } - } - for (button = KD_BUTTON_1, n = 1; n <= pi->nButtons; - button <<= 1, n++) { - if (((pi->buttonState & button) ^ (buttons & button)) && - (buttons & button)) { - _KdEnqueuePointerEvent(pi, ButtonPress, x, y, z, n, - dixflags, FALSE); - } - } - - pi->buttonState = buttons; -} - -void -_KdEnqueuePointerEvent (KdPointerInfo *pi, int type, int x, int y, int z, - int b, int absrel, Bool force) -{ - int nEvents = 0, i = 0; - int valuators[3] = { x, y, z }; - - /* TRUE from KdHandlePointerEvent, means 'we swallowed the event'. */ - if (!force && KdHandlePointerEvent(pi, type, x, y, z, b, absrel)) - return; - - GetEventList(&kdEvents); - nEvents = GetPointerEvents(kdEvents, pi->dixdev, type, b, absrel, - 0, 3, valuators); - for (i = 0; i < nEvents; i++) - KdQueueEvent(pi->dixdev, (InternalEvent *)((kdEvents + i)->event)); -} - -void -KdBlockHandler (int screen, - pointer blockData, - pointer timeout, - pointer readmask) -{ - KdPointerInfo *pi; - int myTimeout=0; - - for (pi = kdPointers; pi; pi = pi->next) - { - if (pi->timeoutPending) - { - int ms; - - ms = pi->emulationTimeout - GetTimeInMillis (); - if (ms < 1) - ms = 1; - if(mspollEvents) - { - (*kdOsFuncs->pollEvents)(); - myTimeout=20; - } - if(myTimeout>0) - AdjustWaitForDelay (timeout, myTimeout); -} - -void -KdWakeupHandler (int screen, - pointer data, - unsigned long lresult, - pointer readmask) -{ - int result = (int) lresult; - fd_set *pReadmask = (fd_set *) readmask; - int i; - KdPointerInfo *pi; - - if (kdInputEnabled && result > 0) - { - for (i = 0; i < kdNumInputFds; i++) - if (FD_ISSET (kdInputFds[i].fd, pReadmask)) - { - KdBlockSigio (); - (*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure); - KdUnblockSigio (); - } - } - for (pi = kdPointers; pi; pi = pi->next) - { - if (pi->timeoutPending) - { - if ((long) (GetTimeInMillis () - pi->emulationTimeout) >= 0) - { - pi->timeoutPending = FALSE; - KdBlockSigio (); - KdReceiveTimeout (pi); - KdUnblockSigio (); - } - } - } - if (kdSwitchPending) - KdProcessSwitch (); -} - -#define KdScreenOrigin(pScreen) (&(KdGetScreenPriv(pScreen)->screen->origin)) - -static Bool -KdCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) -{ - ScreenPtr pScreen = *ppScreen; - ScreenPtr pNewScreen; - int n; - int dx, dy; - int best_x, best_y; - int n_best_x, n_best_y; - CARD32 ms; - - if (kdDisableZaphod || screenInfo.numScreens <= 1) - return FALSE; - - if (0 <= *x && *x < pScreen->width && 0 <= *y && *y < pScreen->height) - return FALSE; - - ms = GetTimeInMillis (); - if (kdOffScreen && (int) (ms - kdOffScreenTime) < 1000) - return FALSE; - kdOffScreen = TRUE; - kdOffScreenTime = ms; - n_best_x = -1; - best_x = 32767; - n_best_y = -1; - best_y = 32767; - for (n = 0; n < screenInfo.numScreens; n++) - { - pNewScreen = screenInfo.screens[n]; - if (pNewScreen == pScreen) - continue; - dx = KdScreenOrigin(pNewScreen)->x - KdScreenOrigin(pScreen)->x; - dy = KdScreenOrigin(pNewScreen)->y - KdScreenOrigin(pScreen)->y; - if (*x < 0) - { - if (dx <= 0 && -dx < best_x) - { - best_x = -dx; - n_best_x = n; - } - } - else if (*x >= pScreen->width) - { - if (dx >= 0 && dx < best_x) - { - best_x = dx; - n_best_x = n; - } - } - if (*y < 0) - { - if (dy <= 0 && -dy < best_y) - { - best_y = -dy; - n_best_y = n; - } - } - else if (*y >= pScreen->height) - { - if (dy >= 0 && dy < best_y) - { - best_y = dy; - n_best_y = n; - } - } - } - if (best_y < best_x) - n_best_x = n_best_y; - if (n_best_x == -1) - return FALSE; - pNewScreen = screenInfo.screens[n_best_x]; - - if (*x < 0) - *x += pNewScreen->width; - if (*y < 0) - *y += pNewScreen->height; - - if (*x >= pScreen->width) - *x -= pScreen->width; - if (*y >= pScreen->height) - *y -= pScreen->height; - - *ppScreen = pNewScreen; - return TRUE; -} - -static void -KdCrossScreen(ScreenPtr pScreen, Bool entering) -{ -#ifndef XIPAQ - if (entering) - KdEnableScreen (pScreen); - else - KdDisableScreen (pScreen); -#endif -} - -int KdCurScreen; /* current event screen */ - -static void -KdWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) -{ - KdBlockSigio (); - KdCurScreen = pScreen->myNum; - miPointerWarpCursor(pDev, pScreen, x, y); - KdUnblockSigio (); -} - -miPointerScreenFuncRec kdPointerScreenFuncs = -{ - KdCursorOffScreen, - KdCrossScreen, - KdWarpCursor -}; - -void -ProcessInputEvents (void) -{ - mieqProcessInputEvents(); - miPointerUpdateSprite(inputInfo.pointer); - if (kdSwitchPending) - KdProcessSwitch (); - KdCheckLock (); -} - -/* FIXME use XSECURITY to work out whether the client should be allowed to - * open and close. */ -void -OpenInputDevice(DeviceIntPtr pDev, ClientPtr client, int *status) -{ - if (!pDev) - *status = BadDevice; - else - *status = Success; -} - -void -CloseInputDevice(DeviceIntPtr pDev, ClientPtr client) -{ - return; -} - -/* We initialise all input devices at startup. */ -void -AddOtherInputDevices(void) -{ - return; -} - -/* At the moment, absolute/relative is up to the client. */ -int -SetDeviceMode(register ClientPtr client, DeviceIntPtr pDev, int mode) -{ - return BadMatch; -} - -int -SetDeviceValuators(register ClientPtr client, DeviceIntPtr pDev, - int *valuators, int first_valuator, int num_valuators) -{ - return BadMatch; -} - -int -ChangeDeviceControl(register ClientPtr client, DeviceIntPtr pDev, - xDeviceCtl *control) -{ - switch (control->control) { - case DEVICE_RESOLUTION: - /* FIXME do something more intelligent here */ - return BadMatch; - - case DEVICE_ABS_CALIB: - case DEVICE_ABS_AREA: - return Success; - - case DEVICE_CORE: - return BadMatch; - case DEVICE_ENABLE: - return Success; - - default: - return BadMatch; - } - - /* NOTREACHED */ - return BadImplementation; -} - -int -NewInputDeviceRequest(InputOption *options, InputAttributes *attrs, - DeviceIntPtr *pdev) -{ - InputOption *option = NULL; - KdPointerInfo *pi = NULL; - KdKeyboardInfo *ki = NULL; - - for (option = options; option; option = option->next) { - if (strcmp(option->key, "type") == 0) { - if (strcmp(option->value, "pointer") == 0) { - pi = KdNewPointer(); - if (!pi) - return BadAlloc; - } - else if (strcmp(option->value, "keyboard") == 0) { - ki = KdNewKeyboard(); - if (!ki) - return BadAlloc; - } - else { - ErrorF("unrecognised device type!\n"); - return BadValue; - } - } -#ifdef CONFIG_HAL - else if (strcmp(option->key, "_source") == 0 && - strcmp(option->value, "server/hal") == 0) - { - ErrorF("Ignoring device from HAL.\n"); - return BadValue; - } -#endif -#ifdef CONFIG_UDEV - else if (strcmp(option->key, "_source") == 0 && - strcmp(option->value, "server/udev") == 0) - { - ErrorF("Ignoring device from udev.\n"); - return BadValue; - } -#endif - } - - if (!ki && !pi) { - ErrorF("unrecognised device identifier!\n"); - return BadValue; - } - - /* FIXME: change this code below to use KdParseKbdOptions and - * KdParsePointerOptions */ - for (option = options; option; option = option->next) { - if (strcmp(option->key, "device") == 0) { - if (pi && option->value) - pi->path = strdup(option->value); - else if (ki && option->value) - ki->path = strdup(option->value); - } - else if (strcmp(option->key, "driver") == 0) { - if (pi) { - pi->driver = KdFindPointerDriver(option->value); - if (!pi->driver) { - ErrorF("couldn't find driver!\n"); - KdFreePointer(pi); - return BadValue; - } - pi->options = options; - } - else if (ki) { - ki->driver = KdFindKeyboardDriver(option->value); - if (!ki->driver) { - ErrorF("couldn't find driver!\n"); - KdFreeKeyboard(ki); - return BadValue; - } - ki->options = options; - } - } - } - - if (pi) { - if (KdAddPointer(pi) != Success || - ActivateDevice(pi->dixdev, TRUE) != Success || - EnableDevice(pi->dixdev, TRUE) != TRUE) { - ErrorF("couldn't add or enable pointer\n"); - return BadImplementation; - } - } - else if (ki) { - if (KdAddKeyboard(ki) != Success || - ActivateDevice(ki->dixdev, TRUE) != Success || - EnableDevice(ki->dixdev, TRUE) != TRUE) { - ErrorF("couldn't add or enable keyboard\n"); - return BadImplementation; - } - } - - if (pi) { - *pdev = pi->dixdev; - } else if(ki) { - *pdev = ki->dixdev; - } - - return Success; -} - -void -DeleteInputDeviceRequest(DeviceIntPtr pDev) -{ - RemoveDevice(pDev, TRUE); -} +/* + * Copyright © 1999 Keith Packard + * Copyright © 2006 Nokia Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the authors not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "kdrive.h" +#include "inputstr.h" + +#define XK_PUBLISHING +#include +#if HAVE_X11_XF86KEYSYM_H +#include +#endif +#include +#include +#ifdef sun +#include /* needed for FNONBLOCK & FASYNC */ +#endif + +#include "xkbsrv.h" + +#include +#include +#include "XIstubs.h" /* even though we don't use stubs. cute, no? */ +#include "exevents.h" +#include "extinit.h" +#include "exglobals.h" +#include "eventstr.h" +#include "xserver-properties.h" + +#define AtomFromName(x) MakeAtom(x, strlen(x), 1) + +struct KdConfigDevice { + char *line; + struct KdConfigDevice *next; +}; + +/* kdKeyboards and kdPointers hold all the real devices. */ +static KdKeyboardInfo *kdKeyboards = NULL; +static KdPointerInfo *kdPointers = NULL; +static struct KdConfigDevice *kdConfigKeyboards = NULL; +static struct KdConfigDevice *kdConfigPointers = NULL; + +static KdKeyboardDriver *kdKeyboardDrivers = NULL; +static KdPointerDriver *kdPointerDrivers = NULL; + +static EventListPtr kdEvents = NULL; + +static Bool kdInputEnabled; +static Bool kdOffScreen; +static unsigned long kdOffScreenTime; +static KdPointerMatrix kdPointerMatrix = { + { { 1, 0, 0 }, + { 0, 1, 0 } } +}; + +void KdResetInputMachine (void); + +#define KD_MAX_INPUT_FDS 8 + +typedef struct _kdInputFd { + int fd; + void (*read) (int fd, void *closure); + int (*enable) (int fd, void *closure); + void (*disable) (int fd, void *closure); + void *closure; +} KdInputFd; + +static KdInputFd kdInputFds[KD_MAX_INPUT_FDS]; +static int kdNumInputFds; + +extern Bool kdRawPointerCoordinates; + +static void +KdSigio (int sig) +{ + int i; + + for (i = 0; i < kdNumInputFds; i++) + (*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure); +} + +static void +KdBlockSigio (void) +{ + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGIO); + sigprocmask (SIG_BLOCK, &set, 0); +} + +static void +KdUnblockSigio (void) +{ + sigset_t set; + + sigemptyset (&set); + sigaddset (&set, SIGIO); + sigprocmask (SIG_UNBLOCK, &set, 0); +} + +#ifdef DEBUG_SIGIO + +void +KdAssertSigioBlocked (char *where) +{ + sigset_t set, old; + + sigemptyset (&set); + sigprocmask (SIG_BLOCK, &set, &old); + if (!sigismember (&old, SIGIO)) { + ErrorF ("SIGIO not blocked at %s\n", where); + KdBacktrace(0); + } +} + +#else + +#define KdAssertSigioBlocked(s) + +#endif + +static int kdnFds; + +#ifdef FNONBLOCK +#define NOBLOCK FNONBLOCK +#else +#define NOBLOCK FNDELAY +#endif + +void +KdResetInputMachine (void) +{ + KdPointerInfo *pi; + + for (pi = kdPointers; pi; pi = pi->next) { + pi->mouseState = start; + pi->eventHeld = FALSE; + } +} + +static void +KdNonBlockFd (int fd) +{ + int flags; + flags = fcntl (fd, F_GETFL); + flags |= FASYNC|NOBLOCK; + fcntl (fd, F_SETFL, flags); +} + +static void +KdAddFd (int fd) +{ + struct sigaction act; + sigset_t set; + + kdnFds++; + fcntl (fd, F_SETOWN, getpid()); + KdNonBlockFd (fd); + AddEnabledDevice (fd); + memset (&act, '\0', sizeof act); + act.sa_handler = KdSigio; + sigemptyset (&act.sa_mask); + sigaddset (&act.sa_mask, SIGIO); + sigaddset (&act.sa_mask, SIGALRM); + sigaddset (&act.sa_mask, SIGVTALRM); + sigaction (SIGIO, &act, 0); + sigemptyset (&set); + sigprocmask (SIG_SETMASK, &set, 0); +} + +static void +KdRemoveFd (int fd) +{ + struct sigaction act; + int flags; + + kdnFds--; + RemoveEnabledDevice (fd); + flags = fcntl (fd, F_GETFL); + flags &= ~(FASYNC|NOBLOCK); + fcntl (fd, F_SETFL, flags); + if (kdnFds == 0) + { + memset (&act, '\0', sizeof act); + act.sa_handler = SIG_IGN; + sigemptyset (&act.sa_mask); + sigaction (SIGIO, &act, 0); + } +} + +Bool +KdRegisterFd (int fd, void (*read) (int fd, void *closure), void *closure) +{ + if (kdNumInputFds == KD_MAX_INPUT_FDS) + return FALSE; + kdInputFds[kdNumInputFds].fd = fd; + kdInputFds[kdNumInputFds].read = read; + kdInputFds[kdNumInputFds].enable = 0; + kdInputFds[kdNumInputFds].disable = 0; + kdInputFds[kdNumInputFds].closure = closure; + kdNumInputFds++; + if (kdInputEnabled) + KdAddFd (fd); + return TRUE; +} + +void +KdUnregisterFd (void *closure, int fd, Bool do_close) +{ + int i, j; + + for (i = 0; i < kdNumInputFds; i++) { + if (kdInputFds[i].closure == closure && + (fd == -1 || kdInputFds[i].fd == fd)) { + if (kdInputEnabled) + KdRemoveFd (kdInputFds[i].fd); + if (do_close) + close (kdInputFds[i].fd); + kdNumInputFds--; + for (j = i; j < kdNumInputFds; j++) + kdInputFds[j] = kdInputFds[j+1]; + break; + } + } +} + +void +KdUnregisterFds (void *closure, Bool do_close) +{ + KdUnregisterFd(closure, -1, do_close); +} + +void +KdDisableInput (void) +{ + KdKeyboardInfo *ki; + KdPointerInfo *pi; + int found = 0, i = 0; + + KdBlockSigio(); + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->driver && ki->driver->Disable) + (*ki->driver->Disable) (ki); + } + + for (pi = kdPointers; pi; pi = pi->next) { + if (pi->driver && pi->driver->Disable) + (*pi->driver->Disable) (pi); + } + + if (kdNumInputFds) { + ErrorF("[KdDisableInput] Buggy drivers: still %d input fds left!", + kdNumInputFds); + i = 0; + while (i < kdNumInputFds) { + found = 0; + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki == kdInputFds[i].closure) { + ErrorF(" fd %d belongs to keybd driver %s\n", + kdInputFds[i].fd, + ki->driver && ki->driver->name ? + ki->driver->name : "(unnamed!)"); + found = 1; + break; + } + } + + if (found) { + i++; + continue; + } + + for (pi = kdPointers; pi; pi = pi->next) { + if (pi == kdInputFds[i].closure) { + ErrorF(" fd %d belongs to pointer driver %s\n", + kdInputFds[i].fd, + pi->driver && pi->driver->name ? + pi->driver->name : "(unnamed!)"); + break; + } + } + + if (found) { + i++; + continue; + } + + ErrorF(" fd %d not claimed by any active device!\n", + kdInputFds[i].fd); + KdUnregisterFd(kdInputFds[i].closure, kdInputFds[i].fd, TRUE); + } + } + + kdInputEnabled = FALSE; +} + +void +KdEnableInput (void) +{ + InternalEvent ev; + KdKeyboardInfo *ki; + KdPointerInfo *pi; + + kdInputEnabled = TRUE; + + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->driver && ki->driver->Enable) + (*ki->driver->Enable) (ki); + } + + for (pi = kdPointers; pi; pi = pi->next) { + if (pi->driver && pi->driver->Enable) + (*pi->driver->Enable) (pi); + } + + /* reset screen saver */ + ev.any.time = GetTimeInMillis (); + NoticeEventTime (&ev); + + KdUnblockSigio (); +} + +static KdKeyboardDriver * +KdFindKeyboardDriver (char *name) +{ + KdKeyboardDriver *ret; + + /* ask a stupid question ... */ + if (!name) + return NULL; + + for (ret = kdKeyboardDrivers; ret; ret = ret->next) { + if (strcmp(ret->name, name) == 0) + return ret; + } + + return NULL; +} + +static KdPointerDriver * +KdFindPointerDriver (char *name) +{ + KdPointerDriver *ret; + + /* ask a stupid question ... */ + if (!name) + return NULL; + + for (ret = kdPointerDrivers; ret; ret = ret->next) { + if (strcmp(ret->name, name) == 0) + return ret; + } + + return NULL; +} + +static int +KdPointerProc(DeviceIntPtr pDevice, int onoff) +{ + DevicePtr pDev = (DevicePtr)pDevice; + KdPointerInfo *pi; + Atom xiclass; + Atom *btn_labels; + Atom *axes_labels; + + if (!pDev) + return BadImplementation; + + for (pi = kdPointers; pi; pi = pi->next) { + if (pi->dixdev && pi->dixdev->id == pDevice->id) + break; + } + + if (!pi || !pi->dixdev || pi->dixdev->id != pDevice->id) { + ErrorF("[KdPointerProc] Failed to find pointer for device %d!\n", + pDevice->id); + return BadImplementation; + } + + switch (onoff) + { + case DEVICE_INIT: +#ifdef DEBUG + ErrorF("initialising pointer %s ...\n", pi->name); +#endif + if (!pi->driver) { + if (!pi->driverPrivate) { + ErrorF("no driver specified for %s\n", pi->name); + return BadImplementation; + } + + pi->driver = KdFindPointerDriver(pi->driverPrivate); + if (!pi->driver) { + ErrorF("Couldn't find pointer driver %s\n", + pi->driverPrivate ? (char *) pi->driverPrivate : + "(unnamed)"); + return !Success; + } + free(pi->driverPrivate); + pi->driverPrivate = NULL; + } + + if (!pi->driver->Init) { + ErrorF("no init function\n"); + return BadImplementation; + } + + if ((*pi->driver->Init) (pi) != Success) { + return !Success; + } + + btn_labels = calloc(pi->nButtons, sizeof(Atom)); + if (!btn_labels) + return BadAlloc; + axes_labels = calloc(pi->nAxes, sizeof(Atom)); + if (!axes_labels) { + free(btn_labels); + return BadAlloc; + } + + switch(pi->nAxes) + { + default: + case 7: + btn_labels[6] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_RIGHT); + case 6: + btn_labels[5] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_HWHEEL_LEFT); + case 5: + btn_labels[4] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_DOWN); + case 4: + btn_labels[3] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_WHEEL_UP); + case 3: + btn_labels[2] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_RIGHT); + case 2: + btn_labels[1] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_MIDDLE); + case 1: + btn_labels[0] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT); + case 0: + break; + } + + if (pi->nAxes >= 2) { + axes_labels[0] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_X); + axes_labels[1] = XIGetKnownProperty(AXIS_LABEL_PROP_REL_Y); + } + + InitPointerDeviceStruct(pDev, pi->map, pi->nButtons, btn_labels, + (PtrCtrlProcPtr)NoopDDA, + GetMotionHistorySize(), pi->nAxes, axes_labels); + + free(btn_labels); + free(axes_labels); + + if (pi->inputClass == KD_TOUCHSCREEN) { + InitAbsoluteClassDeviceStruct(pDevice); + xiclass = AtomFromName(XI_TOUCHSCREEN); + } + else { + xiclass = AtomFromName(XI_MOUSE); + } + + AssignTypeAndName(pi->dixdev, xiclass, + pi->name ? pi->name : "Generic KDrive Pointer"); + + return Success; + + case DEVICE_ON: + if (pDev->on == TRUE) + return Success; + + if (!pi->driver->Enable) { + ErrorF("no enable function\n"); + return BadImplementation; + } + + if ((*pi->driver->Enable) (pi) == Success) { + pDev->on = TRUE; + return Success; + } + else { + return BadImplementation; + } + + return Success; + + case DEVICE_OFF: + if (pDev->on == FALSE) { + return Success; + } + + if (!pi->driver->Disable) { + return BadImplementation; + } + else { + (*pi->driver->Disable) (pi); + pDev->on = FALSE; + return Success; + } + + return Success; + + case DEVICE_CLOSE: + if (pDev->on) { + if (!pi->driver->Disable) { + return BadImplementation; + } + (*pi->driver->Disable) (pi); + pDev->on = FALSE; + } + + if (!pi->driver->Fini) + return BadImplementation; + + (*pi->driver->Fini) (pi); + + KdRemovePointer(pi); + + return Success; + } + + /* NOTREACHED */ + return BadImplementation; +} + +Bool +LegalModifier(unsigned int key, DeviceIntPtr pDev) +{ + return TRUE; +} + +static void +KdBell (int volume, DeviceIntPtr pDev, pointer arg, int something) +{ + 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); +} + +void +DDXRingBell(int volume, int pitch, int duration) +{ + KdKeyboardInfo *ki = NULL; + + if (kdOsFuncs->Bell) { + (*kdOsFuncs->Bell)(volume, pitch, duration); + } + else { + for (ki = kdKeyboards; ki; ki = ki->next) { + if (ki->dixdev->coreEvents) + KdRingBell(ki, volume, pitch, duration); + } + } +} + +void +KdRingBell(KdKeyboardInfo *ki, int volume, int pitch, int duration) +{ + if (!ki || !ki->driver || !ki->driver->Bell) + return; + + if (kdInputEnabled) + (*ki->driver->Bell) (ki, volume, pitch, duration); +} + + +static void +KdSetLeds (KdKeyboardInfo *ki, int leds) +{ + if (!ki || !ki->driver) + return; + + if (kdInputEnabled) { + if (ki->driver->Leds) + (*ki->driver->Leds) (ki, leds); + } +} + +void +KdSetLed (KdKeyboardInfo *ki, int led, Bool on) +{ + if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed) + return; + + NoteLedState (ki->dixdev, led, on); + KdSetLeds (ki, ki->dixdev->kbdfeed->ctrl.leds); +} + +void +KdSetPointerMatrix (KdPointerMatrix *matrix) +{ + kdPointerMatrix = *matrix; +} + +void +KdComputePointerMatrix (KdPointerMatrix *m, Rotation randr, int width, + int height) +{ + int x_dir = 1, y_dir = 1; + int i, j; + int size[2]; + + size[0] = width; size[1] = height; + if (randr & RR_Reflect_X) + x_dir = -1; + if (randr & RR_Reflect_Y) + y_dir = -1; + switch (randr & (RR_Rotate_All)) { + case RR_Rotate_0: + m->matrix[0][0] = x_dir; m->matrix[0][1] = 0; + m->matrix[1][0] = 0; m->matrix[1][1] = y_dir; + break; + case RR_Rotate_90: + m->matrix[0][0] = 0; m->matrix[0][1] = -x_dir; + m->matrix[1][0] = y_dir; m->matrix[1][1] = 0; + break; + case RR_Rotate_180: + m->matrix[0][0] = -x_dir; m->matrix[0][1] = 0; + m->matrix[1][0] = 0; m->matrix[1][1] = -y_dir; + break; + case RR_Rotate_270: + m->matrix[0][0] = 0; m->matrix[0][1] = x_dir; + m->matrix[1][0] = -y_dir; m->matrix[1][1] = 0; + break; + } + for (i = 0; i < 2; i++) + { + m->matrix[i][2] = 0; + for (j = 0 ; j < 2; j++) + if (m->matrix[i][j] < 0) + m->matrix[i][2] = size[j] - 1; + } +} + +void +KdScreenToPointerCoords (int *x, int *y) +{ + int (*m)[3] = kdPointerMatrix.matrix; + int div = m[0][1] * m[1][0] - m[1][1] * m[0][0]; + int sx = *x; + int sy = *y; + + *x = (m[0][1] * sy - m[0][1] * m[1][2] + m[1][1] * m[0][2] - m[1][1] * sx) / div; + *y = (m[1][0] * sx + m[0][0] * m[1][2] - m[1][0] * m[0][2] - m[0][0] * sy) / div; +} + +static void +KdKbdCtrl (DeviceIntPtr pDevice, KeybdCtrl *ctrl) +{ + 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; +} + +extern KeybdCtrl defaultKeyboardControl; + +static int +KdKeyboardProc(DeviceIntPtr pDevice, int onoff) +{ + Bool ret; + DevicePtr pDev = (DevicePtr)pDevice; + KdKeyboardInfo *ki; + Atom xiclass; + XkbRMLVOSet rmlvo; + + if (!pDev) + return BadImplementation; + + 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) { + return BadImplementation; + } + + switch (onoff) + { + case DEVICE_INIT: +#ifdef DEBUG + ErrorF("initialising keyboard %s\n", ki->name); +#endif + if (!ki->driver) { + if (!ki->driverPrivate) { + ErrorF("no driver specified!\n"); + return BadImplementation; + } + + ki->driver = KdFindKeyboardDriver(ki->driverPrivate); + if (!ki->driver) { + ErrorF("Couldn't find keyboard driver %s\n", + ki->driverPrivate ? (char *) ki->driverPrivate : + "(unnamed)"); + return !Success; + } + free(ki->driverPrivate); + ki->driverPrivate = NULL; + } + + if (!ki->driver->Init) { + ErrorF("Keyboard %s: no init function\n", ki->name); + return BadImplementation; + } + + if ((*ki->driver->Init) (ki) != Success) { + return !Success; + } + + memset(&rmlvo, 0, sizeof(rmlvo)); + rmlvo.rules = ki->xkbRules; + rmlvo.model = ki->xkbModel; + rmlvo.layout = ki->xkbLayout; + rmlvo.variant = ki->xkbVariant; + rmlvo.options = ki->xkbOptions; + ret = InitKeyboardDeviceStruct (pDevice, &rmlvo, KdBell, KdKbdCtrl); + if (!ret) { + ErrorF("Couldn't initialise keyboard %s\n", ki->name); + return BadImplementation; + } + + xiclass = AtomFromName(XI_KEYBOARD); + AssignTypeAndName(pDevice, xiclass, + ki->name ? ki->name : "Generic KDrive Keyboard"); + + KdResetInputMachine(); + + return Success; + + case DEVICE_ON: + if (pDev->on == TRUE) + return Success; + + if (!ki->driver->Enable) + return BadImplementation; + + if ((*ki->driver->Enable) (ki) != Success) { + return BadMatch; + } + + pDev->on = TRUE; + return Success; + + case DEVICE_OFF: + if (pDev->on == FALSE) + return Success; + + if (!ki->driver->Disable) + return BadImplementation; + + (*ki->driver->Disable) (ki); + pDev->on = FALSE; + + return Success; + + break; + + case DEVICE_CLOSE: + if (pDev->on) { + if (!ki->driver->Disable) + return BadImplementation; + + (*ki->driver->Disable) (ki); + pDev->on = FALSE; + } + + if (!ki->driver->Fini) + return BadImplementation; + + (*ki->driver->Fini) (ki); + + KdRemoveKeyboard(ki); + + return Success; + } + + /* NOTREACHED */ + return BadImplementation; +} + +void +KdAddPointerDriver (KdPointerDriver *driver) +{ + KdPointerDriver **prev; + + if (!driver) + return; + + for (prev = &kdPointerDrivers; *prev; prev = &(*prev)->next) { + if (*prev == driver) + return; + } + *prev = driver; +} + +void +KdRemovePointerDriver (KdPointerDriver *driver) +{ + KdPointerDriver *tmp; + + if (!driver) + return; + + /* FIXME remove all pointers using this driver */ + for (tmp = kdPointerDrivers; tmp; tmp = tmp->next) { + if (tmp->next == driver) + tmp->next = driver->next; + } + if (tmp == driver) + tmp = NULL; +} + +void +KdAddKeyboardDriver (KdKeyboardDriver *driver) +{ + KdKeyboardDriver **prev; + + if (!driver) + return; + + for (prev = &kdKeyboardDrivers; *prev; prev = &(*prev)->next) { + if (*prev == driver) + return; + } + *prev = driver; +} + +void +KdRemoveKeyboardDriver (KdKeyboardDriver *driver) +{ + KdKeyboardDriver *tmp; + + if (!driver) + return; + + /* FIXME remove all keyboards using this driver */ + for (tmp = kdKeyboardDrivers; tmp; tmp = tmp->next) { + if (tmp->next == driver) + tmp->next = driver->next; + } + if (tmp == driver) + tmp = NULL; +} + +KdKeyboardInfo * +KdNewKeyboard (void) +{ + KdKeyboardInfo *ki = calloc(sizeof(KdKeyboardInfo), 1); + if (!ki) + return NULL; + + ki->minScanCode = 0; + ki->maxScanCode = 0; + ki->leds = 0; + ki->bellPitch = 1000; + ki->bellDuration = 200; + ki->next = NULL; + ki->options = NULL; + ki->xkbRules = strdup(XKB_DFLT_RULES); + ki->xkbModel = strdup(XKB_DFLT_MODEL); + ki->xkbLayout = strdup(XKB_DFLT_LAYOUT); + ki->xkbVariant = strdup(XKB_DFLT_VARIANT); + ki->xkbOptions = strdup(XKB_DFLT_OPTIONS); + + return ki; +} + +int +KdAddConfigKeyboard (char *keyboard) +{ + struct KdConfigDevice **prev, *new; + + if (!keyboard) + return Success; + + new = (struct KdConfigDevice *) calloc(sizeof(struct KdConfigDevice), 1); + if (!new) + return BadAlloc; + + new->line = xstrdup(keyboard); + new->next = NULL; + + for (prev = &kdConfigKeyboards; *prev; prev = &(*prev)->next); + *prev = new; + + return Success; +} + +int +KdAddKeyboard (KdKeyboardInfo *ki) +{ + KdKeyboardInfo **prev; + + if (!ki) + return !Success; + + ki->dixdev = AddInputDevice(serverClient, KdKeyboardProc, TRUE); + if (!ki->dixdev) { + ErrorF("Couldn't register keyboard device %s\n", + ki->name ? ki->name : "(unnamed)"); + return !Success; + } + + ki->dixdev->deviceGrab.ActivateGrab = ActivateKeyboardGrab; + ki->dixdev->deviceGrab.DeactivateGrab = DeactivateKeyboardGrab; + RegisterOtherDevice(ki->dixdev); + +#ifdef DEBUG + ErrorF("added keyboard %s with dix id %d\n", ki->name, ki->dixdev->id); +#endif + + for (prev = &kdKeyboards; *prev; prev = &(*prev)->next); + *prev = ki; + + return Success; +} + +void +KdRemoveKeyboard (KdKeyboardInfo *ki) +{ + KdKeyboardInfo **prev; + + if (!ki) + return; + + for (prev = &kdKeyboards; *prev; prev = &(*prev)->next) { + if (*prev == ki) { + *prev = ki->next; + break; + } + } + + KdFreeKeyboard(ki); +} + +int +KdAddConfigPointer (char *pointer) +{ + struct KdConfigDevice **prev, *new; + + if (!pointer) + return Success; + + new = (struct KdConfigDevice *) calloc(sizeof(struct KdConfigDevice), 1); + if (!new) + return BadAlloc; + + new->line = xstrdup(pointer); + new->next = NULL; + + for (prev = &kdConfigPointers; *prev; prev = &(*prev)->next); + *prev = new; + + return Success; +} + +int +KdAddPointer (KdPointerInfo *pi) +{ + KdPointerInfo **prev; + + if (!pi) + return Success; + + pi->mouseState = start; + pi->eventHeld = FALSE; + + pi->dixdev = AddInputDevice(serverClient, KdPointerProc, TRUE); + if (!pi->dixdev) { + ErrorF("Couldn't add pointer device %s\n", + pi->name ? pi->name : "(unnamed)"); + return BadDevice; + } + + pi->dixdev->deviceGrab.ActivateGrab = ActivatePointerGrab; + pi->dixdev->deviceGrab.DeactivateGrab = DeactivatePointerGrab; + RegisterOtherDevice(pi->dixdev); + + for (prev = &kdPointers; *prev; prev = &(*prev)->next); + *prev = pi; + + return Success; +} + +void +KdRemovePointer (KdPointerInfo *pi) +{ + KdPointerInfo **prev; + + if (!pi) + return; + + for (prev = &kdPointers; *prev; prev = &(*prev)->next) { + if (*prev == pi) { + *prev = pi->next; + break; + } + } + + KdFreePointer(pi); +} + +/* + * You can call your kdriver server with something like: + * $ ./hw/kdrive/yourserver/X :1 -mouse evdev,,device=/dev/input/event4 -keybd + * evdev,,device=/dev/input/event1,xkbmodel=abnt2,xkblayout=br + */ +static Bool +KdGetOptions (InputOption **options, char *string) +{ + InputOption *newopt = NULL, **tmpo = NULL; + int tam_key = 0; + + newopt = calloc(1, sizeof (InputOption)); + if (!newopt) + return FALSE; + + for (tmpo = options; *tmpo; tmpo = &(*tmpo)->next) + ; /* Hello, I'm here */ + *tmpo = newopt; + + if (strchr(string, '=')) + { + tam_key = (strchr(string, '=') - string); + newopt->key = (char *)malloc(tam_key); + strncpy(newopt->key, string, tam_key); + newopt->key[tam_key] = '\0'; + newopt->value = xstrdup(strchr(string, '=') + 1); + } + else + { + newopt->key = xstrdup(string); + newopt->value = NULL; + } + newopt->next = NULL; + + return TRUE; +} + +static void +KdParseKbdOptions (KdKeyboardInfo *ki) +{ + InputOption *option = NULL; + + for (option = ki->options; option; option = option->next) + { + if (strcasecmp(option->key, "XkbRules") == 0) + ki->xkbRules = option->value; + else if (strcasecmp(option->key, "XkbModel") == 0) + ki->xkbModel = option->value; + else if (strcasecmp(option->key, "XkbLayout") == 0) + ki->xkbLayout = option->value; + else if (strcasecmp(option->key, "XkbVariant") == 0) + ki->xkbVariant = option->value; + else if (strcasecmp(option->key, "XkbOptions") == 0) + ki->xkbOptions = option->value; + else if (!strcasecmp (option->key, "device")) + ki->path = strdup(option->value); + else + ErrorF("Kbd option key (%s) of value (%s) not assigned!\n", + option->key, option->value); + } +} + +KdKeyboardInfo * +KdParseKeyboard (char *arg) +{ + char save[1024]; + char delim; + InputOption *options = NULL; + KdKeyboardInfo *ki = NULL; + + ki = KdNewKeyboard(); + if (!ki) + return NULL; + + ki->name = strdup("Unknown KDrive Keyboard"); + ki->path = NULL; + ki->driver = NULL; + ki->driverPrivate = NULL; + ki->next = NULL; + + if (!arg) + { + ErrorF("keybd: no arg\n"); + KdFreeKeyboard (ki); + return NULL; + } + + if (strlen (arg) >= sizeof (save)) + { + ErrorF("keybd: arg too long\n"); + KdFreeKeyboard (ki); + return NULL; + } + + arg = KdParseFindNext (arg, ",", save, &delim); + if (!save[0]) + { + ErrorF("keybd: failed on save[0]\n"); + KdFreeKeyboard (ki); + return NULL; + } + + if (strcmp (save, "auto") == 0) + ki->driverPrivate = NULL; + else + ki->driverPrivate = xstrdup(save); + + if (delim != ',') + { + return ki; + } + + arg = KdParseFindNext (arg, ",", save, &delim); + + while (delim == ',') + { + arg = KdParseFindNext (arg, ",", save, &delim); + + if (!KdGetOptions(&options, save)) + { + KdFreeKeyboard(ki); + return NULL; + } + } + + if (options) + { + ki->options = options; + KdParseKbdOptions(ki); + } + + return ki; +} + +static void +KdParsePointerOptions (KdPointerInfo *pi) +{ + InputOption *option = NULL; + + for (option = pi->options; option; option = option->next) + { + if (!strcmp (option->key, "emulatemiddle")) + pi->emulateMiddleButton = TRUE; + else if (!strcmp (option->key, "noemulatemiddle")) + pi->emulateMiddleButton = FALSE; + else if (!strcmp (option->key, "transformcoord")) + pi->transformCoordinates = TRUE; + else if (!strcmp (option->key, "rawcoord")) + pi->transformCoordinates = FALSE; + else if (!strcasecmp (option->key, "device")) + pi->path = strdup(option->value); + else if (!strcasecmp (option->key, "protocol")) + pi->protocol = strdup(option->value); + else + ErrorF("Pointer option key (%s) of value (%s) not assigned!\n", + option->key, option->value); + } +} + +KdPointerInfo * +KdParsePointer (char *arg) +{ + char save[1024]; + char delim; + KdPointerInfo *pi = NULL; + InputOption *options = NULL; + int i = 0; + + pi = KdNewPointer(); + if (!pi) + return NULL; + pi->emulateMiddleButton = kdEmulateMiddleButton; + pi->transformCoordinates = !kdRawPointerCoordinates; + pi->protocol = NULL; + pi->nButtons = 5; /* XXX should not be hardcoded */ + pi->inputClass = KD_MOUSE; + + if (!arg) + { + ErrorF("mouse: no arg\n"); + KdFreePointer (pi); + return NULL; + } + + if (strlen (arg) >= sizeof (save)) + { + ErrorF("mouse: arg too long\n"); + KdFreePointer (pi); + return NULL; + } + arg = KdParseFindNext (arg, ",", save, &delim); + if (!save[0]) + { + ErrorF("failed on save[0]\n"); + KdFreePointer (pi); + return NULL; + } + + if (strcmp(save, "auto") == 0) + pi->driverPrivate = NULL; + else + pi->driverPrivate = xstrdup(save); + + if (delim != ',') + { + return pi; + } + + arg = KdParseFindNext (arg, ",", save, &delim); + + while (delim == ',') + { + arg = KdParseFindNext (arg, ",", save, &delim); + if (save[0] == '{') + { + char *s = save + 1; + i = 0; + while (*s && *s != '}') + { + if ('1' <= *s && *s <= '0' + pi->nButtons) + pi->map[i] = *s - '0'; + else + UseMsg (); + s++; + } + } + else + { + if (!KdGetOptions(&options, save)) + { + KdFreePointer(pi); + return NULL; + } + } + } + + if (options) + { + pi->options = options; + KdParsePointerOptions(pi); + } + + return pi; +} + + +void +KdInitInput (void) +{ + KdPointerInfo *pi; + KdKeyboardInfo *ki; + struct KdConfigDevice *dev; + + kdInputEnabled = TRUE; + + for (dev = kdConfigPointers; dev; dev = dev->next) { + pi = KdParsePointer(dev->line); + if (!pi) + ErrorF("Failed to parse pointer\n"); + if (KdAddPointer(pi) != Success) + ErrorF("Failed to add pointer!\n"); + } + for (dev = kdConfigKeyboards; dev; dev = dev->next) { + ki = KdParseKeyboard(dev->line); + if (!ki) + ErrorF("Failed to parse keyboard\n"); + if (KdAddKeyboard(ki) != Success) + ErrorF("Failed to add keyboard!\n"); + } + + mieqInit(); +} + +/* + * Middle button emulation state machine + * + * Possible transitions: + * Button 1 press v1 + * Button 1 release ^1 + * Button 2 press v2 + * Button 2 release ^2 + * Button 3 press v3 + * Button 3 release ^3 + * Button other press vo + * Button other release ^o + * Mouse motion <> + * Keyboard event k + * timeout ... + * outside box <-> + * + * States: + * start + * button_1_pend + * button_1_down + * button_2_down + * button_3_pend + * button_3_down + * synthetic_2_down_13 + * synthetic_2_down_3 + * synthetic_2_down_1 + * + * Transition diagram + * + * start + * v1 -> (hold) (settimeout) button_1_pend + * ^1 -> (deliver) start + * v2 -> (deliver) button_2_down + * ^2 -> (deliever) start + * v3 -> (hold) (settimeout) button_3_pend + * ^3 -> (deliver) start + * vo -> (deliver) start + * ^o -> (deliver) start + * <> -> (deliver) start + * k -> (deliver) start + * + * button_1_pend (button 1 is down, timeout pending) + * ^1 -> (release) (deliver) start + * v2 -> (release) (deliver) button_1_down + * ^2 -> (release) (deliver) button_1_down + * v3 -> (cleartimeout) (generate v2) synthetic_2_down_13 + * ^3 -> (release) (deliver) button_1_down + * vo -> (release) (deliver) button_1_down + * ^o -> (release) (deliver) button_1_down + * <-> -> (release) (deliver) button_1_down + * <> -> (deliver) button_1_pend + * k -> (release) (deliver) button_1_down + * ... -> (release) button_1_down + * + * button_1_down (button 1 is down) + * ^1 -> (deliver) start + * v2 -> (deliver) button_1_down + * ^2 -> (deliver) button_1_down + * v3 -> (deliver) button_1_down + * ^3 -> (deliver) button_1_down + * vo -> (deliver) button_1_down + * ^o -> (deliver) button_1_down + * <> -> (deliver) button_1_down + * k -> (deliver) button_1_down + * + * button_2_down (button 2 is down) + * v1 -> (deliver) button_2_down + * ^1 -> (deliver) button_2_down + * ^2 -> (deliver) start + * v3 -> (deliver) button_2_down + * ^3 -> (deliver) button_2_down + * vo -> (deliver) button_2_down + * ^o -> (deliver) button_2_down + * <> -> (deliver) button_2_down + * k -> (deliver) button_2_down + * + * button_3_pend (button 3 is down, timeout pending) + * v1 -> (generate v2) synthetic_2_down + * ^1 -> (release) (deliver) button_3_down + * v2 -> (release) (deliver) button_3_down + * ^2 -> (release) (deliver) button_3_down + * ^3 -> (release) (deliver) start + * vo -> (release) (deliver) button_3_down + * ^o -> (release) (deliver) button_3_down + * <-> -> (release) (deliver) button_3_down + * <> -> (deliver) button_3_pend + * k -> (release) (deliver) button_3_down + * ... -> (release) button_3_down + * + * button_3_down (button 3 is down) + * v1 -> (deliver) button_3_down + * ^1 -> (deliver) button_3_down + * v2 -> (deliver) button_3_down + * ^2 -> (deliver) button_3_down + * ^3 -> (deliver) start + * vo -> (deliver) button_3_down + * ^o -> (deliver) button_3_down + * <> -> (deliver) button_3_down + * k -> (deliver) button_3_down + * + * synthetic_2_down_13 (button 1 and 3 are down) + * ^1 -> (generate ^2) synthetic_2_down_3 + * v2 -> synthetic_2_down_13 + * ^2 -> synthetic_2_down_13 + * ^3 -> (generate ^2) synthetic_2_down_1 + * vo -> (deliver) synthetic_2_down_13 + * ^o -> (deliver) synthetic_2_down_13 + * <> -> (deliver) synthetic_2_down_13 + * k -> (deliver) synthetic_2_down_13 + * + * synthetic_2_down_3 (button 3 is down) + * v1 -> (deliver) synthetic_2_down_3 + * ^1 -> (deliver) synthetic_2_down_3 + * v2 -> synthetic_2_down_3 + * ^2 -> synthetic_2_down_3 + * ^3 -> start + * vo -> (deliver) synthetic_2_down_3 + * ^o -> (deliver) synthetic_2_down_3 + * <> -> (deliver) synthetic_2_down_3 + * k -> (deliver) synthetic_2_down_3 + * + * synthetic_2_down_1 (button 1 is down) + * ^1 -> start + * v2 -> synthetic_2_down_1 + * ^2 -> synthetic_2_down_1 + * v3 -> (deliver) synthetic_2_down_1 + * ^3 -> (deliver) synthetic_2_down_1 + * vo -> (deliver) synthetic_2_down_1 + * ^o -> (deliver) synthetic_2_down_1 + * <> -> (deliver) synthetic_2_down_1 + * k -> (deliver) synthetic_2_down_1 + */ + +typedef enum _inputClass { + down_1, up_1, + down_2, up_2, + down_3, up_3, + down_o, up_o, + motion, outside_box, + keyboard, timeout, + num_input_class +} KdInputClass; + +typedef enum _inputAction { + noop, + hold, + setto, + deliver, + release, + clearto, + gen_down_2, + gen_up_2 +} KdInputAction; + +#define MAX_ACTIONS 2 + +typedef struct _inputTransition { + KdInputAction actions[MAX_ACTIONS]; + KdPointerState nextState; +} KdInputTransition; + +static const +KdInputTransition kdInputMachine[num_input_states][num_input_class] = { + /* start */ + { + { { hold, setto }, button_1_pend }, /* v1 */ + { { deliver, noop }, start }, /* ^1 */ + { { deliver, noop }, button_2_down }, /* v2 */ + { { deliver, noop }, start }, /* ^2 */ + { { hold, setto }, button_3_pend }, /* v3 */ + { { deliver, noop }, start }, /* ^3 */ + { { deliver, noop }, start }, /* vo */ + { { deliver, noop }, start }, /* ^o */ + { { deliver, noop }, start }, /* <> */ + { { deliver, noop }, start }, /* <-> */ + { { noop, noop }, start }, /* k */ + { { noop, noop }, start }, /* ... */ + }, + /* button_1_pend */ + { + { { noop, noop }, button_1_pend }, /* v1 */ + { { release, deliver }, start }, /* ^1 */ + { { release, deliver }, button_1_down }, /* v2 */ + { { release, deliver }, button_1_down }, /* ^2 */ + { { clearto, gen_down_2 }, synth_2_down_13 }, /* v3 */ + { { release, deliver }, button_1_down }, /* ^3 */ + { { release, deliver }, button_1_down }, /* vo */ + { { release, deliver }, button_1_down }, /* ^o */ + { { deliver, noop }, button_1_pend }, /* <> */ + { { release, deliver }, button_1_down }, /* <-> */ + { { noop, noop }, button_1_down }, /* k */ + { { release, noop }, button_1_down }, /* ... */ + }, + /* button_1_down */ + { + { { noop, noop }, button_1_down }, /* v1 */ + { { deliver, noop }, start }, /* ^1 */ + { { deliver, noop }, button_1_down }, /* v2 */ + { { deliver, noop }, button_1_down }, /* ^2 */ + { { deliver, noop }, button_1_down }, /* v3 */ + { { deliver, noop }, button_1_down }, /* ^3 */ + { { deliver, noop }, button_1_down }, /* vo */ + { { deliver, noop }, button_1_down }, /* ^o */ + { { deliver, noop }, button_1_down }, /* <> */ + { { deliver, noop }, button_1_down }, /* <-> */ + { { noop, noop }, button_1_down }, /* k */ + { { noop, noop }, button_1_down }, /* ... */ + }, + /* button_2_down */ + { + { { deliver, noop }, button_2_down }, /* v1 */ + { { deliver, noop }, button_2_down }, /* ^1 */ + { { noop, noop }, button_2_down }, /* v2 */ + { { deliver, noop }, start }, /* ^2 */ + { { deliver, noop }, button_2_down }, /* v3 */ + { { deliver, noop }, button_2_down }, /* ^3 */ + { { deliver, noop }, button_2_down }, /* vo */ + { { deliver, noop }, button_2_down }, /* ^o */ + { { deliver, noop }, button_2_down }, /* <> */ + { { deliver, noop }, button_2_down }, /* <-> */ + { { noop, noop }, button_2_down }, /* k */ + { { noop, noop }, button_2_down }, /* ... */ + }, + /* button_3_pend */ + { + { { clearto, gen_down_2 }, synth_2_down_13 }, /* v1 */ + { { release, deliver }, button_3_down }, /* ^1 */ + { { release, deliver }, button_3_down }, /* v2 */ + { { release, deliver }, button_3_down }, /* ^2 */ + { { release, deliver }, button_3_down }, /* v3 */ + { { release, deliver }, start }, /* ^3 */ + { { release, deliver }, button_3_down }, /* vo */ + { { release, deliver }, button_3_down }, /* ^o */ + { { deliver, noop }, button_3_pend }, /* <> */ + { { release, deliver }, button_3_down }, /* <-> */ + { { release, noop }, button_3_down }, /* k */ + { { release, noop }, button_3_down }, /* ... */ + }, + /* button_3_down */ + { + { { deliver, noop }, button_3_down }, /* v1 */ + { { deliver, noop }, button_3_down }, /* ^1 */ + { { deliver, noop }, button_3_down }, /* v2 */ + { { deliver, noop }, button_3_down }, /* ^2 */ + { { noop, noop }, button_3_down }, /* v3 */ + { { deliver, noop }, start }, /* ^3 */ + { { deliver, noop }, button_3_down }, /* vo */ + { { deliver, noop }, button_3_down }, /* ^o */ + { { deliver, noop }, button_3_down }, /* <> */ + { { deliver, noop }, button_3_down }, /* <-> */ + { { noop, noop }, button_3_down }, /* k */ + { { noop, noop }, button_3_down }, /* ... */ + }, + /* synthetic_2_down_13 */ + { + { { noop, noop }, synth_2_down_13 }, /* v1 */ + { { gen_up_2, noop }, synth_2_down_3 }, /* ^1 */ + { { noop, noop }, synth_2_down_13 }, /* v2 */ + { { noop, noop }, synth_2_down_13 }, /* ^2 */ + { { noop, noop }, synth_2_down_13 }, /* v3 */ + { { gen_up_2, noop }, synth_2_down_1 }, /* ^3 */ + { { deliver, noop }, synth_2_down_13 }, /* vo */ + { { deliver, noop }, synth_2_down_13 }, /* ^o */ + { { deliver, noop }, synth_2_down_13 }, /* <> */ + { { deliver, noop }, synth_2_down_13 }, /* <-> */ + { { noop, noop }, synth_2_down_13 }, /* k */ + { { noop, noop }, synth_2_down_13 }, /* ... */ + }, + /* synthetic_2_down_3 */ + { + { { deliver, noop }, synth_2_down_3 }, /* v1 */ + { { deliver, noop }, synth_2_down_3 }, /* ^1 */ + { { deliver, noop }, synth_2_down_3 }, /* v2 */ + { { deliver, noop }, synth_2_down_3 }, /* ^2 */ + { { noop, noop }, synth_2_down_3 }, /* v3 */ + { { noop, noop }, start }, /* ^3 */ + { { deliver, noop }, synth_2_down_3 }, /* vo */ + { { deliver, noop }, synth_2_down_3 }, /* ^o */ + { { deliver, noop }, synth_2_down_3 }, /* <> */ + { { deliver, noop }, synth_2_down_3 }, /* <-> */ + { { noop, noop }, synth_2_down_3 }, /* k */ + { { noop, noop }, synth_2_down_3 }, /* ... */ + }, + /* synthetic_2_down_1 */ + { + { { noop, noop }, synth_2_down_1 }, /* v1 */ + { { noop, noop }, start }, /* ^1 */ + { { deliver, noop }, synth_2_down_1 }, /* v2 */ + { { deliver, noop }, synth_2_down_1 }, /* ^2 */ + { { deliver, noop }, synth_2_down_1 }, /* v3 */ + { { deliver, noop }, synth_2_down_1 }, /* ^3 */ + { { deliver, noop }, synth_2_down_1 }, /* vo */ + { { deliver, noop }, synth_2_down_1 }, /* ^o */ + { { deliver, noop }, synth_2_down_1 }, /* <> */ + { { deliver, noop }, synth_2_down_1 }, /* <-> */ + { { noop, noop }, synth_2_down_1 }, /* k */ + { { noop, noop }, synth_2_down_1 }, /* ... */ + }, +}; + +#define EMULATION_WINDOW 10 +#define EMULATION_TIMEOUT 100 + +static int +KdInsideEmulationWindow (KdPointerInfo *pi, int x, int y, int z) +{ + pi->emulationDx = pi->heldEvent.x - x; + pi->emulationDy = pi->heldEvent.y - y; + + return (abs (pi->emulationDx) < EMULATION_WINDOW && + abs (pi->emulationDy) < EMULATION_WINDOW); +} + +static KdInputClass +KdClassifyInput (KdPointerInfo *pi, int type, int x, int y, int z, int b) +{ + switch (type) { + case ButtonPress: + switch (b) { + case 1: return down_1; + case 2: return down_2; + case 3: return down_3; + default: return down_o; + } + break; + case ButtonRelease: + switch (b) { + case 1: return up_1; + case 2: return up_2; + case 3: return up_3; + default: return up_o; + } + break; + case MotionNotify: + if (pi->eventHeld && !KdInsideEmulationWindow(pi, x, y, z)) + return outside_box; + else + return motion; + default: + return keyboard; + } + return keyboard; +} + +#ifdef DEBUG +char *kdStateNames[] = { + "start", + "button_1_pend", + "button_1_down", + "button_2_down", + "button_3_pend", + "button_3_down", + "synth_2_down_13", + "synth_2_down_3", + "synthetic_2_down_1", + "num_input_states" +}; + +char *kdClassNames[] = { + "down_1", "up_1", + "down_2", "up_2", + "down_3", "up_3", + "motion", "ouside_box", + "keyboard", "timeout", + "num_input_class" +}; + +char *kdActionNames[] = { + "noop", + "hold", + "setto", + "deliver", + "release", + "clearto", + "gen_down_2", + "gen_up_2", +}; +#endif /* DEBUG */ + +static void +KdQueueEvent (DeviceIntPtr pDev, InternalEvent *ev) +{ + KdAssertSigioBlocked ("KdQueueEvent"); + mieqEnqueue (pDev, ev); +} + +/* We return true if we're stealing the event. */ +static Bool +KdRunMouseMachine (KdPointerInfo *pi, KdInputClass c, int type, int x, int y, + int z, int b, int absrel) +{ + const KdInputTransition *t; + int a; + + c = KdClassifyInput(pi, type, x, y, z, b); + t = &kdInputMachine[pi->mouseState][c]; + for (a = 0; a < MAX_ACTIONS; a++) + { + switch (t->actions[a]) { + case noop: + break; + case hold: + pi->eventHeld = TRUE; + pi->emulationDx = 0; + pi->emulationDy = 0; + pi->heldEvent.type = type; + pi->heldEvent.x = x; + pi->heldEvent.y = y; + pi->heldEvent.z = z; + pi->heldEvent.flags = b; + pi->heldEvent.absrel = absrel; + return TRUE; + break; + case setto: + pi->emulationTimeout = GetTimeInMillis () + EMULATION_TIMEOUT; + pi->timeoutPending = TRUE; + break; + case deliver: + _KdEnqueuePointerEvent (pi, pi->heldEvent.type, pi->heldEvent.x, + pi->heldEvent.y, pi->heldEvent.z, + pi->heldEvent.flags, pi->heldEvent.absrel, + TRUE); + break; + case release: + pi->eventHeld = FALSE; + pi->timeoutPending = FALSE; + _KdEnqueuePointerEvent (pi, pi->heldEvent.type, pi->heldEvent.x, + pi->heldEvent.y, pi->heldEvent.z, + pi->heldEvent.flags, pi->heldEvent.absrel, + TRUE); + return TRUE; + break; + case clearto: + pi->timeoutPending = FALSE; + break; + case gen_down_2: + _KdEnqueuePointerEvent (pi, ButtonPress, x, y, z, 2, absrel, + TRUE); + pi->eventHeld = FALSE; + return TRUE; + break; + case gen_up_2: + _KdEnqueuePointerEvent (pi, ButtonRelease, x, y, z, 2, absrel, + TRUE); + return TRUE; + break; + } + } + pi->mouseState = t->nextState; + return FALSE; +} + +static int +KdHandlePointerEvent (KdPointerInfo *pi, int type, int x, int y, int z, int b, + int absrel) +{ + if (pi->emulateMiddleButton) + return KdRunMouseMachine (pi, KdClassifyInput(pi, type, x, y, z, b), + type, x, y, z, b, absrel); + return FALSE; +} + +static void +KdReceiveTimeout (KdPointerInfo *pi) +{ + KdRunMouseMachine (pi, timeout, 0, 0, 0, 0, 0, 0); +} + +/* + * kdCheckTermination + * + * This function checks for the key sequence that terminates the server. When + * detected, it sets the dispatchException flag and returns. The key sequence + * is: + * Control-Alt + * It's assumed that the server will be waken up by the caller when this + * function returns. + */ + +extern int nClients; + +void +KdReleaseAllKeys (void) +{ +#if 0 + int key, nEvents, i; + KdKeyboardInfo *ki; + + KdBlockSigio (); + + for (ki = kdKeyboards; ki; ki = ki->next) { + for (key = ki->keySyms.minKeyCode; key < ki->keySyms.maxKeyCode; + key++) { + if (key_is_down(ki->dixdev, key, KEY_POSTED | KEY_PROCESSED)) { + KdHandleKeyboardEvent(ki, KeyRelease, key); + GetEventList(&kdEvents); + nEvents = GetKeyboardEvents(kdEvents, ki->dixdev, KeyRelease, key); + for (i = 0; i < nEvents; i++) + KdQueueEvent (ki->dixdev, (kdEvents + i)->event); + } + } + } + + KdUnblockSigio (); +#endif +} + +static void +KdCheckLock (void) +{ + KeyClassPtr keyc = NULL; + Bool isSet = FALSE, shouldBeSet = FALSE; + KdKeyboardInfo *tmp = NULL; + + for (tmp = kdKeyboards; tmp; tmp = tmp->next) { + if (tmp->LockLed && tmp->dixdev && tmp->dixdev->key) { + keyc = tmp->dixdev->key; + isSet = (tmp->leds & (1 << (tmp->LockLed-1))) != 0; + /* FIXME: Just use XKB indicators! */ + shouldBeSet = !!(XkbStateFieldFromRec(&keyc->xkbInfo->state) & LockMask); + if (isSet != shouldBeSet) + KdSetLed (tmp, tmp->LockLed, shouldBeSet); + } + } +} + +void +KdEnqueueKeyboardEvent(KdKeyboardInfo *ki, + unsigned char scan_code, + unsigned char is_up) +{ + unsigned char key_code; + KeyClassPtr keyc = NULL; + KeybdCtrl *ctrl = NULL; + int type, nEvents, i; + + if (!ki || !ki->dixdev || !ki->dixdev->kbdfeed || !ki->dixdev->key) + return; + + keyc = ki->dixdev->key; + ctrl = &ki->dixdev->kbdfeed->ctrl; + + if (scan_code >= ki->minScanCode && scan_code <= ki->maxScanCode) + { + key_code = scan_code + KD_MIN_KEYCODE - ki->minScanCode; + + /* + * Set up this event -- the type may be modified below + */ + if (is_up) + type = KeyRelease; + else + type = KeyPress; + + GetEventList(&kdEvents); + + nEvents = GetKeyboardEvents(kdEvents, ki->dixdev, type, key_code); + for (i = 0; i < nEvents; i++) + KdQueueEvent(ki->dixdev, (InternalEvent *)((kdEvents + i)->event)); + } + else { + ErrorF("driver %s wanted to post scancode %d outside of [%d, %d]!\n", + ki->name, scan_code, ki->minScanCode, ki->maxScanCode); + } +} + +/* + * kdEnqueuePointerEvent + * + * This function converts hardware mouse event information into X event + * information. A mouse movement event is passed off to MI to generate + * a MotionNotify event, if appropriate. Button events are created and + * passed off to MI for enqueueing. + */ + +/* FIXME do something a little more clever to deal with multiple axes here */ +void +KdEnqueuePointerEvent(KdPointerInfo *pi, unsigned long flags, int rx, int ry, + int rz) +{ + CARD32 ms; + unsigned char buttons; + int x, y, z; + int (*matrix)[3] = kdPointerMatrix.matrix; + unsigned long button; + int n; + int dixflags = 0; + + if (!pi) + return; + + ms = GetTimeInMillis(); + + /* we don't need to transform z, so we don't. */ + if (flags & KD_MOUSE_DELTA) { + if (pi->transformCoordinates) { + x = matrix[0][0] * rx + matrix[0][1] * ry; + y = matrix[1][0] * rx + matrix[1][1] * ry; + } + else { + x = rx; + y = ry; + } + } + else { + if (pi->transformCoordinates) { + x = matrix[0][0] * rx + matrix[0][1] * ry + matrix[0][2]; + y = matrix[1][0] * rx + matrix[1][1] * ry + matrix[1][2]; + } + else { + x = rx; + y = ry; + } + } + z = rz; + + if (flags & KD_MOUSE_DELTA) + { + if (x || y || z) + { + dixflags = POINTER_RELATIVE | POINTER_ACCELERATE; + _KdEnqueuePointerEvent(pi, MotionNotify, x, y, z, 0, dixflags, FALSE); + } + } else + { + dixflags = POINTER_ABSOLUTE; + if (x != pi->dixdev->last.valuators[0] || + y != pi->dixdev->last.valuators[1]) + _KdEnqueuePointerEvent(pi, MotionNotify, x, y, z, 0, dixflags, FALSE); + } + + buttons = flags; + + for (button = KD_BUTTON_1, n = 1; n <= pi->nButtons; + button <<= 1, n++) { + if (((pi->buttonState & button) ^ (buttons & button)) && + !(buttons & button)) { + _KdEnqueuePointerEvent(pi, ButtonRelease, x, y, z, n, + dixflags, FALSE); + } + } + for (button = KD_BUTTON_1, n = 1; n <= pi->nButtons; + button <<= 1, n++) { + if (((pi->buttonState & button) ^ (buttons & button)) && + (buttons & button)) { + _KdEnqueuePointerEvent(pi, ButtonPress, x, y, z, n, + dixflags, FALSE); + } + } + + pi->buttonState = buttons; +} + +void +_KdEnqueuePointerEvent (KdPointerInfo *pi, int type, int x, int y, int z, + int b, int absrel, Bool force) +{ + int nEvents = 0, i = 0; + int valuators[3] = { x, y, z }; + + /* TRUE from KdHandlePointerEvent, means 'we swallowed the event'. */ + if (!force && KdHandlePointerEvent(pi, type, x, y, z, b, absrel)) + return; + + GetEventList(&kdEvents); + nEvents = GetPointerEvents(kdEvents, pi->dixdev, type, b, absrel, + 0, 3, valuators); + for (i = 0; i < nEvents; i++) + KdQueueEvent(pi->dixdev, (InternalEvent *)((kdEvents + i)->event)); +} + +void +KdBlockHandler (int screen, + pointer blockData, + pointer timeout, + pointer readmask) +{ + KdPointerInfo *pi; + int myTimeout=0; + + for (pi = kdPointers; pi; pi = pi->next) + { + if (pi->timeoutPending) + { + int ms; + + ms = pi->emulationTimeout - GetTimeInMillis (); + if (ms < 1) + ms = 1; + if(mspollEvents) + { + (*kdOsFuncs->pollEvents)(); + myTimeout=20; + } + if(myTimeout>0) + AdjustWaitForDelay (timeout, myTimeout); +} + +void +KdWakeupHandler (int screen, + pointer data, + unsigned long lresult, + pointer readmask) +{ + int result = (int) lresult; + fd_set *pReadmask = (fd_set *) readmask; + int i; + KdPointerInfo *pi; + + if (kdInputEnabled && result > 0) + { + for (i = 0; i < kdNumInputFds; i++) + if (FD_ISSET (kdInputFds[i].fd, pReadmask)) + { + KdBlockSigio (); + (*kdInputFds[i].read) (kdInputFds[i].fd, kdInputFds[i].closure); + KdUnblockSigio (); + } + } + for (pi = kdPointers; pi; pi = pi->next) + { + if (pi->timeoutPending) + { + if ((long) (GetTimeInMillis () - pi->emulationTimeout) >= 0) + { + pi->timeoutPending = FALSE; + KdBlockSigio (); + KdReceiveTimeout (pi); + KdUnblockSigio (); + } + } + } + if (kdSwitchPending) + KdProcessSwitch (); +} + +#define KdScreenOrigin(pScreen) (&(KdGetScreenPriv(pScreen)->screen->origin)) + +static Bool +KdCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) +{ + ScreenPtr pScreen = *ppScreen; + ScreenPtr pNewScreen; + int n; + int dx, dy; + int best_x, best_y; + int n_best_x, n_best_y; + CARD32 ms; + + if (kdDisableZaphod || screenInfo.numScreens <= 1) + return FALSE; + + if (0 <= *x && *x < pScreen->width && 0 <= *y && *y < pScreen->height) + return FALSE; + + ms = GetTimeInMillis (); + if (kdOffScreen && (int) (ms - kdOffScreenTime) < 1000) + return FALSE; + kdOffScreen = TRUE; + kdOffScreenTime = ms; + n_best_x = -1; + best_x = 32767; + n_best_y = -1; + best_y = 32767; + for (n = 0; n < screenInfo.numScreens; n++) + { + pNewScreen = screenInfo.screens[n]; + if (pNewScreen == pScreen) + continue; + dx = KdScreenOrigin(pNewScreen)->x - KdScreenOrigin(pScreen)->x; + dy = KdScreenOrigin(pNewScreen)->y - KdScreenOrigin(pScreen)->y; + if (*x < 0) + { + if (dx <= 0 && -dx < best_x) + { + best_x = -dx; + n_best_x = n; + } + } + else if (*x >= pScreen->width) + { + if (dx >= 0 && dx < best_x) + { + best_x = dx; + n_best_x = n; + } + } + if (*y < 0) + { + if (dy <= 0 && -dy < best_y) + { + best_y = -dy; + n_best_y = n; + } + } + else if (*y >= pScreen->height) + { + if (dy >= 0 && dy < best_y) + { + best_y = dy; + n_best_y = n; + } + } + } + if (best_y < best_x) + n_best_x = n_best_y; + if (n_best_x == -1) + return FALSE; + pNewScreen = screenInfo.screens[n_best_x]; + + if (*x < 0) + *x += pNewScreen->width; + if (*y < 0) + *y += pNewScreen->height; + + if (*x >= pScreen->width) + *x -= pScreen->width; + if (*y >= pScreen->height) + *y -= pScreen->height; + + *ppScreen = pNewScreen; + return TRUE; +} + +static void +KdCrossScreen(ScreenPtr pScreen, Bool entering) +{ +#ifndef XIPAQ + if (entering) + KdEnableScreen (pScreen); + else + KdDisableScreen (pScreen); +#endif +} + +int KdCurScreen; /* current event screen */ + +static void +KdWarpCursor (DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y) +{ + KdBlockSigio (); + KdCurScreen = pScreen->myNum; + miPointerWarpCursor(pDev, pScreen, x, y); + KdUnblockSigio (); +} + +miPointerScreenFuncRec kdPointerScreenFuncs = +{ + KdCursorOffScreen, + KdCrossScreen, + KdWarpCursor +}; + +void +ProcessInputEvents (void) +{ + mieqProcessInputEvents(); + miPointerUpdateSprite(inputInfo.pointer); + if (kdSwitchPending) + KdProcessSwitch (); + KdCheckLock (); +} + +/* FIXME use XSECURITY to work out whether the client should be allowed to + * open and close. */ +void +OpenInputDevice(DeviceIntPtr pDev, ClientPtr client, int *status) +{ + if (!pDev) + *status = BadDevice; + else + *status = Success; +} + +void +CloseInputDevice(DeviceIntPtr pDev, ClientPtr client) +{ + return; +} + +/* We initialise all input devices at startup. */ +void +AddOtherInputDevices(void) +{ + return; +} + +/* At the moment, absolute/relative is up to the client. */ +int +SetDeviceMode(register ClientPtr client, DeviceIntPtr pDev, int mode) +{ + return BadMatch; +} + +int +SetDeviceValuators(register ClientPtr client, DeviceIntPtr pDev, + int *valuators, int first_valuator, int num_valuators) +{ + return BadMatch; +} + +int +ChangeDeviceControl(register ClientPtr client, DeviceIntPtr pDev, + xDeviceCtl *control) +{ + switch (control->control) { + case DEVICE_RESOLUTION: + /* FIXME do something more intelligent here */ + return BadMatch; + + case DEVICE_ABS_CALIB: + case DEVICE_ABS_AREA: + return Success; + + case DEVICE_CORE: + return BadMatch; + case DEVICE_ENABLE: + return Success; + + default: + return BadMatch; + } + + /* NOTREACHED */ + return BadImplementation; +} + +int +NewInputDeviceRequest(InputOption *options, InputAttributes *attrs, + DeviceIntPtr *pdev) +{ + InputOption *option = NULL; + KdPointerInfo *pi = NULL; + KdKeyboardInfo *ki = NULL; + + for (option = options; option; option = option->next) { + if (strcmp(option->key, "type") == 0) { + if (strcmp(option->value, "pointer") == 0) { + pi = KdNewPointer(); + if (!pi) + return BadAlloc; + } + else if (strcmp(option->value, "keyboard") == 0) { + ki = KdNewKeyboard(); + if (!ki) + return BadAlloc; + } + else { + ErrorF("unrecognised device type!\n"); + return BadValue; + } + } +#ifdef CONFIG_HAL + else if (strcmp(option->key, "_source") == 0 && + strcmp(option->value, "server/hal") == 0) + { + ErrorF("Ignoring device from HAL.\n"); + return BadValue; + } +#endif +#ifdef CONFIG_UDEV + else if (strcmp(option->key, "_source") == 0 && + strcmp(option->value, "server/udev") == 0) + { + ErrorF("Ignoring device from udev.\n"); + return BadValue; + } +#endif + } + + if (!ki && !pi) { + ErrorF("unrecognised device identifier!\n"); + return BadValue; + } + + /* FIXME: change this code below to use KdParseKbdOptions and + * KdParsePointerOptions */ + for (option = options; option; option = option->next) { + if (strcmp(option->key, "device") == 0) { + if (pi && option->value) + pi->path = strdup(option->value); + else if (ki && option->value) + ki->path = strdup(option->value); + } + else if (strcmp(option->key, "driver") == 0) { + if (pi) { + pi->driver = KdFindPointerDriver(option->value); + if (!pi->driver) { + ErrorF("couldn't find driver!\n"); + KdFreePointer(pi); + return BadValue; + } + pi->options = options; + } + else if (ki) { + ki->driver = KdFindKeyboardDriver(option->value); + if (!ki->driver) { + ErrorF("couldn't find driver!\n"); + KdFreeKeyboard(ki); + return BadValue; + } + ki->options = options; + } + } + } + + if (pi) { + if (KdAddPointer(pi) != Success || + ActivateDevice(pi->dixdev, TRUE) != Success || + EnableDevice(pi->dixdev, TRUE) != TRUE) { + ErrorF("couldn't add or enable pointer\n"); + return BadImplementation; + } + } + else if (ki) { + if (KdAddKeyboard(ki) != Success || + ActivateDevice(ki->dixdev, TRUE) != Success || + EnableDevice(ki->dixdev, TRUE) != TRUE) { + ErrorF("couldn't add or enable keyboard\n"); + return BadImplementation; + } + } + + if (pi) { + *pdev = pi->dixdev; + } else if(ki) { + *pdev = ki->dixdev; + } + + return Success; +} + +void +DeleteInputDeviceRequest(DeviceIntPtr pDev) +{ + RemoveDevice(pDev, TRUE); +} diff --git a/xorg-server/hw/kdrive/src/kshadow.c b/xorg-server/hw/kdrive/src/kshadow.c index cf3391dba..4454020f0 100644 --- a/xorg-server/hw/kdrive/src/kshadow.c +++ b/xorg-server/hw/kdrive/src/kshadow.c @@ -1,81 +1,81 @@ -/* - * Copyright © 1999 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of Keith Packard not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. Keith Packard makes no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "kdrive.h" - -Bool -KdShadowFbAlloc (KdScreenInfo *screen, Bool rotate) -{ - int paddedWidth; - void *buf; - int width = rotate ? screen->height : screen->width; - int height = rotate ? screen->width : screen->height; - int bpp = screen->fb.bitsPerPixel; - - /* use fb computation for width */ - paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits); - buf = xalloc (paddedWidth * height); - if (!buf) - return FALSE; - if (screen->fb.shadow) - xfree (screen->fb.frameBuffer); - screen->fb.shadow = TRUE; - screen->fb.frameBuffer = buf; - screen->fb.byteStride = paddedWidth; - screen->fb.pixelStride = paddedWidth * 8 / bpp; - return TRUE; -} - -void -KdShadowFbFree (KdScreenInfo *screen) -{ - if (screen->fb.shadow) - { - xfree (screen->fb.frameBuffer); - screen->fb.frameBuffer = 0; - screen->fb.shadow = FALSE; - } -} - -Bool -KdShadowSet (ScreenPtr pScreen, int randr, ShadowUpdateProc update, ShadowWindowProc window) -{ - KdScreenPriv(pScreen); - KdScreenInfo *screen = pScreenPriv->screen; - - shadowRemove (pScreen, pScreen->GetScreenPixmap(pScreen)); - if(screen->fb.shadow) - { - return shadowAdd (pScreen, pScreen->GetScreenPixmap(pScreen), - update, window, randr, 0); - } - return TRUE; -} - -void -KdShadowUnset (ScreenPtr pScreen) -{ - shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen)); -} +/* + * Copyright © 1999 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "kdrive.h" + +Bool +KdShadowFbAlloc (KdScreenInfo *screen, Bool rotate) +{ + int paddedWidth; + void *buf; + int width = rotate ? screen->height : screen->width; + int height = rotate ? screen->width : screen->height; + int bpp = screen->fb.bitsPerPixel; + + /* use fb computation for width */ + paddedWidth = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof (FbBits); + buf = malloc(paddedWidth * height); + if (!buf) + return FALSE; + if (screen->fb.shadow) + free(screen->fb.frameBuffer); + screen->fb.shadow = TRUE; + screen->fb.frameBuffer = buf; + screen->fb.byteStride = paddedWidth; + screen->fb.pixelStride = paddedWidth * 8 / bpp; + return TRUE; +} + +void +KdShadowFbFree (KdScreenInfo *screen) +{ + if (screen->fb.shadow) + { + free(screen->fb.frameBuffer); + screen->fb.frameBuffer = 0; + screen->fb.shadow = FALSE; + } +} + +Bool +KdShadowSet (ScreenPtr pScreen, int randr, ShadowUpdateProc update, ShadowWindowProc window) +{ + KdScreenPriv(pScreen); + KdScreenInfo *screen = pScreenPriv->screen; + + shadowRemove (pScreen, pScreen->GetScreenPixmap(pScreen)); + if(screen->fb.shadow) + { + return shadowAdd (pScreen, pScreen->GetScreenPixmap(pScreen), + update, window, randr, 0); + } + return TRUE; +} + +void +KdShadowUnset (ScreenPtr pScreen) +{ + shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen)); +} diff --git a/xorg-server/hw/kdrive/src/kxv.c b/xorg-server/hw/kdrive/src/kxv.c index 27ecc5d6c..9fef34d1f 100644 --- a/xorg-server/hw/kdrive/src/kxv.c +++ b/xorg-server/hw/kdrive/src/kxv.c @@ -1,1907 +1,1907 @@ -/* - - XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com) - Adapted for KDrive by Pontus Lidman - - Copyright (C) 2000, 2001 - Nokia Home Communications - Copyright (C) 1998, 1999 - The XFree86 Project 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, and/or sell copies of the Software, and to permit persons -to whom the Software is furnished to do so, provided that the above -copyright notice(s) and this permission notice appear in all copies of -the Software and that both the above copyright notice(s) and this -permission notice appear in supporting documentation. - -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 -OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. - -Except as contained in this notice, the name of a copyright holder -shall not be used in advertising or otherwise to promote the sale, use -or other dealings in this Software without prior written authorization -of the copyright holder. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include "kdrive.h" - -#include "scrnintstr.h" -#include "regionstr.h" -#include "windowstr.h" -#include "pixmapstr.h" -#include "mivalidate.h" -#include "validate.h" -#include "resource.h" -#include "gcstruct.h" -#include "dixstruct.h" - -#include -#include - -#include "kxv.h" -#include "fourcc.h" - - -/* XvScreenRec fields */ - -static Bool KdXVCloseScreen(int, ScreenPtr); -static int KdXVQueryAdaptors(ScreenPtr, XvAdaptorPtr *, int *); - -/* XvAdaptorRec fields */ - -static int KdXVAllocatePort(unsigned long, XvPortPtr, XvPortPtr*); -static int KdXVFreePort(XvPortPtr); -static int KdXVPutVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int KdXVPutStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int KdXVGetVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int KdXVGetStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16); -static int KdXVStopVideo(ClientPtr, XvPortPtr, DrawablePtr); -static int KdXVSetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32); -static int KdXVGetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32 *); -static int KdXVQueryBestSize(ClientPtr, XvPortPtr, CARD8, - CARD16, CARD16,CARD16, CARD16, - unsigned int*, unsigned int*); -static int KdXVPutImage(ClientPtr, DrawablePtr, XvPortPtr, GCPtr, - INT16, INT16, CARD16, CARD16, - INT16, INT16, CARD16, CARD16, - XvImagePtr, unsigned char*, Bool, - CARD16, CARD16); -static int KdXVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr, - CARD16*, CARD16*, int*, int*); - - -/* ScreenRec fields */ - -static Bool KdXVCreateWindow(WindowPtr pWin); -static Bool KdXVDestroyWindow(WindowPtr pWin); -static void KdXVWindowExposures(WindowPtr pWin, RegionPtr r1, RegionPtr r2); -static void KdXVClipNotify(WindowPtr pWin, int dx, int dy); - -/* misc */ -static Bool KdXVInitAdaptors(ScreenPtr, KdVideoAdaptorPtr*, int); - -static int KdXVWindowKeyIndex; -DevPrivateKey KdXVWindowKey = &KdXVWindowKeyIndex; -static int KdXvScreenKeyIndex; -DevPrivateKey KdXvScreenKey = &KdXvScreenKeyIndex; -static unsigned long KdXVGeneration = 0; -static unsigned long PortResource = 0; - -DevPrivateKey (*XvGetScreenKeyProc)(void) = XvGetScreenKey; -unsigned long (*XvGetRTPortProc)(void) = XvGetRTPort; -int (*XvScreenInitProc)(ScreenPtr) = XvScreenInit; - -#define GET_XV_SCREEN(pScreen) ((XvScreenPtr) \ - dixLookupPrivate(&(pScreen)->devPrivates, KdXvScreenKey)) - -#define GET_KDXV_SCREEN(pScreen) \ - ((KdXVScreenPtr)(GET_XV_SCREEN(pScreen)->devPriv.ptr)) - -#define GET_KDXV_WINDOW(pWin) ((KdXVWindowPtr) \ - dixLookupPrivate(&(pWin)->devPrivates, KdXVWindowKey)) - -static KdXVInitGenericAdaptorPtr *GenDrivers = NULL; -static int NumGenDrivers = 0; - -int -KdXVRegisterGenericAdaptorDriver( - KdXVInitGenericAdaptorPtr InitFunc -){ - KdXVInitGenericAdaptorPtr *newdrivers; - -/* fprintf(stderr,"KdXVRegisterGenericAdaptorDriver\n"); */ - - newdrivers = xrealloc(GenDrivers, sizeof(KdXVInitGenericAdaptorPtr) * - (1 + NumGenDrivers)); - if (!newdrivers) - return 0; - GenDrivers = newdrivers; - - GenDrivers[NumGenDrivers++] = InitFunc; - - return 1; -} - -int -KdXVListGenericAdaptors( - KdScreenInfo * screen, - KdVideoAdaptorPtr **adaptors -){ - int i,j,n,num; - KdVideoAdaptorPtr *DrivAdap,*new; - - num = 0; - *adaptors = NULL; - for (i = 0; i < NumGenDrivers; i++) { - n = GenDrivers[i](screen,&DrivAdap); - if (0 == n) - continue; - new = xrealloc(*adaptors, sizeof(KdVideoAdaptorPtr) * (num+n)); - if (NULL == new) - continue; - *adaptors = new; - for (j = 0; j < n; j++, num++) - (*adaptors)[num] = DrivAdap[j]; - } - return num; -} - -KdVideoAdaptorPtr -KdXVAllocateVideoAdaptorRec(KdScreenInfo * screen) -{ - return xcalloc(1, sizeof(KdVideoAdaptorRec)); -} - -void -KdXVFreeVideoAdaptorRec(KdVideoAdaptorPtr ptr) -{ - xfree(ptr); -} - - -Bool -KdXVScreenInit( - ScreenPtr pScreen, - KdVideoAdaptorPtr *adaptors, - int num -){ - KdXVScreenPtr ScreenPriv; - XvScreenPtr pxvs; - -/* fprintf(stderr,"KdXVScreenInit initializing %d adaptors\n",num); */ - - if (KdXVGeneration != serverGeneration) - KdXVGeneration = serverGeneration; - - if(!XvGetScreenKeyProc || !XvGetRTPortProc || !XvScreenInitProc) - return FALSE; - - if(Success != (*XvScreenInitProc)(pScreen)) return FALSE; - - KdXvScreenKey = (*XvGetScreenKeyProc)(); - PortResource = (*XvGetRTPortProc)(); - - pxvs = GET_XV_SCREEN(pScreen); - - - /* Anyone initializing the Xv layer must provide these two. - The Xv di layer calls them without even checking if they exist! */ - - pxvs->ddCloseScreen = KdXVCloseScreen; - pxvs->ddQueryAdaptors = KdXVQueryAdaptors; - - /* The Xv di layer provides us with a private hook so that we don't - have to allocate our own screen private. They also provide - a CloseScreen hook so that we don't have to wrap it. I'm not - sure that I appreciate that. */ - - ScreenPriv = xalloc(sizeof(KdXVScreenRec)); - pxvs->devPriv.ptr = (pointer)ScreenPriv; - - if(!ScreenPriv) return FALSE; - - - ScreenPriv->CreateWindow = pScreen->CreateWindow; - ScreenPriv->DestroyWindow = pScreen->DestroyWindow; - ScreenPriv->WindowExposures = pScreen->WindowExposures; - ScreenPriv->ClipNotify = pScreen->ClipNotify; - -/* fprintf(stderr,"XV: Wrapping screen funcs\n"); */ - - pScreen->CreateWindow = KdXVCreateWindow; - pScreen->DestroyWindow = KdXVDestroyWindow; - pScreen->WindowExposures = KdXVWindowExposures; - pScreen->ClipNotify = KdXVClipNotify; - - if(!KdXVInitAdaptors(pScreen, adaptors, num)) - return FALSE; - - return TRUE; -} - -static void -KdXVFreeAdaptor(XvAdaptorPtr pAdaptor) -{ - int i; - - xfree(pAdaptor->name); - - if(pAdaptor->pEncodings) { - XvEncodingPtr pEncode = pAdaptor->pEncodings; - - for(i = 0; i < pAdaptor->nEncodings; i++, pEncode++) { - xfree(pEncode->name); - } - xfree(pAdaptor->pEncodings); - } - - xfree(pAdaptor->pFormats); - - if(pAdaptor->pPorts) { - XvPortPtr pPort = pAdaptor->pPorts; - XvPortRecPrivatePtr pPriv; - - for(i = 0; i < pAdaptor->nPorts; i++, pPort++) { - pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; - if(pPriv) { - if(pPriv->clientClip) - REGION_DESTROY(pAdaptor->pScreen, pPriv->clientClip); - if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) - REGION_DESTROY(pAdaptor->pScreen, pPriv->pCompositeClip); - xfree(pPriv); - } - } - xfree(pAdaptor->pPorts); - } - - if(pAdaptor->nAttributes) { - XvAttributePtr pAttribute = pAdaptor->pAttributes; - - for(i = 0; i < pAdaptor->nAttributes; i++, pAttribute++) { - xfree(pAttribute->name); - } - - xfree(pAdaptor->pAttributes); - } - - xfree(pAdaptor->pImages); - - xfree(pAdaptor->devPriv.ptr); -} - -static Bool -KdXVInitAdaptors( - ScreenPtr pScreen, - KdVideoAdaptorPtr *infoPtr, - int number -) { - KdScreenPriv(pScreen); - KdScreenInfo * screen = pScreenPriv->screen; - - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - KdVideoAdaptorPtr adaptorPtr; - XvAdaptorPtr pAdaptor, pa; - XvAdaptorRecPrivatePtr adaptorPriv; - int na, numAdaptor; - XvPortRecPrivatePtr portPriv; - XvPortPtr pPort, pp; - int numPort; - KdAttributePtr attributePtr; - XvAttributePtr pAttribute, pat; - KdVideoFormatPtr formatPtr; - XvFormatPtr pFormat, pf; - int numFormat, totFormat; - KdVideoEncodingPtr encodingPtr; - XvEncodingPtr pEncode, pe; - KdImagePtr imagePtr; - XvImagePtr pImage, pi; - int numVisuals; - VisualPtr pVisual; - int i; - - pxvs->nAdaptors = 0; - pxvs->pAdaptors = NULL; - - if(!(pAdaptor = xcalloc(number, sizeof(XvAdaptorRec)))) - return FALSE; - - for(pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) { - adaptorPtr = infoPtr[na]; - - if(!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute || - !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize) - continue; - - /* client libs expect at least one encoding */ - if(!adaptorPtr->nEncodings || !adaptorPtr->pEncodings) - continue; - - pa->type = adaptorPtr->type; - - if(!adaptorPtr->PutVideo && !adaptorPtr->GetVideo) - pa->type &= ~XvVideoMask; - - if(!adaptorPtr->PutStill && !adaptorPtr->GetStill) - pa->type &= ~XvStillMask; - - if(!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes) - pa->type &= ~XvImageMask; - - if(!adaptorPtr->PutVideo && !adaptorPtr->PutImage && - !adaptorPtr->PutStill) - pa->type &= ~XvInputMask; - - if(!adaptorPtr->GetVideo && !adaptorPtr->GetStill) - pa->type &= ~XvOutputMask; - - if(!(adaptorPtr->type & (XvPixmapMask | XvWindowMask))) - continue; - if(!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask))) - continue; - - pa->pScreen = pScreen; - pa->ddAllocatePort = KdXVAllocatePort; - pa->ddFreePort = KdXVFreePort; - pa->ddPutVideo = KdXVPutVideo; - pa->ddPutStill = KdXVPutStill; - pa->ddGetVideo = KdXVGetVideo; - pa->ddGetStill = KdXVGetStill; - pa->ddStopVideo = KdXVStopVideo; - pa->ddPutImage = KdXVPutImage; - pa->ddSetPortAttribute = KdXVSetPortAttribute; - pa->ddGetPortAttribute = KdXVGetPortAttribute; - pa->ddQueryBestSize = KdXVQueryBestSize; - pa->ddQueryImageAttributes = KdXVQueryImageAttributes; - if((pa->name = xalloc(strlen(adaptorPtr->name) + 1))) - strcpy(pa->name, adaptorPtr->name); - - if(adaptorPtr->nEncodings && - (pEncode = xcalloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) { - - for(pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0; - i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++) - { - pe->id = encodingPtr->id; - pe->pScreen = pScreen; - if((pe->name = xalloc(strlen(encodingPtr->name) + 1))) - strcpy(pe->name, encodingPtr->name); - pe->width = encodingPtr->width; - pe->height = encodingPtr->height; - pe->rate.numerator = encodingPtr->rate.numerator; - pe->rate.denominator = encodingPtr->rate.denominator; - } - pa->nEncodings = adaptorPtr->nEncodings; - pa->pEncodings = pEncode; - } - - if(adaptorPtr->nImages && - (pImage = xcalloc(adaptorPtr->nImages, sizeof(XvImageRec)))) { - - for(i = 0, pi = pImage, imagePtr = adaptorPtr->pImages; - i < adaptorPtr->nImages; i++, pi++, imagePtr++) - { - pi->id = imagePtr->id; - pi->type = imagePtr->type; - pi->byte_order = imagePtr->byte_order; - memcpy(pi->guid, imagePtr->guid, 16); - pi->bits_per_pixel = imagePtr->bits_per_pixel; - pi->format = imagePtr->format; - pi->num_planes = imagePtr->num_planes; - pi->depth = imagePtr->depth; - pi->red_mask = imagePtr->red_mask; - pi->green_mask = imagePtr->green_mask; - pi->blue_mask = imagePtr->blue_mask; - pi->y_sample_bits = imagePtr->y_sample_bits; - pi->u_sample_bits = imagePtr->u_sample_bits; - pi->v_sample_bits = imagePtr->v_sample_bits; - pi->horz_y_period = imagePtr->horz_y_period; - pi->horz_u_period = imagePtr->horz_u_period; - pi->horz_v_period = imagePtr->horz_v_period; - pi->vert_y_period = imagePtr->vert_y_period; - pi->vert_u_period = imagePtr->vert_u_period; - pi->vert_v_period = imagePtr->vert_v_period; - memcpy(pi->component_order, imagePtr->component_order, 32); - pi->scanline_order = imagePtr->scanline_order; - } - pa->nImages = adaptorPtr->nImages; - pa->pImages = pImage; - } - - if(adaptorPtr->nAttributes && - (pAttribute = xcalloc(adaptorPtr->nAttributes, sizeof(XvAttributeRec)))) - { - for(pat = pAttribute, attributePtr = adaptorPtr->pAttributes, i = 0; - i < adaptorPtr->nAttributes; pat++, i++, attributePtr++) - { - pat->flags = attributePtr->flags; - pat->min_value = attributePtr->min_value; - pat->max_value = attributePtr->max_value; - if((pat->name = xalloc(strlen(attributePtr->name) + 1))) - strcpy(pat->name, attributePtr->name); - } - pa->nAttributes = adaptorPtr->nAttributes; - pa->pAttributes = pAttribute; - } - - - totFormat = adaptorPtr->nFormats; - - if(!(pFormat = xcalloc(totFormat, sizeof(XvFormatRec)))) { - KdXVFreeAdaptor(pa); - continue; - } - for(pf = pFormat, i = 0, numFormat = 0, formatPtr = adaptorPtr->pFormats; - i < adaptorPtr->nFormats; i++, formatPtr++) - { - numVisuals = pScreen->numVisuals; - pVisual = pScreen->visuals; - - while(numVisuals--) { - if((pVisual->class == formatPtr->class) && - (pVisual->nplanes == formatPtr->depth)) { - - if(numFormat >= totFormat) { - void *moreSpace; - totFormat *= 2; - moreSpace = xrealloc(pFormat, - totFormat * sizeof(XvFormatRec)); - if(!moreSpace) break; - pFormat = moreSpace; - pf = pFormat + numFormat; - } - - pf->visual = pVisual->vid; - pf->depth = formatPtr->depth; - - pf++; - numFormat++; - } - pVisual++; - } - } - pa->nFormats = numFormat; - pa->pFormats = pFormat; - if(!numFormat) { - KdXVFreeAdaptor(pa); - continue; - } - - if(!(adaptorPriv = xcalloc(1, sizeof(XvAdaptorRecPrivate)))) { - KdXVFreeAdaptor(pa); - continue; - } - - adaptorPriv->flags = adaptorPtr->flags; - adaptorPriv->PutVideo = adaptorPtr->PutVideo; - adaptorPriv->PutStill = adaptorPtr->PutStill; - adaptorPriv->GetVideo = adaptorPtr->GetVideo; - adaptorPriv->GetStill = adaptorPtr->GetStill; - adaptorPriv->StopVideo = adaptorPtr->StopVideo; - adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute; - adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute; - adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize; - adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes; - adaptorPriv->PutImage = adaptorPtr->PutImage; - adaptorPriv->ReputImage = adaptorPtr->ReputImage; - - pa->devPriv.ptr = (pointer)adaptorPriv; - - if(!(pPort = xcalloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) { - KdXVFreeAdaptor(pa); - continue; - } - for(pp = pPort, i = 0, numPort = 0; - i < adaptorPtr->nPorts; i++) { - - if(!(pp->id = FakeClientID(0))) - continue; - - if(!(portPriv = xcalloc(1, sizeof(XvPortRecPrivate)))) - continue; - - if(!AddResource(pp->id, PortResource, pp)) { - xfree(portPriv); - continue; - } - - pp->pAdaptor = pa; - pp->pNotify = (XvPortNotifyPtr)NULL; - pp->pDraw = (DrawablePtr)NULL; - pp->client = (ClientPtr)NULL; - pp->grab.client = (ClientPtr)NULL; - pp->time = currentTime; - pp->devPriv.ptr = portPriv; - - portPriv->screen = screen; - portPriv->AdaptorRec = adaptorPriv; - portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr; - - pp++; - numPort++; - } - pa->nPorts = numPort; - pa->pPorts = pPort; - if(!numPort) { - KdXVFreeAdaptor(pa); - continue; - } - - pa->base_id = pPort->id; - - pa++; - numAdaptor++; - } - - if(numAdaptor) { - pxvs->nAdaptors = numAdaptor; - pxvs->pAdaptors = pAdaptor; - } else { - xfree(pAdaptor); - return FALSE; - } - - return TRUE; -} - -/* Video should be clipped to the intersection of the window cliplist - and the client cliplist specified in the GC for which the video was - initialized. When we need to reclip a window, the GC that started - the video may not even be around anymore. That's why we save the - client clip from the GC when the video is initialized. We then - use KdXVUpdateCompositeClip to calculate the new composite clip - when we need it. This is different from what DEC did. They saved - the GC and used it's clip list when they needed to reclip the window, - even if the client clip was different from the one the video was - initialized with. If the original GC was destroyed, they had to stop - the video. I like the new method better (MArk). - - This function only works for windows. Will need to rewrite when - (if) we support pixmap rendering. -*/ - -static void -KdXVUpdateCompositeClip(XvPortRecPrivatePtr portPriv) -{ - RegionPtr pregWin, pCompositeClip; - WindowPtr pWin; - Bool freeCompClip = FALSE; - - if(portPriv->pCompositeClip) - return; - - pWin = (WindowPtr)portPriv->pDraw; - - /* get window clip list */ - if(portPriv->subWindowMode == IncludeInferiors) { - pregWin = NotClippedByChildren(pWin); - freeCompClip = TRUE; - } else - pregWin = &pWin->clipList; - - if(!portPriv->clientClip) { - portPriv->pCompositeClip = pregWin; - portPriv->FreeCompositeClip = freeCompClip; - return; - } - - pCompositeClip = REGION_CREATE(pWin->pScreen, NullBox, 1); - REGION_COPY(pWin->pScreen, pCompositeClip, portPriv->clientClip); - REGION_TRANSLATE(pWin->pScreen, pCompositeClip, - portPriv->pDraw->x + portPriv->clipOrg.x, - portPriv->pDraw->y + portPriv->clipOrg.y); - REGION_INTERSECT(pWin->pScreen, pCompositeClip, pregWin, pCompositeClip); - - portPriv->pCompositeClip = pCompositeClip; - portPriv->FreeCompositeClip = TRUE; - - if(freeCompClip) { - REGION_DESTROY(pWin->pScreen, pregWin); - } -} - -/* Save the current clientClip and update the CompositeClip whenever - we have a fresh GC */ - -static void -KdXVCopyClip( - XvPortRecPrivatePtr portPriv, - GCPtr pGC -){ - /* copy the new clip if it exists */ - if((pGC->clientClipType == CT_REGION) && pGC->clientClip) { - if(!portPriv->clientClip) - portPriv->clientClip = REGION_CREATE(pGC->pScreen, NullBox, 1); - /* Note: this is in window coordinates */ - REGION_COPY(pGC->pScreen, portPriv->clientClip, pGC->clientClip); - } else if(portPriv->clientClip) { /* free the old clientClip */ - REGION_DESTROY(pGC->pScreen, portPriv->clientClip); - portPriv->clientClip = NULL; - } - - /* get rid of the old clip list */ - if(portPriv->pCompositeClip && portPriv->FreeCompositeClip) { - REGION_DESTROY(pWin->pScreen, portPriv->pCompositeClip); - } - - portPriv->clipOrg = pGC->clipOrg; - portPriv->pCompositeClip = pGC->pCompositeClip; - portPriv->FreeCompositeClip = FALSE; - portPriv->subWindowMode = pGC->subWindowMode; -} - -static int -KdXVRegetVideo(XvPortRecPrivatePtr portPriv) -{ - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - KdXVUpdateCompositeClip(portPriv); - - /* translate the video region to the screen */ - WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; - WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; - WinBox.x2 = WinBox.x1 + portPriv->drw_w; - WinBox.y2 = WinBox.y1 + portPriv->drw_h; - - /* clip to the window composite clip */ - REGION_INIT(portPriv->pDraw->pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(portPriv->pDraw->pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(portPriv->pDraw->pScreen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); - - /* that's all if it's totally obscured */ - if(!REGION_NOTEMPTY(portPriv->pDraw->pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(portPriv->pDraw->pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->GetVideo)(portPriv->screen, portPriv->pDraw, - portPriv->vid_x, portPriv->vid_y, - WinBox.x1, WinBox.y1, - portPriv->vid_w, portPriv->vid_h, - portPriv->drw_w, portPriv->drw_h, - &ClipRegion, portPriv->DevPriv.ptr); - - if(ret == Success) - portPriv->isOn = XV_ON; - -CLIP_VIDEO_BAILOUT: - - if((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - /* This clip was copied and only good for one shot */ - if(!portPriv->FreeCompositeClip) - portPriv->pCompositeClip = NULL; - - REGION_UNINIT(portPriv->pDraw->pScreen, &WinRegion); - REGION_UNINIT(portPriv->pDraw->pScreen, &ClipRegion); - - return ret; -} - - -static int -KdXVReputVideo(XvPortRecPrivatePtr portPriv) -{ - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - ScreenPtr pScreen = portPriv->pDraw->pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen=pScreenPriv->screen; - int ret = Success; - Bool clippedAway = FALSE; - - KdXVUpdateCompositeClip(portPriv); - - /* translate the video region to the screen */ - WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; - WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; - WinBox.x2 = WinBox.x1 + portPriv->drw_w; - WinBox.y2 = WinBox.y1 + portPriv->drw_h; - - /* clip to the window composite clip */ - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); - - /* clip and translate to the viewport */ - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = 0; - VPBox.y1 = 0; - VPBox.x2 = screen->width; - VPBox.y2 = screen->height; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - /* that's all if it's totally obscured */ - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - - /* bailout if we have to clip but the hardware doesn't support it */ - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->PutVideo)(portPriv->screen, portPriv->pDraw, - portPriv->vid_x, portPriv->vid_y, - WinBox.x1, WinBox.y1, - portPriv->vid_w, portPriv->vid_h, - portPriv->drw_w, portPriv->drw_h, - &ClipRegion, portPriv->DevPriv.ptr); - - if(ret == Success) portPriv->isOn = XV_ON; - -CLIP_VIDEO_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - /* This clip was copied and only good for one shot */ - if(!portPriv->FreeCompositeClip) - portPriv->pCompositeClip = NULL; - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - -static int -KdXVReputImage(XvPortRecPrivatePtr portPriv) -{ - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - ScreenPtr pScreen = portPriv->pDraw->pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen=pScreenPriv->screen; - int ret = Success; - Bool clippedAway = FALSE; - - KdXVUpdateCompositeClip(portPriv); - - /* translate the video region to the screen */ - WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; - WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; - WinBox.x2 = WinBox.x1 + portPriv->drw_w; - WinBox.y2 = WinBox.y1 + portPriv->drw_h; - - /* clip to the window composite clip */ - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); - - /* clip and translate to the viewport */ - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = 0; - VPBox.y1 = 0; - VPBox.x2 = screen->width; - VPBox.y2 = screen->height; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - /* that's all if it's totally obscured */ - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - - /* bailout if we have to clip but the hardware doesn't support it */ - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto CLIP_VIDEO_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->ReputImage)(portPriv->screen, portPriv->pDraw, - WinBox.x1, WinBox.y1, - &ClipRegion, portPriv->DevPriv.ptr); - - portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF; - -CLIP_VIDEO_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - /* This clip was copied and only good for one shot */ - if(!portPriv->FreeCompositeClip) - portPriv->pCompositeClip = NULL; - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - - -static int -KdXVReputAllVideo(WindowPtr pWin, pointer data) -{ - KdXVWindowPtr WinPriv; - - if (pWin->drawable.type != DRAWABLE_WINDOW) - return WT_DONTWALKCHILDREN; - - WinPriv = GET_KDXV_WINDOW(pWin); - - while(WinPriv) { - if(WinPriv->PortRec->type == XvInputMask) - KdXVReputVideo(WinPriv->PortRec); - else - KdXVRegetVideo(WinPriv->PortRec); - WinPriv = WinPriv->next; - } - - return WT_WALKCHILDREN; -} - -static int -KdXVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) -{ - KdXVWindowPtr winPriv, PrivRoot; - - winPriv = PrivRoot = GET_KDXV_WINDOW(pWin); - - /* Enlist our port in the window private */ - while(winPriv) { - if(winPriv->PortRec == portPriv) /* we're already listed */ - break; - winPriv = winPriv->next; - } - - if(!winPriv) { - winPriv = xalloc(sizeof(KdXVWindowRec)); - if(!winPriv) return BadAlloc; - winPriv->PortRec = portPriv; - winPriv->next = PrivRoot; - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, winPriv); - } - return Success; -} - - -static void -KdXVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) -{ - KdXVWindowPtr winPriv, prevPriv = NULL; - - winPriv = GET_KDXV_WINDOW(pWin); - - while(winPriv) { - if(winPriv->PortRec == portPriv) { - if(prevPriv) - prevPriv->next = winPriv->next; - else - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, winPriv->next); - xfree(winPriv); - break; - } - prevPriv = winPriv; - winPriv = winPriv->next; - } - portPriv->pDraw = NULL; -} - -/**** ScreenRec fields ****/ - - -static Bool -KdXVCreateWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); - int ret; - - pScreen->CreateWindow = ScreenPriv->CreateWindow; - ret = (*pScreen->CreateWindow)(pWin); - pScreen->CreateWindow = KdXVCreateWindow; - - if (ret) - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, NULL); - - return ret; -} - - -static Bool -KdXVDestroyWindow(WindowPtr pWin) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); - KdXVWindowPtr tmp, WinPriv = GET_KDXV_WINDOW(pWin); - int ret; - - while(WinPriv) { - XvPortRecPrivatePtr pPriv = WinPriv->PortRec; - - if(pPriv->isOn > XV_OFF) { - (*pPriv->AdaptorRec->StopVideo)( - pPriv->screen, pPriv->DevPriv.ptr, TRUE); - pPriv->isOn = XV_OFF; - } - - pPriv->pDraw = NULL; - tmp = WinPriv; - WinPriv = WinPriv->next; - xfree(tmp); - } - - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, NULL); - - pScreen->DestroyWindow = ScreenPriv->DestroyWindow; - ret = (*pScreen->DestroyWindow)(pWin); - pScreen->DestroyWindow = KdXVDestroyWindow; - - return ret; -} - - -static void -KdXVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); - KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); - KdXVWindowPtr pPrev; - XvPortRecPrivatePtr pPriv; - Bool AreasExposed; - - AreasExposed = (WinPriv && reg1 && REGION_NOTEMPTY(pScreen, reg1)); - - pScreen->WindowExposures = ScreenPriv->WindowExposures; - (*pScreen->WindowExposures)(pWin, reg1, reg2); - pScreen->WindowExposures = KdXVWindowExposures; - - /* filter out XClearWindow/Area */ - if (!pWin->valdata) return; - - pPrev = NULL; - - while(WinPriv) { - pPriv = WinPriv->PortRec; - - /* Reput anyone with a reput function */ - - switch(pPriv->type) { - case XvInputMask: - KdXVReputVideo(pPriv); - break; - case XvOutputMask: - KdXVRegetVideo(pPriv); - break; - default: /* overlaid still/image*/ - if (pPriv->AdaptorRec->ReputImage) - KdXVReputImage(pPriv); - else if(AreasExposed) { - KdXVWindowPtr tmp; - - if (pPriv->isOn == XV_ON) { - (*pPriv->AdaptorRec->StopVideo)( - pPriv->screen, pPriv->DevPriv.ptr, FALSE); - pPriv->isOn = XV_PENDING; - } - pPriv->pDraw = NULL; - - if(!pPrev) - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, WinPriv->next); - else - pPrev->next = WinPriv->next; - tmp = WinPriv; - WinPriv = WinPriv->next; - xfree(tmp); - continue; - } - break; - } - pPrev = WinPriv; - WinPriv = WinPriv->next; - } -} - - -static void -KdXVClipNotify(WindowPtr pWin, int dx, int dy) -{ - ScreenPtr pScreen = pWin->drawable.pScreen; - KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); - KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); - KdXVWindowPtr tmp, pPrev = NULL; - XvPortRecPrivatePtr pPriv; - Bool visible = (pWin->visibility == VisibilityUnobscured) || - (pWin->visibility == VisibilityPartiallyObscured); - - while(WinPriv) { - pPriv = WinPriv->PortRec; - - if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) - REGION_DESTROY(pScreen, pPriv->pCompositeClip); - - pPriv->pCompositeClip = NULL; - - /* Stop everything except images, but stop them too if the - window isn't visible. But we only remove the images. */ - - if(pPriv->type || !visible) { - if(pPriv->isOn == XV_ON) { - (*pPriv->AdaptorRec->StopVideo)( - pPriv->screen, pPriv->DevPriv.ptr, FALSE); - pPriv->isOn = XV_PENDING; - } - - if(!pPriv->type) { /* overlaid still/image */ - pPriv->pDraw = NULL; - - if(!pPrev) - dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, WinPriv->next); - else - pPrev->next = WinPriv->next; - tmp = WinPriv; - WinPriv = WinPriv->next; - xfree(tmp); - continue; - } - } - - pPrev = WinPriv; - WinPriv = WinPriv->next; - } - - if(ScreenPriv->ClipNotify) { - pScreen->ClipNotify = ScreenPriv->ClipNotify; - (*pScreen->ClipNotify)(pWin, dx, dy); - pScreen->ClipNotify = KdXVClipNotify; - } -} - - - -/**** Required XvScreenRec fields ****/ - -static Bool -KdXVCloseScreen(int i, ScreenPtr pScreen) -{ - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); - XvAdaptorPtr pa; - int c; - - if(!ScreenPriv) return TRUE; - - pScreen->CreateWindow = ScreenPriv->CreateWindow; - pScreen->DestroyWindow = ScreenPriv->DestroyWindow; - pScreen->WindowExposures = ScreenPriv->WindowExposures; - pScreen->ClipNotify = ScreenPriv->ClipNotify; - -/* fprintf(stderr,"XV: Unwrapping screen funcs\n"); */ - - for(c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) { - KdXVFreeAdaptor(pa); - } - - xfree(pxvs->pAdaptors); - xfree(ScreenPriv); - - return TRUE; -} - - -static int -KdXVQueryAdaptors( - ScreenPtr pScreen, - XvAdaptorPtr *p_pAdaptors, - int *p_nAdaptors -){ - XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); - - *p_nAdaptors = pxvs->nAdaptors; - *p_pAdaptors = pxvs->pAdaptors; - - return (Success); -} - -static Bool -KdXVRunning (ScreenPtr pScreen) -{ - return (KdXVGeneration == serverGeneration && - GET_XV_SCREEN(pScreen) != 0); -} - -Bool -KdXVEnable(ScreenPtr pScreen) -{ - if (!KdXVRunning (pScreen)) - return TRUE; - - WalkTree(pScreen, KdXVReputAllVideo, 0); - - return TRUE; -} - -void -KdXVDisable(ScreenPtr pScreen) -{ - XvScreenPtr pxvs; - KdXVScreenPtr ScreenPriv; - XvAdaptorPtr pAdaptor; - XvPortPtr pPort; - XvPortRecPrivatePtr pPriv; - int i, j; - - if (!KdXVRunning (pScreen)) - return; - - pxvs = GET_XV_SCREEN(pScreen); - ScreenPriv = GET_KDXV_SCREEN(pScreen); - - for(i = 0; i < pxvs->nAdaptors; i++) { - pAdaptor = &pxvs->pAdaptors[i]; - for(j = 0; j < pAdaptor->nPorts; j++) { - pPort = &pAdaptor->pPorts[j]; - pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; - if(pPriv->isOn > XV_OFF) { - - (*pPriv->AdaptorRec->StopVideo)( - pPriv->screen, pPriv->DevPriv.ptr, TRUE); - pPriv->isOn = XV_OFF; - - if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) - REGION_DESTROY(pScreen, pPriv->pCompositeClip); - - pPriv->pCompositeClip = NULL; - - if(!pPriv->type && pPriv->pDraw) { /* still */ - KdXVRemovePortFromWindow((WindowPtr)pPriv->pDraw, pPriv); - } - } - } - } -} - -/**** XvAdaptorRec fields ****/ - -static int -KdXVAllocatePort( - unsigned long port, - XvPortPtr pPort, - XvPortPtr *ppPort -){ - *ppPort = pPort; - return Success; -} - -static int -KdXVFreePort(XvPortPtr pPort) -{ - return Success; -} - -static int -KdXVPutVideo( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - KdScreenPriv(portPriv->screen->pScreen); - int result; - - /* No dumping video to pixmaps... For now anyhow */ - if(pDraw->type != DRAWABLE_WINDOW) { - pPort->pDraw = (DrawablePtr)NULL; - return BadAlloc; - } - - /* If we are changing windows, unregister our port in the old window */ - if(portPriv->pDraw && (portPriv->pDraw != pDraw)) - KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - - /* Register our port with the new window */ - result = KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - if(result != Success) return result; - - portPriv->pDraw = pDraw; - portPriv->type = XvInputMask; - - /* save a copy of these parameters */ - portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; - portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - - /* make sure we have the most recent copy of the clientClip */ - KdXVCopyClip(portPriv, pGC); - - /* To indicate to the DI layer that we were successful */ - pPort->pDraw = pDraw; - - if (!pScreenPriv->enabled) return Success; - - return(KdXVReputVideo(portPriv)); -} - -static int -KdXVPutStill( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - ScreenPtr pScreen = pDraw->pScreen; - KdScreenPriv(pScreen); - KdScreenInfo *screen=pScreenPriv->screen; - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - if (pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - if (!pScreenPriv->enabled) return Success; - - WinBox.x1 = pDraw->x + drw_x; - WinBox.y1 = pDraw->y + drw_y; - WinBox.x2 = WinBox.x1 + drw_w; - WinBox.y2 = WinBox.y1 + drw_h; - - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); - - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = 0; - VPBox.y1 = 0; - VPBox.x2 = screen->width; - VPBox.y2 = screen->height; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - if(portPriv->pDraw) { - KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - } - - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto PUT_STILL_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto PUT_STILL_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->PutStill)(portPriv->screen, pDraw, - vid_x, vid_y, WinBox.x1, WinBox.y1, - vid_w, vid_h, drw_w, drw_h, - &ClipRegion, portPriv->DevPriv.ptr); - - if((ret == Success) && - (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) { - - KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - portPriv->isOn = XV_ON; - portPriv->pDraw = pDraw; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - portPriv->type = 0; /* no mask means it's transient and should - not be reput once it's removed */ - pPort->pDraw = pDraw; /* make sure we can get stop requests */ - } - -PUT_STILL_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - -static int -KdXVGetVideo( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - int result; - KdScreenPriv(portPriv->screen->pScreen); - - /* No pixmaps... For now anyhow */ - if(pDraw->type != DRAWABLE_WINDOW) { - pPort->pDraw = (DrawablePtr)NULL; - return BadAlloc; - } - - /* If we are changing windows, unregister our port in the old window */ - if(portPriv->pDraw && (portPriv->pDraw != pDraw)) - KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - - /* Register our port with the new window */ - result = KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - if(result != Success) return result; - - portPriv->pDraw = pDraw; - portPriv->type = XvOutputMask; - - /* save a copy of these parameters */ - portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; - portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - - /* make sure we have the most recent copy of the clientClip */ - KdXVCopyClip(portPriv, pGC); - - /* To indicate to the DI layer that we were successful */ - pPort->pDraw = pDraw; - - if(!pScreenPriv->enabled) return Success; - - return(KdXVRegetVideo(portPriv)); -} - -static int -KdXVGetStill( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 vid_x, INT16 vid_y, - CARD16 vid_w, CARD16 vid_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - ScreenPtr pScreen = pDraw->pScreen; - KdScreenPriv(pScreen); - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - if (pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - if(!pScreenPriv->enabled) return Success; - - WinBox.x1 = pDraw->x + drw_x; - WinBox.y1 = pDraw->y + drw_y; - WinBox.x2 = WinBox.x1 + drw_w; - WinBox.y2 = WinBox.y1 + drw_h; - - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); - - if(portPriv->pDraw) { - KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - } - - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto GET_STILL_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->GetStill)(portPriv->screen, pDraw, - vid_x, vid_y, WinBox.x1, WinBox.y1, - vid_w, vid_h, drw_w, drw_h, - &ClipRegion, portPriv->DevPriv.ptr); - -GET_STILL_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - - - -static int -KdXVStopVideo( - ClientPtr client, - XvPortPtr pPort, - DrawablePtr pDraw -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - KdScreenPriv(portPriv->screen->pScreen); - - if(pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - KdXVRemovePortFromWindow((WindowPtr)pDraw, portPriv); - - if(!pScreenPriv->enabled) return Success; - - /* Must free resources. */ - - if(portPriv->isOn > XV_OFF) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, TRUE); - portPriv->isOn = XV_OFF; - } - - return Success; -} - -static int -KdXVSetPortAttribute( - ClientPtr client, - XvPortPtr pPort, - Atom attribute, - INT32 value -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - return((*portPriv->AdaptorRec->SetPortAttribute)(portPriv->screen, - attribute, value, portPriv->DevPriv.ptr)); -} - - -static int -KdXVGetPortAttribute( - ClientPtr client, - XvPortPtr pPort, - Atom attribute, - INT32 *p_value -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - return((*portPriv->AdaptorRec->GetPortAttribute)(portPriv->screen, - attribute, (int *) p_value, portPriv->DevPriv.ptr)); -} - - - -static int -KdXVQueryBestSize( - ClientPtr client, - XvPortPtr pPort, - CARD8 motion, - CARD16 vid_w, CARD16 vid_h, - CARD16 drw_w, CARD16 drw_h, - unsigned int *p_w, unsigned int *p_h -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - (*portPriv->AdaptorRec->QueryBestSize)(portPriv->screen, - (Bool)motion, vid_w, vid_h, drw_w, drw_h, - p_w, p_h, portPriv->DevPriv.ptr); - - return Success; -} - - -static int -KdXVPutImage( - ClientPtr client, - DrawablePtr pDraw, - XvPortPtr pPort, - GCPtr pGC, - INT16 src_x, INT16 src_y, - CARD16 src_w, CARD16 src_h, - INT16 drw_x, INT16 drw_y, - CARD16 drw_w, CARD16 drw_h, - XvImagePtr format, - unsigned char* data, - Bool sync, - CARD16 width, CARD16 height -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - ScreenPtr pScreen = pDraw->pScreen; - KdScreenPriv(pScreen); - RegionRec WinRegion; - RegionRec ClipRegion; - BoxRec WinBox; - int ret = Success; - Bool clippedAway = FALSE; - - if (pDraw->type != DRAWABLE_WINDOW) - return BadAlloc; - - if(!pScreenPriv->enabled) return Success; - - WinBox.x1 = pDraw->x + drw_x; - WinBox.y1 = pDraw->y + drw_y; - WinBox.x2 = WinBox.x1 + drw_w; - WinBox.y2 = WinBox.y1 + drw_h; - - REGION_INIT(pScreen, &WinRegion, &WinBox, 1); - REGION_INIT(pScreen, &ClipRegion, NullBox, 1); - REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); - - if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { - RegionRec VPReg; - BoxRec VPBox; - - VPBox.x1 = 0; - VPBox.y1 = 0; - VPBox.x2 = pScreen->width; - VPBox.y2 = pScreen->height; - - REGION_INIT(pScreen, &VPReg, &VPBox, 1); - REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); - REGION_UNINIT(pScreen, &VPReg); - } - - if(portPriv->pDraw) { - KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); - } - - if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { - clippedAway = TRUE; - goto PUT_IMAGE_BAILOUT; - } - - if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { - BoxPtr clipBox = REGION_RECTS(&ClipRegion); - if( (REGION_NUM_RECTS(&ClipRegion) != 1) || - (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || - (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) - { - clippedAway = TRUE; - goto PUT_IMAGE_BAILOUT; - } - } - - if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { - REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); - } - - ret = (*portPriv->AdaptorRec->PutImage)(portPriv->screen, pDraw, - src_x, src_y, WinBox.x1, WinBox.y1, - src_w, src_h, drw_w, drw_h, format->id, data, width, height, - sync, &ClipRegion, portPriv->DevPriv.ptr); - - if((ret == Success) && - (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) { - - KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); - portPriv->isOn = XV_ON; - portPriv->pDraw = pDraw; - portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; - portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; - portPriv->type = 0; /* no mask means it's transient and should - not be reput once it's removed */ - pPort->pDraw = pDraw; /* make sure we can get stop requests */ - } - -PUT_IMAGE_BAILOUT: - - if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { - (*portPriv->AdaptorRec->StopVideo)( - portPriv->screen, portPriv->DevPriv.ptr, FALSE); - portPriv->isOn = XV_PENDING; - } - - REGION_UNINIT(pScreen, &WinRegion); - REGION_UNINIT(pScreen, &ClipRegion); - - return ret; -} - - -static int -KdXVQueryImageAttributes( - ClientPtr client, - XvPortPtr pPort, - XvImagePtr format, - CARD16 *width, - CARD16 *height, - int *pitches, - int *offsets -){ - XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); - - return (*portPriv->AdaptorRec->QueryImageAttributes)(portPriv->screen, - format->id, width, height, pitches, offsets); -} - - -/**************** Common video manipulation functions *******************/ - -void -KdXVCopyPackedData(KdScreenInfo *screen, CARD8 *src, CARD8 *dst, int randr, - int srcPitch, int dstPitch, int srcW, int srcH, int top, int left, - int h, int w) -{ - int srcDown = srcPitch, srcRight = 2, srcNext; - int p; - - switch (randr & RR_Rotate_All) { - case RR_Rotate_0: - srcDown = srcPitch; - srcRight = 2; - break; - case RR_Rotate_90: - src += (srcH - 1) * 2; - srcDown = -2; - srcRight = srcPitch; - break; - case RR_Rotate_180: - src += srcPitch * (srcH - 1) + (srcW - 1) * 2; - srcDown = -srcPitch; - srcRight = -2; - break; - case RR_Rotate_270: - src += srcPitch * (srcW - 1); - srcDown = 2; - srcRight = -srcPitch; - break; - } - - src = src + top * srcDown + left * srcRight; - - w >>= 1; - /* srcRight >>= 1; */ - srcNext = srcRight >> 1; - while (h--) { - CARD16 *s = (CARD16 *)src; - CARD32 *d = (CARD32 *)dst; - p = w; - while (p--) { - *d++ = s[0] | (s[srcNext] << 16); - s += srcRight; - } - src += srcPitch; - dst += dstPitch; - } -} - -void -KdXVCopyPlanarData(KdScreenInfo *screen, CARD8 *src, CARD8 *dst, int randr, - int srcPitch, int srcPitch2, int dstPitch, int srcW, int srcH, int height, - int top, int left, int h, int w, int id) -{ - int i, j; - CARD8 *src1, *src2, *src3, *dst1; - int srcDown = srcPitch, srcDown2 = srcPitch2; - int srcRight = 2, srcRight2 = 1, srcNext = 1; - - /* compute source data pointers */ - src1 = src; - src2 = src1 + height * srcPitch; - src3 = src2 + (height >> 1) * srcPitch2; - switch (randr & RR_Rotate_All) { - case RR_Rotate_0: - srcDown = srcPitch; - srcDown2 = srcPitch2; - srcRight = 2; - srcRight2 = 1; - srcNext = 1; - break; - case RR_Rotate_90: - src1 = src1 + srcH - 1; - src2 = src2 + (srcH >> 1) - 1; - src3 = src3 + (srcH >> 1) - 1; - srcDown = -1; - srcDown2 = -1; - srcRight = srcPitch * 2; - srcRight2 = srcPitch2; - srcNext = srcPitch; - break; - case RR_Rotate_180: - src1 = src1 + srcPitch * (srcH - 1) + (srcW - 1); - src2 = src2 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1); - src3 = src3 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1); - srcDown = -srcPitch; - srcDown2 = -srcPitch2; - srcRight = -2; - srcRight2 = -1; - srcNext = -1; - break; - case RR_Rotate_270: - src1 = src1 + srcPitch * (srcW - 1); - src2 = src2 + srcPitch2 * ((srcW >> 1) - 1); - src3 = src3 + srcPitch2 * ((srcW >> 1) - 1); - srcDown = 1; - srcDown2 = 1; - srcRight = -srcPitch * 2; - srcRight2 = -srcPitch2; - srcNext = -srcPitch; - break; - } - - /* adjust for origin */ - src1 += top * srcDown + left * srcNext; - src2 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2; - src3 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2; - - if (id == FOURCC_I420) { - CARD8 *srct = src2; - src2 = src3; - src3 = srct; - } - - dst1 = dst; - - w >>= 1; - for (j = 0; j < h; j++) { - CARD32 *dst = (CARD32 *)dst1; - CARD8 *s1l = src1; - CARD8 *s1r = src1 + srcNext; - CARD8 *s2 = src2; - CARD8 *s3 = src3; - - for (i = 0; i < w; i++) { - *dst++ = *s1l | (*s1r << 16) | (*s3 << 8) | (*s2 << 24); - s1l += srcRight; - s1r += srcRight; - s2 += srcRight2; - s3 += srcRight2; - } - src1 += srcDown; - dst1 += dstPitch; - if (j & 1) { - src2 += srcDown2; - src3 += srcDown2; - } - } -} - -void -KXVPaintRegion (DrawablePtr pDraw, RegionPtr pRgn, Pixel fg) -{ - GCPtr pGC; - CARD32 val[2]; - xRectangle *rects, *r; - BoxPtr pBox = REGION_RECTS (pRgn); - int nBox = REGION_NUM_RECTS (pRgn); - - rects = xalloc (nBox * sizeof (xRectangle)); - if (!rects) - goto bail0; - r = rects; - while (nBox--) - { - r->x = pBox->x1 - pDraw->x; - r->y = pBox->y1 - pDraw->y; - r->width = pBox->x2 - pBox->x1; - r->height = pBox->y2 - pBox->y1; - r++; - pBox++; - } - - pGC = GetScratchGC (pDraw->depth, pDraw->pScreen); - if (!pGC) - goto bail1; - - val[0] = fg; - val[1] = IncludeInferiors; - ChangeGC (pGC, GCForeground|GCSubwindowMode, val); - - ValidateGC (pDraw, pGC); - - (*pGC->ops->PolyFillRect) (pDraw, pGC, - REGION_NUM_RECTS (pRgn), rects); - - FreeScratchGC (pGC); -bail1: - xfree (rects); -bail0: - ; -} +/* + + XFree86 Xv DDX written by Mark Vojkovich (markv@valinux.com) + Adapted for KDrive by Pontus Lidman + + Copyright (C) 2000, 2001 - Nokia Home Communications + Copyright (C) 1998, 1999 - The XFree86 Project 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, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +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 +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR 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. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include "kdrive.h" + +#include "scrnintstr.h" +#include "regionstr.h" +#include "windowstr.h" +#include "pixmapstr.h" +#include "mivalidate.h" +#include "validate.h" +#include "resource.h" +#include "gcstruct.h" +#include "dixstruct.h" + +#include +#include + +#include "kxv.h" +#include "fourcc.h" + + +/* XvScreenRec fields */ + +static Bool KdXVCloseScreen(int, ScreenPtr); +static int KdXVQueryAdaptors(ScreenPtr, XvAdaptorPtr *, int *); + +/* XvAdaptorRec fields */ + +static int KdXVAllocatePort(unsigned long, XvPortPtr, XvPortPtr*); +static int KdXVFreePort(XvPortPtr); +static int KdXVPutVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVPutStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVGetVideo(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVGetStill(ClientPtr, DrawablePtr,XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16); +static int KdXVStopVideo(ClientPtr, XvPortPtr, DrawablePtr); +static int KdXVSetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32); +static int KdXVGetPortAttribute(ClientPtr, XvPortPtr, Atom, INT32 *); +static int KdXVQueryBestSize(ClientPtr, XvPortPtr, CARD8, + CARD16, CARD16,CARD16, CARD16, + unsigned int*, unsigned int*); +static int KdXVPutImage(ClientPtr, DrawablePtr, XvPortPtr, GCPtr, + INT16, INT16, CARD16, CARD16, + INT16, INT16, CARD16, CARD16, + XvImagePtr, unsigned char*, Bool, + CARD16, CARD16); +static int KdXVQueryImageAttributes(ClientPtr, XvPortPtr, XvImagePtr, + CARD16*, CARD16*, int*, int*); + + +/* ScreenRec fields */ + +static Bool KdXVCreateWindow(WindowPtr pWin); +static Bool KdXVDestroyWindow(WindowPtr pWin); +static void KdXVWindowExposures(WindowPtr pWin, RegionPtr r1, RegionPtr r2); +static void KdXVClipNotify(WindowPtr pWin, int dx, int dy); + +/* misc */ +static Bool KdXVInitAdaptors(ScreenPtr, KdVideoAdaptorPtr*, int); + +static int KdXVWindowKeyIndex; +DevPrivateKey KdXVWindowKey = &KdXVWindowKeyIndex; +static int KdXvScreenKeyIndex; +DevPrivateKey KdXvScreenKey = &KdXvScreenKeyIndex; +static unsigned long KdXVGeneration = 0; +static unsigned long PortResource = 0; + +DevPrivateKey (*XvGetScreenKeyProc)(void) = XvGetScreenKey; +unsigned long (*XvGetRTPortProc)(void) = XvGetRTPort; +int (*XvScreenInitProc)(ScreenPtr) = XvScreenInit; + +#define GET_XV_SCREEN(pScreen) ((XvScreenPtr) \ + dixLookupPrivate(&(pScreen)->devPrivates, KdXvScreenKey)) + +#define GET_KDXV_SCREEN(pScreen) \ + ((KdXVScreenPtr)(GET_XV_SCREEN(pScreen)->devPriv.ptr)) + +#define GET_KDXV_WINDOW(pWin) ((KdXVWindowPtr) \ + dixLookupPrivate(&(pWin)->devPrivates, KdXVWindowKey)) + +static KdXVInitGenericAdaptorPtr *GenDrivers = NULL; +static int NumGenDrivers = 0; + +int +KdXVRegisterGenericAdaptorDriver( + KdXVInitGenericAdaptorPtr InitFunc +){ + KdXVInitGenericAdaptorPtr *newdrivers; + +/* fprintf(stderr,"KdXVRegisterGenericAdaptorDriver\n"); */ + + newdrivers = realloc(GenDrivers, sizeof(KdXVInitGenericAdaptorPtr) * + (1 + NumGenDrivers)); + if (!newdrivers) + return 0; + GenDrivers = newdrivers; + + GenDrivers[NumGenDrivers++] = InitFunc; + + return 1; +} + +int +KdXVListGenericAdaptors( + KdScreenInfo * screen, + KdVideoAdaptorPtr **adaptors +){ + int i,j,n,num; + KdVideoAdaptorPtr *DrivAdap,*new; + + num = 0; + *adaptors = NULL; + for (i = 0; i < NumGenDrivers; i++) { + n = GenDrivers[i](screen,&DrivAdap); + if (0 == n) + continue; + new = realloc(*adaptors, sizeof(KdVideoAdaptorPtr) * (num+n)); + if (NULL == new) + continue; + *adaptors = new; + for (j = 0; j < n; j++, num++) + (*adaptors)[num] = DrivAdap[j]; + } + return num; +} + +KdVideoAdaptorPtr +KdXVAllocateVideoAdaptorRec(KdScreenInfo * screen) +{ + return calloc(1, sizeof(KdVideoAdaptorRec)); +} + +void +KdXVFreeVideoAdaptorRec(KdVideoAdaptorPtr ptr) +{ + free(ptr); +} + + +Bool +KdXVScreenInit( + ScreenPtr pScreen, + KdVideoAdaptorPtr *adaptors, + int num +){ + KdXVScreenPtr ScreenPriv; + XvScreenPtr pxvs; + +/* fprintf(stderr,"KdXVScreenInit initializing %d adaptors\n",num); */ + + if (KdXVGeneration != serverGeneration) + KdXVGeneration = serverGeneration; + + if(!XvGetScreenKeyProc || !XvGetRTPortProc || !XvScreenInitProc) + return FALSE; + + if(Success != (*XvScreenInitProc)(pScreen)) return FALSE; + + KdXvScreenKey = (*XvGetScreenKeyProc)(); + PortResource = (*XvGetRTPortProc)(); + + pxvs = GET_XV_SCREEN(pScreen); + + + /* Anyone initializing the Xv layer must provide these two. + The Xv di layer calls them without even checking if they exist! */ + + pxvs->ddCloseScreen = KdXVCloseScreen; + pxvs->ddQueryAdaptors = KdXVQueryAdaptors; + + /* The Xv di layer provides us with a private hook so that we don't + have to allocate our own screen private. They also provide + a CloseScreen hook so that we don't have to wrap it. I'm not + sure that I appreciate that. */ + + ScreenPriv = malloc(sizeof(KdXVScreenRec)); + pxvs->devPriv.ptr = (pointer)ScreenPriv; + + if(!ScreenPriv) return FALSE; + + + ScreenPriv->CreateWindow = pScreen->CreateWindow; + ScreenPriv->DestroyWindow = pScreen->DestroyWindow; + ScreenPriv->WindowExposures = pScreen->WindowExposures; + ScreenPriv->ClipNotify = pScreen->ClipNotify; + +/* fprintf(stderr,"XV: Wrapping screen funcs\n"); */ + + pScreen->CreateWindow = KdXVCreateWindow; + pScreen->DestroyWindow = KdXVDestroyWindow; + pScreen->WindowExposures = KdXVWindowExposures; + pScreen->ClipNotify = KdXVClipNotify; + + if(!KdXVInitAdaptors(pScreen, adaptors, num)) + return FALSE; + + return TRUE; +} + +static void +KdXVFreeAdaptor(XvAdaptorPtr pAdaptor) +{ + int i; + + free(pAdaptor->name); + + if(pAdaptor->pEncodings) { + XvEncodingPtr pEncode = pAdaptor->pEncodings; + + for(i = 0; i < pAdaptor->nEncodings; i++, pEncode++) { + free(pEncode->name); + } + free(pAdaptor->pEncodings); + } + + free(pAdaptor->pFormats); + + if(pAdaptor->pPorts) { + XvPortPtr pPort = pAdaptor->pPorts; + XvPortRecPrivatePtr pPriv; + + for(i = 0; i < pAdaptor->nPorts; i++, pPort++) { + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + if(pPriv) { + if(pPriv->clientClip) + REGION_DESTROY(pAdaptor->pScreen, pPriv->clientClip); + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pAdaptor->pScreen, pPriv->pCompositeClip); + free(pPriv); + } + } + free(pAdaptor->pPorts); + } + + if(pAdaptor->nAttributes) { + XvAttributePtr pAttribute = pAdaptor->pAttributes; + + for(i = 0; i < pAdaptor->nAttributes; i++, pAttribute++) { + free(pAttribute->name); + } + + free(pAdaptor->pAttributes); + } + + free(pAdaptor->pImages); + + free(pAdaptor->devPriv.ptr); +} + +static Bool +KdXVInitAdaptors( + ScreenPtr pScreen, + KdVideoAdaptorPtr *infoPtr, + int number +) { + KdScreenPriv(pScreen); + KdScreenInfo * screen = pScreenPriv->screen; + + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + KdVideoAdaptorPtr adaptorPtr; + XvAdaptorPtr pAdaptor, pa; + XvAdaptorRecPrivatePtr adaptorPriv; + int na, numAdaptor; + XvPortRecPrivatePtr portPriv; + XvPortPtr pPort, pp; + int numPort; + KdAttributePtr attributePtr; + XvAttributePtr pAttribute, pat; + KdVideoFormatPtr formatPtr; + XvFormatPtr pFormat, pf; + int numFormat, totFormat; + KdVideoEncodingPtr encodingPtr; + XvEncodingPtr pEncode, pe; + KdImagePtr imagePtr; + XvImagePtr pImage, pi; + int numVisuals; + VisualPtr pVisual; + int i; + + pxvs->nAdaptors = 0; + pxvs->pAdaptors = NULL; + + if(!(pAdaptor = calloc(number, sizeof(XvAdaptorRec)))) + return FALSE; + + for(pa = pAdaptor, na = 0, numAdaptor = 0; na < number; na++, adaptorPtr++) { + adaptorPtr = infoPtr[na]; + + if(!adaptorPtr->StopVideo || !adaptorPtr->SetPortAttribute || + !adaptorPtr->GetPortAttribute || !adaptorPtr->QueryBestSize) + continue; + + /* client libs expect at least one encoding */ + if(!adaptorPtr->nEncodings || !adaptorPtr->pEncodings) + continue; + + pa->type = adaptorPtr->type; + + if(!adaptorPtr->PutVideo && !adaptorPtr->GetVideo) + pa->type &= ~XvVideoMask; + + if(!adaptorPtr->PutStill && !adaptorPtr->GetStill) + pa->type &= ~XvStillMask; + + if(!adaptorPtr->PutImage || !adaptorPtr->QueryImageAttributes) + pa->type &= ~XvImageMask; + + if(!adaptorPtr->PutVideo && !adaptorPtr->PutImage && + !adaptorPtr->PutStill) + pa->type &= ~XvInputMask; + + if(!adaptorPtr->GetVideo && !adaptorPtr->GetStill) + pa->type &= ~XvOutputMask; + + if(!(adaptorPtr->type & (XvPixmapMask | XvWindowMask))) + continue; + if(!(adaptorPtr->type & (XvImageMask | XvVideoMask | XvStillMask))) + continue; + + pa->pScreen = pScreen; + pa->ddAllocatePort = KdXVAllocatePort; + pa->ddFreePort = KdXVFreePort; + pa->ddPutVideo = KdXVPutVideo; + pa->ddPutStill = KdXVPutStill; + pa->ddGetVideo = KdXVGetVideo; + pa->ddGetStill = KdXVGetStill; + pa->ddStopVideo = KdXVStopVideo; + pa->ddPutImage = KdXVPutImage; + pa->ddSetPortAttribute = KdXVSetPortAttribute; + pa->ddGetPortAttribute = KdXVGetPortAttribute; + pa->ddQueryBestSize = KdXVQueryBestSize; + pa->ddQueryImageAttributes = KdXVQueryImageAttributes; + if((pa->name = malloc(strlen(adaptorPtr->name) + 1))) + strcpy(pa->name, adaptorPtr->name); + + if(adaptorPtr->nEncodings && + (pEncode = calloc(adaptorPtr->nEncodings, sizeof(XvEncodingRec)))) { + + for(pe = pEncode, encodingPtr = adaptorPtr->pEncodings, i = 0; + i < adaptorPtr->nEncodings; pe++, i++, encodingPtr++) + { + pe->id = encodingPtr->id; + pe->pScreen = pScreen; + if((pe->name = malloc(strlen(encodingPtr->name) + 1))) + strcpy(pe->name, encodingPtr->name); + pe->width = encodingPtr->width; + pe->height = encodingPtr->height; + pe->rate.numerator = encodingPtr->rate.numerator; + pe->rate.denominator = encodingPtr->rate.denominator; + } + pa->nEncodings = adaptorPtr->nEncodings; + pa->pEncodings = pEncode; + } + + if(adaptorPtr->nImages && + (pImage = calloc(adaptorPtr->nImages, sizeof(XvImageRec)))) { + + for(i = 0, pi = pImage, imagePtr = adaptorPtr->pImages; + i < adaptorPtr->nImages; i++, pi++, imagePtr++) + { + pi->id = imagePtr->id; + pi->type = imagePtr->type; + pi->byte_order = imagePtr->byte_order; + memcpy(pi->guid, imagePtr->guid, 16); + pi->bits_per_pixel = imagePtr->bits_per_pixel; + pi->format = imagePtr->format; + pi->num_planes = imagePtr->num_planes; + pi->depth = imagePtr->depth; + pi->red_mask = imagePtr->red_mask; + pi->green_mask = imagePtr->green_mask; + pi->blue_mask = imagePtr->blue_mask; + pi->y_sample_bits = imagePtr->y_sample_bits; + pi->u_sample_bits = imagePtr->u_sample_bits; + pi->v_sample_bits = imagePtr->v_sample_bits; + pi->horz_y_period = imagePtr->horz_y_period; + pi->horz_u_period = imagePtr->horz_u_period; + pi->horz_v_period = imagePtr->horz_v_period; + pi->vert_y_period = imagePtr->vert_y_period; + pi->vert_u_period = imagePtr->vert_u_period; + pi->vert_v_period = imagePtr->vert_v_period; + memcpy(pi->component_order, imagePtr->component_order, 32); + pi->scanline_order = imagePtr->scanline_order; + } + pa->nImages = adaptorPtr->nImages; + pa->pImages = pImage; + } + + if(adaptorPtr->nAttributes && + (pAttribute = calloc(adaptorPtr->nAttributes, sizeof(XvAttributeRec)))) + { + for(pat = pAttribute, attributePtr = adaptorPtr->pAttributes, i = 0; + i < adaptorPtr->nAttributes; pat++, i++, attributePtr++) + { + pat->flags = attributePtr->flags; + pat->min_value = attributePtr->min_value; + pat->max_value = attributePtr->max_value; + if((pat->name = malloc(strlen(attributePtr->name) + 1))) + strcpy(pat->name, attributePtr->name); + } + pa->nAttributes = adaptorPtr->nAttributes; + pa->pAttributes = pAttribute; + } + + + totFormat = adaptorPtr->nFormats; + + if(!(pFormat = calloc(totFormat, sizeof(XvFormatRec)))) { + KdXVFreeAdaptor(pa); + continue; + } + for(pf = pFormat, i = 0, numFormat = 0, formatPtr = adaptorPtr->pFormats; + i < adaptorPtr->nFormats; i++, formatPtr++) + { + numVisuals = pScreen->numVisuals; + pVisual = pScreen->visuals; + + while(numVisuals--) { + if((pVisual->class == formatPtr->class) && + (pVisual->nplanes == formatPtr->depth)) { + + if(numFormat >= totFormat) { + void *moreSpace; + totFormat *= 2; + moreSpace = realloc(pFormat, + totFormat * sizeof(XvFormatRec)); + if(!moreSpace) break; + pFormat = moreSpace; + pf = pFormat + numFormat; + } + + pf->visual = pVisual->vid; + pf->depth = formatPtr->depth; + + pf++; + numFormat++; + } + pVisual++; + } + } + pa->nFormats = numFormat; + pa->pFormats = pFormat; + if(!numFormat) { + KdXVFreeAdaptor(pa); + continue; + } + + if(!(adaptorPriv = calloc(1, sizeof(XvAdaptorRecPrivate)))) { + KdXVFreeAdaptor(pa); + continue; + } + + adaptorPriv->flags = adaptorPtr->flags; + adaptorPriv->PutVideo = adaptorPtr->PutVideo; + adaptorPriv->PutStill = adaptorPtr->PutStill; + adaptorPriv->GetVideo = adaptorPtr->GetVideo; + adaptorPriv->GetStill = adaptorPtr->GetStill; + adaptorPriv->StopVideo = adaptorPtr->StopVideo; + adaptorPriv->SetPortAttribute = adaptorPtr->SetPortAttribute; + adaptorPriv->GetPortAttribute = adaptorPtr->GetPortAttribute; + adaptorPriv->QueryBestSize = adaptorPtr->QueryBestSize; + adaptorPriv->QueryImageAttributes = adaptorPtr->QueryImageAttributes; + adaptorPriv->PutImage = adaptorPtr->PutImage; + adaptorPriv->ReputImage = adaptorPtr->ReputImage; + + pa->devPriv.ptr = (pointer)adaptorPriv; + + if(!(pPort = calloc(adaptorPtr->nPorts, sizeof(XvPortRec)))) { + KdXVFreeAdaptor(pa); + continue; + } + for(pp = pPort, i = 0, numPort = 0; + i < adaptorPtr->nPorts; i++) { + + if(!(pp->id = FakeClientID(0))) + continue; + + if(!(portPriv = calloc(1, sizeof(XvPortRecPrivate)))) + continue; + + if(!AddResource(pp->id, PortResource, pp)) { + free(portPriv); + continue; + } + + pp->pAdaptor = pa; + pp->pNotify = (XvPortNotifyPtr)NULL; + pp->pDraw = (DrawablePtr)NULL; + pp->client = (ClientPtr)NULL; + pp->grab.client = (ClientPtr)NULL; + pp->time = currentTime; + pp->devPriv.ptr = portPriv; + + portPriv->screen = screen; + portPriv->AdaptorRec = adaptorPriv; + portPriv->DevPriv.ptr = adaptorPtr->pPortPrivates[i].ptr; + + pp++; + numPort++; + } + pa->nPorts = numPort; + pa->pPorts = pPort; + if(!numPort) { + KdXVFreeAdaptor(pa); + continue; + } + + pa->base_id = pPort->id; + + pa++; + numAdaptor++; + } + + if(numAdaptor) { + pxvs->nAdaptors = numAdaptor; + pxvs->pAdaptors = pAdaptor; + } else { + free(pAdaptor); + return FALSE; + } + + return TRUE; +} + +/* Video should be clipped to the intersection of the window cliplist + and the client cliplist specified in the GC for which the video was + initialized. When we need to reclip a window, the GC that started + the video may not even be around anymore. That's why we save the + client clip from the GC when the video is initialized. We then + use KdXVUpdateCompositeClip to calculate the new composite clip + when we need it. This is different from what DEC did. They saved + the GC and used it's clip list when they needed to reclip the window, + even if the client clip was different from the one the video was + initialized with. If the original GC was destroyed, they had to stop + the video. I like the new method better (MArk). + + This function only works for windows. Will need to rewrite when + (if) we support pixmap rendering. +*/ + +static void +KdXVUpdateCompositeClip(XvPortRecPrivatePtr portPriv) +{ + RegionPtr pregWin, pCompositeClip; + WindowPtr pWin; + Bool freeCompClip = FALSE; + + if(portPriv->pCompositeClip) + return; + + pWin = (WindowPtr)portPriv->pDraw; + + /* get window clip list */ + if(portPriv->subWindowMode == IncludeInferiors) { + pregWin = NotClippedByChildren(pWin); + freeCompClip = TRUE; + } else + pregWin = &pWin->clipList; + + if(!portPriv->clientClip) { + portPriv->pCompositeClip = pregWin; + portPriv->FreeCompositeClip = freeCompClip; + return; + } + + pCompositeClip = REGION_CREATE(pWin->pScreen, NullBox, 1); + REGION_COPY(pWin->pScreen, pCompositeClip, portPriv->clientClip); + REGION_TRANSLATE(pWin->pScreen, pCompositeClip, + portPriv->pDraw->x + portPriv->clipOrg.x, + portPriv->pDraw->y + portPriv->clipOrg.y); + REGION_INTERSECT(pWin->pScreen, pCompositeClip, pregWin, pCompositeClip); + + portPriv->pCompositeClip = pCompositeClip; + portPriv->FreeCompositeClip = TRUE; + + if(freeCompClip) { + REGION_DESTROY(pWin->pScreen, pregWin); + } +} + +/* Save the current clientClip and update the CompositeClip whenever + we have a fresh GC */ + +static void +KdXVCopyClip( + XvPortRecPrivatePtr portPriv, + GCPtr pGC +){ + /* copy the new clip if it exists */ + if((pGC->clientClipType == CT_REGION) && pGC->clientClip) { + if(!portPriv->clientClip) + portPriv->clientClip = REGION_CREATE(pGC->pScreen, NullBox, 1); + /* Note: this is in window coordinates */ + REGION_COPY(pGC->pScreen, portPriv->clientClip, pGC->clientClip); + } else if(portPriv->clientClip) { /* free the old clientClip */ + REGION_DESTROY(pGC->pScreen, portPriv->clientClip); + portPriv->clientClip = NULL; + } + + /* get rid of the old clip list */ + if(portPriv->pCompositeClip && portPriv->FreeCompositeClip) { + REGION_DESTROY(pWin->pScreen, portPriv->pCompositeClip); + } + + portPriv->clipOrg = pGC->clipOrg; + portPriv->pCompositeClip = pGC->pCompositeClip; + portPriv->FreeCompositeClip = FALSE; + portPriv->subWindowMode = pGC->subWindowMode; +} + +static int +KdXVRegetVideo(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + KdXVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(portPriv->pDraw->pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(portPriv->pDraw->pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(portPriv->pDraw->pScreen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(portPriv->pDraw->pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(portPriv->pDraw->pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->GetVideo)(portPriv->screen, portPriv->pDraw, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + + if(ret == Success) + portPriv->isOn = XV_ON; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && portPriv->isOn == XV_ON) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(portPriv->pDraw->pScreen, &WinRegion); + REGION_UNINIT(portPriv->pDraw->pScreen, &ClipRegion); + + return ret; +} + + +static int +KdXVReputVideo(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + ScreenPtr pScreen = portPriv->pDraw->pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen=pScreenPriv->screen; + int ret = Success; + Bool clippedAway = FALSE; + + KdXVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* clip and translate to the viewport */ + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = screen->width; + VPBox.y2 = screen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + /* bailout if we have to clip but the hardware doesn't support it */ + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutVideo)(portPriv->screen, portPriv->pDraw, + portPriv->vid_x, portPriv->vid_y, + WinBox.x1, WinBox.y1, + portPriv->vid_w, portPriv->vid_h, + portPriv->drw_w, portPriv->drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + + if(ret == Success) portPriv->isOn = XV_ON; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + +static int +KdXVReputImage(XvPortRecPrivatePtr portPriv) +{ + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + ScreenPtr pScreen = portPriv->pDraw->pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen=pScreenPriv->screen; + int ret = Success; + Bool clippedAway = FALSE; + + KdXVUpdateCompositeClip(portPriv); + + /* translate the video region to the screen */ + WinBox.x1 = portPriv->pDraw->x + portPriv->drw_x; + WinBox.y1 = portPriv->pDraw->y + portPriv->drw_y; + WinBox.x2 = WinBox.x1 + portPriv->drw_w; + WinBox.y2 = WinBox.y1 + portPriv->drw_h; + + /* clip to the window composite clip */ + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &WinRegion, portPriv->pCompositeClip); + + /* clip and translate to the viewport */ + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = screen->width; + VPBox.y2 = screen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + /* that's all if it's totally obscured */ + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + + /* bailout if we have to clip but the hardware doesn't support it */ + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto CLIP_VIDEO_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->ReputImage)(portPriv->screen, portPriv->pDraw, + WinBox.x1, WinBox.y1, + &ClipRegion, portPriv->DevPriv.ptr); + + portPriv->isOn = (ret == Success) ? XV_ON : XV_OFF; + +CLIP_VIDEO_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + /* This clip was copied and only good for one shot */ + if(!portPriv->FreeCompositeClip) + portPriv->pCompositeClip = NULL; + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + +static int +KdXVReputAllVideo(WindowPtr pWin, pointer data) +{ + KdXVWindowPtr WinPriv; + + if (pWin->drawable.type != DRAWABLE_WINDOW) + return WT_DONTWALKCHILDREN; + + WinPriv = GET_KDXV_WINDOW(pWin); + + while(WinPriv) { + if(WinPriv->PortRec->type == XvInputMask) + KdXVReputVideo(WinPriv->PortRec); + else + KdXVRegetVideo(WinPriv->PortRec); + WinPriv = WinPriv->next; + } + + return WT_WALKCHILDREN; +} + +static int +KdXVEnlistPortInWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) +{ + KdXVWindowPtr winPriv, PrivRoot; + + winPriv = PrivRoot = GET_KDXV_WINDOW(pWin); + + /* Enlist our port in the window private */ + while(winPriv) { + if(winPriv->PortRec == portPriv) /* we're already listed */ + break; + winPriv = winPriv->next; + } + + if(!winPriv) { + winPriv = malloc(sizeof(KdXVWindowRec)); + if(!winPriv) return BadAlloc; + winPriv->PortRec = portPriv; + winPriv->next = PrivRoot; + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, winPriv); + } + return Success; +} + + +static void +KdXVRemovePortFromWindow(WindowPtr pWin, XvPortRecPrivatePtr portPriv) +{ + KdXVWindowPtr winPriv, prevPriv = NULL; + + winPriv = GET_KDXV_WINDOW(pWin); + + while(winPriv) { + if(winPriv->PortRec == portPriv) { + if(prevPriv) + prevPriv->next = winPriv->next; + else + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, winPriv->next); + free(winPriv); + break; + } + prevPriv = winPriv; + winPriv = winPriv->next; + } + portPriv->pDraw = NULL; +} + +/**** ScreenRec fields ****/ + + +static Bool +KdXVCreateWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + int ret; + + pScreen->CreateWindow = ScreenPriv->CreateWindow; + ret = (*pScreen->CreateWindow)(pWin); + pScreen->CreateWindow = KdXVCreateWindow; + + if (ret) + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, NULL); + + return ret; +} + + +static Bool +KdXVDestroyWindow(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + KdXVWindowPtr tmp, WinPriv = GET_KDXV_WINDOW(pWin); + int ret; + + while(WinPriv) { + XvPortRecPrivatePtr pPriv = WinPriv->PortRec; + + if(pPriv->isOn > XV_OFF) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, TRUE); + pPriv->isOn = XV_OFF; + } + + pPriv->pDraw = NULL; + tmp = WinPriv; + WinPriv = WinPriv->next; + free(tmp); + } + + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, NULL); + + pScreen->DestroyWindow = ScreenPriv->DestroyWindow; + ret = (*pScreen->DestroyWindow)(pWin); + pScreen->DestroyWindow = KdXVDestroyWindow; + + return ret; +} + + +static void +KdXVWindowExposures(WindowPtr pWin, RegionPtr reg1, RegionPtr reg2) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); + KdXVWindowPtr pPrev; + XvPortRecPrivatePtr pPriv; + Bool AreasExposed; + + AreasExposed = (WinPriv && reg1 && REGION_NOTEMPTY(pScreen, reg1)); + + pScreen->WindowExposures = ScreenPriv->WindowExposures; + (*pScreen->WindowExposures)(pWin, reg1, reg2); + pScreen->WindowExposures = KdXVWindowExposures; + + /* filter out XClearWindow/Area */ + if (!pWin->valdata) return; + + pPrev = NULL; + + while(WinPriv) { + pPriv = WinPriv->PortRec; + + /* Reput anyone with a reput function */ + + switch(pPriv->type) { + case XvInputMask: + KdXVReputVideo(pPriv); + break; + case XvOutputMask: + KdXVRegetVideo(pPriv); + break; + default: /* overlaid still/image*/ + if (pPriv->AdaptorRec->ReputImage) + KdXVReputImage(pPriv); + else if(AreasExposed) { + KdXVWindowPtr tmp; + + if (pPriv->isOn == XV_ON) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, FALSE); + pPriv->isOn = XV_PENDING; + } + pPriv->pDraw = NULL; + + if(!pPrev) + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, WinPriv->next); + else + pPrev->next = WinPriv->next; + tmp = WinPriv; + WinPriv = WinPriv->next; + free(tmp); + continue; + } + break; + } + pPrev = WinPriv; + WinPriv = WinPriv->next; + } +} + + +static void +KdXVClipNotify(WindowPtr pWin, int dx, int dy) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + KdXVWindowPtr WinPriv = GET_KDXV_WINDOW(pWin); + KdXVWindowPtr tmp, pPrev = NULL; + XvPortRecPrivatePtr pPriv; + Bool visible = (pWin->visibility == VisibilityUnobscured) || + (pWin->visibility == VisibilityPartiallyObscured); + + while(WinPriv) { + pPriv = WinPriv->PortRec; + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pScreen, pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + /* Stop everything except images, but stop them too if the + window isn't visible. But we only remove the images. */ + + if(pPriv->type || !visible) { + if(pPriv->isOn == XV_ON) { + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, FALSE); + pPriv->isOn = XV_PENDING; + } + + if(!pPriv->type) { /* overlaid still/image */ + pPriv->pDraw = NULL; + + if(!pPrev) + dixSetPrivate(&pWin->devPrivates, KdXVWindowKey, WinPriv->next); + else + pPrev->next = WinPriv->next; + tmp = WinPriv; + WinPriv = WinPriv->next; + free(tmp); + continue; + } + } + + pPrev = WinPriv; + WinPriv = WinPriv->next; + } + + if(ScreenPriv->ClipNotify) { + pScreen->ClipNotify = ScreenPriv->ClipNotify; + (*pScreen->ClipNotify)(pWin, dx, dy); + pScreen->ClipNotify = KdXVClipNotify; + } +} + + + +/**** Required XvScreenRec fields ****/ + +static Bool +KdXVCloseScreen(int i, ScreenPtr pScreen) +{ + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + KdXVScreenPtr ScreenPriv = GET_KDXV_SCREEN(pScreen); + XvAdaptorPtr pa; + int c; + + if(!ScreenPriv) return TRUE; + + pScreen->CreateWindow = ScreenPriv->CreateWindow; + pScreen->DestroyWindow = ScreenPriv->DestroyWindow; + pScreen->WindowExposures = ScreenPriv->WindowExposures; + pScreen->ClipNotify = ScreenPriv->ClipNotify; + +/* fprintf(stderr,"XV: Unwrapping screen funcs\n"); */ + + for(c = 0, pa = pxvs->pAdaptors; c < pxvs->nAdaptors; c++, pa++) { + KdXVFreeAdaptor(pa); + } + + free(pxvs->pAdaptors); + free(ScreenPriv); + + return TRUE; +} + + +static int +KdXVQueryAdaptors( + ScreenPtr pScreen, + XvAdaptorPtr *p_pAdaptors, + int *p_nAdaptors +){ + XvScreenPtr pxvs = GET_XV_SCREEN(pScreen); + + *p_nAdaptors = pxvs->nAdaptors; + *p_pAdaptors = pxvs->pAdaptors; + + return (Success); +} + +static Bool +KdXVRunning (ScreenPtr pScreen) +{ + return (KdXVGeneration == serverGeneration && + GET_XV_SCREEN(pScreen) != 0); +} + +Bool +KdXVEnable(ScreenPtr pScreen) +{ + if (!KdXVRunning (pScreen)) + return TRUE; + + WalkTree(pScreen, KdXVReputAllVideo, 0); + + return TRUE; +} + +void +KdXVDisable(ScreenPtr pScreen) +{ + XvScreenPtr pxvs; + KdXVScreenPtr ScreenPriv; + XvAdaptorPtr pAdaptor; + XvPortPtr pPort; + XvPortRecPrivatePtr pPriv; + int i, j; + + if (!KdXVRunning (pScreen)) + return; + + pxvs = GET_XV_SCREEN(pScreen); + ScreenPriv = GET_KDXV_SCREEN(pScreen); + + for(i = 0; i < pxvs->nAdaptors; i++) { + pAdaptor = &pxvs->pAdaptors[i]; + for(j = 0; j < pAdaptor->nPorts; j++) { + pPort = &pAdaptor->pPorts[j]; + pPriv = (XvPortRecPrivatePtr)pPort->devPriv.ptr; + if(pPriv->isOn > XV_OFF) { + + (*pPriv->AdaptorRec->StopVideo)( + pPriv->screen, pPriv->DevPriv.ptr, TRUE); + pPriv->isOn = XV_OFF; + + if(pPriv->pCompositeClip && pPriv->FreeCompositeClip) + REGION_DESTROY(pScreen, pPriv->pCompositeClip); + + pPriv->pCompositeClip = NULL; + + if(!pPriv->type && pPriv->pDraw) { /* still */ + KdXVRemovePortFromWindow((WindowPtr)pPriv->pDraw, pPriv); + } + } + } + } +} + +/**** XvAdaptorRec fields ****/ + +static int +KdXVAllocatePort( + unsigned long port, + XvPortPtr pPort, + XvPortPtr *ppPort +){ + *ppPort = pPort; + return Success; +} + +static int +KdXVFreePort(XvPortPtr pPort) +{ + return Success; +} + +static int +KdXVPutVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + KdScreenPriv(portPriv->screen->pScreen); + int result; + + /* No dumping video to pixmaps... For now anyhow */ + if(pDraw->type != DRAWABLE_WINDOW) { + pPort->pDraw = (DrawablePtr)NULL; + return BadAlloc; + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + result = KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(result != Success) return result; + + portPriv->pDraw = pDraw; + portPriv->type = XvInputMask; + + /* save a copy of these parameters */ + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + + /* make sure we have the most recent copy of the clientClip */ + KdXVCopyClip(portPriv, pGC); + + /* To indicate to the DI layer that we were successful */ + pPort->pDraw = pDraw; + + if (!pScreenPriv->enabled) return Success; + + return(KdXVReputVideo(portPriv)); +} + +static int +KdXVPutStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen = pDraw->pScreen; + KdScreenPriv(pScreen); + KdScreenInfo *screen=pScreenPriv->screen; + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if (!pScreenPriv->enabled) return Success; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = screen->width; + VPBox.y2 = screen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + if(portPriv->pDraw) { + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto PUT_STILL_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto PUT_STILL_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutStill)(portPriv->screen, pDraw, + vid_x, vid_y, WinBox.x1, WinBox.y1, + vid_w, vid_h, drw_w, drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + + if((ret == Success) && + (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_STILLS)) { + + KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + portPriv->isOn = XV_ON; + portPriv->pDraw = pDraw; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + portPriv->type = 0; /* no mask means it's transient and should + not be reput once it's removed */ + pPort->pDraw = pDraw; /* make sure we can get stop requests */ + } + +PUT_STILL_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + +static int +KdXVGetVideo( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + int result; + KdScreenPriv(portPriv->screen->pScreen); + + /* No pixmaps... For now anyhow */ + if(pDraw->type != DRAWABLE_WINDOW) { + pPort->pDraw = (DrawablePtr)NULL; + return BadAlloc; + } + + /* If we are changing windows, unregister our port in the old window */ + if(portPriv->pDraw && (portPriv->pDraw != pDraw)) + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + + /* Register our port with the new window */ + result = KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + if(result != Success) return result; + + portPriv->pDraw = pDraw; + portPriv->type = XvOutputMask; + + /* save a copy of these parameters */ + portPriv->vid_x = vid_x; portPriv->vid_y = vid_y; + portPriv->vid_w = vid_w; portPriv->vid_h = vid_h; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + + /* make sure we have the most recent copy of the clientClip */ + KdXVCopyClip(portPriv, pGC); + + /* To indicate to the DI layer that we were successful */ + pPort->pDraw = pDraw; + + if(!pScreenPriv->enabled) return Success; + + return(KdXVRegetVideo(portPriv)); +} + +static int +KdXVGetStill( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 vid_x, INT16 vid_y, + CARD16 vid_w, CARD16 vid_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen = pDraw->pScreen; + KdScreenPriv(pScreen); + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!pScreenPriv->enabled) return Success; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->pDraw) { + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto GET_STILL_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->GetStill)(portPriv->screen, pDraw, + vid_x, vid_y, WinBox.x1, WinBox.y1, + vid_w, vid_h, drw_w, drw_h, + &ClipRegion, portPriv->DevPriv.ptr); + +GET_STILL_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + + +static int +KdXVStopVideo( + ClientPtr client, + XvPortPtr pPort, + DrawablePtr pDraw +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + KdScreenPriv(portPriv->screen->pScreen); + + if(pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + KdXVRemovePortFromWindow((WindowPtr)pDraw, portPriv); + + if(!pScreenPriv->enabled) return Success; + + /* Must free resources. */ + + if(portPriv->isOn > XV_OFF) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, TRUE); + portPriv->isOn = XV_OFF; + } + + return Success; +} + +static int +KdXVSetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 value +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return((*portPriv->AdaptorRec->SetPortAttribute)(portPriv->screen, + attribute, value, portPriv->DevPriv.ptr)); +} + + +static int +KdXVGetPortAttribute( + ClientPtr client, + XvPortPtr pPort, + Atom attribute, + INT32 *p_value +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return((*portPriv->AdaptorRec->GetPortAttribute)(portPriv->screen, + attribute, (int *) p_value, portPriv->DevPriv.ptr)); +} + + + +static int +KdXVQueryBestSize( + ClientPtr client, + XvPortPtr pPort, + CARD8 motion, + CARD16 vid_w, CARD16 vid_h, + CARD16 drw_w, CARD16 drw_h, + unsigned int *p_w, unsigned int *p_h +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + (*portPriv->AdaptorRec->QueryBestSize)(portPriv->screen, + (Bool)motion, vid_w, vid_h, drw_w, drw_h, + p_w, p_h, portPriv->DevPriv.ptr); + + return Success; +} + + +static int +KdXVPutImage( + ClientPtr client, + DrawablePtr pDraw, + XvPortPtr pPort, + GCPtr pGC, + INT16 src_x, INT16 src_y, + CARD16 src_w, CARD16 src_h, + INT16 drw_x, INT16 drw_y, + CARD16 drw_w, CARD16 drw_h, + XvImagePtr format, + unsigned char* data, + Bool sync, + CARD16 width, CARD16 height +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + ScreenPtr pScreen = pDraw->pScreen; + KdScreenPriv(pScreen); + RegionRec WinRegion; + RegionRec ClipRegion; + BoxRec WinBox; + int ret = Success; + Bool clippedAway = FALSE; + + if (pDraw->type != DRAWABLE_WINDOW) + return BadAlloc; + + if(!pScreenPriv->enabled) return Success; + + WinBox.x1 = pDraw->x + drw_x; + WinBox.y1 = pDraw->y + drw_y; + WinBox.x2 = WinBox.x1 + drw_w; + WinBox.y2 = WinBox.y1 + drw_h; + + REGION_INIT(pScreen, &WinRegion, &WinBox, 1); + REGION_INIT(pScreen, &ClipRegion, NullBox, 1); + REGION_INTERSECT(pScreen, &ClipRegion, &WinRegion, pGC->pCompositeClip); + + if(portPriv->AdaptorRec->flags & VIDEO_CLIP_TO_VIEWPORT) { + RegionRec VPReg; + BoxRec VPBox; + + VPBox.x1 = 0; + VPBox.y1 = 0; + VPBox.x2 = pScreen->width; + VPBox.y2 = pScreen->height; + + REGION_INIT(pScreen, &VPReg, &VPBox, 1); + REGION_INTERSECT(Screen, &ClipRegion, &ClipRegion, &VPReg); + REGION_UNINIT(pScreen, &VPReg); + } + + if(portPriv->pDraw) { + KdXVRemovePortFromWindow((WindowPtr)(portPriv->pDraw), portPriv); + } + + if(!REGION_NOTEMPTY(pScreen, &ClipRegion)) { + clippedAway = TRUE; + goto PUT_IMAGE_BAILOUT; + } + + if(portPriv->AdaptorRec->flags & VIDEO_NO_CLIPPING) { + BoxPtr clipBox = REGION_RECTS(&ClipRegion); + if( (REGION_NUM_RECTS(&ClipRegion) != 1) || + (clipBox->x1 != WinBox.x1) || (clipBox->x2 != WinBox.x2) || + (clipBox->y1 != WinBox.y1) || (clipBox->y2 != WinBox.y2)) + { + clippedAway = TRUE; + goto PUT_IMAGE_BAILOUT; + } + } + + if(portPriv->AdaptorRec->flags & VIDEO_INVERT_CLIPLIST) { + REGION_SUBTRACT(pScreen, &ClipRegion, &WinRegion, &ClipRegion); + } + + ret = (*portPriv->AdaptorRec->PutImage)(portPriv->screen, pDraw, + src_x, src_y, WinBox.x1, WinBox.y1, + src_w, src_h, drw_w, drw_h, format->id, data, width, height, + sync, &ClipRegion, portPriv->DevPriv.ptr); + + if((ret == Success) && + (portPriv->AdaptorRec->flags & VIDEO_OVERLAID_IMAGES)) { + + KdXVEnlistPortInWindow((WindowPtr)pDraw, portPriv); + portPriv->isOn = XV_ON; + portPriv->pDraw = pDraw; + portPriv->drw_x = drw_x; portPriv->drw_y = drw_y; + portPriv->drw_w = drw_w; portPriv->drw_h = drw_h; + portPriv->type = 0; /* no mask means it's transient and should + not be reput once it's removed */ + pPort->pDraw = pDraw; /* make sure we can get stop requests */ + } + +PUT_IMAGE_BAILOUT: + + if((clippedAway || (ret != Success)) && (portPriv->isOn == XV_ON)) { + (*portPriv->AdaptorRec->StopVideo)( + portPriv->screen, portPriv->DevPriv.ptr, FALSE); + portPriv->isOn = XV_PENDING; + } + + REGION_UNINIT(pScreen, &WinRegion); + REGION_UNINIT(pScreen, &ClipRegion); + + return ret; +} + + +static int +KdXVQueryImageAttributes( + ClientPtr client, + XvPortPtr pPort, + XvImagePtr format, + CARD16 *width, + CARD16 *height, + int *pitches, + int *offsets +){ + XvPortRecPrivatePtr portPriv = (XvPortRecPrivatePtr)(pPort->devPriv.ptr); + + return (*portPriv->AdaptorRec->QueryImageAttributes)(portPriv->screen, + format->id, width, height, pitches, offsets); +} + + +/**************** Common video manipulation functions *******************/ + +void +KdXVCopyPackedData(KdScreenInfo *screen, CARD8 *src, CARD8 *dst, int randr, + int srcPitch, int dstPitch, int srcW, int srcH, int top, int left, + int h, int w) +{ + int srcDown = srcPitch, srcRight = 2, srcNext; + int p; + + switch (randr & RR_Rotate_All) { + case RR_Rotate_0: + srcDown = srcPitch; + srcRight = 2; + break; + case RR_Rotate_90: + src += (srcH - 1) * 2; + srcDown = -2; + srcRight = srcPitch; + break; + case RR_Rotate_180: + src += srcPitch * (srcH - 1) + (srcW - 1) * 2; + srcDown = -srcPitch; + srcRight = -2; + break; + case RR_Rotate_270: + src += srcPitch * (srcW - 1); + srcDown = 2; + srcRight = -srcPitch; + break; + } + + src = src + top * srcDown + left * srcRight; + + w >>= 1; + /* srcRight >>= 1; */ + srcNext = srcRight >> 1; + while (h--) { + CARD16 *s = (CARD16 *)src; + CARD32 *d = (CARD32 *)dst; + p = w; + while (p--) { + *d++ = s[0] | (s[srcNext] << 16); + s += srcRight; + } + src += srcPitch; + dst += dstPitch; + } +} + +void +KdXVCopyPlanarData(KdScreenInfo *screen, CARD8 *src, CARD8 *dst, int randr, + int srcPitch, int srcPitch2, int dstPitch, int srcW, int srcH, int height, + int top, int left, int h, int w, int id) +{ + int i, j; + CARD8 *src1, *src2, *src3, *dst1; + int srcDown = srcPitch, srcDown2 = srcPitch2; + int srcRight = 2, srcRight2 = 1, srcNext = 1; + + /* compute source data pointers */ + src1 = src; + src2 = src1 + height * srcPitch; + src3 = src2 + (height >> 1) * srcPitch2; + switch (randr & RR_Rotate_All) { + case RR_Rotate_0: + srcDown = srcPitch; + srcDown2 = srcPitch2; + srcRight = 2; + srcRight2 = 1; + srcNext = 1; + break; + case RR_Rotate_90: + src1 = src1 + srcH - 1; + src2 = src2 + (srcH >> 1) - 1; + src3 = src3 + (srcH >> 1) - 1; + srcDown = -1; + srcDown2 = -1; + srcRight = srcPitch * 2; + srcRight2 = srcPitch2; + srcNext = srcPitch; + break; + case RR_Rotate_180: + src1 = src1 + srcPitch * (srcH - 1) + (srcW - 1); + src2 = src2 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1); + src3 = src3 + srcPitch2 * ((srcH >> 1) - 1) + ((srcW >> 1) - 1); + srcDown = -srcPitch; + srcDown2 = -srcPitch2; + srcRight = -2; + srcRight2 = -1; + srcNext = -1; + break; + case RR_Rotate_270: + src1 = src1 + srcPitch * (srcW - 1); + src2 = src2 + srcPitch2 * ((srcW >> 1) - 1); + src3 = src3 + srcPitch2 * ((srcW >> 1) - 1); + srcDown = 1; + srcDown2 = 1; + srcRight = -srcPitch * 2; + srcRight2 = -srcPitch2; + srcNext = -srcPitch; + break; + } + + /* adjust for origin */ + src1 += top * srcDown + left * srcNext; + src2 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2; + src3 += (top >> 1) * srcDown2 + (left >> 1) * srcRight2; + + if (id == FOURCC_I420) { + CARD8 *srct = src2; + src2 = src3; + src3 = srct; + } + + dst1 = dst; + + w >>= 1; + for (j = 0; j < h; j++) { + CARD32 *dst = (CARD32 *)dst1; + CARD8 *s1l = src1; + CARD8 *s1r = src1 + srcNext; + CARD8 *s2 = src2; + CARD8 *s3 = src3; + + for (i = 0; i < w; i++) { + *dst++ = *s1l | (*s1r << 16) | (*s3 << 8) | (*s2 << 24); + s1l += srcRight; + s1r += srcRight; + s2 += srcRight2; + s3 += srcRight2; + } + src1 += srcDown; + dst1 += dstPitch; + if (j & 1) { + src2 += srcDown2; + src3 += srcDown2; + } + } +} + +void +KXVPaintRegion (DrawablePtr pDraw, RegionPtr pRgn, Pixel fg) +{ + GCPtr pGC; + ChangeGCVal val[2]; + xRectangle *rects, *r; + BoxPtr pBox = REGION_RECTS (pRgn); + int nBox = REGION_NUM_RECTS (pRgn); + + rects = malloc(nBox * sizeof (xRectangle)); + if (!rects) + goto bail0; + r = rects; + while (nBox--) + { + r->x = pBox->x1 - pDraw->x; + r->y = pBox->y1 - pDraw->y; + r->width = pBox->x2 - pBox->x1; + r->height = pBox->y2 - pBox->y1; + r++; + pBox++; + } + + pGC = GetScratchGC (pDraw->depth, pDraw->pScreen); + if (!pGC) + goto bail1; + + val[0].val = fg; + val[1].val = IncludeInferiors; + ChangeGC (NullClient, pGC, GCForeground|GCSubwindowMode, val); + + ValidateGC (pDraw, pGC); + + (*pGC->ops->PolyFillRect) (pDraw, pGC, + REGION_NUM_RECTS (pRgn), rects); + + FreeScratchGC (pGC); +bail1: + free(rects); +bail0: + ; +} -- cgit v1.2.3