83c059f034
In the Xephyr case the position of the pointer relative toward the Xephyr window is controlled by the host server without taking into account rotation of the Xephyr screen. Consequently the pointer coords must always be translated when the fb is rotated. Signed-off-by: Tomas Frydrych <tomas@sleepfive.com> Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
1178 lines
27 KiB
C
1178 lines
27 KiB
C
/*
|
|
* 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(®);
|
|
RegionCopy(®, &pair->local->clipList);
|
|
screen->WindowExposures (pair->local, ®, NullRegion);
|
|
RegionUninit(®);
|
|
}
|
|
#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,
|
|
};
|