ecere/gfx/drivers/LFB; gui/EditBox: Splitting Font Rendering & Management; Italic...
[sdk] / ecere / src / gfx / drivers / XDisplayDriver.ec
1 namespace gfx::drivers;
2
3 // Enable to work around some Linux drivers not supporting PictStandardA8 format properly
4 #define ENABLE_XRENDER_WORK_AROUND
5
6 import "instance"
7
8 #if (defined(__unix__) || defined(__APPLE__)) && !defined(ECERE_MINIGLX)
9
10 default:
11
12 #define property _property
13 #define new _new
14 #define class _class
15 #define uint _uint
16
17 #define Window    X11Window
18 #define Cursor    X11Cursor
19 #define Font      X11Font
20 #define Display   X11Display
21 #define Time      X11Time
22 #define KeyCode   X11KeyCode
23 #define Picture   X11Picture
24 #define Glyph     X11Glyph
25
26 #include <X11/Xlib.h>
27 #include <X11/Xutil.h>
28 #include <X11/extensions/shape.h>
29 #include <X11/extensions/Xrender.h>
30 #include <X11/extensions/XShm.h>
31 #include <sys/ipc.h>
32 #include <sys/shm.h>
33
34 #undef Window
35 #undef Cursor
36 #undef Font
37 #undef Display
38 #undef Time
39 #undef KeyCode
40 #undef Picture
41 #undef Glyph
42
43 #undef uint
44 #undef new
45 #undef property
46 #undef class
47
48 private:
49
50 import "Display"
51 import "XInterface"
52
53 /*
54 static byte defaultRGBLookup[32768];
55 bool rgbLookupSet = false;
56 */
57 class XDisplay : LFBDisplay //struct
58 {
59    Pixmap pixmap;
60    Pixmap shapePixmap;
61    GC windowGC, gc;
62    Point offset;
63    Box updateBox;
64    X11Picture picture;
65    X11Picture shapePicture;
66    XShmSegmentInfo shminfo;
67    XImage * image;
68    XShmSegmentInfo shminfoShape;
69    XImage * shapeImage;
70 };
71
72 class XSurface : struct
73 {
74    Font font;
75    bool opaqueText;
76    int xOffset;
77    bool writingText;
78
79    ColorAlpha foreground, background;
80    bool opaque;
81    bool clipped;
82    Pixmap pixmap;
83    X11Picture picture;
84    X11Picture colorPicture;
85    Pixmap colorPixmap;
86 };
87
88 class XBitmap : struct
89 {
90    Pixmap pixmap;
91    Pixmap mask;
92    X11Picture picture;
93    X11Picture maskPicture;
94 #ifdef ENABLE_XRENDER_WORK_AROUND
95    bool alphaTweak;
96 #endif
97 };
98
99 XRenderPictFormat * GetXRenderFormat(PixelFormat pixelFormat, bool alphaBlend)
100 {
101    XRenderPictFormat * format = null;
102    switch(pixelFormat)
103    {
104       case pixelFormatAlpha:
105          format = XRenderFindStandardFormat(xGlobalDisplay, PictStandardA8);
106          break;
107       case pixelFormat888:
108          format = XRenderFindStandardFormat(xGlobalDisplay, alphaBlend ? PictStandardARGB32 : PictStandardRGB24);
109          // printf("R: %d G: %d B: %d\n", format->direct.red, format->direct.green, format->direct.blue);
110          break;
111       case pixelFormat555:
112       {
113          XRenderPictFormat info = { 0 };
114
115          info.depth = 16;
116          info.type = PictTypeDirect;
117          info.direct.red = 10;
118          info.direct.green = 5;
119          info.direct.blue = 0;
120          info.direct.redMask   = 0x1F;
121          info.direct.greenMask = 0x1F;
122          info.direct.blueMask  = 0x1F;
123
124          format = XRenderFindFormat(xGlobalDisplay,
125             /*PictFormatDepth|*/PictFormatType| PictFormatAlpha|PictFormatRed|PictFormatGreen|PictFormatBlue|
126             PictFormatRedMask|PictFormatGreenMask|PictFormatBlueMask|PictFormatAlphaMask, &info, 0);
127          break;
128       }
129       case pixelFormat565:
130       {
131          XRenderPictFormat info = { 0 };
132
133          info.depth = 16;
134          info.type = PictTypeDirect;
135          info.direct.alpha = 0;
136          info.direct.red = 11;
137          info.direct.green = 5;
138          info.direct.blue = 0;
139          info.direct.redMask   = 0x1F;
140          info.direct.greenMask = 0x3F;
141          info.direct.blueMask  = 0x1F;
142          info.direct.alphaMask = 0;
143          info.id = 0xba;
144
145          format = XRenderFindFormat(xGlobalDisplay,
146             /*PictFormatDepth|*/PictFormatType|PictFormatAlpha|PictFormatRed|PictFormatGreen|PictFormatBlue|
147             PictFormatRedMask|PictFormatGreenMask|PictFormatBlueMask|PictFormatAlphaMask, &info, 0);
148          break;
149       }
150    }
151    return format;
152 }
153
154 static bool ClipBlitCoords(Surface surface, Bitmap src, int *dx, int *dy, int *sx, int *sy, int *w, int *h, bool * flip)
155 {
156    *flip = false;
157
158    if(surface.box.right < surface.box.left || surface.box.bottom < surface.box.top) return false;
159
160    if(*w < 0) { *w = -*w; *flip = true; }
161
162    //Clip against the edges of the source
163    if(*sx<0)
164    {
165       *dx+=-*sx;
166       *w-=-*sx;
167       *sx=0;
168    }
169    if(*sy<0)
170    {
171       *dy+=0-*sy;
172       *h-=0-*sy;
173       *sy=0;
174    }
175    if(*sx+*w>src.width-1)
176       *w-=*sx+*w-(src.width-1)-1;
177    if(*sy+*h>src.height-1)
178       *h-=*sy+*h-(src.height-1)-1;
179    //Clip against the edges of the destination
180    if(*dx<surface.box.left)
181    {
182       if(!*flip) *sx+=surface.box.left-*dx;
183       *w-=surface.box.left-*dx;
184       *dx=surface.box.left;
185    }
186    if(*dy<surface.box.top)
187    {
188       *sy+=surface.box.top-*dy;
189       *h-=surface.box.top-*dy;
190       *dy=surface.box.top;
191    }
192    if((*dx+*w)>surface.box.right)
193    {
194       if(*flip) *sx+=(uint)(*dx+*w)-surface.box.right-1;
195       *w-=((uint)(*dx+*w)-surface.box.right-1);
196    }
197    if((*dy+*h)>surface.box.bottom)
198       *h-=((*dy+*h)-surface.box.bottom-1);
199    if((*w<=0)||(*h<=0))
200       return false;
201    return true;
202 }
203
204 static bool ClipStretchCoords(Surface surface, Bitmap src, int *dx, int *dy, int *sx, int *sy, int *w, int *h, int *sw, int *sh, bool * flip)
205 {
206    float s2dw,s2dh,d2sw,d2sh;
207    *flip = false;
208
209    if(surface.box.right < surface.box.left || surface.box.bottom < surface.box.top || !src.picture) return false;
210
211    if(Sgn(*w) != Sgn(*sw))
212    {
213       *w = Abs(*w);
214       *sw = Abs(*sw);
215       *flip = true;
216    }
217
218    s2dw=(float)*w / *sw;
219    s2dh=(float)*h / *sh;
220    d2sw=(float)*sw / *w;
221    d2sh=(float)*sh / *h;
222
223    //Clip against the edges of the source
224    if(*sx < 0)
225    {
226       *dx += (int)((0-*sx) * s2dw);
227       *w -= (int)((0-*sx) * s2dw);
228       *sw -= 0-*sx;
229       *sx=0;
230    }
231    if(*sy < 0)
232    {
233       *dy += (int)((0-*sy) * s2dh);
234       *h -= (int)((0-*sy) * s2dh);
235
236       *sh -= 0-*sy;
237       *sy=0;
238    }
239    if(*sx+*sw>src.width-1)
240    {
241       *w-=(int)((*sx+*sw-(src.width-1)-1)*s2dw);
242       *sw-=*sx+*sw-(src.width-1)-1;
243    }
244    if(*sy+*sh>(src.height-1))
245    {
246       *h-=(int)((*sy+*sh-(src.height-1)-1)*s2dh);
247       *sh-=*sy+*sh-(src.height-1)-1;
248    }
249    //Clip against the edges of the destination
250    if(*dx < surface.box.left)
251    {
252       if(!*flip) *sx += (int)((surface.box.left-*dx)*d2sw);
253       *sw-=(int)((surface.box.left-*dx)*d2sw);
254       *w-=surface.box.left-*dx;
255       *dx=surface.box.left;
256    }
257    if(*dy < surface.box.top)
258    {
259       *sy += (int)((surface.box.top-*dy)*d2sh);
260       *sh -= (int)((surface.box.top-*dy)*d2sh);
261       *h -= surface.box.top-*dy;
262       *dy =surface.box.top;
263    }
264    if((*dx+*w)>surface.box.right)
265    {
266       if(*flip) *sx+=(int)(((*dx+*w)-surface.box.right-1)*d2sw);
267       *sw-=(int)(((*dx + *w)-surface.box.right-1)*d2sw);
268       *w-=((*dx+*w)-surface.box.right-1);
269    }
270    if((*dy+*h)>surface.box.bottom)
271    {
272       *sh-=(int)(((*dy+*h)-surface.box.bottom-1)*d2sh);
273       *h-=((*dy+*h)-surface.box.bottom-1);
274    }
275    if((*w<=0)||(*h<=0)||(*sw<=0)||(*sh<=0))
276       return false;
277    return true;
278 }
279
280 static void PutBitmapMask(Pixmap mask, Bitmap bitmap) {
281    XImage image = {0};
282    GC maskGC = XCreateGC(xGlobalDisplay, mask, 0, null);
283    uint wordWidth = (bitmap.width+31) >> 5;
284
285    uint x,y;
286    uint32 *b = new0 uint32[wordWidth * bitmap.height];
287    uint32 f = 1;
288
289    XSetGraphicsExposures(xGlobalDisplay, maskGC, False);
290
291    image.width = bitmap.width;
292    image.height = bitmap.height;
293
294    image.format = XYBitmap;
295    #ifdef __BIG_ENDIAN__
296    image.byte_order = MSBFirst;
297    #else
298    image.byte_order = LSBFirst;
299    #endif
300    image.bitmap_unit = 32;
301    image.bitmap_bit_order = LSBFirst;
302    image.bitmap_pad = 32;
303    image.depth = 1;
304    image.bytes_per_line = wordWidth << 2;
305
306    image.data = (char*)b;
307
308    XInitImage(&image);
309
310    switch(bitmap.pixelFormat) {
311       case pixelFormat4: {
312
313       } break;
314       case pixelFormat8: {
315          byte *p = (byte*)bitmap.picture;
316
317          for(y = 0; y<bitmap.height; y++, p+=bitmap.stride) {
318             for(x = 0; x<bitmap.width; x++) {
319                if(p[x])
320                   *b |= f; //XPutPixel(&image, x,y, 1);
321                if (!(f<<=1))
322                   b++, f=1;
323             }
324             if (f != 1)
325                b++, f=1;
326          }
327       } break;
328       case pixelFormat444:
329       case pixelFormat555:
330       case pixelFormat565: {
331          uint16 *p = (uint16*)bitmap.picture;
332 #ifdef _DEBUG
333          PrintLn(bitmap.pixelFormat);
334 #endif
335          for(y = 0; y<bitmap.height; y++, p+=bitmap.stride) {
336             for(x = 0; x<bitmap.width; x++) {
337                if(p[x])
338                   *b |= f; //XPutPixel(&image, x,y, 1);
339                if (!(f<<=1))
340                   b++, f=1;
341             }
342             if (f != 1)
343                b++, f=1;
344          }
345       } break;
346       case pixelFormat888: {
347          ColorAlpha *p = (ColorAlpha*)bitmap.picture;
348          for(y = 0; y<bitmap.height; y++, p+=bitmap.stride) {
349             for(x = 0; x<bitmap.width; x++) {
350                if(p[x].a)
351                   *b |= f; //XPutPixel(&image, x,y, 1);
352                if (!(f<<=1))
353                   b++, f=1;
354             }
355             if (f != 1)
356                b++, f=1;
357          }
358       } break;
359       case pixelFormatAlpha: {
360
361       } break;
362       case pixelFormatText: {
363
364       } break;
365       case pixelFormatRGBA: {
366
367       } break;
368    }
369
370    XSetForeground(xGlobalDisplay, maskGC, 1);
371    XSetBackground(xGlobalDisplay, maskGC, 0);
372
373    XPutImage(xGlobalDisplay, mask, maskGC, &image,
374       0, 0, 0, 0, //coordinates
375       bitmap.width, bitmap.height);
376
377    XFreeGC(xGlobalDisplay, maskGC);
378    delete image.data;
379 }
380
381 class XDisplayDriver : DisplayDriver
382 {
383    class_property(name) = "X";
384
385    bool CreateDisplaySystem(DisplaySystem displaySystem)
386    {
387       //displaySystem.driverData = calloc(1, sizeof(LFBSystem));
388       displaySystem.flags.memBackBuffer = true;
389       displaySystem.pixelFormat = xSystemPixelFormat;
390       return true;
391    }
392
393    void DestroyDisplaySystem(DisplaySystem displaySystem)
394    {
395       // delete displaySystem.driverData;
396    }
397
398    void DestroyDisplay(Display display)
399    {
400       XDisplay xDisplay = display.driverData;
401
402       // Free Shared Memory Pixmap
403       if(xDisplay.shapePixmap)
404          XFreePixmap(xGlobalDisplay, xDisplay.shapePixmap);
405       if(xDisplay.pixmap)
406          XFreePixmap(xGlobalDisplay, xDisplay.pixmap);
407       if(xDisplay.image)
408       {
409          if(xDisplay.shminfoShape.shmid != -1)
410          {
411             XShmDetach(xGlobalDisplay, &xDisplay.shminfo);
412             if(xDisplay.shminfo.shmaddr != (void *)-1)
413                shmdt(xDisplay.shminfo.shmaddr);
414             shmctl(xDisplay.shminfo.shmid, IPC_RMID, 0);
415          }
416       }
417       if(xDisplay.shapeImage)
418       {
419          if(xDisplay.shminfoShape.shmid != -1)
420          {
421             XShmDetach(xGlobalDisplay, &xDisplay.shminfoShape);
422             if(xDisplay.shminfoShape.shmaddr != (void *)-1)
423                shmdt(xDisplay.shminfoShape.shmaddr);
424             shmctl(xDisplay.shminfoShape.shmid, IPC_RMID, 0);
425          }
426          XDestroyImage(xDisplay.shapeImage);
427          xDisplay.shapeImage = None;
428       }
429       if(xDisplay.picture)
430          XRenderFreePicture(xGlobalDisplay, xDisplay.picture);
431       if(xDisplay.shapePicture)
432          XRenderFreePicture(xGlobalDisplay, xDisplay.picture);
433       if(xDisplay.windowGC)
434          XFreeGC(xGlobalDisplay, xDisplay.windowGC);
435       if(xDisplay.gc)
436          XFreeGC(xGlobalDisplay, xDisplay.gc);
437       delete xDisplay;
438       display.driverData = null;
439    }
440
441    void SetPalette(Display display, ColorAlpha * palette, bool colorMatch)
442    {
443
444
445    }
446
447    bool CreateDisplay(Display display)
448    {
449       bool result = false;
450       XDisplay xDisplay = display.driverData = XDisplay { };
451
452       if(display)
453       {
454          xDisplay.windowGC = XCreateGC(xGlobalDisplay, (X11Window)display.window, 0, null);
455          XSetGraphicsExposures(xGlobalDisplay, xDisplay.windowGC, False);
456          result = true;
457       }
458       return result;
459    }
460
461    bool DisplaySize(Display display, int width, int height)
462    {
463       XDisplay xDisplay = display.driverData;
464       bool result = false;
465
466       if(width > display.width || height > display.height)
467       {
468          display.width = width;
469          display.height = height;
470
471          if(xDisplay.picture)
472             XRenderFreePicture(xGlobalDisplay, xDisplay.picture);
473
474          {
475             XRenderPictureAttributes attributes = { 0 };
476             XRenderPictFormat * format = GetXRenderFormat(xSystemPixelFormat, display.alphaBlend);
477             attributes.component_alpha = 1;
478             attributes.poly_mode = PolyModeImprecise;
479             attributes.poly_edge = PolyEdgeSmooth;
480
481             if(xDisplay.pixmap)
482             {
483                XFreePixmap(xGlobalDisplay, xDisplay.pixmap);
484                xDisplay.pixmap = None;
485             }
486             if(xDisplay.shapePixmap)
487             {
488                XFreePixmap(xGlobalDisplay, xDisplay.shapePixmap);
489                xDisplay.shapePixmap = None;
490             }
491
492             // Free Shared Memory Pixmap
493             if(xDisplay.image)
494             {
495                if(xDisplay.shminfoShape.shmid != -1)
496                {
497                   XShmDetach(xGlobalDisplay, &xDisplay.shminfo);
498                   if(xDisplay.shminfo.shmaddr != (void *)-1)
499                      shmdt(xDisplay.shminfo.shmaddr);
500                   shmctl(xDisplay.shminfo.shmid, IPC_RMID, 0);
501                }
502                XDestroyImage(xDisplay.image);
503                xDisplay.image = None;
504             }
505             if(xDisplay.shapeImage)
506             {
507                if(xDisplay.shminfoShape.shmid != -1)
508                {
509                   XShmDetach(xGlobalDisplay, &xDisplay.shminfoShape);
510                   if(xDisplay.shminfoShape.shmaddr != (void *)-1)
511                      shmdt(xDisplay.shminfoShape.shmaddr);
512                   shmctl(xDisplay.shminfoShape.shmid, IPC_RMID, 0);
513                }
514                XDestroyImage(xDisplay.shapeImage);
515                xDisplay.shapeImage = None;
516             }
517
518             // Initialize Shared Memory Pixmap
519 #ifdef __linux__
520             if(xSharedMemory && display.useSharedMemory && format)
521             {
522 #ifdef _DEBUG
523                printf("Using shared memory!\n");
524 #endif
525                xDisplay.image = XShmCreateImage(xGlobalDisplay, xSystemVisual /*DefaultVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay))*/,
526                   format->depth, ZPixmap, null, &xDisplay.shminfo, width, height);
527             }
528             else if(display.useSharedMemory && !xSharedMemory)
529                printf("%s", $"Error: Requested shared memory but shared memory pixmaps are not supported by X server.\n");
530 #endif
531             if(xDisplay.image)
532             {
533                memset(&xDisplay.shminfo, 0, sizeof(XShmSegmentInfo));
534                // printf("shmget: %d\n", xDisplay.image->bytes_per_line * xDisplay.image->height);
535                xDisplay.shminfo.shmid = shmget(IPC_PRIVATE, xDisplay.image->bytes_per_line * xDisplay.image->height, IPC_CREAT|0777);
536                if(xDisplay.shminfo.shmid != -1)
537                {
538                   xDisplay.shminfo.shmaddr = shmat(xDisplay.shminfo.shmid, 0, 0);
539                   if(xDisplay.shminfo.shmaddr != (void *)-1)
540                   {
541                      // printf("%d,  %d\n", xDisplay.shminfo.shmid, xDisplay.shminfo.shmaddr);
542                      xDisplay.shminfo.readOnly = False;
543                      if(XShmAttach(xGlobalDisplay, &xDisplay.shminfo))
544                      {
545                         xDisplay.pixmap = XShmCreatePixmap(xGlobalDisplay, (X11Window)display.window, xDisplay.shminfo.shmaddr, &xDisplay.shminfo, width, height, format->depth);
546
547                         xDisplay.bitmap.width = width;
548                         xDisplay.bitmap.height = height;
549                         xDisplay.bitmap.stride = xDisplay.image->bytes_per_line >> GetColorDepthShifts(display.pixelFormat);
550                         xDisplay.bitmap.pixelFormat = display.pixelFormat;
551                         xDisplay.bitmap.picture = (byte *)xDisplay.shminfo.shmaddr;
552                         xDisplay.bitmap.size = width * height;
553                         xDisplay.bitmap.sizeBytes = (uint)xDisplay.bitmap.size << GetColorDepthShifts(display.pixelFormat);
554                      }
555                   }
556                }
557                if(!xDisplay.pixmap)
558                {
559                   if(xDisplay.shminfo.shmid != -1)
560                   {
561                      XShmDetach(xGlobalDisplay, &xDisplay.shminfo);
562                      if(xDisplay.shminfo.shmaddr != (void *)-1)
563                         shmdt(xDisplay.shminfo.shmaddr);
564                      shmctl(xDisplay.shminfo.shmid, IPC_RMID, 0);
565                   }
566                   XDestroyImage(xDisplay.image);
567                   xDisplay.image = None;
568                }
569             }
570
571 #ifdef __linux__
572             // Initialize Shared Memory Shape Pixmap
573             if(xSharedMemory && display.useSharedMemory && display.alphaBlend)
574                xDisplay.shapeImage = XShmCreateImage(xGlobalDisplay, xSystemVisual /*DefaultVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay))*/,
575                   1, ZPixmap, null, &xDisplay.shminfoShape, width, height);
576 #endif
577             if(xDisplay.shapeImage)
578             {
579                xDisplay.shminfoShape.shmid = shmget(IPC_PRIVATE, xDisplay.shapeImage->bytes_per_line * xDisplay.shapeImage->height, IPC_CREAT|0777);
580                if(xDisplay.shminfoShape.shmid != -1)
581                {
582                   xDisplay.shminfoShape.shmaddr = shmat(xDisplay.shminfoShape.shmid, 0, 0);
583                   if(xDisplay.shminfoShape.shmaddr != (void *)-1)
584                   {
585                      xDisplay.shminfoShape.readOnly = False;
586                      if(XShmAttach(xGlobalDisplay, &xDisplay.shminfoShape))
587                      {
588                         xDisplay.shapePixmap = XShmCreatePixmap(xGlobalDisplay, (X11Window)display.window, xDisplay.shminfoShape.shmaddr, &xDisplay.shminfoShape, width, height, 1);
589                      }
590                   }
591                }
592                if(!xDisplay.shapePixmap)
593                {
594                   if(xDisplay.shminfoShape.shmid != -1)
595                   {
596                      XShmDetach(xGlobalDisplay, &xDisplay.shminfoShape);
597                      if(xDisplay.shminfoShape.shmaddr != (void *)-1)
598                         shmdt(xDisplay.shminfoShape.shmaddr);
599                      shmctl(xDisplay.shminfoShape.shmid, IPC_RMID, 0);
600                   }
601                   XDestroyImage(xDisplay.shapeImage);
602                   xDisplay.shapeImage = None;
603                }
604             }
605
606             if(!xDisplay.pixmap && format)
607                xDisplay.pixmap = XCreatePixmap(xGlobalDisplay, (X11Window)display.window, width, height, format->depth);
608             if(display.alphaBlend && !xDisplay.shapePixmap)
609                xDisplay.shapePixmap = XCreatePixmap(xGlobalDisplay, (X11Window)display.window, width, height, 1);
610             if(!xDisplay.gc)
611             {
612                xDisplay.gc = XCreateGC(xGlobalDisplay, (Pixmap)xDisplay.pixmap, 0, null);
613                XSetGraphicsExposures(xGlobalDisplay, xDisplay.gc, False);
614             }
615
616             if(format)
617                xDisplay.picture = XRenderCreatePicture(xGlobalDisplay, xDisplay.pixmap, format, CPComponentAlpha, &attributes);
618
619             if(display.alphaBlend)
620                xDisplay.shapePicture = XRenderCreatePicture(xGlobalDisplay, xDisplay.shapePixmap, XRenderFindStandardFormat(xGlobalDisplay, PictStandardA1), 0, &attributes);
621          }
622       }
623       xDisplay.updateBox.left = display.width;
624       xDisplay.updateBox.top = display.height;
625       xDisplay.updateBox.right = 0;
626       xDisplay.updateBox.bottom = 0;
627
628       result = true;
629       return result;
630    }
631
632    void DisplayPosition(Display display, int x, int y)
633    {
634       XDisplay xDisplay = display.driverData;
635       xDisplay.offset.x = x;
636       xDisplay.offset.y = y;
637    }
638
639    void RestorePalette(Display display)
640    {
641
642    }
643
644    void FreeBitmap(DisplaySystem displaySystem, Bitmap bitmap)
645    {
646       XBitmap xBitmap = bitmap.driverData;
647       if(xBitmap)
648       {
649          if(xBitmap.pixmap)
650             XFreePixmap(xGlobalDisplay, xBitmap.pixmap);
651          if(xBitmap.mask)
652             XFreePixmap(xGlobalDisplay, xBitmap.mask);
653          if(xBitmap.picture)
654             XRenderFreePicture(xGlobalDisplay, xBitmap.picture);
655          if(xBitmap.maskPicture)
656             XRenderFreePicture(xGlobalDisplay, xBitmap.maskPicture);
657          delete xBitmap;
658          bitmap.driverData = null;
659       }
660       ((subclass(DisplayDriver))class(LFBDisplayDriver)).FreeBitmap(displaySystem, bitmap);
661    }
662
663    bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps)
664    {
665       //XDisplay xDisplay = display.driverData;
666       XBitmap xBitmap { };
667       XImage image = { 0 };
668       GC gc = 0;
669
670 #ifdef ENABLE_XRENDER_WORK_AROUND
671       if(bitmap.pixelFormat == pixelFormatAlpha)
672       {
673          xBitmap.alphaTweak = true;
674          bitmap.alphaBlend = true;
675       }
676 #else
677       if(bitmap.pixelFormat != pixelFormatAlpha)
678 #endif
679          bitmap.Convert(null, bitmap.alphaBlend ? pixelFormat888 : xSystemPixelFormat, null);
680
681       //bitmap.Convert(null, pixelFormatRGBA, null);
682       //bitmap.Convert(null, pixelFormat888, null);
683       xBitmap.pixmap =
684          XCreatePixmap(xGlobalDisplay, confineWindow /*(X11Window)display.window*/, bitmap.width, bitmap.height,
685             (bitmap.pixelFormat == pixelFormatAlpha) ? 8 : (bitmap.alphaBlend ? 32 : ((bitmap.pixelFormat == pixelFormat888) ? 24 : xSystemDepth)));
686       if(bitmap.transparent)
687          xBitmap.mask =
688             XCreatePixmap(xGlobalDisplay, confineWindow /*(X11Window)display.window*/, bitmap.width, bitmap.height, 1);
689
690       {
691          XRenderPictureAttributes attributes = { 0 };
692          XRenderPictFormat * format = GetXRenderFormat(bitmap.pixelFormat, bitmap.alphaBlend);
693          attributes.component_alpha = 1;
694
695          if(format)
696             xBitmap.picture = XRenderCreatePicture(xGlobalDisplay, xBitmap.pixmap, format, CPComponentAlpha, &attributes);
697          if(bitmap.transparent && bitmap.pixelFormat != pixelFormatAlpha)
698             xBitmap.maskPicture = XRenderCreatePicture(xGlobalDisplay, xBitmap.mask, XRenderFindStandardFormat(xGlobalDisplay, PictStandardA1), CPComponentAlpha, &attributes);
699       }
700
701       gc = XCreateGC(xGlobalDisplay, (Pixmap)xBitmap.pixmap, 0, null);
702
703       XSetGraphicsExposures(xGlobalDisplay, gc, False);
704
705       image.width = bitmap.width;
706       image.height = bitmap.height;
707
708       if(bitmap.pixelFormat == pixelFormatAlpha)
709       {
710          image.depth = 8;
711          image.bitmap_pad = 8;
712          image.bytes_per_line = bitmap.stride;
713          image.bits_per_pixel = 8;
714       }
715       else
716       {
717          image.depth = bitmap.alphaBlend ? 32 : ((bitmap.pixelFormat == pixelFormat888) ? 24 : xSystemDepth);
718          image.bitmap_pad = (bitmap.pixelFormat == pixelFormat888) ? 32 : 16;
719          image.bytes_per_line = ((bitmap.pixelFormat == pixelFormat888) ? 4 : 2) * bitmap.stride;
720          image.bits_per_pixel = (bitmap.pixelFormat == pixelFormat888) ? 32 : 16;
721       }
722
723       image.format = ZPixmap;
724       //image.bitmap_bit_order = MSBFirst;
725       #ifdef __BIG_ENDIAN__
726       image.byte_order = MSBFirst;
727       #endif
728       image.bitmap_unit = 8;
729       /*
730       image.red_mask   = 0xF800;
731       image.green_mask = 0x7E0;
732       image.blue_mask  = 0x1F;
733       */
734
735       /*
736       image.red_mask   = 0x0000FF;
737       image.green_mask = 0x00FF00;
738       image.blue_mask  = 0xFF0000;
739       */
740       // image.red_mask  = 0xFFFF0000;
741
742       image.data = (char *)bitmap.picture;
743       XInitImage(&image);
744
745       if(bitmap.pixelFormat != pixelFormatAlpha && bitmap.alphaBlend)
746       {
747          int x,y;
748          for(y = 0; y<bitmap.height; y++)
749          {
750             for(x = 0; x<bitmap.width; x++)
751             {
752                ColorAlpha * p = ((ColorAlpha *)bitmap.picture) + y * bitmap.stride + x;
753                int alpha = p->a;
754                p->color.r = (byte)(p->color.r * alpha / 255);
755                p->color.g = (byte)(p->color.g * alpha / 255);
756                p->color.b = (byte)(p->color.b * alpha / 255);
757             }
758          }
759       }
760
761       XPutImage(xGlobalDisplay, (Pixmap)xBitmap.pixmap, gc, &image,
762          0, 0, 0, 0, bitmap.width,bitmap.height);
763
764       if(bitmap.transparent && !bitmap.alphaBlend && bitmap.pixelFormat != pixelFormatAlpha)
765          PutBitmapMask(xBitmap.mask, bitmap);
766
767       XFreeGC(xGlobalDisplay, gc);
768
769       if(!bitmap.keepData)
770          delete bitmap.picture;
771
772       bitmap.driverData = xBitmap;
773       bitmap.driver = displaySystem.driver;
774       return true;
775    }
776
777    void ReleaseSurface(Display display, Surface surface)
778    {
779       XSurface xSurface = surface.driverData;
780       XDisplay xDisplay = display ? display.driverData : null;
781       XRectangle rectangle;
782
783       if(xSurface.colorPicture)
784          XRenderFreePicture(xGlobalDisplay, xSurface.colorPicture);
785
786       rectangle.x = 0;
787       rectangle.y = 0;
788       if(display)
789       {
790          rectangle.width = (uint16)display.width;
791          rectangle.height = (uint16)display.height;
792          XRenderSetPictureClipRectangles(xGlobalDisplay, xDisplay.picture, 0, 0, &rectangle, 1);
793       }
794
795       if(xSurface.colorPixmap)
796          XFreePixmap(xGlobalDisplay, xSurface.colorPixmap);
797
798       delete xSurface;
799    }
800
801    bool GetBitmapSurface(DisplaySystem displaySystem, Surface surface, Bitmap bitmap, int x, int y, Box clip)
802    {
803       bool result = false;
804       XBitmap xBitmap = bitmap.driverData;
805       XSurface xSurface;
806
807       if((surface.driverData = xSurface = XSurface { }))
808       {
809          surface.offset.x = x;
810          surface.offset.y = y;
811          surface.unclippedBox = surface.box = clip;
812
813          xSurface.pixmap = xBitmap.pixmap;
814
815          result = true;
816       }
817       return result;
818    }
819
820    bool GetSurface(Display display, Surface surface, int x,int y, Box clip)
821    {
822       bool result = false;
823       XDisplay xDisplay = display.driverData;
824       XSurface xSurface;
825       if((surface.driverData = xSurface = XSurface { }))
826       {
827          XRectangle rectangle;
828
829          surface.offset.x = x;
830          surface.offset.y = y;
831          surface.unclippedBox = surface.box = clip;
832          xSurface.pixmap = xDisplay.pixmap;
833          xSurface.picture = xDisplay.picture;
834
835          xSurface.colorPixmap = XCreatePixmap(xGlobalDisplay, (X11Window)confineWindow /*display.window*/, 1, 1, /*(xSystemDepth == 16) ? 16 : */32);
836
837          rectangle.x = (short)(clip.left + x);
838          rectangle.y = (short)(clip.top + y);
839          rectangle.width = (short)(clip.right - clip.left + 1);
840          rectangle.height = (short)(clip.bottom - clip.top + 1);
841
842          XSetClipRectangles(xGlobalDisplay, xDisplay.gc, 0,0, &rectangle, 1, YXBanded);
843          XRenderSetPictureClipRectangles(xGlobalDisplay, xDisplay.picture, 0, 0, &rectangle, 1);
844
845          xDisplay.updateBox.left  = Min(x + clip.left,  xDisplay.updateBox.left);
846          xDisplay.updateBox.top   = Min(y + clip.top,   xDisplay.updateBox.top);
847          xDisplay.updateBox.right = Max(x + clip.right, xDisplay.updateBox.right);
848          xDisplay.updateBox.bottom  = Max(y + clip.bottom,  xDisplay.updateBox.bottom);
849
850          result = true;
851       }
852       return result;
853    }
854
855    void Clip(Display display, Surface surface, Box clip)
856    {
857       XSurface xSurface = surface.driverData;
858       XDisplay xDisplay = display.driverData;
859       bool changed = false;
860       if(clip != null)
861       {
862          Box box = clip;
863
864          box.Clip(surface.unclippedBox);
865
866          surface.box = box;
867
868          xSurface.clipped = true;
869          changed = true;
870       }
871       else if(xSurface.clipped)
872       {
873          surface.box = surface.unclippedBox;
874          xSurface.clipped = false;
875          changed = true;
876       }
877       if(changed)
878       {
879          XRectangle rectangle =
880          {
881             (short)(surface.box.left + surface.offset.x),
882             (short)(surface.box.top + surface.offset.y),
883             (short)(surface.box.right - surface.box.left + 1),
884             (short)(surface.box.bottom - surface.box.top + 1)
885          };
886          XSetClipRectangles(xGlobalDisplay, xDisplay.gc,
887             0,0, &rectangle, 1, YXBanded);
888       }
889    }
890
891    bool GrabScreen(Display display, Bitmap bitmap, int x, int y, unsigned int w, unsigned int h)
892    {
893       bool result = false;
894       XDisplay xDisplay = display ? display.driverData : null;
895       XImage * xImage;
896       PixelFormat format = pixelFormat888;
897       Bitmap source { };
898       int sx = x, sy = y;
899       int dx = 0, dy = 0;
900       int sw = w, sh = h;
901
902       if(sx<0)
903       {
904          dx+=-sx;
905          sw-=-sx;
906          sx=0;
907       }
908       if(sy<0)
909       {
910          dy+=0-sy;
911          sh-=0-sy;
912          sy=0;
913       }
914       if(display)
915       {
916          if(sx+sw>display.width-1)
917             sw-=sx+sw-(display.width-1)-1;
918          if(sy+sh>display.height-1)
919             sh-=sy+sh-(display.height-1)-1;
920       }
921
922       if(display)
923          xImage = XGetImage(xGlobalDisplay, xDisplay.pixmap, sx, sy, sw, sh, MAXDWORD, ZPixmap);
924       else
925          xImage = XGetImage(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), sx, sy, sw, sh, MAXDWORD, ZPixmap);
926
927       source.pixelFormat = format;
928       source.picture = (byte *)xImage->data;
929       source.width = sw;
930       source.height = sh;
931       source.stride = xImage->bytes_per_line / 4;
932
933       if(!bitmap || bitmap.pixelFormat != format || bitmap.width < w || bitmap.height < h)
934       {
935          bitmap.Free();
936          bitmap.Allocate(null, w,h,w, format, (format == pixelFormat8)?true:false);
937       }
938       if(bitmap)
939       {
940          Surface surface = bitmap.GetSurface(0, 0, null);
941          surface.Blit(source, dx,dy,0,0,sw,sh);
942          delete surface;
943          result = true;
944       }
945       source.picture = null;
946       delete source;
947
948       XDestroyImage(xImage);
949       return result;
950    }
951
952    void SetForeground(Display display, Surface surface, ColorAlpha color)
953    {
954       XSurface xSurface = surface.driverData;
955       XDisplay xDisplay = display ? display.driverData : null;
956       XRenderColor renderColor = { (uint16)(color.color.r * color.a), (uint16)(color.color.g * color.a), (uint16)(color.color.b * color.a), (uint16)(color.a * 255) };
957
958       if(xSurface.colorPicture)
959          XRenderFreePicture(xGlobalDisplay, xSurface.colorPicture);
960       // xSurface.colorPicture = XRenderCreateSolidFill(xGlobalDisplay, &renderColor);
961
962       {
963          XRenderPictureAttributes attributes = { 0 };
964          // XRenderPictFormat * format = myXRenderFindStandardFormat(xGlobalDisplay, PictStandardARGB32  /*PictStandardRGB24 /*PictStandardARGB32*/, 1);
965          XRenderPictFormat * format = /*(xSystemPixelFormat != pixelFormat888) ? GetXRenderFormat(xSystemPixelFormat, false) : */XRenderFindStandardFormat(xGlobalDisplay, PictStandardARGB32);
966          #if !defined(__APPLE__) && !defined(__OLDX__)
967          attributes.repeat = RepeatNormal;
968          #else
969          attributes.repeat = 1;
970          #endif
971          ///attributes.component_alpha = 0;
972          if(format)
973             xSurface.colorPicture = XRenderCreatePicture(xGlobalDisplay, xSurface.colorPixmap, format, /*CPComponentAlpha | */CPRepeat, &attributes);
974          XRenderFillRectangle(xGlobalDisplay, PictOpSrc, xSurface.colorPicture, &renderColor, 0, 0, 1, 1);
975       }
976
977       // xSurface.foreground = ARGB(A(color),B(color),G(color),R(color));
978       xSurface.foreground = color;
979
980       if(xDisplay)
981          XSetForeground(xGlobalDisplay, xDisplay.gc, (xSystemPixelFormat == pixelFormat888) ? xSurface.foreground :
982             ((xSystemPixelFormat == pixelFormat565) ? ((Color565)xSurface.foreground) : ((Color555)xSurface.foreground)));
983    }
984
985    void SetBackground(Display display, Surface surface, ColorAlpha color)
986    {
987       XSurface xSurface = surface.driverData;
988       XDisplay xDisplay = display ? display.driverData : null;
989       // xSurface.background = ARGB(A(color),B(color),G(color),R(color));
990       xSurface.background = color;
991
992       if(xDisplay)
993          XSetBackground(xGlobalDisplay, xDisplay.gc, (xSystemPixelFormat == pixelFormat888) ? xSurface.background :
994             ((xSystemPixelFormat == pixelFormat565) ? ((Color565)xSurface.background) : ((Color555)xSurface.background)));
995    }
996
997    ColorAlpha GetPixel(Display display, Surface surface, int x, int y)
998    {
999       return 0;
1000    }
1001
1002    void PutPixel(Display display, Surface surface,int x,int y)
1003    {
1004       XSurface xSurface = surface.driverData;
1005       XDisplay xDisplay = display.driverData;
1006
1007       if(xSurface.foreground.a < 255)
1008          DrawLine(display, surface, x,y,x,y);
1009       else
1010          XDrawPoint(xGlobalDisplay, (Pixmap)xDisplay.pixmap, xDisplay.gc,
1011             x + surface.offset.x,
1012             y + surface.offset.y);
1013    }
1014
1015    void DrawLine(Display display, Surface surface, int x1, int y1, int x2, int y2)
1016    {
1017       XDisplay xDisplay = display ? display.driverData : null;
1018       XSurface xSurface = surface.driverData;
1019       if(!xDisplay || xSurface.foreground.a < 255)
1020       {
1021          XTrapezoid traps[3];
1022          int nTraps = 0;
1023          double offset = 0.5;
1024          double width = 0.5;
1025
1026          x1 += surface.offset.x;
1027          y1 += surface.offset.y;
1028          x2 += surface.offset.x;
1029          y2 += surface.offset.y;
1030
1031          if(y1 == y2)
1032          {
1033             x2++;
1034             x1--;
1035             {
1036                XTrapezoid trap1 =
1037                {
1038                   XDoubleToFixed(y1 - width + offset), XDoubleToFixed(y1 + width + offset),
1039                   { { XDoubleToFixed(Min(x1, x2) - 0 + offset), XDoubleToFixed(y1 - width + offset) }, { XDoubleToFixed(Min(x1, x2) + 0.0 + offset), XDoubleToFixed(y1 + width+ offset) } },
1040                   { { XDoubleToFixed(Max(x1, x2) - 0 + offset), XDoubleToFixed(y1 - width + offset) }, { XDoubleToFixed(Max(x1, x2) + 0.0 + offset), XDoubleToFixed(y1 + width+ offset) } }
1041                };
1042                traps[0] = trap1;
1043                nTraps = 1;
1044             }
1045          }
1046          else if(x1 == x2)
1047          {
1048             y2++;
1049             y1--;
1050             {
1051                XTrapezoid trap1 =
1052                {
1053                   XDoubleToFixed(Min(y1, y2) - 0.0 + offset), XDoubleToFixed(Max(y1, y2) + 0.0 + offset),
1054                   { { XDoubleToFixed(x1 - width + offset), XDoubleToFixed(Min(y1, y2) - 0.0 + offset) }, { XDoubleToFixed(x1 - width + offset), XDoubleToFixed(Max(y1, y2) + 0.0 + offset) } },
1055                   { { XDoubleToFixed(x1 + width + offset), XDoubleToFixed(Min(y1, y2) - 0.0 + offset) }, { XDoubleToFixed(x1 + width + offset), XDoubleToFixed(Max(y1, y2) + 0.0 + offset) } }
1056                };
1057                traps[0] = trap1;
1058                nTraps = 1;
1059             }
1060          }
1061          else
1062          {
1063             double dx, dy, l;
1064             Pointf A, B, C, D, E, F;
1065             if(y1 > y2)
1066             {
1067                int tmp = y2;
1068                y2 = y1;
1069                y1 = tmp;
1070                tmp = x2;
1071                x2 = x1;
1072                x1 = tmp;
1073             }
1074
1075             dx = x2 - x1;
1076             dy = y2 - y1;
1077             l = sqrt(dx * dx + dy * dy);
1078             dx /= l;
1079             dy /= l;
1080
1081             if(x2 > x1)
1082             {
1083                A = { (float)(x1 + dy * width), (float)(y1 - dx * width) };
1084                B = { (float)(x1 - dy * width), (float)(y1 + dx * width) };
1085                C = { (float)(A.x + ((B.y - A.y) * dx / dy)), B.y };
1086                E = { (float)(x2 + dy * width), (float)(y2 - dx * width) };
1087                F = { (float)(x2 - dy * width), (float)(y2 + dx * width) };
1088                D = { (float)(F.x + ((E.y - F.y) * dx / dy)), E.y };
1089
1090                {
1091                   XTrapezoid trap1 =
1092                   {
1093                      XDoubleToFixed(A.y + offset), XDoubleToFixed(B.y + offset),
1094                      { { XDoubleToFixed(A.x + offset), XDoubleToFixed(A.y + offset) }, { XDoubleToFixed(B.x + offset), XDoubleToFixed(B.y + offset) } },
1095                      { { XDoubleToFixed(A.x + offset), XDoubleToFixed(A.y + offset) }, { XDoubleToFixed(C.x + offset), XDoubleToFixed(C.y + offset) } }
1096                   };
1097                   XTrapezoid trap2 =
1098                   {
1099                      XDoubleToFixed(B.y + offset), XDoubleToFixed(D.y + offset),
1100                      { { XDoubleToFixed(B.x + offset), XDoubleToFixed(B.y + offset) }, { XDoubleToFixed(D.x + offset), XDoubleToFixed(D.y + offset) } },
1101                      { { XDoubleToFixed(C.x + offset), XDoubleToFixed(C.y + offset) }, { XDoubleToFixed(E.x + offset), XDoubleToFixed(E.y + offset) } }
1102                   };
1103                   XTrapezoid trap3 =
1104                   {
1105                      XDoubleToFixed(D.y + offset), XDoubleToFixed(F.y + offset),
1106                      { { XDoubleToFixed(D.x + offset), XDoubleToFixed(D.y + offset) }, { XDoubleToFixed(F.x + offset), XDoubleToFixed(F.y + offset) } },
1107                      { { XDoubleToFixed(E.x + offset), XDoubleToFixed(E.y + offset) }, { XDoubleToFixed(F.x + offset), XDoubleToFixed(F.y + offset) } }
1108                   };
1109                   traps[0] = trap1;
1110                   traps[1] = trap2;
1111                   traps[2] = trap3;
1112                   nTraps = 3;
1113                }
1114             }
1115             else
1116             {
1117                A = { (float)(x1 - dy * width), (float)(y1 + dx * width) };
1118                B = { (float)(x1 + dy * width), (float)(y1 - dx * width) };
1119                C = { (float)(A.x + ((B.y - A.y) * dx / dy)), B.y };
1120                E = { (float)(x2 - dy * width), (float)(y2 + dx * width) };
1121                F = { (float)(x2 + dy * width), (float)(y2 - dx * width) };
1122                D = { (float)(F.x + ((E.y - F.y) * dx / dy)), E.y };
1123
1124                {
1125                   XTrapezoid trap1 =
1126                   {
1127                      XDoubleToFixed(A.y + offset), XDoubleToFixed(B.y + offset),
1128                      { { XDoubleToFixed(A.x + offset), XDoubleToFixed(A.y + offset) }, { XDoubleToFixed(C.x + offset), XDoubleToFixed(C.y + offset) } },
1129                      { { XDoubleToFixed(A.x + offset), XDoubleToFixed(A.y + offset) }, { XDoubleToFixed(B.x + offset), XDoubleToFixed(B.y + offset) } }
1130                   };
1131                   XTrapezoid trap2 =
1132                   {
1133                      XDoubleToFixed(B.y + offset), XDoubleToFixed(D.y + offset),
1134                      { { XDoubleToFixed(C.x + offset), XDoubleToFixed(C.y + offset) }, { XDoubleToFixed(E.x + offset), XDoubleToFixed(E.y + offset) } },
1135                      { { XDoubleToFixed(B.x + offset), XDoubleToFixed(B.y + offset) }, { XDoubleToFixed(D.x + offset), XDoubleToFixed(D.y + offset) } }
1136                   };
1137                   XTrapezoid trap3 =
1138                   {
1139                      XDoubleToFixed(D.y + offset), XDoubleToFixed(F.y + offset),
1140                      { { XDoubleToFixed(E.x + offset), XDoubleToFixed(E.y + offset) }, { XDoubleToFixed(F.x + offset), XDoubleToFixed(F.y + offset) } },
1141                      { { XDoubleToFixed(D.x + offset), XDoubleToFixed(D.y + offset) }, { XDoubleToFixed(F.x + offset), XDoubleToFixed(F.y + offset) } }
1142                   };
1143                   traps[0] = trap1;
1144                   traps[1] = trap2;
1145                   traps[2] = trap3;
1146                   nTraps = 3;
1147                }
1148             }
1149             /*
1150             printf("Line: (%d, %d)-(%d, %d)\n", x1,y1, x2,y2);
1151             printf("Line: A = (%.2f, %.2f), B = (%.2f, %.2f), C = (%.2f, %.2f)\n", A.x,A.y, B.x,B.y, C.x,C.y);
1152             printf("Line: D = (%.2f, %.2f), E = (%.2f, %.2f), F = (%.2f, %.2f)\n", D.x,D.y, E.x,E.y, F.x,F.y);
1153             printf("Trap1: top = %.2f, bottom = %.2f, left = (%.2f, %.2f)-(%.2f, %.2f), right = (%.2f, %.2f)-(%.2f, %.2f)\n",
1154                traps[0].top / 65536.0, traps[0].bottom / 65536.0,
1155                traps[0].left.p1.x / 65536.0, traps[0].left.p1.y / 65536.0, traps[0].left.p2.x / 65536.0, traps[0].left.p2.y / 65536.0,
1156                traps[0].right.p1.x / 65536.0, traps[0].right.p1.y / 65536.0, traps[0].right.p2.x / 65536.0, traps[0].right.p2.y / 65536.0);
1157             printf("Trap2: top = %.2f, bottom = %.2f, left = (%.2f, %.2f)-(%.2f, %.2f), right = (%.2f, %.2f)-(%.2f, %.2f)\n",
1158                traps[1].top / 65536.0, traps[1].bottom / 65536.0,
1159                traps[1].left.p1.x / 65536.0,  traps[1].left.p1.y / 65536.0,  traps[1].left.p2.x / 65536.0,  traps[1].left.p2.y / 65536.0,
1160                traps[1].right.p1.x / 65536.0, traps[1].right.p1.y / 65536.0, traps[1].right.p2.x / 65536.0, traps[1].right.p2.y / 65536.0);
1161             printf("Trap3: top = %.2f, bottom = %.2f, left = (%.2f, %.2f)-(%.2f, %.2f), right = (%.2f, %.2f)-(%.2f, %.2f)\n",
1162                traps[2].top / 65536.0, traps[2].bottom / 65536.0,
1163                traps[2].left.p1.x / 65536.0,  traps[2].left.p1.y / 65536.0,  traps[2].left.p2.x / 65536.0,  traps[2].left.p2.y / 65536.0,
1164                traps[2].right.p1.x / 65536.0, traps[2].right.p1.y / 65536.0, traps[2].right.p2.x / 65536.0, traps[2].right.p2.y / 65536.0);
1165             printf("\n");
1166             */
1167          }
1168          XRenderCompositeTrapezoids(xGlobalDisplay, PictOpOver, xSurface.colorPicture, xSurface.picture, None, 0, 0, traps, nTraps);
1169       }
1170       else
1171          XDrawLine(xGlobalDisplay, (Pixmap)xDisplay.pixmap, xDisplay.gc,
1172             x1 + surface.offset.x,
1173             y1 + surface.offset.y,
1174             x2 + surface.offset.x,
1175             y2 + surface.offset.y);
1176    }
1177
1178    void Rectangle(Display display, Surface surface,int x1,int y1,int x2,int y2)
1179    {
1180       XDisplay xDisplay = display ? display.driverData : null;
1181       XSurface xSurface = surface.driverData;
1182
1183       if(!xDisplay || xSurface.foreground.a < 255)
1184       {
1185          DrawLine(display, surface,x1,y1,x2-1,y1);
1186          DrawLine(display, surface,x2,y1,x2,y2-1);
1187          DrawLine(display, surface,x1,y2,x2-1,y2);
1188          DrawLine(display, surface,x1,y1+1,x1,y2-1);
1189       }
1190       else
1191          XDrawRectangle(xGlobalDisplay, (Pixmap)xDisplay.pixmap, xDisplay.gc,
1192             x1 + surface.offset.x,
1193             y1 + surface.offset.y,
1194             x2 - x1, y2 - y1);
1195    }
1196
1197    void Area(Display display, Surface surface,int x1,int y1,int x2,int y2)
1198    {
1199       XDisplay xDisplay = display ? display.driverData : null;
1200       XSurface xSurface = surface.driverData;
1201       if(!xDisplay || xSurface.background.a < 255)
1202       {
1203          XRenderColor renderColor =
1204          {
1205             (uint16)(xSurface.background.color.r * xSurface.background.a),
1206             (uint16)(xSurface.background.color.g * xSurface.background.a),
1207             (uint16)(xSurface.background.color.b * xSurface.background.a),
1208             (uint16)(xSurface.background.a * 255)
1209          };
1210          x1 += surface.offset.x;
1211          y1 += surface.offset.y;
1212          x2 += surface.offset.x;
1213          y2 += surface.offset.y;
1214          XRenderFillRectangle(xGlobalDisplay, PictOpOver, xSurface.picture, &renderColor, x1, y1, (x2 - x1) + 1, (y2 - y1) + 1);
1215       }
1216       else
1217       {
1218          XSetForeground(xGlobalDisplay, xDisplay.gc, (xSystemPixelFormat == pixelFormat888) ? xSurface.background :
1219             ((xSystemPixelFormat == pixelFormat565) ? ((Color565)xSurface.background) : ((Color555)xSurface.background)));
1220          XFillRectangle(xGlobalDisplay, (Pixmap) xDisplay.pixmap, xDisplay.gc,
1221             x1 + surface.offset.x,
1222             y1 + surface.offset.y,
1223             x2 - x1 + 1, y2 - y1 + 1);
1224          XSetForeground(xGlobalDisplay, xDisplay.gc, (xSystemPixelFormat == pixelFormat888) ? xSurface.foreground :
1225             ((xSystemPixelFormat == pixelFormat565) ? ((Color565)xSurface.foreground) : ((Color555)xSurface.foreground)));
1226       }
1227    }
1228
1229    void Clear(Display display, Surface surface, ClearType flags)
1230    {
1231       if(flags != depthBuffer)
1232       {
1233          // XDisplay xDisplay = display.driverData;
1234          XSurface xSurface = surface.driverData;
1235          if(xSurface.background.a < 255)
1236          {
1237             int x1 = surface.box.left;
1238             int y1 = surface.box.top;
1239             int x2 = surface.box.right;
1240             int y2 = surface.box.bottom;
1241             XRenderColor renderColor =
1242             {
1243                (uint16)(xSurface.background.color.r * xSurface.background.a),
1244                (uint16)(xSurface.background.color.g * xSurface.background.a),
1245                (uint16)(xSurface.background.color.b * xSurface.background.a),
1246                (uint16)(xSurface.background.a * 255)
1247             };
1248             x1 += surface.offset.x;
1249             y1 += surface.offset.y;
1250             x2 += surface.offset.x;
1251             y2 += surface.offset.y;
1252             XRenderFillRectangle(xGlobalDisplay, PictOpSrc, xSurface.picture, &renderColor, x1, y1, (x2 - x1) + 1, (y2 - y1) + 1);
1253          }
1254          else
1255             Area(display, surface,surface.box.left,surface.box.top,surface.box.right,surface.box.bottom);
1256       }
1257    }
1258
1259    bool ConvertBitmap(DisplaySystem displaySystem, Bitmap src, PixelFormat format, ColorAlpha * palette)
1260    {
1261       return true;
1262    }
1263
1264    bool AllocateBitmap(DisplaySystem displaySystem, Bitmap bitmap, int width, int height, int stride, PixelFormat format, bool allocatePalette)
1265    {
1266       bool result = false;
1267       XBitmap xBitmap = bitmap.driverData = XBitmap { };
1268       if(xBitmap)
1269       {
1270          if(!stride)
1271          {
1272             switch(GetColorDepthShifts(format))
1273             {
1274                case 0: stride = (width + 3) & 0xFFFFFFFC; break;
1275                case 1: stride = (width + 1) & 0xFFFFFFFE; break;
1276                case 2: stride = width;                    break;
1277             }
1278          }
1279
1280          bitmap.stride = stride;
1281          bitmap.width = width;
1282          bitmap.height = height;
1283          bitmap.size = (uint)stride * (uint)height;
1284          bitmap.sizeBytes = bitmap.size << GetColorDepthShifts(format);
1285          bitmap.pixelFormat = format;
1286          bitmap.transparent = false;
1287          bitmap.allocatePalette = allocatePalette;
1288          if(allocatePalette)
1289          {
1290             bitmap.palette = new ColorAlpha[256];
1291             if(bitmap.palette)
1292                CopyBytesBy4(bitmap.palette, GetDefaultPalette(), 256);
1293          }
1294          else
1295             bitmap.palette = GetDefaultPalette();
1296
1297          result = true;
1298
1299          if(!result)
1300             FreeBitmap(displaySystem, bitmap);
1301       }
1302
1303       return result;
1304    }
1305
1306    void Blit(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
1307    {
1308       XDisplay xDisplay = display.driverData;
1309       XSurface xSurface = surface.driverData;
1310       XBitmap xBitmap = src.driverData;
1311       if(xBitmap)
1312       {
1313          bool flip;
1314          if(!ClipBlitCoords(surface, src, &dx, &dy, &sx, &sy, &w, &h, &flip))
1315             return;
1316
1317          dx += surface.offset.x;
1318          dy += surface.offset.y;
1319
1320          if(src.transparent && !src.alphaBlend && !display.alphaBlend)
1321          {
1322             XSetClipMask(xGlobalDisplay, xDisplay.gc, xBitmap.mask);
1323             XSetClipOrigin(xGlobalDisplay, xDisplay.gc, dx - sx, dy - sy);
1324          }
1325          if(xSurface.xOffset)
1326          {
1327             XTransform transform =
1328             {
1329                {
1330                   { (int)(1.0f * (1<<16)), (int)(0.0f * (1<<16)), -(xSurface.xOffset << 10) },
1331                   { (int)(0.0f), (int)(-1.0f * (1<<16)), (int)(0.0f * (1<<16)) },
1332                   { (int)(0.0f * (1<<16)), (int)(0.0f * (1<<16)), (int)(1.0f * (1<<16)) }
1333                }
1334             };
1335             // printf("XOffset: %d\n", xSurface.xOffset);
1336             XRenderSetPictureTransform(xGlobalDisplay, xBitmap.picture, &transform);
1337          }
1338
1339          if(src.alphaBlend || display.alphaBlend)
1340          {
1341             if(src.pixelFormat == pixelFormatAlpha
1342 #ifdef ENABLE_XRENDER_WORK_AROUND
1343                || xBitmap.alphaTweak
1344 #endif
1345                )
1346             {
1347                XRenderComposite(xGlobalDisplay, PictOpOver, xSurface.colorPicture, xBitmap.picture, xSurface.picture, 0, 0, sx, sy, dx, dy, w + (xSurface.xOffset ? 1 : 1), h);
1348             }
1349             else if(src.alphaBlend)
1350                XRenderComposite(xGlobalDisplay, PictOpOver, xBitmap.picture, None, xSurface.picture, sx, sy, sx, sy, dx, dy, w, h);
1351             else
1352                XRenderComposite(xGlobalDisplay, PictOpOver, xBitmap.picture, xBitmap.maskPicture, xSurface.picture, sx, sy, sx, sy, dx, dy, w, h);
1353          }
1354          else
1355             XCopyArea(xGlobalDisplay, (Pixmap)xBitmap.pixmap, (Pixmap)xSurface.pixmap, xDisplay.gc,
1356                sx, sy, w, h, dx, dy);
1357
1358          if(xSurface.xOffset)
1359          {
1360             XTransform identity =
1361             {
1362                {
1363                   { (int)(1.0f * (1<<16)), (int)(0.0f * (1<<16)), (int)(0.0f * (1<<16)) },
1364                   { (int)(0.0f * (1<<16)), (int)(1.0f * (1<<16)), (int)(0.0f * (1<<16)) },
1365                   { (int)(0.0f * (1<<16)), (int)(0.0f * (1<<16)), (int)(1.0f * (1<<16)) }
1366                }
1367             };
1368             XRenderSetPictureTransform(xGlobalDisplay, xBitmap.picture, &identity);
1369          }
1370          if(src.transparent && !src.alphaBlend && !display.alphaBlend)
1371          {
1372             XSetClipOrigin(xGlobalDisplay, xDisplay.gc, 0, 0);
1373             {
1374                XRectangle rectangle;
1375
1376                rectangle.x = (short)(surface.unclippedBox.left + surface.offset.x);
1377                rectangle.y = (short)(surface.unclippedBox.top + surface.offset.y);
1378                rectangle.width = (short)(surface.unclippedBox.right - surface.unclippedBox.left + 1);
1379                rectangle.height = (short)(surface.unclippedBox.bottom - surface.unclippedBox.top + 1);
1380
1381                XSetClipRectangles(xGlobalDisplay, xDisplay.gc, 0,0, &rectangle, 1, YXBanded);
1382             }
1383          }
1384       }
1385    }
1386
1387    void Stretch(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
1388    {
1389       XSurface xSurface = surface.driverData;
1390       XBitmap xBitmap = src.driverData;
1391       if(xBitmap)
1392       {
1393          XTransform transform =
1394          {
1395             {
1396                { (int)((float)sw / w * (1<<16)), (int)(0.0f * (1<<16)), (int)(0.0f * (1<<16)) },
1397                { (int)(0.0f * (1<<16)), (int)((float)sh / h * (1<<16)), (int)(0.0f * (1<<16)) },
1398                { (int)(0.0f * (1<<16)), (int)(0.0f * (1<<16)), (int)(1.0f * (1<<16)) }
1399             }
1400          };
1401          XTransform identity =
1402          {
1403             {
1404                { (int)(1.0f * (1<<16)), (int)(0.0f * (1<<16)), (int)(0.0f * (1<<16)) },
1405                { (int)(0.0f * (1<<16)), (int)(1.0f * (1<<16)), (int)(0.0f * (1<<16)) },
1406                { (int)(0.0f * (1<<16)), (int)(0.0f * (1<<16)), (int)(1.0f * (1<<16)) }
1407             }
1408          };
1409          dx += surface.offset.x;
1410          dy += surface.offset.y;
1411
1412          XRenderSetPictureTransform(xGlobalDisplay, xBitmap.picture, &transform);
1413
1414          if(src.pixelFormat == pixelFormatAlpha
1415 #ifdef ENABLE_XRENDER_WORK_AROUND
1416             || xBitmap.alphaTweak
1417 #endif
1418             )
1419             XRenderComposite(xGlobalDisplay, PictOpOver, xSurface.colorPicture, xBitmap.picture, xSurface.picture, 0, 0, sx, sy, dx, dy, w, h);
1420          else if(src.alphaBlend)
1421             XRenderComposite(xGlobalDisplay, PictOpOver, xBitmap.picture, None, xSurface.picture, sx, sy, sx, sy, dx, dy, w, h);
1422          else
1423          {
1424             XRenderSetPictureTransform(xGlobalDisplay, xBitmap.maskPicture, &transform);
1425             XRenderComposite(xGlobalDisplay, PictOpOver, xBitmap.picture, xBitmap.maskPicture, xSurface.picture, sx, sy, sx, sy, dx, dy, w, h);
1426             XRenderSetPictureTransform(xGlobalDisplay, xBitmap.maskPicture, &identity);
1427          }
1428          XRenderSetPictureTransform(xGlobalDisplay, xBitmap.picture, &identity);
1429       }
1430    }
1431
1432    void Filter(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
1433    {
1434       XBitmap xBitmap = src.driverData;
1435       if(xBitmap)
1436       {
1437          XRenderSetPictureFilter(xGlobalDisplay, xBitmap.picture, "bilinear", null, 0);
1438          Stretch(display, surface, src, dx, dy, sx, sy, w, h, sw, sh);
1439          XRenderSetPictureFilter(xGlobalDisplay, xBitmap.picture, "nearest", null, 0);
1440       }
1441    }
1442
1443    void BlitDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h)
1444    {
1445       XImage image = { 0 };
1446       XDisplay xDisplay = display ? display.driverData : null;
1447       XSurface xSurface = surface.driverData;
1448       bool flip;
1449
1450       if(!xDisplay || !src.picture || !ClipBlitCoords(surface, src, &dx, &dy, &sx, &sy, &w, &h, &flip))
1451          return;
1452
1453       if(src.pixelFormat == display.pixelFormat)
1454       {
1455          image.width = src.width;
1456          image.height = src.height;
1457          image.depth = (src.pixelFormat == pixelFormat888) ? 24 : xSystemDepth;
1458          image.bitmap_pad = (src.pixelFormat == pixelFormat888) ? 32 : 16;
1459          image.format = ZPixmap;
1460          image.bitmap_unit = 8;
1461          image.bytes_per_line = ((src.pixelFormat == pixelFormat888) ? 4 : 2) * src.stride;
1462          image.bits_per_pixel = (src.pixelFormat == pixelFormat888) ? 32 : 16;
1463
1464          image.data = (char *)src.picture;
1465          XInitImage(&image);
1466
1467          XPutImage(xGlobalDisplay, (Pixmap)xSurface.pixmap, xDisplay.gc, &image,
1468             sx, sy, dx + surface.offset.x, dy + surface.offset.y, w,h);
1469       }
1470       else
1471       {
1472          Bitmap temp { };
1473          Surface s;
1474          temp.Allocate(null, w, h, 0, xSystemPixelFormat, false);
1475          s = temp.GetSurface(0,0,null);
1476          s.Blit(src, 0,0, sx,sy, flip ? -w : w, h);
1477
1478          image.width = w;
1479          image.height = h;
1480          image.depth = (temp.pixelFormat == pixelFormat888) ? 24 : xSystemDepth;
1481          image.bitmap_pad = (temp.pixelFormat == pixelFormat888) ? 32 : 16;
1482          image.format = ZPixmap;
1483          image.bitmap_unit = 8;
1484          image.bytes_per_line = ((temp.pixelFormat == pixelFormat888) ? 4 : 2) * temp.stride;
1485          image.bits_per_pixel = (temp.pixelFormat == pixelFormat888) ? 32 : 16;
1486
1487          image.data = (char *)temp.picture;
1488
1489          XInitImage(&image);
1490          if(!src.transparent)
1491          {
1492             // printf("Stride: %d, dx: %d, dy: %d, w: %d, h: %d, %d\n", temp.stride, dx + surface.offset.x, dy + surface.offset.y, w,h, xSystemDepth);
1493             XPutImage(xGlobalDisplay, (Pixmap)xSurface.pixmap, xDisplay.gc, &image,
1494                0, 0, dx + surface.offset.x, dy + surface.offset.y, w,h);
1495          }
1496          else
1497          {
1498          #if 0
1499             GC maskGC = 0, gc = 0;
1500             Pixmap pixmap, mask;
1501
1502             pixmap = XCreatePixmap(xGlobalDisplay, (X11Window)confineWindow /*display.window*/, w, h, xSystemDepth /*24*/);
1503             mask = XCreatePixmap(xGlobalDisplay, (X11Window)confineWindow /*display.window*/, w, h, 1);
1504
1505             gc = XCreateGC(xGlobalDisplay, pixmap, 0, null);
1506             maskGC = XCreateGC(xGlobalDisplay, mask, 0, null);
1507             XSetGraphicsExposures(xGlobalDisplay, gc, False);
1508             XSetGraphicsExposures(xGlobalDisplay, maskGC, False);
1509
1510             XPutImage(xGlobalDisplay, pixmap, gc, &image, 0, 0, 0, 0, w,h);
1511             XSetForeground(xGlobalDisplay, maskGC, 0);
1512             XFillRectangle(xGlobalDisplay, mask, maskGC, 0, 0, w, h);
1513             XSetForeground(xGlobalDisplay, maskGC, 1);
1514             if(temp.pixelFormat == pixelFormat888)
1515             {
1516                int x,y;
1517                for(y = 0; y<h; y++)
1518                {
1519                   for(x = 0; x<w; x++)
1520                   {
1521                      if(((ColorAlpha *)temp.picture)[y * temp.stride + x].a)
1522                         XDrawPoint(xGlobalDisplay, mask, maskGC, x, y);
1523                   }
1524                }
1525             }
1526             else if(src.pixelFormat == pixelFormat8)
1527             {
1528                int x,y;
1529                for(y = 0; y<h; y++)
1530                {
1531                   for(x = 0; x<w; x++)
1532                   {
1533                      if(src.picture[(y + sy) * src.stride + (flip ? (w-1-(sx + x)) : (sx + x)])
1534                         XDrawPoint(xGlobalDisplay, mask, maskGC, x, y);
1535                   }
1536                }
1537             }
1538             else
1539             {
1540                int x,y;
1541                for(y = 0; y<h; y++)
1542                {
1543                   for(x = 0; x<w; x++)
1544                   {
1545                      if(((uint16 *)temp.picture)[y * temp.stride + x])
1546                         XDrawPoint(xGlobalDisplay, mask, maskGC, x, y);
1547                   }
1548                }
1549             }
1550
1551             XFreeGC(xGlobalDisplay, maskGC);
1552          #else
1553          GC gc = 0;
1554             Pixmap pixmap, mask;
1555
1556             pixmap = XCreatePixmap(xGlobalDisplay, (X11Window)confineWindow /*display.window*/, w, h, xSystemDepth /*24*/);
1557             mask = XCreatePixmap(xGlobalDisplay, (X11Window)confineWindow /*display.window*/, w, h, 1);
1558
1559             gc = XCreateGC(xGlobalDisplay, pixmap, 0, null);
1560             XSetGraphicsExposures(xGlobalDisplay, gc, False);
1561
1562             XPutImage(xGlobalDisplay, pixmap, gc, &image, 0, 0, 0, 0, w,h);
1563
1564          PutBitmapMask(mask, temp);
1565          #endif
1566
1567             XSetClipMask(xGlobalDisplay, xDisplay.gc, mask);
1568             XSetClipOrigin(xGlobalDisplay, xDisplay.gc, dx + surface.offset.x, dy + surface.offset.y);
1569             XCopyArea(xGlobalDisplay, pixmap, (Pixmap)xSurface.pixmap, xDisplay.gc, 0, 0, w, h, dx + surface.offset.x, dy + surface.offset.y);
1570             XSetClipOrigin(xGlobalDisplay, xDisplay.gc, 0, 0);
1571             {
1572                XRectangle rectangle;
1573
1574                rectangle.x = (short)(surface.unclippedBox.left + surface.offset.x);
1575                rectangle.y = (short)(surface.unclippedBox.top + surface.offset.y);
1576                rectangle.width = (short)(surface.unclippedBox.right - surface.unclippedBox.left + 1);
1577                rectangle.height = (short)(surface.unclippedBox.bottom - surface.unclippedBox.top + 1);
1578
1579                XSetClipRectangles(xGlobalDisplay, xDisplay.gc, 0,0, &rectangle, 1, YXBanded);
1580             }
1581
1582             XFreeGC(xGlobalDisplay, gc);
1583             XFreePixmap(xGlobalDisplay, pixmap);
1584             XFreePixmap(xGlobalDisplay, mask);
1585          }
1586          delete s;
1587          delete temp;
1588       }
1589    }
1590
1591    void StretchDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
1592    {
1593       bool flip;
1594       if(ClipStretchCoords(surface, src, &dx, &dy, &sx, &sy, &w, &h, &sw, &sh, &flip))
1595       {
1596          XImage image = { 0 };
1597          XDisplay xDisplay = display.driverData;
1598          XSurface xSurface = surface.driverData;
1599          Bitmap temp { };
1600          Surface s;
1601          temp.Allocate(null, w, h, 0, xSystemPixelFormat, false);
1602          s = temp.GetSurface(0,0,null);
1603          s.Stretch(src, 0,0, sx,sy, w, h, sw, sh);
1604
1605          image.width = w;
1606          image.height = h;
1607          image.depth = (temp.pixelFormat == pixelFormat888) ? 24 : xSystemDepth;
1608          image.bitmap_pad = (temp.pixelFormat == pixelFormat888) ? 32 : 16;
1609          image.format = ZPixmap;
1610          image.bitmap_unit = 8;
1611          image.bytes_per_line = ((temp.pixelFormat == pixelFormat888) ? 4 : 2) * temp.stride;
1612          image.bits_per_pixel = (temp.pixelFormat == pixelFormat888) ? 32 : 16;
1613
1614          image.data = (char *)temp.picture;
1615          XInitImage(&image);
1616
1617          // printf("Blitting DI\n");
1618          XPutImage(xGlobalDisplay, (Pixmap)xSurface.pixmap, xDisplay.gc, &image,
1619             0, 0, dx + surface.offset.x, dy + surface.offset.y, w,h);
1620
1621          delete s;
1622          delete temp;
1623       }
1624    }
1625
1626    void FilterDI(Display display, Surface surface, Bitmap src, int dx, int dy, int sx, int sy, int w, int h, int sw, int sh)
1627    {
1628       bool flip;
1629       if(ClipStretchCoords(surface, src, &dx, &dy, &sx, &sy, &w, &h, &sw, &sh, &flip))
1630       {
1631          XImage image = { 0 };
1632          XDisplay xDisplay = display.driverData;
1633          XSurface xSurface = surface.driverData;
1634          Bitmap temp { };
1635          Surface s;
1636          temp.Allocate(null, w, h, 0, xSystemPixelFormat, false);
1637          s = temp.GetSurface(0,0,null);
1638          s.Filter(src, 0,0, sx,sy, w, h, sw, sh);
1639
1640          image.width = w;
1641          image.height = h;
1642          image.depth = (temp.pixelFormat == pixelFormat888) ? 24 : xSystemDepth;
1643          image.bitmap_pad = (temp.pixelFormat == pixelFormat888) ? 32 : 16;
1644          image.format = ZPixmap;
1645          image.bitmap_unit = 8;
1646          image.bytes_per_line = ((temp.pixelFormat == pixelFormat888) ? 4 : 2) * temp.stride;
1647          image.bits_per_pixel = (temp.pixelFormat == pixelFormat888) ? 32 : 16;;
1648
1649          image.data = (char *)temp.picture;
1650          XInitImage(&image);
1651
1652          // printf("Blitting DI\n");
1653          XPutImage(xGlobalDisplay, (Pixmap)xSurface.pixmap, xDisplay.gc, &image,
1654             0, 0, dx + surface.offset.x, dy + surface.offset.y, w,h);
1655
1656          delete s;
1657          delete temp;
1658       }
1659    }
1660
1661    Font LoadFont(DisplaySystem displaySystem, const char * faceName, float size, FontFlags flags)
1662    {
1663       Font font;
1664       font = ((subclass(DisplayDriver))class(LFBDisplayDriver)).LoadFont(displaySystem, faceName, size, flags);
1665       return font;
1666    }
1667
1668    void UnloadFont(DisplaySystem displaySystem, Font font)
1669    {
1670       ((subclass(DisplayDriver))class(LFBDisplayDriver)).UnloadFont(displaySystem, font);
1671    }
1672
1673    void TextFont(Display display, Surface surface, Font font)
1674    {
1675       // XSurface xSurface = surface.driverData;
1676       ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextFont(display, surface, font);
1677    }
1678
1679    void TextOpacity(Display display, Surface surface, bool opaque)
1680    {
1681       XSurface xSurface = surface.driverData;
1682       xSurface.opaque = opaque;
1683    }
1684
1685    #define CHAR_WIDTH   6
1686    #define CHAR_HEIGHT  14
1687
1688    void WriteText(Display display, Surface surface, int x, int y, const char * text, int len, int prevGlyph, int * rPrevGlyph)
1689    {
1690       XSurface xSurface = surface.driverData;
1691       //XDisplay xDisplay = display.driverData;
1692       int tw, th, adv;
1693
1694       ((subclass(DisplayDriver))class(LFBDisplayDriver)).TextExtent(display, surface, text, len, &tw, &th, prevGlyph, rPrevGlyph, &adv);
1695       tw += adv;
1696       if(xSurface.opaque)
1697       {
1698 #if 0
1699          XSetForeground(xGlobalDisplay, xDisplay.gc, xSurface.background);
1700
1701          XFillRectangle(xGlobalDisplay, (Pixmap)xDisplay.pixmap, xDisplay.gc,
1702             x + surface.offset.x, y + surface.offset.y,
1703             tw /*len * CHAR_WIDTH*/, th /*CHAR_HEIGHT*/);
1704
1705          XSetForeground(xGlobalDisplay, xDisplay.gc, xSurface.foreground);
1706 #endif
1707
1708          XRenderColor renderColor =
1709          {
1710             (uint16)(xSurface.background.color.r * xSurface.background.a),
1711             (uint16)(xSurface.background.color.g * xSurface.background.a),
1712             (uint16)(xSurface.background.color.b * xSurface.background.a),
1713             (uint16)xSurface.background.a
1714          };
1715          //printf("Filling rectangle\n");
1716          XRenderFillRectangle(xGlobalDisplay, PictOpSrc /*PictOpOver*/, xSurface.picture, &renderColor,
1717             x + surface.offset.x, y + surface.offset.y, tw, th);
1718       }
1719       /*
1720       XDrawString(xGlobalDisplay, (Pixmap)xDisplay.pixmap, xDisplay.gc,
1721          x + surface.offset.x, y + surface.offset.y + 12, text, len);
1722       */
1723
1724       ((subclass(DisplayDriver))class(LFBDisplayDriver)).WriteText(display, surface, x, y, text, len, prevGlyph, rPrevGlyph);
1725    }
1726
1727    void TextExtent(Display display, Surface surface, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
1728    {
1729       XSurface xSurface = surface.driverData;
1730       /*
1731       uint realLen;
1732       for(realLen = 0; realLen<len && text[realLen]; realLen++);
1733       if(width) *width = len * CHAR_WIDTH;
1734       if(height) *height = CHAR_HEIGHT;
1735       */
1736
1737       FontExtent(display.displaySystem, xSurface.font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
1738    }
1739
1740    void FontExtent(DisplaySystem displaySystem, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * adv)
1741    {
1742       /*
1743       if(width) *width = len * CHAR_WIDTH;
1744       if(height) *height = CHAR_HEIGHT;
1745       */
1746       ((subclass(DisplayDriver))class(LFBDisplayDriver)).FontExtent(displaySystem, font, text, len, width, height, prevGlyph, rPrevGlyph, adv);
1747    }
1748
1749    void DrawingChar(Display display, Surface surface, byte character)
1750    {
1751
1752    }
1753
1754    void LineStipple(Display display, Surface surface, uint stipple)
1755    {
1756       XDisplay xDisplay = display.driverData;
1757       char list[32] = { 0 };
1758       int count = 0;
1759
1760       if(stipple)
1761       {
1762          int c;
1763          int offset = 0;
1764          uint16 on = 0x8000;
1765
1766          for(c = 0; c<32; c++)
1767          {
1768             if((stipple & 0x8000) == on)
1769                list[count]++;
1770             else
1771             {
1772                if(!list[count])
1773                   offset = 1;
1774                else
1775                {
1776                   count++;
1777                   list[count]++;
1778                   on ^= 0x8000;
1779                }
1780             }
1781             stipple <<= 1;
1782          }
1783          XSetLineAttributes(xGlobalDisplay, xDisplay.gc, 0, LineOnOffDash, CapButt, JoinMiter);
1784          XSetDashes(xGlobalDisplay, xDisplay.gc, offset, list, count);
1785       }
1786       else
1787       {
1788          list[0] = 4;
1789          count = 1;
1790          XSetLineAttributes(xGlobalDisplay, xDisplay.gc, 0, LineSolid, CapButt, JoinMiter);
1791          XSetDashes(xGlobalDisplay, xDisplay.gc, 0, list, count);
1792       }
1793    }
1794
1795    bool Lock(Display display)
1796    {
1797       //XLockDisplay(xGlobalDisplay);
1798       return true;
1799    }
1800
1801    void Unlock(Display display)
1802    {
1803       //XUnlockDisplay(xGlobalDisplay);
1804    }
1805
1806    void StartUpdate(Display display)
1807    {
1808
1809    }
1810
1811    void Scroll(Display display, Box scroll, int x, int y, Extent dirty)
1812    {
1813
1814    }
1815
1816    void Update(Display display, Box updateBox)
1817    {
1818       XDisplay xDisplay = display.driverData;
1819       Box * box = (updateBox != null) ? updateBox : &xDisplay.updateBox;
1820
1821       {
1822          XRectangle rectangle;
1823          rectangle.x = 0;
1824          rectangle.y = 0;
1825          rectangle.width = (uint16)display.width;
1826          rectangle.height = (uint16)display.height;
1827          XSetClipRectangles(xGlobalDisplay, xDisplay.gc, 0,0, &rectangle, 1, YXBanded);
1828       }
1829       /*if(display.alphaBlend)
1830          XRenderComposite(xGlobalDisplay, PictOpSrc, xDisplay.picture, None, xDisplay.windowPicture, box->left, box->top, 0, 0, box->left, box->top,
1831             box->right - box->left + 1, box->bottom - box->top + 1);
1832       else*/
1833          XCopyArea(xGlobalDisplay, (Pixmap)xDisplay.pixmap, (X11Window)display.window, xDisplay.gc /*windowGC*/,
1834             box->left, box->top,
1835             box->right - box->left + 1,
1836             box->bottom - box->top + 1,
1837             box->left, box->top);
1838
1839       if(display.alphaBlend)
1840       {
1841          Box * box = &xDisplay.updateBox;
1842          XRenderComposite(xGlobalDisplay, PictOpSrc, xDisplay.picture, None, xDisplay.shapePicture, box->left, box->top, 0, 0, box->left, box->top,
1843             box->right - box->left + 1, box->bottom - box->top + 1);
1844          #if !defined(__APPLE__) && !defined(__OLDX__)
1845          XShapeCombineMask(xGlobalDisplay, (X11Window)display.window, ShapeInput, 0, 0, xDisplay.shapePixmap, ShapeSet);
1846          #else
1847          XShapeCombineMask(xGlobalDisplay, (X11Window)display.window, 2, 0, 0, xDisplay.shapePixmap, ShapeSet);
1848          #endif
1849       }
1850
1851       XFlush(xGlobalDisplay);
1852       if(updateBox == null)
1853       {
1854          xDisplay.updateBox.left = display.width;
1855          xDisplay.updateBox.top = display.height;
1856          xDisplay.updateBox.right = 0;
1857          xDisplay.updateBox.bottom = 0;
1858       }
1859    }
1860
1861    void EndUpdate(Display display)
1862    {
1863
1864    }
1865 }
1866
1867 default dllexport long IS_XGetPixmap(Bitmap bitmap)
1868 {
1869    XBitmap xBitmap = bitmap.driverData;
1870    return xBitmap.pixmap;
1871 }
1872
1873 default dllexport void IS_XGetSurfaceInfo(Surface surface, Pixmap * pixmap, GC * gc, int *x, int * y)
1874 {
1875    Display display = surface.display;
1876    XDisplay xDisplay = display.driverData;
1877
1878    *pixmap = xDisplay.pixmap;
1879    *gc = xDisplay.gc;
1880    *x = surface.offset.x;
1881    *y = surface.offset.y;
1882 }
1883
1884 #endif