LCOV - code coverage report
Current view: top level - gdraw - gxdraw.c (source / functions) Hit Total Coverage
Test: FontForge coverage report 2017-08-04 01:21:11+02:00 (commit d35f7e4107a9e1db65cce47c468fcc914cecb8fd) Lines: 0 2479 0.0 %
Date: 2017-08-04 Functions: 0 165 0.0 %

          Line data    Source code
       1             : /* Copyright (C) 2000-2012 by George Williams */
       2             : /*
       3             :  * Redistribution and use in source and binary forms, with or without
       4             :  * modification, are permitted provided that the following conditions are met:
       5             : 
       6             :  * Redistributions of source code must retain the above copyright notice, this
       7             :  * list of conditions and the following disclaimer.
       8             : 
       9             :  * Redistributions in binary form must reproduce the above copyright notice,
      10             :  * this list of conditions and the following disclaimer in the documentation
      11             :  * and/or other materials provided with the distribution.
      12             : 
      13             :  * The name of the author may not be used to endorse or promote products
      14             :  * derived from this software without specific prior written permission.
      15             : 
      16             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
      17             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      18             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
      19             :  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      20             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      21             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      22             :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      23             :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      24             :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      25             :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26             :  */
      27             : 
      28             : #if defined(__MINGW32__)
      29             : #include <winsock2.h>
      30             : #include <windows.h>
      31             : #endif
      32             :  
      33             : #include "gxdrawP.h"
      34             : #include "gxcdrawP.h"
      35             : 
      36             : #include <stdlib.h>
      37             : #include <math.h>
      38             : 
      39             : #if !defined(__MINGW32__)
      40             : #include <unistd.h>               /* for timers & select */
      41             : #endif
      42             : #include <sys/types.h>            /* for timers & select */
      43             : #include <sys/time.h>             /* for timers & select */
      44             : #include <signal.h>               /* error handler */
      45             : #include <locale.h>               /* for setting the X locale properly */
      46             : 
      47             : #ifdef HAVE_PTHREAD_H
      48             : # ifndef __MINGW32__
      49             : #  include <sys/socket.h>
      50             : #  include <sys/un.h>
      51             : # endif
      52             : #endif
      53             : 
      54             : #include <ustring.h>
      55             : #include <utype.h>
      56             : #include "fontP.h"
      57             : #include <gresource.h>
      58             : 
      59             : enum cm_type { cmt_default=-1, cmt_current, cmt_copy, cmt_private };
      60             : 
      61             : void GDrawIErrorRun(const char *fmt,...);
      62             : void GDrawIError(const char *fmt,...);
      63             : 
      64             : 
      65             : #ifndef X_DISPLAY_MISSING
      66             : # include <X11/Xatom.h>
      67             : # include <X11/keysym.h>
      68             : # include <X11/cursorfont.h>
      69             : # include <X11/Xresource.h>
      70             : 
      71             : #define XKeysym_Mask    0x01000000
      72             : 
      73             : #define XKEYSYM_TOP     8364
      74             : extern int gdraw_xkeysym_2_unicode[];
      75             : 
      76             : 
      77             : extern int cmdlinearg_forceUIHidden;
      78             : 
      79             : static void GXDrawTransmitSelection(GXDisplay *gd,XEvent *event);
      80             : static void GXDrawClearSelData(GXDisplay *gd,enum selnames sel);
      81             : 
      82             : /* ************************************************************************** */
      83             : /* ******************************* Font Stuff ******************************* */
      84             : /* ************************************************************************** */
      85             : 
      86           0 : static void _GXDraw_InitFonts(GXDisplay *gxdisplay) {
      87           0 :     FState *fs = calloc(1,sizeof(FState));
      88             : 
      89             :     /* In inches, because that's how fonts are measured */
      90           0 :     gxdisplay->fontstate = fs;
      91           0 :     fs->res = gxdisplay->res;
      92           0 : }
      93             : 
      94             : /* ************************************************************************** */
      95             : /* ****************************** COLOR Stuff ******************************* */
      96             : /* ************************************************************************** */
      97             : 
      98             : #define DIV_BY_0x33(x) (((x)*1286)>>16)           /* Fast way to do x/0x33 */
      99             : #define RND_BY_0x33(x) (((x+0x19)*1286)>>16)
     100             : #define DIV_BY_0x11(x) (((x)*241)>>12)            /* Fast way to do x/0x11 */
     101             : #define RND_BY_0x11(x) (((x+8)*241)>>12)
     102             : 
     103           0 : static void _GXDraw_FindVisual(GXDisplay *gdisp) {
     104             :     /* In the old days before 24bit color was common, a 32 bit visual was */
     105             :     /* the standard way to go (extra 8 bits were ignored). Then came the */
     106             :     /* composite extension which supported alpha channels in images, and */
     107             :     /* we had to be careful what went into the extra byte, 0 doesn't work */
     108             :     static int oldvsearch[][2] = {{ 32, TrueColor },
     109             :                                 { 24, TrueColor },
     110             :                                 { 16, TrueColor },
     111             :                                 { 15, TrueColor },
     112             :                                 { 12, TrueColor },
     113             :                                 {0}};
     114             :     static int newvsearch[][2] = {{ 24, TrueColor },
     115             :                                 { 16, TrueColor },
     116             :                                 { 15, TrueColor },
     117             :                                 { 12, TrueColor },
     118             :                                 {0}};
     119             :     static int v2search[][2] = {{ 8, PseudoColor },
     120             :                                 { 8, GrayScale },
     121             :                                 { 1, GrayScale },
     122             :                                 { 1, StaticGray }};
     123           0 :     int (*vsearch)[2] = gdisp->supports_alpha_images || gdisp->supports_alpha_windows
     124           0 :             ? newvsearch : oldvsearch;
     125           0 :     Display *display = gdisp->display;
     126             :     XVisualInfo vinf, *ret;
     127             :     int pixel_size, vc, i, j, first;
     128             :     ScreenFormat *sf;
     129           0 :     int user=false, cnt;
     130             : 
     131           0 :     if ( gdisp->desired_depth!=-1 || gdisp->desired_vc!=-1 ) {
     132           0 :         vinf.depth = gdisp->desired_depth;
     133           0 :         vinf.class = gdisp->desired_vc;
     134           0 :         ret = XGetVisualInfo(display,
     135           0 :                 (gdisp->desired_depth==-1?0:VisualDepthMask )|
     136           0 :                 (gdisp->desired_vc==-1?0:VisualClassMask ),
     137             :                 &vinf, &cnt);
     138           0 :         if ( cnt>0 ) {
     139           0 :             for ( i=0; i<cnt; ++i )
     140           0 :                 if ( ret[i].visual==DefaultVisual(display,gdisp->screen))
     141           0 :             break;
     142           0 :             if ( i==cnt )
     143           0 :                 i=0;
     144           0 :             gdisp->visual = ret[i].visual;
     145           0 :             gdisp->depth = ret[i].depth;
     146           0 :             user = true;
     147           0 :             XFree(ret);
     148             :         } else
     149           0 :             fprintf( stderr, "Failed to find your desired visual structure\n" );
     150             :     }
     151             : 
     152             :     /* I'd like TrueColor if I can get it */
     153           0 :     if ( gdisp->visual == NULL ) {
     154           0 :         for ( i=0; vsearch[i][0]!=0 ; ++i ) {
     155           0 :             vinf.depth = vsearch[i][0];
     156           0 :             vinf.class = vsearch[i][1];
     157           0 :             ret = XGetVisualInfo(display,
     158           0 :                     (gdisp->desired_depth==-1?0:VisualDepthMask )|
     159           0 :                     (gdisp->desired_vc==-1?0:VisualClassMask ),
     160             :                     &vinf, &cnt);
     161           0 :             if ( cnt>0 ) {
     162           0 :                 for ( j=0; j<cnt; ++j )
     163           0 :                     if ( ret[j].visual==DefaultVisual(display,gdisp->screen))
     164           0 :                 break;
     165           0 :                 if ( j==cnt )
     166           0 :                     j=0;
     167           0 :                 gdisp->visual = ret[j].visual;
     168           0 :                 gdisp->depth = ret[j].depth;
     169           0 :                 user = true;
     170           0 :                 XFree(ret);
     171           0 :         break;
     172             :             }
     173             :         }
     174             :     }
     175           0 :     if ( gdisp->visual == NULL ) {
     176           0 :         gdisp->visual = DefaultVisual(display,gdisp->screen);
     177           0 :         gdisp->depth = DefaultDepth(display,gdisp->screen);
     178             :     }
     179             :     /* Failing TrueColor I'd like PseudoColor on color displays, and GreyScale*/
     180             :     /*  on monochrom displays */
     181           0 :     if ( !user ) {
     182           0 :         if ( gdisp->visual->class==DirectColor || gdisp->visual->class==StaticColor ) {
     183           0 :             if ( XMatchVisualInfo(display,gdisp->screen,8,PseudoColor,&vinf)) {
     184           0 :                 gdisp->visual = vinf.visual;
     185           0 :                 gdisp->depth = 8;
     186             :             }
     187           0 :         } else if ( gdisp->visual->class==GrayScale || gdisp->visual->class==StaticGray ) {
     188           0 :             if ( XMatchVisualInfo(display,gdisp->screen,8,GrayScale,&vinf)) {
     189           0 :                 gdisp->visual = vinf.visual;
     190           0 :                 gdisp->depth = 8;
     191             :             }
     192             :         }
     193             :     }
     194             : 
     195           0 :     for ( first = true; ; ) {
     196             :         /* I want not only the number of meaningful bits in a pixel (which is the */
     197             :         /*  depth) but also the number of bits in pixel when writing an image */
     198             :         /* I wish I knew how to do this without diving into hidden X structures */
     199           0 :         gdisp->bitmap_pad = gdisp->pixel_size = gdisp->depth;
     200           0 :         for ( i=0; i<((_XPrivDisplay) display)->nformats; ++i ) {
     201           0 :             sf = &((_XPrivDisplay) display)->pixmap_format[i];
     202           0 :             if ( sf->depth == gdisp->depth ) { 
     203           0 :                 gdisp->pixel_size = sf->bits_per_pixel;
     204           0 :                 gdisp->bitmap_pad = sf->scanline_pad;
     205           0 :         break;
     206             :             }
     207             :         }
     208             : 
     209           0 :         if ( gdisp->pixel_size==1 || gdisp->pixel_size==8 || gdisp->pixel_size==16 ||
     210           0 :                 gdisp->pixel_size==24 || gdisp->pixel_size==32 )
     211             :     break;      /* We like it */
     212           0 :         else if ( first ) {
     213             :             /* If I still don't have something I can work with, try for black&white */
     214           0 :             for ( i=0; i<sizeof(v2search)/(2*sizeof(int)); ++i ) {
     215           0 :                 if ( XMatchVisualInfo(display,gdisp->screen,v2search[i][0],v2search[i][1],&vinf)) {
     216           0 :                     gdisp->visual = vinf.visual;
     217           0 :                     gdisp->depth = vinf.depth;
     218           0 :             break;
     219             :                 }
     220             :             }
     221           0 :             first = false;
     222             :         } else
     223           0 :     break;
     224           0 :     }
     225             : 
     226           0 :     pixel_size = gdisp->pixel_size; vc = gdisp->visual->class;
     227           0 :     if ( pixel_size==1 || pixel_size==8 ||
     228           0 :             ((pixel_size==16 || pixel_size==24 || pixel_size==32) && vc==TrueColor))
     229             :         /* We can deal with it */;
     230           0 :     else if ( vc==TrueColor || ( vc==PseudoColor && pixel_size<8)) {
     231           0 :        fprintf( stderr, "%s will not work well with this visual.  Colored images will be displayed as bitmaps\n", GResourceProgramName );
     232             :     } else {
     233           0 :        fprintf( stderr, "%s will not work with this visual.  Restart your X server with a TrueColor\n", GResourceProgramName );
     234           0 :        fprintf( stderr, " visual (You do this on an SGI by adding an argument \"-class TrueColor\" to\n" );
     235           0 :        fprintf( stderr, " the command which starts up X, which is probably in /var/X11/xdm/Xservers.\n" );
     236           0 :        fprintf( stderr, " On a sun you add \"-cc 4\" to the server start line, probably found in\n" );
     237           0 :        fprintf( stderr, " /usr/lib/X11/xdm/Xservers).\n" );
     238           0 :        exit(1);
     239             :    }
     240             : 
     241           0 :     if ( gdisp->visual == DefaultVisual(display,gdisp->screen)) {
     242           0 :         gdisp->cmap = DefaultColormap(display,gdisp->screen);
     243           0 :         gdisp->default_visual = true;
     244             :     } else {
     245           0 :         gdisp->cmap = XCreateColormap(display,gdisp->root,gdisp->visual,
     246             :                 AllocNone);
     247           0 :         XInstallColormap(display,gdisp->cmap);
     248             :     }
     249           0 : }
     250             : 
     251           0 : static int _GXDraw_AllocColors(GXDisplay *gdisp,XColor *x_colors) {
     252             :     /* Try to insure that the standard colours we expect to use are available */
     253             :     /*  in the default colormap */
     254           0 :     Display *display = gdisp->display;
     255             :     XColor *acolour;
     256             :     static unsigned short rgb[][3]={
     257             :             {0x8000,0x8000,0x8000}, {0x4000,0x4000,0x4000},
     258             :             {0xc000,0xc000,0xc000},
     259             :             {0x1100,0x1100,0x1100}, {0x2200,0x2200,0x2200},
     260             :             /*{0x3300,0x3300,0x3300},*/ {0x5500,0x5500,0x5500},
     261             :             /*{0x6600,0x6600,0x6600},*/ {0x7700,0x7700,0x7700},
     262             :             {0xaa00,0xaa00,0xaa00}, {0xbb00,0xbb00,0xbb00},
     263             :             {0xdd00,0xdd00,0xdd00}, {0xee00,0xee00,0xee00},
     264             :             };
     265             :     int i, r,g,b;
     266             :     static int cube[] = { 0x00, 0x33, 0x66, 0x99, 0xcc, 0xff };
     267             : 
     268           0 :     acolour = x_colors;
     269             : 
     270           0 :     for(r = 5; r >= 0; --r) {
     271           0 :       for(g = 5; g >= 0; --g) {
     272           0 :         for(b = 5; b >= 0; --b) {
     273           0 :         acolour->red = (cube[r]<<8)|cube[r];
     274           0 :         acolour->green = (cube[g]<<8)|cube[g];
     275           0 :         acolour->blue = (cube[b]<<8)|cube[b];
     276           0 :         acolour->pixel = 0;
     277           0 :         acolour->flags = 7;
     278           0 :         if ( XAllocColor(display,gdisp->cmap,acolour))
     279           0 :             ++acolour;
     280             :     }}}
     281             : 
     282           0 :     for ( i=0; i<sizeof(rgb)/sizeof(rgb[0]); ++i ) {
     283           0 :         acolour->red = rgb[i][0];
     284           0 :         acolour->green = rgb[i][1];
     285           0 :         acolour->blue = rgb[i][2];
     286           0 :         if ( XAllocColor(display,gdisp->cmap,acolour))
     287           0 :             ++acolour;
     288             :     }
     289           0 : return( acolour-x_colors );
     290             : }
     291             : 
     292           0 : static void _GXDraw_AllocGreys(GXDisplay *gdisp) {
     293           0 :     Display *display = gdisp->display;
     294             :     XColor xcolour;
     295           0 :     int step = 255/((1<<gdisp->depth)-1), r;
     296             : 
     297           0 :     for(r = 0; r < 256; r+=step ) {
     298           0 :         xcolour.red = r<<8;
     299           0 :         xcolour.green = r<<8;
     300           0 :         xcolour.blue = r<<8;
     301           0 :         XAllocColor(display,gdisp->cmap,&xcolour);
     302             :     }
     303           0 : }
     304             : 
     305           0 : static int _GXDraw_CopyColors(GXDisplay *gdisp, XColor *x_colors, Colormap new) {
     306             :     int i;
     307             : 
     308           0 :     for ( i=0; i<(1<<gdisp->depth); ++i )
     309           0 :         x_colors[i].pixel = i;
     310           0 :     XQueryColors(gdisp->display,gdisp->cmap,x_colors,1<<gdisp->depth);
     311           0 :     XStoreColors(gdisp->display,new,x_colors,1<<gdisp->depth);
     312           0 :     gdisp->cmap = new;
     313           0 : return( 1<<gdisp->depth );
     314             : }
     315             : 
     316           0 : static int FindAllColors(GXDisplay *gdisp, XColor *x_colors) {
     317             :     int i;
     318             : 
     319           0 :     for ( i=0; i<(1<<gdisp->depth); ++i )
     320           0 :         x_colors[i].pixel = i;
     321           0 :     XQueryColors(gdisp->display,gdisp->cmap,x_colors,1<<gdisp->depth);
     322           0 : return( 1<<gdisp->depth );
     323             : }
     324             : 
     325           0 : static void InitTrueColor(GXDisplay *gdisp) {
     326           0 :     Visual *vis = gdisp->visual;
     327             :     int red_shift, green_shift, blue_shift;
     328             :     int red_bits_shift, blue_bits_shift, green_bits_shift;
     329             : 
     330             :     /* The SGI display is not RGB but BGR.  X says TrueColor maps are increasing */
     331           0 :     for ( red_shift=0; red_shift<24 && !(vis->red_mask&(1<<red_shift)); ++red_shift );
     332           0 :     for ( green_shift=0; green_shift<24 && !(vis->green_mask&(1<<green_shift)); ++green_shift );
     333           0 :     for ( blue_shift=0; blue_shift<24 && !(vis->blue_mask&(1<<blue_shift)); ++blue_shift );
     334           0 :     gdisp->cs.red_shift = red_shift;
     335           0 :     gdisp->cs.green_shift = green_shift;
     336           0 :     gdisp->cs.blue_shift = blue_shift;
     337             : 
     338           0 :     gdisp->cs.red_bits_mask = vis->red_mask>>red_shift;
     339           0 :     gdisp->cs.green_bits_mask = vis->green_mask>>green_shift;
     340           0 :     gdisp->cs.blue_bits_mask = vis->blue_mask>>blue_shift;
     341           0 :     for ( red_bits_shift=0; gdisp->cs.red_bits_mask&(1<<red_bits_shift) ;
     342           0 :             ++red_bits_shift );
     343           0 :     for ( green_bits_shift=0; gdisp->cs.green_bits_mask&(1<<green_bits_shift) ;
     344           0 :             ++green_bits_shift );
     345           0 :     for ( blue_bits_shift=0; gdisp->cs.blue_bits_mask&(1<<blue_bits_shift) ;
     346           0 :             ++blue_bits_shift );
     347           0 :     gdisp->cs.red_bits_shift = 24-red_bits_shift;
     348           0 :     gdisp->cs.green_bits_shift = 16-green_bits_shift;
     349           0 :     gdisp->cs.blue_bits_shift = 8-blue_bits_shift;
     350             : 
     351           0 :     gdisp->cs.alpha_bits = 0xffffffff&~(vis->red_mask|vis->green_mask|vis->blue_mask);
     352           0 : }
     353             : 
     354           0 : static void _GXDraw_InitCols(GXDisplay *gdisp) {
     355             :     int i;
     356             :     XColor x_colors[256];
     357             :     GClut clut;
     358             :     int x_color_max;
     359             :     int vclass, depth;
     360           0 :     int n=0;
     361           0 :     char **extlist = XListExtensions(gdisp->display,&n);
     362             : 
     363           0 :     for ( i=0; i<n; ++i ) {
     364           0 :         if ( strcasecmp(extlist[i],"Composite")==0 ) {        /* "Render"??? */
     365             : /* Silly me. I had assumed that writing an alpha channel image to a window*/
     366             : /*  would do overlay composition on what was in the window. Instead it */
     367             : /*  overwrites the window, and retains the alpha channel so that the */
     368             : /*  window becomes translucent, rather than the image. */
     369             : /* In otherwords, it is totally useless to me */
     370             :             /* gdisp->supports_alpha_images = true; */
     371           0 :             gdisp->supports_alpha_windows = true;
     372           0 :     break;
     373             :         }
     374             :     }
     375           0 :     if ( extlist!=NULL )
     376           0 :         XFreeExtensionList(extlist);
     377             : 
     378           0 :     _GXDraw_FindVisual(gdisp);
     379           0 :     if ( gdisp->depth!=32 && gdisp->supports_alpha_images )
     380           0 :         gdisp->supports_alpha_images = false;
     381             : 
     382           0 :     vclass = gdisp->visual->class;
     383           0 :     depth = gdisp->depth;
     384             : 
     385           0 :     if ( depth<=8 ) {
     386           0 :         memset(&clut,'\0',sizeof(clut));
     387           0 :         if ( vclass==StaticGray || vclass == GrayScale ) {
     388           0 :             _GXDraw_AllocGreys(gdisp);
     389           0 :             gdisp->cs.is_grey = clut.is_grey = true;
     390           0 :             x_color_max = FindAllColors(gdisp,x_colors);
     391           0 :         } else if ( gdisp->desired_cm==cmt_private ) {
     392           0 :             gdisp->cmap = XCreateColormap(gdisp->display,gdisp->root,
     393             :                     gdisp->visual,AllocNone);
     394           0 :             XInstallColormap(gdisp->display,gdisp->cmap);
     395           0 :             x_color_max = _GXDraw_AllocColors(gdisp,x_colors);
     396             :         } else {
     397           0 :             x_color_max = _GXDraw_AllocColors(gdisp,x_colors);
     398           0 :             if (( gdisp->desired_cm==cmt_default && x_color_max<30 ) ||
     399           0 :                     gdisp->desired_cm==cmt_copy ) {
     400           0 :                 x_color_max = _GXDraw_CopyColors(gdisp,x_colors,
     401             :                         XCreateColormap(gdisp->display,gdisp->root,
     402             :                                 gdisp->visual,AllocAll));
     403           0 :                 XInstallColormap(gdisp->display,gdisp->cmap);
     404             :             }
     405             :         }
     406           0 :         clut.clut_len = x_color_max;
     407           0 :         for ( i=0; i<x_color_max; ++i )
     408           0 :             clut.clut[x_colors[i].pixel] = COLOR_CREATE(x_colors[i].red>>8,x_colors[i].green>>8,x_colors[i].blue>>8);
     409           0 :         gdisp->cs.rev = GClutReverse(&clut,8);
     410           0 :     } else if ( vclass==TrueColor )
     411           0 :        InitTrueColor(gdisp);
     412           0 : }
     413             : 
     414           0 : unsigned long _GXDraw_GetScreenPixel(GXDisplay *gdisp, Color col) {
     415             : 
     416           0 :     if ( gdisp->depth==24 )
     417           0 : return( Pixel24(gdisp,col) );
     418           0 :     else if ( gdisp->depth==32 )
     419           0 : return( Pixel32(gdisp,col) );
     420           0 :     else if ( gdisp->depth>8 )
     421           0 : return( Pixel16(gdisp,col));
     422             : 
     423           0 : return( _GImage_GetIndexedPixel/*Precise*/(col, gdisp->cs.rev)->pixel );
     424             : }
     425             : 
     426             : /* ****************************** Error Handler ***************************** */
     427             : 
     428             : static char *XProtocolCodes[] = {
     429             :     "X_Undefined_0",
     430             :     "X_CreateWindow",
     431             :     "X_ChangeWindowAttributes",
     432             :     "X_GetWindowAttributes",
     433             :     "X_DestroyWindow",
     434             :     "X_DestroySubwindows",
     435             :     "X_ChangeSaveSet",
     436             :     "X_ReparentWindow",
     437             :     "X_MapWindow",
     438             :     "X_MapSubwindows",
     439             :     "X_UnmapWindow",
     440             :     "X_UnmapSubwindows",
     441             :     "X_ConfigureWindow",
     442             :     "X_CirculateWindow",
     443             :     "X_GetGeometry",
     444             :     "X_QueryTree",
     445             :     "X_InternAtom",
     446             :     "X_GetAtomName",
     447             :     "X_ChangeProperty",
     448             :     "X_DeleteProperty",
     449             :     "X_GetProperty",
     450             :     "X_ListProperties",
     451             :     "X_SetSelectionOwner",
     452             :     "X_GetSelectionOwner",
     453             :     "X_ConvertSelection",
     454             :     "X_SendEvent",
     455             :     "X_GrabPointer",
     456             :     "X_UngrabPointer",
     457             :     "X_GrabButton",
     458             :     "X_UngrabButton",
     459             :     "X_ChangeActivePointerGrab",
     460             :     "X_GrabKeyboard",
     461             :     "X_UngrabKeyboard",
     462             :     "X_GrabKey",
     463             :     "X_UngrabKey",
     464             :     "X_AllowEvents",
     465             :     "X_GrabServer",
     466             :     "X_UngrabServer",
     467             :     "X_QueryPointer",
     468             :     "X_GetMotionEvents",
     469             :     "X_TranslateCoords",
     470             :     "X_WarpPointer",
     471             :     "X_SetInputFocus",
     472             :     "X_GetInputFocus",
     473             :     "X_QueryKeymap",
     474             :     "X_OpenFont",
     475             :     "X_CloseFont",
     476             :     "X_QueryFont",
     477             :     "X_QueryTextExtents",
     478             :     "X_ListFonts",
     479             :     "X_ListFontsWithInfo",
     480             :     "X_SetFontPath",
     481             :     "X_GetFontPath",
     482             :     "X_CreatePixmap",
     483             :     "X_FreePixmap",
     484             :     "X_CreateGC",
     485             :     "X_ChangeGC",
     486             :     "X_CopyGC",
     487             :     "X_SetDashes",
     488             :     "X_SetClipRectangles",
     489             :     "X_FreeGC",
     490             :     "X_ClearArea",
     491             :     "X_CopyArea",
     492             :     "X_CopyPlane",
     493             :     "X_PolyPoint",
     494             :     "X_PolyLine",
     495             :     "X_PolySegment",
     496             :     "X_PolyRectangle",
     497             :     "X_PolyArc",
     498             :     "X_FillPoly",
     499             :     "X_PolyFillRectangle",
     500             :     "X_PolyFillArc",
     501             :     "X_PutImage",
     502             :     "X_GetImage",
     503             :     "X_PolyText8",
     504             :     "X_PolyText16",
     505             :     "X_ImageText8",
     506             :     "X_ImageText16",
     507             :     "X_CreateColormap",
     508             :     "X_FreeColormap",
     509             :     "X_CopyColormapAndFree",
     510             :     "X_InstallColormap",
     511             :     "X_UninstallColormap",
     512             :     "X_ListInstalledColormaps",
     513             :     "X_AllocColor",
     514             :     "X_AllocNamedColor",
     515             :     "X_AllocColorCells",
     516             :     "X_AllocColorPlanes",
     517             :     "X_FreeColors",
     518             :     "X_StoreColors",
     519             :     "X_StoreNamedColor",
     520             :     "X_QueryColors",
     521             :     "X_LookupColor",
     522             :     "X_CreateCursor",
     523             :     "X_CreateGlyphCursor",
     524             :     "X_FreeCursor",
     525             :     "X_RecolorCursor",
     526             :     "X_QueryBestSize",
     527             :     "X_QueryExtension",
     528             :     "X_ListExtensions",
     529             :     "X_ChangeKeyboardMapping",
     530             :     "X_GetKeyboardMapping",
     531             :     "X_ChangeKeyboardControl",
     532             :     "X_GetKeyboardControl",
     533             :     "X_Bell",
     534             :     "X_ChangePointerControl",
     535             :     "X_GetPointerControl",
     536             :     "X_SetScreenSaver",
     537             :     "X_GetScreenSaver",
     538             :     "X_ChangeHosts",
     539             :     "X_ListHosts",
     540             :     "X_SetAccessControl",
     541             :     "X_SetCloseDownMode",
     542             :     "X_KillClient",
     543             :     "X_RotateProperties",
     544             :     "X_ForceScreenSaver",
     545             :     "X_SetPointerMapping",
     546             :     "X_GetPointerMapping",
     547             :     "X_SetModifierMapping",
     548             :     "X_GetModifierMapping",
     549             :     "X_Undefined_120",
     550             :     "X_Undefined_121",
     551             :     "X_Undefined_122",
     552             :     "X_Undefined_123",
     553             :     "X_Undefined_124",
     554             :     "X_Undefined_125",
     555             :     "X_Undefined_126",
     556             :     "X_NoOperation"
     557             : };
     558             : 
     559             : static char *lastfontrequest;
     560             : 
     561           0 : static int myerrorhandler(Display *disp, XErrorEvent *err) {
     562             :     /* Under twm I get a bad match, under kde a bad window? */
     563             :     char buffer[200], *majorcode;
     564             : 
     565           0 :     if (err->request_code>0 && err->request_code<128)
     566           0 :         majorcode = XProtocolCodes[err->request_code];
     567             :     else
     568           0 :         majorcode = "";
     569           0 :     if ( err->request_code==45 && lastfontrequest!=NULL )
     570           0 :         fprintf( stderr, "Error attempting to load font:\n  %s\nThe X Server claimed the font existed, but when I asked for it,\nI got this error instead:\n\n", lastfontrequest );
     571           0 :     XGetErrorText(disp,err->error_code,buffer,sizeof(buffer));
     572           0 :     fprintf( stderr, "X Error of failed request: %s\n", buffer );
     573           0 :     fprintf( stderr, "  Major opcode of failed request:  %d.%d (%s)\n",
     574           0 :             err->request_code, err->minor_code, majorcode );
     575           0 :     fprintf( stderr, "  Serial number of failed request:  %ld\n", (long) err->serial );
     576           0 :     fprintf( stderr, "  Failed resource ID:  %x\n", (unsigned int) err->resourceid );
     577           0 :     raise(SIGABRT);     /* I want something that alerts the debugger, not a semi-successful exit */
     578           0 : return( 1 );
     579             : }
     580             : 
     581             : /* ************************************************************************** */
     582             : 
     583           0 : static void _GXDraw_InitAtoms( GXDisplay *gdisp) {
     584           0 :     Display *display = gdisp->display;
     585           0 :     gdisp->atoms.wm_del_window = XInternAtom(display,"WM_DELETE_WINDOW",False);
     586           0 :     gdisp->atoms.wm_protocols = XInternAtom(display,"WM_PROTOCOLS",False);
     587           0 :     gdisp->atoms.drag_and_drop = XInternAtom(display,"DRAG_AND_DROP",False);
     588           0 : }
     589             : 
     590             : static Cursor StdCursor[ct_user] = { 0 };
     591             : static int cursor_map[ct_user] = { 0,
     592             :         XC_left_ptr,            /* pointer */
     593             :         XC_right_ptr,           /* backpointer */
     594             :         XC_hand2,               /* hand */
     595             :         XC_question_arrow,      /* question */
     596             :         XC_tcross,              /* cross */
     597             :         XC_fleur,               /* 4way */
     598             :         XC_xterm,               /* text */
     599             :         XC_watch,               /* watch */
     600             :         XC_right_ptr };         /* drag and drop */
     601             : 
     602           0 : static Cursor _GXDraw_GetCursor( GXDisplay *gdisp, enum cursor_types ct ) {
     603           0 :     Display *display = gdisp->display;
     604             : 
     605           0 :     if ( ct>=ct_user )
     606           0 : return( ct-ct_user );
     607           0 :     else if ( ct==ct_default )
     608           0 : return( CopyFromParent );
     609           0 :     if ( StdCursor[ct]==0 ) {
     610             :         XColor fb[2];
     611           0 :         fb[0].red = COLOR_RED(gdisp->def_foreground)*0x101; fb[0].green = COLOR_GREEN(gdisp->def_foreground)*0x101; fb[0].blue = COLOR_BLUE(gdisp->def_foreground)*0x101;
     612           0 :         fb[1].red = COLOR_RED(gdisp->def_background)*0x101; fb[1].green = COLOR_GREEN(gdisp->def_background)*0x101; fb[1].blue = COLOR_BLUE(gdisp->def_background)*0x101;
     613           0 :         if ( ct==ct_invisible ) {
     614             :             static short zeros[16]={0};
     615           0 :             Pixmap temp = XCreatePixmapFromBitmapData(display,gdisp->root,
     616             :                 (char *) zeros,16,16,1,0,1);
     617           0 :             StdCursor[ct] = XCreatePixmapCursor(display,temp,temp,&fb[0],&fb[1],0,0);
     618           0 :             XFreePixmap(display,temp);
     619             :         } else {
     620           0 :             StdCursor[ct] = XCreateFontCursor(display,cursor_map[ct]);
     621             :             /*XRecolorCursor(display,StdCursor[ct],&fb[0],&fb[1]);*/
     622             :         }
     623             :     }
     624           0 : return( StdCursor[ct]);
     625             : }
     626             : 
     627             : /* ************************************************************************** */
     628             : /* ************************** Utility Routines ****************************** */
     629             : /* ************************************************************************** */
     630             : 
     631           0 : static void initParentissimus(GXDisplay *gdisp, Window wind) {
     632           0 :     Display *display = gdisp->display;
     633             :     Window par, *children, root;
     634             :     unsigned int junk,width,height; int sjunk;
     635             : 
     636             :     while (1) {
     637           0 :         XQueryTree(display,wind,&root,&par,&children,&junk);
     638           0 :         XFree(children);
     639           0 :         if ( par==root )
     640           0 :     break;
     641           0 :         wind = par;
     642           0 :     }
     643           0 :     XGetGeometry(display,wind,&root,&sjunk,&sjunk,&width,&height,
     644             :             &junk,&junk);
     645           0 :     if (( width>DisplayWidth(display,gdisp->screen) &&
     646           0 :             height>=DisplayHeight(display,gdisp->screen)) ||
     647           0 :         ( width>=DisplayWidth(display,gdisp->screen) &&
     648           0 :             height>DisplayHeight(display,gdisp->screen)) )
     649           0 :         gdisp->virtualRoot = wind;
     650             :     else
     651           0 :         gdisp->virtualRoot = root;
     652           0 : }
     653             : 
     654           0 : static int qterror(Display *disp, XErrorEvent *err) {
     655             :     /* under kde a bad window? */
     656           0 :     if ( err->error_code == BadMatch || err->error_code == BadWindow ) {
     657             :     } else {
     658           0 :         myerrorhandler(disp,err);
     659             :     }
     660           0 : return( 1 );
     661             : }
     662             : 
     663           0 : static Window GetParentissimus(GXWindow gw) {
     664           0 :     GXDisplay *gdisp = gw->display;
     665           0 :     Display *display = gdisp->display;
     666           0 :     Window par, *children, root, wind = gw->w;
     667             :     unsigned int junk;
     668             :     fd_set junkset;
     669             :     struct timeval tenthsec;
     670             : 
     671           0 :     if ( gw->parentissimus )
     672           0 : return( gw->parentissimus );
     673           0 :     if ( gdisp->virtualRoot==BadAlloc )        /* Check for vtwm */
     674           0 :         initParentissimus(gdisp,wind);
     675             : 
     676             :     /* For reasons quite obscure to me, XQueryTree gives a BadWindow error */
     677             :     /*  under kde and gnome if there is no pause in the loop. XQueryTree */
     678             :     /*  isn't even documented to fail, so it's all very strange */
     679           0 :     FD_ZERO(&junkset);
     680           0 :     tenthsec.tv_sec = 0;
     681           0 :     tenthsec.tv_usec = 100000;
     682             : 
     683           0 :     XSync(gdisp->display,false);
     684           0 :     GDrawProcessPendingEvents((GDisplay *) gdisp);
     685           0 :     XSetErrorHandler(/*gdisp->display,*/qterror);
     686             : 
     687             :     /* Find the top window, some window managers will add two layers of */
     688             :     /*  decoration windows, (some might add none), some will have a virtualRoot*/
     689             :     while (1) {
     690           0 :         if ( XQueryTree(display,wind,&root,&par,&children,&junk)==0 ) {
     691           0 :             XSetErrorHandler(/*gdisp->display,*/myerrorhandler);
     692           0 : return( gw->w );             /* How can it fail? It does though */
     693             :         }
     694           0 :         if (children)
     695           0 :             XFree(children);
     696           0 :         if ( par==root || par==gdisp->virtualRoot ) {
     697           0 :             gw->parentissimus = wind;
     698           0 :             XSetErrorHandler(/*gdisp->display,*/myerrorhandler);
     699           0 : return(wind);
     700             :         }
     701           0 :         wind = par;
     702           0 :         select(0,&junkset,&junkset,&junkset,&tenthsec);
     703           0 :     }
     704             : }
     705             : 
     706             : /* ************************************************************************** */
     707             : /* ************************** Control Routines ****************************** */
     708             : /* ************************************************************************** */
     709             : 
     710           0 : static void GXDrawInit(GDisplay *gdisp) {
     711           0 :     _GXDraw_InitCols( (GXDisplay *) gdisp);
     712           0 :     _GXDraw_InitAtoms( (GXDisplay *) gdisp);
     713           0 :     _GXDraw_InitFonts((GXDisplay *) gdisp);
     714           0 : }
     715             : 
     716           0 : static void GXDrawTerm(GDisplay *gdisp) {
     717           0 : }
     718             : 
     719           0 : static void *GXDrawNativeDisplay(GDisplay *gdisp) {
     720           0 : return( ((GXDisplay *) gdisp)->display );
     721             : }
     722             : 
     723           0 : static GGC *_GXDraw_NewGGC() {
     724           0 :     GGC *ggc = calloc(1,sizeof(GGC));
     725           0 :     ggc->clip.width = ggc->clip.height = 0x7fff;
     726           0 :     ggc->fg = 0;
     727           0 :     ggc->bg = 0xffffff;
     728           0 : return( ggc );
     729             : }
     730             : 
     731           0 : static void GXDrawSetDefaultIcon(GWindow icon) {
     732           0 :     GXDisplay *gdisp = (GXDisplay *) (icon->display);
     733             : 
     734           0 :     gdisp->default_icon = (GXWindow) icon;
     735           0 : }
     736             : 
     737           0 : static Window MakeIconWindow(GXDisplay *gdisp, GXWindow pixmap) {
     738             :     XSetWindowAttributes attrs;
     739           0 :     unsigned long wmask = 0;
     740             :     
     741           0 :     if ( !gdisp->default_visual ) {
     742           0 :         attrs.colormap = gdisp->cmap;
     743           0 :         wmask |= CWColormap;
     744             :     }
     745           0 :     wmask |= CWBackPixmap;
     746           0 :     attrs.background_pixmap = pixmap->w;
     747           0 : return( XCreateWindow(gdisp->display, gdisp->root,
     748           0 :             0, 0, pixmap->pos.width, pixmap->pos.height,
     749             :             0,
     750           0 :             gdisp->depth, InputOutput, gdisp->visual, wmask, &attrs));
     751             : }
     752             : 
     753             : #if 0
     754             : static void _GXDraw_DestroyWindow(GXDisplay *gdisp, GWindow input) {
     755             :   // TODO: Reconcile differences between this function (written from _GXDraw_CreateWindow)
     756             :   // with the actual function GXDrawDestroyWindow below.
     757             :   GXWindow inputc = (GXWindow)input;
     758             :   if (inputc->w != NULL) { 
     759             :     if (inputc->is_pixmap) {
     760             :       XFreePixmap(gdisp->display, inputc->w);
     761             :     } else {
     762             :       XDestroyWindow(gdisp->display, inputc->w);
     763             :     }
     764             :     inputc->w = NULL;
     765             :   }
     766             :   if (inputc->gc != NULL) { XFreeGC(gdisp->display, inputc->gc); inputc->gc = NULL; }
     767             :   free(input);
     768             : }
     769             : #endif // 0
     770             : 
     771           0 : static GWindow _GXDraw_CreateWindow(GXDisplay *gdisp, GXWindow gw, GRect *pos,
     772             :         int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs) {
     773             :     Window parent;
     774           0 :     Display *display = gdisp->display;
     775           0 :     GXWindow nw = calloc(1,sizeof(struct gxwindow));
     776             :     XSetWindowAttributes attrs;
     777             :     static GWindowAttrs temp = GWINDOWATTRS_EMPTY;
     778           0 :     unsigned long wmask = 0;
     779             :     XClassHint ch;
     780             :     char *pt;
     781             : 
     782           0 :     if ( gw==NULL )
     783           0 :         gw = gdisp->groot;
     784           0 :     parent = gw->w;
     785           0 :     if ( wattrs==NULL ) wattrs = &temp;
     786           0 :     if ( nw==NULL )
     787           0 : return( NULL );
     788           0 :     nw->ggc = _GXDraw_NewGGC();
     789           0 :     if ( nw->ggc==NULL ) {
     790           0 :         free(nw);
     791           0 : return( NULL );
     792             :     }
     793           0 :     nw->display = gdisp;
     794           0 :     nw->eh = eh;
     795           0 :     nw->parent = gw;
     796           0 :     nw->pos = *pos;
     797           0 :     nw->user_data = user_data;
     798             : 
     799           0 :     attrs.bit_gravity = NorthWestGravity;
     800           0 :     wmask |= CWBitGravity;
     801           0 :     if ( (wattrs->mask&wam_bordcol) && wattrs->border_color!=COLOR_UNKNOWN ) {
     802           0 :         attrs.border_pixel = _GXDraw_GetScreenPixel(gdisp,wattrs->border_color);
     803           0 :         wmask |= CWBorderPixel;
     804             :     }
     805           0 :     if ( !(wattrs->mask&wam_backcol) || wattrs->background_color==COLOR_DEFAULT )
     806           0 :         wattrs->background_color = gdisp->def_background;
     807           0 :     if ( wattrs->background_color != COLOR_UNKNOWN ) {
     808           0 :         attrs.background_pixel = _GXDraw_GetScreenPixel(gdisp,wattrs->background_color);
     809           0 :         wmask |= CWBackPixel;
     810             :     }
     811           0 :     nw->ggc->bg = wattrs->background_color;
     812           0 :     if ( (wattrs->mask&wam_cursor) && wattrs->cursor!=0 ) {
     813           0 :         attrs.cursor = _GXDraw_GetCursor(gdisp,wattrs->cursor);
     814           0 :         wmask |= CWCursor;
     815             :     }
     816           0 :     if ( (wattrs->mask&wam_nodecor) && wattrs->nodecoration ) {
     817           0 :         attrs.override_redirect = true;
     818           0 :         wmask |= CWOverrideRedirect;
     819           0 :         nw->is_popup = true;
     820           0 :         nw->is_dlg = true;
     821           0 :         nw->not_restricted = true;
     822             :     }
     823           0 :     if ( (wattrs->mask&wam_isdlg) && wattrs->is_dlg ) {
     824           0 :         nw->is_dlg = true;
     825             :     }
     826           0 :     if ( (wattrs->mask&wam_notrestricted) && wattrs->not_restricted ) {
     827           0 :         nw->not_restricted = true;
     828             :     }
     829           0 :     if ( !gdisp->default_visual ) {
     830           0 :         attrs.colormap = gdisp->cmap;
     831           0 :         wmask |= CWColormap|CWBackPixel|CWBorderPixel;
     832             :         /* CopyFromParent doesn't work if we've got different visuals!!!! */
     833             :     }
     834           0 :     wmask |= CWEventMask;
     835           0 :     attrs.event_mask = ExposureMask|StructureNotifyMask/*|PropertyChangeMask*/;
     836           0 :     if ( gw==gdisp->groot )
     837           0 :         attrs.event_mask |= FocusChangeMask|EnterWindowMask|LeaveWindowMask;
     838           0 :     if ( wattrs->mask&wam_events ) {
     839           0 :         if ( wattrs->event_masks&(1<<et_char) )
     840           0 :             attrs.event_mask |= KeyPressMask;
     841           0 :         if ( wattrs->event_masks&(1<<et_charup) )
     842           0 :             attrs.event_mask |= KeyReleaseMask;
     843           0 :         if ( wattrs->event_masks&(1<<et_mousemove) )
     844           0 :             attrs.event_mask |= PointerMotionMask;
     845           0 :         if ( wattrs->event_masks&(1<<et_mousedown) )
     846           0 :             attrs.event_mask |= ButtonPressMask;
     847           0 :         if ( wattrs->event_masks&(1<<et_mouseup) )
     848           0 :             attrs.event_mask |= ButtonReleaseMask;
     849           0 :         if ( (wattrs->event_masks&(1<<et_mouseup)) && (wattrs->event_masks&(1<<et_mousedown)) )
     850           0 :             attrs.event_mask |= OwnerGrabButtonMask;
     851           0 :         if ( wattrs->event_masks&(1<<et_visibility) )
     852           0 :             attrs.event_mask |= VisibilityChangeMask;
     853             :     }
     854             : 
     855             :     /* Only put the new dlgs underneath the cursor if focusfollows mouse, where */
     856             :     /*  they need to be there... */
     857           0 :     if ( gw == gdisp->groot &&
     858           0 :             ( ((wattrs->mask&wam_centered) && wattrs->centered) ||
     859           0 :               ((wattrs->mask&wam_undercursor) && wattrs->undercursor && !gdisp->focusfollowsmouse)) ) {
     860           0 :         pos->x = (gdisp->groot->pos.width-pos->width)/2;
     861           0 :         pos->y = (gdisp->groot->pos.height-pos->height)/2;
     862           0 :         if ( wattrs->centered==2 )
     863           0 :             pos->y = (gdisp->groot->pos.height-pos->height)/3;
     864           0 :         nw->pos = *pos;
     865           0 :     } else if ( (wattrs->mask&wam_undercursor) && wattrs->undercursor && gw == gdisp->groot) {
     866             :         int junk;
     867             :         Window wjunk;
     868             :         int x, y; unsigned int state;
     869             : 
     870           0 :         XQueryPointer(display,gw->w,&wjunk,&wjunk,&junk,&junk,&x,&y,&state);
     871           0 :         pos->x = x-pos->width/2;
     872           0 :         pos->y = y-pos->height/2-(!gdisp->top_offsets_set?20:gdisp->off_y);
     873           0 :         if ( pos->x+pos->width>gdisp->groot->pos.width ) pos->x = gdisp->groot->pos.width-pos->width;
     874           0 :         if ( pos->x<0 ) pos->x = 0;
     875           0 :         if ( pos->y+pos->height>gdisp->groot->pos.height ) pos->y = gdisp->groot->pos.height-pos->height;
     876           0 :         if ( pos->y<0 ) pos->y = 0;
     877           0 :         nw->pos = *pos;
     878             :     }
     879           0 :     nw->w = XCreateWindow(display, parent,
     880           0 :             pos->x, pos->y, pos->width, pos->height,
     881           0 :             (wattrs->mask&wam_bordwidth)?wattrs->border_width:0,
     882           0 :             gdisp->depth, InputOutput, gdisp->visual, wmask, &attrs);
     883           0 :     if ( gdisp->gcstate[0].gc==NULL ) {
     884             :         XGCValues vals;
     885           0 :         gdisp->gcstate[0].gc = XCreateGC(display,nw->w,0,&vals);
     886             :     }
     887             : 
     888           0 :     if ( gw == gdisp->groot ) {
     889             :         XWMHints wm_hints;
     890             :         XSizeHints s_h;
     891           0 :         wm_hints.flags = InputHint | StateHint;
     892           0 :         wm_hints.input = True;
     893           0 :         wm_hints.initial_state = NormalState;
     894           0 :         if ( ((wattrs->mask&wam_icon) && wattrs->icon!=NULL ) ||
     895           0 :                 ( !(wattrs->mask&wam_icon) && gdisp->default_icon!=NULL )) {
     896           0 :             GXWindow icon = (wattrs->mask&wam_icon)? (GXWindow) (wattrs->icon) : gdisp->default_icon;
     897           0 :             wm_hints.icon_pixmap = icon->w;
     898           0 :             wm_hints.flags |= IconPixmapHint;
     899           0 :             if ( !icon->ggc->bitmap_col && gdisp->depth!=1 ) {
     900             :                 /* X Icons are bitmaps. If we want a pixmap we create a dummy */
     901             :                 /*  window with the pixmap as background */
     902           0 :                 wm_hints.icon_window = MakeIconWindow(gdisp,icon);
     903           0 :                 wm_hints.flags |= IconWindowHint;
     904             :             }
     905             :         }
     906           0 :         XSetWMHints(display,nw->w,&wm_hints);
     907           0 :         if ( (wattrs->mask&wam_wtitle) && wattrs->window_title!=NULL ) {
     908           0 :             XmbSetWMProperties(display,nw->w,(pt = u2def_copy(wattrs->window_title)),NULL,NULL,0,NULL,NULL,NULL);
     909           0 :             free(pt);
     910             :         }
     911           0 :         if ( (wattrs->mask&wam_ititle) && wattrs->icon_title!=NULL ) {
     912           0 :             XmbSetWMProperties(display,nw->w,NULL,(pt = u2def_copy(wattrs->icon_title)),NULL,0,NULL,NULL,NULL);
     913           0 :             free(pt);
     914             :         }
     915           0 :         if ( (wattrs->mask&wam_utf8_wtitle) && wattrs->utf8_window_title!=NULL ) {
     916             : #ifdef X_HAVE_UTF8_STRING
     917           0 :         Xutf8SetWMProperties(display, nw->w, wattrs->utf8_window_title, NULL, NULL, 0, NULL, NULL, NULL);
     918             : #else
     919             :             unichar_t *tit = utf82u_copy(wattrs->utf8_window_title);
     920             :             XmbSetWMProperties(display,nw->w,(pt = u2def_copy(tit)),NULL,NULL,0,NULL,NULL,NULL);
     921             :             free(pt); free(tit);
     922             : #endif
     923             :         }
     924           0 :         if ( (wattrs->mask&wam_utf8_ititle) && wattrs->utf8_icon_title!=NULL ) {
     925             : #ifdef X_HAVE_UTF8_STRING
     926           0 :         Xutf8SetWMProperties(display, nw->w, NULL, wattrs->utf8_icon_title, NULL, 0, NULL, NULL, NULL);
     927             : #else
     928             :             unichar_t *tit = utf82u_copy(wattrs->utf8_icon_title);
     929             :             XmbSetWMProperties(display,nw->w,NULL,(pt = u2def_copy(tit)),NULL,0,NULL,NULL,NULL);
     930             :             free(pt); free(tit);
     931             : #endif
     932             :         }
     933           0 :         s_h.x = pos->x; s_h.y = pos->y;
     934           0 :         s_h.base_width = s_h.width = pos->width; s_h.base_height = s_h.height = pos->height;
     935           0 :         s_h.min_width = s_h.max_width = s_h.width;
     936           0 :         s_h.min_height = s_h.max_height = s_h.height;
     937           0 :         s_h.flags = PPosition | PSize | PBaseSize;
     938           0 :         if (( (wattrs->mask&wam_positioned) && wattrs->positioned ) ||
     939           0 :                 ((wattrs->mask&wam_centered) && wattrs->centered ) ||
     940           0 :                 ((wattrs->mask&wam_undercursor) && wattrs->undercursor )) {
     941           0 :             s_h.flags = USPosition | USSize | PBaseSize;
     942           0 :             nw->was_positioned = true;
     943             :         }
     944           0 :         if ( (wattrs->mask&wam_noresize) && wattrs->noresize )
     945           0 :             s_h.flags |= PMinSize | PMaxSize;
     946           0 :         XSetNormalHints(display,nw->w,&s_h);
     947           0 :         XSetWMProtocols(display,nw->w,&gdisp->atoms.wm_del_window,1);
     948           0 :         if ( wattrs->mask&wam_restrict )
     949           0 :             nw->restrict_input_to_me = wattrs->restrict_input_to_me;
     950           0 :         if ( wattrs->mask&wam_redirect ) {
     951           0 :             nw->redirect_chars_to_me = wattrs->redirect_chars_to_me;
     952           0 :             nw->redirect_from = wattrs->redirect_from;
     953             :         }
     954           0 :         if ( (wattrs->mask&wam_transient) && wattrs->transient!=NULL ) {
     955           0 :             XSetTransientForHint(display,nw->w,((GXWindow) (wattrs->transient))->w);
     956           0 :             nw->istransient = true;
     957           0 :             nw->transient_owner = ((GXWindow) (wattrs->transient))->w;
     958           0 :             nw->is_dlg = true;
     959           0 :         } else if ( !nw->is_dlg )
     960           0 :             ++gdisp->top_window_count;
     961           0 :         else if ( nw->restrict_input_to_me && gdisp->last_nontransient_window!=0 ) {
     962           0 :             XSetTransientForHint(display,nw->w,gdisp->last_nontransient_window);
     963           0 :             nw->transient_owner = gdisp->last_nontransient_window;
     964           0 :             nw->istransient = true;
     965             :         }
     966           0 :         nw->isverytransient = (wattrs->mask&wam_verytransient)?1:0;
     967           0 :         nw->is_toplevel = true;
     968           0 :         XChangeProperty(display,nw->w,gdisp->atoms.wm_protocols,XA_ATOM,32,
     969           0 :                 PropModeReplace,(unsigned char *) &gdisp->atoms.wm_del_window, 1);
     970             :     }
     971           0 :     ch.res_class = GResourceProgramName;
     972           0 :     ch.res_name = GResourceProgramName;
     973           0 :     XSetClassHint(display,nw->w,&ch);
     974           0 :     XSaveContext(display,nw->w,gdisp->mycontext,(void *) nw);
     975           0 :     if ( eh!=NULL ) {
     976             :         GEvent e;
     977           0 :         memset(&e,0,sizeof(e));
     978           0 :         e.type = et_create;
     979           0 :         e.w = (GWindow) nw;
     980           0 :         e.native_window = (void *) (intpt) nw->w;
     981           0 :         (eh)((GWindow) nw,&e);
     982             :     }
     983             : #ifndef _NO_LIBCAIRO
     984             :     /* Only do sub-pixel/anti-alias stuff if we've got truecolor */
     985           0 :     if ( gdisp->visual->class==TrueColor && !(wattrs->mask&wam_nocairo) &&_GXCDraw_hasCairo() )
     986           0 :         _GXCDraw_NewWindow(nw);
     987             : #endif
     988             :     /* Must come after the cairo init so pango will know to use cairo or xft */
     989             :     /* I think we will always want to use pango, so it isn't conditional on a wam */
     990           0 :     _GXPDraw_NewWindow(nw);
     991           0 : return( (GWindow) nw );
     992             : }
     993             : 
     994           0 : static GWindow GXDrawCreateTopWindow(GDisplay *gdisp, GRect *pos,
     995             :         int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs) {
     996           0 : return( _GXDraw_CreateWindow((GXDisplay *) gdisp,NULL,pos,eh,user_data, wattrs));
     997             : }
     998             : 
     999           0 : static GWindow GXDrawCreateSubWindow(GWindow w, GRect *pos,
    1000             :         int (*eh)(GWindow,GEvent *), void *user_data, GWindowAttrs *wattrs) {
    1001           0 : return( _GXDraw_CreateWindow(((GXWindow) w)->display,(GXWindow) w,pos,eh,user_data, wattrs));
    1002             : }
    1003             : 
    1004           0 : static void GXDrawSetZoom(GWindow w, GRect *pos, enum gzoom_flags flags) {
    1005             :     XSizeHints zoom, normal;
    1006           0 :     Display *display = ((GXWindow) w)->display->display;
    1007             :     long supplied_return;
    1008             : 
    1009           0 :     memset(&zoom,0,sizeof(zoom));
    1010           0 :     if ( flags&gzf_pos ) {
    1011           0 :         zoom.x = pos->x;
    1012           0 :         zoom.y = pos->y;
    1013           0 :         zoom.flags = PPosition;
    1014             :     }
    1015           0 :     if ( flags&gzf_size ) {
    1016           0 :         zoom.width = zoom.base_width = zoom.max_width = pos->width;
    1017           0 :         zoom.height = zoom.base_height = zoom.max_height = pos->height;
    1018           0 :         zoom.flags |= PSize | PBaseSize | PMaxSize;
    1019           0 :         XGetWMNormalHints(display,((GXWindow) w)->w,&normal,&supplied_return);
    1020           0 :         normal.flags |= PMaxSize;
    1021           0 :         normal.max_width = pos->width;
    1022           0 :         normal.max_height = pos->height;
    1023           0 :         XSetWMNormalHints(display,((GXWindow) w)->w,&normal);
    1024             :     }
    1025           0 :     XSetWMSizeHints(display,((GXWindow) w)->w,&zoom,XA_WM_ZOOM_HINTS);
    1026           0 : }
    1027             : 
    1028           0 : static GWindow GXDrawCreatePixmap(GDisplay *gdisp, uint16 width, uint16 height) {
    1029           0 :     GXWindow gw = calloc(1,sizeof(struct gxwindow));
    1030           0 :     int wamcairo = false;
    1031             : 
    1032           0 :     if ( gw==NULL )
    1033           0 : return( NULL );
    1034           0 :     gw->ggc = _GXDraw_NewGGC();
    1035           0 :     gw->ggc->bg = ((GXDisplay *) gdisp)->def_background;
    1036           0 :     if ( gw->ggc==NULL ) {
    1037           0 :         free(gw);
    1038           0 : return( NULL );
    1039             :     }
    1040           0 :     if ( width&0x8000 ) {
    1041           0 :         width &= 0x7fff;
    1042           0 :         wamcairo = true;
    1043             :     }
    1044             :     // icon windows.
    1045           0 :     if ( width == 48 ) {
    1046           0 :         wamcairo = true;
    1047             :     }
    1048             :     
    1049           0 :     gw->display = (GXDisplay *) gdisp;
    1050           0 :     gw->is_pixmap = 1;
    1051           0 :     gw->parent = NULL;
    1052           0 :     gw->pos.x = gw->pos.y = 0;
    1053           0 :     gw->pos.width = width; gw->pos.height = height;
    1054           0 :     gw->w = XCreatePixmap(gw->display->display, gw->display->root, width, height, gw->display->depth);
    1055             : #ifndef _NO_LIBCAIRO
    1056             :     /* Only do sub-pixel/anti-alias stuff if we've got truecolor */
    1057           0 :     if ( ((GXDisplay *) gdisp)->visual->class==TrueColor && wamcairo &&
    1058           0 :             _GXCDraw_hasCairo() )
    1059           0 :         _GXCDraw_NewWindow(gw);
    1060             : #endif
    1061             :     /* Must come after the cairo init so pango will know to use cairo or xft */
    1062             :     /* I think we will always want to use pango, so it isn't conditional */
    1063           0 :     _GXPDraw_NewWindow(gw);
    1064           0 : return( (GWindow) gw );
    1065             : }
    1066             : 
    1067           0 : static GWindow GXDrawCreateBitmap(GDisplay *disp, uint16 width, uint16 height, uint8 *data) {
    1068           0 :     GXDisplay *gdisp = (GXDisplay *) disp;
    1069           0 :     GXWindow gw = calloc(1,sizeof(struct gxwindow));
    1070             : 
    1071           0 :     if ( gw==NULL )
    1072           0 : return( NULL );
    1073           0 :     gw->ggc = _GXDraw_NewGGC();
    1074           0 :     if ( gw->ggc==NULL ) {
    1075           0 :         free(gw);
    1076           0 : return( NULL );
    1077             :     }
    1078           0 :     gw->ggc->bitmap_col = true;
    1079           0 :     gw->display = (GXDisplay *) gdisp;
    1080           0 :     gw->is_pixmap = 1;
    1081           0 :     gw->parent = NULL;
    1082           0 :     gw->pos.x = gw->pos.y = 0;
    1083           0 :     gw->pos.width = width; gw->pos.height = height;
    1084           0 :     if ( data==NULL )
    1085           0 :         gw->w = XCreatePixmap(gdisp->display, gw->display->root, width, height, 1);
    1086             :     else
    1087           0 :         gw->w = XCreateBitmapFromData(gdisp->display, gw->display->root,
    1088             :                 (char *) data, width, height );
    1089           0 :     if ( gdisp->gcstate[1].gc==NULL ) {
    1090             :         XGCValues vals;
    1091           0 :         gdisp->gcstate[1].gc = XCreateGC(gdisp->display,gw->w,0,&vals);
    1092             :     }
    1093           0 : return( (GWindow) gw );
    1094             : }
    1095             : 
    1096           0 : static GCursor GXDrawCreateCursor(GWindow src,GWindow mask,Color fg,Color bg,
    1097             :         int16 x, int16 y ) {
    1098           0 :     GXDisplay *gdisp = (GXDisplay *) (src->display);
    1099           0 :     Display *display = gdisp->display;
    1100             :     XColor fgc, bgc;
    1101             :     /* The XServer shipping with redhat 7.1 seems to suffer a protocol change */
    1102             :     /*  with the red and blue members of XColor structure reversed */
    1103             :     /* The XServer runing on Mac OS/X can only handle 16x16 cursors */
    1104             : 
    1105           0 :     fgc.red = COLOR_RED(fg)*0x101; fgc.green = COLOR_GREEN(fg)*0x101; fgc.blue = COLOR_BLUE(fg)*0x101;
    1106           0 :     bgc.red = COLOR_RED(bg)*0x101; bgc.green = COLOR_GREEN(bg)*0x101; bgc.blue = COLOR_BLUE(bg)*0x101;
    1107           0 :     fgc.pixel = _GXDraw_GetScreenPixel(gdisp,fg); fgc.flags = -1;
    1108           0 :     bgc.pixel = _GXDraw_GetScreenPixel(gdisp,bg); bgc.flags = -1;
    1109           0 : return( ct_user + XCreatePixmapCursor(display,((GXWindow) src)->w, ((GXWindow) mask)->w,
    1110             :         &fgc,&bgc, x,y));
    1111             : }
    1112             : 
    1113             : static void GTimerRemoveWindowTimers(GXWindow gw);
    1114             : 
    1115           0 : static void GXDrawDestroyWindow(GWindow w) {
    1116           0 :     GXWindow gw = (GXWindow) w;
    1117             : 
    1118             : #ifndef _NO_LIBCAIRO
    1119           0 :     if ( gw->usecairo )
    1120           0 :         _GXCDraw_DestroyWindow(gw);
    1121             : #endif
    1122           0 :     _GXPDraw_DestroyWindow(gw);
    1123             : 
    1124           0 :     if ( gw->is_pixmap ) {
    1125           0 :         XFreePixmap(gw->display->display,gw->w);
    1126           0 :         free(gw->ggc);
    1127           0 :         free(gw);
    1128             :     } else {
    1129             :         /*GTimerRemoveWindowTimers(gw);*/ /* Moved to _GXDraw_CleanUpWindow, not all windows are actively destroyed */
    1130           0 :         gw->is_dying = true;
    1131           0 :         if ( gw->display->grab_window==w ) gw->display->grab_window = NULL;
    1132           0 :         XDestroyWindow(gw->display->display,gw->w);
    1133             :         /* Windows should be freed when we get the destroy event */
    1134             :     }
    1135           0 : }
    1136             : 
    1137           0 : static void GXDestroyCursor(GDisplay *gdisp,GCursor ct) {
    1138           0 :     XFreeCursor(((GXDisplay *) gdisp)->display, ct-ct_user);
    1139           0 : }
    1140             : 
    1141           0 : static int GXNativeWindowExists(GDisplay *gdisp,void *native) {
    1142             :     void *ret;
    1143             : 
    1144           0 :     if ( XFindContext(((GXDisplay *) gdisp)->display,(Window) (intpt) native,((GXDisplay *) gdisp)->mycontext,(void *) &ret)==0 &&
    1145           0 :             ret!=NULL )
    1146           0 : return( true );
    1147             : 
    1148           0 : return( false );
    1149             : }
    1150             : 
    1151           0 : static void GXDrawSetWindowBorder(GWindow w,int width,Color col) {
    1152           0 :     GXWindow gw = (GXWindow) w;
    1153             : 
    1154           0 :     if ( width>=0 )
    1155           0 :         XSetWindowBorderWidth(gw->display->display,gw->w,width);
    1156           0 :     if ( col!=COLOR_DEFAULT )
    1157           0 :         XSetWindowBorder(gw->display->display,gw->w,
    1158           0 :                 _GXDraw_GetScreenPixel(gw->display,col));
    1159           0 : }
    1160             : 
    1161           0 : static void GXDrawSetWindowBackground(GWindow w,Color col) {
    1162           0 :     GXWindow gw = (GXWindow) w;
    1163             : 
    1164           0 :     if ( col!=COLOR_DEFAULT )
    1165           0 :         XSetWindowBackground(gw->display->display,gw->w,
    1166           0 :                 _GXDraw_GetScreenPixel(gw->display,col));
    1167           0 : }
    1168             : 
    1169           0 : static int GXSetDither(GDisplay *gdisp,int dither) {
    1170           0 :     int old = ((GXDisplay *) gdisp)->do_dithering;
    1171           0 :     ((GXDisplay *) gdisp)->do_dithering = dither;
    1172           0 : return( old );
    1173             : }
    1174             : 
    1175           0 : static void _GXDraw_RemoveRedirects(GXDisplay *gdisp,GXWindow gw) {
    1176           0 :     if ( gdisp->input!=NULL ) {
    1177           0 :         struct inputRedirect *next=gdisp->input, *test;
    1178           0 :         if ( next->cur_dlg == (GWindow) gw ) {
    1179           0 :             gdisp->input = next->prev;
    1180           0 :             free(next);
    1181           0 :         } else for ( test=next->prev; test!=NULL; test=test->prev ) {
    1182           0 :             if ( test->cur_dlg == (GWindow) gw ) {
    1183           0 :                 next->prev = test->prev;
    1184           0 :                 free( test );
    1185           0 :         break;
    1186             :             }
    1187             :         }
    1188             :     }
    1189           0 : }
    1190             : 
    1191           0 : static void _GXDraw_CleanUpWindow( GWindow w ) {
    1192           0 :     GXWindow gw = (GXWindow) w;
    1193           0 :     GXDisplay *gdisp = gw->display;
    1194             :     int i;
    1195             :     struct gxinput_context *gic, *next;
    1196             : 
    1197           0 :     XSaveContext(gdisp->display,gw->w,gdisp->mycontext,NULL);
    1198           0 :     if ( gdisp->grab_window==w ) gdisp->grab_window = NULL;
    1199           0 :     if ( gdisp->last_dd.gw==w ) {
    1200           0 :         gdisp->last_dd.gw = NULL;
    1201           0 :         gdisp->last_dd.w = None;
    1202             :     }
    1203             : 
    1204           0 :     GTimerRemoveWindowTimers(gw);
    1205           0 :     _GXDraw_RemoveRedirects(gdisp,gw);
    1206           0 :     if ( gdisp->groot == gw->parent && !gw->is_dlg )
    1207           0 :         --gdisp->top_window_count;
    1208             : 
    1209             :     /* If the window owns any selection it just lost them, cleanup our data */
    1210             :     /*  structures... */
    1211           0 :     for ( i = 0; i<sn_max; ++i ) {
    1212           0 :         if ( gdisp->selinfo[i].owner == gw ) {
    1213           0 :             GXDrawClearSelData(gdisp,i);
    1214           0 :             gdisp->selinfo[i].owner = NULL;
    1215             :         }
    1216             :     }
    1217             : 
    1218             :     /* Does the window have any input contexts? If so get rid of them all */
    1219           0 :     for ( gic = gw->all; gic!=NULL; gic = next ) {
    1220           0 :         next = gic->next;
    1221           0 :         XDestroyIC(gic->ic);
    1222           0 :         free(gic);
    1223             :     }
    1224             : 
    1225           0 :     free(gw->ggc);
    1226           0 :     memset(gw,'\0',sizeof(*gw));
    1227           0 :     free(gw);
    1228           0 : }
    1229             : 
    1230           0 : static void GXDrawReparentWindow(GWindow child,GWindow newparent, int x,int y) {
    1231           0 :     GXWindow gchild = (GXWindow) child, gpar = (GXWindow) newparent;
    1232           0 :     GXDisplay *gdisp = gchild->display;
    1233             :     /* Gnome won't let me reparent a top level window */
    1234             :     /* It only pays attention to override-redirect if the window hasn't been mapped */
    1235           0 :     XReparentWindow(gdisp->display,gchild->w,gpar->w,x,y);
    1236           0 : }
    1237             : 
    1238           0 : static void GXDrawSetVisible(GWindow w, int visible) {
    1239           0 :     GXWindow gw = (GXWindow) w;
    1240           0 :     GXDisplay *gdisp = gw->display;
    1241             : 
    1242           0 :     if( cmdlinearg_forceUIHidden )
    1243           0 :         visible = false;
    1244             :     
    1245           0 :     gw->visible_request = visible;
    1246           0 :     if ( visible ) {
    1247           0 :         XMapWindow(gdisp->display,gw->w);
    1248           0 :         if ( gw->restrict_input_to_me || gw->redirect_chars_to_me ||
    1249           0 :                 gw->redirect_from!=NULL ) {
    1250           0 :             struct inputRedirect *ir = calloc(1,sizeof(struct inputRedirect));
    1251           0 :             if ( ir!=NULL ) {
    1252           0 :                 ir->prev = gdisp->input;
    1253           0 :                 gdisp->input = ir;
    1254           0 :                 ir->cur_dlg = (GWindow) gw;
    1255           0 :                 if ( gw->redirect_from!=NULL ) {
    1256           0 :                     ir->it = it_targetted;
    1257           0 :                     ir->inactive = gw->redirect_from;
    1258           0 :                 } else if ( gw->redirect_chars_to_me )
    1259           0 :                     ir->it = it_redirected;
    1260             :                 else
    1261           0 :                     ir->it = it_restricted;
    1262             :             }
    1263             :         }
    1264           0 :     } else if ( !visible ) {
    1265           0 :         if ( gw->is_toplevel && gw->is_visible ) {
    1266             :             /* Save the current position in the size hints. Otherwise some */
    1267             :             /*  window managers will pop it up where originally positioned */
    1268             :             /*  or if unpositioned ask user to position it. Ug */
    1269             :             XSizeHints s_h;
    1270           0 :             s_h.flags = USPosition;
    1271           0 :             s_h.x = gw->pos.x + gdisp->off_x;
    1272           0 :             s_h.y = gw->pos.y + gdisp->off_y;
    1273           0 :             XSetNormalHints(gdisp->display,gw->w,&s_h);
    1274             :         }
    1275           0 :         if (gw->is_toplevel)
    1276           0 :                 XWithdrawWindow(gdisp->display,gw->w,gdisp->screen);
    1277             :         else
    1278           0 :                 XUnmapWindow(gdisp->display,gw->w);
    1279           0 :         _GXDraw_RemoveRedirects(gdisp,gw);
    1280             :     }
    1281           0 : }
    1282             : 
    1283           0 : static void GXDrawMove(GWindow w, int32 x, int32 y) {
    1284           0 :     GXWindow gw = (GXWindow) w;
    1285             : 
    1286           0 :     if ( gw->is_toplevel ) {
    1287             :         /* Save the current position in the size hints. Otherwise some */
    1288             :         /*  (if unmapped) window managers will pop it up where originally */
    1289             :         /*  positioned or if unpositioned ask user to position it. Ug */
    1290             :         XSizeHints s_h;
    1291           0 :         s_h.flags = USPosition;
    1292           0 :         s_h.x = x;
    1293           0 :         s_h.y = y;
    1294           0 :         XSetNormalHints(gw->display->display,gw->w,&s_h);
    1295             :     }
    1296           0 :     XMoveWindow(gw->display->display,gw->w,x,y);
    1297           0 : }
    1298             : 
    1299           0 : static void GXDrawTrueMove(GWindow w, int32 x, int32 y) {
    1300           0 :     GXWindow gw = (GXWindow) w;
    1301             : 
    1302           0 :     if ( gw->is_toplevel && !gw->is_popup && !gw->istransient ) {
    1303           0 :         x -= gw->display->off_x;
    1304           0 :         y -= gw->display->off_y;
    1305             :     }
    1306           0 :     GXDrawMove(w,x,y);
    1307           0 : }
    1308             : 
    1309           0 : static void GXDrawResize(GWindow w, int32 width, int32 height) {
    1310           0 :     GXWindow gw = (GXWindow) w;
    1311             : 
    1312           0 :     XResizeWindow(gw->display->display,gw->w,width,height);
    1313           0 :     if ( gw->is_toplevel ) {
    1314             :         XSizeHints s_h;
    1315             :         /* for some reason the USPosition bit gets unset if I just set the width */
    1316           0 :         s_h.flags = -1;         /* I don't know if this is needed, but let's be paranoid */
    1317           0 :         XGetNormalHints(gw->display->display,gw->w,&s_h);
    1318           0 :         s_h.flags |= USSize;
    1319           0 :         s_h.width = width;
    1320           0 :         s_h.height = height;
    1321           0 :         XSetNormalHints(gw->display->display,gw->w,&s_h);
    1322             :     }
    1323           0 : }
    1324             : 
    1325           0 : static void GXDrawMoveResize(GWindow w, int32 x, int32 y, int32 width, int32 height) {
    1326           0 :     GXWindow gw = (GXWindow) w;
    1327             : 
    1328           0 :     if ( gw->is_toplevel ) {
    1329             :         /* Save the current position in the size hints. Otherwise some */
    1330             :         /*  window managers will pop it up where originally positioned */
    1331             :         /*  or if unpositioned ask user to position it. Ug */
    1332             :         /* Might as well do the size too... */
    1333             :         XSizeHints s_h;
    1334           0 :         s_h.flags = USPosition|USSize;
    1335           0 :         s_h.x = x;
    1336           0 :         s_h.y = y;
    1337           0 :         s_h.width = width;
    1338           0 :         s_h.height = height;
    1339           0 :         XSetNormalHints(gw->display->display,gw->w,&s_h);
    1340             :     }
    1341           0 :     XMoveResizeWindow(gw->display->display,gw->w,x,y,width,height);
    1342           0 : }
    1343             : 
    1344           0 : static void GXDrawRaise(GWindow w) {
    1345           0 :     GXWindow gw = (GXWindow) w;
    1346             : 
    1347           0 :     XRaiseWindow(gw->display->display,gw->w);
    1348           0 : }
    1349             : 
    1350             : static GXDisplay *edisp;
    1351           0 : static int error(Display *disp, XErrorEvent *err) {
    1352             :     /* Under twm I get a bad match, under kde a bad window? */
    1353           0 :     if ( err->error_code == BadMatch || err->error_code == BadWindow ) {
    1354           0 :         if ( edisp!=NULL ) edisp->wm_breaks_raiseabove = true;
    1355             :     } else {
    1356           0 :         myerrorhandler(disp,err);
    1357             :     }
    1358           0 : return( 1 );
    1359             : }
    1360             : 
    1361           0 : static void GXDrawRaiseAbove(GWindow w,GWindow below) {
    1362           0 :     GXWindow gw = (GXWindow) w, gbelow = (GXWindow) below;
    1363           0 :     Window gxw = gw->w, gxbelow = gbelow->w;
    1364           0 :     GXDisplay *gdisp = gw->display;
    1365             :     XWindowChanges ch;
    1366             : 
    1367             :     /* Sometimes we get a BadWindow error here for no good reason */
    1368           0 :     XSync(gdisp->display,false);
    1369           0 :     GDrawProcessPendingEvents((GDisplay *) gdisp);
    1370           0 :     XSetErrorHandler(/*gdisp->display,*/error);
    1371           0 :     if ( !gdisp->wm_raiseabove_tested ) {
    1372           0 :         edisp = gdisp;
    1373             :     } else
    1374           0 :         edisp = NULL;
    1375             :  retry:
    1376           0 :     if ( gdisp->wm_breaks_raiseabove ) {
    1377             :         /* If we do this code in gnome it breaks things */
    1378             :         /* if we don't do it in twm it breaks things. Sigh */
    1379           0 :         if ( gw->is_toplevel )
    1380           0 :             gxw = GetParentissimus(gw);
    1381           0 :         if ( gbelow->is_toplevel )
    1382           0 :             gxbelow = GetParentissimus(gbelow);
    1383             :     }
    1384           0 :     ch.sibling = gxbelow;
    1385           0 :     ch.stack_mode = Above;
    1386           0 :     XConfigureWindow(gdisp->display,gxw,CWSibling|CWStackMode,&ch);
    1387           0 :     XSync(gdisp->display,false);
    1388           0 :     GDrawProcessPendingEvents((GDisplay *) gdisp);
    1389           0 :     if ( !gdisp->wm_raiseabove_tested ) {
    1390           0 :         gdisp->wm_raiseabove_tested = true;
    1391           0 :         if ( gdisp->wm_breaks_raiseabove )
    1392           0 :  goto retry;
    1393             :     }
    1394           0 :     XSetErrorHandler(/*gdisp->display,*/myerrorhandler);
    1395           0 : }
    1396             : 
    1397           0 : static int GXDrawIsAbove(GWindow w,GWindow other) {
    1398           0 :     GXWindow gw = (GXWindow) w, gother = (GXWindow) other;
    1399           0 :     Window gxw = gw->w, gxother = gother->w, parent;
    1400           0 :     GXDisplay *gdisp = (GXDisplay *) (gw->display);
    1401             :     Window par, *children, root;
    1402             :     unsigned int nkids; int i;
    1403             : 
    1404           0 :     if ( gw->is_toplevel && gother->is_toplevel ) {
    1405           0 :         gxw = GetParentissimus(gw);
    1406           0 :         gxother = GetParentissimus(gother);
    1407           0 :         parent = gdisp->root;
    1408           0 :     } else if ( gw->parent!=gother->parent )
    1409           0 : return( -1 );                   /* Incommensurate */
    1410             :     else
    1411           0 :         parent = gw->parent->w;
    1412             : 
    1413           0 :     XQueryTree(gdisp->display,parent,&root,&par,&children,&nkids);
    1414             :     /* bottom-most child is children[0], topmost is children[nkids-1] */
    1415           0 :     for ( i=nkids-1; i>=0; --i ) {
    1416           0 :         if ( children[i] == gxw )
    1417           0 : return( true );
    1418           0 :         if ( children[i] == gxother )
    1419           0 : return( false );
    1420             :     }
    1421           0 :     if ( children )
    1422           0 :         XFree(children);
    1423           0 : return( -1 );
    1424             : }
    1425             : 
    1426           0 : static void GXDrawLower(GWindow w) {
    1427           0 :     GXWindow gw = (GXWindow) w;
    1428             : 
    1429           0 :     XLowerWindow(gw->display->display,gw->w);
    1430           0 : }
    1431             : 
    1432           0 : static void GXDrawSetWindowTitles(GWindow w, const unichar_t *title, const unichar_t *icontit) {
    1433           0 :     GXWindow gw = (GXWindow) w;
    1434           0 :     Display *display = gw->display->display;
    1435             :     char *ipt, *tpt;
    1436             : 
    1437           0 :     XmbSetWMProperties(display,gw->w,(tpt = u2def_copy(title)),
    1438             :                         (ipt = u2def_copy(icontit)),
    1439             :                         NULL,0,NULL,NULL,NULL);
    1440           0 :     free(ipt); free(tpt);
    1441           0 : }
    1442             : 
    1443           0 : static void GXDrawSetWindowTitles8(GWindow w, const char *title, const char *icontit) {
    1444           0 :     GXWindow gw = (GXWindow) w;
    1445           0 :     Display *display = gw->display->display;
    1446             : #ifdef X_HAVE_UTF8_STRING
    1447           0 :     Xutf8SetWMProperties(display, gw->w, title, icontit, NULL, 0, NULL, NULL, NULL);
    1448             : #else
    1449             :     unichar_t *tit = utf82u_copy(title), *itit = utf82u_copy(icontit);
    1450             :     char *ipt, *tpt;
    1451             : 
    1452             :     XmbSetWMProperties(display,gw->w,(tpt = u2def_copy(tit)),
    1453             :                         (ipt = u2def_copy(itit)),
    1454             :                         NULL,0,NULL,NULL,NULL);
    1455             :     free(tit); free(tpt);
    1456             :     free(itit); free(ipt);
    1457             : #endif
    1458           0 : }
    1459             : 
    1460           0 : static void GXDrawSetTransientFor(GWindow transient, GWindow owner) {
    1461           0 :     GXWindow gw = (GXWindow) transient;
    1462           0 :     GXDisplay *gdisp = gw->display;
    1463           0 :     Display *display = gdisp->display;
    1464             :     Window ow;
    1465             : 
    1466           0 :     if ( owner==(GWindow) -1 )
    1467           0 :         ow = gdisp->last_nontransient_window;
    1468           0 :     else if ( owner==NULL )
    1469           0 :         ow = 0;
    1470             :     else
    1471           0 :         ow = ((GXWindow) owner)->w;
    1472           0 :     XSetTransientForHint(display,gw->w, ow );
    1473           0 :     gw->transient_owner = ow;
    1474           0 :     gw->istransient = ow!=0;
    1475           0 : }
    1476             : 
    1477           0 : static void GXDrawSetCursor(GWindow w, GCursor ct) {
    1478           0 :     GXWindow gw = (GXWindow) w;
    1479           0 :     GXDisplay *gdisp = gw->display;
    1480           0 :     Cursor cur = _GXDraw_GetCursor(gdisp,ct);
    1481             : 
    1482           0 :     XDefineCursor(gdisp->display,gw->w,cur);
    1483           0 :     gw->cursor = ct;
    1484           0 : }
    1485             : 
    1486           0 : static GCursor GXDrawGetCursor(GWindow w) {
    1487           0 :     GXWindow gw = (GXWindow) w;
    1488             : 
    1489           0 : return( gw->cursor );
    1490             : }
    1491             : 
    1492           0 : static GWindow GXDrawGetRedirectWindow(GDisplay *gd) {
    1493           0 :     GXDisplay *gdisp = (GXDisplay *) gd;
    1494             : 
    1495           0 :     if ( gdisp->input==NULL )
    1496           0 : return( NULL );
    1497             : 
    1498           0 : return( gdisp->input->cur_dlg );
    1499             : }
    1500             : 
    1501           0 : static void GXDrawGetPointerPosition(GWindow w, GEvent *ret) {
    1502           0 :     GXWindow gw = (GXWindow) w;
    1503           0 :     Display *display = gw->display->display;
    1504             :     int junk;
    1505             :     Window wjunk;
    1506             :     int x, y; unsigned int state;
    1507             : 
    1508           0 :     XQueryPointer(display,gw->w,&wjunk,&wjunk,&junk,&junk,&x,&y,&state);
    1509           0 :     ret->u.mouse.state = state;
    1510           0 :     ret->u.mouse.x = x;
    1511           0 :     ret->u.mouse.y = y;
    1512           0 : }
    1513             : 
    1514           0 : static Window _GXDrawGetPointerWindow(GWindow w) {
    1515           0 :     GXWindow gw = (GXWindow) w;
    1516           0 :     Display *display = gw->display->display;
    1517             :     int junk;
    1518             :     Window parent, child, wjunk;
    1519             :     int x, y; unsigned int state;
    1520             : 
    1521           0 :     parent = gw->display->groot->w;
    1522             :     for (;;) {
    1523           0 :         child = None;
    1524           0 :         if ( !XQueryPointer(display,parent,&wjunk,&child,&junk,&junk,&x,&y,&state))
    1525           0 :     break;
    1526           0 :         if ( child==None )
    1527           0 :     break;
    1528           0 :         parent = child;
    1529           0 :     }
    1530           0 : return( parent );
    1531             : }
    1532             : 
    1533           0 : static GWindow GXDrawGetPointerWindow(GWindow w) {
    1534           0 :     GXWindow gw = (GXWindow) w;
    1535           0 :     Display *display = gw->display->display;
    1536             :     void *ret;
    1537             :     Window parent;
    1538             : 
    1539           0 :     parent = _GXDrawGetPointerWindow(w);
    1540           0 :     if ( (gw->w&0xfff00000) == (parent&0xfff00000)) {
    1541             :         /* It is one of our windows, so it is safe to look for it */
    1542           0 :         if ( XFindContext(display,parent,gw->display->mycontext,(void *) &ret)==0 )
    1543           0 : return( (GWindow) ret );
    1544             :     }
    1545           0 : return( NULL );
    1546             : }
    1547             : 
    1548             : static char *GXDrawGetWindowTitle8(GWindow w);
    1549             : 
    1550           0 : static unichar_t *GXDrawGetWindowTitle(GWindow w) {
    1551             : #if X_HAVE_UTF8_STRING
    1552           0 :     char *ret1 = GXDrawGetWindowTitle8(w);
    1553           0 :     unichar_t *ret = utf82u_copy(ret1);
    1554             : 
    1555           0 :     free(ret1);
    1556           0 : return( ret );
    1557             : #else
    1558             :     GXWindow gw = (GXWindow) w;
    1559             :     Display *display = gw->display->display;
    1560             :     char *pt;
    1561             :     unichar_t *ret;
    1562             : 
    1563             :     XFetchName(display,gw->w,&pt);
    1564             :     ret = def2u_copy(pt);
    1565             :     XFree(pt);
    1566             : return( ret );
    1567             : #endif
    1568             : }
    1569             : 
    1570           0 : static char *GXDrawGetWindowTitle8(GWindow w) {
    1571             : #if X_HAVE_UTF8_STRING
    1572           0 :     GXWindow gw = (GXWindow) w;
    1573           0 :     Display *display = gw->display->display;
    1574             :     XTextProperty prop;
    1575             :     char **propret;
    1576             :     int cnt, i, len;
    1577             :     char *ret;
    1578             : 
    1579           0 :     memset(&prop,0,sizeof(prop));
    1580           0 :     XGetTextProperty(display,gw->w, &prop, XA_WM_NAME );
    1581           0 :     if ( prop.value == NULL )
    1582           0 : return( NULL );
    1583           0 :     Xutf8TextPropertyToTextList(display,&prop,&propret,&cnt);
    1584           0 :     XFree(prop.value);
    1585           0 :     for ( i=len=0; i<cnt; ++i )
    1586           0 :         len += strlen( propret[i]);
    1587           0 :     ret = malloc(len+1);
    1588           0 :     for ( i=len=0; i<cnt; ++i ) {
    1589           0 :         strcpy(ret+len,propret[i]);
    1590           0 :         len += strlen( propret[i]);
    1591             :     }
    1592           0 :     XFreeStringList( propret );
    1593           0 : return( ret );
    1594             : #else
    1595             :     unichar_t *ret1 = GXDrawGetWindowTitle(w);
    1596             :     char *ret = u2utf8_copy(ret1);
    1597             : 
    1598             :     free(ret1);
    1599             : return( ret );
    1600             : #endif
    1601             : }
    1602             : 
    1603           0 : static void GXDrawTranslateCoordinates(GWindow _from,GWindow _to, GPoint *pt) {
    1604           0 :     GXDisplay *gd = (GXDisplay *) ((_from!=NULL)?_from->display:_to->display);
    1605           0 :     Window from = (_from==NULL)?gd->root:((GXWindow) _from)->w;
    1606           0 :     Window to = (_to==NULL)?gd->root:((GXWindow) _to)->w;
    1607             :     int x,y;
    1608             :     Window child;
    1609             : 
    1610           0 :     XTranslateCoordinates(gd->display,from,to,pt->x,pt->y,&x,&y,&child);
    1611           0 :     pt->x = x; pt->y = y;
    1612           0 : }
    1613             : 
    1614           0 : static void GXDrawBeep(GDisplay *gdisp) {
    1615           0 :     XBell(((GXDisplay *) gdisp)->display,80);
    1616           0 : }
    1617             : 
    1618           0 : static void GXDrawFlush(GDisplay *gdisp) {
    1619           0 :     XFlush(((GXDisplay *) gdisp)->display);
    1620           0 : }
    1621             : /* ************************************************************************** */
    1622             : /* **************************** Draw Routines ******************************* */
    1623             : /* ************************************************************************** */
    1624             : 
    1625           0 : void _GXDraw_SetClipFunc(GXDisplay *gdisp, GGC *mine) {
    1626             :     XRectangle clip;
    1627             :     XGCValues vals;
    1628           0 :     long mask=0;
    1629           0 :     GCState *gcs = &gdisp->gcstate[mine->bitmap_col];
    1630             : 
    1631           0 :     if ( mine->clip.x!=gcs->clip.x ||
    1632           0 :             mine->clip.width!=gcs->clip.width ||
    1633           0 :             mine->clip.y!=gcs->clip.y ||
    1634           0 :             mine->clip.height!=gcs->clip.height ) {
    1635           0 :         clip.x = mine->clip.x; clip.y = mine->clip.y;
    1636           0 :         clip.width = mine->clip.width;
    1637           0 :         clip.height = mine->clip.height;
    1638           0 :         XSetClipRectangles(gdisp->display,gcs->gc,0,0,&clip,1,YXBanded);
    1639           0 :         gcs->clip = mine->clip;
    1640             :     }
    1641           0 :     if ( mine->func!=gcs->func ) {
    1642           0 :         vals.function = mine->func==df_copy?GXcopy:GXxor;
    1643           0 :         mask |= GCFunction;
    1644           0 :         gcs->func = mine->func;
    1645             :     }
    1646           0 :     if ( mine->copy_through_sub_windows != gcs->copy_through_sub_windows ) {
    1647           0 :         vals.subwindow_mode = mine->copy_through_sub_windows?IncludeInferiors:ClipByChildren;
    1648           0 :         mask |= GCSubwindowMode;
    1649           0 :         gcs->copy_through_sub_windows = mine->copy_through_sub_windows;
    1650             :     }
    1651           0 :     if ( mask!=0 )
    1652           0 :         XChangeGC(gdisp->display,gcs->gc,mask,&vals);
    1653           0 : }
    1654             : 
    1655           0 : static int GXDrawSetcolfunc(GXDisplay *gdisp, GGC *mine) {
    1656             :     XGCValues vals;
    1657           0 :     long mask=0;
    1658           0 :     GCState *gcs = &gdisp->gcstate[mine->bitmap_col];
    1659             : 
    1660           0 :     _GXDraw_SetClipFunc(gdisp,mine);
    1661           0 :     if ( mine->fg!=gcs->fore_col || mine->func!=gcs->func || mine->func==df_xor ) {
    1662           0 :         if ( mine->bitmap_col ) {
    1663           0 :             vals.foreground = mine->fg;
    1664             :         } else {
    1665           0 :             vals.foreground = _GXDraw_GetScreenPixel(gdisp,mine->fg);
    1666             :         }
    1667           0 :         gcs->fore_col = mine->fg;
    1668           0 :         if ( mine->func==df_xor ) {
    1669           0 :             vals.foreground ^= _GXDraw_GetScreenPixel(gdisp,mine->xor_base);
    1670           0 :             gcs->fore_col = COLOR_UNKNOWN;
    1671             :         }
    1672           0 :         mask |= GCForeground;
    1673             :     }
    1674           0 :     if ( mine->bg!=gcs->back_col ) {
    1675           0 :         vals.background = _GXDraw_GetScreenPixel(gdisp,mine->bg);
    1676           0 :         mask |= GCBackground;
    1677           0 :         gcs->back_col = mine->bg;
    1678             :     }
    1679           0 :     if ( mine->ts != gcs->ts || mine->ts != 0 ||
    1680           0 :             mine->ts_xoff != gcs->ts_xoff ||
    1681           0 :             mine->ts_yoff != gcs->ts_yoff ) {
    1682           0 :         if ( mine->ts!=0 ) {
    1683           0 :             vals.stipple = mine->ts==1?gdisp->grey_stipple: gdisp->fence_stipple;
    1684           0 :             mask |= GCStipple;
    1685             :         }
    1686           0 :         vals.fill_style = (mine->ts?FillStippled:FillSolid);
    1687           0 :         vals.ts_x_origin = mine->ts_xoff;
    1688           0 :         vals.ts_y_origin = mine->ts_yoff;
    1689           0 :         mask |= GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle;
    1690           0 :         gcs->ts = mine->ts;
    1691           0 :         gcs->ts_xoff = mine->ts_xoff;
    1692           0 :         gcs->ts_yoff = mine->ts_yoff;
    1693             :     }
    1694           0 :     if ( mask!=0 )
    1695           0 :         XChangeGC(gdisp->display,gcs->gc,mask,&vals);
    1696           0 : return( true );
    1697             : }
    1698             : 
    1699           0 : static int GXDrawSetline(GXDisplay *gdisp, GGC *mine) {
    1700             :     XGCValues vals;
    1701           0 :     long mask=0;
    1702           0 :     GCState *gcs = &gdisp->gcstate[mine->bitmap_col];
    1703             : 
    1704           0 :     _GXDraw_SetClipFunc(gdisp,mine);
    1705           0 :     if ( mine->fg!=gcs->fore_col || mine->func!=gcs->func || mine->func==df_xor ) {
    1706           0 :         if ( mine->bitmap_col ) {
    1707           0 :             vals.foreground = mine->fg;
    1708             :         } else {
    1709           0 :             vals.foreground = _GXDraw_GetScreenPixel(gdisp,mine->fg);
    1710             :         }
    1711           0 :         gcs->fore_col = mine->fg;
    1712           0 :         if ( mine->func==df_xor ) {
    1713           0 :             vals.foreground ^= _GXDraw_GetScreenPixel(gdisp,mine->xor_base);
    1714           0 :             gcs->fore_col = COLOR_UNKNOWN;
    1715             :         }
    1716           0 :         mask |= GCForeground;
    1717             :     }
    1718           0 :     if ( mine->line_width==1 ) mine->line_width = 0;
    1719           0 :     if ( mine->line_width!=gcs->line_width ) {
    1720           0 :         vals.line_width = mine->line_width;
    1721           0 :         mask |= GCLineWidth;
    1722           0 :         gcs->line_width = mine->line_width;
    1723             :     }
    1724           0 :     if ( mine->dash_len != gcs->dash_len || mine->skip_len != gcs->skip_len ||
    1725           0 :             mine->dash_offset != gcs->dash_offset ) {
    1726           0 :         vals.line_style = mine->dash_len==0?LineSolid:LineOnOffDash;
    1727           0 :         mask |= GCLineStyle;
    1728           0 :         if ( vals.line_style!=LineSolid ) {
    1729           0 :             if ( mine->dash_len==mine->skip_len ) {
    1730           0 :                 vals.dash_offset = mine->dash_offset;
    1731           0 :                 vals.dashes = mine->dash_len;
    1732           0 :                 mask |= GCDashOffset|GCDashList;
    1733             :             } else {
    1734             :                 char dashes[2];
    1735           0 :                 dashes[0] = mine->dash_len; dashes[1] = mine->skip_len;
    1736           0 :                 XSetDashes(gdisp->display,gcs->gc,mine->dash_offset,dashes,2);
    1737             :             }
    1738             :         }
    1739           0 :         gcs->dash_offset = mine->dash_offset;
    1740           0 :         gcs->dash_len = mine->dash_len;
    1741           0 :         gcs->skip_len = mine->skip_len;
    1742             :     }
    1743           0 :     if ( mine->ts != gcs->ts ||
    1744           0 :             mine->ts_xoff != gcs->ts_xoff ||
    1745           0 :             mine->ts_yoff != gcs->ts_yoff ) {
    1746           0 :         if ( mine->ts!=0 ) {
    1747           0 :             vals.stipple = mine->ts==1 ? gdisp->grey_stipple : gdisp->fence_stipple;
    1748           0 :             mask |= GCStipple;
    1749           0 :             if ( !mine->bitmap_col ) {
    1750             :                 /* For reasons inexplicable to me, X sometimes draws with OpaqueStippled */
    1751           0 :                 vals.background = _GXDraw_GetScreenPixel(gdisp,gcs->back_col);
    1752           0 :                 mask |= GCBackground;
    1753             :             }
    1754             :         }
    1755           0 :         vals.fill_style = (mine->ts?FillStippled:FillSolid);
    1756           0 :         vals.ts_x_origin = mine->ts_xoff;
    1757           0 :         vals.ts_y_origin = mine->ts_yoff;
    1758           0 :         mask |= GCTileStipXOrigin|GCTileStipYOrigin|GCFillStyle;
    1759           0 :         gcs->ts = mine->ts;
    1760           0 :         gcs->ts_xoff = mine->ts_xoff;
    1761           0 :         gcs->ts_yoff = mine->ts_yoff;
    1762             :     }
    1763           0 :     if ( mask!=0 )
    1764           0 :         XChangeGC(gdisp->display,gcs->gc,mask,&vals);
    1765           0 : return( true );
    1766             : }
    1767             : 
    1768           0 : static void GXDrawPushClipOnly(GWindow w)
    1769             : {
    1770             : #ifndef _NO_LIBCAIRO
    1771           0 :     if ( ((GXWindow) w)->usecairo )
    1772           0 :         _GXCDraw_PushClipOnly((GXWindow) w);
    1773             : #endif
    1774           0 : }
    1775             : 
    1776           0 : static void GXDrawClipPreserve(GWindow w)
    1777             : {
    1778             : #ifndef _NO_LIBCAIRO
    1779           0 :     if ( ((GXWindow) w)->usecairo )
    1780           0 :         _GXCDraw_ClipPreserve((GXWindow) w);
    1781             : #endif
    1782           0 : }
    1783             : 
    1784             : 
    1785           0 : static void GXDrawPushClip(GWindow w, GRect *rct, GRect *old) {
    1786             :     /* return the current clip, and intersect the current clip with the desired */
    1787             :     /*  clip to get the new */
    1788           0 :     *old = w->ggc->clip;
    1789           0 :     w->ggc->clip = *rct;
    1790           0 :     if ( w->ggc->clip.x+w->ggc->clip.width>old->x+old->width )
    1791           0 :         w->ggc->clip.width = old->x+old->width-w->ggc->clip.x;
    1792           0 :     if ( w->ggc->clip.y+w->ggc->clip.height>old->y+old->height )
    1793           0 :         w->ggc->clip.height = old->y+old->height-w->ggc->clip.y;
    1794           0 :     if ( w->ggc->clip.x<old->x ) {
    1795           0 :         if ( w->ggc->clip.width > (old->x-w->ggc->clip.x))
    1796           0 :             w->ggc->clip.width -= (old->x-w->ggc->clip.x);
    1797             :         else
    1798           0 :             w->ggc->clip.width = 0;
    1799           0 :         w->ggc->clip.x = old->x;
    1800             :     }
    1801           0 :     if ( w->ggc->clip.y<old->y ) {
    1802           0 :         if ( w->ggc->clip.height > (old->y-w->ggc->clip.y))
    1803           0 :             w->ggc->clip.height -= (old->y-w->ggc->clip.y);
    1804             :         else
    1805           0 :             w->ggc->clip.height = 0;
    1806           0 :         w->ggc->clip.y = old->y;
    1807             :     }
    1808           0 :     if ( w->ggc->clip.height<0 || w->ggc->clip.width<0 ) {
    1809             :         /* Negative values mean large positive values, so if we want to clip */
    1810             :         /*  to nothing force clip outside window */
    1811           0 :         w->ggc->clip.x = w->ggc->clip.y = -100;
    1812           0 :         w->ggc->clip.height = w->ggc->clip.width = 1;
    1813             :     }
    1814             : #ifndef _NO_LIBCAIRO
    1815           0 :     if ( ((GXWindow) w)->usecairo )
    1816           0 :         _GXCDraw_PushClip((GXWindow) w);
    1817             : #endif
    1818           0 : }
    1819             : 
    1820           0 : static void GXDrawPopClip(GWindow w, GRect *old) {
    1821           0 :     w->ggc->clip = *old;
    1822             : #ifndef _NO_LIBCAIRO
    1823           0 :     if ( ((GXWindow) w)->usecairo )
    1824           0 :         _GXCDraw_PopClip((GXWindow) w);
    1825             : #endif
    1826           0 : }
    1827             : 
    1828             : 
    1829             : 
    1830           0 : static void GXDrawClear(GWindow gw, GRect *rect) {
    1831           0 :     GXWindow gxw = (GXWindow) gw;
    1832             : #ifndef _NO_LIBCAIRO
    1833           0 :     if ( gxw->usecairo )
    1834           0 :         _GXCDraw_Clear(gxw,rect);
    1835             :     else
    1836             : #endif
    1837             :     {
    1838           0 :         GXDisplay *display = (GXDisplay *) (gw->display);
    1839             : 
    1840           0 :         if ( rect==NULL )
    1841           0 :             XClearWindow(display->display,gxw->w);
    1842             :         else
    1843           0 :             XClearArea(display->display,gxw->w,
    1844           0 :                     rect->x,rect->y,rect->width,rect->height, false );
    1845             :     }
    1846           0 : }
    1847             : 
    1848           0 : static void GXDrawDrawLine(GWindow w, int32 x,int32 y, int32 xend,int32 yend, Color col) {
    1849           0 :     w->ggc->fg = col;
    1850             : 
    1851             : #ifndef _NO_LIBCAIRO
    1852           0 :     if ( ((GXWindow) w)->usecairo && w->ggc->func==df_copy ) {
    1853           0 :         _GXCDraw_DrawLine((GXWindow) w,x,y,xend,yend);
    1854             :     } else {
    1855           0 :         if (((GXWindow) w)->usecairo )
    1856           0 :             _GXCDraw_Flush((GXWindow) w);
    1857             : #endif
    1858             :     {
    1859           0 :         GXDisplay *display = (GXDisplay *) (w->display);
    1860           0 :         GXDrawSetline(display,w->ggc);
    1861           0 :         XDrawLine(display->display,((GXWindow) w)->w,display->gcstate[w->ggc->bitmap_col].gc,x,y,xend,yend);
    1862             :     }
    1863             : #ifndef _NO_LIBCAIRO
    1864           0 :         if (((GXWindow) w)->usecairo ) {
    1865           0 :             if ( xend<x ) { int temp = x; x = xend; xend=temp;}
    1866           0 :             if ( yend<y ) { int temp = y; y = yend; yend=temp;}
    1867           0 :             _GXCDraw_DirtyRect((GXWindow) w,x,y,xend-x+1,yend-y+1);
    1868             :         }
    1869             :     }
    1870             : #endif
    1871           0 : }
    1872             : 
    1873           0 : static void _DrawArrow(GXWindow gxw, int32 x, int32 y, int32 xother, int32 yother ) {
    1874           0 :     GXDisplay *display = gxw->display;
    1875             :     XPoint points[3];
    1876             :     double a;
    1877             :     int off1, off2;
    1878             :     double len;
    1879             : 
    1880           0 :     if ( x==xother && y==yother )
    1881           0 : return;
    1882           0 :     a = atan2(y-yother,x-xother);
    1883           0 :     len = sqrt((double) (x-xother)*(x-xother)+(y-yother)*(y-yother));
    1884           0 :     if ( len>20 ) len = 10; else len = 2*len/3;
    1885           0 :     if ( len<2 )
    1886           0 : return;
    1887             : 
    1888           0 :     points[0].x = x; points[0].y = y;
    1889           0 :     off1 = len*sin(a+3.1415926535897932/8)+.5; off2 = len*cos(a+3.1415926535897932/8)+.5;
    1890           0 :     points[1].x = x-off2; points[1].y = y-off1;
    1891           0 :     off1 = len*sin(a-3.1415926535897932/8)+.5; off2 = len*cos(a-3.1415926535897932/8)+.5;
    1892           0 :     points[2].x = x-off2; points[2].y = y-off1;
    1893           0 :     XFillPolygon(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,points,3,Complex,CoordModeOrigin);
    1894           0 :     XDrawLines(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,points,3,CoordModeOrigin);
    1895             : }
    1896             : 
    1897           0 : static void GXDrawDrawArrow(GWindow gw, int32 x,int32 y, int32 xend,int32 yend, int16 arrows, Color col) {
    1898           0 :     GXWindow gxw = (GXWindow) gw;
    1899           0 :     GXDisplay *display = gxw->display;
    1900             : 
    1901             : #ifndef _NO_LIBCAIRO
    1902           0 :     if ( gxw->usecairo )
    1903           0 :         GDrawIError("DrawArrow not supported");
    1904             : #endif
    1905           0 :     gxw->ggc->fg = col;
    1906           0 :     GXDrawSetline(display,gxw->ggc);
    1907           0 :     XDrawLine(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,x,y,xend,yend);
    1908           0 :     if ( arrows&1 )
    1909           0 :         _DrawArrow(gxw,x,y,xend,yend);
    1910           0 :     if ( arrows&2 )
    1911           0 :         _DrawArrow(gxw,xend,yend,x,y);
    1912           0 : }
    1913             : 
    1914           0 : static void GXDrawDrawRect(GWindow gw, GRect *rect, Color col) {
    1915           0 :     GXWindow gxw = (GXWindow) gw;
    1916             : 
    1917           0 :     gxw->ggc->fg = col;
    1918             : #ifndef _NO_LIBCAIRO
    1919           0 :     if ( gxw->usecairo && gw->ggc->func==df_copy ) {
    1920           0 :         _GXCDraw_DrawRect(gxw,rect);
    1921             :     } else {
    1922           0 :         if ( gxw->usecairo )
    1923           0 :             _GXCDraw_Flush(gxw);
    1924             : #endif
    1925             :     {
    1926           0 :         GXDisplay *display = gxw->display;
    1927             : 
    1928           0 :         GXDrawSetline(display,gxw->ggc);
    1929           0 :         XDrawRectangle(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,rect->x,rect->y,
    1930           0 :                 rect->width,rect->height);
    1931             :     }
    1932             : #ifndef _NO_LIBCAIRO
    1933           0 :         if ( gxw->usecairo )
    1934           0 :             _GXCDraw_DirtyRect(gxw,rect->x,rect->y,rect->width,rect->height);
    1935             :     }
    1936             : #endif
    1937           0 : }
    1938             : 
    1939           0 : static void GXDrawFillRect(GWindow gw, GRect *rect, Color col) {
    1940           0 :     GXWindow gxw = (GXWindow) gw;
    1941             : 
    1942           0 :     gxw->ggc->fg = col;
    1943             : #ifndef _NO_LIBCAIRO
    1944           0 :     if ( gxw->usecairo && gw->ggc->func==df_copy ) {
    1945           0 :         _GXCDraw_FillRect( gxw,rect);
    1946           0 : return;
    1947             :     } else {
    1948           0 :         if (gxw->usecairo )
    1949           0 :             _GXCDraw_Flush(gxw);
    1950             : #endif
    1951             :     {
    1952           0 :         GXDisplay *display = gxw->display;
    1953             : 
    1954           0 :         GXDrawSetcolfunc(display,gxw->ggc);
    1955           0 :         XFillRectangle(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,rect->x,rect->y,
    1956           0 :                 rect->width,rect->height);
    1957             :     }
    1958             : #ifndef _NO_LIBCAIRO
    1959           0 :         if (gxw->usecairo )
    1960           0 :             _GXCDraw_DirtyRect(gxw,rect->x,rect->y,rect->width,rect->height);
    1961             :     }
    1962             : #endif
    1963             : }
    1964             : 
    1965           0 : static void GXDrawFillRoundRect(GWindow gw, GRect *rect, int radius, Color col) {
    1966           0 :     GXWindow gxw = (GXWindow) gw;
    1967           0 :     int rr = radius <= (rect->height+1)/2 ? (radius > 0 ? radius : 0) : (rect->height+1)/2;
    1968             : 
    1969           0 :     gxw->ggc->fg = col;
    1970             : #ifndef _NO_LIBCAIRO
    1971           0 :     if ( gxw->usecairo && gw->ggc->func==df_copy ) {
    1972           0 :         _GXCDraw_FillRoundRect( gxw,rect,rr );
    1973           0 : return;
    1974             :     } else {
    1975           0 :         if (gxw->usecairo )
    1976           0 :             _GXCDraw_Flush(gxw);
    1977             : #endif
    1978             :     {
    1979           0 :         GRect middle = {rect->x, rect->y + radius, rect->width, rect->height - 2 * radius};
    1980           0 :         int xend = rect->x + rect->width - 1;
    1981           0 :         int yend = rect->y + rect->height - 1;
    1982           0 :         int precalc = rr * 2 - 1;
    1983             :         int i, xoff;
    1984             : 
    1985           0 :         for (i = 0; i < rr; i++) {
    1986           0 :             xoff = rr - lrint(sqrt( (double)(i * (precalc - i)) ));
    1987           0 :             GXDrawDrawLine(gw, rect->x + xoff, rect->y + i, xend - xoff, rect->y + i, col);
    1988           0 :             GXDrawDrawLine(gw, rect->x + xoff, yend - i, xend - xoff, yend - i, col);
    1989             :         }
    1990           0 :         GXDrawFillRect(gw, &middle, col);
    1991             :     }
    1992             : #ifndef _NO_LIBCAIRO
    1993           0 :         if (gxw->usecairo )
    1994           0 :             _GXCDraw_DirtyRect(gxw,rect->x,rect->y,rect->width,rect->height);
    1995             :     }
    1996             : #endif
    1997             : }
    1998             : 
    1999           0 : static void GXDrawDrawElipse(GWindow gw, GRect *rect, Color col) {
    2000           0 :     GXWindow gxw = (GXWindow) gw;
    2001             : 
    2002           0 :     gxw->ggc->fg = col;
    2003             : #ifndef _NO_LIBCAIRO
    2004           0 :     if ( gxw->usecairo ) {
    2005           0 :         _GXCDraw_DrawEllipse( gxw,rect);
    2006             :     } else
    2007             : #endif
    2008             :     {
    2009           0 :         GXDisplay *display = gxw->display;
    2010             : 
    2011           0 :         GXDrawSetline(display,gxw->ggc);
    2012           0 :         XDrawArc(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,rect->x,rect->y,
    2013           0 :                 rect->width,rect->height,0,360*64);
    2014             :     }
    2015           0 : }
    2016             : 
    2017           0 : static void GXDrawDrawArc(GWindow gw, GRect *rect, int32 sangle, int32 tangle, Color col) {
    2018           0 :     GXWindow gxw = (GXWindow) gw;
    2019           0 :     GXDisplay *display = gxw->display;
    2020           0 :     gxw->ggc->fg = col;
    2021           0 :     GXDrawSetline(display,gxw->ggc);
    2022           0 :     XDrawArc(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,rect->x,rect->y,
    2023           0 :             rect->width,rect->height,
    2024             :             sangle,tangle );
    2025           0 : }
    2026             : 
    2027           0 : static void GXDrawFillElipse(GWindow gw, GRect *rect, Color col) {
    2028           0 :     GXWindow gxw = (GXWindow) gw;
    2029           0 :     GXDisplay *display = gxw->display;
    2030             : 
    2031           0 :     gxw->ggc->fg = col;
    2032             : #ifndef _NO_LIBCAIRO
    2033           0 :     if ( gxw->usecairo ) {
    2034           0 :         _GXCDraw_FillEllipse( gxw,rect);
    2035             :     } else
    2036             : #endif
    2037             :     {
    2038           0 :         GXDrawSetcolfunc(display,gxw->ggc);
    2039           0 :         XFillArc(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,rect->x,rect->y,
    2040           0 :                 rect->width,rect->height,0,360*64);
    2041             :     }
    2042           0 : }
    2043             : 
    2044           0 : static void GXDrawDrawPoly(GWindow gw, GPoint *pts, int16 cnt, Color col) {
    2045           0 :     GXWindow gxw = (GXWindow) gw;
    2046           0 :     GXDisplay *display = gxw->display;
    2047             : 
    2048           0 :     gxw->ggc->fg = col;
    2049             : #ifndef _NO_LIBCAIRO
    2050           0 :     if ( gxw->usecairo ) {
    2051           0 :         _GXCDraw_DrawPoly( gxw,pts,cnt);
    2052             :     } else
    2053             : #endif
    2054             :     {
    2055           0 :         GXDrawSetline(display,gxw->ggc);
    2056           0 :         XDrawLines(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,(XPoint *) pts,cnt,CoordModeOrigin);
    2057             :     }
    2058           0 : }
    2059             : 
    2060           0 : static void GXDrawFillPoly(GWindow gw, GPoint *pts, int16 cnt, Color col) {
    2061           0 :     GXWindow gxw = (GXWindow) gw;
    2062           0 :     GXDisplay *display = gxw->display;
    2063             : 
    2064           0 :     gxw->ggc->fg = col;
    2065             : #ifndef _NO_LIBCAIRO
    2066           0 :     if ( gxw->usecairo ) {
    2067           0 :         _GXCDraw_FillPoly( gxw,pts,cnt);
    2068             :     } else
    2069             : #endif
    2070             :     {
    2071           0 :         GXDrawSetline(display,gxw->ggc);             /* Polygons draw their borders too! so we need the line mode */
    2072           0 :         GXDrawSetcolfunc(display,gxw->ggc);  
    2073           0 :         XFillPolygon(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,(XPoint *) pts,cnt,Complex,CoordModeOrigin);
    2074           0 :         XDrawLines(display->display,gxw->w,display->gcstate[gxw->ggc->bitmap_col].gc,(XPoint *) pts,cnt,CoordModeOrigin);
    2075             :     }
    2076           0 : }
    2077             : 
    2078             : #ifndef _NO_LIBCAIRO
    2079           0 : static enum gcairo_flags GXDrawHasCairo(GWindow w) {
    2080           0 :     if ( ((GXWindow) w)->usecairo )
    2081           0 : return( _GXCDraw_CairoCapabilities( (GXWindow) w));
    2082             : 
    2083           0 : return( gc_xor );
    2084             : }
    2085             : 
    2086           0 : static void GXDrawPathStartNew(GWindow w) {
    2087           0 :     if ( !((GXWindow) w)->usecairo )
    2088           0 : return;
    2089           0 :     _GXCDraw_PathStartNew(w);
    2090             : }
    2091             : 
    2092           0 : static void GXDrawPathStartSubNew(GWindow w) {
    2093           0 :     if ( !((GXWindow) w)->usecairo )
    2094           0 : return;
    2095           0 :     _GXCDraw_PathStartSubNew(w);
    2096             : }
    2097             : 
    2098           0 : static int GXDrawFillRuleSetWinding(GWindow w) {
    2099           0 :     if ( !((GXWindow) w)->usecairo )
    2100           0 : return 0;
    2101           0 :     return _GXCDraw_FillRuleSetWinding(w);
    2102             : }
    2103             : 
    2104           0 : static void GXDrawPathClose(GWindow w) {
    2105           0 :     if ( !((GXWindow) w)->usecairo )
    2106           0 : return;
    2107           0 :     _GXCDraw_PathClose(w);
    2108             : }
    2109             : 
    2110           0 : static void GXDrawPathMoveTo(GWindow w,double x, double y) {
    2111           0 :     if ( !((GXWindow) w)->usecairo )
    2112           0 : return;
    2113           0 :     _GXCDraw_PathMoveTo(w,x,y);
    2114             : }
    2115             : 
    2116           0 : static void GXDrawPathLineTo(GWindow w,double x, double y) {
    2117           0 :     if ( !((GXWindow) w)->usecairo )
    2118           0 : return;
    2119           0 :     _GXCDraw_PathLineTo(w,x,y);
    2120             : }
    2121             : 
    2122           0 : static void GXDrawPathCurveTo(GWindow w,
    2123             :                     double cx1, double cy1,
    2124             :                     double cx2, double cy2,
    2125             :                     double x, double y) {
    2126           0 :     if ( !((GXWindow) w)->usecairo )
    2127           0 : return;
    2128           0 :     _GXCDraw_PathCurveTo(w,cx1,cy1,cx2,cy2,x,y);
    2129             : }
    2130             : 
    2131           0 : static void GXDrawPathStroke(GWindow w,Color col) {
    2132           0 :     if ( !((GXWindow) w)->usecairo )
    2133           0 : return;
    2134           0 :     _GXCDraw_PathStroke(w,col);
    2135             : }
    2136             : 
    2137           0 : static void GXDrawPathFill(GWindow w,Color col) {
    2138           0 :     if ( !((GXWindow) w)->usecairo )
    2139           0 : return;
    2140           0 :     _GXCDraw_PathFill(w,col);
    2141             : }
    2142             : 
    2143           0 : static void GXDrawPathFillAndStroke(GWindow w,Color fillcol, Color strokecol) {
    2144           0 :     if ( !((GXWindow) w)->usecairo )
    2145           0 : return;
    2146           0 :     _GXCDraw_PathFillAndStroke(w,fillcol,strokecol);
    2147             : }
    2148             : 
    2149             : #else
    2150             : static enum gcairo_flags GXDrawHasCairo(GWindow w) {
    2151             : return( gc_xor );
    2152             : }
    2153             : 
    2154             : static void GXDrawPathStartNew(GWindow w) {
    2155             : }
    2156             : 
    2157             : static void GXDrawPathStartSubNew(GWindow w) {
    2158             : }
    2159             : 
    2160             : static int GXDrawFillRuleSetWinding(GWindow w) {
    2161             :     return 0;
    2162             : }
    2163             : 
    2164             : static void GXDrawPathClose(GWindow w) {
    2165             : }
    2166             : 
    2167             : static void GXDrawPathMoveTo(GWindow w,double x, double y) {
    2168             : }
    2169             : 
    2170             : static void GXDrawPathLineTo(GWindow w,double x, double y) {
    2171             : }
    2172             : 
    2173             : static void GXDrawPathCurveTo(GWindow w,
    2174             :                     double cx1, double cy1,
    2175             :                     double cx2, double cy2,
    2176             :                     double x, double y) {
    2177             : }
    2178             : 
    2179             : static void GXDrawPathStroke(GWindow w,Color col) {
    2180             : }
    2181             : 
    2182             : static void GXDrawPathFill(GWindow w,Color col) {
    2183             : }
    2184             : 
    2185             : static void GXDrawPathFillAndStroke(GWindow w,Color fillcol, Color strokecol) {
    2186             : }
    2187             : 
    2188             : #endif
    2189             : 
    2190           0 : static void GXDrawLayoutInit(GWindow w, char *text, int cnt, GFont *fi) {
    2191           0 :     _GXPDraw_LayoutInit(w,text,cnt,fi);
    2192           0 : }
    2193             : 
    2194           0 : static void GXDraw_LayoutDraw(GWindow w, int32 x, int32 y, Color fg) {
    2195           0 :     _GXPDraw_LayoutDraw(w,x,y,fg);
    2196           0 : }
    2197             : 
    2198           0 : static void GXDraw_LayoutIndexToPos(GWindow w, int index, GRect *pos) {
    2199           0 :     _GXPDraw_LayoutIndexToPos(w,index,pos);
    2200           0 : }
    2201             : 
    2202           0 : static int GXDraw_LayoutXYToIndex(GWindow w, int x, int y) {
    2203           0 : return( _GXPDraw_LayoutXYToIndex(w,x,y));
    2204             : }
    2205             : 
    2206           0 : static void GXDraw_LayoutExtents(GWindow w, GRect *size) {
    2207           0 :     _GXPDraw_LayoutExtents(w,size);
    2208           0 : }
    2209             : 
    2210           0 : static void GXDraw_LayoutSetWidth(GWindow w, int width) {
    2211           0 :     _GXPDraw_LayoutSetWidth(w,width);
    2212           0 : }
    2213             : 
    2214           0 : static int GXDraw_LayoutLineCount(GWindow w) {
    2215           0 : return( _GXPDraw_LayoutLineCount(w));
    2216             : }
    2217             : 
    2218           0 : static int GXDraw_LayoutLineStart(GWindow w, int l) {
    2219           0 : return( _GXPDraw_LayoutLineStart(w, l));
    2220             : }
    2221             : 
    2222           0 : static void GXDrawSendExpose(GXWindow gw, int x,int y,int wid,int hei ) {
    2223           0 :     if ( gw->eh!=NULL ) {
    2224             :         struct gevent event;
    2225           0 :         memset(&event,0,sizeof(event));
    2226           0 :         event.type = et_expose;
    2227           0 :         if ( x<0 ) { wid += x; x = 0; }
    2228           0 :         if ( y<0 ) { hei += y; y = 0; }
    2229           0 :         event.u.expose.rect.x = x;
    2230           0 :         event.u.expose.rect.y = y;
    2231           0 :         if ( x+wid>gw->pos.width ) wid = gw->pos.width-x;
    2232           0 :         if ( y+hei>gw->pos.height ) hei = gw->pos.height-y;
    2233           0 :         if ( wid<0 || hei<0 )
    2234           0 : return;
    2235           0 :         event.u.expose.rect.width = wid;
    2236           0 :         event.u.expose.rect.height = hei;
    2237           0 :         event.w = (GWindow) gw;
    2238           0 :         event.native_window = ((GWindow) gw)->native_window;
    2239           0 :         (gw->eh)((GWindow ) gw,&event);
    2240             :     }
    2241             : }
    2242             : 
    2243           0 : static void GXDrawScroll(GWindow _w, GRect *rect, int32 hor, int32 vert) {
    2244           0 :     GXWindow gw = (GXWindow) _w;
    2245           0 :     GXDisplay *gdisp = gw->display;
    2246             :     GRect temp, old;
    2247             : 
    2248           0 :     vert = -vert;
    2249             : 
    2250           0 :     if ( rect == NULL ) {
    2251           0 :         temp.x = temp.y = 0; temp.width = gw->pos.width; temp.height = gw->pos.height;
    2252           0 :         rect = &temp;
    2253             :     }
    2254             : 
    2255             :     /*GDrawForceUpdate((GWindow) gw); */        /* need to make sure the screen holds what it should */
    2256             :                 /* but user has to do it, it's probably too late here */
    2257           0 :     GDrawPushClip(_w,rect,&old);
    2258             : #ifdef _COMPOSITE_BROKEN
    2259             :     GXDrawSendExpose(gw,0,0,gw->pos.width,gw->pos.height);
    2260             : #else
    2261           0 :     _GXDraw_SetClipFunc(gdisp,gw->ggc);
    2262             : #ifndef _NO_LIBCAIRO
    2263           0 :     if ( gw->usecairo ) {
    2264             :         /* Cairo can happily scroll the window -- except it doesn't know about*/
    2265             :         /*  child windows, and so we don't get the requisit events to redraw */
    2266             :         /*  areas covered by children. Rats. */
    2267           0 :         GXDrawSendExpose(gw,rect->x,rect->y,rect->x+rect->width,rect->y+rect->height);
    2268           0 :         GXDrawPopClip(_w,&old);
    2269           0 : return;
    2270             :         /* _GXCDraw_CopyArea(gw,gw,rect,rect->x+hor,rect->y+vert); */
    2271             :     } else
    2272             : #endif
    2273           0 :         XCopyArea(gdisp->display,gw->w,gw->w,gdisp->gcstate[gw->ggc->bitmap_col].gc,
    2274           0 :                 rect->x,rect->y,  rect->width,rect->height,
    2275           0 :                 rect->x+hor,rect->y+vert);
    2276           0 :     if ( hor>0 )
    2277           0 :         GXDrawSendExpose(gw,rect->x,rect->y, hor,rect->height);
    2278           0 :     else if ( hor<0 )
    2279           0 :         GXDrawSendExpose(gw,rect->x+rect->width+hor,rect->y,-hor,rect->height);
    2280           0 :     if ( vert>0 )
    2281           0 :         GXDrawSendExpose(gw,rect->x,rect->y,rect->width,vert);
    2282           0 :     else if ( vert<0 )
    2283           0 :         GXDrawSendExpose(gw,rect->x,rect->y+rect->height+vert,rect->width,-vert);
    2284             : #endif
    2285           0 :     GXDrawPopClip(_w,&old);
    2286             : }
    2287             : 
    2288           0 : static void _GXDraw_Pixmap( GWindow _w, GWindow _pixmap, GRect *src, int32 x, int32 y) {
    2289           0 :     GXWindow gw = (GXWindow) _w, pixmap = (GXWindow) _pixmap;
    2290           0 :     GXDisplay *gdisp = gw->display;
    2291             : 
    2292           0 :     if ( pixmap->ggc->bitmap_col ) {
    2293           0 :         GXDrawSetcolfunc(gdisp,gw->ggc);
    2294           0 :         XCopyPlane(gdisp->display,pixmap->w,gw->w,gdisp->gcstate[gw->ggc->bitmap_col].gc,
    2295           0 :                 src->x,src->y,    src->width,src->height,
    2296             :                 x,y,1);
    2297             :     } else {
    2298           0 :         _GXDraw_SetClipFunc(gdisp,gw->ggc);
    2299             : #ifndef _NO_LIBCAIRO
    2300             :         /* FIXME: _GXCDraw_CopyArea makes the glyph dissabear in the class kern
    2301             :          * dialog */
    2302             :         if ( 0 && gw->usecairo )
    2303             :             _GXCDraw_CopyArea(pixmap,gw,src,x,y);
    2304             :         else
    2305             : #endif
    2306           0 :             XCopyArea(gdisp->display,pixmap->w,gw->w,gdisp->gcstate[gw->ggc->bitmap_col].gc,
    2307           0 :                     src->x,src->y,        src->width,src->height,
    2308             :                     x,y);
    2309             :     }
    2310           0 : }
    2311             : 
    2312           0 : static void _GXDraw_TilePixmap( GWindow _w, GWindow _pixmap, GRect *src, int32 x, int32 y) {
    2313           0 :     GXWindow gw = (GXWindow) _w, pixmap = (GXWindow) _pixmap;
    2314           0 :     GXDisplay *gdisp = gw->display;
    2315             :     GRect old;
    2316             :     int i,j;
    2317             : 
    2318           0 :     GDrawPushClip(_w,src,&old);
    2319           0 :     GXDrawSetcolfunc(gdisp,gw->ggc);
    2320           0 :     for ( i=y; i<gw->ggc->clip.y+gw->ggc->clip.height; i+=pixmap->pos.height ) {
    2321           0 :         if ( i+pixmap->pos.height<gw->ggc->clip.y )
    2322           0 :     continue;
    2323           0 :         for ( j=x; j<gw->ggc->clip.x+gw->ggc->clip.width; j+=pixmap->pos.width ) {
    2324           0 :             if ( j+pixmap->pos.width<gw->ggc->clip.x )
    2325           0 :         continue;
    2326           0 :             if ( pixmap->ggc->bitmap_col ) {
    2327           0 :                 XCopyPlane(gdisp->display,((GXWindow) pixmap)->w,gw->w,gdisp->gcstate[1].gc,
    2328           0 :                         0,0,  pixmap->pos.width, pixmap->pos.height,
    2329             :                         j,i,1);
    2330             : #ifndef _NO_LIBCAIRO
    2331           0 :             } else if ( gw->usecairo ) {
    2332           0 :                 _GXCDraw_CopyArea(pixmap,gw,&pixmap->pos,j,i);
    2333             : #endif
    2334             :             } else {
    2335           0 :                 XCopyArea(gdisp->display,((GXWindow) pixmap)->w,gw->w,gdisp->gcstate[0].gc,
    2336           0 :                         0,0,  pixmap->pos.width, pixmap->pos.height,
    2337             :                         j,i);
    2338             :             }
    2339             :         }
    2340             :     }
    2341           0 :     GDrawPopClip(_w,&old);
    2342           0 : }
    2343             : 
    2344           0 : static void GXDrawFontMetrics( GWindow w,GFont *fi,int *as, int *ds, int *ld) {
    2345           0 :     _GXPDraw_FontMetrics(w, fi, as, ds, ld);
    2346           0 : }
    2347             :     
    2348             : 
    2349           0 : static GIC *GXDrawCreateInputContext(GWindow w,enum gic_style def_style) {
    2350             :     static int styles[] = { XIMPreeditNone | XIMStatusNone,
    2351             :             XIMPreeditNothing | XIMStatusNothing,
    2352             :             XIMPreeditPosition | XIMStatusNothing };
    2353             :     int i;
    2354           0 :     XIC ic = 0;
    2355             :     struct gxinput_context *gic;
    2356           0 :     GXDisplay *gdisp = (GXDisplay *) (w->display);
    2357             :     unsigned long fevent;
    2358             :     XWindowAttributes win_attrs;
    2359             :     XVaNestedList listp, lists;
    2360             : 
    2361           0 :     if ( gdisp->im==NULL )
    2362           0 : return( NULL );
    2363             : 
    2364           0 :     gic = calloc(1,sizeof(struct gxinput_context));
    2365           0 :     gic->w = w;
    2366           0 :     gic->ploc.y = 20; gic->sloc.y = 40;
    2367           0 :     listp = XVaCreateNestedList(0, XNFontSet, gdisp->def_im_fontset,
    2368             :                     XNForeground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_foreground),
    2369             :                     XNBackground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_background),
    2370             :                     XNSpotLocation, &gic->ploc, NULL);
    2371           0 :     lists = XVaCreateNestedList(0, XNFontSet, gdisp->def_im_fontset,
    2372             :                     XNForeground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_foreground),
    2373             :                     XNBackground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_background),
    2374             :                     XNSpotLocation, &gic->sloc, NULL);
    2375           0 :     for ( i=(def_style&gic_type); i>=gic_hidden; --i ) {
    2376           0 :         ic = XCreateIC(gdisp->im,XNInputStyle,styles[i],
    2377             :                     XNClientWindow, ((GXWindow) w)->w,
    2378             :                     XNFocusWindow, ((GXWindow) w)->w,
    2379             :                     XNPreeditAttributes, listp,
    2380             :                     XNStatusAttributes, lists,
    2381             :                     NULL );
    2382           0 :         if ( ic!=0 )
    2383           0 :     break;
    2384           0 :         if ( !(def_style&gic_orlesser) )
    2385           0 :     break;
    2386             :     }
    2387           0 :     XFree(lists); XFree(listp);
    2388           0 :     if ( ic==0 ) {
    2389           0 :         free(gic);
    2390           0 : return( NULL );
    2391             :     }
    2392             : 
    2393           0 :     gic->style = i;
    2394           0 :     gic->w = w;
    2395           0 :     gic->ic = ic;
    2396           0 :     gic->next = ((GXWindow) w)->all;
    2397           0 :     ((GXWindow) w)->all = gic;
    2398             : 
    2399             :     /* Now make sure we get all the events the IC needs */
    2400           0 :     XGetWindowAttributes(gdisp->display, ((GXWindow) w)->w, &win_attrs);
    2401           0 :     XGetICValues(ic, XNFilterEvents, &fevent, NULL);
    2402           0 :     XSelectInput(gdisp->display, ((GXWindow) w)->w, fevent|win_attrs.your_event_mask);
    2403             : 
    2404           0 : return( (GIC *) gic );
    2405             : }
    2406             : 
    2407           0 : static void GXDrawSetGIC(GWindow w, GIC *_gic, int x, int y) {
    2408           0 :     struct gxinput_context *gic = (struct gxinput_context *) _gic;
    2409             :     XVaNestedList listp, lists;
    2410           0 :     GXDisplay *gdisp = (GXDisplay *) (w->display);
    2411             : 
    2412           0 :     if ( x==10000 && y==x && gic!=NULL ) {
    2413           0 :         XUnsetICFocus(gic->ic);
    2414           0 :     } else if ( gic!=NULL ) {
    2415           0 :         gic->ploc.x = x;
    2416           0 :         gic->ploc.y = y;
    2417           0 :         gic->sloc.x = x;
    2418           0 :         gic->sloc.y = y+20;
    2419           0 :         XSetICFocus(gic->ic);
    2420           0 :         if ( gic->style==gic_overspot ) {
    2421           0 :             listp = XVaCreateNestedList(0, XNFontSet, gdisp->def_im_fontset,
    2422             :                     XNForeground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_foreground),
    2423             :                     XNBackground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_background),
    2424             :                     XNSpotLocation, &gic->ploc, NULL);
    2425           0 :             lists = XVaCreateNestedList(0, XNFontSet, gdisp->def_im_fontset,
    2426             :                     XNForeground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_foreground),
    2427             :                     XNBackground, _GXDraw_GetScreenPixel(gdisp,gdisp->def_background),
    2428             :                     XNSpotLocation, &gic->sloc, NULL);
    2429           0 :             XSetICValues(gic->ic,
    2430             :                     XNPreeditAttributes, listp,
    2431             :                     XNStatusAttributes, lists,
    2432             :                     NULL );
    2433           0 :             XFree(listp); XFree(lists);
    2434             :         }
    2435             :     }
    2436           0 :     ((GXWindow) w)->gic = gic;
    2437           0 : }
    2438             : 
    2439           0 : int _GXDraw_WindowOrParentsDying(GXWindow gw) {
    2440           0 :     while ( gw!=NULL ) {
    2441           0 :         if ( gw->is_dying )
    2442           0 : return( true );
    2443           0 :         if ( gw->is_toplevel )
    2444           0 : return( false );
    2445           0 :         gw = gw->parent;
    2446             :     }
    2447           0 : return( false );
    2448             : }
    2449             : 
    2450           0 : static void GXDrawRequestExpose(GWindow gw, GRect *rect,int doclear) {
    2451           0 :     GXWindow gxw = (GXWindow) gw;
    2452           0 :     GXDisplay *display = (GXDisplay *) (gw->display);
    2453             :     GRect temp;
    2454             : 
    2455           0 :     if ( !gw->is_visible || _GXDraw_WindowOrParentsDying(gxw) )
    2456           0 : return;
    2457           0 :     if ( rect==NULL ) {
    2458           0 :         temp.x = temp.y = 0;
    2459           0 :         temp.width = gxw->pos.width; temp.height = gxw->pos.height;
    2460           0 :         rect = &temp;
    2461           0 :     } else if ( rect->x<0 || rect->y<0 || rect->x+rect->width>gw->pos.width ||
    2462           0 :             rect->y+rect->height>gw->pos.height ) {
    2463           0 :         temp = *rect;
    2464           0 :         if ( temp.x < 0 ) { temp.width += temp.x; temp.x = 0; }
    2465           0 :         if ( temp.y < 0 ) { temp.height += temp.y; temp.y = 0; }
    2466           0 :         if ( temp.x+temp.width>gw->pos.width )
    2467           0 :             temp.width = gw->pos.width - temp.x;
    2468           0 :         if ( temp.y+temp.height>gw->pos.height )
    2469           0 :             temp.height = gw->pos.height - temp.y;
    2470           0 :         if ( temp.height<=0 || temp.width <= 0 )
    2471           0 : return;
    2472           0 :         rect = &temp;
    2473             :     }
    2474             :     /* Don't simply XClearArea with exposures == True, flicker is noticeable */
    2475           0 :     if ( doclear )
    2476           0 :         XClearArea(display->display,gxw->w,rect->x,rect->y,rect->width,rect->height, false );
    2477           0 :     if ( gw->eh!=NULL ) {
    2478             :         struct gevent event;
    2479           0 :         memset(&event,0,sizeof(event));
    2480           0 :         event.type = et_expose;
    2481           0 :         event.u.expose.rect = *rect;
    2482           0 :         event.w = gw;
    2483           0 :         event.native_window = gw->native_window;
    2484           0 :         (gw->eh)(gw,&event);
    2485             :     }
    2486             : }
    2487             : 
    2488           0 : static void GTimerSetNext(GTimer *timer,int32 time_from_now) {
    2489             :     struct timeval tv;
    2490             : 
    2491           0 :     gettimeofday(&tv,NULL);
    2492           0 :     timer->time_sec  = tv.tv_sec +time_from_now/1000;
    2493           0 :     timer->time_usec = tv.tv_usec+(time_from_now%1000)*1000;
    2494           0 :     if ( timer->time_usec>=1000000 ) {
    2495           0 :         ++timer->time_sec;
    2496           0 :         timer->time_usec-=1000000;
    2497             :     }
    2498           0 : }
    2499             : 
    2500           0 : static void GTimerInsertOrdered(GXDisplay *gdisp,GTimer *timer) {
    2501             :     GTimer *prev, *test;
    2502             : 
    2503           0 :     if ( gdisp->timers==NULL ) {
    2504           0 :         gdisp->timers = timer;
    2505           0 :         timer->next = NULL;
    2506           0 :     } else if ( gdisp->timers->time_sec>timer->time_sec ||
    2507           0 :             ( gdisp->timers->time_sec==timer->time_sec && gdisp->timers->time_usec>timer->time_usec )) {
    2508           0 :         timer->next = gdisp->timers;
    2509           0 :         gdisp->timers = timer;
    2510             :     } else {
    2511           0 :         prev = gdisp->timers;
    2512           0 :         for ( test = prev->next; test!=NULL; prev=test, test=test->next )
    2513           0 :             if ( test->time_sec>timer->time_sec ||
    2514           0 :                     ( test->time_sec==timer->time_sec && test->time_usec>timer->time_usec ))
    2515             :         break;
    2516           0 :         timer->next = test;
    2517           0 :         prev->next = timer;
    2518             :     }
    2519           0 : }
    2520             : 
    2521           0 : static int GTimerRemove(GXDisplay *gdisp,GTimer *timer) {
    2522             :     GTimer *prev, *test;
    2523             : 
    2524           0 :     if ( gdisp->timers==timer )
    2525           0 :         gdisp->timers = timer->next;
    2526             :     else {
    2527           0 :         prev = gdisp->timers;
    2528           0 :         if ( prev==NULL )
    2529           0 : return( false );
    2530           0 :         for ( test = prev->next; test!=NULL && test!=timer; prev=test, test=test->next );
    2531           0 :         if ( test==NULL )               /* Wasn't in the list, oh well */
    2532           0 : return(false);
    2533           0 :         prev->next = timer->next;
    2534             :     }
    2535           0 : return( true );
    2536             : }
    2537             : 
    2538           0 : static void GTimerRemoveWindowTimers(GXWindow gw) {
    2539             :     GTimer *prev, *test, *next;
    2540           0 :     GXDisplay *gdisp = gw->display;
    2541             : 
    2542           0 :     while ( gdisp->timers && gdisp->timers->owner==(GWindow) gw )
    2543           0 :         gdisp->timers = gdisp->timers->next;
    2544           0 :     prev = gdisp->timers;
    2545           0 :     if ( prev==NULL )
    2546           0 : return;
    2547           0 :     for ( test = prev->next; test!=NULL; ) {
    2548           0 :         next = test->next;
    2549           0 :         if ( test->owner==(GWindow) gw ) {
    2550           0 :             prev->next = next;
    2551           0 :             free(test);
    2552             :         } else
    2553           0 :             prev = test;
    2554           0 :         test = next;
    2555             :     }
    2556             : }
    2557             : 
    2558           0 : static int GTimerInList(GXDisplay *gdisp,GTimer *timer) {
    2559             :     GTimer *test;
    2560             : 
    2561           0 :     for ( test=gdisp->timers; test!=NULL; test = test->next )
    2562           0 :         if ( test==timer )
    2563           0 : return( true );
    2564             : 
    2565           0 : return( false );
    2566             : }
    2567             : 
    2568           0 : static void GTimerReinstall(GXDisplay *gdisp,GTimer *timer) {
    2569             : 
    2570           0 :     GTimerRemove(gdisp,timer);
    2571           0 :     if ( timer->repeat_time!=0 ) {
    2572           0 :         GTimerSetNext(timer,timer->repeat_time);
    2573           0 :         GTimerInsertOrdered(gdisp,timer);
    2574             :     } else
    2575           0 :         free(timer);
    2576           0 : }
    2577             : 
    2578           0 : static GTimer *GXDrawRequestTimer(GWindow w,int32 time_from_now,int32 frequency,
    2579             :         void *userdata) {
    2580           0 :     GTimer *timer = calloc(1,sizeof(GTimer));
    2581             : 
    2582           0 :     GTimerSetNext(timer,time_from_now);
    2583             : 
    2584           0 :     timer->owner = w;
    2585           0 :     timer->repeat_time = frequency;
    2586           0 :     timer->userdata = userdata;
    2587           0 :     timer->active = false;
    2588           0 :     GTimerInsertOrdered(((GXWindow) w)->display,timer);
    2589           0 : return( timer );
    2590             : }
    2591             : 
    2592           0 : static void GXDrawCancelTimer(GTimer *timer) {
    2593           0 :     GXDisplay *gdisp = ((GXWindow) (timer->owner))->display;
    2594             : 
    2595           0 :     if ( GTimerRemove(gdisp,timer))
    2596           0 :         free(timer);
    2597           0 : }
    2598             : 
    2599           0 : static void GXDrawSyncThread(GDisplay *gd, void (*func)(void *), void *data) {
    2600             : #ifdef HAVE_PTHREAD_H
    2601           0 :     GXDisplay *gdisp = (GXDisplay *) gd;
    2602             :     struct things_to_do *ttd;
    2603             : 
    2604           0 :     pthread_mutex_lock(&gdisp->xthread.sync_mutex);
    2605           0 :     if ( gdisp->xthread.sync_sock==-1 ) {
    2606             :         #if !defined(__MINGW32__)
    2607             :         int sv[2];
    2608           0 :         socketpair(PF_UNIX,SOCK_DGRAM,0,sv);
    2609           0 :         gdisp->xthread.sync_sock = sv[0];
    2610           0 :         gdisp->xthread.send_sock = sv[1];
    2611             :         #endif
    2612             :     }
    2613           0 :     if ( func==NULL ) {
    2614             :         /* what's the point in calling this routine with no function? */
    2615             :         /*  it sets things up so that the event loop is prepared to be */
    2616             :         /*  stopped by the new socket. (otherwise it doesn't stop till */
    2617             :         /*  it gets its next event. ie. if the eventloop is entered with */
    2618             :         /*  sync_sock==-1 it won't wait on it, but next time it's entered*/
    2619             :         /*  it won't be -1. This just allows us to make that condition */
    2620             :         /*  true a little earlier */
    2621             :     } else {
    2622           0 :         for ( ttd=gdisp->xthread.things_to_do; ttd!=NULL &&
    2623           0 :                 (ttd->func!=func || ttd->data!=data); ttd = ttd->next );
    2624           0 :         if ( ttd==NULL ) {
    2625           0 :             ttd = malloc(sizeof(struct things_to_do));
    2626           0 :             if ( gdisp->xthread.things_to_do==NULL )
    2627           0 :                 send(gdisp->xthread.send_sock," ",1,0);
    2628           0 :             ttd->func = func;
    2629           0 :             ttd->data = data;
    2630           0 :             ttd->next = gdisp->xthread.things_to_do;
    2631           0 :             gdisp->xthread.things_to_do = ttd;
    2632             :         }
    2633             :     }
    2634           0 :     pthread_mutex_unlock(&gdisp->xthread.sync_mutex);
    2635             : #else
    2636             :     (func)(data);
    2637             : #endif
    2638           0 : }
    2639             : 
    2640           0 : static int GXDrawProcessTimerEvent(GXDisplay *gdisp,GTimer *timer) {
    2641             :     struct gevent gevent;
    2642             :     GWindow o;
    2643           0 :     int ret = false;
    2644             : 
    2645           0 :     if ( timer->active )
    2646           0 : return( false );
    2647           0 :     timer->active = true;
    2648           0 :     for ( o = timer->owner; o!=NULL && !o->is_dying; o=o->parent );
    2649           0 :     if ( timer->owner!=NULL && timer->owner->eh!=NULL && o==NULL ) {
    2650           0 :         memset(&gevent,0,sizeof(gevent));
    2651           0 :         gevent.type = et_timer;
    2652           0 :         gevent.w = timer->owner;
    2653           0 :         gevent.native_window = timer->owner->native_window;
    2654           0 :         gevent.u.timer.timer = timer;
    2655           0 :         gevent.u.timer.userdata = timer->userdata;
    2656           0 :         (timer->owner->eh)(timer->owner,&gevent);
    2657             :             /* If this routine calls something that checks events then */
    2658             :             /*  without the active flag above we'd loop forever half-invoking*/
    2659             :             /*  this timer */
    2660           0 :         ret = true;
    2661             :     }
    2662           0 :     if ( GTimerInList(gdisp,timer)) {           /* carefull, they might have cancelled it */
    2663           0 :         timer->active = false;
    2664           0 :         if ( timer->repeat_time==0 )
    2665           0 :             GXDrawCancelTimer(timer);
    2666             :         else
    2667           0 :             GTimerReinstall(gdisp,timer);
    2668           0 :         ret = true;
    2669             :     }
    2670           0 : return(ret);
    2671             : }
    2672             : 
    2673           0 : static void GXDrawCheckPendingTimers(GXDisplay *gdisp) {
    2674             :     struct timeval tv;
    2675             :     GTimer *timer, *next;
    2676             : 
    2677           0 :     gettimeofday(&tv,NULL);
    2678           0 :     for ( timer = gdisp->timers; timer!=NULL; timer=next ) {
    2679           0 :         next = timer->next;
    2680           0 :         if ( timer->time_sec>tv.tv_sec ||
    2681           0 :                 (timer->time_sec == tv.tv_sec && timer->time_usec>tv.tv_usec ))
    2682             :     break;
    2683           0 :         if ( GXDrawProcessTimerEvent(gdisp,timer))
    2684           0 :     break;
    2685             :     }
    2686           0 : }
    2687             : 
    2688             : #ifdef HAVE_PTHREAD_H
    2689           0 : static void GXDrawDoThings(GXDisplay *gdisp) {
    2690             :     char buffer[10];
    2691             :     /* we enter and leave with the mutex locked */
    2692             : 
    2693           0 :     while ( gdisp->xthread.things_to_do!=NULL ) {
    2694             :         struct things_to_do *ttd, *next;
    2695           0 :         recv(gdisp->xthread.sync_sock,buffer,sizeof(buffer),0);
    2696           0 :         ttd = gdisp->xthread.things_to_do;
    2697           0 :         gdisp->xthread.things_to_do = NULL;
    2698           0 :         pthread_mutex_unlock(&gdisp->xthread.sync_mutex);
    2699             :         /* Don't let the user do stuff with the mutex locked */
    2700           0 :         while ( ttd!=NULL ) {
    2701           0 :             next = ttd->next;
    2702           0 :             (ttd->func)(ttd->data);
    2703           0 :             free(ttd);
    2704           0 :             ttd = next;
    2705             :         }
    2706           0 :         pthread_mutex_lock(&gdisp->xthread.sync_mutex);
    2707             :     }
    2708           0 : }
    2709             : #endif
    2710             : 
    2711           0 : static void GXDrawWaitForEvent(GXDisplay *gdisp) {
    2712             :     struct timeval tv;
    2713           0 :     Display *display = gdisp->display;
    2714             :     struct timeval offset, *timeout;
    2715             :     fd_set read, write, except;
    2716             :     int fd,ret;
    2717           0 :     int idx = 0;
    2718             : 
    2719             :     for (;;) {
    2720           0 :         gettimeofday(&tv,NULL);
    2721           0 :         GXDrawCheckPendingTimers(gdisp);
    2722             : 
    2723             : #ifdef _WACOM_DRV_BROKEN
    2724             :         _GXDraw_Wacom_TestEvents(gdisp);
    2725             : #endif
    2726             : 
    2727           0 :         if ( XEventsQueued(display,QueuedAfterFlush))
    2728           0 : return;
    2729             : #ifdef HAVE_PTHREAD_H
    2730           0 :         if ( gdisp->xthread.sync_sock!=-1 ) {
    2731           0 :             pthread_mutex_lock(&gdisp->xthread.sync_mutex);
    2732           0 :             if ( gdisp->xthread.things_to_do )
    2733           0 :                 GXDrawDoThings(gdisp);
    2734           0 :             pthread_mutex_unlock(&gdisp->xthread.sync_mutex);
    2735             :         }
    2736             : #endif
    2737           0 :         if ( gdisp->timers==NULL )
    2738           0 :             timeout = NULL;
    2739             :         else {
    2740           0 :             offset.tv_sec = gdisp->timers->time_sec - tv.tv_sec;
    2741           0 :             if (( offset.tv_usec= gdisp->timers->time_usec- tv.tv_usec)<0 ) {
    2742           0 :                 offset.tv_usec += 1000000;
    2743           0 :                 --offset.tv_sec;
    2744             :             }
    2745           0 :             if ( offset.tv_sec<0 || (offset.tv_sec==0 && offset.tv_usec==0))
    2746           0 :     continue;
    2747           0 :             timeout = &offset;
    2748             :         }
    2749           0 :         fd = XConnectionNumber(display);
    2750             : //    printf("gxdraw.... x connection number:%d\n", fd );
    2751           0 :         FD_ZERO(&read); FD_ZERO(&write); FD_ZERO(&except);
    2752           0 :         FD_SET(fd,&read);
    2753           0 :         FD_SET(fd,&except);
    2754           0 :         if ( gdisp->xthread.sync_sock!=-1 ) {
    2755           0 :             FD_SET(gdisp->xthread.sync_sock,&read);
    2756           0 :             if ( gdisp->xthread.sync_sock>fd )
    2757           0 :                 fd = gdisp->xthread.sync_sock;
    2758             :         }
    2759             : #ifdef _WACOM_DRV_BROKEN
    2760             :         if ( gdisp->wacom_fd!=-1 ) {
    2761             :             FD_SET(gdisp->wacom_fd,&read);
    2762             :             if ( gdisp->wacom_fd>fd )
    2763             :                 fd = gdisp->wacom_fd;
    2764             :         }
    2765             : #endif
    2766             : 
    2767           0 :         for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
    2768             :         {
    2769           0 :             fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
    2770           0 :             FD_SET( cb->fd, &read );
    2771           0 :             fd = MAX( fd, cb->fd );
    2772             :         }
    2773             :         
    2774           0 :         ret = select(fd+1,&read,&write,&except,timeout);
    2775             : 
    2776           0 :         for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
    2777             :         {
    2778           0 :             fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
    2779           0 :             if( FD_ISSET(cb->fd,&read))
    2780           0 :                 cb->callback( cb->fd, cb->udata );
    2781             :         }
    2782           0 :     }
    2783             : }
    2784             : 
    2785           0 : static void GXDrawPointerUngrab(GDisplay *gdisp) {
    2786           0 :     GXDisplay *gd = (GXDisplay *) gdisp;
    2787           0 :     XUngrabPointer(gd->display,gd->last_event_time);
    2788           0 :     gd->grab_window = NULL;
    2789           0 : }
    2790             : 
    2791           0 : static void GXDrawPointerGrab(GWindow gw) {
    2792           0 :     GXDisplay *gd = (GXDisplay *) (gw->display);
    2793           0 :     GXWindow w = (GXWindow) gw;
    2794           0 :     XGrabPointer(gd->display,w->w,false,
    2795             :             PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
    2796             :             GrabModeAsync, GrabModeAsync,None,None,gd->last_event_time);
    2797           0 :     gd->grab_window = gw;
    2798           0 : }
    2799             : 
    2800             : 
    2801             : /* Any input within the current dlg is ok */
    2802             : /* if input is restricted to that dlg then nothing else is permitted */
    2803             : /* if input is redirected then return the redirection to the current dlg */
    2804             : /* if input is within an inactive window, then return the current dlg */
    2805             : /* if there are any previous redirections outstanding then test them too */
    2806             : /*  (ie. if we are a dlg called from another dlg) */
    2807             : /* Now it's possible that the return tries to redirect something to the */
    2808             : /*  current inactive window, and if so we should redirect that to the */
    2809             : /*  current dlg. Indeed this is likely in a dlg produced by a dlg */
    2810           0 : static GWindow InputRedirection(struct inputRedirect *input,GWindow gw) {
    2811             :     GWindow ret;
    2812             : 
    2813           0 :     if ( input==NULL || input->cur_dlg->is_dying )
    2814           0 : return( NULL );
    2815           0 :     if ( gw->is_toplevel && ((GXWindow) gw)->not_restricted )
    2816           0 : return( NULL );                 /* Popup windows (menus, pulldown lists) count as part of their effective parents */
    2817           0 :     if ( GDrawWindowIsAncestor(input->cur_dlg,gw))
    2818           0 : return( NULL );
    2819           0 :     if ( input->it == it_restricted || input->it == it_redirected ) {
    2820           0 :         if ( input->it == it_redirected )
    2821           0 : return( input->cur_dlg );
    2822             :         else
    2823           0 : return( (GWindow) -1 );
    2824             :     }
    2825           0 :     if ( GDrawWindowIsAncestor(input->inactive,gw))
    2826           0 : return( input->cur_dlg );
    2827           0 :     ret = NULL;
    2828           0 :     if ( input->prev!=NULL )
    2829           0 :         ret = InputRedirection(input->prev,gw);
    2830           0 :     if ( ret==NULL || ret==(GWindow) (-1) )
    2831           0 : return( ret );
    2832           0 :     if ( GDrawWindowIsAncestor(input->inactive,ret))
    2833           0 : return( input->cur_dlg );
    2834             : 
    2835           0 : return( ret );
    2836             : }
    2837             : 
    2838           0 : static void dispatchEvent(GXDisplay *gdisp, XEvent *event) {
    2839             :     struct gevent gevent;
    2840           0 :     GWindow gw=NULL, redirect;
    2841             :     void *ret;
    2842             :     char charbuf[80], *pt;
    2843             :     Status status;
    2844             :     KeySym keysym; int len;
    2845             :     GPoint p;
    2846           0 :     int expecting_core = gdisp->expecting_core_event;
    2847             :     XEvent subevent;
    2848             : 
    2849           0 :     if ( XFilterEvent(event,None))      /* Make sure this happens before anything else */
    2850           0 : return;
    2851             : 
    2852           0 :     gdisp->expecting_core_event = false;
    2853             : 
    2854           0 :     if ( XFindContext(gdisp->display,event->xany.window,gdisp->mycontext,(void *) &ret)==0 )
    2855           0 :         gw = (GWindow) ret;
    2856           0 :     if ( gw==NULL || (_GXDraw_WindowOrParentsDying((GXWindow) gw) && event->type!=DestroyNotify ))
    2857           0 : return;
    2858           0 :     memset(&gevent,0,sizeof(gevent));
    2859           0 :     gevent.w = gw;
    2860           0 :     gevent.native_window = (void *) event->xany.window;
    2861           0 :     gevent.type = -1;
    2862           0 :     if ( event->type==KeyPress || event->type==ButtonPress || event->type == ButtonRelease ) {
    2863           0 :         if ( ((GXWindow ) gw)->transient_owner!=0 && ((GXWindow ) gw)->isverytransient )
    2864           0 :             gdisp->last_nontransient_window = ((GXWindow ) gw)->transient_owner;
    2865             :         else
    2866           0 :             gdisp->last_nontransient_window = ((GXWindow ) gw)->w;
    2867             :     }
    2868           0 :     switch(event->type) {
    2869             :       case KeyPress: case KeyRelease:
    2870           0 :         gdisp->last_event_time = event->xkey.time;
    2871           0 :         gevent.type = event->type==KeyPress?et_char:et_charup;
    2872           0 :         gevent.u.chr.time = event->xkey.time;
    2873           0 :         gevent.u.chr.state = event->xkey.state;
    2874           0 :         gevent.u.chr.autorepeat = 0;
    2875             : //      printf("event->xkey.state:%d\n", event->xkey.state );
    2876             : /*#ifdef __Mac*/
    2877             :         /* On mac os x, map the command key to the control key. So Comand-Q=>^Q=>Quit */
    2878             :         /* No... don't. Let the user have access to the command key as distinct from control */
    2879             :         /* I don't think it hurts to leave this enabled... */
    2880             : /*      if ( (event->xkey.state&ksm_cmdmacosx) && gdisp->macosx_cmd ) gevent.u.chr.state |= ksm_control; */
    2881             : /* Under 10.4 the option key generates the meta mask already */
    2882             : /* Under 10.6 it does not (change may have happened in 10.5.8) */
    2883           0 :         if ( (event->xkey.state&ksm_option) && gdisp->macosx_cmd ) gevent.u.chr.state |= ksm_meta;
    2884             : /*#endif*/
    2885           0 :         gevent.u.chr.x = event->xkey.x;
    2886           0 :         gevent.u.chr.y = event->xkey.y;
    2887           0 :         if ((redirect = InputRedirection(gdisp->input,gw))== (GWindow)(-1) ) {
    2888           0 :             len = XLookupString((XKeyEvent *) event,charbuf,sizeof(charbuf),&keysym,&gdisp->buildingkeys);
    2889           0 :             if ( event->type==KeyPress && len!=0 )
    2890           0 :                 GXDrawBeep((GDisplay *) gdisp);
    2891           0 : return;
    2892           0 :         } else if ( redirect!=NULL ) {
    2893             :             GPoint pt;
    2894           0 :             gevent.w = redirect;
    2895           0 :             pt.x = event->xkey.x; pt.y = event->xkey.y;
    2896           0 :             GXDrawTranslateCoordinates(gw,redirect,&pt);
    2897           0 :             gevent.u.chr.x = pt.x;
    2898           0 :             gevent.u.chr.y = pt.y;
    2899           0 :             gw = redirect;
    2900             :         }
    2901           0 :         if ( gevent.type==et_char ) {
    2902             :             /* The state may be modified in the gevent where a mac command key*/
    2903             :             /*  entry gets converted to control, etc. */
    2904           0 :             if ( ((GXWindow) gw)->gic==NULL ) {
    2905           0 :                 len = XLookupString((XKeyEvent *) event,charbuf,sizeof(charbuf),&keysym,&gdisp->buildingkeys);
    2906           0 :                 charbuf[len] = '\0';
    2907           0 :                 gevent.u.chr.keysym = keysym;
    2908           0 :                 def2u_strncpy(gevent.u.chr.chars,charbuf,
    2909             :                         sizeof(gevent.u.chr.chars)/sizeof(gevent.u.chr.chars[0]));
    2910             :             } else {
    2911             : #ifdef X_HAVE_UTF8_STRING
    2912             : /* I think there's a bug in SCIM. If I leave the meta(alt/option) modifier */
    2913             : /*  bit set, then scim returns no keysym and no characters. On the other hand,*/
    2914             : /*  if I don't leave that bit set, then the default input method on the mac */
    2915             : /*  will not do the Option key transformations properly. What I pass should */
    2916             : /*  be IM independent. So I don't think I should have to do the next line */
    2917           0 :                 event->xkey.state &= ~Mod2Mask;
    2918             : /* But I do */
    2919           0 :                 len = Xutf8LookupString(((GXWindow) gw)->gic->ic,(XKeyPressedEvent*)event,
    2920             :                                 charbuf, sizeof(charbuf), &keysym, &status);
    2921           0 :                 pt = charbuf;
    2922           0 :                 if ( status==XBufferOverflow ) {
    2923           0 :                     pt = malloc(len+1);
    2924           0 :                     len = Xutf8LookupString(((GXWindow) gw)->gic->ic,(XKeyPressedEvent*)&event,
    2925             :                                     pt, len, &keysym, &status);
    2926             :                 }
    2927           0 :                 if ( status!=XLookupChars && status!=XLookupBoth )
    2928           0 :                     len = 0;
    2929           0 :                 if ( status!=XLookupKeySym && status!=XLookupBoth )
    2930           0 :                     keysym = 0;
    2931           0 :                 pt[len] = '\0';
    2932           0 :                 gevent.u.chr.keysym = keysym;
    2933           0 :                 utf82u_strncpy(gevent.u.chr.chars,pt,
    2934             :                         sizeof(gevent.u.chr.chars)/sizeof(gevent.u.chr.chars[0]));
    2935           0 :                 if ( pt!=charbuf )
    2936           0 :                     free(pt);
    2937             : #else
    2938             :                 gevent.u.chr.keysym = keysym = 0;
    2939             :                 gevent.u.chr.chars[0] = 0;
    2940             : #endif
    2941             :             }
    2942             :             /* Convert X11 keysym values to unicode */
    2943           0 :             if ( keysym>=XKeysym_Mask )
    2944           0 :                 keysym -= XKeysym_Mask;
    2945           0 :             else if ( keysym<=XKEYSYM_TOP && keysym>=0 )
    2946           0 :                 keysym = gdraw_xkeysym_2_unicode[keysym];
    2947           0 :             gevent.u.chr.keysym = keysym;
    2948           0 :             if ( keysym==gdisp->mykey_keysym &&
    2949           0 :                     (event->xkey.state&(ControlMask|Mod1Mask))==gdisp->mykey_mask ) {
    2950           0 :                 gdisp->mykeybuild = !gdisp->mykeybuild;
    2951           0 :                 gdisp->mykey_state = 0;
    2952           0 :                 gevent.u.chr.chars[0] = '\0';
    2953           0 :                 gevent.u.chr.keysym = '\0';
    2954           0 :                 if ( !gdisp->mykeybuild && _GDraw_BuildCharHook!=NULL )
    2955           0 :                     (_GDraw_BuildCharHook)((GDisplay *) gdisp);
    2956           0 :             } else if ( gdisp->mykeybuild )
    2957           0 :                 _GDraw_ComposeChars((GDisplay *) gdisp,&gevent);
    2958             :         } else {
    2959             :             /* XLookupKeysym doesn't do shifts for us (or I don't know how to use the index arg to make it) */
    2960           0 :             len = XLookupString((XKeyEvent *) event,charbuf,sizeof(charbuf),&keysym,&gdisp->buildingkeys);
    2961           0 :             gevent.u.chr.keysym = keysym;
    2962           0 :             gevent.u.chr.chars[0] = '\0';
    2963             :         }
    2964             : 
    2965             :         /*
    2966             :          * If we are a charup, but the very next XEvent is a chardown
    2967             :          * on the same key, then we are just an autorepeat XEvent which
    2968             :          * other code might like to ignore
    2969             :          */
    2970           0 :         if ( gevent.type==et_charup && XEventsQueued(gdisp->display, QueuedAfterReading)) {
    2971             :             XEvent nev;
    2972           0 :             XPeekEvent(gdisp->display, &nev);
    2973           0 :             if (nev.type == KeyPress && nev.xkey.time == event->xkey.time &&
    2974           0 :                 nev.xkey.keycode == event->xkey.keycode)
    2975             :             {
    2976           0 :                 gevent.u.chr.autorepeat = 1;
    2977             :             }
    2978             :         }
    2979           0 :       break;
    2980             :       case ButtonPress: case ButtonRelease: case MotionNotify:
    2981           0 :         if ( expecting_core && gdisp->last_event_time==event->xbutton.time )
    2982           0 :       break; /* core event is a duplicate of device event */
    2983             :              /*  (only it's not quite a duplicate, often it's a few pixels */
    2984             :              /*  off from the device location */
    2985           0 :         if ( event->type==ButtonPress )
    2986           0 :             gdisp->grab_window = gw;
    2987           0 :         else if ( gdisp->grab_window!=NULL ) {
    2988           0 :             if ( gw!=gdisp->grab_window ) {
    2989             :                 Window wjunk;
    2990           0 :                 gevent.w = gw = gdisp->grab_window;
    2991           0 :                 XTranslateCoordinates(gdisp->display,
    2992           0 :                         event->xbutton.window,((GXWindow) gw)->w,
    2993           0 :                         event->xbutton.x, event->xbutton.y,
    2994           0 :                         &event->xbutton.x, &event->xbutton.y,
    2995             :                         &wjunk);
    2996             :             }
    2997           0 :             if ( event->type==ButtonRelease )
    2998           0 :                 gdisp->grab_window = NULL;
    2999             :         }
    3000             : 
    3001           0 :         gdisp->last_event_time = event->xbutton.time;
    3002           0 :         gevent.u.mouse.time = event->xbutton.time;
    3003           0 :         if ( event->type==MotionNotify && gdisp->grab_window==NULL )
    3004             :             /* Allow simple motion events to go through */;
    3005           0 :         else if ((redirect = InputRedirection(gdisp->input,gw))!=NULL ) {
    3006           0 :             if ( event->type==ButtonPress )
    3007           0 :                 GXDrawBeep((GDisplay *) gdisp);
    3008           0 : return;
    3009             :         }
    3010           0 :         gevent.u.mouse.state = event->xbutton.state;
    3011           0 :         gevent.u.mouse.x = event->xbutton.x;
    3012           0 :         gevent.u.mouse.y = event->xbutton.y;
    3013           0 :         gevent.u.mouse.button = event->xbutton.button;
    3014           0 :         gevent.u.mouse.device = NULL;
    3015           0 :         gevent.u.mouse.pressure = gevent.u.mouse.xtilt = gevent.u.mouse.ytilt = gevent.u.mouse.separation = 0;
    3016           0 :         if ( (event->xbutton.state&0x40) && gdisp->twobmouse_win )
    3017           0 :             gevent.u.mouse.button = 2;
    3018           0 :         if ( event->type == MotionNotify ) {
    3019             : #if defined (__MINGW32__) || __CygWin
    3020             :         //For some reason, a mouse move event is triggered even if it hasn't moved.
    3021             :         if(gdisp->mousemove_last_x == event->xbutton.x &&
    3022             :            gdisp->mousemove_last_y == event->xbutton.y) {
    3023             :             return;
    3024             :         }
    3025             :         gdisp->mousemove_last_x = event->xbutton.x;
    3026             :         gdisp->mousemove_last_y = event->xbutton.y;
    3027             : #endif
    3028           0 :             gevent.type = et_mousemove;
    3029           0 :             gevent.u.mouse.button = 0;
    3030           0 :             gevent.u.mouse.clicks = 0;
    3031           0 :         } else if ( event->type == ButtonPress ) {
    3032             :             int diff, temp;
    3033           0 :             gevent.type = et_mousedown;
    3034           0 :             if (( diff = event->xbutton.x-gdisp->bs.release_x )<0 ) diff= -diff;
    3035           0 :             if (( temp = event->xbutton.y-gdisp->bs.release_y )<0 ) temp= -temp;
    3036           0 :             if ( diff+temp<gdisp->bs.double_wiggle &&
    3037           0 :                     event->xbutton.window == gdisp->bs.release_w &&
    3038           0 :                     event->xbutton.button == gdisp->bs.release_button &&
    3039           0 :                     event->xbutton.time-gdisp->bs.release_time < gdisp->bs.double_time &&
    3040           0 :                     event->xbutton.time >= gdisp->bs.release_time )    /* Time can wrap */
    3041           0 :                 ++ gdisp->bs.cur_click;
    3042             :             else
    3043           0 :                 gdisp->bs.cur_click = 1;
    3044           0 :             gevent.u.mouse.clicks = gdisp->bs.cur_click;
    3045             :         } else {
    3046           0 :             gevent.type = et_mouseup;
    3047           0 :             gdisp->bs.release_time = event->xbutton.time;
    3048           0 :             gdisp->bs.release_w = event->xbutton.window;
    3049           0 :             gdisp->bs.release_x = event->xbutton.x;
    3050           0 :             gdisp->bs.release_y = event->xbutton.y;
    3051           0 :             gdisp->bs.release_button = event->xbutton.button;
    3052           0 :             gevent.u.mouse.clicks = gdisp->bs.cur_click;
    3053             :         }
    3054           0 :       break;
    3055             :       case Expose: case GraphicsExpose:
    3056           0 :         gevent.type = et_expose;
    3057           0 :         gevent.u.expose.rect.x = event->xexpose.x;
    3058           0 :         gevent.u.expose.rect.y = event->xexpose.y;
    3059           0 :         gevent.u.expose.rect.width = event->xexpose.width;
    3060           0 :         gevent.u.expose.rect.height = event->xexpose.height;
    3061             :         /* Slurp any pending exposes and merge into one big rectangle */
    3062           0 :         while ( XCheckTypedWindowEvent(gdisp->display,event->xany.window,event->type,
    3063             :                 &subevent)) {
    3064           0 :             if ( subevent.xexpose.x+subevent.xexpose.width > gevent.u.expose.rect.x+gevent.u.expose.rect.width )
    3065           0 :                 gevent.u.expose.rect.width = subevent.xexpose.x+subevent.xexpose.width - gevent.u.expose.rect.x;
    3066           0 :             if ( subevent.xexpose.x < gevent.u.expose.rect.x ) {
    3067           0 :                 gevent.u.expose.rect.width += gevent.u.expose.rect.x - subevent.xexpose.x;
    3068           0 :                 gevent.u.expose.rect.x = subevent.xexpose.x;
    3069             :             }
    3070           0 :             if ( subevent.xexpose.y+subevent.xexpose.height > gevent.u.expose.rect.y+gevent.u.expose.rect.height )
    3071           0 :                 gevent.u.expose.rect.height = subevent.xexpose.y+subevent.xexpose.height - gevent.u.expose.rect.y;
    3072           0 :             if ( subevent.xexpose.y < gevent.u.expose.rect.y ) {
    3073           0 :                 gevent.u.expose.rect.height += gevent.u.expose.rect.y - subevent.xexpose.y;
    3074           0 :                 gevent.u.expose.rect.y = subevent.xexpose.y;
    3075             :             }
    3076             :         }
    3077             : #ifndef _NO_LIBCAIRO
    3078           0 :         if ( ((GXWindow) gw)->usecairo )             /* X11 does this automatically. but cairo won't get the event */
    3079           0 :             GXDrawClear(gw,&gevent.u.expose.rect);
    3080             : #endif
    3081           0 :       break;
    3082             :       case VisibilityNotify:
    3083           0 :         gevent.type = et_visibility;
    3084           0 :         gevent.u.visibility.state = event->xvisibility.state;
    3085           0 :       break;
    3086             :       case FocusIn: case FocusOut:      /* Should only get this on top level */
    3087           0 :         gevent.type = et_focus;
    3088           0 :         gevent.u.focus.gained_focus = event->type==FocusIn;
    3089           0 :         gevent.u.focus.mnemonic_focus = false;
    3090           0 :       break;
    3091             :       case EnterNotify: case LeaveNotify: /* Should only get this on top level */
    3092           0 :         if ( event->xcrossing.detail == NotifyInferior )
    3093           0 :       break;
    3094           0 :         if ( gdisp->focusfollowsmouse && gw!=NULL && gw->eh!=NULL ) {
    3095           0 :             gevent.type = et_focus;
    3096           0 :             gevent.u.focus.gained_focus = event->type==EnterNotify;
    3097           0 :             gevent.u.focus.mnemonic_focus = false;
    3098           0 :             (gw->eh)((GWindow) gw, &gevent);
    3099             :         }
    3100           0 :         gevent.type = et_crossing;
    3101           0 :         gevent.u.crossing.x = event->xcrossing.x;
    3102           0 :         gevent.u.crossing.y = event->xcrossing.y;
    3103           0 :         gevent.u.crossing.state = event->xcrossing.state;
    3104           0 :         gevent.u.crossing.entered = event->type==EnterNotify;
    3105           0 :         gevent.u.crossing.device = NULL;
    3106           0 :         gevent.u.crossing.time = event->xcrossing.time;
    3107           0 :       break;
    3108             :       case ConfigureNotify:
    3109             :         /* Eat up multiple resize notifications in case the window manager */
    3110             :         /*  does animated resizes */
    3111           0 :         while ( XCheckTypedWindowEvent(event->xconfigure.display,
    3112           0 :                 event->xconfigure.window,ConfigureNotify,event));
    3113           0 :         gevent.type = et_resize;
    3114           0 :         gevent.u.resize.size.x = event->xconfigure.x;
    3115           0 :         gevent.u.resize.size.y = event->xconfigure.y;
    3116           0 :         gevent.u.resize.size.width = event->xconfigure.width;
    3117           0 :         gevent.u.resize.size.height = event->xconfigure.height;
    3118           0 :         if ( gw->is_toplevel ) {
    3119           0 :             p.x = 0; p.y = 0;
    3120           0 :             GXDrawTranslateCoordinates(gw,(GWindow) (gdisp->groot),&p);
    3121           0 :             gevent.u.resize.size.x = p.x;
    3122           0 :             gevent.u.resize.size.y = p.y;
    3123             :         }
    3124           0 :         gevent.u.resize.dx = gevent.u.resize.size.x-gw->pos.x;
    3125           0 :         gevent.u.resize.dy = gevent.u.resize.size.y-gw->pos.y;
    3126           0 :         gevent.u.resize.dwidth = gevent.u.resize.size.width-gw->pos.width;
    3127           0 :         gevent.u.resize.dheight = gevent.u.resize.size.height-gw->pos.height;
    3128           0 :         gevent.u.resize.moved = gevent.u.resize.sized = false;
    3129           0 :         if ( gevent.u.resize.dx!=0 || gevent.u.resize.dy!=0 )
    3130           0 :             gevent.u.resize.moved = true;
    3131           0 :         if ( gevent.u.resize.dwidth!=0 || gevent.u.resize.dheight!=0 ) {
    3132           0 :             gevent.u.resize.sized = true;
    3133             : #ifndef _NO_LIBCAIRO
    3134           0 :             if ( ((GXWindow) gw)->usecairo )
    3135           0 :                 _GXCDraw_ResizeWindow((GXWindow) gw, &gevent.u.resize.size);
    3136             : #endif
    3137             :         }
    3138           0 :         gw->pos = gevent.u.resize.size;
    3139           0 :         if ( !gdisp->top_offsets_set && ((GXWindow) gw)->was_positioned &&
    3140           0 :                 gw->is_toplevel && !((GXWindow) gw)->is_popup &&
    3141           0 :                 !((GXWindow) gw)->istransient ) {
    3142             :             /* I don't know why I need a fudge factor here, but I do */
    3143           0 :             gdisp->off_x = gevent.u.resize.dx-2;
    3144           0 :             gdisp->off_y = gevent.u.resize.dy-1;
    3145           0 :             gdisp->top_offsets_set = true;
    3146             :         }
    3147           0 :       break;
    3148             :       case CreateNotify:
    3149             :         /* actually CreateNotify events only go to the window parent if */
    3150             :         /*  substructureNotify is set. We aren't a window manager, so we */
    3151             :         /*  shouldn't get any. Sigh. I simulate them instead */
    3152           0 :         gevent.type = et_create;
    3153           0 :       break;
    3154             :       case MapNotify:
    3155           0 :         gevent.type = et_map;
    3156           0 :         gevent.u.map.is_visible = true;
    3157           0 :         gw->is_visible = true;
    3158           0 :       break;
    3159             :       case UnmapNotify:
    3160           0 :         gevent.type = et_map;
    3161           0 :         gevent.u.map.is_visible = false;
    3162           0 :         gw->is_visible = false;
    3163           0 :       break;
    3164             :       case DestroyNotify:
    3165           0 :         gevent.type = et_destroy;
    3166           0 :       break;
    3167             :       case ClientMessage:
    3168           0 :         if ((redirect = InputRedirection(gdisp->input,gw))!=NULL ) {
    3169           0 :             GXDrawBeep((GDisplay *) gdisp);
    3170           0 : return;
    3171             :         }
    3172           0 :         if ( event->xclient.message_type == gdisp->atoms.wm_protocols &&
    3173           0 :                 event->xclient.data.l[0] == gdisp->atoms.wm_del_window )
    3174           0 :             gevent.type = et_close;
    3175           0 :         else if ( event->xclient.message_type == gdisp->atoms.drag_and_drop ) {
    3176           0 :             gevent.type = event->xclient.data.l[0];
    3177           0 :             gevent.u.drag_drop.x = event->xclient.data.l[1];
    3178           0 :             gevent.u.drag_drop.y = event->xclient.data.l[2];
    3179             :         }
    3180           0 :       break;
    3181             :       case SelectionClear: {
    3182             :         int i;
    3183           0 :         gdisp->last_event_time = event->xselectionclear.time;
    3184           0 :         gevent.type = et_selclear;
    3185           0 :         gevent.u.selclear.sel = sn_primary;
    3186           0 :         for ( i=0; i<sn_max; ++i ) {
    3187           0 :             if ( event->xselectionclear.selection==gdisp->selinfo[i].sel_atom ) {
    3188           0 :                 gevent.u.selclear.sel = i;
    3189           0 :         break;
    3190             :             }
    3191             :         }
    3192           0 :         GXDrawClearSelData(gdisp,gevent.u.selclear.sel);
    3193           0 :       } break;
    3194             :       case SelectionRequest:
    3195           0 :         gdisp->last_event_time = event->xselectionrequest.time;
    3196           0 :         GXDrawTransmitSelection(gdisp,event);
    3197           0 :       break;
    3198             :       case SelectionNotify:             /* !!!!! paste */
    3199             :         /*gdisp->last_event_time = event->xselection.time;*/ /* it's the request's time not the current? */
    3200           0 :       break;
    3201             :       case PropertyNotify:
    3202           0 :         gdisp->last_event_time = event->xproperty.time;
    3203           0 :       break;
    3204             :       case ReparentNotify:
    3205           0 :         if ( event->xreparent.parent==gdisp->root ) {
    3206           0 :             gw->parent = (GWindow) (gdisp->groot);
    3207           0 :             gw->is_toplevel = true;
    3208           0 :         } else if ( XFindContext(gdisp->display,event->xreparent.parent,gdisp->mycontext,(void *) &ret)==0 ) {
    3209           0 :             GWindow gparent = (GWindow) ret;
    3210           0 :             gw->parent = gparent;
    3211           0 :             gw->is_toplevel = (GXWindow) gparent==gdisp->groot;
    3212             :         }
    3213           0 :       break;
    3214             :       case MappingNotify:
    3215           0 :         XRefreshKeyboardMapping((XMappingEvent *) event);
    3216           0 :       break;
    3217             :       default:
    3218             : #ifndef _NO_XKB
    3219           0 :         if ( event->type==gdisp->xkb.event ) {
    3220           0 :             switch ( ((XkbAnyEvent *) event)->xkb_type ) {
    3221             :               case XkbNewKeyboardNotify:
    3222             :                 /* I don't think I need to do anything here. But I think I */
    3223             :                 /*  need to get the event since otherwise xkb restricts the */
    3224             :                 /*  keycodes it will send me */
    3225           0 :               break;
    3226             :               case XkbMapNotify:
    3227           0 :                 XkbRefreshKeyboardMapping((XkbMapNotifyEvent *) event);
    3228           0 :               break;
    3229             :             }
    3230           0 :       break;
    3231             :         }
    3232             : #endif
    3233             : #ifndef _NO_XINPUT
    3234             :         if ( event->type>=LASTEvent ) {   /* An XInput event */
    3235             :             int i,j;
    3236             :             static int types[5] = { et_mousemove, et_mousedown, et_mouseup, et_char, et_charup };
    3237             :             for ( i=0 ; i<gdisp->n_inputdevices; ++i ) {
    3238             :                 if ( ((XDeviceButtonEvent *) event)->deviceid==gdisp->inputdevices[i].devid ) { 
    3239             :                     for ( j=0; j<5; ++j )
    3240             :                         if ( event->type==gdisp->inputdevices[i].event_types[j] ) {
    3241             :                             gevent.type = types[j];
    3242             :             goto found;
    3243             :                         }
    3244             :                 }
    3245             :             }
    3246             :             found: ;
    3247             :             if ( gevent.type != et_noevent ) {
    3248             :                 gdisp->last_event_time = ((XDeviceButtonEvent *) event)->time;
    3249             :                 gevent.u.mouse.time = ((XDeviceButtonEvent *) event)->time;
    3250             :                 gevent.u.mouse.device = gdisp->inputdevices[i].name; /* Same place in key and mouse events */
    3251             :                 if ( j>3 ) { /* Key event */
    3252             :                     gevent.u.chr.state = ((XDeviceKeyEvent *) event)->device_state;
    3253             :                     gevent.u.chr.x = ((XDeviceKeyEvent *) event)->x;
    3254             :                     gevent.u.chr.y = ((XDeviceKeyEvent *) event)->y;
    3255             :                     gevent.u.chr.keysym = ((XDeviceKeyEvent *) event)->keycode;
    3256             :                     gevent.u.chr.chars[0] = 0;
    3257             :                     if ( ((XDeviceKeyEvent *) event)->first_axis!=0 )
    3258             :                         gevent.type = et_noevent;       /* Repeat of previous event to add more axes */
    3259             :                 } else {
    3260             :                     /* Pass the buttons from the device, the key modifiers from the normal state */
    3261             :                     gevent.u.mouse.state =
    3262             :                             ( ((XDeviceButtonEvent *) event)->device_state & 0xffffff00) |
    3263             :                             ( ((XDeviceButtonEvent *) event)->state     & 0x000000ff);
    3264             :                     gevent.u.mouse.x = ((XDeviceButtonEvent *) event)->x;
    3265             :                     gevent.u.mouse.y = ((XDeviceButtonEvent *) event)->y;
    3266             :                     gdisp->expecting_core_event = true;
    3267             :                     if ( j!=0 ) {
    3268             :                         gevent.u.mouse.button = ((XDeviceButtonEvent *) event)->button;
    3269             :                         if ( ((XDeviceButtonEvent *) event)->first_axis!=0 )
    3270             :                             gevent.type = et_noevent;   /* Repeat of previous event to add more axes */
    3271             :                         if ( ((XDeviceButtonEvent *) event)->axes_count==6 ) {
    3272             :                             gevent.u.mouse.pressure = ((XDeviceButtonEvent *) event)->axis_data[2];
    3273             :                             gevent.u.mouse.xtilt = ((XDeviceButtonEvent *) event)->axis_data[3];
    3274             :                             gevent.u.mouse.ytilt = ((XDeviceButtonEvent *) event)->axis_data[4];
    3275             :                         } else
    3276             :                             gevent.u.mouse.pressure = gevent.u.mouse.xtilt = gevent.u.mouse.ytilt = gevent.u.mouse.separation = 0;
    3277             :                     } else {
    3278             :                         if ( ((XDeviceMotionEvent *) event)->first_axis!=0 )
    3279             :                             gevent.type = et_noevent;   /* Repeat of previous event to add more axes */
    3280             :                         gevent.u.mouse.button = 0;
    3281             :                         if ( ((XDeviceMotionEvent *) event)->axes_count==6 ) {
    3282             :                             gevent.u.mouse.pressure = ((XDeviceMotionEvent *) event)->axis_data[2];
    3283             :                             gevent.u.mouse.xtilt = ((XDeviceMotionEvent *) event)->axis_data[3];
    3284             :                             gevent.u.mouse.ytilt = ((XDeviceMotionEvent *) event)->axis_data[4];
    3285             :                         } else
    3286             :                             gevent.u.mouse.pressure = gevent.u.mouse.xtilt = gevent.u.mouse.ytilt = gevent.u.mouse.separation = 0;
    3287             :                     }
    3288             :                 }
    3289             :             }
    3290             :         }
    3291             : #endif
    3292           0 :       break;
    3293             :     }
    3294             : 
    3295           0 :     if ( gevent.type != et_noevent && gw!=NULL && gw->eh!=NULL )
    3296           0 :         (gw->eh)((GWindow) gw, &gevent);
    3297           0 :     if ( event->type==DestroyNotify && gw!=NULL )
    3298           0 :         _GXDraw_CleanUpWindow( gw );
    3299             : }
    3300             : 
    3301           0 : static void GXDrawForceUpdate(GWindow gw) {
    3302             :     XEvent event;
    3303           0 :     Window w=((GXWindow) gw)->w;
    3304           0 :     Display *display = ((GXDisplay *) (gw->display))->display;
    3305             :     /* Do NOT check for timer events here! we are only interested in Exposes */
    3306             :     /* I assume that GraphicsExposes are also caught by ExposureMask? */
    3307             : 
    3308           0 :     while ( XCheckWindowEvent(display,w,ExposureMask,&event))
    3309           0 :         dispatchEvent((GXDisplay *) (gw->display), &event);
    3310           0 : }
    3311             : 
    3312             : /* any event is good here */
    3313           0 : static Bool allevents(Display *display, XEvent *event, char *arg) {
    3314           0 : return( true );
    3315             : }
    3316             : 
    3317           0 : static Bool windowevents(Display *display, XEvent *event, char *arg) {
    3318           0 : return( event->xany.window == (Window) arg );
    3319             : }
    3320             : 
    3321           0 : static void GXDrawProcessOneEvent(GDisplay *gdisp) {
    3322             :     XEvent event;
    3323           0 :     Display *display = ((GXDisplay *) gdisp)->display;
    3324             :     /* Handle one X event (actually we might also handle a bunch of timers too) */
    3325             : 
    3326           0 :     GXDrawWaitForEvent((GXDisplay *) gdisp);
    3327           0 :     XNextEvent(display,&event);
    3328           0 :     dispatchEvent((GXDisplay *) gdisp, &event);
    3329           0 : }
    3330             : 
    3331             : struct mmarg { Window w; int state; int stop; };
    3332             : 
    3333           0 : static Bool mmpred(Display *d, XEvent *e, XPointer arg) {
    3334           0 :     struct mmarg *mmarg = (struct mmarg *) arg;
    3335             : 
    3336           0 :     if ( mmarg->stop )
    3337           0 : return( False );
    3338           0 :     if ( e->type==MotionNotify ) {
    3339           0 :         if ( e->xmotion.window==mmarg->w && e->xmotion.state == mmarg->state )
    3340           0 : return( True );
    3341           0 :         mmarg->stop = true;
    3342           0 :     } else if ( e->type == ButtonPress || e->type==ButtonRelease )
    3343           0 :         mmarg->stop = true;
    3344           0 : return( False );
    3345             : }
    3346             : 
    3347           0 : static void GXDrawSkipMouseMoveEvents(GWindow w, GEvent *last) {
    3348             :     XEvent event;
    3349           0 :     GXWindow gw = (GXWindow) w;
    3350             :     struct mmarg arg;
    3351             : 
    3352           0 :     arg.w = gw->w; arg.state = last->u.mouse.state; arg.stop = false;
    3353           0 :     while ( XCheckIfEvent(gw->display->display,&event,mmpred,(XPointer) &arg) ) {
    3354           0 :         last->u.mouse.x = event.xmotion.x;
    3355           0 :         last->u.mouse.y = event.xmotion.y;
    3356             :     }
    3357           0 : }
    3358             : 
    3359           0 : static void GXDrawProcessPendingEvents(GDisplay *gdisp) {
    3360             :     XEvent event;
    3361           0 :     Display *display = ((GXDisplay *) gdisp)->display;
    3362             :     /* We don't wait for anything. Only stuff already in the queue */
    3363             : 
    3364           0 :     GXDrawCheckPendingTimers((GXDisplay *) gdisp);
    3365           0 :     while ( XCheckIfEvent(display,&event,allevents,NULL))
    3366           0 :         dispatchEvent((GXDisplay *) gdisp, &event);
    3367           0 : }
    3368             : 
    3369           0 : static void GXDrawProcessWindowEvents(GWindow w) {
    3370             :     XEvent event;
    3371           0 :     GXWindow gw = (GXWindow) w;
    3372           0 :     Display *display = gw->display->display;
    3373             : 
    3374           0 :     while ( XCheckIfEvent(display,&event,windowevents,(char *) (gw->w)))
    3375           0 :         dispatchEvent(gw->display, &event);
    3376           0 : }
    3377             : 
    3378           0 : static void GXDrawSync(GDisplay *gdisp) {
    3379           0 :     XSync(((GXDisplay *) gdisp)->display,false);
    3380           0 : }
    3381             : 
    3382           0 : void dispatchError(GDisplay *gdisp) {
    3383           0 :     if ((gdisp->err_flag) && (gdisp->err_report)) {
    3384           0 :       GDrawIErrorRun("%s",gdisp->err_report);
    3385             :     }
    3386           0 :     if (gdisp->err_report) {
    3387           0 :       free(gdisp->err_report); gdisp->err_report = NULL;
    3388             :     }
    3389           0 : }
    3390             : 
    3391             : /* Munch events until we no longer have any top level windows. That essentially*/
    3392             : /*  means no windows (even if they got reparented, we still think they are top)*/
    3393             : /*  At that point try very hard to clear out the event queue. It is conceivable*/
    3394             : /*  that doing so will create a new window. If no luck then return */
    3395           0 : static void GXDrawEventLoop(GDisplay *gd) {
    3396             :     XEvent event;
    3397           0 :     GXDisplay *gdisp = (GXDisplay *) gd;
    3398           0 :     Display *display = gdisp->display;
    3399             : 
    3400             :     do {
    3401           0 :         while ( gdisp->top_window_count>0 ) {
    3402           0 :             GXDrawWaitForEvent(gdisp);
    3403           0 :             XNextEvent(display,&event);
    3404           0 :             dispatchEvent(gdisp, &event);
    3405           0 :             dispatchError(gd);
    3406             :         }
    3407           0 :         XSync(display,false);
    3408           0 :         GXDrawProcessPendingEvents(gd);
    3409           0 :         XSync(display,false);
    3410           0 :     } while ( gdisp->top_window_count>0 || XEventsQueued(display,QueuedAlready)>0 );
    3411           0 : }
    3412             : 
    3413           0 : static void GXDrawPostEvent(GEvent *e) {
    3414             :     /* Doesn't check event masks, not sure if that's desirable or not. It's easy though */
    3415           0 :     GXWindow gw = (GXWindow) (e->w);
    3416           0 :     e->native_window = ((GWindow) gw)->native_window;
    3417           0 :     (gw->eh)((GWindow) gw, e);
    3418           0 : }
    3419             : 
    3420             : /* Drag and drop works thusly:
    3421             :     the user drags a selection somewhere
    3422             :      as this happens we send out drag events to each window the cursor moves
    3423             :       over telling the window where the cursor is (to allow the window to do
    3424             :       feedback like showing a text cursor or something)
    3425             :      when we exit a window we send one last event (a dragout event) to let it
    3426             :       know it should clear its cursor
    3427             :     when the user drops the selection
    3428             :      the client grabs the DRAG_AND_DROP selection
    3429             :      fills it up with whatever types are appropriate
    3430             :      sends the window a drop event
    3431             :      the window looks at that event and extracts a (local to it) position of
    3432             :       the drop
    3433             :      it queries the selection to get the data
    3434             :      it performs the drop operation
    3435             : */
    3436             :     
    3437           0 : static void gxdrawSendDragOut(GXDisplay *gdisp) {
    3438             : 
    3439           0 :     if ( gdisp->last_dd.gw!=NULL ) {
    3440             :         GEvent e;
    3441           0 :         memset(&e,0,sizeof(e));
    3442           0 :         e.type = et_dragout;
    3443           0 :         e.u.drag_drop.x = gdisp->last_dd.rx;
    3444           0 :         e.u.drag_drop.y = gdisp->last_dd.ry;
    3445           0 :         e.native_window = NULL;
    3446           0 :         if ( gdisp->last_dd.gw->eh!=NULL )
    3447           0 :             (gdisp->last_dd.gw->eh)(gdisp->last_dd.gw,&e);
    3448             :     } else {
    3449             :         XEvent xe;
    3450           0 :         xe.type = ClientMessage;
    3451           0 :         xe.xclient.display = gdisp->display;
    3452           0 :         xe.xclient.window = gdisp->last_dd.w;
    3453           0 :         xe.xclient.message_type = gdisp->atoms.drag_and_drop;
    3454           0 :         xe.xclient.format = 32;
    3455           0 :         xe.xclient.data.l[0] = et_dragout;
    3456           0 :         xe.xclient.data.l[1] = gdisp->last_dd.rx;
    3457           0 :         xe.xclient.data.l[2] = gdisp->last_dd.ry;
    3458           0 :         XSendEvent(gdisp->display,gdisp->last_dd.w,False,0,&xe);
    3459             :     }
    3460           0 :     gdisp->last_dd.w = None;
    3461           0 :     gdisp->last_dd.gw = NULL;
    3462           0 : }
    3463             : 
    3464           0 : static void GXDrawPostDragEvent(GWindow w,GEvent *mouse,enum event_type et) {
    3465           0 :     GXWindow gw = (GXWindow) w;
    3466           0 :     GXDisplay *gdisp = gw->display;
    3467             :     GEvent e;
    3468             :     Window child, curwin;
    3469             :     int x,y;
    3470             :     void *vd;
    3471           0 :     GWindow destw = NULL;
    3472             : 
    3473             :     /* if the cursor hasn't moved much, don't bother to send a drag event */
    3474           0 :     if (( x = mouse->u.mouse.x-gdisp->last_dd.x )<0 ) x = -x;
    3475           0 :     if (( y = mouse->u.mouse.y-gdisp->last_dd.y )<0 ) y = -y;
    3476           0 :     if ( x+y < 4 && et==et_drag )
    3477           0 : return;
    3478             : 
    3479           0 :     curwin = _GXDrawGetPointerWindow(w);
    3480             : 
    3481           0 :     if ( gdisp->last_dd.w!=None && gdisp->last_dd.w!=curwin )
    3482           0 :         gxdrawSendDragOut(gdisp);
    3483             : 
    3484           0 :     memset(&e,0,sizeof(e));
    3485             : 
    3486             :     /* Are we still within the original window? */
    3487           0 :     if ( curwin == gw->w ) {
    3488           0 :         e.type = et;
    3489           0 :         x = e.u.drag_drop.x = mouse->u.mouse.x;
    3490           0 :         y = e.u.drag_drop.y = mouse->u.mouse.y;
    3491           0 :         (gw->eh)(w, &e);
    3492             :     } else {
    3493           0 :         XTranslateCoordinates(gdisp->display,gw->w,curwin,
    3494           0 :                 mouse->u.mouse.x,mouse->u.mouse.y,
    3495             :                 &x,&y,&child);
    3496             : 
    3497           0 :         e.type = et;
    3498           0 :         e.u.drag_drop.x = x;
    3499           0 :         e.u.drag_drop.y = y;
    3500           0 :         e.native_window = (void *) curwin;
    3501             : 
    3502           0 :         if ( (curwin&0xfff00000)==(gw->w&0xfff00000) &&
    3503           0 :                 XFindContext(gdisp->display,curwin,gdisp->mycontext,(void *) &vd)==0 ) {
    3504           0 :             destw = (GWindow) vd;
    3505             :             /* is it one of our windows? If so use our own event mechanism */
    3506           0 :             if ( destw->eh!=NULL )
    3507           0 :                 (destw->eh)(destw,&e);
    3508           0 :         } else if ( curwin!=gdisp->root ) {
    3509             :             XEvent xe;
    3510           0 :             xe.type = ClientMessage;
    3511           0 :             xe.xclient.display = gdisp->display;
    3512           0 :             xe.xclient.window = curwin;
    3513           0 :             xe.xclient.message_type = gdisp->atoms.drag_and_drop;
    3514           0 :             xe.xclient.format = 32;
    3515           0 :             xe.xclient.data.l[0] = et;
    3516           0 :             xe.xclient.data.l[1] = x;
    3517           0 :             xe.xclient.data.l[2] = y;
    3518           0 :             XSendEvent(gdisp->display,curwin,False,0,&xe);
    3519             :         }
    3520             :     }
    3521           0 :     if ( et!=et_drop ) {
    3522           0 :         gdisp->last_dd.w = curwin;
    3523           0 :         gdisp->last_dd.gw = destw;
    3524           0 :         gdisp->last_dd.x = mouse->u.mouse.x;
    3525           0 :         gdisp->last_dd.y = mouse->u.mouse.y;
    3526           0 :         gdisp->last_dd.rx = x;
    3527           0 :         gdisp->last_dd.ry = y;
    3528             :     } else {
    3529           0 :         gdisp->last_dd.w = None;
    3530           0 :         gdisp->last_dd.gw = NULL;
    3531             :     }
    3532             : }
    3533             : 
    3534             : static int devopen_failed;
    3535             : static char *device_name;
    3536             : 
    3537           0 : static int devopenerror(Display *disp, XErrorEvent *err) {
    3538             :     /* Some ubuntu releases seem to give everybody wacom devices by default */
    3539             :     /*  in their xorg.conf file. However if the user has no wacom tablet then */
    3540             :     /*  an attempt to use one of those devices will cause X to return a */
    3541             :     /*  BadDevice error */
    3542             :     /* Unfortunately there is no good way to test for BadDevice (at least */
    3543             :     /*  not that I am aware of). It's an extension error, so its numeric value*/
    3544             :     /*  varies from machine to machine. I could grab the error message as a */
    3545             :     /*  string, but it could be localized, and might change too. */
    3546             :     /* So I just assume that any error in the extension error range is likely */
    3547             :     /*  to be BadDevice */
    3548             : 
    3549           0 :     if ( err->error_code>=128 ) {
    3550           0 :         devopen_failed = true;
    3551           0 :         fprintf( stderr, "X11 claims there exists a device called \"%s\", but an attempt to open it fails.\n  Rerun the program with the -dontopenxdevices argument.\n",
    3552             :                 device_name );
    3553             :     } else {
    3554           0 :         myerrorhandler(disp,err);
    3555             :     }
    3556           0 : return( 1 );
    3557             : }
    3558             : 
    3559           0 : static int GXDrawRequestDeviceEvents(GWindow w,int devcnt,struct gdeveventmask *de) {
    3560             : #ifndef _NO_XINPUT
    3561             :     GXDisplay *gdisp = (GXDisplay *) (w->display);
    3562             :     int i,j,k,cnt,foo, availdevcnt;
    3563             :     XEventClass *classes;
    3564             :     GResStruct res[2];
    3565             : 
    3566             :     if ( !gdisp->devicesinit ) {
    3567             :         int ndevs=0;
    3568             :         XDeviceInfo *devs;
    3569             :         int dontopentemp = 0;
    3570             : 
    3571             :         memset(res,0,sizeof(res));
    3572             :         i=0;
    3573             :         res[i].resname = "DontOpenXDevices"; res[i].type = rt_bool; res[i].val = &dontopentemp; ++i;
    3574             :         res[i].resname = NULL;
    3575             :         GResourceFind(res,NULL);
    3576             :         if ( dontopentemp ) {
    3577             :             gdisp->devicesinit = true;
    3578             : return( 0 );
    3579             :         }
    3580             :         
    3581             :         devs = XListInputDevices(gdisp->display,&ndevs);
    3582             :         gdisp->devicesinit = true;
    3583             :         if ( ndevs==0 )
    3584             : return( 0 );
    3585             :         gdisp->inputdevices = calloc(ndevs+1,sizeof(struct inputdevices));
    3586             :         for ( i=0; i<ndevs; ++i ) {
    3587             :             gdisp->inputdevices[i].name = copy(devs[i].name);
    3588             :             gdisp->inputdevices[i].devid = devs[i].id;
    3589             :         }
    3590             :         gdisp->n_inputdevices = ndevs;
    3591             :         XFreeDeviceList(devs);
    3592             :     }
    3593             :     classes = NULL;
    3594             :     for ( k=0; k<2; ++k ) {
    3595             :         cnt=availdevcnt=0;
    3596             :         for ( j=0; de[j].device_name!=NULL; ++j ) {
    3597             :             for ( i=0; i<gdisp->n_inputdevices; ++i )
    3598             :                 if ( strcmp(de[j].device_name,gdisp->inputdevices[i].name)==0 )
    3599             :             break;
    3600             :             if ( i<gdisp->n_inputdevices ) {
    3601             :                 if ( gdisp->inputdevices[i].dev==NULL ) {
    3602             :                     XSync(gdisp->display,false);
    3603             :                     GDrawProcessPendingEvents((GDisplay *) gdisp);
    3604             :                     XSetErrorHandler(/*gdisp->display,*/devopenerror);
    3605             :                     devopen_failed = false;
    3606             :                     device_name = gdisp->inputdevices[i].name;
    3607             :                     gdisp->inputdevices[i].dev = XOpenDevice(gdisp->display,gdisp->inputdevices[i].devid);
    3608             :                     XSync(gdisp->display,false);
    3609             :                     GDrawProcessPendingEvents((GDisplay *) gdisp);
    3610             :                     XSetErrorHandler(/*gdisp->display,*/myerrorhandler);
    3611             :                     if ( devopen_failed )
    3612             :                         gdisp->inputdevices[i].dev = NULL;
    3613             :                 }
    3614             :                 if ( gdisp->inputdevices[i].dev!=NULL ) {
    3615             :                     ++availdevcnt;
    3616             :                     if ( de[j].event_mask & (1<<et_mousemove) ) {
    3617             :                         if ( classes!=NULL )
    3618             :                             DeviceMotionNotify(gdisp->inputdevices[i].dev,gdisp->inputdevices[i].event_types[0],classes[cnt]);
    3619             :                         ++cnt;
    3620             :                     }
    3621             :                     if ( de[j].event_mask & (1<<et_mousedown) ) {
    3622             :                         if ( classes!=NULL )
    3623             :                             DeviceButtonPress(gdisp->inputdevices[i].dev,gdisp->inputdevices[i].event_types[1],classes[cnt]);
    3624             :                         ++cnt;
    3625             :                     }
    3626             :                     if ( de[j].event_mask & (1<<et_mouseup) ) {
    3627             :                         if ( classes!=NULL )
    3628             :                             DeviceButtonRelease(gdisp->inputdevices[i].dev,gdisp->inputdevices[i].event_types[2],classes[cnt]);
    3629             :                         ++cnt;
    3630             :                     }
    3631             :                     if ( (de[j].event_mask & (1<<et_mousedown)) && (de[j].event_mask & (1<<et_mouseup)) ) {
    3632             :                         if ( classes!=NULL )
    3633             :                             DeviceButtonPressGrab(gdisp->inputdevices[i].dev,foo,classes[cnt]);
    3634             :                         ++cnt;
    3635             :                     }
    3636             :                     if ( de[j].event_mask & (1<<et_char) ) {
    3637             :                         if ( classes!=NULL )
    3638             :                             DeviceKeyPress(gdisp->inputdevices[i].dev,foo,classes[cnt]);
    3639             :                         ++cnt;
    3640             :                     }
    3641             :                     if ( de[j].event_mask & (1<<et_charup) ) {
    3642             :                         if ( classes!=NULL )
    3643             :                             DeviceKeyRelease(gdisp->inputdevices[i].dev,foo,classes[cnt]);
    3644             :                         ++cnt;
    3645             :                     }
    3646             :                 }
    3647             :             }
    3648             :         }
    3649             :         if ( cnt==0 )
    3650             : return(0);
    3651             :         if ( k==0 )
    3652             :             classes = malloc(cnt*sizeof(XEventClass));
    3653             :     }
    3654             :     XSelectExtensionEvent(gdisp->display,((GXWindow) w)->w,classes,cnt);
    3655             :     free(classes);
    3656             : return( availdevcnt );
    3657             : #else
    3658           0 : return( 0 );
    3659             : #endif
    3660             : }
    3661             : 
    3662           0 : static Bool exposeornotify(Display *d,XEvent *e,XPointer arg) {
    3663           0 :     if ( e->type == Expose || e->type == GraphicsExpose ||
    3664           0 :             e->type == CreateNotify || e->type == MapNotify ||
    3665           0 :             e->type == DestroyNotify || e->type == UnmapNotify ||
    3666           0 :             (e->type == SelectionNotify && e->xselection.requestor==(Window) arg) ||
    3667           0 :             e->type == SelectionClear || e->type == SelectionRequest )
    3668           0 : return( true );
    3669             : 
    3670           0 : return( false );
    3671             : }
    3672             : 
    3673           0 : static int GXDrawWaitForNotifyEvent(GXDisplay *gdisp,XEvent *event, Window w) {
    3674             :     struct timeval tv, giveup, timer, *which;
    3675           0 :     Display *display = gdisp->display;
    3676             :     struct timeval offset;
    3677             :     fd_set read, write, except;
    3678             :     int fd,ret;
    3679           0 :     int idx = 0;
    3680             :     
    3681           0 :     gettimeofday(&giveup,NULL);
    3682           0 :     giveup.tv_sec += gdisp->SelNotifyTimeout;
    3683             :     
    3684             :     for (;;) {
    3685           0 :         gettimeofday(&tv,NULL);
    3686           0 :         GXDrawCheckPendingTimers(gdisp);
    3687             : #ifdef _WACOM_DRV_BROKEN
    3688             :         _GXDraw_Wacom_TestEvents(gdisp);
    3689             : #endif
    3690             : #ifdef HAVE_PTHREAD_H
    3691           0 :         if ( gdisp->xthread.sync_sock!=-1 ) {
    3692           0 :             pthread_mutex_lock(&gdisp->xthread.sync_mutex);
    3693           0 :             if ( gdisp->xthread.things_to_do )
    3694           0 :                 GXDrawDoThings(gdisp);
    3695           0 :             pthread_mutex_unlock(&gdisp->xthread.sync_mutex);
    3696             :         }
    3697             : #endif
    3698             : 
    3699           0 :         while ( XCheckIfEvent(display,event,exposeornotify,(XPointer) w)) {
    3700           0 :             if ( event->type == SelectionNotify )
    3701           0 : return( true );
    3702           0 :             dispatchEvent(gdisp, event);
    3703             :         }
    3704             :         /* Which happens sooner? The timeout for waiting for a paste response,*/
    3705             :         /*  or one of the timers? */
    3706           0 :         if ( gdisp->timers==NULL )
    3707           0 :             which = &giveup;
    3708           0 :         else if ( giveup.tv_sec<gdisp->timers->time_sec ||
    3709           0 :                 ( giveup.tv_sec==gdisp->timers->time_sec && giveup.tv_usec<gdisp->timers->time_usec ))
    3710           0 :             which = &giveup;
    3711             :         else {
    3712           0 :             timer.tv_usec = gdisp->timers->time_usec; timer.tv_sec = gdisp->timers->time_sec;
    3713           0 :             which = &timer;
    3714             :         }
    3715           0 :         offset.tv_sec = which->tv_sec - tv.tv_sec;
    3716           0 :         if (( offset.tv_usec= which->tv_usec- tv.tv_usec)<0 ) {
    3717           0 :             offset.tv_usec += 1000000;
    3718           0 :             --offset.tv_sec;
    3719             :         }
    3720           0 :         if ( offset.tv_sec<0 || (offset.tv_sec==0 && offset.tv_usec==0)) {
    3721           0 :             if ( which == &giveup )
    3722           0 : return( false );
    3723             :         } else
    3724           0 :     continue;   /* Handle timer */
    3725             : 
    3726           0 :         fd = XConnectionNumber(display);
    3727           0 :         FD_ZERO(&read); FD_ZERO(&write); FD_ZERO(&except);
    3728           0 :         FD_SET(fd,&read);
    3729           0 :         FD_SET(fd,&except);
    3730           0 :         if ( gdisp->xthread.sync_sock!=-1 ) {
    3731           0 :             FD_SET(gdisp->xthread.sync_sock,&read);
    3732           0 :             if ( gdisp->xthread.sync_sock>fd )
    3733           0 :                 fd = gdisp->xthread.sync_sock;
    3734             :         }
    3735             : #ifdef _WACOM_DRV_BROKEN
    3736             :         if ( gdisp->wacom_fd!=-1 ) {
    3737             :             FD_SET(gdisp->wacom_fd,&read);
    3738             :             if ( gdisp->wacom_fd>fd )
    3739             :                 fd = gdisp->wacom_fd;
    3740             :         }
    3741             : #endif
    3742             : 
    3743           0 :         for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
    3744             :         {
    3745           0 :             fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
    3746           0 :             FD_SET( cb->fd, &read );
    3747           0 :             fd = MAX( fd, cb->fd );
    3748             :         }
    3749             :         
    3750           0 :         ret = select(fd+1,&read,&write,&except,&offset);
    3751             : 
    3752           0 :         for( idx = 0; idx < gdisp->fd_callbacks_last; ++idx )
    3753             :         {
    3754           0 :             fd_callback_t* cb = &gdisp->fd_callbacks[ idx ];
    3755           0 :             if( FD_ISSET(cb->fd,&read))
    3756           0 :                 cb->callback( cb->fd, cb->udata );
    3757             :         }
    3758           0 :     }
    3759             : }
    3760             : 
    3761           0 : static Atom GXDrawGetAtom(GXDisplay *gd, char *name) {
    3762             :     int i;
    3763             : 
    3764           0 :     if ( gd->atomdata==NULL ) {
    3765           0 :         gd->atomdata = calloc(10,sizeof(struct atomdata));
    3766           0 :         gd->amax = 10;
    3767             :     }
    3768           0 :     for ( i=0; i<gd->alen; ++i )
    3769           0 :         if ( strcmp(name,gd->atomdata[i].atomname)==0 )
    3770           0 : return( gd->atomdata[i].xatom );
    3771             : 
    3772           0 :     if ( i>=gd->amax )
    3773           0 :         gd->atomdata = realloc(gd->atomdata,(gd->amax+=10)*sizeof(struct atomdata));
    3774           0 :     gd->atomdata[i].atomname = copy(name);
    3775           0 :     gd->atomdata[i].xatom = XInternAtom(gd->display,name,false);
    3776           0 :     ++gd->alen;
    3777           0 : return( gd->atomdata[i].xatom );
    3778             : }
    3779             : 
    3780           0 : static void GXDrawClearSelData(GXDisplay *gd,enum selnames sel) {
    3781           0 :     struct seldata *sd = gd->selinfo[sel].datalist, *next;
    3782             : 
    3783           0 :     while ( sd!=NULL ) {
    3784           0 :         next = sd->next;
    3785           0 :         if ( sd->freedata )
    3786           0 :             (sd->freedata)(sd->data);
    3787             :         else
    3788           0 :             free(sd->data);
    3789           0 :         free(sd);
    3790           0 :         sd = next;
    3791             :     }
    3792           0 :     gd->selinfo[sel].datalist = NULL;
    3793           0 :     gd->selinfo[sel].owner = NULL;
    3794           0 : }
    3795             : 
    3796           0 : static void GXDrawGrabSelection(GWindow w,enum selnames sel) {
    3797           0 :     GXDisplay *gd = (GXDisplay *) (w->display);
    3798           0 :     GXWindow gw = (GXWindow) w;
    3799           0 :     if ( gd->selinfo[sel].owner!=NULL && gd->selinfo[sel].datalist != NULL) {
    3800             :         GEvent e;
    3801           0 :         memset(&e,0,sizeof(e));
    3802           0 :         e.type = et_selclear;
    3803           0 :         e.u.selclear.sel = sel;
    3804           0 :         e.native_window = (void *) (intpt) gd->selinfo[sel].owner->w;
    3805           0 :         if ( gd->selinfo[sel].owner->eh!=NULL )
    3806           0 :             (gd->selinfo[sel].owner->eh)((GWindow) gd->selinfo[sel].owner, &e);
    3807             :     }
    3808             :     //Only one clipboard exists on Windows. Selectively set the selection owner
    3809             :     //as otherwise the Windows clipboard will be cleared.
    3810             : #ifdef _WIN32
    3811             :     if (sel == sn_clipboard)
    3812             : #endif
    3813           0 :     XSetSelectionOwner(gd->display,gd->selinfo[sel].sel_atom,gw->w,gd->last_event_time);
    3814           0 :     GXDrawClearSelData(gd,sel);
    3815           0 :     gd->selinfo[sel].owner = gw;
    3816           0 :     gd->selinfo[sel].timestamp = gd->last_event_time;
    3817           0 : }
    3818             : 
    3819           0 : static void GXDrawAddSelectionType(GWindow w,enum selnames sel,char *type,
    3820             :         void *data,int32 cnt,int32 unitsize, void *(*gendata)(void *,int32 *len),
    3821             :         void (*freedata)(void *)) {
    3822           0 :     GXDisplay *gd = (GXDisplay *) (w->display);
    3823           0 :     int typeatom = GXDrawGetAtom(gd,type);
    3824             :     struct seldata *sd;
    3825             : 
    3826           0 :     if ( unitsize!=1 && unitsize!=2 && unitsize!=4 ) {
    3827           0 :         GDrawIError( "Bad unitsize to GXDrawAddSelectionType" );
    3828           0 :         unitsize = 1;
    3829             :     }
    3830           0 :     for ( sd=gd->selinfo[sel].datalist; sd!=NULL && sd->typeatom!=typeatom;
    3831           0 :             sd = sd->next );
    3832           0 :     if ( sd==NULL ) {
    3833           0 :         sd = malloc(sizeof(struct seldata));
    3834           0 :         sd->next = gd->selinfo[sel].datalist;
    3835           0 :         gd->selinfo[sel].datalist = sd;
    3836           0 :         sd->typeatom = typeatom;
    3837             :     }
    3838           0 :     sd->cnt = cnt;
    3839           0 :     sd->data = data;
    3840           0 :     sd->unitsize = unitsize;
    3841           0 :     sd->gendata = gendata;
    3842           0 :     sd->freedata = freedata;
    3843           0 : }
    3844             : 
    3845           0 : static void GXDrawTransmitSelection(GXDisplay *gd,XEvent *event) {
    3846           0 :     int prop_set = False;
    3847             :     int which;
    3848             :     XEvent e_to_send;
    3849             :     Atom *targets;
    3850           0 :     Atom cur_targ = event->xselectionrequest.target;
    3851             :     Atom prop;
    3852             :     int tlen;
    3853             :     struct seldata *sd;
    3854           0 :     int is_multiple = cur_targ == GXDrawGetAtom(gd,"MULTIPLE");
    3855           0 :     int found = 0;
    3856             :     void *temp;
    3857             :     int32 proplen;
    3858             : 
    3859           0 :     for ( which = 0; which<sn_max; ++which )
    3860           0 :         if ( event->xselectionrequest.selection == gd->selinfo[which].sel_atom )
    3861           0 :     break;
    3862           0 :     if ( which==sn_max )
    3863           0 : return;
    3864             : 
    3865           0 :     e_to_send.type = SelectionNotify;
    3866           0 :     e_to_send.xselection.display = event->xselectionrequest.display;
    3867           0 :     e_to_send.xselection.requestor = event->xselectionrequest.requestor;
    3868           0 :     e_to_send.xselection.selection = event->xselectionrequest.selection;
    3869           0 :     e_to_send.xselection.target = event->xselectionrequest.target;
    3870           0 :     e_to_send.xselection.property = event->xselectionrequest.property;
    3871           0 :     e_to_send.xselection.time = event->xselectionrequest.time;
    3872             :      /* Obsolete convention */
    3873           0 :     if ( e_to_send.xselection.property==None )
    3874           0 :         e_to_send.xselection.property = e_to_send.xselection.target;
    3875           0 :     prop = e_to_send.xselection.property;
    3876             : 
    3877           0 :     tlen = 0;
    3878           0 :     for ( sd = gd->selinfo[which].datalist; sd!=NULL && !found; sd = sd->next, ++tlen ) {
    3879           0 :         if ( cur_targ==sd->typeatom || is_multiple ) {
    3880           0 :             found = (cur_targ==sd->typeatom);
    3881           0 :             prop_set = 1;
    3882           0 :             if (is_multiple)
    3883           0 :                 prop = sd->typeatom;
    3884           0 :             temp = sd->data;
    3885           0 :             proplen = sd->cnt;
    3886           0 :             if ( sd->gendata )
    3887           0 :                 temp = (sd->gendata)(temp,&proplen);
    3888           0 :             XChangeProperty(e_to_send.xselection.display,
    3889             :                                         e_to_send.xselection.requestor,
    3890             :                                         prop,
    3891           0 :                                         sd->typeatom,
    3892           0 :                                         8*sd->unitsize,PropModeReplace,
    3893             :                                         temp,proplen);
    3894           0 :             if ( sd->gendata )
    3895           0 :                 free( temp );
    3896             :         }
    3897             :     }
    3898           0 :     sd = gd->selinfo[which].datalist;
    3899           0 :     if (sd!=NULL && ( cur_targ==GXDrawGetAtom(gd,"LENGTH") || is_multiple )) {
    3900           0 :         if ( is_multiple )
    3901           0 :             prop = GXDrawGetAtom(gd,"LENGTH");
    3902           0 :         temp = NULL; proplen = sd->cnt*sd->unitsize;
    3903           0 :         if ( sd->gendata )
    3904           0 :             temp = (sd->gendata)(sd->data,&proplen);
    3905           0 :         XChangeProperty(e_to_send.xselection.display,
    3906             :                                     e_to_send.xselection.requestor,
    3907             :                                     prop,
    3908             :                                     GXDrawGetAtom(gd,"LENGTH"),32,PropModeReplace,
    3909             :                                     (void *) &proplen,1);
    3910           0 :         free(temp);
    3911           0 :         prop_set = True;
    3912             :     }
    3913           0 :     if ( sd!=NULL && ( cur_targ==GXDrawGetAtom(gd,"IDENTIFY") || is_multiple )) {
    3914           0 :         int temp = sd->typeatom;
    3915           0 :         if (is_multiple)
    3916           0 :             prop = GXDrawGetAtom(gd,"IDENTIFY");
    3917           0 :         XChangeProperty(e_to_send.xselection.display,
    3918             :                                     e_to_send.xselection.requestor,
    3919             :                                     prop,
    3920             :                                     GXDrawGetAtom(gd,"IDENTIFY"),32,PropModeReplace,
    3921             :                                     (void *) &temp,1);
    3922           0 :         prop_set = True;
    3923             :     }
    3924           0 :     if ( cur_targ==GXDrawGetAtom(gd,"TIMESTAMP") || is_multiple ) {
    3925           0 :         if (is_multiple)
    3926           0 :             prop = GXDrawGetAtom(gd,"TIMESTAMP");
    3927           0 :         XChangeProperty(e_to_send.xselection.display,
    3928             :                                     e_to_send.xselection.requestor,
    3929             :                                     prop,
    3930             :                                     XA_INTEGER,32,PropModeReplace,
    3931           0 :                                     (void *) &gd->selinfo[which].timestamp,1);
    3932           0 :         prop_set = True;
    3933             :     }
    3934           0 :     if ( cur_targ==GXDrawGetAtom(gd,"TARGETS") || is_multiple ) {
    3935             :         int i;
    3936           0 :         targets = calloc(tlen+5,sizeof(Atom));
    3937           0 :         for ( sd = gd->selinfo[which].datalist, i=0; sd!=NULL; sd = sd->next, ++i )
    3938           0 :             targets[i] = sd->typeatom;
    3939           0 :         targets[i++] = GXDrawGetAtom(gd,"LENGTH");
    3940           0 :         targets[i++] = GXDrawGetAtom(gd,"IDENTIFY");
    3941           0 :         targets[i++] = GXDrawGetAtom(gd,"TIMESTAMP");
    3942           0 :         targets[i++] = GXDrawGetAtom(gd,"TARGETS");
    3943           0 :         targets[i++] = GXDrawGetAtom(gd,"MULTIPLE");
    3944           0 :         if (is_multiple)
    3945           0 :             prop = GXDrawGetAtom(gd,"TARGETS");
    3946           0 :         XChangeProperty(e_to_send.xselection.display,
    3947             :                                     e_to_send.xselection.requestor,
    3948             :                                     prop,
    3949             :                                     XA_ATOM,32,PropModeReplace,
    3950             :                                     (void *) targets,i);
    3951           0 :         free(targets);
    3952           0 :         prop_set = True;
    3953             :     }
    3954           0 :     if ( is_multiple ) {
    3955             :         int i;
    3956           0 :         targets = calloc(tlen+5,sizeof(Atom));
    3957           0 :         for ( sd = gd->selinfo[which].datalist, i=0; sd!=NULL; sd = sd->next, ++i )
    3958           0 :             targets[i] = sd->typeatom;
    3959           0 :         targets[i++] = GXDrawGetAtom(gd,"LENGTH");
    3960           0 :         targets[i++] = GXDrawGetAtom(gd,"IDENTIFY");
    3961           0 :         targets[i++] = GXDrawGetAtom(gd,"TIMESTAMP");
    3962           0 :         targets[i++] = GXDrawGetAtom(gd,"TARGETS");
    3963           0 :         targets[i++] = GXDrawGetAtom(gd,"MULTIPLE");
    3964           0 :         XChangeProperty(e_to_send.xselection.display,
    3965             :                                     e_to_send.xselection.requestor,
    3966           0 :                                     targets[i-1],       /* multiple */
    3967             :                                     XA_ATOM,32,PropModeReplace,
    3968             :                                     (void *) targets,i);
    3969           0 :         XChangeProperty(e_to_send.xselection.display,
    3970             :                                     e_to_send.xselection.requestor,
    3971             :                                     e_to_send.xselection.target,
    3972             :                                     XA_ATOM,32,PropModeReplace,
    3973             :                                     (void *) targets,i);
    3974           0 :         free(targets);
    3975             :     }
    3976             : 
    3977           0 :     if ( !prop_set )
    3978           0 :         e_to_send.xselection.property = None;
    3979           0 :     XSendEvent(gd->display,e_to_send.xselection.requestor,True,0,&e_to_send);
    3980             : }
    3981             : 
    3982           0 : static void *GXDrawRequestSelection(GWindow w,enum selnames sn, char *typename, int32 *len) {
    3983           0 :     GXDisplay *gd = (GXDisplay *) (w->display);
    3984           0 :     GXWindow gw = (GXWindow) w;
    3985           0 :     Display *display = gd->display;
    3986             :     unsigned long nitems, bytes_after;
    3987             :     Atom actual_type;
    3988             :     int actual_format;
    3989             :     char *prop;
    3990             :     char *temp;
    3991             :     int bytelen;
    3992           0 :     Atom typeatom = GXDrawGetAtom(gd,typename);
    3993             :     XEvent xevent;
    3994             :     struct seldata *sd;
    3995             : 
    3996           0 :     if ( len!=NULL )
    3997           0 :         *len = 0;
    3998             : 
    3999             :     /* Do we own the selection? If so check for the type in our list of things*/
    4000             :     /*  if present return a copy (so they can free it), if absent return NULL */
    4001           0 :     if ( gd->selinfo[sn].owner!=NULL ) {
    4002           0 :         for ( sd=gd->selinfo[sn].datalist; sd!=NULL; sd=sd->next ) {
    4003           0 :             if ( sd->typeatom == typeatom ) {
    4004           0 :                 if ( sd->gendata!=NULL ) {
    4005           0 :                     temp = (sd->gendata)(sd->data,len);
    4006           0 :                     *len *= sd->unitsize;
    4007             :                 } else {
    4008           0 :                     bytelen = sd->unitsize*sd->cnt;
    4009           0 :                     temp = malloc(bytelen+4);
    4010           0 :                     memcpy(temp,sd->data,bytelen);
    4011           0 :                     temp[bytelen] = '\0';
    4012           0 :                     temp[bytelen+1] = '\0';
    4013           0 :                     temp[bytelen+2] = '\0';
    4014           0 :                     temp[bytelen+3] = '\0';
    4015           0 :                     *len = bytelen;
    4016             :                 }
    4017           0 : return( temp );
    4018             :             }
    4019             :         }
    4020           0 : return( NULL );
    4021             :     }
    4022             : 
    4023             :     /* Otherwise ask the owner for the selection, wait to be notified that he's*/
    4024             :     /*  given it to us (we might time out, return NULL if we do) */
    4025           0 :     XConvertSelection(display, gd->selinfo[sn].sel_atom, typeatom,
    4026           0 :            gd->selinfo[sn].sel_atom, gw->w,gd->last_event_time);
    4027           0 :     if ( !GXDrawWaitForNotifyEvent(gd,&xevent, gw->w) ||
    4028           0 :             xevent.xselection.property == None ) {
    4029           0 : return( NULL );
    4030           0 :     } else if (XGetWindowProperty(display,xevent.xselection.requestor,
    4031             :               xevent.xselection.property,0L,100000000L,True,AnyPropertyType,
    4032             :               &actual_type,&actual_format,&nitems,&bytes_after,
    4033           0 :               (unsigned char **) &prop) != Success ||
    4034           0 :             prop==NULL ) {
    4035           0 :         GDrawIError("Could not retrieve property in GXDrawRequestSelection" );
    4036           0 : return( NULL );
    4037             :     }
    4038             : 
    4039           0 :     bytelen = nitems * (actual_format/8);
    4040           0 :     temp = malloc(bytelen+4);
    4041           0 :     memcpy(temp,prop,bytelen);
    4042           0 :     temp[bytelen]='\0';
    4043           0 :     temp[bytelen+1]='\0';               /* Nul terminate unicode strings too */
    4044           0 :     temp[bytelen+2] = '\0';
    4045           0 :     temp[bytelen+3] = '\0';
    4046           0 :     if ( len!=NULL )
    4047           0 :         *len = bytelen;
    4048           0 :     XFree(prop);
    4049           0 : return(temp);
    4050             : }
    4051             : 
    4052           0 : static int GXDrawSelectionHasType(GWindow w,enum selnames sn, char *typename) {
    4053           0 :     GXDisplay *gd = (GXDisplay *) (w->display);
    4054           0 :     Display *display = gd->display;
    4055           0 :     GXWindow gw = (GXWindow) w;
    4056             :     unsigned long nitems, bytes_after;
    4057             :     Atom actual_type;
    4058             :     int actual_format;
    4059             :     char *prop;
    4060           0 :     Atom typeatom = GXDrawGetAtom(gd,typename);
    4061             :     int i;
    4062             :     XEvent xevent;
    4063             :     struct seldata *sd;
    4064             : 
    4065             :     /* Do we own the selection? If so check for the type in our list of things*/
    4066             :     /*  if present return a copy (so they can free it), if absent return NULL */
    4067           0 :     if ( gd->selinfo[sn].owner!=NULL ) {
    4068           0 :         for ( sd=gd->selinfo[sn].datalist; sd!=NULL; sd=sd->next ) {
    4069           0 :             if ( sd->typeatom == typeatom )
    4070           0 : return( true );
    4071             :         }
    4072           0 : return( false );
    4073             :     }
    4074             : 
    4075           0 :     if ( gd->seltypes.timestamp!=gd->last_event_time ) {
    4076             :         /* List is not up to date, ask for a new one */
    4077           0 :         gd->seltypes.cnt = 0;
    4078           0 :         XFree(gd->seltypes.types); gd->seltypes.types = NULL;
    4079           0 :         XConvertSelection(display, gd->selinfo[sn].sel_atom, GXDrawGetAtom(gd,"TARGETS"),
    4080           0 :                gd->selinfo[sn].sel_atom, gw->w,gd->last_event_time);
    4081           0 :         if ( !GXDrawWaitForNotifyEvent(gd,&xevent, gw->w) ||
    4082           0 :                 xevent.xselection.property == None ) {
    4083           0 : return( false );
    4084           0 :         } else if (XGetWindowProperty(display,xevent.xselection.requestor,
    4085             :                   xevent.xselection.property,0L,100000000L,True,AnyPropertyType,
    4086             :                   &actual_type,&actual_format,&nitems,&bytes_after,
    4087           0 :                   (unsigned char **) &prop) != Success ||
    4088           0 :                 prop==NULL || actual_format!=32 ) {
    4089           0 :         GDrawIError("Could not retrieve property in GXDrawSelectionHasType" );
    4090           0 : return( false );
    4091             :         } else {
    4092           0 :             gd->seltypes.cnt = nitems;
    4093           0 :             gd->seltypes.types = (Atom *) prop;
    4094           0 :             gd->seltypes.timestamp = gd->last_event_time = xevent.xselection.time;
    4095             :         }
    4096             :     }
    4097           0 :     for ( i=0; i<gd->seltypes.cnt; ++i )
    4098           0 :         if ( gd->seltypes.types[i]==typeatom )
    4099           0 : return( true );
    4100             : 
    4101           0 : return( false );
    4102             : }
    4103             : 
    4104           0 : static void GXDrawBindSelection(GDisplay *disp,enum selnames sn, char *atomname) {
    4105           0 :     GXDisplay *gdisp = (GXDisplay *) disp;
    4106           0 :     Display *display = gdisp->display;
    4107           0 :     if ( sn>=0 && sn<sn_max )
    4108           0 :         gdisp->selinfo[sn].sel_atom = XInternAtom(display,atomname,False);
    4109           0 : }
    4110             : 
    4111           0 : static int GXDrawSelectionHasOwner(GDisplay *disp,enum selnames sn) {
    4112           0 :     GXDisplay *gdisp = (GXDisplay *) disp;
    4113           0 :     Display *display = ((GXDisplay *) gdisp)->display;
    4114           0 :     if ( sn<0 || sn>=sn_max )
    4115           0 : return( false );
    4116             : 
    4117           0 : return( XGetSelectionOwner(display,gdisp->selinfo[sn].sel_atom)!=None );
    4118             : }
    4119             : 
    4120           0 : static int match(char **list, char *val) {
    4121             :     int i;
    4122             : 
    4123           0 :     for ( i=0; list[i]!=NULL; ++i )
    4124           0 :         if ( strmatch(val,list[i])==0 )
    4125           0 : return( i );
    4126             : 
    4127           0 : return( -1 );
    4128             : }
    4129             : 
    4130           0 : static void *vc_cvt(char *val, void *def) {
    4131             :     static char *classes[] = { "StaticGray", "GrayScale", "StaticColor", "PsuedoColor", "TrueColor", "DirectColor", NULL };
    4132           0 :     int ret = match(classes,val);
    4133           0 :     if ( ret== -1 ) {
    4134             :         char *ept;
    4135           0 :         ret = strtol(val,&ept,10);
    4136           0 :         if ( ept==val || *ept!='\0' )
    4137           0 : return( def );
    4138             :     }
    4139           0 : return( (void *) (intpt) ret );
    4140             : }
    4141             : 
    4142           0 : static void *cm_cvt(char *val, void *def) {
    4143             :     static char *choices[] = { "default", "current", "copy", "private", NULL };
    4144           0 :     int ret = match(choices,val);
    4145           0 :     if ( ret== -1 )
    4146           0 : return( (void *) -1 );
    4147             : 
    4148           0 : return( (void *) (intpt) (ret-1) );
    4149             : }
    4150             : 
    4151           0 : static void GXResourceInit(GXDisplay *gdisp,char *programname) {
    4152             :     Atom rmatom, type;
    4153             :     int format, i; unsigned long nitems, bytes_after;
    4154           0 :     unsigned char *ret = NULL;
    4155             :     GResStruct res[21];
    4156             :     int dithertemp; double sizetemp, sizetempcm;
    4157           0 :     int depth = -1, vc = -1, cm=-1, cmpos;
    4158           0 :     int tbf = 1;
    4159             : #if __Mac
    4160             :     int mxc = 1;        /* Don't leave this on by default. The cmd key uses the same bit as numlock on other systems */
    4161             : #else
    4162           0 :     int mxc = 0;
    4163             : #endif
    4164             : 
    4165           0 :     rmatom = XInternAtom(gdisp->display,"RESOURCE_MANAGER",true);
    4166           0 :     if ( rmatom!=None ) {
    4167           0 :         XGetWindowProperty(gdisp->display,((GXWindow) (gdisp->groot))->w, rmatom, 0,
    4168             :                 0x7fffff, false, XA_STRING,
    4169             :                 &type, &format, &nitems, &bytes_after, &ret);
    4170           0 :         if ( type == None )
    4171           0 :             ret = NULL;
    4172           0 :         else if ( type!=XA_STRING || format!=8 ) {
    4173           0 :             XFree(ret);
    4174           0 :             ret = NULL;
    4175             :         }
    4176             :     }
    4177           0 :     GResourceAddResourceString((char *) ret,programname);
    4178           0 :     if ( ret!=NULL ) XFree(ret);
    4179             : 
    4180           0 :     memset(res,0,sizeof(res));
    4181           0 :     i = 0;
    4182           0 :     res[i].resname = "MultiClickTime"; res[i].type = rt_int; res[i].val = &gdisp->bs.double_time; ++i;
    4183           0 :     res[i].resname = "MultiClickWiggle"; res[i].type = rt_int; res[i].val = &gdisp->bs.double_wiggle; ++i;
    4184           0 :     res[i].resname = "SelectionNotifyTimeout"; res[i].type = rt_int; res[i].val = &gdisp->SelNotifyTimeout; ++i;
    4185           0 :     dithertemp = gdisp->do_dithering;
    4186           0 :     res[i].resname = "DoDithering"; res[i].type = rt_bool; res[i].val = &dithertemp; ++i;
    4187           0 :     res[i].resname = "ScreenWidthPixels"; res[i].type = rt_int; res[i].val = &gdisp->groot->pos.width; ++i;
    4188           0 :     res[i].resname = "ScreenHeightPixels"; res[i].type = rt_int; res[i].val = &gdisp->groot->pos.height; ++i;
    4189           0 :     sizetemp = WidthMMOfScreen(DefaultScreenOfDisplay(gdisp->display))/25.4;
    4190           0 :     sizetempcm = WidthMMOfScreen(DefaultScreenOfDisplay(gdisp->display))/10;
    4191           0 :     gdisp->xres = gdisp->groot->pos.width/sizetemp;
    4192           0 :     res[i].resname = "ScreenWidthInches"; res[i].type = rt_double; res[i].val = &sizetemp; ++i;
    4193           0 :     cmpos = i;
    4194           0 :     res[i].resname = "ScreenWidthCentimeters"; res[i].type = rt_double; res[i].val = &sizetempcm; ++i;
    4195           0 :     res[i].resname = "Depth"; res[i].type = rt_int; res[i].val = &depth; ++i;
    4196           0 :     res[i].resname = "VisualClass"; res[i].type = rt_string; res[i].val = &vc; res[i].cvt=vc_cvt; ++i;
    4197           0 :     res[i].resname = "TwoButtonFixup"; res[i].type = rt_bool; res[i].val = &tbf; ++i;
    4198           0 :     res[i].resname = "MacOSXCmd"; res[i].type = rt_bool; res[i].val = &mxc; ++i;
    4199           0 :     res[i].resname = "Colormap"; res[i].type = rt_string; res[i].val = &cm; res[i].cvt=cm_cvt; ++i;
    4200           0 :     res[i].resname = NULL;
    4201           0 :     GResourceFind(res,NULL);
    4202             : 
    4203           0 :     if ( !res[cmpos].found && !res[cmpos-1].found && rint(gdisp->groot->pos.width/sizetemp) == 75 )
    4204           0 :         gdisp->res = 100;    /* X seems to think that if it doesn't know */
    4205             :                                 /*  the screen width, then 75 dpi is a good guess */
    4206             :                                 /*  Now-a-days, 100 seems better */
    4207             :     else
    4208           0 :     if ( res[cmpos].found && sizetempcm>=1 )
    4209           0 :         gdisp->res = gdisp->groot->pos.width*2.54/sizetempcm;
    4210           0 :     else if ( sizetemp>=1 )
    4211           0 :         gdisp->res = gdisp->groot->pos.width/sizetemp;
    4212           0 :     gdisp->desired_depth = depth; gdisp->desired_vc = vc;
    4213           0 :     gdisp->desired_cm = cm;
    4214           0 :     gdisp->macosx_cmd = mxc;
    4215           0 :     gdisp->twobmouse_win = tbf;
    4216           0 : }
    4217             : 
    4218           0 : static GWindow GXPrinterStartJob(GDisplay *gdisp,void *user_data,GPrinterAttrs *attrs) {
    4219           0 :     fprintf(stderr, "Invalid call to GPrinterStartJob on X display\n" );
    4220           0 : return( NULL );
    4221             : }
    4222             : 
    4223           0 : static void GXPrinterNextPage(GWindow w) {
    4224           0 :     fprintf(stderr, "Invalid call to GPrinterNextPage on X display\n" );
    4225           0 : }
    4226             : 
    4227           0 : static int GXPrinterEndJob(GWindow w,int cancel) {
    4228           0 :     fprintf(stderr, "Invalid call to GPrinterEndJob on X display\n" );
    4229           0 : return( false );
    4230             : }
    4231             : 
    4232             : static struct displayfuncs xfuncs = {
    4233             :     GXDrawInit,
    4234             :     GXDrawTerm,
    4235             :     GXDrawNativeDisplay,
    4236             : 
    4237             :     GXDrawSetDefaultIcon,
    4238             : 
    4239             :     GXDrawCreateTopWindow,
    4240             :     GXDrawCreateSubWindow,
    4241             :     GXDrawCreatePixmap,
    4242             :     GXDrawCreateBitmap,
    4243             :     GXDrawCreateCursor,
    4244             :     GXDrawDestroyWindow,
    4245             :     GXDestroyCursor,
    4246             :     GXNativeWindowExists,
    4247             :     GXDrawSetZoom,
    4248             :     GXDrawSetWindowBorder,
    4249             :     GXDrawSetWindowBackground,
    4250             :     GXSetDither,
    4251             : 
    4252             :     GXDrawReparentWindow,
    4253             :     GXDrawSetVisible,
    4254             :     GXDrawMove,
    4255             :     GXDrawTrueMove,
    4256             :     GXDrawResize,
    4257             :     GXDrawMoveResize,
    4258             :     GXDrawRaise,
    4259             :     GXDrawRaiseAbove,
    4260             :     GXDrawIsAbove,
    4261             :     GXDrawLower,
    4262             :     GXDrawSetWindowTitles,
    4263             :     GXDrawSetWindowTitles8,
    4264             :     GXDrawGetWindowTitle,
    4265             :     GXDrawGetWindowTitle8,
    4266             :     GXDrawSetTransientFor,
    4267             :     GXDrawGetPointerPosition,
    4268             :     GXDrawGetPointerWindow,
    4269             :     GXDrawSetCursor,
    4270             :     GXDrawGetCursor,
    4271             :     GXDrawGetRedirectWindow,
    4272             :     GXDrawTranslateCoordinates,
    4273             : 
    4274             :     GXDrawBeep,
    4275             :     GXDrawFlush,
    4276             : 
    4277             :     GXDrawPushClip,
    4278             :     GXDrawPopClip,
    4279             : 
    4280             :     GXDrawClear,
    4281             :     GXDrawDrawLine,
    4282             :     GXDrawDrawArrow,
    4283             :     GXDrawDrawRect,
    4284             :     GXDrawFillRect,
    4285             :     GXDrawFillRoundRect,
    4286             :     GXDrawDrawElipse,
    4287             :     GXDrawFillElipse,
    4288             :     GXDrawDrawArc,
    4289             :     GXDrawDrawPoly,
    4290             :     GXDrawFillPoly,
    4291             :     GXDrawScroll,
    4292             : 
    4293             :     _GXDraw_Image,
    4294             :     _GXDraw_TileImage,
    4295             :     _GXDraw_Glyph,
    4296             :     _GXDraw_ImageMagnified,
    4297             :     _GXDraw_CopyScreenToImage,
    4298             :     _GXDraw_Pixmap,
    4299             :     _GXDraw_TilePixmap,
    4300             : 
    4301             :     GXDrawCreateInputContext,
    4302             :     GXDrawSetGIC,
    4303             : 
    4304             :     GXDrawGrabSelection,
    4305             :     GXDrawAddSelectionType,
    4306             :     GXDrawRequestSelection,
    4307             :     GXDrawSelectionHasType,
    4308             :     GXDrawBindSelection,
    4309             :     GXDrawSelectionHasOwner,
    4310             : 
    4311             :     GXDrawPointerUngrab,
    4312             :     GXDrawPointerGrab,
    4313             :     GXDrawRequestExpose,
    4314             :     GXDrawForceUpdate,
    4315             :     GXDrawSync,
    4316             :     GXDrawSkipMouseMoveEvents,
    4317             :     GXDrawProcessPendingEvents,
    4318             :     GXDrawProcessWindowEvents,
    4319             :     GXDrawProcessOneEvent,
    4320             :     GXDrawEventLoop,
    4321             :     GXDrawPostEvent,
    4322             :     GXDrawPostDragEvent,
    4323             :     GXDrawRequestDeviceEvents,
    4324             : 
    4325             :     GXDrawRequestTimer,
    4326             :     GXDrawCancelTimer,
    4327             : 
    4328             :     GXDrawSyncThread,
    4329             : 
    4330             :     GXPrinterStartJob,
    4331             :     GXPrinterNextPage,
    4332             :     GXPrinterEndJob,
    4333             : 
    4334             :     GXDrawFontMetrics,
    4335             : 
    4336             :     GXDrawHasCairo,
    4337             :     GXDrawPathStartNew,
    4338             :     GXDrawPathClose,
    4339             :     GXDrawPathMoveTo,
    4340             :     GXDrawPathLineTo,
    4341             :     GXDrawPathCurveTo,
    4342             :     GXDrawPathStroke,
    4343             :     GXDrawPathFill,
    4344             :     GXDrawPathFillAndStroke,
    4345             : 
    4346             :     GXDrawLayoutInit,
    4347             :     GXDraw_LayoutDraw,
    4348             :     GXDraw_LayoutIndexToPos,
    4349             :     GXDraw_LayoutXYToIndex,
    4350             :     GXDraw_LayoutExtents,
    4351             :     GXDraw_LayoutSetWidth,
    4352             :     GXDraw_LayoutLineCount,
    4353             :     GXDraw_LayoutLineStart,
    4354             :     GXDrawPathStartSubNew,
    4355             :     GXDrawFillRuleSetWinding,
    4356             : 
    4357             :     GXDrawPushClipOnly,
    4358             :     GXDrawClipPreserve
    4359             : };
    4360             : 
    4361           0 : static void GDrawInitXKB(GXDisplay *gdisp) {
    4362             : #ifdef _NO_XKB
    4363             :     gdisp->has_xkb = false;
    4364             : #else
    4365           0 :     int lib_major = XkbMajorVersion, lib_minor = XkbMinorVersion;
    4366             : 
    4367           0 :     gdisp->has_xkb = false;
    4368           0 :     if ( XkbLibraryVersion(&lib_major, &lib_minor))
    4369           0 :         gdisp->has_xkb = XkbQueryExtension(gdisp->display,
    4370             :                 &gdisp->xkb.opcode,&gdisp->xkb.event,&gdisp->xkb.error,
    4371             :                 &lib_major,&lib_minor);
    4372           0 :     if ( gdisp->has_xkb ) {
    4373           0 :         int mask = XkbNewKeyboardNotifyMask | XkbMapNotifyMask;
    4374           0 :         XkbSelectEvents(gdisp->display,XkbUseCoreKbd,mask,mask);
    4375             :     }
    4376             : #endif
    4377           0 : }
    4378             : 
    4379           0 : void _GXDraw_DestroyDisplay(GDisplay * gdisp) {
    4380           0 :     GXDisplay* gdispc = (GXDisplay*)(gdisp);
    4381           0 :     if (gdispc->grey_stipple != BadAlloc && gdispc->grey_stipple != BadDrawable && gdispc->grey_stipple != BadValue) {
    4382           0 :       XFreePixmap(gdispc->display, gdispc->grey_stipple); gdispc->grey_stipple = BadAlloc;
    4383             :     }
    4384           0 :     if (gdispc->fence_stipple != BadAlloc && gdispc->fence_stipple != BadDrawable && gdispc->fence_stipple != BadValue) {
    4385           0 :       XFreePixmap(gdispc->display, gdispc->fence_stipple); gdispc->fence_stipple = BadAlloc;
    4386             :     }
    4387           0 :     if (gdispc->pango_context != NULL) {
    4388           0 :         g_object_unref(gdispc->pango_context); gdispc->pango_context = NULL;
    4389             :     }
    4390           0 :     if (gdispc->groot != NULL) {
    4391           0 :       if (gdispc->groot->ggc != NULL) { free(gdispc->groot->ggc); gdispc->groot->ggc = NULL; }
    4392           0 :       free(gdispc->groot); gdispc->groot = NULL;
    4393             :     }
    4394           0 :     if (gdispc->im != NULL) { XCloseIM(gdispc->im); gdispc->im = NULL; }
    4395           0 :     if (gdispc->display != NULL) { XCloseDisplay(gdispc->display); gdispc->display = NULL; }
    4396           0 :     return;
    4397             : }
    4398             : 
    4399           0 : GDisplay *_GXDraw_CreateDisplay(char *displayname,char *programname) {
    4400             :     GXDisplay *gdisp;
    4401             :     Display *display;
    4402             :     GXWindow groot;
    4403             :     Window focus;
    4404             :     int revert;
    4405             :     static unsigned char grey_init[8] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };
    4406             :     static unsigned char fence_init[8] = { 0x55, 0x22, 0x55, 0x88, 0x55, 0x22, 0x55, 0x88};
    4407             : #ifdef HAVE_PTHREAD_H
    4408             :     static pthread_mutex_t defmutex = PTHREAD_MUTEX_INITIALIZER;
    4409             : #endif
    4410             : 
    4411           0 :     display = XOpenDisplay(displayname);
    4412           0 :     if ( display==NULL )
    4413           0 : return( NULL );
    4414             : 
    4415           0 :     setlocale(LC_ALL,"");
    4416           0 :     XSupportsLocale();
    4417           0 :     XSetLocaleModifiers("");
    4418             : 
    4419           0 :     gdisp = calloc(1,sizeof(GXDisplay));
    4420           0 :     if ( gdisp==NULL ) {
    4421           0 :         XCloseDisplay(display);
    4422           0 : return( NULL );
    4423             :     }
    4424             : 
    4425           0 :     gdisp->funcs = &xfuncs;
    4426           0 :     gdisp->display = display;
    4427           0 :     gdisp->screen = DefaultScreen(display);
    4428           0 :     gdisp->root = RootWindow(display,gdisp->screen);
    4429           0 :     gdisp->virtualRoot = BadAlloc;
    4430           0 :     gdisp->res = (25.4*WidthOfScreen(DefaultScreenOfDisplay(display)))/
    4431           0 :             WidthMMOfScreen(DefaultScreenOfDisplay(display));
    4432           0 :     gdisp->scale_screen_by = 1;
    4433           0 :     gdisp->mykey_keysym = XK_F12;
    4434           0 :     gdisp->mykey_mask = 0;
    4435           0 :     gdisp->do_dithering = true;
    4436           0 :     gdisp->desired_vc = gdisp->desired_depth = -1;
    4437             : 
    4438           0 :     gdisp->gcstate[0].gc = NULL;
    4439           0 :     gdisp->gcstate[0].fore_col = 0x1000000;  /* Doesn't match any colour */
    4440           0 :     gdisp->gcstate[0].back_col = 0x1000000;  /* Doesn't match any colour */
    4441           0 :     gdisp->gcstate[0].clip.x = gdisp->gcstate[0].clip.y = 0;
    4442           0 :     gdisp->gcstate[0].clip.width = gdisp->gcstate[0].clip.height = 0x7fff;
    4443           0 :     gdisp->gcstate[0].func = df_copy;
    4444             : 
    4445           0 :     gdisp->gcstate[1].fore_col = 0x1000000;  /* Doesn't match any colour */
    4446           0 :     gdisp->gcstate[1].back_col = 0x1000000;  /* Doesn't match any colour */
    4447           0 :     gdisp->gcstate[1].clip.x = gdisp->gcstate[1].clip.y = 0;
    4448           0 :     gdisp->gcstate[1].clip.width = gdisp->gcstate[1].clip.height = 0x7fff;
    4449           0 :     gdisp->gcstate[1].func = df_copy;
    4450             : 
    4451           0 :     gdisp->bs.double_time = 200;
    4452           0 :     gdisp->bs.double_wiggle = 3;
    4453           0 :     gdisp->SelNotifyTimeout = 20;            /* wait 20 seconds for a response to a selection request */
    4454             : 
    4455           0 :     while ( gdisp->mycontext==0 )
    4456           0 :         gdisp->mycontext = XUniqueContext();
    4457             : 
    4458           0 :     gdisp->grey_stipple = XCreatePixmapFromBitmapData(display,gdisp->root,(char *) grey_init,8,8,1,0,1);
    4459           0 :     gdisp->fence_stipple = XCreatePixmapFromBitmapData(display,gdisp->root,(char *) fence_init,8,8,1,0,1);
    4460             : 
    4461           0 :     XGetInputFocus(display,&focus,&revert);
    4462           0 :     if ( focus==PointerRoot )
    4463           0 :         gdisp->focusfollowsmouse = true;
    4464             : 
    4465           0 :     gdisp->groot = calloc(1,sizeof(struct gxwindow));
    4466           0 :     groot = (GXWindow)(gdisp->groot);
    4467           0 :     groot->ggc = _GXDraw_NewGGC();
    4468           0 :     groot->display = gdisp;
    4469           0 :     groot->w = gdisp->root;
    4470           0 :     groot->pos.width = XDisplayWidth(display,gdisp->screen);
    4471           0 :     groot->pos.height = XDisplayHeight(display,gdisp->screen);
    4472           0 :     groot->is_toplevel = true;
    4473           0 :     groot->is_visible = true;
    4474             :     
    4475           0 :     GXResourceInit(gdisp,programname);
    4476             : 
    4477           0 :     gdisp->bs.double_time = GResourceFindInt( "DoubleClickTime", gdisp->bs.double_time );
    4478           0 :     gdisp->def_background = GResourceFindColor( "Background", COLOR_CREATE(0xf5,0xff,0xfa));
    4479           0 :     gdisp->def_foreground = GResourceFindColor( "Foreground", COLOR_CREATE(0x00,0x00,0x00));
    4480           0 :     if ( GResourceFindBool("Synchronize", false ))
    4481           0 :         XSynchronize(gdisp->display,true);
    4482             : 
    4483             : #ifdef X_HAVE_UTF8_STRING       /* Don't even try without this. I don't want to have to guess encodings myself... */
    4484             :     /* X Input method initialization */
    4485           0 :     XSetLocaleModifiers(""); // As it turns out, we can't free this here.
    4486           0 :     gdisp->im = XOpenIM(display, XrmGetDatabase(display),
    4487             :             GResourceProgramName, GResourceProgramName);
    4488             :     /* The only reason this seems to fail is if XMODIFIERS contains an @im */
    4489             :     /*  which points to something that isn't running. If XMODIFIERS is not */
    4490             :     /*  defined we get some kind of built-in default method. If it doesn't */
    4491             :     /*  recognize the locale we still get something */
    4492             :     /* If it does fail, then fall back on the old fashioned stuff */
    4493             : #endif
    4494             : 
    4495           0 :     (gdisp->funcs->init)((GDisplay *) gdisp);
    4496           0 :     gdisp->top_window_count = 0;
    4497           0 :     gdisp->selinfo[sn_primary].sel_atom = XA_PRIMARY;
    4498           0 :     gdisp->selinfo[sn_clipboard].sel_atom = XInternAtom(display,"CLIPBOARD",False);
    4499           0 :     gdisp->selinfo[sn_drag_and_drop].sel_atom = XInternAtom(display,"DRAG_AND_DROP",False);
    4500           0 :     gdisp->selinfo[sn_user1].sel_atom = XA_PRIMARY;
    4501           0 :     gdisp->selinfo[sn_user2].sel_atom = XA_PRIMARY;
    4502             : 
    4503           0 :     gdisp->xthread.sync_sock = -1;
    4504             : #ifdef HAVE_PTHREAD_H
    4505           0 :     gdisp->xthread.sync_mutex = defmutex;
    4506           0 :     gdisp->xthread.things_to_do = NULL;
    4507             : #endif
    4508           0 :     XSetErrorHandler(/*gdisp->display,*/myerrorhandler);
    4509           0 :     _GDraw_InitError((GDisplay *) gdisp);
    4510             : 
    4511             : #ifdef _WACOM_DRV_BROKEN
    4512             :     _GXDraw_Wacom_Init(gdisp);
    4513             : #endif
    4514             : 
    4515           0 :     GDrawInitXKB(gdisp);
    4516             : 
    4517           0 : return( (GDisplay *) gdisp);
    4518             : }
    4519             : 
    4520           0 : void _XSyncScreen() {
    4521           0 :     XSync(((GXDisplay *) screen_display)->display,false);
    4522           0 : }
    4523             : 
    4524             : /* map GK_ keys to X keys */
    4525             : /* Assumes most are mapped 1-1, see gkeysym.h */
    4526             : /* abort on unimplemented translations */
    4527           0 : int GDrawKeyToXK(int keysym) {
    4528             :     switch( keysym ) {
    4529             :       default:
    4530           0 :         if ( keysym==' ' ||
    4531           0 :                 (keysym>='0' && keysym<='9') ||
    4532           0 :                 (keysym>='A' && keysym<='Z') ||
    4533           0 :                 (keysym>='a' && keysym<='z') )
    4534           0 : return( keysym );
    4535             :     }
    4536           0 :     abort();
    4537             : return( 0 );
    4538             : }
    4539             : 
    4540           0 : int GDrawKeyState(int keysym) {
    4541             :     char key_map_stat[32];
    4542           0 :     Display *xdisplay = ((GXDisplay *)screen_display)->display;
    4543             :     KeyCode code;
    4544             : 
    4545           0 :     XQueryKeymap(xdisplay, key_map_stat);
    4546             : 
    4547           0 :     code = XKeysymToKeycode(xdisplay, GDrawKeyToXK(keysym));
    4548           0 :     if ( !code ) {
    4549           0 : abort();
    4550             : return 0;
    4551             :     }
    4552           0 : return ((key_map_stat[code >> 3] >> (code & 7)) & 1);
    4553             : }
    4554             : 
    4555             : #else   /* NO X */
    4556             : 
    4557             : GDisplay *_GXDraw_CreateDisplay(char *displayname,char *programname) {
    4558             :     fprintf( stderr, "This program was not compiled with X11, and cannot open the display\n" );
    4559             :     exit(1);
    4560             : }
    4561             : 
    4562             : void _XSyncScreen() {
    4563             : }
    4564             : #endif
    4565             : 
    4566             : 

Generated by: LCOV version 1.10