aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/kdrive/ephyr/ephyr.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/kdrive/ephyr/ephyr.c')
-rw-r--r--xorg-server/hw/kdrive/ephyr/ephyr.c2365
1 files changed, 1188 insertions, 1177 deletions
diff --git a/xorg-server/hw/kdrive/ephyr/ephyr.c b/xorg-server/hw/kdrive/ephyr/ephyr.c
index ac8e5bef9..b08dc1e40 100644
--- a/xorg-server/hw/kdrive/ephyr/ephyr.c
+++ b/xorg-server/hw/kdrive/ephyr/ephyr.c
@@ -1,1177 +1,1188 @@
-/*
- * Xephyr - A kdrive X server thats runs in a host X window.
- * Authored by Matthew Allum <mallum@openedhand.com>
- *
- * Copyright © 2004 Nokia
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of Nokia not be used in
- * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission. Nokia makes no
- * representations about the suitability of this software for any purpose. It
- * is provided "as is" without express or implied warranty.
- *
- * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <kdrive-config.h>
-#endif
-#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 */
-
-#include "xkbsrv.h"
-
-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;
-static Rotation ephyrRandr = RR_Rotate_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);
-
- /*
- * Use the rotation last applied to ourselves (in the Xephyr case the fb
- * coordinate system moves independently of the pointer coordiante system).
- */
- KdComputePointerMatrix (&m, ephyrRandr, 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 (RegionNotEmpty(pRegion))
- {
- int nbox;
- BoxPtr pbox;
-
- nbox = RegionNumRects (pRegion);
- pbox = RegionRects (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
- */
-
- /*
- * We need to store the rotation value for pointer coords transformation;
- * though initially the pointer and fb rotation are identical, when we map
- * the fb, the screen will be reinitialized and return into an unrotated
- * state (presumably the HW is taking care of the rotation of the fb), but the
- * pointer still needs to be transformed.
- */
- ephyrRandr = KdAddRotation (screen->randr, randr);
- scrpriv->randr = ephyrRandr;
-
- 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)
-{
-
- DeviceIntPtr pDev = inputInfo.keyboard;
- KeyClassPtr keyc = pDev->key;
- int i;
- CARD8 mask;
- int xkb_state;
-
- if (!pDev)
- return;
-
- xkb_state = XkbStateFieldFromRec(&pDev->key->xkbInfo->state);
- state = state & 0xff;
-
- if (xkb_state == state)
- return;
-
- for (i = 0, mask = 1; i < 8; i++, mask <<= 1) {
- int key;
-
- /* Modifier is down, but shouldn't be
- */
- if ((xkb_state & mask) && !(state & mask)) {
- int count = keyc->modifierKeyCount[i];
-
- for (key = 0; key < MAP_LENGTH; key++)
- if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
- if (key_is_down(pDev, key, KEY_PROCESSED))
- KdEnqueueKeyboardEvent (ephyrKbd, key, TRUE);
-
- if (--count == 0)
- break;
- }
- }
-
- /* Modifier shoud be down, but isn't
- */
- if (!(xkb_state & mask) && (state & mask))
- for (key = 0; key < MAP_LENGTH; key++)
- if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
- KdEnqueueKeyboardEvent (ephyrKbd, key, FALSE);
- break;
- }
- }
-}
-
-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;
- RegionNull(&reg);
- RegionCopy(&reg, &pair->local->clipList);
- screen->WindowExposures (pair->local, &reg, NullRegion);
- RegionUninit(&reg);
-}
-#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;
- ephyrUpdateModifierState(ev.key_state);
- 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");
-
- /*
- * Must transform pointer coords since the pointer position
- * relative to the Xephyr window is controlled by the host server and
- * remains constant regardless of any rotation applied to the Xephyr screen.
- */
- pi->transformCoordinates = TRUE;
-
- 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,
-};
+/*
+ * Xephyr - A kdrive X server thats runs in a host X window.
+ * Authored by Matthew Allum <mallum@openedhand.com>
+ *
+ * Copyright © 2004 Nokia
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Nokia not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Nokia makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <kdrive-config.h>
+#endif
+#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 */
+
+#include "xkbsrv.h"
+
+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;
+static Rotation ephyrRandr = RR_Rotate_0;
+
+typedef struct _EphyrInputPrivate {
+ Bool enabled;
+} EphyrKbdPrivate, EphyrPointerPrivate;
+
+Bool EphyrWantGrayScale = 0;
+
+
+Bool
+ephyrInitialize (KdCardInfo *card, EphyrPriv *priv)
+{
+#ifdef _MSC_VER
+ __asm int 3;
+#else
+ OsSignal(SIGUSR1, hostx_handle_signal);
+#endif
+ 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);
+
+ /*
+ * Use the rotation last applied to ourselves (in the Xephyr case the fb
+ * coordinate system moves independently of the pointer coordiante system).
+ */
+ KdComputePointerMatrix (&m, ephyrRandr, 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 (RegionNotEmpty(pRegion))
+ {
+ int nbox;
+ BoxPtr pbox;
+
+ nbox = RegionNumRects (pRegion);
+ pbox = RegionRects (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
+ */
+
+ /*
+ * We need to store the rotation value for pointer coords transformation;
+ * though initially the pointer and fb rotation are identical, when we map
+ * the fb, the screen will be reinitialized and return into an unrotated
+ * state (presumably the HW is taking care of the rotation of the fb), but the
+ * pointer still needs to be transformed.
+ */
+ ephyrRandr = KdAddRotation (screen->randr, randr);
+ scrpriv->randr = ephyrRandr;
+
+ 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)
+{
+
+ DeviceIntPtr pDev = inputInfo.keyboard;
+ KeyClassPtr keyc = pDev->key;
+ int i;
+ CARD8 mask;
+ int xkb_state;
+
+ if (!pDev)
+ return;
+
+ xkb_state = XkbStateFieldFromRec(&pDev->key->xkbInfo->state);
+ state = state & 0xff;
+
+ if (xkb_state == state)
+ return;
+
+ for (i = 0, mask = 1; i < 8; i++, mask <<= 1) {
+ int key;
+
+ /* Modifier is down, but shouldn't be
+ */
+ if ((xkb_state & mask) && !(state & mask)) {
+ int count = keyc->modifierKeyCount[i];
+
+ for (key = 0; key < MAP_LENGTH; key++)
+ if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
+ if (key_is_down(pDev, key, KEY_PROCESSED))
+ KdEnqueueKeyboardEvent (ephyrKbd, key, TRUE);
+
+ if (--count == 0)
+ break;
+ }
+ }
+
+ /* Modifier shoud be down, but isn't
+ */
+ if (!(xkb_state & mask) && (state & mask))
+ for (key = 0; key < MAP_LENGTH; key++)
+ if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
+ KdEnqueueKeyboardEvent (ephyrKbd, key, FALSE);
+ break;
+ }
+ }
+}
+
+static void
+ephyrBlockSigio (void)
+{
+#ifdef _MSC_VER
+ __asm int 3;
+#else
+ sigset_t set;
+
+ sigemptyset (&set);
+ sigaddset (&set, SIGIO);
+ sigprocmask (SIG_BLOCK, &set, 0);
+#endif
+}
+
+static void
+ephyrUnblockSigio (void)
+{
+#ifdef _MSC_VER
+ __asm int 3;
+#else
+ sigset_t set;
+
+ sigemptyset (&set);
+ sigaddset (&set, SIGIO);
+ sigprocmask (SIG_UNBLOCK, &set, 0);
+#endif
+}
+
+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;
+ RegionNull(&reg);
+ RegionCopy(&reg, &pair->local->clipList);
+ screen->WindowExposures (pair->local, &reg, NullRegion);
+ RegionUninit(&reg);
+}
+#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;
+ ephyrUpdateModifierState(ev.key_state);
+ 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");
+
+ /*
+ * Must transform pointer coords since the pointer position
+ * relative to the Xephyr window is controlled by the host server and
+ * remains constant regardless of any rotation applied to the Xephyr screen.
+ */
+ pi->transformCoordinates = TRUE;
+
+ 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,
+};