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