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 46extern Bool ephyr_glamor; 47 48KdKeyboardInfo *ephyrKbd; 49KdPointerInfo *ephyrMouse; 50Bool ephyrNoDRI = FALSE; 51Bool ephyrNoXV = FALSE; 52 53static int mouseState = 0; 54static Rotation ephyrRandr = RR_Rotate_0; 55 56typedef struct _EphyrInputPrivate { 57 Bool enabled; 58} EphyrKbdPrivate, EphyrPointerPrivate; 59 60Bool EphyrWantGrayScale = 0; 61Bool EphyrWantResize = 0; 62Bool EphyrWantNoHostGrab = 0; 63 64Bool 65ephyrInitialize(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 74Bool 75ephyrCardInit(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 92Bool 93ephyrScreenInitialize(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 178void * 179ephyrWindowLinear(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 */ 197int 198ephyrBufferHeight(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 209Bool 210ephyrMapFramebuffer(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 254void 255ephyrSetScreenSizes(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 275Bool 276ephyrUnmapFramebuffer(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 288void 289ephyrShadowUpdate(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 304static void 305ephyrInternalDamageRedisplay(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 339static void 340ephyrXcbProcessEvents(Bool queued_only); 341 342static Bool 343ephyrEventWorkProc(ClientPtr client, void *closure) 344{ 345 ephyrXcbProcessEvents(TRUE); 346 return TRUE; 347} 348 349static void 350ephyrScreenBlockHandler(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 371Bool 372ephyrSetInternalDamage(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 390void 391ephyrUnsetInternalDamage(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 402Bool 403ephyrRandRGetInfo(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 461Bool 462ephyrRandRSetConfig(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 590Bool 591ephyrRandRInit(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 604static Bool 605ephyrResizeScreen (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 644Bool 645ephyrCreateColormap(ColormapPtr pmap) 646{ 647 return fbInitializeColormap(pmap); 648} 649 650Bool 651ephyrInitScreen(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 682Bool 683ephyrFinishInitScreen(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 */ 712Bool 713ephyrCreateResources(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 737void 738ephyrScreenFini(KdScreenInfo * screen) 739{ 740 EphyrScrPriv *scrpriv = screen->driver; 741 742 if (scrpriv->shadow) { 743 KdShadowFbFree(screen); 744 } 745 scrpriv->BlockHandler = NULL; 746} 747 748void 749ephyrCloseScreen(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 */ 758void 759ephyrUpdateModifierState(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 810static Bool 811ephyrCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) 812{ 813 return FALSE; 814} 815 816static void 817ephyrCrossScreen(ScreenPtr pScreen, Bool entering) 818{ 819} 820 821ScreenPtr ephyrCursorScreen; /* screen containing the cursor */ 822 823static void 824ephyrWarpCursor(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 833miPointerScreenFuncRec ephyrPointerScreenFuncs = { 834 ephyrCursorOffScreen, 835 ephyrCrossScreen, 836 ephyrWarpCursor, 837}; 838 839static KdScreenInfo * 840screen_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 860static void 861ephyrProcessErrorEvent(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 876static void 877ephyrProcessExpose(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 898static void 899ephyrProcessMouseMotion(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; 922 y = motion->event_y; 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 935static void 936ephyrProcessButtonPress(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 956static void 957ephyrProcessButtonRelease(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 */ 983static int 984ephyrUpdateGrabModifierState(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 996static void 997ephyrProcessKeyPress(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 1011static void 1012ephyrProcessKeyRelease(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 1095static void 1096ephyrProcessConfigureNotify(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, configure->height); 1110#endif /* RANDR */ 1111} 1112 1113static void 1114ephyrXcbProcessEvents(Bool queued_only) 1115{ 1116 xcb_connection_t *conn = hostx_get_xcbconn(); 1117 xcb_generic_event_t *expose = NULL, *configure = NULL; 1118 1119 while (TRUE) { 1120 xcb_generic_event_t *xev = hostx_get_event(queued_only); 1121 1122 if (!xev) { 1123 /* If our XCB connection has died (for example, our window was 1124 * closed), exit now. 1125 */ 1126 if (xcb_connection_has_error(conn)) { 1127 CloseWellKnownConnections(); 1128 OsCleanup(1); 1129 exit(1); 1130 } 1131 1132 break; 1133 } 1134 1135 switch (xev->response_type & 0x7f) { 1136 case 0: 1137 ephyrProcessErrorEvent(xev); 1138 break; 1139 1140 case XCB_EXPOSE: 1141 free(expose); 1142 expose = xev; 1143 xev = NULL; 1144 break; 1145 1146 case XCB_MOTION_NOTIFY: 1147 ephyrProcessMouseMotion(xev); 1148 break; 1149 1150 case XCB_KEY_PRESS: 1151 ephyrProcessKeyPress(xev); 1152 break; 1153 1154 case XCB_KEY_RELEASE: 1155 ephyrProcessKeyRelease(xev); 1156 break; 1157 1158 case XCB_BUTTON_PRESS: 1159 ephyrProcessButtonPress(xev); 1160 break; 1161 1162 case XCB_BUTTON_RELEASE: 1163 ephyrProcessButtonRelease(xev); 1164 break; 1165 1166 case XCB_CONFIGURE_NOTIFY: 1167 free(configure); 1168 configure = xev; 1169 xev = NULL; 1170 break; 1171 } 1172 1173 if (xev) { 1174 if (ephyr_glamor) 1175 ephyr_glamor_process_event(xev); 1176 1177 free(xev); 1178 } 1179 } 1180 1181 if (configure) { 1182 ephyrProcessConfigureNotify(configure); 1183 free(configure); 1184 } 1185 1186 if (expose) { 1187 ephyrProcessExpose(expose); 1188 free(expose); 1189 } 1190} 1191 1192static void 1193ephyrXcbNotify(int fd, int ready, void *data) 1194{ 1195 ephyrXcbProcessEvents(FALSE); 1196} 1197 1198void 1199ephyrCardFini(KdCardInfo * card) 1200{ 1201 EphyrPriv *priv = card->driver; 1202 1203 free(priv); 1204} 1205 1206void 1207ephyrGetColors(ScreenPtr pScreen, int n, xColorItem * pdefs) 1208{ 1209 /* XXX Not sure if this is right */ 1210 1211 EPHYR_LOG("mark"); 1212 1213 while (n--) { 1214 pdefs->red = 0; 1215 pdefs->green = 0; 1216 pdefs->blue = 0; 1217 pdefs++; 1218 } 1219 1220} 1221 1222void 1223ephyrPutColors(ScreenPtr pScreen, int n, xColorItem * pdefs) 1224{ 1225 KdScreenPriv(pScreen); 1226 KdScreenInfo *screen = pScreenPriv->screen; 1227 EphyrScrPriv *scrpriv = screen->driver; 1228 int min, max, p; 1229 1230 /* XXX Not sure if this is right */ 1231 1232 min = 256; 1233 max = 0; 1234 1235 while (n--) { 1236 p = pdefs->pixel; 1237 if (p < min) 1238 min = p; 1239 if (p > max) 1240 max = p; 1241 1242 hostx_set_cmap_entry(pScreen, p, 1243 pdefs->red >> 8, 1244 pdefs->green >> 8, pdefs->blue >> 8); 1245 pdefs++; 1246 } 1247 if (scrpriv->pDamage) { 1248 BoxRec box; 1249 RegionRec region; 1250 1251 box.x1 = 0; 1252 box.y1 = 0; 1253 box.x2 = pScreen->width; 1254 box.y2 = pScreen->height; 1255 RegionInit(®ion, &box, 1); 1256 DamageReportDamage(scrpriv->pDamage, ®ion); 1257 RegionUninit(®ion); 1258 } 1259} 1260 1261/* Mouse calls */ 1262 1263static Status 1264MouseInit(KdPointerInfo * pi) 1265{ 1266 pi->driverPrivate = (EphyrPointerPrivate *) 1267 calloc(sizeof(EphyrPointerPrivate), 1); 1268 ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = FALSE; 1269 pi->nAxes = 3; 1270 pi->nButtons = 32; 1271 free(pi->name); 1272 pi->name = strdup("Xephyr virtual mouse"); 1273 1274 /* 1275 * Must transform pointer coords since the pointer position 1276 * relative to the Xephyr window is controlled by the host server and 1277 * remains constant regardless of any rotation applied to the Xephyr screen. 1278 */ 1279 pi->transformCoordinates = TRUE; 1280 1281 ephyrMouse = pi; 1282 return Success; 1283} 1284 1285static Status 1286MouseEnable(KdPointerInfo * pi) 1287{ 1288 ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = TRUE; 1289 SetNotifyFd(hostx_get_fd(), ephyrXcbNotify, X_NOTIFY_READ, NULL); 1290 return Success; 1291} 1292 1293static void 1294MouseDisable(KdPointerInfo * pi) 1295{ 1296 ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = FALSE; 1297 RemoveNotifyFd(hostx_get_fd()); 1298 return; 1299} 1300 1301static void 1302MouseFini(KdPointerInfo * pi) 1303{ 1304 free(pi->driverPrivate); 1305 ephyrMouse = NULL; 1306 return; 1307} 1308 1309KdPointerDriver EphyrMouseDriver = { 1310 "ephyr", 1311 MouseInit, 1312 MouseEnable, 1313 MouseDisable, 1314 MouseFini, 1315 NULL, 1316}; 1317 1318/* Keyboard */ 1319 1320static Status 1321EphyrKeyboardInit(KdKeyboardInfo * ki) 1322{ 1323 KeySymsRec keySyms; 1324 CARD8 modmap[MAP_LENGTH]; 1325 XkbControlsRec controls; 1326 1327 ki->driverPrivate = (EphyrKbdPrivate *) 1328 calloc(sizeof(EphyrKbdPrivate), 1); 1329 1330 if (hostx_load_keymap(&keySyms, modmap, &controls)) { 1331 XkbApplyMappingChange(ki->dixdev, &keySyms, 1332 keySyms.minKeyCode, 1333 keySyms.maxKeyCode - keySyms.minKeyCode + 1, 1334 modmap, serverClient); 1335 XkbDDXChangeControls(ki->dixdev, &controls, &controls); 1336 free(keySyms.map); 1337 } 1338 1339 ki->minScanCode = keySyms.minKeyCode; 1340 ki->maxScanCode = keySyms.maxKeyCode; 1341 1342 if (ki->name != NULL) { 1343 free(ki->name); 1344 } 1345 1346 ki->name = strdup("Xephyr virtual keyboard"); 1347 ephyrKbd = ki; 1348 return Success; 1349} 1350 1351static Status 1352EphyrKeyboardEnable(KdKeyboardInfo * ki) 1353{ 1354 ((EphyrKbdPrivate *) ki->driverPrivate)->enabled = TRUE; 1355 1356 return Success; 1357} 1358 1359static void 1360EphyrKeyboardDisable(KdKeyboardInfo * ki) 1361{ 1362 ((EphyrKbdPrivate *) ki->driverPrivate)->enabled = FALSE; 1363} 1364 1365static void 1366EphyrKeyboardFini(KdKeyboardInfo * ki) 1367{ 1368 free(ki->driverPrivate); 1369 ephyrKbd = NULL; 1370 return; 1371} 1372 1373static void 1374EphyrKeyboardLeds(KdKeyboardInfo * ki, int leds) 1375{ 1376} 1377 1378static void 1379EphyrKeyboardBell(KdKeyboardInfo * ki, int volume, int frequency, int duration) 1380{ 1381} 1382 1383KdKeyboardDriver EphyrKeyboardDriver = { 1384 "ephyr", 1385 EphyrKeyboardInit, 1386 EphyrKeyboardEnable, 1387 EphyrKeyboardLeds, 1388 EphyrKeyboardBell, 1389 EphyrKeyboardDisable, 1390 EphyrKeyboardFini, 1391 NULL, 1392}; 1393