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