2 * Xephyr - A kdrive X server thats runs in a host X window.
3 * Authored by Matthew Allum <mallum@o-hand.com>
5 * Copyright © 2004 Nokia
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.
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.
27 #include <kdrive-config.h>
36 #include <string.h> /* for memset */
44 #include <X11/keysym.h>
46 #include <xcb/xproto.h>
47 #include <xcb/xcb_icccm.h>
48 #include <xcb/xcb_aux.h>
50 #include <xcb/xcb_image.h>
51 #include <xcb/shape.h>
52 #include <xcb/xcb_keysyms.h>
54 #include <xcb/xf86dri.h>
60 struct EphyrHostXVars
{
61 char *server_dpy_name
;
62 xcb_connection_t
*conn
;
64 xcb_visualtype_t
*visual
;
73 KdScreenInfo
**screens
;
75 long damage_debug_msec
;
77 unsigned long cmap
[256];
80 /* memset ( missing> ) instead of below */
81 /*static EphyrHostXVars HostX = { "?", 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};*/
82 static EphyrHostXVars HostX
;
84 static int HostXWantDamageDebug
= 0;
86 extern EphyrKeySyms ephyrKeySyms
;
88 extern int monitorResolution
;
90 extern Bool EphyrWantResize
;
92 char *ephyrResName
= NULL
;
93 int ephyrResNameFromCmd
= 0;
94 char *ephyrTitle
= NULL
;
97 hostx_set_fullscreen_hint(void);
99 #define host_depth_matches_server(_vars) (HostX.depth == (_vars)->server_depth)
102 hostx_want_screen_size(KdScreenInfo
*screen
, int *width
, int *height
)
104 EphyrScrPriv
*scrpriv
= screen
->driver
;
106 if (scrpriv
&& (scrpriv
->win_pre_existing
!= None
||
107 HostX
.use_fullscreen
== TRUE
)) {
108 *width
= scrpriv
->win_width
;
109 *height
= scrpriv
->win_height
;
117 hostx_add_screen(KdScreenInfo
*screen
, unsigned long win_id
, int screen_num
)
119 EphyrScrPriv
*scrpriv
= screen
->driver
;
120 int index
= HostX
.n_screens
;
122 HostX
.n_screens
+= 1;
123 HostX
.screens
= realloc(HostX
.screens
,
124 HostX
.n_screens
* sizeof(HostX
.screens
[0]));
125 HostX
.screens
[index
] = screen
;
127 scrpriv
->screen
= screen
;
128 scrpriv
->win_pre_existing
= win_id
;
132 hostx_set_display_name(char *name
)
134 HostX
.server_dpy_name
= strdup(name
);
138 hostx_set_screen_number(KdScreenInfo
*screen
, int number
)
140 EphyrScrPriv
*scrpriv
= screen
->driver
;
143 scrpriv
->mynum
= number
;
144 hostx_set_win_title(screen
, "");
149 hostx_set_win_title(KdScreenInfo
*screen
, const char *extra_text
)
151 EphyrScrPriv
*scrpriv
= screen
->driver
;
157 xcb_icccm_set_wm_name(HostX
.conn
,
165 char buf
[BUF_LEN
+ 1];
167 memset(buf
, 0, BUF_LEN
+ 1);
168 snprintf(buf
, BUF_LEN
, "Xephyr on %s.%d %s",
169 HostX
.server_dpy_name
,
170 scrpriv
->mynum
, (extra_text
!= NULL
) ? extra_text
: "");
172 xcb_icccm_set_wm_name(HostX
.conn
,
178 xcb_flush(HostX
.conn
);
183 hostx_want_host_cursor(void)
185 return !HostX
.use_sw_cursor
;
189 hostx_use_sw_cursor(void)
191 HostX
.use_sw_cursor
= TRUE
;
195 hostx_want_preexisting_window(KdScreenInfo
*screen
)
197 EphyrScrPriv
*scrpriv
= screen
->driver
;
199 if (scrpriv
&& scrpriv
->win_pre_existing
) {
208 hostx_use_fullscreen(void)
210 HostX
.use_fullscreen
= TRUE
;
214 hostx_want_fullscreen(void)
216 return HostX
.use_fullscreen
;
219 static xcb_intern_atom_cookie_t cookie_WINDOW_STATE
,
220 cookie_WINDOW_STATE_FULLSCREEN
;
223 hostx_set_fullscreen_hint(void)
225 xcb_atom_t atom_WINDOW_STATE
, atom_WINDOW_STATE_FULLSCREEN
;
227 xcb_intern_atom_reply_t
*reply
;
229 reply
= xcb_intern_atom_reply(HostX
.conn
, cookie_WINDOW_STATE
, NULL
);
230 atom_WINDOW_STATE
= reply
->atom
;
233 reply
= xcb_intern_atom_reply(HostX
.conn
, cookie_WINDOW_STATE_FULLSCREEN
,
235 atom_WINDOW_STATE_FULLSCREEN
= reply
->atom
;
238 for (index
= 0; index
< HostX
.n_screens
; index
++) {
239 EphyrScrPriv
*scrpriv
= HostX
.screens
[index
]->driver
;
240 xcb_change_property(HostX
.conn
,
247 &atom_WINDOW_STATE_FULLSCREEN
);
252 hostx_toggle_damage_debug(void)
254 HostXWantDamageDebug
^= 1;
258 hostx_handle_signal(int signum
)
260 hostx_toggle_damage_debug();
261 EPHYR_DBG("Signal caught. Damage Debug:%i\n", HostXWantDamageDebug
);
265 hostx_use_resname(char *name
, int fromcmd
)
268 ephyrResNameFromCmd
= fromcmd
;
272 hostx_set_title(char *title
)
278 /* prevent "Function has no return statement" error for x_io_error_handler */
279 #pragma does_not_return(exit)
286 xcb_cursor_t empty_cursor
;
287 xcb_pixmap_t cursor_pxm
;
288 uint16_t red
, green
, blue
;
294 const xcb_query_extension_reply_t
*shm_rep
;
295 xcb_screen_t
*xscreen
;
298 XCB_EVENT_MASK_BUTTON_PRESS
299 | XCB_EVENT_MASK_BUTTON_RELEASE
300 | XCB_EVENT_MASK_POINTER_MOTION
301 | XCB_EVENT_MASK_KEY_PRESS
302 | XCB_EVENT_MASK_KEY_RELEASE
303 | XCB_EVENT_MASK_EXPOSURE
304 | XCB_EVENT_MASK_STRUCTURE_NOTIFY
;
307 HostX
.conn
= xcb_connect(NULL
, &HostX
.screen
);
308 if (xcb_connection_has_error(HostX
.conn
)) {
309 fprintf(stderr
, "\nXephyr cannot open host display. Is DISPLAY set?\n");
313 xscreen
= xcb_aux_get_screen(HostX
.conn
, HostX
.screen
);
314 HostX
.winroot
= xscreen
->root
;
315 HostX
.gc
= xcb_generate_id(HostX
.conn
);
316 HostX
.depth
= xscreen
->root_depth
;
317 HostX
.visual
= xcb_aux_find_visual_by_id(xscreen
, xscreen
->root_visual
);
319 xcb_create_gc(HostX
.conn
, HostX
.gc
, HostX
.winroot
, 0, NULL
);
320 cookie_WINDOW_STATE
= xcb_intern_atom(HostX
.conn
, FALSE
,
321 strlen("_NET_WM_STATE"),
323 cookie_WINDOW_STATE_FULLSCREEN
=
324 xcb_intern_atom(HostX
.conn
, FALSE
,
325 strlen("_NET_WM_STATE_FULLSCREEN"),
326 "_NET_WM_STATE_FULLSCREEN");
328 for (index
= 0; index
< HostX
.n_screens
; index
++) {
329 KdScreenInfo
*screen
= HostX
.screens
[index
];
330 EphyrScrPriv
*scrpriv
= screen
->driver
;
332 scrpriv
->win
= xcb_generate_id(HostX
.conn
);
333 scrpriv
->server_depth
= HostX
.depth
;
334 scrpriv
->ximg
= NULL
;
336 if (scrpriv
->win_pre_existing
!= XCB_WINDOW_NONE
) {
337 xcb_get_geometry_reply_t
*prewin_geom
;
338 xcb_get_geometry_cookie_t cookie
;
339 xcb_generic_error_t
*e
= NULL
;
341 /* Get screen size from existing window */
342 cookie
= xcb_get_geometry(HostX
.conn
,
343 scrpriv
->win_pre_existing
);
344 prewin_geom
= xcb_get_geometry_reply(HostX
.conn
, cookie
, &e
);
349 fprintf (stderr
, "\nXephyr -parent window' does not exist!\n");
353 scrpriv
->win_width
= prewin_geom
->width
;
354 scrpriv
->win_height
= prewin_geom
->height
;
358 xcb_create_window(HostX
.conn
,
359 XCB_COPY_FROM_PARENT
,
361 scrpriv
->win_pre_existing
,
366 XCB_WINDOW_CLASS_COPY_FROM_PARENT
,
367 XCB_COPY_FROM_PARENT
,
372 xcb_create_window(HostX
.conn
,
373 XCB_COPY_FROM_PARENT
,
376 0,0,100,100, /* will resize */
378 XCB_WINDOW_CLASS_COPY_FROM_PARENT
,
379 XCB_COPY_FROM_PARENT
,
383 hostx_set_win_title(screen
,
384 "(ctrl+shift grabs mouse and keyboard)");
386 if (HostX
.use_fullscreen
) {
387 scrpriv
->win_width
= xscreen
->width_in_pixels
;
388 scrpriv
->win_height
= xscreen
->height_in_pixels
;
390 hostx_set_fullscreen_hint();
393 tmpstr
= getenv("RESOURCE_NAME");
394 if (tmpstr
&& (!ephyrResNameFromCmd
))
395 ephyrResName
= tmpstr
;
396 class_len
= strlen(ephyrResName
) + 1 + strlen("Xephyr") + 1;
397 class_hint
= malloc(class_len
);
399 strcpy(class_hint
, ephyrResName
);
400 strcpy(class_hint
+ strlen(ephyrResName
) + 1, "Xephyr");
401 xcb_change_property(HostX
.conn
,
402 XCB_PROP_MODE_REPLACE
,
414 if (!xcb_aux_parse_color("red", &red
, &green
, &blue
)) {
415 xcb_lookup_color_cookie_t c
=
416 xcb_lookup_color(HostX
.conn
, xscreen
->default_colormap
, 3, "red");
417 xcb_lookup_color_reply_t
*reply
=
418 xcb_lookup_color_reply(HostX
.conn
, c
, NULL
);
419 red
= reply
->exact_red
;
420 green
= reply
->exact_green
;
421 blue
= reply
->exact_blue
;
426 xcb_alloc_color_cookie_t c
= xcb_alloc_color(HostX
.conn
,
427 xscreen
->default_colormap
,
429 xcb_alloc_color_reply_t
*r
= xcb_alloc_color_reply(HostX
.conn
, c
, NULL
);
437 xcb_change_gc(HostX
.conn
, HostX
.gc
, XCB_GC_FOREGROUND
, &pixel
);
439 if (!hostx_want_host_cursor ()) {
440 CursorVisible
= TRUE
;
441 /* Ditch the cursor, we provide our 'own' */
442 cursor_pxm
= xcb_generate_id(HostX
.conn
);
443 xcb_create_pixmap(HostX
.conn
, 1, cursor_pxm
, HostX
.winroot
, 1, 1);
444 empty_cursor
= xcb_generate_id(HostX
.conn
);
445 xcb_create_cursor(HostX
.conn
,
447 cursor_pxm
, cursor_pxm
,
451 for (index
= 0; index
< HostX
.n_screens
; index
++) {
452 KdScreenInfo
*screen
= HostX
.screens
[index
];
453 EphyrScrPriv
*scrpriv
= screen
->driver
;
455 xcb_change_window_attributes(HostX
.conn
,
460 xcb_free_pixmap(HostX
.conn
, cursor_pxm
);
463 /* Try to get share memory ximages for a little bit more speed */
464 shm_rep
= xcb_get_extension_data(HostX
.conn
, &xcb_shm_id
);
465 if (!shm_rep
|| !shm_rep
->present
|| getenv("XEPHYR_NO_SHM")) {
466 fprintf(stderr
, "\nXephyr unable to use SHM XImages\n");
467 HostX
.have_shm
= FALSE
;
470 /* Really really check we have shm - better way ?*/
471 xcb_shm_segment_info_t shminfo
;
472 xcb_generic_error_t
*e
;
473 xcb_void_cookie_t cookie
;
474 xcb_shm_seg_t shmseg
;
476 HostX
.have_shm
= TRUE
;
478 shminfo
.shmid
= shmget(IPC_PRIVATE
, 1, IPC_CREAT
|0777);
479 shminfo
.shmaddr
= shmat(shminfo
.shmid
,0,0);
481 shmseg
= xcb_generate_id(HostX
.conn
);
482 cookie
= xcb_shm_attach_checked(HostX
.conn
, shmseg
, shminfo
.shmid
,
484 e
= xcb_request_check(HostX
.conn
, cookie
);
487 fprintf(stderr
, "\nXephyr unable to use SHM XImages\n");
488 HostX
.have_shm
= FALSE
;
492 shmdt(shminfo
.shmaddr
);
493 shmctl(shminfo
.shmid
, IPC_RMID
, 0);
496 xcb_flush(HostX
.conn
);
498 /* Setup the pause time between paints when debugging updates */
500 HostX
.damage_debug_msec
= 20000; /* 1/50 th of a second */
502 if (getenv("XEPHYR_PAUSE")) {
503 HostX
.damage_debug_msec
= strtol(getenv("XEPHYR_PAUSE"), NULL
, 0);
504 EPHYR_DBG("pause is %li\n", HostX
.damage_debug_msec
);
511 hostx_get_depth(void)
517 hostx_get_server_depth(KdScreenInfo
*screen
)
519 EphyrScrPriv
*scrpriv
= screen
->driver
;
521 return scrpriv
? scrpriv
->server_depth
: 0;
525 hostx_get_bpp(KdScreenInfo
*screen
)
527 EphyrScrPriv
*scrpriv
= screen
->driver
;
532 if (host_depth_matches_server(scrpriv
))
533 return HostX
.visual
->bits_per_rgb_value
;
535 return scrpriv
->server_depth
; /*XXX correct ?*/
539 hostx_get_visual_masks(KdScreenInfo
*screen
,
540 CARD32
*rmsk
, CARD32
*gmsk
, CARD32
*bmsk
)
542 EphyrScrPriv
*scrpriv
= screen
->driver
;
547 if (host_depth_matches_server(scrpriv
)) {
548 *rmsk
= HostX
.visual
->red_mask
;
549 *gmsk
= HostX
.visual
->green_mask
;
550 *bmsk
= HostX
.visual
->blue_mask
;
552 else if (scrpriv
->server_depth
== 16) {
553 /* Assume 16bpp 565 */
566 hostx_calculate_color_shift(unsigned long mask
)
570 /* count # of bits in mask */
571 while ((mask
= (mask
>> 1)))
573 /* cmap entry is an unsigned char so adjust it by size of that */
574 shift
= shift
- sizeof(unsigned char) * 8;
581 hostx_set_cmap_entry(unsigned char idx
,
582 unsigned char r
, unsigned char g
, unsigned char b
)
584 /* need to calculate the shifts for RGB because server could be BGR. */
585 /* XXX Not sure if this is correct for 8 on 16, but this works for 8 on 24.*/
586 static int rshift
, bshift
, gshift
= 0;
587 static int first_time
= 1;
591 rshift
= hostx_calculate_color_shift(HostX
.visual
->red_mask
);
592 gshift
= hostx_calculate_color_shift(HostX
.visual
->green_mask
);
593 bshift
= hostx_calculate_color_shift(HostX
.visual
->blue_mask
);
595 HostX
.cmap
[idx
] = ((r
<< rshift
) & HostX
.visual
->red_mask
) |
596 ((g
<< gshift
) & HostX
.visual
->green_mask
) |
597 ((b
<< bshift
) & HostX
.visual
->blue_mask
);
601 * hostx_screen_init creates the XImage that will contain the front buffer of
602 * the ephyr screen, and possibly offscreen memory.
604 * @param width width of the screen
605 * @param height height of the screen
606 * @param buffer_height height of the rectangle to be allocated.
608 * hostx_screen_init() creates an XImage, using MIT-SHM if it's available.
609 * buffer_height can be used to create a larger offscreen buffer, which is used
610 * by fakexa for storing offscreen pixmap data.
613 hostx_screen_init(KdScreenInfo
*screen
,
614 int width
, int height
, int buffer_height
,
615 int *bytes_per_line
, int *bits_per_pixel
)
617 EphyrScrPriv
*scrpriv
= screen
->driver
;
618 Bool shm_success
= FALSE
;
621 fprintf(stderr
, "%s: Error in accessing hostx data\n", __func__
);
625 EPHYR_DBG("host_screen=%p wxh=%dx%d, buffer_height=%d",
626 host_screen
, width
, height
, buffer_height
);
628 if (scrpriv
->ximg
!= NULL
) {
629 /* Free up the image data if previously used
630 * i.ie called by server reset
633 if (HostX
.have_shm
) {
634 xcb_shm_detach(HostX
.conn
, scrpriv
->shminfo
.shmseg
);
635 xcb_image_destroy(scrpriv
->ximg
);
636 shmdt(scrpriv
->shminfo
.shmaddr
);
637 shmctl(scrpriv
->shminfo
.shmid
, IPC_RMID
, 0);
640 free(scrpriv
->ximg
->data
);
641 scrpriv
->ximg
->data
= NULL
;
643 xcb_image_destroy(scrpriv
->ximg
);
647 if (HostX
.have_shm
) {
648 scrpriv
->ximg
= xcb_image_create_native(HostX
.conn
,
651 XCB_IMAGE_FORMAT_Z_PIXMAP
,
657 scrpriv
->shminfo
.shmid
=
659 scrpriv
->ximg
->stride
* buffer_height
,
661 scrpriv
->ximg
->data
= shmat(scrpriv
->shminfo
.shmid
, 0, 0);
662 scrpriv
->shminfo
.shmaddr
= scrpriv
->ximg
->data
;
664 if (scrpriv
->ximg
->data
== (uint8_t *) -1) {
666 ("Can't attach SHM Segment, falling back to plain XImages");
667 HostX
.have_shm
= FALSE
;
668 xcb_image_destroy (scrpriv
->ximg
);
669 shmctl(scrpriv
->shminfo
.shmid
, IPC_RMID
, 0);
672 EPHYR_DBG("SHM segment attached %p", scrpriv
->shminfo
.shmaddr
);
673 scrpriv
->shminfo
.shmseg
= xcb_generate_id(HostX
.conn
);
674 xcb_shm_attach(HostX
.conn
,
675 scrpriv
->shminfo
.shmseg
,
676 scrpriv
->shminfo
.shmid
,
683 EPHYR_DBG("Creating image %dx%d for screen scrpriv=%p\n",
684 width
, buffer_height
, scrpriv
);
685 scrpriv
->ximg
= xcb_image_create_native(HostX
.conn
,
688 XCB_IMAGE_FORMAT_Z_PIXMAP
,
694 scrpriv
->ximg
->data
=
695 malloc(scrpriv
->ximg
->stride
* buffer_height
);
699 uint32_t mask
= XCB_CONFIG_WINDOW_WIDTH
| XCB_CONFIG_WINDOW_HEIGHT
;
700 uint32_t values
[2] = {width
, height
};
701 xcb_configure_window(HostX
.conn
, scrpriv
->win
, mask
, values
);
704 if (scrpriv
->win_pre_existing
== None
&& !EphyrWantResize
) {
705 /* Ask the WM to keep our size static */
706 xcb_size_hints_t size_hints
= {0};
707 size_hints
.max_width
= size_hints
.min_width
= width
;
708 size_hints
.max_height
= size_hints
.min_height
= height
;
709 size_hints
.flags
= (XCB_ICCCM_SIZE_HINT_P_MIN_SIZE
|
710 XCB_ICCCM_SIZE_HINT_P_MAX_SIZE
);
711 xcb_icccm_set_wm_normal_hints(HostX
.conn
, scrpriv
->win
,
715 xcb_map_window(HostX
.conn
, scrpriv
->win
);
717 xcb_aux_sync(HostX
.conn
);
719 scrpriv
->win_width
= width
;
720 scrpriv
->win_height
= height
;
722 if (host_depth_matches_server(scrpriv
)) {
723 *bytes_per_line
= scrpriv
->ximg
->stride
;
724 *bits_per_pixel
= scrpriv
->ximg
->bpp
;
726 EPHYR_DBG("Host matches server");
727 return scrpriv
->ximg
->data
;
730 int bytes_per_pixel
= scrpriv
->server_depth
>> 3;
731 int stride
= (width
* bytes_per_pixel
+ 0x3) & ~0x3;
733 *bytes_per_line
= stride
;
734 *bits_per_pixel
= scrpriv
->server_depth
;
736 EPHYR_DBG("server bpp %i", bytes_per_pixel
);
737 scrpriv
->fb_data
= malloc (stride
* buffer_height
);
738 return scrpriv
->fb_data
;
742 static void hostx_paint_debug_rect(KdScreenInfo
*screen
,
743 int x
, int y
, int width
, int height
);
746 hostx_paint_rect(KdScreenInfo
*screen
,
747 int sx
, int sy
, int dx
, int dy
, int width
, int height
)
749 EphyrScrPriv
*scrpriv
= screen
->driver
;
751 EPHYR_DBG("painting in screen %d\n", scrpriv
->mynum
);
754 * Copy the image data updated by the shadow layer
758 if (HostXWantDamageDebug
) {
759 hostx_paint_debug_rect(screen
, dx
, dy
, width
, height
);
763 * If the depth of the ephyr server is less than that of the host,
764 * the kdrive fb does not point to the ximage data but to a buffer
765 * ( fb_data ), we shift the various bits from this onto the XImage
766 * so they match the host.
768 * Note, This code is pretty new ( and simple ) so may break on
769 * endian issues, 32 bpp host etc.
770 * Not sure if 8bpp case is right either.
771 * ... and it will be slower than the matching depth case.
774 if (!host_depth_matches_server(scrpriv
)) {
775 int x
, y
, idx
, bytes_per_pixel
= (scrpriv
->server_depth
>> 3);
776 int stride
= (scrpriv
->win_width
* bytes_per_pixel
+ 0x3) & ~0x3;
777 unsigned char r
, g
, b
;
778 unsigned long host_pixel
;
780 EPHYR_DBG("Unmatched host depth scrpriv=%p\n", scrpriv
);
781 for (y
= sy
; y
< sy
+ height
; y
++)
782 for (x
= sx
; x
< sx
+ width
; x
++) {
783 idx
= y
* stride
+ x
* bytes_per_pixel
;
785 switch (scrpriv
->server_depth
) {
788 unsigned short pixel
=
789 *(unsigned short *) (scrpriv
->fb_data
+ idx
);
791 r
= ((pixel
& 0xf800) >> 8);
792 g
= ((pixel
& 0x07e0) >> 3);
793 b
= ((pixel
& 0x001f) << 3);
795 host_pixel
= (r
<< 16) | (g
<< 8) | (b
);
797 xcb_image_put_pixel(scrpriv
->ximg
, x
, y
, host_pixel
);
802 unsigned char pixel
=
803 *(unsigned char *) (scrpriv
->fb_data
+ idx
);
804 xcb_image_put_pixel(scrpriv
->ximg
, x
, y
,
814 if (HostX
.have_shm
) {
815 xcb_image_shm_put(HostX
.conn
, scrpriv
->win
,
816 HostX
.gc
, scrpriv
->ximg
,
818 sx
, sy
, dx
, dy
, width
, height
, FALSE
);
821 xcb_image_put(HostX
.conn
, scrpriv
->win
, HostX
.gc
, scrpriv
->ximg
,
825 xcb_aux_sync(HostX
.conn
);
829 hostx_paint_debug_rect(KdScreenInfo
*screen
,
830 int x
, int y
, int width
, int height
)
832 EphyrScrPriv
*scrpriv
= screen
->driver
;
833 struct timespec tspec
;
834 xcb_rectangle_t rect
= { .x
= x
, .y
= y
, .width
= width
, .height
= height
};
835 xcb_void_cookie_t cookie
;
836 xcb_generic_error_t
*e
;
838 tspec
.tv_sec
= HostX
.damage_debug_msec
/ (1000000);
839 tspec
.tv_nsec
= (HostX
.damage_debug_msec
% 1000000) * 1000;
841 EPHYR_DBG("msec: %li tv_sec %li, tv_msec %li",
842 HostX
.damage_debug_msec
, tspec
.tv_sec
, tspec
.tv_nsec
);
844 /* fprintf(stderr, "Xephyr updating: %i+%i %ix%i\n", x, y, width, height); */
846 cookie
= xcb_poly_fill_rectangle_checked(HostX
.conn
, scrpriv
->win
,
848 e
= xcb_request_check(HostX
.conn
, cookie
);
851 /* nanosleep seems to work better than usleep for me... */
852 nanosleep(&tspec
, NULL
);
856 hostx_load_keymap(void)
858 int min_keycode
, max_keycode
;
860 min_keycode
= xcb_get_setup(HostX
.conn
)->min_keycode
;
861 max_keycode
= xcb_get_setup(HostX
.conn
)->max_keycode
;
863 EPHYR_DBG("min: %d, max: %d", min_keycode
, max_keycode
);
865 ephyrKeySyms
.minKeyCode
= min_keycode
;
866 ephyrKeySyms
.maxKeyCode
= max_keycode
;
870 hostx_get_xcbconn(void)
876 hostx_get_screen(void)
882 hostx_get_window(int a_screen_number
)
884 EphyrScrPriv
*scrpriv
;
885 if (a_screen_number
< 0 || a_screen_number
>= HostX
.n_screens
) {
886 EPHYR_LOG_ERROR("bad screen number:%d\n", a_screen_number
);
889 scrpriv
= HostX
.screens
[a_screen_number
]->driver
;
894 hostx_get_window_attributes(int a_window
, EphyrHostWindowAttributes
* a_attrs
)
896 xcb_get_geometry_cookie_t geom_cookie
;
897 xcb_get_window_attributes_cookie_t attr_cookie
;
898 xcb_get_geometry_reply_t
*geom_reply
;
899 xcb_get_window_attributes_reply_t
*attr_reply
;
901 geom_cookie
= xcb_get_geometry(HostX
.conn
, a_window
);
902 attr_cookie
= xcb_get_window_attributes(HostX
.conn
, a_window
);
903 geom_reply
= xcb_get_geometry_reply(HostX
.conn
, geom_cookie
, NULL
);
904 attr_reply
= xcb_get_window_attributes_reply(HostX
.conn
, attr_cookie
, NULL
);
906 a_attrs
->x
= geom_reply
->x
;
907 a_attrs
->y
= geom_reply
->y
;
908 a_attrs
->width
= geom_reply
->width
;
909 a_attrs
->height
= geom_reply
->height
;
910 a_attrs
->visualid
= attr_reply
->visual
;
918 hostx_get_visuals_info(EphyrHostVisualInfo
** a_visuals
, int *a_num_entries
)
921 EphyrHostVisualInfo
*host_visuals
= NULL
;
922 int nb_items
= 0, i
= 0, screen_num
;
923 xcb_screen_iterator_t screens
;
924 xcb_depth_iterator_t depths
;
926 EPHYR_RETURN_VAL_IF_FAIL(a_visuals
&& a_num_entries
, FALSE
);
927 EPHYR_LOG("enter\n");
929 screens
= xcb_setup_roots_iterator(xcb_get_setup(HostX
.conn
));
930 for (screen_num
= 0; screens
.rem
; screen_num
++, xcb_screen_next(&screens
)) {
931 depths
= xcb_screen_allowed_depths_iterator(screens
.data
);
932 for (; depths
.rem
; xcb_depth_next(&depths
)) {
933 xcb_visualtype_t
*visuals
= xcb_depth_visuals(depths
.data
);
934 EphyrHostVisualInfo
*tmp_visuals
=
935 realloc(host_visuals
,
936 (nb_items
+ depths
.data
->visuals_len
)
937 * sizeof(EphyrHostVisualInfo
));
941 host_visuals
= tmp_visuals
;
942 for (i
= 0; i
< depths
.data
->visuals_len
; i
++) {
943 host_visuals
[nb_items
+ i
].visualid
= visuals
[i
].visual_id
;
944 host_visuals
[nb_items
+ i
].screen
= screen_num
;
945 host_visuals
[nb_items
+ i
].depth
= depths
.data
->depth
;
946 host_visuals
[nb_items
+ i
].class = visuals
[i
]._class
;
947 host_visuals
[nb_items
+ i
].red_mask
= visuals
[i
].red_mask
;
948 host_visuals
[nb_items
+ i
].green_mask
= visuals
[i
].green_mask
;
949 host_visuals
[nb_items
+ i
].blue_mask
= visuals
[i
].blue_mask
;
950 host_visuals
[nb_items
+ i
].colormap_size
= visuals
[i
].colormap_entries
;
951 host_visuals
[nb_items
+ i
].bits_per_rgb
= visuals
[i
].bits_per_rgb_value
;
953 nb_items
+= depths
.data
->visuals_len
;
957 EPHYR_LOG("host advertises %d visuals\n", nb_items
);
958 *a_visuals
= host_visuals
;
959 *a_num_entries
= nb_items
;
966 EPHYR_LOG("leave\n");
972 hostx_create_window(int a_screen_number
,
973 EphyrBox
* a_geometry
,
974 int a_visual_id
, int *a_host_peer
/*out parameter */ )
980 xcb_screen_t
*screen
= xcb_aux_get_screen(HostX
.conn
, hostx_get_screen());
981 xcb_visualtype_t
*visual
;
983 EphyrScrPriv
*scrpriv
= HostX
.screens
[a_screen_number
]->driver
;
985 EPHYR_RETURN_VAL_IF_FAIL(screen
&& a_geometry
, FALSE
);
987 EPHYR_LOG("enter\n");
989 visual
= xcb_aux_find_visual_by_id(screen
, a_visual_id
);
991 EPHYR_LOG_ERROR ("argh, could not find a remote visual with id:%d\n",
995 depth
= xcb_aux_get_depth_of_visual(screen
, a_visual_id
);
997 winmask
= XCB_CW_EVENT_MASK
| XCB_CW_COLORMAP
;
998 attrs
[0] = XCB_EVENT_MASK_BUTTON_PRESS
999 |XCB_EVENT_MASK_BUTTON_RELEASE
1000 |XCB_EVENT_MASK_POINTER_MOTION
1001 |XCB_EVENT_MASK_KEY_PRESS
1002 |XCB_EVENT_MASK_KEY_RELEASE
1003 |XCB_EVENT_MASK_EXPOSURE
;
1004 attrs
[1] = xcb_generate_id(HostX
.conn
);
1005 xcb_create_colormap(HostX
.conn
,
1006 XCB_COLORMAP_ALLOC_NONE
,
1008 hostx_get_window(a_screen_number
),
1011 win
= xcb_generate_id(HostX
.conn
);
1012 xcb_create_window(HostX
.conn
,
1015 hostx_get_window (a_screen_number
),
1016 a_geometry
->x
, a_geometry
->y
,
1017 a_geometry
->width
, a_geometry
->height
, 0,
1018 XCB_WINDOW_CLASS_COPY_FROM_PARENT
,
1019 a_visual_id
, winmask
, attrs
);
1021 if (scrpriv
->peer_win
== XCB_NONE
) {
1022 scrpriv
->peer_win
= win
;
1025 EPHYR_LOG_ERROR("multiple peer windows created for same screen\n");
1027 xcb_flush(HostX
.conn
);
1028 xcb_map_window(HostX
.conn
, win
);
1032 EPHYR_LOG("leave\n");
1037 hostx_destroy_window(int a_win
)
1039 xcb_destroy_window(HostX
.conn
, a_win
);
1040 xcb_flush(HostX
.conn
);
1045 hostx_set_window_geometry(int a_win
, EphyrBox
* a_geo
)
1047 uint32_t mask
= XCB_CONFIG_WINDOW_X
1048 | XCB_CONFIG_WINDOW_Y
1049 | XCB_CONFIG_WINDOW_WIDTH
1050 | XCB_CONFIG_WINDOW_HEIGHT
;
1053 EPHYR_RETURN_VAL_IF_FAIL(a_geo
, FALSE
);
1055 EPHYR_LOG("enter. x,y,w,h:(%d,%d,%d,%d)\n",
1056 a_geo
->x
, a_geo
->y
, a_geo
->width
, a_geo
->height
);
1058 values
[0] = a_geo
->x
;
1059 values
[1] = a_geo
->y
;
1060 values
[2] = a_geo
->width
;
1061 values
[3] = a_geo
->height
;
1062 xcb_configure_window(HostX
.conn
, a_win
, mask
, values
);
1064 EPHYR_LOG("leave\n");
1069 hostx_set_window_bounding_rectangles(int a_window
,
1070 EphyrRect
* a_rects
, int a_num_rects
)
1074 xcb_rectangle_t
*rects
= NULL
;
1076 EPHYR_RETURN_VAL_IF_FAIL(a_rects
, FALSE
);
1078 EPHYR_LOG("enter. num rects:%d\n", a_num_rects
);
1080 rects
= calloc(a_num_rects
, sizeof (xcb_rectangle_t
));
1083 for (i
= 0; i
< a_num_rects
; i
++) {
1084 rects
[i
].x
= a_rects
[i
].x1
;
1085 rects
[i
].y
= a_rects
[i
].y1
;
1086 rects
[i
].width
= abs(a_rects
[i
].x2
- a_rects
[i
].x1
);
1087 rects
[i
].height
= abs(a_rects
[i
].y2
- a_rects
[i
].y1
);
1088 EPHYR_LOG("borders clipped to rect[x:%d,y:%d,w:%d,h:%d]\n",
1089 rects
[i
].x
, rects
[i
].y
, rects
[i
].width
, rects
[i
].height
);
1091 xcb_shape_rectangles(HostX
.conn
,
1093 XCB_SHAPE_SK_BOUNDING
,
1094 XCB_CLIP_ORDERING_YX_BANDED
,
1104 EPHYR_LOG("leave\n");
1115 #define RESOURCE_PEERS_SIZE 1024*10
1116 static ResourcePair resource_peers
[RESOURCE_PEERS_SIZE
];
1119 hostx_allocate_resource_id_peer(int a_local_resource_id
,
1120 int *a_remote_resource_id
)
1123 ResourcePair
*peer
= NULL
;
1126 * first make sure a resource peer
1127 * does not exist already for
1128 * a_local_resource_id
1130 for (i
= 0; i
< RESOURCE_PEERS_SIZE
; i
++) {
1131 if (resource_peers
[i
].is_valid
1132 && resource_peers
[i
].local_id
== a_local_resource_id
) {
1133 peer
= &resource_peers
[i
];
1138 * find one free peer entry, an feed it with
1141 for (i
= 0; i
< RESOURCE_PEERS_SIZE
; i
++) {
1142 if (!resource_peers
[i
].is_valid
) {
1143 peer
= &resource_peers
[i
];
1148 peer
->remote_id
= xcb_generate_id(HostX
.conn
);
1149 peer
->local_id
= a_local_resource_id
;
1150 peer
->is_valid
= TRUE
;
1154 *a_remote_resource_id
= peer
->remote_id
;
1161 hostx_get_resource_id_peer(int a_local_resource_id
, int *a_remote_resource_id
)
1164 ResourcePair
*peer
= NULL
;
1166 for (i
= 0; i
< RESOURCE_PEERS_SIZE
; i
++) {
1167 if (resource_peers
[i
].is_valid
1168 && resource_peers
[i
].local_id
== a_local_resource_id
) {
1169 peer
= &resource_peers
[i
];
1174 *a_remote_resource_id
= peer
->remote_id
;
1180 #endif /* XF86DRI */