Commit | Line | Data |
---|---|---|
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 | ||
48 | extern int KdTsPhyScreen; | |
49 | ||
50 | KdKeyboardInfo *ephyrKbd; | |
51 | KdPointerInfo *ephyrMouse; | |
52 | EphyrKeySyms ephyrKeySyms; | |
53 | Bool ephyrNoDRI = FALSE; | |
54 | Bool ephyrNoXV = FALSE; | |
55 | ||
56 | static int mouseState = 0; | |
57 | static Rotation ephyrRandr = RR_Rotate_0; | |
58 | ||
59 | typedef struct _EphyrInputPrivate { | |
60 | Bool enabled; | |
61 | } EphyrKbdPrivate, EphyrPointerPrivate; | |
62 | ||
63 | Bool EphyrWantGrayScale = 0; | |
64 | Bool EphyrWantResize = 0; | |
65 | ||
66 | Bool | |
67 | host_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 | ||
76 | Bool | |
77 | ephyrInitialize(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 | ||
86 | Bool | |
87 | ephyrCardInit(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 | ||
104 | Bool | |
105 | ephyrScreenInitialize(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 | ||
187 | void * | |
188 | ephyrWindowLinear(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 | */ | |
206 | int | |
207 | ephyrBufferHeight(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 | ||
218 | Bool | |
219 | ephyrMapFramebuffer(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 | ||
262 | void | |
263 | ephyrSetScreenSizes(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 | ||
283 | Bool | |
284 | ephyrUnmapFramebuffer(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 | ||
296 | void | |
297 | ephyrShadowUpdate(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 | ||
312 | static void | |
313 | ephyrInternalDamageRedisplay(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 | ||
343 | static void | |
344 | ephyrInternalDamageBlockHandler(pointer data, OSTimePtr pTimeout, pointer pRead) | |
345 | { | |
346 | ScreenPtr pScreen = (ScreenPtr) data; | |
347 | ||
348 | ephyrInternalDamageRedisplay(pScreen); | |
349 | } | |
350 | ||
351 | static void | |
352 | ephyrInternalDamageWakeupHandler(pointer data, int i, pointer LastSelectMask) | |
353 | { | |
354 | /* FIXME: Not needed ? */ | |
355 | } | |
356 | ||
357 | Bool | |
358 | ephyrSetInternalDamage(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 | ||
381 | void | |
382 | ephyrUnsetInternalDamage(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 | |
396 | Bool | |
397 | ephyrRandRGetInfo(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 | ||
455 | Bool | |
456 | ephyrRandRSetConfig(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 | ||
572 | Bool | |
573 | ephyrRandRInit(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 | ||
586 | static Bool | |
587 | ephyrResizeScreen (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 | ||
624 | Bool | |
625 | ephyrCreateColormap(ColormapPtr pmap) | |
626 | { | |
627 | return fbInitializeColormap(pmap); | |
628 | } | |
629 | ||
630 | Bool | |
631 | ephyrInitScreen(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 | ||
665 | Bool | |
666 | ephyrFinishInitScreen(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 | ||
682 | Bool | |
683 | ephyrCreateResources(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 | ||
700 | void | |
701 | ephyrPreserve(KdCardInfo * card) | |
702 | { | |
703 | } | |
704 | ||
705 | Bool | |
706 | ephyrEnable(ScreenPtr pScreen) | |
707 | { | |
708 | return TRUE; | |
709 | } | |
710 | ||
711 | Bool | |
712 | ephyrDPMS(ScreenPtr pScreen, int mode) | |
713 | { | |
714 | return TRUE; | |
715 | } | |
716 | ||
717 | void | |
718 | ephyrDisable(ScreenPtr pScreen) | |
719 | { | |
720 | } | |
721 | ||
722 | void | |
723 | ephyrRestore(KdCardInfo * card) | |
724 | { | |
725 | } | |
726 | ||
727 | void | |
728 | ephyrScreenFini(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 | */ | |
741 | void | |
742 | ephyrUpdateModifierState(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 | ||
789 | static Bool | |
790 | ephyrCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y) | |
791 | { | |
792 | return FALSE; | |
793 | } | |
794 | ||
795 | static void | |
796 | ephyrCrossScreen(ScreenPtr pScreen, Bool entering) | |
797 | { | |
798 | } | |
799 | ||
800 | ScreenPtr ephyrCursorScreen; /* screen containing the cursor */ | |
801 | ||
802 | static void | |
803 | ephyrWarpCursor(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 | ||
812 | miPointerScreenFuncRec 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 | */ | |
833 | static void | |
834 | ephyrExposePairedWindow(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(®); | |
846 | RegionCopy(®, &pair->local->clipList); | |
847 | screen->WindowExposures(pair->local, ®, NullRegion); | |
848 | RegionUninit(®); | |
849 | } | |
850 | #endif /* XF86DRI */ | |
851 | ||
852 | static KdScreenInfo * | |
853 | screen_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 | ||
873 | static void | |
874 | ephyrProcessErrorEvent(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 | ||
889 | static void | |
890 | ephyrProcessExpose(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 | ||
921 | static void | |
922 | ephyrProcessMouseMotion(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 | ||
973 | static void | |
974 | ephyrProcessButtonPress(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 | ||
994 | static void | |
995 | ephyrProcessButtonRelease(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 | ||
1011 | static void | |
1012 | ephyrProcessKeyPress(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 | ||
1025 | static void | |
1026 | ephyrProcessKeyRelease(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 | ||
1107 | static void | |
1108 | ephyrProcessConfigureNotify(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 | ||
1125 | void | |
1126 | ephyrPoll(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 | ||
1183 | void | |
1184 | ephyrCardFini(KdCardInfo * card) | |
1185 | { | |
1186 | EphyrPriv *priv = card->driver; | |
1187 | ||
1188 | free(priv); | |
1189 | } | |
1190 | ||
1191 | void | |
1192 | ephyrGetColors(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 | ||
1207 | void | |
1208 | ephyrPutColors(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 | ||
1233 | static Status | |
1234 | MouseInit(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 | ||
1255 | static Status | |
1256 | MouseEnable(KdPointerInfo * pi) | |
1257 | { | |
1258 | ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = TRUE; | |
1259 | return Success; | |
1260 | } | |
1261 | ||
1262 | static void | |
1263 | MouseDisable(KdPointerInfo * pi) | |
1264 | { | |
1265 | ((EphyrPointerPrivate *) pi->driverPrivate)->enabled = FALSE; | |
1266 | return; | |
1267 | } | |
1268 | ||
1269 | static void | |
1270 | MouseFini(KdPointerInfo * pi) | |
1271 | { | |
1272 | ephyrMouse = NULL; | |
1273 | return; | |
1274 | } | |
1275 | ||
1276 | KdPointerDriver EphyrMouseDriver = { | |
1277 | "ephyr", | |
1278 | MouseInit, | |
1279 | MouseEnable, | |
1280 | MouseDisable, | |
1281 | MouseFini, | |
1282 | NULL, | |
1283 | }; | |
1284 | ||
1285 | /* Keyboard */ | |
1286 | ||
1287 | static Status | |
1288 | EphyrKeyboardInit(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 | ||
1305 | static Status | |
1306 | EphyrKeyboardEnable(KdKeyboardInfo * ki) | |
1307 | { | |
1308 | ((EphyrKbdPrivate *) ki->driverPrivate)->enabled = TRUE; | |
1309 | ||
1310 | return Success; | |
1311 | } | |
1312 | ||
1313 | static void | |
1314 | EphyrKeyboardDisable(KdKeyboardInfo * ki) | |
1315 | { | |
1316 | ((EphyrKbdPrivate *) ki->driverPrivate)->enabled = FALSE; | |
1317 | } | |
1318 | ||
1319 | static void | |
1320 | EphyrKeyboardFini(KdKeyboardInfo * ki) | |
1321 | { | |
1322 | ephyrKbd = NULL; | |
1323 | return; | |
1324 | } | |
1325 | ||
1326 | static void | |
1327 | EphyrKeyboardLeds(KdKeyboardInfo * ki, int leds) | |
1328 | { | |
1329 | } | |
1330 | ||
1331 | static void | |
1332 | EphyrKeyboardBell(KdKeyboardInfo * ki, int volume, int frequency, int duration) | |
1333 | { | |
1334 | } | |
1335 | ||
1336 | KdKeyboardDriver EphyrKeyboardDriver = { | |
1337 | "ephyr", | |
1338 | EphyrKeyboardInit, | |
1339 | EphyrKeyboardEnable, | |
1340 | EphyrKeyboardLeds, | |
1341 | EphyrKeyboardBell, | |
1342 | EphyrKeyboardDisable, | |
1343 | EphyrKeyboardFini, | |
1344 | NULL, | |
1345 | }; |