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 clear() {
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 			// clear 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 	SelectionClear		=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 XSelectionClearEvent
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 	XSelectionClearEvent xselectionclear;
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");