1156 lines
27 KiB
C
1156 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 XEPHYR_DRI
|
|
#include "ephyrdri.h"
|
|
#include "ephyrdriext.h"
|
|
#include "ephyrglxext.h"
|
|
#endif /*XEPHYR_DRI*/
|
|
|
|
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;
|
|
unsigned long 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[0].depth = 8;
|
|
|
|
if (screen->fb[0].depth && screen->fb[0].depth != hostx_get_depth())
|
|
{
|
|
if (screen->fb[0].depth < hostx_get_depth()
|
|
&& (screen->fb[0].depth == 24 || screen->fb[0].depth == 16
|
|
|| screen->fb[0].depth == 8))
|
|
{
|
|
hostx_set_server_depth(screen, screen->fb[0].depth);
|
|
}
|
|
else
|
|
ErrorF("\nXephyr: requested screen depth not supported, setting to match hosts.\n");
|
|
}
|
|
|
|
screen->fb[0].depth = hostx_get_server_depth(screen);
|
|
screen->rate = 72;
|
|
|
|
if (screen->fb[0].depth <= 8)
|
|
{
|
|
if (EphyrWantGrayScale)
|
|
screen->fb[0].visuals = ((1 << StaticGray) | (1 << GrayScale));
|
|
else
|
|
screen->fb[0].visuals = ((1 << StaticGray) |
|
|
(1 << GrayScale) |
|
|
(1 << StaticColor) |
|
|
(1 << PseudoColor) |
|
|
(1 << TrueColor) |
|
|
(1 << DirectColor));
|
|
|
|
screen->fb[0].redMask = 0x00;
|
|
screen->fb[0].greenMask = 0x00;
|
|
screen->fb[0].blueMask = 0x00;
|
|
screen->fb[0].depth = 8;
|
|
screen->fb[0].bitsPerPixel = 8;
|
|
}
|
|
else
|
|
{
|
|
screen->fb[0].visuals = (1 << TrueColor);
|
|
|
|
if (screen->fb[0].depth <= 15)
|
|
{
|
|
screen->fb[0].depth = 15;
|
|
screen->fb[0].bitsPerPixel = 16;
|
|
}
|
|
else if (screen->fb[0].depth <= 16)
|
|
{
|
|
screen->fb[0].depth = 16;
|
|
screen->fb[0].bitsPerPixel = 16;
|
|
}
|
|
else
|
|
{
|
|
screen->fb[0].depth = 24;
|
|
screen->fb[0].bitsPerPixel = 32;
|
|
}
|
|
|
|
hostx_get_visual_masks (screen, &redMask, &greenMask, &blueMask);
|
|
|
|
screen->fb[0].redMask = (Pixel) redMask;
|
|
screen->fb[0].greenMask = (Pixel) greenMask;
|
|
screen->fb[0].blueMask = (Pixel) blueMask;
|
|
|
|
}
|
|
|
|
scrpriv->randr = screen->randr;
|
|
|
|
return ephyrMapFramebuffer (screen);
|
|
}
|
|
|
|
Bool
|
|
ephyrScreenInit (KdScreenInfo *screen)
|
|
{
|
|
EphyrScrPriv *scrpriv;
|
|
|
|
scrpriv = xalloc (sizeof (EphyrScrPriv));
|
|
|
|
if (!scrpriv)
|
|
return FALSE;
|
|
|
|
memset (scrpriv, 0, sizeof (EphyrScrPriv));
|
|
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;
|
|
}
|
|
|
|
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[0].bitsPerPixel + 31) >> 5) << 2;
|
|
|
|
/* point the framebuffer to the data in an XImage */
|
|
/* If fakexa is enabled, allocate a larger buffer so that fakexa has space to
|
|
* put offscreen pixmaps.
|
|
*/
|
|
if (ephyrFuncs.initAccel == NULL)
|
|
buffer_height = screen->height;
|
|
else
|
|
buffer_height = 3 * screen->height;
|
|
|
|
priv->base = hostx_screen_init (screen, screen->width, screen->height, buffer_height);
|
|
|
|
screen->memory_base = (CARD8 *) (priv->base);
|
|
screen->memory_size = priv->bytes_per_line * buffer_height;
|
|
screen->off_screen_base = priv->bytes_per_line * screen->height;
|
|
|
|
if ((scrpriv->randr & RR_Rotate_0) && !(scrpriv->randr & RR_Reflect_All))
|
|
{
|
|
scrpriv->shadow = FALSE;
|
|
|
|
screen->fb[0].byteStride = priv->bytes_per_line;
|
|
screen->fb[0].pixelStride = screen->width;
|
|
screen->fb[0].frameBuffer = (CARD8 *) (priv->base);
|
|
}
|
|
else
|
|
{
|
|
/* Rotated/Reflected so we need to use shadow fb */
|
|
scrpriv->shadow = TRUE;
|
|
|
|
EPHYR_LOG("allocing shadow");
|
|
|
|
KdShadowFbAlloc (screen, 0,
|
|
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, 0);
|
|
|
|
/* 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;
|
|
|
|
EPHYR_LOG("mark");
|
|
|
|
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 }
|
|
};
|
|
|
|
*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);
|
|
|
|
KdOffscreenSwapOut (screen->pScreen);
|
|
|
|
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[0].depth,
|
|
screen->fb[0].bitsPerPixel,
|
|
screen->fb[0].byteStride,
|
|
screen->fb[0].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 XEPHYR_DRI
|
|
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, 0);
|
|
}
|
|
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)
|
|
{
|
|
DeviceIntPtr pkeydev;
|
|
KeyClassPtr keyc;
|
|
int i;
|
|
CARD8 mask;
|
|
|
|
pkeydev = inputInfo.keyboard;
|
|
|
|
if (!pkeydev)
|
|
return;
|
|
|
|
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->modifierMap[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->modifierMap[key] & mask)
|
|
{
|
|
if (keyc->modifierMap[key] & mask && ephyrKbd &&
|
|
((EphyrKbdPrivate *)ephyrKbd->driverPrivate)->enabled)
|
|
KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE); /* press */
|
|
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 (ScreenPtr pScreen, int x, int y)
|
|
{
|
|
ephyrBlockSigio ();
|
|
ephyrCurScreen = pScreen->myNum;
|
|
miPointerWarpCursor (pScreen, x, y);
|
|
ephyrUnblockSigio ();
|
|
}
|
|
|
|
miPointerScreenFuncRec ephyrPointerScreenFuncs =
|
|
{
|
|
ephyrCursorOffScreen,
|
|
ephyrCrossScreen,
|
|
ephyrWarpCursor
|
|
};
|
|
|
|
#ifdef XEPHYR_DRI
|
|
/**
|
|
* 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 /*XEPHYR_DRI*/
|
|
|
|
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
|
|
(screenInfo.screens[ev.data.mouse_motion.screen],
|
|
ev.data.mouse_motion.x,
|
|
ev.data.mouse_motion.y );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int x=0, y=0;
|
|
#ifdef XEPHYR_DRI
|
|
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 XEPHYR_DRI
|
|
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 XEPHYR_DRI
|
|
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 /*XEPHYR_DRI*/
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ephyrCardFini (KdCardInfo *card)
|
|
{
|
|
EphyrPriv *priv = card->driver;
|
|
xfree (priv);
|
|
}
|
|
|
|
void
|
|
ephyrGetColors (ScreenPtr pScreen, int fb, 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 fb, 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;
|
|
pi->name = KdSaveString("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->keySyms.minKeyCode = ephyrKeySyms.minKeyCode;
|
|
ki->keySyms.maxKeyCode = ephyrKeySyms.maxKeyCode;
|
|
ki->minScanCode = ki->keySyms.minKeyCode;
|
|
ki->maxScanCode = ki->keySyms.maxKeyCode;
|
|
ki->keySyms.mapWidth = ephyrKeySyms.mapWidth;
|
|
xfree(ki->keySyms.map);
|
|
ki->keySyms.map = ephyrKeySyms.map;
|
|
ki->name = KdSaveString("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)
|
|
{
|
|
/* not xfree: we call malloc from hostx.c. */
|
|
free(ki->keySyms.map);
|
|
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,
|
|
};
|