1 module simpledisplay;
2 /*
3     Stuff to add:
4 
5     Pens and brushes?
6     Maybe a global event loop?
7 
8     Mouse deltas
9     Key items
10 */
11 
12 version(linux)
13     version = X11;
14 version(OSX)
15     version = X11;
16 version(FreeBSD)
17     version = X11;
18 version(Solaris)
19     version = X11;
20 
21 import std.exception;
22 import core.thread;
23 import std.string; // FIXME: move to drawText X11 on next dmd
24 
25 import std.stdio;
26 
27 import arsd.color; // no longer stand alone... :-( but i need a common type for this to work with images easily.
28 
29 struct Point {
30     int x;
31     int y;
32 }
33 
34 struct Size {
35     int width;
36     int height;
37 }
38 
39 
40 struct KeyEvent {
41 
42 }
43 
44 struct MouseEvent {
45     int type; // movement, press, release, double click
46 
47     int x;
48     int y;
49 
50     int button;
51     int buttonFlags;
52 }
53 
54 struct MouseClickEvent {
55 
56 }
57 
58 struct MouseMoveEvent {
59 
60 }
61 
62 
63 struct Pen {
64     Color color;
65     int width;
66     Style style;
67 /+
68 // From X.h
69 
70 #define LineSolid       0
71 #define LineOnOffDash       1
72 #define LineDoubleDash      2
73        LineDou-        The full path of the line is drawn, but the
74        bleDash         even dashes are filled differently from the
75                        odd dashes (see fill-style) with CapButt
76                        style used where even and odd dashes meet.
77 
78 
79 
80 /* capStyle */
81 
82 #define CapNotLast      0
83 #define CapButt         1
84 #define CapRound        2
85 #define CapProjecting       3
86 
87 /* joinStyle */
88 
89 #define JoinMiter       0
90 #define JoinRound       1
91 #define JoinBevel       2
92 
93 /* fillStyle */
94 
95 #define FillSolid       0
96 #define FillTiled       1
97 #define FillStippled        2
98 #define FillOpaqueStippled  3
99 
100 
101 +/
102     enum Style {
103         Solid,
104         Dashed
105     }
106 }
107 
108 
109 class Image {
110     this(int width, int height) {
111         this.width = width;
112         this.height = height;
113 
114         impl.createImage(width, height);
115     }
116 
117     this(Size size) {
118         this(size.width, size.height);
119     }
120 
121     ~this() {
122         impl.dispose();
123     }
124 
125     void putPixel(int x, int y, Color c) {
126         if(x < 0 || x >= width)
127             return;
128         if(y < 0 || y >= height)
129             return;
130 
131         impl.setPixel(x, y, c);
132     }
133 
134     void opIndexAssign(Color c, int x, int y) {
135         putPixel(x, y, c);
136     }
137 
138     immutable int width;
139     immutable int height;
140     private:
141     mixin NativeImageImplementation!() impl;
142 }
143 
144 void displayImage(Image image, SimpleWindow win = null) {
145     if(win is null) {
146         win = new SimpleWindow(image);
147         {
148             auto p = win.draw;
149             p.drawImage(Point(0, 0), image);
150         }
151         win.eventLoop(0,
152             (int) {
153                 win.close();
154             } );
155     } else {
156         win.image = image;
157     }
158 }
159 
160 /// Most functions use the outlineColor instead of taking a color themselves.
161 struct ScreenPainter {
162     SimpleWindow window;
163     this(SimpleWindow window, NativeWindowHandle handle) {
164         this.window = window;
165         if(window.activeScreenPainter !is null) {
166             impl = window.activeScreenPainter;
167             impl.referenceCount++;
168         //  writeln("refcount ++ ", impl.referenceCount);
169         } else {
170             impl = new ScreenPainterImplementation;
171             impl.window = window;
172             impl.create(handle);
173             impl.referenceCount = 1;
174             window.activeScreenPainter = impl;
175         //  writeln("constructed");
176         }
177     }
178 
179     ~this() {
180         impl.referenceCount--;
181         //writeln("refcount -- ", impl.referenceCount);
182         if(impl.referenceCount == 0) {
183             //writeln("destructed");
184             impl.dispose();
185             window.activeScreenPainter = null;
186         }
187     }
188 
189     // @disable this(this) { } // compiler bug? the linker is bitching about it beind defined twice
190 
191     this(this) {
192         impl.referenceCount++;
193         //writeln("refcount ++ ", impl.referenceCount);
194     }
195 
196     @property void outlineColor(Color c) {
197         impl.outlineColor(c);
198     }
199 
200     @property void fillColor(Color c) {
201         impl.fillColor(c);
202     }
203 
204     void updateDisplay() {
205         // FIXME
206     }
207 
208     void.destroy() {
209         fillColor = Color(255, 255, 255);
210         drawRectangle(Point(0, 0), window.width, window.height);
211     }
212 
213     void drawImage(Point upperLeft, Image i) {
214         impl.drawImage(upperLeft.x, upperLeft.y, i);
215     }
216 
217     void drawText(Point upperLeft, string text) {
218         // bounding rect other sizes are ignored for now
219         impl.drawText(upperLeft.x, upperLeft.y, 0, 0, text);
220     }
221 
222     void drawPixel(Point where) {
223         impl.drawPixel(where.x, where.y);
224     }
225 
226 
227     void drawLine(Point starting, Point ending) {
228         impl.drawLine(starting.x, starting.y, ending.x, ending.y);
229     }
230 
231     void drawRectangle(Point upperLeft, int width, int height) {
232         impl.drawRectangle(upperLeft.x, upperLeft.y, width, height);
233     }
234 
235     /// Arguments are the points of the bounding rectangle
236     void drawEllipse(Point upperLeft, Point lowerRight) {
237         impl.drawEllipse(upperLeft.x, upperLeft.y, lowerRight.x, lowerRight.y);
238     }
239 
240     void drawArc(Point upperLeft, int width, int height, int start, int finish) {
241         impl.drawArc(upperLeft.x, upperLeft.y, width, height, start, finish);
242     }
243 
244     void drawPolygon(Point[] vertexes) {
245         impl.drawPolygon(vertexes);
246     }
247 
248 
249     // and do a draw/fill in a single call maybe. Windows can do it... but X can't, though it could do two calls.
250 
251     //mixin NativeScreenPainterImplementation!() impl;
252 
253 
254     // HACK: if I mixin the impl directly, it won't let me override the copy
255     // constructor! The linker complains about there being multiple definitions.
256     // I'll make the best of it and reference count it though.
257     ScreenPainterImplementation* impl;
258 }
259 
260     // HACK: I need a pointer to the implementation so it's separate
261     struct ScreenPainterImplementation {
262         SimpleWindow window;
263         int referenceCount;
264         mixin NativeScreenPainterImplementation!();
265     }
266 
267 class SimpleWindow {
268     int width;
269     int height;
270 
271     // HACK: making the best of some copy constructor woes with refcounting
272     private ScreenPainterImplementation* activeScreenPainter;
273 
274     /// Creates a window based on the given image. It's client area
275     /// width and height is equal to the image. (A window's client area
276     /// is the drawable space inside; it excludes the title bar, etc.)
277     this(Image image, string title = null) {
278         this.backingImage = image;
279         this(image.width, image.height, title);
280     }
281 
282     this(Size size, string title = null) {
283         this(size.width, size.height, title);
284     }
285 
286     this(int width, int height, string title = null) {
287         this.width = width;
288         this.height = height;
289         impl.createWindow(width, height, title is null ? "D Application" : title);
290     }
291 
292     Image backingImage;
293 
294     ~this() {
295         impl.dispose();
296     }
297 
298     /// Closes the window and terminates it's event loop.
299     void close() {
300         impl.closeWindow();
301     }
302 
303     /// The event loop automatically returns when the window is closed
304     /// pulseTimeout is given in milliseconds.
305     final int eventLoop(T...)(
306         long pulseTimeout,    /// set to zero if you don't want a pulse. Note: don't set it too big, or user input may not be processed in a timely manner. I suggest something < 150.
307         T eventHandlers) /// delegate list like std.concurrency.receive
308     {
309 
310         // FIXME: add more events
311         foreach(handler; eventHandlers) {
312             static if(__traits(compiles, handleKeyEvent = handler)) {
313                 handleKeyEvent = handler;
314             } else static if(__traits(compiles, handleCharEvent = handler)) {
315                 handleCharEvent = handler;
316             } else static if(__traits(compiles, handlePulse = handler)) {
317                 handlePulse = handler;
318             } else static if(__traits(compiles, handleMouseEvent = handler)) {
319                 handleMouseEvent = handler;
320             } else static assert(0, "I can't use this event handler " ~ typeof(handler).stringof);
321         }
322 
323 
324         return impl.eventLoop(pulseTimeout);
325     }
326 
327     ScreenPainter draw() {
328         return impl.getPainter();
329     }
330 
331     @property void image(Image i) {
332         backingImage = i;
333         version(Windows) {
334             RECT r;
335             r.right = i.width;
336             r.bottom = i.height;
337 
338             InvalidateRect(hwnd, &r, false);
339         }
340         version(X11) {
341             if(!destroyed)
342             XPutImage(display, cast(Drawable) window, gc, backingImage.handle, 0, 0, 0, 0, backingImage.width, backingImage.height);
343         }
344     }
345 
346     /// What follows are the event handlers. These are set automatically
347     /// by the eventLoop function, but are still public so you can change
348     /// them later.
349 
350     /// Handles a low-level keyboard event
351     void delegate(int key) handleKeyEvent;
352 
353     /// Handles a higher level keyboard event - c is the character just pressed.
354     void delegate(dchar c) handleCharEvent;
355 
356     void delegate() handlePulse;
357 
358     void delegate(MouseEvent) handleMouseEvent;
359 
360     /** Platform specific - handle any native messages this window gets.
361       *
362       * Note: this is called *in addition to* other event handlers.
363 
364       * On Windows, it takes the form of void delegate(UINT, WPARAM, LPARAM).
365 
366       * On X11, it takes the form of void delegate(XEvent).
367     **/
368     NativeEventHandler handleNativeEvent;
369 
370   private:
371     mixin NativeSimpleWindowImplementation!() impl;
372 }
373 
374 /* Additional utilities */
375 
376 
377 import std.conv;
378 import std.math;
379 
380 Color fromHsl(real h, real s, real l) {
381     h = h % 360;
382 
383     real C = (1 - abs(2 * l - 1)) * s;
384 
385     real hPrime = h / 60;
386 
387     real X = C * (1 - abs(hPrime % 2 - 1));
388 
389     real r, g, b;
390 
391     if(std.math.isNaN(h))
392         r = g = b = 0;
393     else if (hPrime >= 0 && hPrime < 1) {
394         r = C;
395         g = X;
396         b = 0;
397     } else if (hPrime >= 1 && hPrime < 2) {
398         r = X;
399         g = C;
400         b = 0;
401     } else if (hPrime >= 2 && hPrime < 3) {
402         r = 0;
403         g = C;
404         b = X;
405     } else if (hPrime >= 3 && hPrime < 4) {
406         r = 0;
407         g = X;
408         b = C;
409     } else if (hPrime >= 4 && hPrime < 5) {
410         r = X;
411         g = 0;
412         b = C;
413     } else if (hPrime >= 5 && hPrime < 6) {
414         r = C;
415         g = 0;
416         b = X;
417     }
418 
419     real m = l - C / 2;
420 
421     r += m;
422     g += m;
423     b += m;
424 
425     return Color(
426         cast(ubyte)(r * 255),
427         cast(ubyte)(g * 255),
428         cast(ubyte)(b * 255),
429         255);
430 }
431 
432 
433 
434 /* ********** What follows is the system-specific implementations *********/
435 version(Windows) {
436     import std.string;
437 
438     SimpleWindow[HWND] windowObjects;
439 
440     alias void delegate(UINT, WPARAM, LPARAM) NativeEventHandler;
441     alias HWND NativeWindowHandle;
442 
443     extern(Windows)
444     int WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) nothrow {
445         try {
446             if(hWnd in windowObjects) {
447                 auto window = windowObjects[hWnd];
448                 return window.windowProcedure(hWnd, iMessage, wParam, lParam);
449             } else {
450                 return DefWindowProc(hWnd, iMessage, wParam, lParam);
451             }
452         } catch (Exception e) {
453             assert(false, "Exception caught in WndProc");
454         }
455     }
456 
457     mixin template NativeScreenPainterImplementation() {
458         HDC hdc;
459         HWND hwnd;
460         HDC windowHdc;
461         HBITMAP oldBmp;
462 
463         void create(NativeWindowHandle window) {
464             auto buffer = this.window.impl.buffer;
465             hwnd = window;
466             windowHdc = GetDC(hwnd);
467 
468             hdc = CreateCompatibleDC(windowHdc);
469             oldBmp = SelectObject(hdc, buffer);
470 
471             // X doesn't draw a text background, so neither should we
472             SetBkMode(hdc, TRANSPARENT);
473         }
474 
475         // just because we can on Windows...
476         //void create(Image image);
477 
478         void dispose() {
479             // FIXME: this.window.width/height is probably wrong
480             BitBlt(windowHdc, 0, 0, this.window.width, this.window.height, hdc, 0, 0, SRCCOPY);
481 
482             ReleaseDC(hwnd, windowHdc);
483 
484             if(originalPen !is null)
485                 SelectObject(hdc, originalPen);
486             if(currentPen !is null)
487                 DeleteObject(currentPen);
488             if(originalBrush !is null)
489                 SelectObject(hdc, originalBrush);
490             if(currentBrush !is null)
491                 DeleteObject(currentBrush);
492 
493             SelectObject(hdc, oldBmp);
494 
495             DeleteDC(hdc);
496         }
497 
498         HPEN originalPen;
499         HPEN currentPen;
500 
501         Color _foreground;
502         @property void outlineColor(Color c) {
503             _foreground = c;
504             HPEN pen;
505             if(c.a == 0) {
506                 pen = GetStockObject(NULL_PEN);
507             } else {
508                 pen = CreatePen(PS_SOLID, 1, RGB(c.r, c.g, c.b));
509             }
510             auto orig = SelectObject(hdc, pen);
511             if(originalPen is null)
512                 originalPen = orig;
513 
514             if(currentPen !is null)
515                 DeleteObject(currentPen);
516 
517             currentPen = pen;
518 
519             // the outline is like a foreground since it's done that way on X
520             SetTextColor(hdc, RGB(c.r, c.g, c.b));
521         }
522 
523         HBRUSH originalBrush;
524         HBRUSH currentBrush;
525         @property void fillColor(Color c) {
526             HBRUSH brush;
527             if(c.a == 0) {
528                 brush = GetStockObject(HOLLOW_BRUSH);
529             } else {
530                 brush = CreateSolidBrush(RGB(c.r, c.g, c.b));
531             }
532             auto orig = SelectObject(hdc, brush);
533             if(originalBrush is null)
534                 originalBrush = orig;
535 
536             if(currentBrush !is null)
537                 DeleteObject(currentBrush);
538 
539             currentBrush = brush;
540 
541             // background color is NOT set because X doesn't draw text backgrounds
542             //   SetBkColor(hdc, RGB(255, 255, 255));
543         }
544 
545         void drawImage(int x, int y, Image i) {
546             BITMAP bm;
547 
548             HDC hdcMem = CreateCompatibleDC(hdc);
549             HBITMAP hbmOld = SelectObject(hdcMem, i.handle);
550 
551             GetObject(i.handle, bm.sizeof, &bm);
552 
553             BitBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
554 
555             SelectObject(hdcMem, hbmOld);
556             DeleteDC(hdcMem);
557         }
558 
559         void drawText(int x, int y, int x2, int y2, string text) {
560             /*
561             RECT rect;
562             rect.left = x;
563             rect.top = y;
564             rect.right = x2;
565             rect.bottom = y2;
566 
567             DrawText(hdc, text.ptr, text.length, &rect, DT_LEFT);
568             */
569 
570             TextOut(hdc, x, y, text.ptr, text.length);
571         }
572 
573         void drawPixel(int x, int y) {
574             SetPixel(hdc, x, y, RGB(_foreground.r, _foreground.g, _foreground.b));
575         }
576 
577         // The basic shapes, outlined
578 
579         void drawLine(int x1, int y1, int x2, int y2) {
580             MoveToEx(hdc, x1, y1, null);
581             LineTo(hdc, x2, y2);
582         }
583 
584         void drawRectangle(int x, int y, int width, int height) {
585             Rectangle(hdc, x, y, x + width, y + height);
586         }
587 
588         /// Arguments are the points of the bounding rectangle
589         void drawEllipse(int x1, int y1, int x2, int y2) {
590             Ellipse(hdc, x1, y1, x2, y2);
591         }
592 
593         void drawArc(int x1, int y1, int width, int height, int start, int finish) {
594             // FIXME: start X, start Y, end X, end Y
595             Arc(hdc, x1, y1, x1 + width, y1 + height, 0, 0, 0, 0);
596         }
597 
598         void drawPolygon(Point[] vertexes) {
599             POINT[] points;
600             points.length = vertexes.length;
601 
602             foreach(i, p; vertexes) {
603                 points[i].x = p.x;
604                 points[i].y = p.y;
605             }
606 
607             Polygon(hdc, points.ptr, points.length);
608         }
609     }
610 
611 
612     // Mix this into the SimpleWindow class
613     mixin template NativeSimpleWindowImplementation() {
614         ScreenPainter getPainter() {
615             return ScreenPainter(this, hwnd);
616         }
617 
618         HBITMAP buffer;
619 
620         void createWindow(int width, int height, string title) {
621             const char* cn = "DSimpleWindow";
622 
623             HINSTANCE hInstance = cast(HINSTANCE) GetModuleHandle(null);
624 
625             WNDCLASS wc;
626 
627             wc.cbClsExtra = 0;
628             wc.cbWndExtra = 0;
629             wc.hbrBackground = cast(HBRUSH) GetStockObject(WHITE_BRUSH);
630             wc.hCursor = LoadCursor(null, IDC_ARROW);
631             wc.hIcon = LoadIcon(hInstance, null);
632             wc.hInstance = hInstance;
633             wc.lpfnWndProc = &WndProc;
634             wc.lpszClassName = cn;
635             wc.style = CS_HREDRAW | CS_VREDRAW;
636             if(!RegisterClass(&wc))
637                 throw new Exception("RegisterClass");
638 
639             hwnd = CreateWindow(cn, toStringz(title), WS_OVERLAPPEDWINDOW,
640                 CW_USEDEFAULT, CW_USEDEFAULT, width, height,
641                 null, null, hInstance, null);
642 
643             windowObjects[hwnd] = this;
644 
645             HDC hdc = GetDC(hwnd);
646             buffer = CreateCompatibleBitmap(hdc, width, height);
647 
648             auto hdcBmp = CreateCompatibleDC(hdc);
649             // make sure it's filled with a blank slate
650             auto oldBmp = SelectObject(hdcBmp, buffer);
651             auto oldBrush = SelectObject(hdcBmp, GetStockObject(WHITE_BRUSH));
652             Rectangle(hdcBmp, 0, 0, width, height);
653             SelectObject(hdcBmp, oldBmp);
654             SelectObject(hdcBmp, oldBrush);
655             DeleteDC(hdcBmp);
656 
657             ReleaseDC(hwnd, hdc);
658 
659             // We want the window's client area to match the image size
660             RECT rcClient, rcWindow;
661             POINT ptDiff;
662             GetClientRect(hwnd, &rcClient);
663             GetWindowRect(hwnd, &rcWindow);
664             ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right;
665             ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom;
666             MoveWindow(hwnd,rcWindow.left, rcWindow.top, width + ptDiff.x, height + ptDiff.y, true);
667 
668             ShowWindow(hwnd, SW_SHOWNORMAL);
669         }
670 
671 
672         void dispose() {
673             DeleteObject(buffer);
674         }
675 
676         void closeWindow() {
677             DestroyWindow(hwnd);
678         }
679 
680         HWND hwnd;
681 
682         // the extern(Windows) wndproc should just forward to this
683         int windowProcedure(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam) {
684             assert(hwnd is this.hwnd);
685 
686             MouseEvent mouse;
687             switch(msg) {
688                 case WM_CHAR:
689                     wchar c = cast(wchar) wParam;
690                     if(handleCharEvent)
691                         handleCharEvent(cast(dchar) c);
692                 break;
693                 case WM_MOUSEMOVE:
694 
695                 case WM_LBUTTONDOWN:
696                 case WM_LBUTTONUP:
697                 case WM_LBUTTONDBLCLK:
698 
699                 case WM_RBUTTONDOWN:
700                 case WM_RBUTTONUP:
701                 case WM_RBUTTONDBLCLK:
702 
703                 case WM_MBUTTONDOWN:
704                 case WM_MBUTTONUP:
705                 case WM_MBUTTONDBLCLK:
706                     mouse.type = 0;
707                     mouse.x = LOWORD(lParam);
708                     mouse.y = HIWORD(lParam);
709                     mouse.buttonFlags = wParam;
710 
711                     if(handleMouseEvent)
712                         handleMouseEvent(mouse);
713                 break;
714                 case WM_KEYDOWN:
715                     if(handleKeyEvent)
716                         handleKeyEvent(wParam);
717                 break;
718                 case WM_CLOSE:
719                 case WM_DESTROY:
720                     PostQuitMessage(0);
721                 break;
722                 case WM_PAINT: {
723                     BITMAP bm;
724                     PAINTSTRUCT ps;
725 
726                     HDC hdc = BeginPaint(hwnd, &ps);
727 
728 /*
729                     if(backingImage !is null) {
730                         HDC hdcMem = CreateCompatibleDC(hdc);
731                         HBITMAP hbmOld = SelectObject(hdcMem, backingImage.handle);
732 
733                         GetObject(backingImage.handle, bm.sizeof, &bm);
734 
735                         BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
736 
737                         SelectObject(hdcMem, hbmOld);
738                         DeleteDC(hdcMem);
739                     }
740 */
741                     HDC hdcMem = CreateCompatibleDC(hdc);
742                     HBITMAP hbmOld = SelectObject(hdcMem, buffer);
743 
744                     GetObject(buffer, bm.sizeof, &bm);
745 
746                     BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
747 
748                     SelectObject(hdcMem, hbmOld);
749                     DeleteDC(hdcMem);
750 
751 
752                     EndPaint(hwnd, &ps);
753                 } break;
754                   default:
755                     return DefWindowProc(hwnd, msg, wParam, lParam);
756             }
757              return 0;
758 
759         }
760 
761         int eventLoop(long pulseTimeout) {
762             MSG message;
763             int ret;
764 
765             if(pulseTimeout) {
766                 bool done = false;
767                 while(!done) {
768                     while(!done && PeekMessage(&message, hwnd, 0, 0, PM_NOREMOVE)) {
769                         ret = GetMessage(&message, hwnd, 0, 0);
770                         if(ret == 0)
771                             done = true;
772 
773                         TranslateMessage(&message);
774                         DispatchMessage(&message);
775                     }
776 
777                     if(!done && handlePulse !is null)
778                         handlePulse();
779                     Thread.sleep(dur!"msecs"(pulseTimeout));
780                 }
781             } else {
782                 while((ret = GetMessage(&message, hwnd, 0, 0)) != 0) {
783                     if(ret == -1)
784                         throw new Exception("GetMessage failed");
785                     TranslateMessage(&message);
786                     DispatchMessage(&message);
787                 }
788             }
789 
790             return message.wParam;
791         }
792     }
793 
794     mixin template NativeImageImplementation() {
795         HBITMAP handle;
796         byte* rawData;
797 
798         void setPixel(int x, int y, Color c) {
799             auto itemsPerLine = ((cast(int) width * 3 + 3) / 4) * 4;
800             // remember, bmps are upside down
801             auto offset = itemsPerLine * (height - y - 1) + x * 3;
802 
803             rawData[offset + 0] = c.b;
804             rawData[offset + 1] = c.g;
805             rawData[offset + 2] = c.r;
806         }
807 
808         void createImage(int width, int height) {
809             BITMAPINFO infoheader;
810             infoheader.bmiHeader.biSize = infoheader.bmiHeader.sizeof;
811             infoheader.bmiHeader.biWidth = width;
812             infoheader.bmiHeader.biHeight = height;
813             infoheader.bmiHeader.biPlanes = 1;
814             infoheader.bmiHeader.biBitCount = 24;
815             infoheader.bmiHeader.biCompression = BI_RGB;
816 
817             handle = enforce(CreateDIBSection(
818                 null,
819                 &infoheader,
820                 DIB_RGB_COLORS,
821                 cast(void**) &rawData,
822                 null,
823                 0));
824 
825         }
826 
827         void dispose() {
828             DeleteObject(handle);
829         }
830     }
831 
832     enum KEY_ESCAPE = 27;
833 }
834 version(X11) {
835 
836     alias void delegate(XEvent) NativeEventHandler;
837     alias Window NativeWindowHandle;
838 
839     enum KEY_ESCAPE = 9;
840     import core.stdc.stdlib;
841 
842     mixin template NativeScreenPainterImplementation() {
843         Display* display;
844         Drawable d;
845         Drawable destiny;
846         GC gc;
847 
848         void create(NativeWindowHandle window) {
849             this.display = XDisplayConnection.get();
850 
851                 auto buffer = this.window.impl.buffer;
852 
853             this.d = cast(Drawable) buffer;
854             this.destiny = cast(Drawable) window;
855 
856             auto dgc = DefaultGC(display, DefaultScreen(display));
857 
858             this.gc = XCreateGC(display, d, 0, null);
859 
860             XCopyGC(display, dgc, 0xffffffff, this.gc);
861 
862         }
863 
864         void dispose() {
865                 auto buffer = this.window.impl.buffer;
866 
867             // FIXME: this.window.width/height is probably wrong
868 
869             // src x,y     then dest x, y
870             XCopyArea(display, d, destiny, gc, 0, 0, this.window.width, this.window.height, 0, 0);
871 
872             XFreeGC(display, gc);
873         }
874 
875         bool backgroundIsNotTransparent = true;
876         bool foregroundIsNotTransparent = true;
877 
878         Color _outlineColor;
879         Color _fillColor;
880 
881         @property void outlineColor(Color c) {
882             _outlineColor = c;
883             if(c.a == 0) {
884                 foregroundIsNotTransparent = false;
885                 return;
886             }
887 
888             foregroundIsNotTransparent = true;
889 
890             XSetForeground(display, gc,
891                 cast(uint) c.r << 16 |
892                 cast(uint) c.g << 8 |
893                 cast(uint) c.b);
894         }
895 
896         @property void fillColor(Color c) {
897             _fillColor = c;
898             if(c.a == 0) {
899                 backgroundIsNotTransparent = false;
900                 return;
901             }
902 
903             backgroundIsNotTransparent = true;
904 
905             XSetBackground(display, gc,
906                 cast(uint) c.r << 16 |
907                 cast(uint) c.g << 8 |
908                 cast(uint) c.b);
909 
910         }
911 
912         void swapColors() {
913             auto tmp = _fillColor;
914             fillColor = _outlineColor;
915             outlineColor = tmp;
916         }
917 
918         void drawImage(int x, int y, Image i) {
919             // source x, source y
920             XPutImage(display, d, gc, i.handle, 0, 0, x, y, i.width, i.height);
921         }
922 
923         void drawText(int x, int y, int x2, int y2, string text) {
924             foreach(line; text.split("\n")) {
925                 XDrawString(display, d, gc, x, y + 12, line.ptr, cast(int) line.length);
926                 y += 16;
927             }
928         }
929 
930         void drawPixel(int x, int y) {
931             XDrawPoint(display, d, gc, x, y);
932         }
933 
934         // The basic shapes, outlined
935 
936         void drawLine(int x1, int y1, int x2, int y2) {
937             if(foregroundIsNotTransparent)
938                 XDrawLine(display, d, gc, x1, y1, x2, y2);
939         }
940 
941         void drawRectangle(int x, int y, int width, int height) {
942             if(backgroundIsNotTransparent) {
943                 swapColors();
944                 XFillRectangle(display, d, gc, x, y, width, height);
945                 swapColors();
946             }
947             if(foregroundIsNotTransparent)
948                 XDrawRectangle(display, d, gc, x, y, width, height);
949         }
950 
951         /// Arguments are the points of the bounding rectangle
952         void drawEllipse(int x1, int y1, int x2, int y2) {
953             drawArc(x1, y1, x2 - x1, y2 - y1, 0, 360 * 64);
954         }
955 
956         // NOTE: start and finish are in units of degrees * 64
957         void drawArc(int x1, int y1, int width, int height, int start, int finish) {
958             if(backgroundIsNotTransparent) {
959                 swapColors();
960                 XFillArc(display, d, gc, x1, y1, width, height, start, finish);
961                 swapColors();
962             }
963             if(foregroundIsNotTransparent)
964                 XDrawArc(display, d, gc, x1, y1, width, height, start, finish);
965         }
966 
967         void drawPolygon(Point[] vertexes) {
968             XPoint[] points;
969             points.length = vertexes.length;
970 
971             foreach(i, p; vertexes) {
972                 points[i].x = cast(short) p.x;
973                 points[i].y = cast(short) p.y;
974             }
975 
976             if(backgroundIsNotTransparent) {
977                 swapColors();
978                 XFillPolygon(display, d, gc, points.ptr, cast(int) points.length, PolygonShape.Complex, CoordMode.CoordModeOrigin);
979                 swapColors();
980             }
981             if(foregroundIsNotTransparent) {
982                 XDrawLines(display, d, gc, points.ptr, cast(int) points.length, CoordMode.CoordModeOrigin);
983             }
984         }
985     }
986 
987 
988     class XDisplayConnection {
989         private static Display* display;
990 
991         static Display* get() {
992             if(display is null)
993                 display = enforce(XOpenDisplay(null));
994 
995             return display;
996         }
997 
998         static void close() {
999             XCloseDisplay(display);
1000             display = null;
1001         }
1002     }
1003 
1004     mixin template NativeImageImplementation() {
1005         XImage* handle;
1006         byte* rawData;
1007 
1008         void createImage(int width, int height) {
1009             auto display = XDisplayConnection.get();
1010             auto screen = DefaultScreen(display);
1011 
1012             // This actually needs to be malloc to avoid a double free error when XDestroyImage is called
1013             rawData = cast(byte*) malloc(width * height * 4);
1014 
1015             handle = XCreateImage(
1016                 display,
1017                 DefaultVisual(display, screen),
1018                 24, // bpp
1019                 ImageFormat.ZPixmap,
1020                 0, // offset
1021                 rawData,
1022                 width, height,
1023                 8 /* FIXME */, 4 * width); // padding, bytes per line
1024         }
1025 
1026         void dispose() {
1027             XDestroyImage(handle);
1028         }
1029 
1030         /*
1031         Color getPixel(int x, int y) {
1032 
1033         }
1034         */
1035 
1036         void setPixel(int x, int y, Color c) {
1037             auto offset = (y * width + x) * 4;
1038             rawData[offset + 0] = c.b;
1039             rawData[offset + 1] = c.g;
1040             rawData[offset + 2] = c.r;
1041         }
1042     }
1043 
1044     mixin template NativeSimpleWindowImplementation() {
1045         GC gc;
1046         Window window;
1047         Display* display;
1048 
1049         Pixmap buffer;
1050 
1051         ScreenPainter getPainter() {
1052             return ScreenPainter(this, window);
1053         }
1054 
1055         void createWindow(int width, int height, string title) {
1056             display = XDisplayConnection.get();
1057             auto screen = DefaultScreen(display);
1058 
1059             window = XCreateSimpleWindow(
1060                 display,
1061                 RootWindow(display, screen),
1062                 0, 0, // x, y
1063                 width, height,
1064                 1, // border width
1065                 BlackPixel(display, screen), // border
1066                 WhitePixel(display, screen)); // background
1067 
1068             XTextProperty windowName;
1069             windowName.value = title.ptr;
1070             windowName.encoding = XA_STRING;
1071             windowName.format = 8;
1072             windowName.nitems = cast(uint) title.length;
1073 
1074             XSetWMName(display, window, &windowName);
1075 
1076             buffer = XCreatePixmap(display, cast(Drawable) window, width, height, 24);
1077 
1078             gc = DefaultGC(display, screen);
1079 
1080             //.destroy out the buffer to get us started...
1081             XSetForeground(display, gc, WhitePixel(display, screen));
1082             XFillRectangle(display, cast(Drawable) buffer, gc, 0, 0, width, height);
1083             XSetForeground(display, gc, BlackPixel(display, screen));
1084 
1085             // This gives our window a close button
1086             Atom atom = XInternAtom(display, "WM_DELETE_WINDOW".ptr, true); // FIXME: does this need to be freed?
1087             XSetWMProtocols(display, window, &atom, 1);
1088 
1089             XMapWindow(display, window);
1090 
1091             XSelectInput(display, window,
1092                 EventMask.ExposureMask |
1093                 EventMask.KeyPressMask |
1094                 EventMask.StructureNotifyMask
1095                 | EventMask.PointerMotionMask // FIXME: not efficient
1096                 | EventMask.ButtonPressMask
1097                 | EventMask.ButtonReleaseMask
1098             );
1099         }
1100 
1101         void closeWindow() {
1102             XFreePixmap(display, buffer);
1103             XDestroyWindow(display, window);
1104         }
1105 
1106         void dispose() {
1107         }
1108 
1109         bool destroyed = false;
1110 
1111         int eventLoop(long pulseTimeout) {
1112             XEvent e;
1113             bool done = false;
1114 
1115             while (!done) {
1116             while(!done &&
1117                 (pulseTimeout == 0 || (XPending(display) > 0)))
1118             {
1119                 XNextEvent(display, &e);
1120 
1121                 switch(e.type) {
1122                   case EventType.Expose:
1123                     //if(backingImage !is null)
1124                     //  XPutImage(display, cast(Drawable) window, gc, backingImage.handle, 0, 0, 0, 0, backingImage.width, backingImage.height);
1125                     XCopyArea(display, cast(Drawable) buffer, cast(Drawable) window, gc, 0, 0, width, height, 0, 0);
1126                   break;
1127                   case EventType.ClientMessage: // User clicked the close button
1128                   case EventType.DestroyNotify:
1129                     done = true;
1130                     destroyed = true;
1131                   break;
1132 
1133                   case EventType.MotionNotify:
1134                     MouseEvent mouse;
1135                     auto event = e.xmotion;
1136 
1137                     mouse.type = 0;
1138                     mouse.x = event.x;
1139                     mouse.y = event.y;
1140                     mouse.buttonFlags = event.state;
1141 
1142                     if(handleMouseEvent)
1143                         handleMouseEvent(mouse);
1144                   break;
1145                   case EventType.ButtonPress:
1146                   case EventType.ButtonRelease:
1147                     MouseEvent mouse;
1148                     auto event = e.xbutton;
1149 
1150                     mouse.type = e.type == EventType.ButtonPress ? 1 : 2;
1151                     mouse.x = event.x;
1152                     mouse.y = event.y;
1153                     mouse.button = event.button;
1154                     //mouse.buttonFlags = event.detail;
1155 
1156                     if(handleMouseEvent)
1157                         handleMouseEvent(mouse);
1158                   break;
1159 
1160                   case EventType.KeyPress:
1161                     if(handleCharEvent)
1162                         handleCharEvent(
1163                             XKeycodeToKeysym(
1164                                 XDisplayConnection.get(),
1165                                 e.xkey.keycode,
1166                                 0)); // FIXME: we should check shift, etc. too, so it matches Windows' behavior better
1167                     if(handleKeyEvent)
1168                         handleKeyEvent(e.xkey.keycode);
1169                   break;
1170                   default:
1171                 }
1172             }
1173                 if(!done && pulseTimeout !=0) {
1174                     if(handlePulse !is null)
1175                         handlePulse();
1176                     Thread.sleep(pulseTimeout * 10000);
1177                 }
1178             }
1179 
1180             return 0;
1181         }
1182     }
1183 }
1184 
1185 /* *************************************** */
1186 /*      Done with simpledisplay stuff      */
1187 /* *************************************** */
1188 
1189 // Necessary C library bindings follow
1190 
1191 version(Windows) {
1192     import core.sys.windows.windows;
1193 
1194     pragma(lib, "gdi32");
1195 
1196     extern(Windows) {
1197         // The included D headers are incomplete, finish them here
1198         // enough that this module works.
1199         alias GetObjectA GetObject;
1200         alias GetMessageA GetMessage;
1201         alias PeekMessageA PeekMessage;
1202         alias TextOutA TextOut;
1203         alias DispatchMessageA DispatchMessage;
1204         alias GetModuleHandleA GetModuleHandle;
1205         alias LoadCursorA LoadCursor;
1206         alias LoadIconA LoadIcon;
1207         alias RegisterClassA RegisterClass;
1208         alias CreateWindowA CreateWindow;
1209         alias DefWindowProcA DefWindowProc;
1210         alias DrawTextA DrawText;
1211 
1212         bool MoveWindow(HWND hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
1213         HBITMAP CreateDIBSection(HDC, const BITMAPINFO*, uint, void**, HANDLE hSection, DWORD);
1214         bool BitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop);
1215         bool DestroyWindow(HWND);
1216         int DrawTextA(HDC hDC, LPCTSTR lpchText, int nCount, LPRECT lpRect, UINT uFormat);
1217         bool Rectangle(HDC, int, int, int, int);
1218         bool Ellipse(HDC, int, int, int, int);
1219         bool Arc(HDC, int, int, int, int, int, int, int, int);
1220         bool Polygon(HDC, POINT*, int);
1221         HBRUSH CreateSolidBrush(COLORREF);
1222 
1223         HBITMAP CreateCompatibleBitmap(HDC, int, int);
1224 
1225         uint SetTimer(HWND, uint, uint, void*);
1226         bool KillTimer(HWND, uint);
1227 
1228 
1229         enum BI_RGB = 0;
1230         enum DIB_RGB_COLORS = 0;
1231         enum DT_LEFT = 0;
1232         enum TRANSPARENT = 1;
1233 
1234     }
1235 
1236 }
1237 
1238 else version(X11) {
1239 
1240 // X11 bindings needed here
1241 /*
1242     A little of this is from the bindings project on
1243     D Source and some of it is copy/paste from the C
1244     header.
1245 
1246     The DSource listing consistently used D's long
1247     where C used long. That's wrong - C long is 32 bit, so
1248     it should be int in D. I changed that here.
1249 
1250     Note:
1251     This isn't complete, just took what I needed for myself.
1252 */
1253 
1254 pragma(lib, "X11");
1255 
1256 extern(C):
1257 
1258 
1259 KeySym XKeycodeToKeysym(
1260     Display*        /* display */,
1261     KeyCode     /* keycode */,
1262     int         /* index */
1263 );
1264 
1265 Display* XOpenDisplay(const char*);
1266 int XCloseDisplay(Display*);
1267 
1268 
1269 enum MappingType:int {
1270     MappingModifier     =0,
1271     MappingKeyboard     =1,
1272     MappingPointer      =2
1273 }
1274 
1275 /* ImageFormat -- PutImage, GetImage */
1276 enum ImageFormat:int {
1277     XYBitmap    =0, /* depth 1, XYFormat */
1278     XYPixmap    =1, /* depth == drawable depth */
1279     ZPixmap =2  /* depth == drawable depth */
1280 }
1281 
1282 enum ModifierName:int {
1283     ShiftMapIndex   =0,
1284     LockMapIndex    =1,
1285     ControlMapIndex =2,
1286     Mod1MapIndex    =3,
1287     Mod2MapIndex    =4,
1288     Mod3MapIndex    =5,
1289     Mod4MapIndex    =6,
1290     Mod5MapIndex    =7
1291 }
1292 
1293 enum ButtonMask:int {
1294     Button1Mask =1<<8,
1295     Button2Mask =1<<9,
1296     Button3Mask =1<<10,
1297     Button4Mask =1<<11,
1298     Button5Mask =1<<12,
1299     AnyModifier =1<<15/* used in GrabButton, GrabKey */
1300 }
1301 
1302 enum KeyOrButtonMask:uint {
1303     ShiftMask   =1<<0,
1304     LockMask    =1<<1,
1305     ControlMask =1<<2,
1306     Mod1Mask    =1<<3,
1307     Mod2Mask    =1<<4,
1308     Mod3Mask    =1<<5,
1309     Mod4Mask    =1<<6,
1310     Mod5Mask    =1<<7,
1311     Button1Mask =1<<8,
1312     Button2Mask =1<<9,
1313     Button3Mask =1<<10,
1314     Button4Mask =1<<11,
1315     Button5Mask =1<<12,
1316     AnyModifier =1<<15/* used in GrabButton, GrabKey */
1317 }
1318 
1319 enum ButtonName:int {
1320     Button1 =1,
1321     Button2 =2,
1322     Button3 =3,
1323     Button4 =4,
1324     Button5 =5
1325 }
1326 
1327 /* Notify modes */
1328 enum NotifyModes:int
1329 {
1330     NotifyNormal        =0,
1331     NotifyGrab          =1,
1332     NotifyUngrab        =2,
1333     NotifyWhileGrabbed  =3
1334 }
1335 const int NotifyHint    =1; /* for MotionNotify events */
1336 
1337 /* Notify detail */
1338 enum NotifyDetail:int
1339 {
1340     NotifyAncestor          =0,
1341     NotifyVirtual           =1,
1342     NotifyInferior          =2,
1343     NotifyNonlinear         =3,
1344     NotifyNonlinearVirtual  =4,
1345     NotifyPointer           =5,
1346     NotifyPointerRoot       =6,
1347     NotifyDetailNone        =7
1348 }
1349 
1350 /* Visibility notify */
1351 
1352 enum VisibilityNotify:int
1353 {
1354 VisibilityUnobscured        =0,
1355 VisibilityPartiallyObscured =1,
1356 VisibilityFullyObscured     =2
1357 }
1358 
1359 
1360 enum WindowStackingMethod:int
1361 {
1362     Above       =0,
1363     Below       =1,
1364     TopIf       =2,
1365     BottomIf    =3,
1366     Opposite    =4
1367 }
1368 
1369 /* Circulation request */
1370 enum CirculationRequest:int
1371 {
1372     PlaceOnTop      =0,
1373     PlaceOnBottom   =1
1374 }
1375 
1376 enum PropertyNotification:int
1377 {
1378     PropertyNewValue    =0,
1379     PropertyDelete      =1
1380 }
1381 
1382 enum ColorMapNotification:int
1383 {
1384     ColormapUninstalled =0,
1385     ColormapInstalled       =1
1386 }
1387 
1388 
1389     struct _XPrivate {}
1390     struct _XrmHashBucketRec {}
1391 
1392     alias void* XPointer;
1393     alias void* XExtData;
1394 
1395     alias uint XID;
1396 
1397     alias XID Window;
1398     alias XID Drawable;
1399     alias XID Pixmap;
1400 
1401     alias uint Atom;
1402     alias bool Bool;
1403     alias Display XDisplay;
1404 
1405     alias int ByteOrder;
1406     alias uint Time;
1407     alias void ScreenFormat;
1408 
1409     struct XImage {
1410         int width, height;          /* size of image */
1411         int xoffset;                /* number of pixels offset in X direction */
1412         ImageFormat format;     /* XYBitmap, XYPixmap, ZPixmap */
1413         void *data;                 /* pointer to image data */
1414         ByteOrder byte_order;       /* data byte order, LSBFirst, MSBFirst */
1415         int bitmap_unit;            /* quant. of scanline 8, 16, 32 */
1416         int bitmap_bit_order;       /* LSBFirst, MSBFirst */
1417         int bitmap_pad;         /* 8, 16, 32 either XY or ZPixmap */
1418         int depth;                  /* depth of image */
1419         int bytes_per_line;         /* accelarator to next line */
1420         int bits_per_pixel;         /* bits per pixel (ZPixmap) */
1421         uint red_mask;  /* bits in z arrangment */
1422         uint green_mask;
1423         uint blue_mask;
1424         XPointer obdata;            /* hook for the object routines to hang on */
1425         struct f {              /* image manipulation routines */
1426             XImage* function(
1427                 XDisplay*           /* display */,
1428                 Visual*             /* visual */,
1429                 uint                /* depth */,
1430                 int                 /* format */,
1431                 int                 /* offset */,
1432                 byte*               /* data */,
1433                 uint                /* width */,
1434                 uint                /* height */,
1435                 int                 /* bitmap_pad */,
1436                 int                 /* bytes_per_line */) create_image;
1437             int  function(XImage *)destroy_image;
1438             uint function(XImage *, int, int)get_pixel;
1439             int  function(XImage *, int, int, uint)put_pixel;
1440             XImage function(XImage *, int, int, uint, uint)sub_image;
1441             int function(XImage *, int)add_pixel;
1442         }
1443     }
1444 
1445 
1446 
1447 /*
1448  * Definitions of specific events.
1449  */
1450 struct XKeyEvent
1451 {
1452     int type;           /* of event */
1453     uint serial;        /* # of last request processed by server */
1454     Bool send_event;    /* true if this came from a SendEvent request */
1455     Display *display;   /* Display the event was read from */
1456     Window window;          /* "event" window it is reported relative to */
1457     Window root;            /* root window that the event occurred on */
1458     Window subwindow;   /* child window */
1459     Time time;      /* milliseconds */
1460     int x, y;       /* pointer x, y coordinates in event window */
1461     int x_root, y_root; /* coordinates relative to root */
1462     KeyOrButtonMask state;  /* key or button mask */
1463     uint keycode;   /* detail */
1464     Bool same_screen;   /* same screen flag */
1465 }
1466 alias XKeyEvent XKeyPressedEvent;
1467 alias XKeyEvent XKeyReleasedEvent;
1468 
1469 struct XButtonEvent
1470 {
1471     int type;       /* of event */
1472     uint serial;    /* # of last request processed by server */
1473     Bool send_event;    /* true if this came from a SendEvent request */
1474     Display *display;   /* Display the event was read from */
1475     Window window;          /* "event" window it is reported relative to */
1476     Window root;            /* root window that the event occurred on */
1477     Window subwindow;   /* child window */
1478     Time time;      /* milliseconds */
1479     int x, y;       /* pointer x, y coordinates in event window */
1480     int x_root, y_root; /* coordinates relative to root */
1481     KeyOrButtonMask state;  /* key or button mask */
1482     uint button;    /* detail */
1483     Bool same_screen;   /* same screen flag */
1484 }
1485 alias XButtonEvent XButtonPressedEvent;
1486 alias XButtonEvent XButtonReleasedEvent;
1487 
1488 struct XMotionEvent{
1489     int type;       /* of event */
1490     uint serial;    /* # of last request processed by server */
1491     Bool send_event;    /* true if this came from a SendEvent request */
1492     Display *display;   /* Display the event was read from */
1493     Window window;          /* "event" window reported relative to */
1494     Window root;            /* root window that the event occurred on */
1495     Window subwindow;   /* child window */
1496     Time time;      /* milliseconds */
1497     int x, y;       /* pointer x, y coordinates in event window */
1498     int x_root, y_root; /* coordinates relative to root */
1499     KeyOrButtonMask state;  /* key or button mask */
1500     byte is_hint;       /* detail */
1501     Bool same_screen;   /* same screen flag */
1502 }
1503 alias XMotionEvent XPointerMovedEvent;
1504 
1505 struct XCrossingEvent{
1506     int type;       /* of event */
1507     uint serial;    /* # of last request processed by server */
1508     Bool send_event;    /* true if this came from a SendEvent request */
1509     Display *display;   /* Display the event was read from */
1510     Window window;          /* "event" window reported relative to */
1511     Window root;            /* root window that the event occurred on */
1512     Window subwindow;   /* child window */
1513     Time time;      /* milliseconds */
1514     int x, y;       /* pointer x, y coordinates in event window */
1515     int x_root, y_root; /* coordinates relative to root */
1516     NotifyModes mode;       /* NotifyNormal, NotifyGrab, NotifyUngrab */
1517     NotifyDetail detail;
1518     /*
1519      * NotifyAncestor, NotifyVirtual, NotifyInferior,
1520      * NotifyNonlinear,NotifyNonlinearVirtual
1521      */
1522     Bool same_screen;   /* same screen flag */
1523     Bool focus;     /* Boolean focus */
1524     KeyOrButtonMask state;  /* key or button mask */
1525 }
1526 alias XCrossingEvent XEnterWindowEvent;
1527 alias XCrossingEvent XLeaveWindowEvent;
1528 
1529 struct XFocusChangeEvent{
1530     int type;       /* FocusIn or FocusOut */
1531     uint serial;    /* # of last request processed by server */
1532     Bool send_event;    /* true if this came from a SendEvent request */
1533     Display *display;   /* Display the event was read from */
1534     Window window;      /* window of event */
1535     NotifyModes mode;       /* NotifyNormal, NotifyWhileGrabbed,
1536                    NotifyGrab, NotifyUngrab */
1537     NotifyDetail detail;
1538     /*
1539      * NotifyAncestor, NotifyVirtual, NotifyInferior,
1540      * NotifyNonlinear,NotifyNonlinearVirtual, NotifyPointer,
1541      * NotifyPointerRoot, NotifyDetailNone
1542      */
1543 }
1544 alias XFocusChangeEvent XFocusInEvent;
1545 alias XFocusChangeEvent XFocusOutEvent;
1546 Window XCreateSimpleWindow(
1547     Display*    /* display */,
1548     Window      /* parent */,
1549     int         /* x */,
1550     int         /* y */,
1551     uint        /* width */,
1552     uint        /* height */,
1553     uint        /* border_width */,
1554     uint        /* border */,
1555     uint        /* background */
1556 );
1557 
1558 XImage *XCreateImage(
1559     Display*        /* display */,
1560     Visual*     /* visual */,
1561     uint    /* depth */,
1562     int         /* format */,
1563     int         /* offset */,
1564     byte*       /* data */,
1565     uint    /* width */,
1566     uint    /* height */,
1567     int         /* bitmap_pad */,
1568     int         /* bytes_per_line */
1569 );
1570 
1571 Atom XInternAtom(
1572     Display*        /* display */,
1573     const char* /* atom_name */,
1574     Bool        /* only_if_exists */
1575 );
1576 
1577 alias int Status;
1578 
1579 
1580 enum EventMask:int
1581 {
1582     NoEventMask             =0,
1583     KeyPressMask            =1<<0,
1584     KeyReleaseMask          =1<<1,
1585     ButtonPressMask         =1<<2,
1586     ButtonReleaseMask       =1<<3,
1587     EnterWindowMask         =1<<4,
1588     LeaveWindowMask         =1<<5,
1589     PointerMotionMask       =1<<6,
1590     PointerMotionHintMask   =1<<7,
1591     Button1MotionMask       =1<<8,
1592     Button2MotionMask       =1<<9,
1593     Button3MotionMask       =1<<10,
1594     Button4MotionMask       =1<<11,
1595     Button5MotionMask       =1<<12,
1596     ButtonMotionMask        =1<<13,
1597     KeymapStateMask     =1<<14,
1598     ExposureMask            =1<<15,
1599     VisibilityChangeMask    =1<<16,
1600     StructureNotifyMask     =1<<17,
1601     ResizeRedirectMask      =1<<18,
1602     SubstructureNotifyMask  =1<<19,
1603     SubstructureRedirectMask=1<<20,
1604     FocusChangeMask         =1<<21,
1605     PropertyChangeMask      =1<<22,
1606     ColormapChangeMask      =1<<23,
1607     OwnerGrabButtonMask     =1<<24
1608 }
1609 
1610 int XPutImage(
1611     Display*    /* display */,
1612     Drawable    /* d */,
1613     GC          /* gc */,
1614     XImage* /* image */,
1615     int         /* src_x */,
1616     int         /* src_y */,
1617     int         /* dest_x */,
1618     int         /* dest_y */,
1619     uint        /* width */,
1620     uint        /* height */
1621 );
1622 
1623 int XDestroyWindow(
1624     Display*    /* display */,
1625     Window      /* w */
1626 );
1627 
1628 int XDestroyImage(
1629     XImage*);
1630 
1631 int XSelectInput(
1632     Display*    /* display */,
1633     Window      /* w */,
1634     EventMask   /* event_mask */
1635 );
1636 
1637 int XMapWindow(
1638     Display*    /* display */,
1639     Window      /* w */
1640 );
1641 
1642 int XNextEvent(
1643     Display*    /* display */,
1644     XEvent*     /* event_return */
1645 );
1646 
1647 Status XSetWMProtocols(
1648     Display*    /* display */,
1649     Window      /* w */,
1650     Atom*       /* protocols */,
1651     int         /* count */
1652 );
1653 
1654 enum EventType:int
1655 {
1656     KeyPress            =2,
1657     KeyRelease          =3,
1658     ButtonPress         =4,
1659     ButtonRelease       =5,
1660     MotionNotify        =6,
1661     EnterNotify         =7,
1662     LeaveNotify         =8,
1663     FocusIn             =9,
1664     FocusOut            =10,
1665     KeymapNotify        =11,
1666     Expose              =12,
1667     GraphicsExpose      =13,
1668     NoExpose            =14,
1669     VisibilityNotify    =15,
1670     CreateNotify        =16,
1671     DestroyNotify       =17,
1672     UnmapNotify     =18,
1673     MapNotify           =19,
1674     MapRequest          =20,
1675     ReparentNotify      =21,
1676     ConfigureNotify     =22,
1677     ConfigureRequest    =23,
1678     GravityNotify       =24,
1679     ResizeRequest       =25,
1680     CirculateNotify     =26,
1681     CirculateRequest    =27,
1682     PropertyNotify      =28,
1683     Selectio.destroy        =29,
1684     SelectionRequest    =30,
1685     SelectionNotify     =31,
1686     ColormapNotify      =32,
1687     ClientMessage       =33,
1688     MappingNotify       =34,
1689     LASTEvent           =35 /* must be bigger than any event # */
1690 }
1691 /* generated on EnterWindow and FocusIn  when KeyMapState selected */
1692 struct XKeymapEvent
1693 {
1694     int type;
1695     uint serial;    /* # of last request processed by server */
1696     Bool send_event;    /* true if this came from a SendEvent request */
1697     Display *display;   /* Display the event was read from */
1698     Window window;
1699     byte key_vector[32];
1700 }
1701 
1702 struct XExposeEvent
1703 {
1704     int type;
1705     uint serial;    /* # of last request processed by server */
1706     Bool send_event;    /* true if this came from a SendEvent request */
1707     Display *display;   /* Display the event was read from */
1708     Window window;
1709     int x, y;
1710     int width, height;
1711     int count;      /* if non-zero, at least this many more */
1712 }
1713 
1714 struct XGraphicsExposeEvent{
1715     int type;
1716     uint serial;    /* # of last request processed by server */
1717     Bool send_event;    /* true if this came from a SendEvent request */
1718     Display *display;   /* Display the event was read from */
1719     Drawable drawable;
1720     int x, y;
1721     int width, height;
1722     int count;      /* if non-zero, at least this many more */
1723     int major_code;     /* core is CopyArea or CopyPlane */
1724     int minor_code;     /* not defined in the core */
1725 }
1726 
1727 struct XNoExposeEvent{
1728     int type;
1729     uint serial;    /* # of last request processed by server */
1730     Bool send_event;    /* true if this came from a SendEvent request */
1731     Display *display;   /* Display the event was read from */
1732     Drawable drawable;
1733     int major_code;     /* core is CopyArea or CopyPlane */
1734     int minor_code;     /* not defined in the core */
1735 }
1736 
1737 struct XVisibilityEvent{
1738     int type;
1739     uint serial;    /* # of last request processed by server */
1740     Bool send_event;    /* true if this came from a SendEvent request */
1741     Display *display;   /* Display the event was read from */
1742     Window window;
1743     VisibilityNotify state;     /* Visibility state */
1744 }
1745 
1746 struct XCreateWindowEvent{
1747     int type;
1748     uint serial;    /* # of last request processed by server */
1749     Bool send_event;    /* true if this came from a SendEvent request */
1750     Display *display;   /* Display the event was read from */
1751     Window parent;      /* parent of the window */
1752     Window window;      /* window id of window created */
1753     int x, y;       /* window location */
1754     int width, height;  /* size of window */
1755     int border_width;   /* border width */
1756     Bool override_redirect; /* creation should be overridden */
1757 }
1758 
1759 struct XDestroyWindowEvent
1760 {
1761     int type;
1762     uint serial;        /* # of last request processed by server */
1763     Bool send_event;    /* true if this came from a SendEvent request */
1764     Display *display;   /* Display the event was read from */
1765     Window event;
1766     Window window;
1767 }
1768 
1769 struct XUnmapEvent
1770 {
1771     int type;
1772     uint serial;        /* # of last request processed by server */
1773     Bool send_event;    /* true if this came from a SendEvent request */
1774     Display *display;   /* Display the event was read from */
1775     Window event;
1776     Window window;
1777     Bool from_configure;
1778 }
1779 
1780 struct XMapEvent
1781 {
1782     int type;
1783     uint serial;        /* # of last request processed by server */
1784     Bool send_event;    /* true if this came from a SendEvent request */
1785     Display *display;   /* Display the event was read from */
1786     Window event;
1787     Window window;
1788     Bool override_redirect; /* Boolean, is override set... */
1789 }
1790 
1791 struct XMapRequestEvent
1792 {
1793     int type;
1794     uint serial;    /* # of last request processed by server */
1795     Bool send_event;    /* true if this came from a SendEvent request */
1796     Display *display;   /* Display the event was read from */
1797     Window parent;
1798     Window window;
1799 }
1800 
1801 struct XReparentEvent
1802 {
1803     int type;
1804     uint serial;    /* # of last request processed by server */
1805     Bool send_event;    /* true if this came from a SendEvent request */
1806     Display *display;   /* Display the event was read from */
1807     Window event;
1808     Window window;
1809     Window parent;
1810     int x, y;
1811     Bool override_redirect;
1812 }
1813 
1814 struct XConfigureEvent
1815 {
1816     int type;
1817     uint serial;    /* # of last request processed by server */
1818     Bool send_event;    /* true if this came from a SendEvent request */
1819     Display *display;   /* Display the event was read from */
1820     Window event;
1821     Window window;
1822     int x, y;
1823     int width, height;
1824     int border_width;
1825     Window above;
1826     Bool override_redirect;
1827 }
1828 
1829 struct XGravityEvent
1830 {
1831     int type;
1832     uint serial;    /* # of last request processed by server */
1833     Bool send_event;    /* true if this came from a SendEvent request */
1834     Display *display;   /* Display the event was read from */
1835     Window event;
1836     Window window;
1837     int x, y;
1838 }
1839 
1840 struct XResizeRequestEvent
1841 {
1842     int type;
1843     uint serial;    /* # of last request processed by server */
1844     Bool send_event;    /* true if this came from a SendEvent request */
1845     Display *display;   /* Display the event was read from */
1846     Window window;
1847     int width, height;
1848 }
1849 
1850 struct  XConfigureRequestEvent
1851 {
1852     int type;
1853     uint serial;    /* # of last request processed by server */
1854     Bool send_event;    /* true if this came from a SendEvent request */
1855     Display *display;   /* Display the event was read from */
1856     Window parent;
1857     Window window;
1858     int x, y;
1859     int width, height;
1860     int border_width;
1861     Window above;
1862     WindowStackingMethod detail;        /* Above, Below, TopIf, BottomIf, Opposite */
1863     uint value_mask;
1864 }
1865 
1866 struct XCirculateEvent
1867 {
1868     int type;
1869     uint serial;    /* # of last request processed by server */
1870     Bool send_event;    /* true if this came from a SendEvent request */
1871     Display *display;   /* Display the event was read from */
1872     Window event;
1873     Window window;
1874     CirculationRequest place;       /* PlaceOnTop, PlaceOnBottom */
1875 }
1876 
1877 struct XCirculateRequestEvent
1878 {
1879     int type;
1880     uint serial;    /* # of last request processed by server */
1881     Bool send_event;    /* true if this came from a SendEvent request */
1882     Display *display;   /* Display the event was read from */
1883     Window parent;
1884     Window window;
1885     CirculationRequest place;       /* PlaceOnTop, PlaceOnBottom */
1886 }
1887 
1888 struct XPropertyEvent
1889 {
1890     int type;
1891     uint serial;    /* # of last request processed by server */
1892     Bool send_event;    /* true if this came from a SendEvent request */
1893     Display *display;   /* Display the event was read from */
1894     Window window;
1895     Atom atom;
1896     Time time;
1897     PropertyNotification state;     /* NewValue, Deleted */
1898 }
1899 
1900 struct XSelectio.destroyEvent
1901 {
1902     int type;
1903     uint serial;    /* # of last request processed by server */
1904     Bool send_event;    /* true if this came from a SendEvent request */
1905     Display *display;   /* Display the event was read from */
1906     Window window;
1907     Atom selection;
1908     Time time;
1909 }
1910 
1911 struct XSelectionRequestEvent
1912 {
1913     int type;
1914     uint serial;    /* # of last request processed by server */
1915     Bool send_event;    /* true if this came from a SendEvent request */
1916     Display *display;   /* Display the event was read from */
1917     Window owner;
1918     Window requestor;
1919     Atom selection;
1920     Atom target;
1921     Atom property;
1922     Time time;
1923 }
1924 
1925 struct XSelectionEvent
1926 {
1927     int type;
1928     uint serial;    /* # of last request processed by server */
1929     Bool send_event;    /* true if this came from a SendEvent request */
1930     Display *display;   /* Display the event was read from */
1931     Window requestor;
1932     Atom selection;
1933     Atom target;
1934     Atom property;      /* ATOM or None */
1935     Time time;
1936 }
1937 
1938 struct XColormapEvent
1939 {
1940     int type;
1941     uint serial;    /* # of last request processed by server */
1942     Bool send_event;    /* true if this came from a SendEvent request */
1943     Display *display;   /* Display the event was read from */
1944     Window window;
1945     Colormap colormap;  /* COLORMAP or None */
1946     Bool new_;      /* C++ */
1947     ColorMapNotification state;     /* ColormapInstalled, ColormapUninstalled */
1948 }
1949 
1950 struct XClientMessageEvent
1951 {
1952     int type;
1953     uint serial;    /* # of last request processed by server */
1954     Bool send_event;    /* true if this came from a SendEvent request */
1955     Display *display;   /* Display the event was read from */
1956     Window window;
1957     Atom message_type;
1958     int format;
1959     union data{
1960         byte b[20];
1961         short s[10];
1962         int l[5];
1963         }
1964 }
1965 
1966 struct XMappingEvent
1967 {
1968     int type;
1969     uint serial;    /* # of last request processed by server */
1970     Bool send_event;    /* true if this came from a SendEvent request */
1971     Display *display;   /* Display the event was read from */
1972     Window window;      /* unused */
1973     MappingType request;        /* one of MappingModifier, MappingKeyboard,
1974                    MappingPointer */
1975     int first_keycode;  /* first keycode */
1976     int count;      /* defines range of change w. first_keycode*/
1977 }
1978 
1979 struct XErrorEvent
1980 {
1981     int type;
1982     Display *display;   /* Display the event was read from */
1983     XID resourceid;     /* resource id */
1984     uint serial;    /* serial number of failed request */
1985     uint error_code;    /* error code of failed request */
1986     ubyte request_code; /* Major op-code of failed request */
1987     ubyte minor_code;   /* Minor op-code of failed request */
1988 }
1989 
1990 struct XAnyEvent
1991 {
1992     int type;
1993     ubyte serial;   /* # of last request processed by server */
1994     Bool send_event;    /* true if this came from a SendEvent request */
1995     Display *display;/* Display the event was read from */
1996     Window window;  /* window on which event was requested in event mask */
1997 }
1998 
1999 union XEvent{
2000     int type;       /* must not be changed; first element */
2001     XAnyEvent xany;
2002     XKeyEvent xkey;
2003     XButtonEvent xbutton;
2004     XMotionEvent xmotion;
2005     XCrossingEvent xcrossing;
2006     XFocusChangeEvent xfocus;
2007     XExposeEvent xexpose;
2008     XGraphicsExposeEvent xgraphicsexpose;
2009     XNoExposeEvent xnoexpose;
2010     XVisibilityEvent xvisibility;
2011     XCreateWindowEvent xcreatewindow;
2012     XDestroyWindowEvent xdestroywindow;
2013     XUnmapEvent xunmap;
2014     XMapEvent xmap;
2015     XMapRequestEvent xmaprequest;
2016     XReparentEvent xreparent;
2017     XConfigureEvent xconfigure;
2018     XGravityEvent xgravity;
2019     XResizeRequestEvent xresizerequest;
2020     XConfigureRequestEvent xconfigurerequest;
2021     XCirculateEvent xcirculate;
2022     XCirculateRequestEvent xcirculaterequest;
2023     XPropertyEvent xproperty;
2024     XSelectio.destroyEvent xselectio.destroy;
2025     XSelectionRequestEvent xselectionrequest;
2026     XSelectionEvent xselection;
2027     XColormapEvent xcolormap;
2028     XClientMessageEvent xclient;
2029     XMappingEvent xmapping;
2030     XErrorEvent xerror;
2031     XKeymapEvent xkeymap;
2032     int pad[24];
2033 }
2034 
2035 
2036     struct Display {
2037         XExtData *ext_data; /* hook for extension to hang data */
2038         _XPrivate *private1;
2039         int fd;         /* Network socket. */
2040         int private2;
2041         int proto_major_version;/* major version of server's X protocol */
2042         int proto_minor_version;/* minor version of servers X protocol */
2043         char *vendor;       /* vendor of the server hardware */
2044             XID private3;
2045         XID private4;
2046         XID private5;
2047         int private6;
2048         XID function(Display*)resource_alloc;/* allocator function */
2049         ByteOrder byte_order;       /* screen byte order, LSBFirst, MSBFirst */
2050         int bitmap_unit;    /* padding and data requirements */
2051         int bitmap_pad;     /* padding requirements on bitmaps */
2052         ByteOrder bitmap_bit_order; /* LeastSignificant or MostSignificant */
2053         int nformats;       /* number of pixmap formats in list */
2054         ScreenFormat *pixmap_format;    /* pixmap format list */
2055         int private8;
2056         int release;        /* release of the server */
2057         _XPrivate *private9;
2058         _XPrivate *private10;
2059         int qlen;       /* Length of input event queue */
2060         uint last_request_read; /* seq number of last event read */
2061         uint request;   /* sequence number of last request. */
2062         XPointer private11;
2063         XPointer private12;
2064         XPointer private13;
2065         XPointer private14;
2066         uint max_request_size; /* maximum number 32 bit words in request*/
2067         _XrmHashBucketRec *db;
2068         int function  (Display*)private15;
2069         char *display_name; /* "host:display" string used on this connect*/
2070         int default_screen; /* default screen for operations */
2071         int nscreens;       /* number of screens on this server*/
2072         Screen *screens;    /* pointer to list of screens */
2073         uint motion_buffer; /* size of motion buffer */
2074         uint private16;
2075         int min_keycode;    /* minimum defined keycode */
2076         int max_keycode;    /* maximum defined keycode */
2077         XPointer private17;
2078         XPointer private18;
2079         int private19;
2080         byte *xdefaults;    /* contents of defaults from server */
2081         /* there is more to this structure, but it is private to Xlib */
2082     }
2083 
2084 struct Depth
2085 {
2086     int depth;      /* this depth (Z) of the depth */
2087     int nvisuals;       /* number of Visual types at this depth */
2088     Visual *visuals;    /* list of visuals possible at this depth */
2089 }
2090 
2091 alias void* GC;
2092 alias int VisualID;
2093 alias XID Colormap;
2094 alias XID KeySym;
2095 alias uint KeyCode;
2096 
2097 struct Screen{
2098     XExtData *ext_data;     /* hook for extension to hang data */
2099     Display *display;       /* back pointer to display structure */
2100     Window root;            /* Root window id. */
2101     int width, height;      /* width and height of screen */
2102     int mwidth, mheight;    /* width and height of  in millimeters */
2103     int ndepths;            /* number of depths possible */
2104     Depth *depths;          /* list of allowable depths on the screen */
2105     int root_depth;         /* bits per pixel */
2106     Visual *root_visual;    /* root visual */
2107     GC default_gc;          /* GC for the root root visual */
2108     Colormap cmap;          /* default color map */
2109     uint white_pixel;
2110     uint black_pixel;       /* White and Black pixel values */
2111     int max_maps, min_maps; /* max and min color maps */
2112     int backing_store;      /* Never, WhenMapped, Always */
2113     bool save_unders;
2114     int root_input_mask;    /* initial root input mask */
2115 }
2116 
2117 struct Visual
2118 {
2119     XExtData *ext_data; /* hook for extension to hang data */
2120     VisualID visualid;  /* visual id of this visual */
2121     int class_;         /* class of screen (monochrome, etc.) */
2122     uint red_mask, green_mask, blue_mask;   /* mask values */
2123     int bits_per_rgb;   /* log base 2 of distinct color values */
2124     int map_entries;    /* color map entries */
2125 }
2126 
2127     alias Display* _XPrivDisplay;
2128 
2129     Screen* ScreenOfDisplay(Display* dpy, int scr) {
2130         return (&(cast(_XPrivDisplay)dpy).screens[scr]);
2131     }
2132 
2133     Window  RootWindow(Display *dpy,int scr) {
2134         return ScreenOfDisplay(dpy,scr).root;
2135     }
2136 
2137     int DefaultScreen(Display *dpy) {
2138         return dpy.default_screen;
2139     }
2140 
2141     Visual* DefaultVisual(Display *dpy,int scr) {
2142         return ScreenOfDisplay(dpy,scr).root_visual;
2143     }
2144 
2145     GC DefaultGC(Display *dpy,int scr) {
2146         return ScreenOfDisplay(dpy,scr).default_gc;
2147     }
2148 
2149     uint BlackPixel(Display *dpy,int scr) {
2150         return ScreenOfDisplay(dpy,scr).black_pixel;
2151     }
2152 
2153     uint WhitePixel(Display *dpy,int scr) {
2154         return ScreenOfDisplay(dpy,scr).white_pixel;
2155     }
2156 
2157     int XDrawString(Display*, Drawable, GC, int, int, in char*, int);
2158     int XDrawLine(Display*, Drawable, GC, int, int, int, int);
2159     int XDrawRectangle(Display*, Drawable, GC, int, int, uint, uint);
2160     int XDrawArc(Display*, Drawable, GC, int, int, uint, uint, int, int);
2161     int XFillRectangle(Display*, Drawable, GC, int, int, uint, uint);
2162     int XFillArc(Display*, Drawable, GC, int, int, uint, uint, int, int);
2163     int XDrawPoint(Display*, Drawable, GC, int, int);
2164     int XSetForeground(Display*, GC, uint);
2165     int XSetBackground(Display*, GC, uint);
2166 
2167     GC XCreateGC(Display*, Drawable, uint, void*);
2168     int XCopyGC(Display*, GC, uint, GC);
2169     int XFreeGC(Display*, GC);
2170 
2171     bool XCheckWindowEvent(Display*, Window, int, XEvent*);
2172     bool XCheckMaskEvent(Display*, int, XEvent*);
2173 
2174     int XPending(Display*);
2175 
2176     Pixmap XCreatePixmap(Display*, Drawable, uint, uint, uint);
2177     int XFreePixmap(Display*, Pixmap);
2178     int XCopyArea(Display*, Drawable, Drawable, GC, int, int, uint, uint, int, int);
2179     int XFlush(Display*);
2180 
2181     struct XPoint {
2182         short x;
2183         short y;
2184     }
2185 
2186     int XDrawLines(Display*, Drawable, GC, XPoint*, int, CoordMode);
2187     int XFillPolygon(Display*, Drawable, GC, XPoint*, int, PolygonShape, CoordMode);
2188 
2189     enum CoordMode:int {
2190         CoordModeOrigin = 0,
2191         CoordModePrevious = 1
2192     }
2193 
2194     enum PolygonShape:int {
2195         Complex = 0,
2196         Nonconvex = 1,
2197         Convex = 2
2198     }
2199 
2200     struct XTextProperty {
2201         const(char)* value;     /* same as Property routines */
2202         Atom encoding;          /* prop type */
2203         int format;             /* prop data format: 8, 16, or 32 */
2204         uint nitems;        /* number of data items in value */
2205     }
2206 
2207     void XSetWMName(Display*, Window, XTextProperty*);
2208 
2209     enum Atom XA_STRING = 31;
2210 
2211 } else static assert(0, "Unsupported operating system");