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