Enable DRI2 based on Dodji Seketeli's DRI work
[xephyr-with-gl-acceleration:xephyr-with-gl-acceleration.git] / xserver / hw / kdrive / ephyr / hostx.c
1 /*
2  * Xephyr - A kdrive X server thats runs in a host X window.
3  *          Authored by Matthew Allum <mallum@o-hand.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 /*
31  * including some server headers (like kdrive-config.h)
32  * might define the macro _XSERVER64
33  * on 64 bits machines. That macro must _NOT_ be defined for Xlib
34  * client code, otherwise bad things happen.
35  * So let's undef that macro if necessary.
36  */
37 #ifdef _XSERVER64
38 #undef _XSERVER64
39 #endif
40
41
42 #include "hostx.h"
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <unistd.h>
47 #include <string.h>             /* for memset */
48 #include <time.h>
49
50 #include <sys/ipc.h>
51 #include <sys/shm.h>
52 #include <sys/time.h>
53
54 #include <X11/Xlib.h>
55 #include <X11/Xutil.h>
56 #include <X11/Xatom.h>
57 #include <X11/keysym.h>
58 #include <X11/extensions/XShm.h>
59 #include <X11/extensions/shape.h>
60 #if defined(XF86DRI) || defined(DRI2)
61 #include <GL/glx.h>
62 #endif /* XF86DRI */
63 #include "ephyrlog.h"
64
65 #ifdef XF86DRI
66 extern Bool XF86DRIQueryExtension (Display *dpy,
67                                    int *event_basep,
68                                    int *error_basep);
69 #endif
70
71 /*  
72  * All xlib calls go here, which gets built as its own .a .
73  * Mixing kdrive and xlib headers causes all sorts of types
74  * to get clobbered. 
75  */
76
77 struct EphyrHostScreen
78 {
79   Window          win;
80   Window          win_pre_existing;     /* Set via -parent option like xnest */
81   XImage         *ximg;
82   int             win_width, win_height;
83   int             server_depth;
84   unsigned char  *fb_data;      /* only used when host bpp != server bpp */
85   XShmSegmentInfo shminfo;
86
87   void           *info;   /* Pointer to the screen this is associated with */
88   int             mynum;  /* Screen number */
89 };
90
91 struct EphyrHostXVars
92 {
93   char           *server_dpy_name;
94   Display        *dpy;
95   int             screen;
96   Visual         *visual;
97   Window          winroot;
98   GC              gc;
99   int             depth;
100   Bool            use_host_cursor;
101   Bool            use_fullscreen;
102   Bool            have_shm;
103
104   int             n_screens;
105   struct EphyrHostScreen *screens;
106
107   long            damage_debug_msec;
108
109   unsigned long   cmap[256];
110 };
111
112 /* memset ( missing> ) instead of below  */
113 /*static EphyrHostXVars HostX = { "?", 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};*/
114 static EphyrHostXVars HostX;
115
116 static int            HostXWantDamageDebug = 0;
117
118 extern EphyrKeySyms   ephyrKeySyms;
119
120 extern int            monitorResolution;
121
122 char           *ephyrResName = NULL;
123 int             ephyrResNameFromCmd = 0;
124
125 static void
126 hostx_set_fullscreen_hint(void);
127
128 /* X Error traps */
129
130 static int trapped_error_code = 0;
131 static int (*old_error_handler) (Display *d, XErrorEvent *e);
132
133 #define host_depth_matches_server(_vars) (HostX.depth == (_vars)->server_depth)
134
135 static struct EphyrHostScreen *
136 host_screen_from_screen_info (EphyrScreenInfo *screen)
137 {
138   int i;
139
140   for (i = 0 ; i < HostX.n_screens ; i++)
141     {
142       if ( HostX.screens[i].info == screen)
143         {
144           return &HostX.screens[i];
145         }
146     }
147   return NULL;
148 }
149
150 static int
151 error_handler(Display     *display,
152               XErrorEvent *error)
153 {
154   trapped_error_code = error->error_code;
155   return 0;
156 }
157
158 static void
159 hostx_errors_trap(void)
160 {
161   trapped_error_code = 0;
162   old_error_handler = XSetErrorHandler(error_handler);
163 }
164
165 static int
166 hostx_errors_untrap(void)
167 {
168   XSetErrorHandler(old_error_handler);
169   return trapped_error_code;
170 }
171
172 int
173 hostx_want_screen_size (EphyrScreenInfo screen, int *width, int *height )
174 {
175   struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
176
177   if (host_screen &&
178        (host_screen->win_pre_existing != None ||
179          HostX.use_fullscreen == True))
180     {
181       *width  = host_screen->win_width;
182       *height = host_screen->win_height;
183       return 1;
184     }
185
186  return 0;
187 }
188
189 void
190 hostx_add_screen (EphyrScreenInfo screen,
191                   unsigned long win_id,
192                   int screen_num)
193 {
194   int index = HostX.n_screens;
195
196   HostX.n_screens += 1;
197   HostX.screens = realloc (HostX.screens,
198                            HostX.n_screens * sizeof(struct EphyrHostScreen));
199   memset (&HostX.screens[index], 0, sizeof (struct EphyrHostScreen));
200
201   HostX.screens[index].info       = screen;
202   HostX.screens[index].win_pre_existing = win_id;
203 }
204
205
206 void
207 hostx_set_display_name (char *name)
208 {
209   HostX.server_dpy_name = strdup (name);
210 }
211
212 void
213 hostx_set_screen_number(EphyrScreenInfo screen, int number)
214 {
215   struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
216   if (host_screen) {
217     host_screen->mynum = number;
218     hostx_set_win_title (host_screen->info, "") ;
219   }}
220
221 void
222 hostx_set_win_title (EphyrScreenInfo screen, char *extra_text)
223 {
224   struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
225 #define BUF_LEN 256
226   char buf[BUF_LEN+1];
227
228   if (!host_screen)
229     return;
230
231   memset (buf, 0, BUF_LEN+1) ;
232   snprintf (buf, BUF_LEN, "Xephyr on %s.%d %s", 
233             HostX.server_dpy_name, 
234             host_screen->mynum,
235             (extra_text != NULL) ? extra_text : "");
236
237   XStoreName (HostX.dpy, host_screen->win, buf);
238 }
239
240 int
241 hostx_want_host_cursor (void)
242 {
243   return HostX.use_host_cursor;
244 }
245
246 void
247 hostx_use_host_cursor (void)
248 {
249   HostX.use_host_cursor = True;
250 }
251
252 int
253 hostx_want_preexisting_window (EphyrScreenInfo screen)
254 {
255   struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
256
257   if (host_screen && host_screen->win_pre_existing)
258     {
259       return 1;
260     }
261   else
262     {
263     return 0;
264     }
265 }
266
267 void
268 hostx_use_fullscreen (void)
269 {
270   HostX.use_fullscreen = True;
271 }
272
273 int
274 hostx_want_fullscreen (void)
275 {
276   return HostX.use_fullscreen;
277 }
278
279 static void
280 hostx_set_fullscreen_hint (void)
281 {
282   Atom atom_WINDOW_STATE, atom_WINDOW_STATE_FULLSCREEN;
283   int index;
284
285   atom_WINDOW_STATE 
286     = XInternAtom(HostX.dpy, "_NET_WM_STATE", False);
287   atom_WINDOW_STATE_FULLSCREEN 
288     = XInternAtom(HostX.dpy, "_NET_WM_STATE_FULLSCREEN",False);
289
290   for (index = 0 ; index < HostX.n_screens ; index++)
291     {
292       XChangeProperty (HostX.dpy, HostX.screens[index].win,
293                        atom_WINDOW_STATE, XA_ATOM, 32,
294                        PropModeReplace,
295                        (unsigned char *)&atom_WINDOW_STATE_FULLSCREEN, 1);
296     }
297 }
298
299
300 static void
301 hostx_toggle_damage_debug (void)
302 {
303   HostXWantDamageDebug ^= 1;
304 }
305
306 void
307 hostx_handle_signal (int signum)
308 {
309   hostx_toggle_damage_debug();
310   EPHYR_DBG ("Signal caught. Damage Debug:%i\n",
311               HostXWantDamageDebug);
312 }
313
314 void
315 hostx_use_resname (char *name, int fromcmd)
316 {
317   ephyrResName = name;
318   ephyrResNameFromCmd = fromcmd;
319 }
320
321 int
322 hostx_init (void)
323 {
324   XSetWindowAttributes  attr;
325   Cursor                empty_cursor;
326   Pixmap                cursor_pxm;
327   XColor                col;
328   int                   index;
329   char                  *tmpstr;
330   XClassHint            *class_hint;
331
332   attr.event_mask =
333     ButtonPressMask
334     |ButtonReleaseMask
335     |PointerMotionMask
336     |KeyPressMask
337     |KeyReleaseMask
338     |ExposureMask;
339
340   EPHYR_DBG("mark");
341
342   if ((HostX.dpy = XOpenDisplay(getenv("DISPLAY"))) == NULL)
343     {
344       fprintf(stderr, "\nXephyr cannot open host display. Is DISPLAY set?\n");
345       exit(1);
346     }
347
348   HostX.screen  = DefaultScreen(HostX.dpy);
349   HostX.winroot = RootWindow(HostX.dpy, HostX.screen);
350   HostX.gc      = XCreateGC(HostX.dpy, HostX.winroot, 0, NULL);
351   HostX.depth   = DefaultDepth(HostX.dpy, HostX.screen);
352   HostX.visual  = DefaultVisual(HostX.dpy, HostX.screen);
353
354   class_hint = XAllocClassHint();
355
356   for (index = 0 ; index < HostX.n_screens ; index++)
357     {
358       struct EphyrHostScreen *host_screen = &HostX.screens[index];
359
360       host_screen->server_depth = HostX.depth;
361       if (host_screen->win_pre_existing != None)
362         {
363           Status            result;
364           XWindowAttributes prewin_attr;
365
366           /* Get screen size from existing window */
367
368           hostx_errors_trap();
369
370           result = XGetWindowAttributes (HostX.dpy,
371                                          host_screen->win_pre_existing,
372                                          &prewin_attr);
373
374
375           if (hostx_errors_untrap() || !result)
376           {
377               fprintf (stderr, "\nXephyr -parent window' does not exist!\n");
378               exit (1);
379           }
380
381           host_screen->win_width  = prewin_attr.width;
382           host_screen->win_height = prewin_attr.height;
383
384           host_screen->win = XCreateWindow (HostX.dpy,
385                                             host_screen->win_pre_existing,
386                                             0,0,
387                                             host_screen->win_width,
388                                             host_screen->win_height,
389                                             0,
390                                             CopyFromParent,
391                                             CopyFromParent,
392                                             CopyFromParent,
393                                             CWEventMask,
394                                             &attr);
395         }
396       else
397         {
398           host_screen->win = XCreateWindow (HostX.dpy,
399                                             HostX.winroot,
400                                             0,0,100,100, /* will resize */
401                                             0,
402                                             CopyFromParent,
403                                             CopyFromParent,
404                                             CopyFromParent,
405                                             CWEventMask,
406                                             &attr);
407
408           hostx_set_win_title (host_screen->info,
409                                "(ctrl+shift grabs mouse and keyboard)");
410
411           if (HostX.use_fullscreen)
412             {
413               host_screen->win_width  = DisplayWidth(HostX.dpy, HostX.screen);
414               host_screen->win_height = DisplayHeight(HostX.dpy, HostX.screen);
415
416               hostx_set_fullscreen_hint();
417             }
418
419           if (class_hint) 
420             {
421               tmpstr = getenv("RESOURCE_NAME");
422               if (tmpstr && (!ephyrResNameFromCmd))
423                 ephyrResName = tmpstr;
424               class_hint->res_name = ephyrResName;
425               class_hint->res_class = "Xephyr";
426               XSetClassHint(hostx_get_display(), host_screen->win, class_hint);
427
428             }
429
430         }
431     }
432
433   if (class_hint)
434       XFree(class_hint);
435
436   XParseColor (HostX.dpy, DefaultColormap (HostX.dpy,HostX.screen),
437                "red", &col);
438   XAllocColor (HostX.dpy, DefaultColormap (HostX.dpy, HostX.screen),
439                &col);
440   XSetForeground (HostX.dpy, HostX.gc, col.pixel);
441
442   if (!hostx_want_host_cursor ())
443     {
444       /* Ditch the cursor, we provide our 'own' */
445       cursor_pxm = XCreatePixmap (HostX.dpy, HostX.winroot, 1, 1, 1);
446       memset (&col, 0, sizeof (col));
447       empty_cursor = XCreatePixmapCursor (HostX.dpy,
448                                           cursor_pxm, cursor_pxm, 
449                                           &col, &col, 1, 1);
450       for ( index = 0 ; index < HostX.n_screens ; index++ )
451         {
452           XDefineCursor (HostX.dpy,
453                          HostX.screens[index].win,
454                          empty_cursor);
455         }
456       XFreePixmap (HostX.dpy, cursor_pxm);
457     }
458
459   for (index = 0 ; index < HostX.n_screens ; index++)
460     {
461       HostX.screens[index].ximg   = NULL;
462     }
463   /* Try to get share memory ximages for a little bit more speed */
464
465   if (!XShmQueryExtension(HostX.dpy) || getenv("XEPHYR_NO_SHM"))
466     {
467       fprintf(stderr, "\nXephyr unable to use SHM XImages\n");
468       HostX.have_shm = False;
469     }
470   else
471     {
472       /* Really really check we have shm - better way ?*/
473       XShmSegmentInfo shminfo;
474
475         HostX.have_shm = True;
476
477         shminfo.shmid=shmget(IPC_PRIVATE, 1, IPC_CREAT|0777);
478         shminfo.shmaddr=shmat(shminfo.shmid,0,0);
479         shminfo.readOnly=True;
480
481         hostx_errors_trap();
482
483         XShmAttach(HostX.dpy, &shminfo);
484         XSync(HostX.dpy, False);
485
486         if (hostx_errors_untrap())
487           {
488             fprintf(stderr, "\nXephyr unable to use SHM XImages\n");
489             HostX.have_shm = False;
490           }
491
492         shmdt(shminfo.shmaddr);
493         shmctl(shminfo.shmid, IPC_RMID, 0);
494 }
495
496   XFlush(HostX.dpy);
497
498   /* Setup the pause time between paints when debugging updates */
499
500   HostX.damage_debug_msec = 20000; /* 1/50 th of a second */
501
502   if (getenv ("XEPHYR_PAUSE"))
503     {
504       HostX.damage_debug_msec = strtol (getenv ("XEPHYR_PAUSE"), NULL, 0);
505       EPHYR_DBG ("pause is %li\n", HostX.damage_debug_msec);
506     }
507
508   return 1;
509 }
510
511 int
512 hostx_get_depth (void)
513 {
514   return HostX.depth;
515 }
516
517 int
518 hostx_get_server_depth (EphyrScreenInfo screen)
519 {
520   struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
521
522   return (host_screen ? host_screen->server_depth : 0);
523 }
524
525 void
526 hostx_set_server_depth (EphyrScreenInfo screen, int depth)
527 {
528   struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
529
530   if (host_screen)
531     host_screen->server_depth = depth;
532 }
533
534 int
535 hostx_get_bpp (EphyrScreenInfo screen)
536 {
537   struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
538
539   if (!host_screen)
540     return 0;
541
542   if (host_depth_matches_server (host_screen))
543     return HostX.visual->bits_per_rgb;
544   else
545     return host_screen->server_depth; /*XXX correct ?*/
546 }
547
548 void
549 hostx_get_visual_masks (EphyrScreenInfo screen,
550                         CARD32 *rmsk,
551                         CARD32 *gmsk,
552                         CARD32 *bmsk)
553 {
554   struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
555
556   if (!host_screen)
557     return;
558
559   if (host_depth_matches_server(host_screen))
560     {
561       *rmsk = HostX.visual->red_mask;
562       *gmsk = HostX.visual->green_mask;
563       *bmsk = HostX.visual->blue_mask;
564     }
565   else if (host_screen->server_depth == 16)
566     {
567       /* Assume 16bpp 565 */
568       *rmsk = 0xf800;
569       *gmsk = 0x07e0;
570       *bmsk = 0x001f;
571     }
572   else
573     {
574       *rmsk = 0x0;
575       *gmsk = 0x0;
576       *bmsk = 0x0;
577     }
578 }
579
580 static int 
581 hostx_calculate_color_shift(unsigned long mask)
582 {
583     int shift = 1;
584     /* count # of bits in mask */
585     while (mask=(mask>>1)) shift++;
586     /* cmap entry is an unsigned char so adjust it by size of that */
587     shift = shift - sizeof(unsigned char) * 8;
588     if (shift < 0) shift = 0;
589     return shift;
590 }
591
592 void
593 hostx_set_cmap_entry(unsigned char idx,
594                      unsigned char r,
595                      unsigned char g,
596                      unsigned char b)
597 {
598 /* need to calculate the shifts for RGB because server could be BGR. */
599 /* XXX Not sure if this is correct for 8 on 16, but this works for 8 on 24.*/
600     static int rshift, bshift, gshift = 0;
601     static int first_time = 1;
602     if (first_time) {
603         first_time = 0;
604         rshift = hostx_calculate_color_shift(HostX.visual->red_mask);
605         gshift = hostx_calculate_color_shift(HostX.visual->green_mask);
606         bshift = hostx_calculate_color_shift(HostX.visual->blue_mask);
607     }
608     HostX.cmap[idx] = ((r << rshift) & HostX.visual->red_mask) |
609                       ((g << gshift) & HostX.visual->green_mask) |
610                       ((b << bshift) & HostX.visual->blue_mask);
611 }
612
613 /**
614  * hostx_screen_init creates the XImage that will contain the front buffer of
615  * the ephyr screen, and possibly offscreen memory.
616  *
617  * @param width width of the screen
618  * @param height height of the screen
619  * @param buffer_height  height of the rectangle to be allocated.
620  *
621  * hostx_screen_init() creates an XImage, using MIT-SHM if it's available.
622  * buffer_height can be used to create a larger offscreen buffer, which is used
623  * by fakexa for storing offscreen pixmap data.
624  */
625 void*
626 hostx_screen_init (EphyrScreenInfo screen,
627                    int width, int height,
628                    int buffer_height)
629 {
630   int         bitmap_pad;
631   Bool        shm_success = False;
632   XSizeHints *size_hints;
633
634   struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
635   if (!host_screen)
636     {
637       fprintf (stderr, "%s: Error in accessing hostx data\n", __func__ );
638       exit(1);
639     }
640
641   EPHYR_DBG ("host_screen=%p wxh=%dx%d, buffer_height=%d",
642              host_screen, width, height, buffer_height);
643
644   if (host_screen->ximg != NULL)
645     {
646       /* Free up the image data if previously used
647        * i.ie called by server reset
648        */
649
650       if (HostX.have_shm)
651         {
652           XShmDetach(HostX.dpy, &host_screen->shminfo);
653           XDestroyImage (host_screen->ximg);
654           shmdt(host_screen->shminfo.shmaddr);
655           shmctl(host_screen->shminfo.shmid, IPC_RMID, 0);
656         }
657       else
658         {
659           if (host_screen->ximg->data) 
660             {
661               free(host_screen->ximg->data);
662               host_screen->ximg->data = NULL;
663             } 
664
665           XDestroyImage(host_screen->ximg);
666         }
667     }
668
669   if (HostX.have_shm)
670     {
671       host_screen->ximg = XShmCreateImage (HostX.dpy, HostX.visual, HostX.depth,
672                                            ZPixmap, NULL, &host_screen->shminfo,
673                                            width, buffer_height );
674
675       host_screen->shminfo.shmid =
676                       shmget(IPC_PRIVATE,
677                              host_screen->ximg->bytes_per_line * buffer_height,
678                              IPC_CREAT|0777);
679       host_screen->ximg->data = shmat(host_screen->shminfo.shmid, 0, 0);
680       host_screen->shminfo.shmaddr = host_screen->ximg->data;
681
682       if (host_screen->ximg->data == (char *)-1)
683         {
684           EPHYR_DBG("Can't attach SHM Segment, falling back to plain XImages");
685           HostX.have_shm = False;
686           XDestroyImage(host_screen->ximg);
687           shmctl(host_screen->shminfo.shmid, IPC_RMID, 0);
688         }
689       else
690         {
691           EPHYR_DBG("SHM segment attached %p", host_screen->shminfo.shmaddr);
692           host_screen->shminfo.readOnly = False;
693           XShmAttach(HostX.dpy, &host_screen->shminfo);
694           shm_success = True;
695         }
696     }
697
698   if (!shm_success)
699     {
700       bitmap_pad = ( HostX.depth > 16 )? 32 : (( HostX.depth > 8 )? 16 : 8 );
701
702       EPHYR_DBG("Creating image %dx%d for screen host_screen=%p\n",
703                 width, buffer_height, host_screen );
704       host_screen->ximg = XCreateImage (HostX.dpy,
705                                         HostX.visual,
706                                         HostX.depth,
707                                         ZPixmap, 0, 0,
708                                         width,
709                                         buffer_height,
710                                         bitmap_pad,
711                                         0);
712
713       host_screen->ximg->data =
714               malloc (host_screen->ximg->bytes_per_line * buffer_height);
715     }
716
717   XResizeWindow (HostX.dpy, host_screen->win, width, height);
718
719   /* Ask the WM to keep our size static */
720   size_hints = XAllocSizeHints();
721   size_hints->max_width = size_hints->min_width = width;
722   size_hints->max_height = size_hints->min_height = height;
723   size_hints->flags = PMinSize|PMaxSize;
724   XSetWMNormalHints(HostX.dpy, host_screen->win, size_hints);
725   XFree(size_hints);
726
727   XMapWindow(HostX.dpy, host_screen->win);
728
729   XSync(HostX.dpy, False);
730
731   host_screen->win_width  = width;
732   host_screen->win_height = height;
733
734   if (host_depth_matches_server(host_screen))
735     {
736       EPHYR_DBG("Host matches server");
737       return host_screen->ximg->data;
738     }
739   else
740     {
741       EPHYR_DBG("server bpp %i", host_screen->server_depth>>3);
742       host_screen->fb_data = malloc(width*buffer_height*(host_screen->server_depth>>3));
743       return host_screen->fb_data;
744     }
745 }
746
747 static void hostx_paint_debug_rect (struct EphyrHostScreen *host_screen,
748                                     int x,     int y,
749                                     int width, int height);
750
751 void
752 hostx_paint_rect (EphyrScreenInfo screen,
753                   int sx,    int sy,
754                   int dx,    int dy,
755                   int width, int height)
756 {
757   struct EphyrHostScreen *host_screen = host_screen_from_screen_info (screen);
758
759   EPHYR_DBG ("painting in screen %d\n", host_screen->mynum) ;
760
761   /*
762    *  Copy the image data updated by the shadow layer
763    *  on to the window
764    */
765
766   if (HostXWantDamageDebug)
767     {
768       hostx_paint_debug_rect(host_screen, dx, dy, width, height);
769     }
770
771   /* 
772    * If the depth of the ephyr server is less than that of the host,
773    * the kdrive fb does not point to the ximage data but to a buffer
774    * ( fb_data ), we shift the various bits from this onto the XImage
775    * so they match the host.
776    *
777    * Note, This code is pretty new ( and simple ) so may break on 
778    *       endian issues, 32 bpp host etc. 
779    *       Not sure if 8bpp case is right either. 
780    *       ... and it will be slower than the matching depth case.
781    */
782
783   if (!host_depth_matches_server(host_screen))
784     {
785       int            x,y,idx, bytes_per_pixel = (host_screen->server_depth>>3);
786       unsigned char  r,g,b;
787       unsigned long  host_pixel;
788
789       EPHYR_DBG("Unmatched host depth host_screen=%p\n", host_screen);
790       for (y=sy; y<sy+height; y++)
791         for (x=sx; x<sx+width; x++)
792           {
793             idx = (host_screen->win_width*y*bytes_per_pixel)+(x*bytes_per_pixel);
794
795             switch (host_screen->server_depth)
796               {
797               case 16:
798                 {
799                   unsigned short pixel = *(unsigned short*)(host_screen->fb_data+idx);
800
801                   r = ((pixel & 0xf800) >> 8);
802                   g = ((pixel & 0x07e0) >> 3);
803                   b = ((pixel & 0x001f) << 3);
804
805                   host_pixel = (r << 16) | (g << 8) | (b);
806                   
807                   XPutPixel(host_screen->ximg, x, y, host_pixel);
808                   break;
809                 }
810               case 8:
811                 {
812                   unsigned char pixel = *(unsigned char*)(host_screen->fb_data+idx);
813                   XPutPixel(host_screen->ximg, x, y, HostX.cmap[pixel]);
814                   break;
815                 }
816               default:
817                 break;
818               }
819           }
820     }
821
822   if (HostX.have_shm)
823     {
824       XShmPutImage (HostX.dpy, host_screen->win,
825                     HostX.gc, host_screen->ximg,
826                     sx, sy, dx, dy, width, height, False);
827     }
828   else
829     {
830       XPutImage (HostX.dpy, host_screen->win, HostX.gc, host_screen->ximg, 
831                  sx, sy, dx, dy, width, height);
832     }
833
834   XSync (HostX.dpy, False);
835 }
836
837 static void
838 hostx_paint_debug_rect (struct EphyrHostScreen *host_screen,
839                         int x,     int y,
840                         int width, int height)
841 {
842   struct timespec tspec;
843
844   tspec.tv_sec  = HostX.damage_debug_msec / (1000000);
845   tspec.tv_nsec = (HostX.damage_debug_msec % 1000000) * 1000;
846
847   EPHYR_DBG("msec: %li tv_sec %li, tv_msec %li", 
848             HostX.damage_debug_msec, tspec.tv_sec, tspec.tv_nsec);
849
850   /* fprintf(stderr, "Xephyr updating: %i+%i %ix%i\n", x, y, width, height); */
851
852   XFillRectangle (HostX.dpy, host_screen->win, HostX.gc, x, y, width,height);
853   XSync (HostX.dpy, False);
854
855   /* nanosleep seems to work better than usleep for me... */
856   nanosleep(&tspec, NULL);
857 }
858
859 void
860 hostx_load_keymap(void)
861 {
862   XID             *keymap;
863   int              host_width, min_keycode, max_keycode, width;
864   int              i,j;
865
866   XDisplayKeycodes (HostX.dpy, &min_keycode, &max_keycode);
867
868   EPHYR_DBG ("min: %d, max: %d", min_keycode, max_keycode);
869
870   keymap = XGetKeyboardMapping (HostX.dpy,
871                                 min_keycode,
872                                 max_keycode - min_keycode + 1,
873                                 &host_width);
874
875   /* Try and copy the hosts keymap into our keymap to avoid loads
876    * of messing around.
877    *
878    * kdrive cannot can have more than 4 keysyms per keycode
879    * so we only copy at most the first 4 ( xorg has 6 per keycode, XVNC 2 )
880    */
881   width = (host_width > 4) ? 4 : host_width;
882
883   ephyrKeySyms.map = (CARD32 *)calloc(sizeof(CARD32),
884                                       (max_keycode - min_keycode + 1) *
885                                       width);
886   if (!ephyrKeySyms.map)
887         return;
888
889   for (i=0; i<(max_keycode - min_keycode+1); i++)
890     for (j=0; j<width; j++)
891       ephyrKeySyms.map[(i*width)+j] = (CARD32) keymap[(i*host_width) + j];
892
893   EPHYR_DBG("keymap width, host:%d kdrive:%d", host_width, width);
894
895   ephyrKeySyms.minKeyCode  = min_keycode;
896   ephyrKeySyms.maxKeyCode  = max_keycode;
897   ephyrKeySyms.mapWidth    = width;
898
899   XFree(keymap);
900 }
901
902 static struct EphyrHostScreen *
903 host_screen_from_window (Window w)
904 {
905   int index = 0;
906   struct EphyrHostScreen *result  = NULL;
907 #if 0
908   unsigned int num_children = 0;
909   Window root = None, parent = None, *children = NULL;
910 #endif
911
912   for (index = 0 ; index < HostX.n_screens ; index++)
913     {
914       if (HostX.screens[index].win == w)
915         {
916           result = &HostX.screens[index];
917           goto out;
918         }
919     }
920 #if 0
921   XQueryTree (hostx_get_display (), w, &root, &parent,
922               &children, &num_children);
923   if (parent == root || parent == None)
924       goto out;
925   result = host_screen_from_window (parent);
926 #endif
927
928 out:
929 #if 0
930   if (children)
931       {
932         XFree (children);
933         children = NULL;
934       }
935 #endif
936   return result;
937 }
938
939 int
940 hostx_get_event(EphyrHostXEvent *ev)
941 {
942   XEvent      xev;
943   static int  grabbed_screen = -1;
944
945   if (XPending(HostX.dpy))
946     {
947       XNextEvent(HostX.dpy, &xev);
948
949       switch (xev.type) 
950         {
951         case Expose:
952           /* Not so great event compression, but works ok */
953           while (XCheckTypedWindowEvent(HostX.dpy, xev.xexpose.window,
954                                         Expose, &xev));
955           {
956             struct EphyrHostScreen *host_screen =
957                 host_screen_from_window (xev.xexpose.window);
958             if (host_screen)
959               {
960                 hostx_paint_rect (host_screen->info, 0, 0, 0, 0,
961                                   host_screen->win_width,
962                                   host_screen->win_height);
963               }
964             else
965               {
966                 EPHYR_LOG_ERROR ("failed to get host screen\n");
967                 ev->type = EPHYR_EV_EXPOSE;
968                 ev->data.expose.window = xev.xexpose.window;
969                 return 1;
970               }
971           }
972           return 0;
973
974         case MotionNotify:
975           {
976             struct EphyrHostScreen *host_screen =
977                 host_screen_from_window (xev.xmotion.window);
978
979             ev->type = EPHYR_EV_MOUSE_MOTION;
980             ev->data.mouse_motion.x = xev.xmotion.x;
981             ev->data.mouse_motion.y = xev.xmotion.y;
982             ev->data.mouse_motion.window = xev.xmotion.window;
983             ev->data.mouse_motion.screen = (host_screen ? host_screen->mynum : -1);
984           }
985           return 1;
986
987         case ButtonPress:
988           ev->type = EPHYR_EV_MOUSE_PRESS;
989           ev->key_state = xev.xkey.state;
990           /* 
991            * This is a bit hacky. will break for button 5 ( defined as 0x10 )
992            * Check KD_BUTTON defines in kdrive.h 
993            */
994           ev->data.mouse_down.button_num = 1<<(xev.xbutton.button-1);
995           return 1;
996
997         case ButtonRelease:
998           ev->type = EPHYR_EV_MOUSE_RELEASE;
999           ev->key_state = xev.xkey.state;
1000           ev->data.mouse_up.button_num = 1<<(xev.xbutton.button-1);
1001           return 1;
1002
1003         case KeyPress:
1004           {
1005             ev->type = EPHYR_EV_KEY_PRESS;
1006             ev->key_state = xev.xkey.state;
1007             ev->data.key_down.scancode = xev.xkey.keycode;  
1008             return 1;
1009           }
1010         case KeyRelease:
1011
1012           if ((XKeycodeToKeysym(HostX.dpy,xev.xkey.keycode,0) == XK_Shift_L
1013                || XKeycodeToKeysym(HostX.dpy,xev.xkey.keycode,0) == XK_Shift_R)
1014               && (xev.xkey.state & ControlMask))
1015             {
1016               struct EphyrHostScreen *host_screen =
1017                   host_screen_from_window (xev.xexpose.window);
1018
1019               if (grabbed_screen != -1)
1020                 {
1021                   XUngrabKeyboard (HostX.dpy, CurrentTime);
1022                   XUngrabPointer (HostX.dpy, CurrentTime);
1023                   grabbed_screen = -1;
1024                   hostx_set_win_title (host_screen->info,
1025                                        "(ctrl+shift grabs mouse and keyboard)");
1026                 }
1027               else
1028                 {
1029                   /* Attempt grab */
1030                   if (XGrabKeyboard (HostX.dpy, host_screen->win, True, 
1031                                      GrabModeAsync, 
1032                                      GrabModeAsync, 
1033                                      CurrentTime) == 0)
1034                     {
1035                       if (XGrabPointer (HostX.dpy, host_screen->win, True, 
1036                                         NoEventMask, 
1037                                         GrabModeAsync, 
1038                                         GrabModeAsync, 
1039                                         host_screen->win, None, CurrentTime) == 0)
1040                         {
1041                           grabbed_screen = host_screen->mynum;
1042                           hostx_set_win_title
1043                                   (host_screen->info,
1044                                    "(ctrl+shift releases mouse and keyboard)");
1045                         }
1046                       else      /* Failed pointer grabm  ungrab keyboard */
1047                         XUngrabKeyboard (HostX.dpy, CurrentTime);
1048                     }
1049                 }
1050             }
1051
1052           /* Still send the release event even if above has happened
1053            * server will get confused with just an up event. 
1054            * Maybe it would be better to just block shift+ctrls getting to
1055            * kdrive all togeather. 
1056            */
1057           ev->type = EPHYR_EV_KEY_RELEASE;
1058           ev->key_state = xev.xkey.state;
1059           ev->data.key_up.scancode = xev.xkey.keycode;
1060           return 1;
1061
1062         default:
1063           break;
1064
1065         }
1066     }
1067   return 0;
1068 }
1069
1070 void*
1071 hostx_get_display(void)
1072 {
1073     return HostX.dpy ;
1074 }
1075
1076 int
1077 hostx_get_window (int a_screen_number)
1078 {
1079     if (a_screen_number < 0 || a_screen_number >= HostX.n_screens) {
1080         EPHYR_LOG_ERROR ("bad screen number:%d\n", a_screen_number) ;
1081         return 0;
1082     }
1083     return HostX.screens[a_screen_number].win ;
1084 }
1085
1086 int
1087 hostx_get_window_attributes (int a_window, EphyrHostWindowAttributes *a_attrs)
1088 {
1089     XWindowAttributes attrs ;
1090
1091     memset (&attrs, 0, sizeof (attrs)) ;
1092
1093     if (!XGetWindowAttributes (hostx_get_display (),
1094                                a_window,
1095                                &attrs)) {
1096         return FALSE ;
1097     }
1098     a_attrs->x = attrs.x ;
1099     a_attrs->y = attrs.y ;
1100     a_attrs->width = attrs.width ;
1101     a_attrs->height = attrs.height ;
1102     if (attrs.visual)
1103         a_attrs->visualid = attrs.visual->visualid ;
1104     return TRUE ;
1105 }
1106
1107 int
1108 hostx_get_extension_info (const char *a_ext_name,
1109                           int *a_major_opcode,
1110                           int *a_first_event,
1111                           int *a_first_error)
1112 {
1113     if (!a_ext_name || !a_major_opcode || !a_first_event || !a_first_error)
1114       return 0 ;
1115    if (!XQueryExtension (HostX.dpy,
1116                          a_ext_name,
1117                          a_major_opcode,
1118                          a_first_event,
1119                          a_first_error))
1120      {
1121        return 0 ;
1122      }
1123    return 1 ;
1124 }
1125
1126 int
1127 hostx_get_visuals_info (EphyrHostVisualInfo **a_visuals,
1128                         int *a_num_entries)
1129 {
1130     Display *dpy=hostx_get_display () ;
1131     Bool is_ok=False ;
1132     XVisualInfo templ, *visuals=NULL;
1133     EphyrHostVisualInfo *host_visuals=NULL ;
1134     int nb_items=0, i=0;
1135
1136     EPHYR_RETURN_VAL_IF_FAIL (a_visuals && a_num_entries && dpy,
1137                               False) ;
1138     EPHYR_LOG ("enter\n") ;
1139     memset (&templ, 0, sizeof (templ)) ;
1140     visuals = XGetVisualInfo (dpy, VisualNoMask, &templ, &nb_items) ;
1141     if (!visuals) {
1142         EPHYR_LOG_ERROR ("host does not advertise any visual\n") ;
1143         goto out ;
1144     }
1145     EPHYR_LOG ("host advertises %d visuals\n", nb_items) ;
1146     host_visuals = calloc (nb_items, sizeof (EphyrHostVisualInfo)) ;
1147     for (i=0; i<nb_items; i++) {
1148         host_visuals[i].visualid = visuals[i].visualid ;
1149         host_visuals[i].screen = visuals[i].screen ;
1150         host_visuals[i].depth = visuals[i].depth ;
1151         host_visuals[i].class = visuals[i].class ;
1152         host_visuals[i].red_mask = visuals[i].red_mask ;
1153         host_visuals[i].green_mask = visuals[i].green_mask ;
1154         host_visuals[i].blue_mask = visuals[i].blue_mask ;
1155         host_visuals[i].colormap_size = visuals[i].colormap_size ;
1156         host_visuals[i].bits_per_rgb = visuals[i].bits_per_rgb ;
1157     }
1158     *a_visuals = host_visuals ;
1159     *a_num_entries = nb_items;
1160     host_visuals=NULL;
1161
1162     is_ok = TRUE;
1163 out:
1164     if (visuals) {
1165         XFree (visuals) ;
1166         visuals = NULL;
1167     }
1168     if (host_visuals) {
1169         free (host_visuals) ;
1170         host_visuals = NULL;
1171     }
1172     EPHYR_LOG ("leave\n") ;
1173     return is_ok ;
1174
1175 }
1176
1177 int
1178 hostx_create_window (int a_screen_number,
1179                      EphyrBox *a_geometry,
1180                      int a_visual_id,
1181                      int *a_host_peer /*out parameter*/)
1182 {
1183     Bool is_ok=FALSE ;
1184     Display *dpy=hostx_get_display () ;
1185     XVisualInfo *visual_info=NULL, visual_info_templ;
1186     int visual_mask=VisualIDMask ;
1187     Window win=None ;
1188     int nb_visuals=0, winmask=0;
1189     XSetWindowAttributes attrs;
1190
1191     EPHYR_RETURN_VAL_IF_FAIL (dpy && a_geometry, FALSE) ;
1192
1193     EPHYR_LOG ("enter\n") ;
1194
1195      /*get visual*/
1196     memset (&visual_info, 0, sizeof (visual_info)) ;
1197     visual_info_templ.visualid = a_visual_id ;
1198     visual_info = XGetVisualInfo (dpy, visual_mask,
1199                                   &visual_info_templ,
1200                                   &nb_visuals) ;
1201     if (!visual_info) {
1202         EPHYR_LOG_ERROR ("argh, could not find a remote visual with id:%d\n",
1203                          a_visual_id) ;
1204         goto out ;
1205     }
1206     memset (&attrs, 0, sizeof (attrs)) ;
1207     attrs.colormap = XCreateColormap (dpy,
1208                                       RootWindow (dpy,
1209                                                   visual_info->screen),
1210                                       visual_info->visual,
1211                                       AllocNone) ;
1212     attrs.event_mask = ButtonPressMask
1213                        |ButtonReleaseMask
1214                        |PointerMotionMask
1215                        |KeyPressMask
1216                        |KeyReleaseMask
1217                        |ExposureMask;
1218     winmask = CWColormap|CWEventMask;
1219
1220     win = XCreateWindow (dpy, hostx_get_window (a_screen_number),
1221                          a_geometry->x, a_geometry->y,
1222                          a_geometry->width, a_geometry->height, 0,
1223                          visual_info->depth, CopyFromParent,
1224                          visual_info->visual, winmask, &attrs) ;
1225     if (win == None) {
1226         EPHYR_LOG_ERROR ("failed to create peer window\n") ;
1227         goto out ;
1228     }
1229     XFlush (dpy) ;
1230     XMapWindow (dpy, win) ;
1231     *a_host_peer = win ;
1232     is_ok = TRUE ;
1233 out:
1234     EPHYR_LOG ("leave\n") ;
1235     return is_ok ;
1236 }
1237
1238 int
1239 hostx_destroy_window (int a_win)
1240 {
1241     Display *dpy=hostx_get_display () ;
1242
1243     EPHYR_RETURN_VAL_IF_FAIL (dpy, FALSE) ;
1244     XDestroyWindow (dpy, a_win) ;
1245     XFlush (dpy) ;
1246     return TRUE ;
1247 }
1248
1249 int
1250 hostx_set_window_geometry (int a_win, EphyrBox *a_geo)
1251 {
1252     Display *dpy=hostx_get_display ();
1253
1254     EPHYR_RETURN_VAL_IF_FAIL (dpy && a_geo, FALSE) ;
1255
1256     EPHYR_LOG ("enter. x,y,w,h:(%d,%d,%d,%d)\n",
1257                a_geo->x, a_geo->y,
1258                a_geo->width, a_geo->height) ;
1259
1260     XMoveWindow (dpy, a_win, a_geo->x, a_geo->y) ;
1261     XResizeWindow (dpy, a_win, a_geo->width, a_geo->height) ;
1262     EPHYR_LOG ("leave\n") ;
1263     return TRUE;
1264 }
1265
1266 int
1267 hostx_set_window_bounding_rectangles (int a_window,
1268                                       EphyrRect *a_rects,
1269                                       int a_num_rects)
1270 {
1271     Bool is_ok=FALSE;
1272     Display *dpy=hostx_get_display () ;
1273     int i=0 ;
1274     XRectangle *rects=NULL ;
1275
1276     EPHYR_RETURN_VAL_IF_FAIL (dpy && a_rects, FALSE) ;
1277
1278     EPHYR_LOG ("enter. num rects:%d\n", a_num_rects) ;
1279
1280     rects = calloc (a_num_rects, sizeof (XRectangle)) ;
1281     for (i=0; i<a_num_rects; i++) {
1282         rects[i].x = a_rects[i].x1 ;
1283         rects[i].y = a_rects[i].y1 ;
1284         rects[i].width = abs (a_rects[i].x2 - a_rects[i].x1);
1285         rects[i].height = abs (a_rects[i].y2 - a_rects[i].y1) ;
1286         EPHYR_LOG ("borders clipped to rect[x:%d,y:%d,w:%d,h:%d]\n",
1287                    rects[i].x, rects[i].y,
1288                    rects[i].width, rects[i].height) ;
1289     }
1290     /*this aways returns 1*/
1291     XShapeCombineRectangles (dpy, a_window, ShapeBounding, 0, 0,
1292                              rects, a_num_rects, ShapeSet, YXBanded) ;
1293     is_ok = TRUE ;
1294
1295     if (rects) {
1296         free (rects) ;
1297         rects = NULL ;
1298     }
1299     EPHYR_LOG ("leave\n") ;
1300     return is_ok;
1301 }
1302
1303 int
1304 hostx_set_window_clipping_rectangles (int a_window,
1305                                       EphyrRect *a_rects,
1306                                       int a_num_rects)
1307 {
1308     Bool is_ok=FALSE;
1309     Display *dpy=hostx_get_display () ;
1310     int i=0 ;
1311     XRectangle *rects=NULL ;
1312
1313     EPHYR_RETURN_VAL_IF_FAIL (dpy && a_rects, FALSE) ;
1314
1315     EPHYR_LOG ("enter. num rects:%d\n", a_num_rects) ;
1316
1317     rects = calloc (a_num_rects, sizeof (XRectangle)) ;
1318     for (i=0; i<a_num_rects; i++) {
1319         rects[i].x = a_rects[i].x1 ;
1320         rects[i].y = a_rects[i].y1 ;
1321         rects[i].width = abs (a_rects[i].x2 - a_rects[i].x1);
1322         rects[i].height = abs (a_rects[i].y2 - a_rects[i].y1) ;
1323         EPHYR_LOG ("clipped to rect[x:%d,y:%d,w:%d,h:%d]\n",
1324                    rects[i].x, rects[i].y,
1325                    rects[i].width, rects[i].height) ;
1326     }
1327     /*this aways returns 1*/
1328     XShapeCombineRectangles (dpy, a_window, ShapeClip, 0, 0,
1329                              rects, a_num_rects, ShapeSet, YXBanded) ;
1330     is_ok = TRUE ;
1331
1332     if (rects) {
1333         free (rects) ;
1334         rects = NULL ;
1335     }
1336     EPHYR_LOG ("leave\n") ;
1337     return is_ok;
1338 }
1339
1340 int
1341 hostx_has_xshape (void)
1342 {
1343     int event_base=0, error_base=0 ;
1344     Display *dpy=hostx_get_display () ;
1345     if (!XShapeQueryExtension (dpy,
1346                                &event_base,
1347                                &error_base)) {
1348         return FALSE ;
1349     }
1350     return TRUE;
1351 }
1352
1353 #if defined(XF86DRI) || defined(DRI2)
1354 typedef struct {
1355     int is_valid ;
1356     int local_id ;
1357     int remote_id ;
1358 } ResourcePair ;
1359
1360 #define RESOURCE_PEERS_SIZE 1024*10
1361 static ResourcePair resource_peers[RESOURCE_PEERS_SIZE] ;
1362
1363
1364 int
1365 hostx_allocate_resource_id_peer (int a_local_resource_id,
1366                                  int *a_remote_resource_id)
1367 {
1368     int i=0 ;
1369     ResourcePair *peer=NULL ;
1370     Display *dpy=hostx_get_display ();
1371
1372     /*
1373      * first make sure a resource peer
1374      * does not exist already for
1375      * a_local_resource_id
1376      */
1377     for (i=0; i<RESOURCE_PEERS_SIZE; i++) {
1378         if (resource_peers[i].is_valid
1379             && resource_peers[i].local_id == a_local_resource_id) {
1380             peer = &resource_peers[i] ;
1381             break ;
1382         }
1383     }
1384     /*
1385      * find one free peer entry, an feed it with
1386      */
1387     if (!peer) {
1388         for (i=0; i<RESOURCE_PEERS_SIZE; i++) {
1389             if (!resource_peers[i].is_valid) {
1390                 peer = &resource_peers[i] ;
1391                 break ;
1392             }
1393         }
1394         if (peer) {
1395             peer->remote_id = XAllocID (dpy);
1396             peer->local_id = a_local_resource_id ;
1397             peer->is_valid = TRUE ;
1398         }
1399     }
1400     if (peer) {
1401         *a_remote_resource_id = peer->remote_id ;
1402         return TRUE ;
1403     }
1404     return FALSE ;
1405 }
1406
1407 int
1408 hostx_get_resource_id_peer (int a_local_resource_id,
1409                             int *a_remote_resource_id)
1410 {
1411     int i=0 ;
1412     ResourcePair *peer=NULL ;
1413     for (i=0; i<RESOURCE_PEERS_SIZE; i++) {
1414         if (resource_peers[i].is_valid
1415             && resource_peers[i].local_id == a_local_resource_id) {
1416             peer = &resource_peers[i] ;
1417             break ;
1418         }
1419     }
1420     if (peer) {
1421         *a_remote_resource_id = peer->remote_id ;
1422         return TRUE ;
1423     }
1424     return FALSE ;
1425 }
1426
1427 int
1428 hostx_has_glx (void)
1429 {
1430     Display *dpy=hostx_get_display () ;
1431     int event_base=0, error_base=0 ;
1432
1433     if (!glXQueryExtension (dpy, &event_base, &error_base)) {
1434         return FALSE ;
1435     }
1436     return TRUE ;
1437 }
1438
1439 #endif
1440
1441 #ifdef XF86DRI
1442 int
1443 hostx_has_dri (void)
1444 {
1445     int event_base=0, error_base=0 ;
1446     Display *dpy=hostx_get_display () ;
1447
1448     if (!dpy)
1449         return FALSE ;
1450
1451     if (!XF86DRIQueryExtension (dpy,
1452                                 &event_base,
1453                                 &error_base)) {
1454         return FALSE ;
1455     }
1456     return TRUE ;
1457 }
1458 #endif /* XF86DRI */
1459
1460 #ifdef DRI2
1461 int
1462 hostx_has_dri2 (void)
1463 {
1464     int event_base=0, error_base=0 ;
1465     Display *dpy=hostx_get_display () ;
1466
1467     if (!dpy)
1468         return FALSE ;
1469
1470     if (!DRI2QueryExtension (dpy,
1471                                 &event_base,
1472                                 &error_base)) {
1473         return FALSE ;
1474     }
1475     return TRUE ;
1476 }
1477 #endif