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");