xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

ephyr.c (37592B)


      1 /*
      2  * Xephyr - A kdrive X server that runs in a host X window.
      3  *          Authored by Matthew Allum <mallum@openedhand.com>
      4  *
      5  * Copyright © 2004 Nokia
      6  *
      7  * Permission to use, copy, modify, distribute, and sell this software and its
      8  * documentation for any purpose is hereby granted without fee, provided that
      9  * the above copyright notice appear in all copies and that both that
     10  * copyright notice and this permission notice appear in supporting
     11  * documentation, and that the name of Nokia not be used in
     12  * advertising or publicity pertaining to distribution of the software without
     13  * specific, written prior permission. Nokia makes no
     14  * representations about the suitability of this software for any purpose.  It
     15  * is provided "as is" without express or implied warranty.
     16  *
     17  * NOKIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     19  * EVENT SHALL NOKIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     22  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     23  * PERFORMANCE OF THIS SOFTWARE.
     24  */
     25 
     26 #ifdef HAVE_DIX_CONFIG_H
     27 #include <dix-config.h>
     28 #endif
     29 
     30 #include <xcb/xcb_keysyms.h>
     31 #include <X11/keysym.h>
     32 
     33 #include "ephyr.h"
     34 
     35 #include "inputstr.h"
     36 #include "scrnintstr.h"
     37 #include "ephyrlog.h"
     38 
     39 #ifdef GLAMOR
     40 #include "glamor.h"
     41 #endif
     42 #include "ephyr_glamor_glx.h"
     43 #include "glx_extinit.h"
     44 #include "xkbsrv.h"
     45 
     46 extern Bool ephyr_glamor;
     47 
     48 KdKeyboardInfo *ephyrKbd;
     49 KdPointerInfo *ephyrMouse;
     50 Bool ephyrNoDRI = FALSE;
     51 Bool ephyrNoXV = FALSE;
     52 
     53 static int mouseState = 0;
     54 static Rotation ephyrRandr = RR_Rotate_0;
     55 
     56 typedef struct _EphyrInputPrivate {
     57     Bool enabled;
     58 } EphyrKbdPrivate, EphyrPointerPrivate;
     59 
     60 Bool EphyrWantGrayScale = 0;
     61 Bool EphyrWantResize = 0;
     62 Bool EphyrWantNoHostGrab = 0;
     63 
     64 Bool
     65 ephyrInitialize(KdCardInfo * card, EphyrPriv * priv)
     66 {
     67     OsSignal(SIGUSR1, hostx_handle_signal);
     68 
     69     priv->base = 0;
     70     priv->bytes_per_line = 0;
     71     return TRUE;
     72 }
     73 
     74 Bool
     75 ephyrCardInit(KdCardInfo * card)
     76 {
     77     EphyrPriv *priv;
     78 
     79     priv = (EphyrPriv *) malloc(sizeof(EphyrPriv));
     80     if (!priv)
     81         return FALSE;
     82 
     83     if (!ephyrInitialize(card, priv)) {
     84         free(priv);
     85         return FALSE;
     86     }
     87     card->driver = priv;
     88 
     89     return TRUE;
     90 }
     91 
     92 Bool
     93 ephyrScreenInitialize(KdScreenInfo *screen)
     94 {
     95     EphyrScrPriv *scrpriv = screen->driver;
     96     int x = 0, y = 0;
     97     int width = 640, height = 480;
     98     CARD32 redMask, greenMask, blueMask;
     99 
    100     if (hostx_want_screen_geometry(screen, &width, &height, &x, &y)
    101         || !screen->width || !screen->height) {
    102         screen->width = width;
    103         screen->height = height;
    104         screen->x = x;
    105         screen->y = y;
    106     }
    107 
    108     if (EphyrWantGrayScale)
    109         screen->fb.depth = 8;
    110 
    111     if (screen->fb.depth && screen->fb.depth != hostx_get_depth()) {
    112         if (screen->fb.depth < hostx_get_depth()
    113             && (screen->fb.depth == 24 || screen->fb.depth == 16
    114                 || screen->fb.depth == 8)) {
    115             scrpriv->server_depth = screen->fb.depth;
    116         }
    117         else
    118             ErrorF
    119                 ("\nXephyr: requested screen depth not supported, setting to match hosts.\n");
    120     }
    121 
    122     screen->fb.depth = hostx_get_server_depth(screen);
    123     screen->rate = 72;
    124 
    125     if (screen->fb.depth <= 8) {
    126         if (EphyrWantGrayScale)
    127             screen->fb.visuals = ((1 << StaticGray) | (1 << GrayScale));
    128         else
    129             screen->fb.visuals = ((1 << StaticGray) |
    130                                   (1 << GrayScale) |
    131                                   (1 << StaticColor) |
    132                                   (1 << PseudoColor) |
    133                                   (1 << TrueColor) | (1 << DirectColor));
    134 
    135         screen->fb.redMask = 0x00;
    136         screen->fb.greenMask = 0x00;
    137         screen->fb.blueMask = 0x00;
    138         screen->fb.depth = 8;
    139         screen->fb.bitsPerPixel = 8;
    140     }
    141     else {
    142         screen->fb.visuals = (1 << TrueColor);
    143 
    144         if (screen->fb.depth <= 15) {
    145             screen->fb.depth = 15;
    146             screen->fb.bitsPerPixel = 16;
    147         }
    148         else if (screen->fb.depth <= 16) {
    149             screen->fb.depth = 16;
    150             screen->fb.bitsPerPixel = 16;
    151         }
    152         else if (screen->fb.depth <= 24) {
    153             screen->fb.depth = 24;
    154             screen->fb.bitsPerPixel = 32;
    155         }
    156         else if (screen->fb.depth <= 30) {
    157             screen->fb.depth = 30;
    158             screen->fb.bitsPerPixel = 32;
    159         }
    160         else {
    161             ErrorF("\nXephyr: Unsupported screen depth %d\n", screen->fb.depth);
    162             return FALSE;
    163         }
    164 
    165         hostx_get_visual_masks(screen, &redMask, &greenMask, &blueMask);
    166 
    167         screen->fb.redMask = (Pixel) redMask;
    168         screen->fb.greenMask = (Pixel) greenMask;
    169         screen->fb.blueMask = (Pixel) blueMask;
    170 
    171     }
    172 
    173     scrpriv->randr = screen->randr;
    174 
    175     return ephyrMapFramebuffer(screen);
    176 }
    177 
    178 void *
    179 ephyrWindowLinear(ScreenPtr pScreen,
    180                   CARD32 row,
    181                   CARD32 offset, int mode, CARD32 *size, void *closure)
    182 {
    183     KdScreenPriv(pScreen);
    184     EphyrPriv *priv = pScreenPriv->card->driver;
    185 
    186     if (!pScreenPriv->enabled)
    187         return 0;
    188 
    189     *size = priv->bytes_per_line;
    190     return priv->base + row * priv->bytes_per_line + offset;
    191 }
    192 
    193 /**
    194  * Figure out display buffer size. If fakexa is enabled, allocate a larger
    195  * buffer so that fakexa has space to put offscreen pixmaps.
    196  */
    197 int
    198 ephyrBufferHeight(KdScreenInfo * screen)
    199 {
    200     int buffer_height;
    201 
    202     if (ephyrFuncs.initAccel == NULL)
    203         buffer_height = screen->height;
    204     else
    205         buffer_height = 3 * screen->height;
    206     return buffer_height;
    207 }
    208 
    209 Bool
    210 ephyrMapFramebuffer(KdScreenInfo * screen)
    211 {
    212     EphyrScrPriv *scrpriv = screen->driver;
    213     EphyrPriv *priv = screen->card->driver;
    214     KdPointerMatrix m;
    215     int buffer_height;
    216 
    217     EPHYR_LOG("screen->width: %d, screen->height: %d index=%d",
    218               screen->width, screen->height, screen->mynum);
    219 
    220     /*
    221      * Use the rotation last applied to ourselves (in the Xephyr case the fb
    222      * coordinate system moves independently of the pointer coordinate system).
    223      */
    224     KdComputePointerMatrix(&m, ephyrRandr, screen->width, screen->height);
    225     KdSetPointerMatrix(&m);
    226 
    227     buffer_height = ephyrBufferHeight(screen);
    228 
    229     priv->base =
    230         hostx_screen_init(screen, screen->x, screen->y,
    231                           screen->width, screen->height, buffer_height,
    232                           &priv->bytes_per_line, &screen->fb.bitsPerPixel);
    233 
    234     if ((scrpriv->randr & RR_Rotate_0) && !(scrpriv->randr & RR_Reflect_All)) {
    235         scrpriv->shadow = FALSE;
    236 
    237         screen->fb.byteStride = priv->bytes_per_line;
    238         screen->fb.pixelStride = screen->width;
    239         screen->fb.frameBuffer = (CARD8 *) (priv->base);
    240     }
    241     else {
    242         /* Rotated/Reflected so we need to use shadow fb */
    243         scrpriv->shadow = TRUE;
    244 
    245         EPHYR_LOG("allocing shadow");
    246 
    247         KdShadowFbAlloc(screen,
    248                         scrpriv->randr & (RR_Rotate_90 | RR_Rotate_270));
    249     }
    250 
    251     return TRUE;
    252 }
    253 
    254 void
    255 ephyrSetScreenSizes(ScreenPtr pScreen)
    256 {
    257     KdScreenPriv(pScreen);
    258     KdScreenInfo *screen = pScreenPriv->screen;
    259     EphyrScrPriv *scrpriv = screen->driver;
    260 
    261     if (scrpriv->randr & (RR_Rotate_0 | RR_Rotate_180)) {
    262         pScreen->width = screen->width;
    263         pScreen->height = screen->height;
    264         pScreen->mmWidth = screen->width_mm;
    265         pScreen->mmHeight = screen->height_mm;
    266     }
    267     else {
    268         pScreen->width = screen->height;
    269         pScreen->height = screen->width;
    270         pScreen->mmWidth = screen->height_mm;
    271         pScreen->mmHeight = screen->width_mm;
    272     }
    273 }
    274 
    275 Bool
    276 ephyrUnmapFramebuffer(KdScreenInfo * screen)
    277 {
    278     EphyrScrPriv *scrpriv = screen->driver;
    279 
    280     if (scrpriv->shadow)
    281         KdShadowFbFree(screen);
    282 
    283     /* Note, priv->base will get freed when XImage recreated */
    284 
    285     return TRUE;
    286 }
    287 
    288 void
    289 ephyrShadowUpdate(ScreenPtr pScreen, shadowBufPtr pBuf)
    290 {
    291     KdScreenPriv(pScreen);
    292     KdScreenInfo *screen = pScreenPriv->screen;
    293 
    294     EPHYR_LOG("slow paint");
    295 
    296     /* FIXME: Slow Rotated/Reflected updates could be much
    297      * much faster efficiently updating via transforming
    298      * pBuf->pDamage  regions
    299      */
    300     shadowUpdateRotatePacked(pScreen, pBuf);
    301     hostx_paint_rect(screen, 0, 0, 0, 0, screen->width, screen->height);
    302 }
    303 
    304 static void
    305 ephyrInternalDamageRedisplay(ScreenPtr pScreen)
    306 {
    307     KdScreenPriv(pScreen);
    308     KdScreenInfo *screen = pScreenPriv->screen;
    309     EphyrScrPriv *scrpriv = screen->driver;
    310     RegionPtr pRegion;
    311 
    312     if (!scrpriv || !scrpriv->pDamage)
    313         return;
    314 
    315     pRegion = DamageRegion(scrpriv->pDamage);
    316 
    317     if (RegionNotEmpty(pRegion)) {
    318         int nbox;
    319         BoxPtr pbox;
    320 
    321         if (ephyr_glamor) {
    322             ephyr_glamor_damage_redisplay(scrpriv->glamor, pRegion);
    323         } else {
    324             nbox = RegionNumRects(pRegion);
    325             pbox = RegionRects(pRegion);
    326 
    327             while (nbox--) {
    328                 hostx_paint_rect(screen,
    329                                  pbox->x1, pbox->y1,
    330                                  pbox->x1, pbox->y1,
    331                                  pbox->x2 - pbox->x1, pbox->y2 - pbox->y1);
    332                 pbox++;
    333             }
    334         }
    335         DamageEmpty(scrpriv->pDamage);
    336     }
    337 }
    338 
    339 static void
    340 ephyrXcbProcessEvents(Bool queued_only);
    341 
    342 static Bool
    343 ephyrEventWorkProc(ClientPtr client, void *closure)
    344 {
    345     ephyrXcbProcessEvents(TRUE);
    346     return TRUE;
    347 }
    348 
    349 static void
    350 ephyrScreenBlockHandler(ScreenPtr pScreen, void *timeout)
    351 {
    352     KdScreenPriv(pScreen);
    353     KdScreenInfo *screen = pScreenPriv->screen;
    354     EphyrScrPriv *scrpriv = screen->driver;
    355 
    356     pScreen->BlockHandler = scrpriv->BlockHandler;
    357     (*pScreen->BlockHandler)(pScreen, timeout);
    358     scrpriv->BlockHandler = pScreen->BlockHandler;
    359     pScreen->BlockHandler = ephyrScreenBlockHandler;
    360 
    361     if (scrpriv->pDamage)
    362         ephyrInternalDamageRedisplay(pScreen);
    363 
    364     if (hostx_has_queued_event()) {
    365         if (!QueueWorkProc(ephyrEventWorkProc, NULL, NULL))
    366             FatalError("cannot queue event processing in ephyr block handler");
    367         AdjustWaitForDelay(timeout, 0);
    368     }
    369 }
    370 
    371 Bool
    372 ephyrSetInternalDamage(ScreenPtr pScreen)
    373 {
    374     KdScreenPriv(pScreen);
    375     KdScreenInfo *screen = pScreenPriv->screen;
    376     EphyrScrPriv *scrpriv = screen->driver;
    377     PixmapPtr pPixmap = NULL;
    378 
    379     scrpriv->pDamage = DamageCreate((DamageReportFunc) 0,
    380                                     (DamageDestroyFunc) 0,
    381                                     DamageReportNone, TRUE, pScreen, pScreen);
    382 
    383     pPixmap = (*pScreen->GetScreenPixmap) (pScreen);
    384 
    385     DamageRegister(&pPixmap->drawable, scrpriv->pDamage);
    386 
    387     return TRUE;
    388 }
    389 
    390 void
    391 ephyrUnsetInternalDamage(ScreenPtr pScreen)
    392 {
    393     KdScreenPriv(pScreen);
    394     KdScreenInfo *screen = pScreenPriv->screen;
    395     EphyrScrPriv *scrpriv = screen->driver;
    396 
    397     DamageDestroy(scrpriv->pDamage);
    398     scrpriv->pDamage = NULL;
    399 }
    400 
    401 #ifdef RANDR
    402 Bool
    403 ephyrRandRGetInfo(ScreenPtr pScreen, Rotation * rotations)
    404 {
    405     KdScreenPriv(pScreen);
    406     KdScreenInfo *screen = pScreenPriv->screen;
    407     EphyrScrPriv *scrpriv = screen->driver;
    408     RRScreenSizePtr pSize;
    409     Rotation randr;
    410     int n = 0;
    411 
    412     struct {
    413         int width, height;
    414     } sizes[] = {
    415         {1600, 1200},
    416         {1400, 1050},
    417         {1280, 960},
    418         {1280, 1024},
    419         {1152, 864},
    420         {1024, 768},
    421         {832, 624},
    422         {800, 600},
    423         {720, 400},
    424         {480, 640},
    425         {640, 480},
    426         {640, 400},
    427         {320, 240},
    428         {240, 320},
    429         {160, 160},
    430         {0, 0}
    431     };
    432 
    433     EPHYR_LOG("mark");
    434 
    435     *rotations = RR_Rotate_All | RR_Reflect_All;
    436 
    437     if (!hostx_want_preexisting_window(screen)
    438         && !hostx_want_fullscreen()) {  /* only if no -parent switch */
    439         while (sizes[n].width != 0 && sizes[n].height != 0) {
    440             RRRegisterSize(pScreen,
    441                            sizes[n].width,
    442                            sizes[n].height,
    443                            (sizes[n].width * screen->width_mm) / screen->width,
    444                            (sizes[n].height * screen->height_mm) /
    445                            screen->height);
    446             n++;
    447         }
    448     }
    449 
    450     pSize = RRRegisterSize(pScreen,
    451                            screen->width,
    452                            screen->height, screen->width_mm, screen->height_mm);
    453 
    454     randr = KdSubRotation(scrpriv->randr, screen->randr);
    455 
    456     RRSetCurrentConfig(pScreen, randr, 0, pSize);
    457 
    458     return TRUE;
    459 }
    460 
    461 Bool
    462 ephyrRandRSetConfig(ScreenPtr pScreen,
    463                     Rotation randr, int rate, RRScreenSizePtr pSize)
    464 {
    465     KdScreenPriv(pScreen);
    466     KdScreenInfo *screen = pScreenPriv->screen;
    467     EphyrScrPriv *scrpriv = screen->driver;
    468     Bool wasEnabled = pScreenPriv->enabled;
    469     EphyrScrPriv oldscr;
    470     int oldwidth, oldheight, oldmmwidth, oldmmheight;
    471     Bool oldshadow;
    472     int newwidth, newheight;
    473 
    474     if (screen->randr & (RR_Rotate_0 | RR_Rotate_180)) {
    475         newwidth = pSize->width;
    476         newheight = pSize->height;
    477     }
    478     else {
    479         newwidth = pSize->height;
    480         newheight = pSize->width;
    481     }
    482 
    483     if (wasEnabled)
    484         KdDisableScreen(pScreen);
    485 
    486     oldscr = *scrpriv;
    487 
    488     oldwidth = screen->width;
    489     oldheight = screen->height;
    490     oldmmwidth = pScreen->mmWidth;
    491     oldmmheight = pScreen->mmHeight;
    492     oldshadow = scrpriv->shadow;
    493 
    494     /*
    495      * Set new configuration
    496      */
    497 
    498     /*
    499      * We need to store the rotation value for pointer coords transformation;
    500      * though initially the pointer and fb rotation are identical, when we map
    501      * the fb, the screen will be reinitialized and return into an unrotated
    502      * state (presumably the HW is taking care of the rotation of the fb), but the
    503      * pointer still needs to be transformed.
    504      */
    505     ephyrRandr = KdAddRotation(screen->randr, randr);
    506     scrpriv->randr = ephyrRandr;
    507 
    508     ephyrUnmapFramebuffer(screen);
    509 
    510     screen->width = newwidth;
    511     screen->height = newheight;
    512 
    513     scrpriv->win_width = screen->width;
    514     scrpriv->win_height = screen->height;
    515 #ifdef GLAMOR
    516     ephyr_glamor_set_window_size(scrpriv->glamor,
    517                                  scrpriv->win_width,
    518                                  scrpriv->win_height);
    519 #endif
    520 
    521     if (!ephyrMapFramebuffer(screen))
    522         goto bail4;
    523 
    524     /* FIXME below should go in own call */
    525 
    526     if (oldshadow)
    527         KdShadowUnset(screen->pScreen);
    528     else
    529         ephyrUnsetInternalDamage(screen->pScreen);
    530 
    531     ephyrSetScreenSizes(screen->pScreen);
    532 
    533     if (scrpriv->shadow) {
    534         if (!KdShadowSet(screen->pScreen,
    535                          scrpriv->randr, ephyrShadowUpdate, ephyrWindowLinear))
    536             goto bail4;
    537     }
    538     else {
    539 #ifdef GLAMOR
    540         if (ephyr_glamor)
    541             ephyr_glamor_create_screen_resources(pScreen);
    542 #endif
    543         /* Without shadow fb ( non rotated ) we need
    544          * to use damage to efficiently update display
    545          * via signal regions what to copy from 'fb'.
    546          */
    547         if (!ephyrSetInternalDamage(screen->pScreen))
    548             goto bail4;
    549     }
    550 
    551     /*
    552      * Set frame buffer mapping
    553      */
    554     (*pScreen->ModifyPixmapHeader) (fbGetScreenPixmap(pScreen),
    555                                     pScreen->width,
    556                                     pScreen->height,
    557                                     screen->fb.depth,
    558                                     screen->fb.bitsPerPixel,
    559                                     screen->fb.byteStride,
    560                                     screen->fb.frameBuffer);
    561 
    562     /* set the subpixel order */
    563 
    564     KdSetSubpixelOrder(pScreen, scrpriv->randr);
    565 
    566     if (wasEnabled)
    567         KdEnableScreen(pScreen);
    568 
    569     RRScreenSizeNotify(pScreen);
    570 
    571     return TRUE;
    572 
    573  bail4:
    574     EPHYR_LOG("bailed");
    575 
    576     ephyrUnmapFramebuffer(screen);
    577     *scrpriv = oldscr;
    578     (void) ephyrMapFramebuffer(screen);
    579 
    580     pScreen->width = oldwidth;
    581     pScreen->height = oldheight;
    582     pScreen->mmWidth = oldmmwidth;
    583     pScreen->mmHeight = oldmmheight;
    584 
    585     if (wasEnabled)
    586         KdEnableScreen(pScreen);
    587     return FALSE;
    588 }
    589 
    590 Bool
    591 ephyrRandRInit(ScreenPtr pScreen)
    592 {
    593     rrScrPrivPtr pScrPriv;
    594 
    595     if (!RRScreenInit(pScreen))
    596         return FALSE;
    597 
    598     pScrPriv = rrGetScrPriv(pScreen);
    599     pScrPriv->rrGetInfo = ephyrRandRGetInfo;
    600     pScrPriv->rrSetConfig = ephyrRandRSetConfig;
    601     return TRUE;
    602 }
    603 
    604 static Bool
    605 ephyrResizeScreen (ScreenPtr           pScreen,
    606                   int                  newwidth,
    607                   int                  newheight)
    608 {
    609     KdScreenPriv(pScreen);
    610     KdScreenInfo *screen = pScreenPriv->screen;
    611     RRScreenSize size = {0};
    612     Bool ret;
    613     int t;
    614 
    615     if (screen->randr & (RR_Rotate_90|RR_Rotate_270)) {
    616         t = newwidth;
    617         newwidth = newheight;
    618         newheight = t;
    619     }
    620 
    621     if (newwidth == screen->width && newheight == screen->height) {
    622         return FALSE;
    623     }
    624 
    625     size.width = newwidth;
    626     size.height = newheight;
    627 
    628     hostx_size_set_from_configure(TRUE);
    629     ret = ephyrRandRSetConfig (pScreen, screen->randr, 0, &size);
    630     hostx_size_set_from_configure(FALSE);
    631     if (ret) {
    632         RROutputPtr output;
    633 
    634         output = RRFirstOutput(pScreen);
    635         if (!output)
    636             return FALSE;
    637         RROutputSetModes(output, NULL, 0, 0);
    638     }
    639 
    640     return ret;
    641 }
    642 #endif
    643 
    644 Bool
    645 ephyrCreateColormap(ColormapPtr pmap)
    646 {
    647     return fbInitializeColormap(pmap);
    648 }
    649 
    650 Bool
    651 ephyrInitScreen(ScreenPtr pScreen)
    652 {
    653     KdScreenPriv(pScreen);
    654     KdScreenInfo *screen = pScreenPriv->screen;
    655 
    656     EPHYR_LOG("pScreen->myNum:%d\n", pScreen->myNum);
    657     hostx_set_screen_number(screen, pScreen->myNum);
    658     if (EphyrWantNoHostGrab) {
    659         hostx_set_win_title(screen, "xephyr");
    660     } else {
    661         hostx_set_win_title(screen, "(ctrl+shift grabs mouse and keyboard)");
    662     }
    663     pScreen->CreateColormap = ephyrCreateColormap;
    664 
    665 #ifdef XV
    666     if (!ephyrNoXV) {
    667         if (ephyr_glamor)
    668             ephyr_glamor_xv_init(pScreen);
    669         else if (!ephyrInitVideo(pScreen)) {
    670             EPHYR_LOG_ERROR("failed to initialize xvideo\n");
    671         }
    672         else {
    673             EPHYR_LOG("initialized xvideo okay\n");
    674         }
    675     }
    676 #endif /*XV*/
    677 
    678     return TRUE;
    679 }
    680 
    681 
    682 Bool
    683 ephyrFinishInitScreen(ScreenPtr pScreen)
    684 {
    685     KdScreenPriv(pScreen);
    686     KdScreenInfo *screen = pScreenPriv->screen;
    687     EphyrScrPriv *scrpriv = screen->driver;
    688 
    689     /* FIXME: Calling this even if not using shadow.
    690      * Seems harmless enough. But may be safer elsewhere.
    691      */
    692     if (!shadowSetup(pScreen))
    693         return FALSE;
    694 
    695 #ifdef RANDR
    696     if (!ephyrRandRInit(pScreen))
    697         return FALSE;
    698 #endif
    699 
    700     scrpriv->BlockHandler = pScreen->BlockHandler;
    701     pScreen->BlockHandler = ephyrScreenBlockHandler;
    702 
    703     return TRUE;
    704 }
    705 
    706 /**
    707  * Called by kdrive after calling down the
    708  * pScreen->CreateScreenResources() chain, this gives us a chance to
    709  * make any pixmaps after the screen and all extensions have been
    710  * initialized.
    711  */
    712 Bool
    713 ephyrCreateResources(ScreenPtr pScreen)
    714 {
    715     KdScreenPriv(pScreen);
    716     KdScreenInfo *screen = pScreenPriv->screen;
    717     EphyrScrPriv *scrpriv = screen->driver;
    718 
    719     EPHYR_LOG("mark pScreen=%p mynum=%d shadow=%d",
    720               pScreen, pScreen->myNum, scrpriv->shadow);
    721 
    722     if (scrpriv->shadow)
    723         return KdShadowSet(pScreen,
    724                            scrpriv->randr,
    725                            ephyrShadowUpdate, ephyrWindowLinear);
    726     else {
    727 #ifdef GLAMOR
    728         if (ephyr_glamor) {
    729             if (!ephyr_glamor_create_screen_resources(pScreen))
    730                 return FALSE;
    731         }
    732 #endif
    733         return ephyrSetInternalDamage(pScreen);
    734     }
    735 }
    736 
    737 void
    738 ephyrScreenFini(KdScreenInfo * screen)
    739 {
    740     EphyrScrPriv *scrpriv = screen->driver;
    741 
    742     if (scrpriv->shadow) {
    743         KdShadowFbFree(screen);
    744     }
    745     scrpriv->BlockHandler = NULL;
    746 }
    747 
    748 void
    749 ephyrCloseScreen(ScreenPtr pScreen)
    750 {
    751     ephyrUnsetInternalDamage(pScreen);
    752 }
    753 
    754 /*
    755  * Port of Mark McLoughlin's Xnest fix for focus in + modifier bug.
    756  * See https://bugs.freedesktop.org/show_bug.cgi?id=3030
    757  */
    758 void
    759 ephyrUpdateModifierState(unsigned int state)
    760 {
    761 
    762     DeviceIntPtr pDev = inputInfo.keyboard;
    763     KeyClassPtr keyc = pDev->key;
    764     int i;
    765     CARD8 mask;
    766     int xkb_state;
    767 
    768     if (!pDev)
    769         return;
    770 
    771     xkb_state = XkbStateFieldFromRec(&pDev->key->xkbInfo->state);
    772     state = state & 0xff;
    773 
    774     if (xkb_state == state)
    775         return;
    776 
    777     for (i = 0, mask = 1; i < 8; i++, mask <<= 1) {
    778         int key;
    779 
    780         /* Modifier is down, but shouldn't be */
    781         if ((xkb_state & mask) && !(state & mask)) {
    782             int count = keyc->modifierKeyCount[i];
    783 
    784             for (key = 0; key < MAP_LENGTH; key++)
    785                 if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
    786                     if (mask == XCB_MOD_MASK_LOCK) {
    787                         KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE);
    788                         KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE);
    789                     }
    790                     else if (key_is_down(pDev, key, KEY_PROCESSED))
    791                         KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE);
    792 
    793                     if (--count == 0)
    794                         break;
    795                 }
    796         }
    797 
    798         /* Modifier should be down, but isn't */
    799         if (!(xkb_state & mask) && (state & mask))
    800             for (key = 0; key < MAP_LENGTH; key++)
    801                 if (keyc->xkbInfo->desc->map->modmap[key] & mask) {
    802                     KdEnqueueKeyboardEvent(ephyrKbd, key, FALSE);
    803                     if (mask == XCB_MOD_MASK_LOCK)
    804                         KdEnqueueKeyboardEvent(ephyrKbd, key, TRUE);
    805                     break;
    806                 }
    807     }
    808 }
    809 
    810 static Bool
    811 ephyrCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
    812 {
    813     return FALSE;
    814 }
    815 
    816 static void
    817 ephyrCrossScreen(ScreenPtr pScreen, Bool entering)
    818 {
    819 }
    820 
    821 ScreenPtr ephyrCursorScreen; /* screen containing the cursor */
    822 
    823 static void
    824 ephyrWarpCursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x, int y)
    825 {
    826     input_lock();
    827     ephyrCursorScreen = pScreen;
    828     miPointerWarpCursor(inputInfo.pointer, pScreen, x, y);
    829 
    830     input_unlock();
    831 }
    832 
    833 miPointerScreenFuncRec ephyrPointerScreenFuncs = {
    834     ephyrCursorOffScreen,
    835     ephyrCrossScreen,
    836     ephyrWarpCursor,
    837 };
    838 
    839 static KdScreenInfo *
    840 screen_from_window(Window w)
    841 {
    842     int i = 0;
    843 
    844     for (i = 0; i < screenInfo.numScreens; i++) {
    845         ScreenPtr pScreen = screenInfo.screens[i];
    846         KdPrivScreenPtr kdscrpriv = KdGetScreenPriv(pScreen);
    847         KdScreenInfo *screen = kdscrpriv->screen;
    848         EphyrScrPriv *scrpriv = screen->driver;
    849 
    850         if (scrpriv->win == w
    851             || scrpriv->peer_win == w
    852             || scrpriv->win_pre_existing == w) {
    853             return screen;
    854         }
    855     }
    856 
    857     return NULL;
    858 }
    859 
    860 static void
    861 ephyrProcessErrorEvent(xcb_generic_event_t *xev)
    862 {
    863     xcb_generic_error_t *e = (xcb_generic_error_t *)xev;
    864 
    865     FatalError("X11 error\n"
    866                "Error code: %hhu\n"
    867                "Sequence number: %hu\n"
    868                "Major code: %hhu\tMinor code: %hu\n"
    869                "Error value: %u\n",
    870                e->error_code,
    871                e->sequence,
    872                e->major_code, e->minor_code,
    873                e->resource_id);
    874 }
    875 
    876 static void
    877 ephyrProcessExpose(xcb_generic_event_t *xev)
    878 {
    879     xcb_expose_event_t *expose = (xcb_expose_event_t *)xev;
    880     KdScreenInfo *screen = screen_from_window(expose->window);
    881     EphyrScrPriv *scrpriv = screen->driver;
    882 
    883     /* Wait for the last expose event in a series of cliprects
    884      * to actually paint our screen.
    885      */
    886     if (expose->count != 0)
    887         return;
    888 
    889     if (scrpriv) {
    890         hostx_paint_rect(scrpriv->screen, 0, 0, 0, 0,
    891                          scrpriv->win_width,
    892                          scrpriv->win_height);
    893     } else {
    894         EPHYR_LOG_ERROR("failed to get host screen\n");
    895     }
    896 }
    897 
    898 static void
    899 ephyrProcessMouseMotion(xcb_generic_event_t *xev)
    900 {
    901     xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *)xev;
    902     KdScreenInfo *screen = screen_from_window(motion->event);
    903 
    904     if (!ephyrMouse ||
    905         !((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
    906         EPHYR_LOG("skipping mouse motion:%d\n", screen->pScreen->myNum);
    907         return;
    908     }
    909 
    910     if (ephyrCursorScreen != screen->pScreen) {
    911         EPHYR_LOG("warping mouse cursor. "
    912                   "cur_screen:%d, motion_screen:%d\n",
    913                   ephyrCursorScreen->myNum, screen->pScreen->myNum);
    914         ephyrWarpCursor(inputInfo.pointer, screen->pScreen,
    915                         motion->event_x, motion->event_y);
    916     }
    917     else {
    918         int x = 0, y = 0;
    919 
    920         EPHYR_LOG("enqueuing mouse motion:%d\n", screen->pScreen->myNum);
    921         x = motion->event_x / SCALE;
    922         y = motion->event_y / SCALE;
    923         EPHYR_LOG("initial (x,y):(%d,%d)\n", x, y);
    924 
    925         /* convert coords into desktop-wide coordinates.
    926          * fill_pointer_events will convert that back to
    927          * per-screen coordinates where needed */
    928         x += screen->pScreen->x;
    929         y += screen->pScreen->y;
    930 
    931         KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_POINTER_DESKTOP, x, y, 0);
    932     }
    933 }
    934 
    935 static void
    936 ephyrProcessButtonPress(xcb_generic_event_t *xev)
    937 {
    938     xcb_button_press_event_t *button = (xcb_button_press_event_t *)xev;
    939 
    940     if (!ephyrMouse ||
    941         !((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
    942         EPHYR_LOG("skipping mouse press:%d\n", screen_from_window(button->event)->pScreen->myNum);
    943         return;
    944     }
    945 
    946     ephyrUpdateModifierState(button->state);
    947     /* This is a bit hacky. will break for button 5 ( defined as 0x10 )
    948      * Check KD_BUTTON defines in kdrive.h
    949      */
    950     mouseState |= 1 << (button->detail - 1);
    951 
    952     EPHYR_LOG("enqueuing mouse press:%d\n", screen_from_window(button->event)->pScreen->myNum);
    953     KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0, 0);
    954 }
    955 
    956 static void
    957 ephyrProcessButtonRelease(xcb_generic_event_t *xev)
    958 {
    959     xcb_button_press_event_t *button = (xcb_button_press_event_t *)xev;
    960 
    961     if (!ephyrMouse ||
    962         !((EphyrPointerPrivate *) ephyrMouse->driverPrivate)->enabled) {
    963         return;
    964     }
    965 
    966     ephyrUpdateModifierState(button->state);
    967     mouseState &= ~(1 << (button->detail - 1));
    968 
    969     EPHYR_LOG("enqueuing mouse release:%d\n", screen_from_window(button->event)->pScreen->myNum);
    970     KdEnqueuePointerEvent(ephyrMouse, mouseState | KD_MOUSE_DELTA, 0, 0, 0);
    971 }
    972 
    973 /* Xephyr wants ctrl+shift to grab the window, but that conflicts with
    974    ctrl+alt+shift key combos. Remember the modifier state on key presses and
    975    releases, if mod1 is pressed, we need ctrl, shift and mod1 released
    976    before we allow a shift-ctrl grab activation.
    977 
    978    note: a key event contains the mask _before_ the current key takes
    979    effect, so mod1_was_down will be reset on the first key press after all
    980    three were released, not on the last release. That'd require some more
    981    effort.
    982  */
    983 static int
    984 ephyrUpdateGrabModifierState(int state)
    985 {
    986     static int mod1_was_down = 0;
    987 
    988     if ((state & (XCB_MOD_MASK_CONTROL|XCB_MOD_MASK_SHIFT|XCB_MOD_MASK_1)) == 0)
    989         mod1_was_down = 0;
    990     else if (state & XCB_MOD_MASK_1)
    991         mod1_was_down = 1;
    992 
    993     return mod1_was_down;
    994 }
    995 
    996 static void
    997 ephyrProcessKeyPress(xcb_generic_event_t *xev)
    998 {
    999     xcb_key_press_event_t *key = (xcb_key_press_event_t *)xev;
   1000 
   1001     if (!ephyrKbd ||
   1002         !((EphyrKbdPrivate *) ephyrKbd->driverPrivate)->enabled) {
   1003         return;
   1004     }
   1005 
   1006     ephyrUpdateGrabModifierState(key->state);
   1007     ephyrUpdateModifierState(key->state);
   1008     KdEnqueueKeyboardEvent(ephyrKbd, key->detail, FALSE);
   1009 }
   1010 
   1011 static void
   1012 ephyrProcessKeyRelease(xcb_generic_event_t *xev)
   1013 {
   1014     xcb_connection_t *conn = hostx_get_xcbconn();
   1015     xcb_key_release_event_t *key = (xcb_key_release_event_t *)xev;
   1016     static xcb_key_symbols_t *keysyms;
   1017     static int grabbed_screen = -1;
   1018     int mod1_down = ephyrUpdateGrabModifierState(key->state);
   1019 
   1020     if (!keysyms)
   1021         keysyms = xcb_key_symbols_alloc(conn);
   1022 
   1023     if (!EphyrWantNoHostGrab &&
   1024         (((xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Shift_L
   1025           || xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Shift_R)
   1026          && (key->state & XCB_MOD_MASK_CONTROL)) ||
   1027         ((xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Control_L
   1028           || xcb_key_symbols_get_keysym(keysyms, key->detail, 0) == XK_Control_R)
   1029          && (key->state & XCB_MOD_MASK_SHIFT)))) {
   1030         KdScreenInfo *screen = screen_from_window(key->event);
   1031         EphyrScrPriv *scrpriv = screen->driver;
   1032 
   1033         if (grabbed_screen != -1) {
   1034             xcb_ungrab_keyboard(conn, XCB_TIME_CURRENT_TIME);
   1035             xcb_ungrab_pointer(conn, XCB_TIME_CURRENT_TIME);
   1036             grabbed_screen = -1;
   1037             hostx_set_win_title(screen,
   1038                                 "(ctrl+shift grabs mouse and keyboard)");
   1039         }
   1040         else if (!mod1_down) {
   1041             /* Attempt grab */
   1042             xcb_grab_keyboard_cookie_t kbgrabc =
   1043                 xcb_grab_keyboard(conn,
   1044                                   TRUE,
   1045                                   scrpriv->win,
   1046                                   XCB_TIME_CURRENT_TIME,
   1047                                   XCB_GRAB_MODE_ASYNC,
   1048                                   XCB_GRAB_MODE_ASYNC);
   1049             xcb_grab_keyboard_reply_t *kbgrabr;
   1050             xcb_grab_pointer_cookie_t pgrabc =
   1051                 xcb_grab_pointer(conn,
   1052                                  TRUE,
   1053                                  scrpriv->win,
   1054                                  0,
   1055                                  XCB_GRAB_MODE_ASYNC,
   1056                                  XCB_GRAB_MODE_ASYNC,
   1057                                  scrpriv->win,
   1058                                  XCB_NONE,
   1059                                  XCB_TIME_CURRENT_TIME);
   1060             xcb_grab_pointer_reply_t *pgrabr;
   1061             kbgrabr = xcb_grab_keyboard_reply(conn, kbgrabc, NULL);
   1062             if (!kbgrabr || kbgrabr->status != XCB_GRAB_STATUS_SUCCESS) {
   1063                 xcb_discard_reply(conn, pgrabc.sequence);
   1064                 xcb_ungrab_pointer(conn, XCB_TIME_CURRENT_TIME);
   1065             } else {
   1066                 pgrabr = xcb_grab_pointer_reply(conn, pgrabc, NULL);
   1067                 if (!pgrabr || pgrabr->status != XCB_GRAB_STATUS_SUCCESS)
   1068                     {
   1069                         xcb_ungrab_keyboard(conn,
   1070                                             XCB_TIME_CURRENT_TIME);
   1071                     } else {
   1072                     grabbed_screen = scrpriv->mynum;
   1073                     hostx_set_win_title
   1074                         (screen,
   1075                          "(ctrl+shift releases mouse and keyboard)");
   1076                 }
   1077             }
   1078         }
   1079     }
   1080 
   1081     if (!ephyrKbd ||
   1082         !((EphyrKbdPrivate *) ephyrKbd->driverPrivate)->enabled) {
   1083         return;
   1084     }
   1085 
   1086     /* Still send the release event even if above has happened server
   1087      * will get confused with just an up event.  Maybe it would be
   1088      * better to just block shift+ctrls getting to kdrive all
   1089      * together.
   1090      */
   1091     ephyrUpdateModifierState(key->state);
   1092     KdEnqueueKeyboardEvent(ephyrKbd, key->detail, TRUE);
   1093 }
   1094 
   1095 static void
   1096 ephyrProcessConfigureNotify(xcb_generic_event_t *xev)
   1097 {
   1098     xcb_configure_notify_event_t *configure =
   1099         (xcb_configure_notify_event_t *)xev;
   1100     KdScreenInfo *screen = screen_from_window(configure->window);
   1101     EphyrScrPriv *scrpriv = screen->driver;
   1102 
   1103     if (!scrpriv ||
   1104         (scrpriv->win_pre_existing == None && !EphyrWantResize)) {
   1105         return;
   1106     }
   1107 
   1108 #ifdef RANDR
   1109     ephyrResizeScreen(screen->pScreen, configure->width / SCALE,
   1110                       configure->height / SCALE);
   1111 #endif /* RANDR */
   1112 }
   1113 
   1114 static void
   1115 ephyrXcbProcessEvents(Bool queued_only)
   1116 {
   1117     xcb_connection_t *conn = hostx_get_xcbconn();
   1118     xcb_generic_event_t *expose = NULL, *configure = NULL;
   1119 
   1120     while (TRUE) {
   1121         xcb_generic_event_t *xev = hostx_get_event(queued_only);
   1122 
   1123         if (!xev) {
   1124             /* If our XCB connection has died (for example, our window was
   1125              * closed), exit now.
   1126              */
   1127             if (xcb_connection_has_error(conn)) {
   1128                 CloseWellKnownConnections();
   1129                 OsCleanup(1);
   1130                 exit(1);
   1131             }
   1132 
   1133             break;
   1134         }
   1135 
   1136         switch (xev->response_type & 0x7f) {
   1137         case 0:
   1138             ephyrProcessErrorEvent(xev);
   1139             break;
   1140 
   1141         case XCB_EXPOSE:
   1142             free(expose);
   1143             expose = xev;
   1144             xev = NULL;
   1145             break;
   1146 
   1147         case XCB_MOTION_NOTIFY:
   1148             ephyrProcessMouseMotion(xev);
   1149             break;
   1150 
   1151         case XCB_KEY_PRESS:
   1152             ephyrProcessKeyPress(xev);
   1153             break;
   1154 
   1155         case XCB_KEY_RELEASE:
   1156             ephyrProcessKeyRelease(xev);
   1157             break;
   1158 
   1159         case XCB_BUTTON_PRESS:
   1160             ephyrProcessButtonPress(xev);
   1161             break;
   1162 
   1163         case XCB_BUTTON_RELEASE:
   1164             ephyrProcessButtonRelease(xev);
   1165             break;
   1166 
   1167         case XCB_CONFIGURE_NOTIFY:
   1168             free(configure);
   1169             configure = xev;
   1170             xev = NULL;
   1171             break;
   1172         }
   1173 
   1174         if (xev) {
   1175             if (ephyr_glamor)
   1176                 ephyr_glamor_process_event(xev);
   1177 
   1178             free(xev);
   1179         }
   1180     }
   1181 
   1182     if (configure) {
   1183         ephyrProcessConfigureNotify(configure);
   1184         free(configure);
   1185     }
   1186 
   1187     if (expose) {
   1188         ephyrProcessExpose(expose);
   1189         free(expose);
   1190     }
   1191 }
   1192 
   1193 static void
   1194 ephyrXcbNotify(int fd, int ready, void *data)
   1195 {
   1196     ephyrXcbProcessEvents(FALSE);
   1197 }
   1198 
   1199 void
   1200 ephyrCardFini(KdCardInfo * card)
   1201 {
   1202     EphyrPriv *priv = card->driver;
   1203 
   1204     free(priv);
   1205 }
   1206 
   1207 void
   1208 ephyrGetColors(ScreenPtr pScreen, int n, xColorItem * pdefs)
   1209 {
   1210     /* XXX Not sure if this is right */
   1211 
   1212     EPHYR_LOG("mark");
   1213 
   1214     while (n--) {
   1215         pdefs->red = 0;
   1216         pdefs->green = 0;
   1217         pdefs->blue = 0;
   1218         pdefs++;
   1219     }
   1220 
   1221 }
   1222 
   1223 void
   1224 ephyrPutColors(ScreenPtr pScreen, int n, xColorItem * pdefs)
   1225 {
   1226     KdScreenPriv(pScreen);
   1227     KdScreenInfo *screen = pScreenPriv->screen;
   1228     EphyrScrPriv *scrpriv = screen->driver;
   1229     int min, max, p;
   1230 
   1231     /* XXX Not sure if this is right */
   1232 
   1233     min = 256;
   1234     max = 0;
   1235 
   1236     while (n--) {
   1237         p = pdefs->pixel;
   1238         if (p < min)
   1239             min = p;
   1240         if (p > max)
   1241             max = p;
   1242 
   1243         hostx_set_cmap_entry(pScreen, p,
   1244                              pdefs->red >> 8,
   1245                              pdefs->green >> 8, pdefs->blue >> 8);
   1246         pdefs++;
   1247     }
   1248     if (scrpriv->pDamage) {
   1249         BoxRec box;
   1250         RegionRec region;
   1251 
   1252         box.x1 = 0;
   1253         box.y1 = 0;
   1254         box.x2 = pScreen->width;
   1255         box.y2 = pScreen->height;
   1256         RegionInit(&region, &box, 1);
   1257         DamageReportDamage(scrpriv->pDamage, &region);
   1258         RegionUninit(&region);
   1259     }
   1260 }
   1261 
   1262 /* Mouse calls */
   1263 
   1264 static Status
   1265 MouseInit(KdPointerInfo * pi)
   1266 {
   1267     pi->driverPrivate = (EphyrPointerPrivate *)
   1268         calloc(sizeof(EphyrPointerPrivate), 1);
   1269     ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = FALSE;
   1270     pi->nAxes = 3;
   1271     pi->nButtons = 32;
   1272     free(pi->name);
   1273     pi->name = strdup("Xephyr virtual mouse");
   1274 
   1275     /*
   1276      * Must transform pointer coords since the pointer position
   1277      * relative to the Xephyr window is controlled by the host server and
   1278      * remains constant regardless of any rotation applied to the Xephyr screen.
   1279      */
   1280     pi->transformCoordinates = TRUE;
   1281 
   1282     ephyrMouse = pi;
   1283     return Success;
   1284 }
   1285 
   1286 static Status
   1287 MouseEnable(KdPointerInfo * pi)
   1288 {
   1289     ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = TRUE;
   1290     SetNotifyFd(hostx_get_fd(), ephyrXcbNotify, X_NOTIFY_READ, NULL);
   1291     return Success;
   1292 }
   1293 
   1294 static void
   1295 MouseDisable(KdPointerInfo * pi)
   1296 {
   1297     ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = FALSE;
   1298     RemoveNotifyFd(hostx_get_fd());
   1299     return;
   1300 }
   1301 
   1302 static void
   1303 MouseFini(KdPointerInfo * pi)
   1304 {
   1305     free(pi->driverPrivate);
   1306     ephyrMouse = NULL;
   1307     return;
   1308 }
   1309 
   1310 KdPointerDriver EphyrMouseDriver = {
   1311     "ephyr",
   1312     MouseInit,
   1313     MouseEnable,
   1314     MouseDisable,
   1315     MouseFini,
   1316     NULL,
   1317 };
   1318 
   1319 /* Keyboard */
   1320 
   1321 static Status
   1322 EphyrKeyboardInit(KdKeyboardInfo * ki)
   1323 {
   1324     KeySymsRec keySyms;
   1325     CARD8 modmap[MAP_LENGTH];
   1326     XkbControlsRec controls;
   1327 
   1328     ki->driverPrivate = (EphyrKbdPrivate *)
   1329         calloc(sizeof(EphyrKbdPrivate), 1);
   1330 
   1331     if (hostx_load_keymap(&keySyms, modmap, &controls)) {
   1332         XkbApplyMappingChange(ki->dixdev, &keySyms,
   1333                               keySyms.minKeyCode,
   1334                               keySyms.maxKeyCode - keySyms.minKeyCode + 1,
   1335                               modmap, serverClient);
   1336         XkbDDXChangeControls(ki->dixdev, &controls, &controls);
   1337         free(keySyms.map);
   1338     }
   1339 
   1340     ki->minScanCode = keySyms.minKeyCode;
   1341     ki->maxScanCode = keySyms.maxKeyCode;
   1342 
   1343     if (ki->name != NULL) {
   1344         free(ki->name);
   1345     }
   1346 
   1347     ki->name = strdup("Xephyr virtual keyboard");
   1348     ephyrKbd = ki;
   1349     return Success;
   1350 }
   1351 
   1352 static Status
   1353 EphyrKeyboardEnable(KdKeyboardInfo * ki)
   1354 {
   1355     ((EphyrKbdPrivate *) ki->driverPrivate)->enabled = TRUE;
   1356 
   1357     return Success;
   1358 }
   1359 
   1360 static void
   1361 EphyrKeyboardDisable(KdKeyboardInfo * ki)
   1362 {
   1363     ((EphyrKbdPrivate *) ki->driverPrivate)->enabled = FALSE;
   1364 }
   1365 
   1366 static void
   1367 EphyrKeyboardFini(KdKeyboardInfo * ki)
   1368 {
   1369     free(ki->driverPrivate);
   1370     ephyrKbd = NULL;
   1371     return;
   1372 }
   1373 
   1374 static void
   1375 EphyrKeyboardLeds(KdKeyboardInfo * ki, int leds)
   1376 {
   1377 }
   1378 
   1379 static void
   1380 EphyrKeyboardBell(KdKeyboardInfo * ki, int volume, int frequency, int duration)
   1381 {
   1382 }
   1383 
   1384 KdKeyboardDriver EphyrKeyboardDriver = {
   1385     "ephyr",
   1386     EphyrKeyboardInit,
   1387     EphyrKeyboardEnable,
   1388     EphyrKeyboardLeds,
   1389     EphyrKeyboardBell,
   1390     EphyrKeyboardDisable,
   1391     EphyrKeyboardFini,
   1392     NULL,
   1393 };