1 /++ 2 Implementation of cross-platform creation and management of a window. 3 4 Also, at the same time, it is possible to create a graphical context for the 5 window to be able to use hardware acceleration using a common open API - OpenGL. 6 7 Creating_a_window: 8 First of all, creating a window begins with allocating memory and setting 9 the input parameters: 10 --- 11 Window window = new Window(640, 480, "Example title"); 12 --- 13 14 Only input parameters are set in the constructor, this does not mean that the 15 window is ready for use. Here only the initial width, height and title of the 16 window are set. Other properties do not affect creation, everything is done 17 after the window is created. 18 19 The window is created by the $(LREF windowInitialize) function: 20 --- 21 windowInitialize(window, 100, 100); 22 ... 23 window.windowInitialize(100, 100); // UFCS 24 --- 25 26 Now, you can interact with the window or create a graphics context to access 27 hardware acceleration. To do this, again, allocate the mod memory for the 28 context collector and create a structure with a description of the 29 context properties: 30 --- 31 Context context = new Context(); 32 33 // We just set the parameters by color. Each color will weigh 8 bits. 34 GraphicsAttributes attributes = AttribBySizeOfTheColor!8; 35 context.setAttributes(attributes); 36 context.create(window); 37 38 // We set the current context to the window. 39 window.context = context; 40 --- 41 Now you will have access to hardware acceleration according to the attributes 42 you specified, what you can do next is load open graphics libraries and start 43 drawing primitives. To display primitives on the screen, 44 use the $(HREF window/IWindow.swapBuffers.html, IWindow.swapBuffers) function. 45 46 OS_specific_actions: 47 It may be that the built-in tools are not enough and you need, say, to change 48 some properties that other platforms cannot do. For this, each object has an 49 open $(B `handle`) field. Getting it is easy, however, be careful with what you do 50 with it. You can do such things that the interaction interface after your 51 manipulations will not be able to control it. To do this, it is enough not to 52 change the properties that can be controlled by the interaction interface. 53 54 Macros: 55 LREF = <a href="#$1">$1</a> 56 HREF = <a href="$1">$2</a> 57 PHOBREF = <a href="https://dlang.org/phobos/$1.html#$2">$2</a> 58 59 Authors: $(HREF https://github.com/TodNaz,TodNaz) 60 Copyright: Copyright (c) 2020 - 2021, TodNaz. 61 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT) 62 +/ 63 module tida.window; 64 65 enum ConfFindError = 66 "The required configuration for the specified graphic attributes was not found!"; 67 68 enum WithoutContext = 0; /// Without creating a graphical context. 69 enum WithContext = 1; /// With the creation of a graphical context. 70 71 /++ 72 Graphics attributes for creating a special graphics pipeline 73 (default parameters are indicated in the structure). 74 +/ 75 struct GraphicsAttributes 76 { 77 int redSize = 8; /// Red size 78 int greenSize = 8; /// Green size 79 int blueSize = 8; /// Blue size 80 int alphaSize = 8; /// Alpha channel size 81 int depthSize = 24; /// Depth size 82 int stencilSize = 8; /// Stencil size 83 int colorDepth = 32; /// Color depth 84 bool doubleBuffer = true; /// Double buffering 85 int glmajor = 3; /// GL major recomendet version. 86 int glminor = 0; /// GL minor recomendet version. 87 } 88 89 /++ 90 Automatic determination of the structure of graphic attributes by the total 91 size of the color unit. 92 93 Params: 94 colorSize = Color unit size. 95 +/ 96 template AttribBySizeOfTheColor(int colorSize) 97 { 98 enum AttribBySizeOfTheColor = GraphicsAttributes( colorSize, 99 colorSize, 100 colorSize, 101 colorSize); 102 } 103 104 /++ 105 Graphics context creation interface for hardware graphics acceleration. 106 107 With this technology, the context can be easily created with the given 108 attributes, and it is obligatory $(U after) the window is created. 109 110 Example: 111 --- 112 // Window creation code . . . 113 Context contex = new Context(); 114 context.setAttribute(attributes...); 115 context.create(window); 116 // The graphics context has been created! 117 --- 118 +/ 119 interface IContext 120 { 121 @safe: 122 /++ 123 Sets the input attributes for creating the graphics context. 124 At the same time, he must simultaneously give these attributes 125 unsparingly to the very object of the pixel description, 126 if such is possible. As a rule, this method is followed by the creation 127 of the context, but the function itself should not do this. 128 129 Params: 130 attributes = graphic context description attributes. 131 132 Throws: 133 $(PHOBREF object,Exception) if the graphics attributes did not fit the creation 134 of the context (see what parameters you could set, maybe inconsistent with 135 each other). 136 +/ 137 void setAttributes(GraphicsAttributes attributes); 138 139 /++ 140 Creates directly, a graphics context object for a specific platform, 141 based on the previously specified graphics context attributes. 142 143 Params: 144 window = Pointer to the window to create the graphics context. 145 146 Throws: 147 $(PHOBREF object,Exception) if the creation of the graphics context was 148 not successful. The attributes were probably not initialized. 149 +/ 150 void create(IWindow window); 151 152 /++ 153 Destroys the context. 154 +/ 155 void destroy(); 156 } 157 158 /++ 159 Window interaction interface. It does not provide its creation, it is created by 160 a separate function within the interface implementation, in particular 161 the `initialize` function. 162 +/ 163 interface IWindow 164 { 165 import tida.image; 166 167 @safe: 168 /// The position of the window in the plane of the desktop. 169 @property int x(); 170 171 /// The position of the window in the plane of the desktop. 172 @property int y(); 173 174 /// Window width 175 @property uint width(); 176 177 /// Window height 178 @property uint height(); 179 180 /// Window mode, namely whether windowed or full screen 181 @property void fullscreen(bool value); 182 183 /// Window mode, namely whether windowed or full screen 184 @property bool fullscreen(); 185 186 /// Whether the window can be resized by the user. 187 @property void resizable(bool value); 188 189 /// Whether the window can be resized by the user. 190 @property bool resizable(); 191 192 /// Frames around the window. 193 @property void border(bool value); 194 195 /// Frames around the window. 196 @property bool border(); 197 198 /// Window title. 199 @property void title(string value); 200 201 /// Window title. 202 @property string title(); 203 204 /// Whether the window is always on top of the others. 205 @property void alwaysOnTop(bool value); 206 207 /// Whether the window is always on top of the others. 208 @property bool alwaysOnTop(); 209 210 /// Dynamic window icon. 211 @property void icon(Image iconimage); 212 213 /// Grahphics context 214 @property void context(IContext ctx); 215 216 /// Grahphics context 217 @property IContext context(); 218 219 /++ 220 Window resizing function. 221 222 Params: 223 w = Window width. 224 h = Window height. 225 +/ 226 void resize(uint w, uint h); 227 228 /++ 229 Changes the position of the window in the plane of the desktop. 230 231 Params: 232 xposition = Position x-axis. 233 yposition = Position y-axis. 234 +/ 235 void move(int xposition, int yposition); 236 237 /++ 238 Shows a window in the plane of the desktop. 239 +/ 240 void show(); 241 242 /++ 243 Hide a window in the plane of the desktop. 244 (Can be tracked in the task manager.) 245 +/ 246 void hide(); 247 248 /++ 249 Swap two buffers. 250 +/ 251 void swapBuffers(); 252 253 /++ 254 Destroys the window and its associated data (not the structure itself, all values are reset to zero). 255 +/ 256 void destroy(); 257 } 258 259 version (Posix) 260 class Context : IContext 261 { 262 import tida.runtime; 263 import x11.X, x11.Xlib, x11.Xutil; 264 import dglx.glx; 265 266 private: 267 GLXContext _context; 268 XVisualInfo* visual; 269 GLXFBConfig bestFbcs; 270 271 public @trusted override: 272 void setAttributes(GraphicsAttributes attributes) 273 { 274 import std.exception : enforce; 275 import std.conv : to; 276 277 int[] glxAttributes = 278 [ 279 GLX_X_RENDERABLE , True, 280 GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, 281 GLX_RENDER_TYPE , GLX_RGBA_BIT, 282 GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, 283 GLX_RED_SIZE , attributes.redSize, 284 GLX_GREEN_SIZE , attributes.greenSize, 285 GLX_BLUE_SIZE , attributes.blueSize, 286 GLX_ALPHA_SIZE , attributes.alphaSize, 287 GLX_DEPTH_SIZE , attributes.depthSize, 288 GLX_STENCIL_SIZE , attributes.stencilSize, 289 GLX_DOUBLEBUFFER , attributes.doubleBuffer.to!int, 290 None 291 ]; 292 293 int fbcount = 0; 294 scope fbc = glXChooseFBConfig( runtime.display, runtime.displayID, 295 glxAttributes.ptr, &fbcount); 296 scope(success) XFree(fbc); 297 enforce!Exception(fbc, ConfFindError); 298 299 int bestFbc = -1, bestNum = -1; 300 foreach (int i; 0 .. fbcount) 301 { 302 int sampBuff, samples; 303 glXGetFBConfigAttrib( runtime.display, fbc[i], 304 GLX_SAMPLE_BUFFERS, &sampBuff); 305 glXGetFBConfigAttrib( runtime.display, fbc[i], 306 GLX_SAMPLES, &samples); 307 308 if (bestFbc < 0 || (sampBuff && samples > bestNum)) 309 { 310 bestFbc = i; 311 bestNum = samples; 312 } 313 } 314 315 this.bestFbcs = fbc[bestFbc]; 316 enforce!Exception(bestFbcs, ConfFindError); 317 318 this.visual = glXGetVisualFromFBConfig(runtime.display, bestFbcs); 319 enforce!Exception(visual, ConfFindError); 320 } 321 322 void create(IWindow window) 323 { 324 _context = glXCreateNewContext( runtime.display, this.bestFbcs, 325 GLX_RGBA_TYPE, null, true); 326 } 327 328 void destroy() 329 { 330 glXDestroyContext(runtime.display, _context); 331 if(visual) XFree(visual); 332 } 333 } 334 335 version (Posix) 336 class Window : IWindow 337 { 338 import tida.runtime, tida.image; 339 import x11.X, x11.Xlib, x11.Xutil; 340 import dglx.glx; 341 import std.utf : toUTFz; 342 343 private: 344 string _title; 345 bool _fullscreen; 346 bool _border; 347 bool _resizable; 348 bool _alwaysTop; 349 IContext _context; 350 uint _widthInit; 351 uint _heightInit; 352 353 public: 354 x11.X.Window handle; 355 Visual* visual; 356 int depth; 357 358 @trusted: 359 this(uint w, uint h, string caption) 360 { 361 this._widthInit = w; 362 this._heightInit = h; 363 } 364 365 void createFromXVisual(XVisualInfo* vinfo, int posX = 100, int posY = 100) 366 { 367 visual = vinfo.visual; 368 depth = vinfo.depth; 369 370 auto rootWindow = runtime.rootWindow; 371 372 XSetWindowAttributes windowAttribs; 373 windowAttribs.border_pixel = 0x000000; 374 windowAttribs.background_pixel = 0xFFFFFF; 375 windowAttribs.override_redirect = True; 376 windowAttribs.colormap = XCreateColormap(runtime.display, rootWindow, 377 visual, AllocNone); 378 379 windowAttribs.event_mask = ExposureMask | ButtonPressMask | KeyPressMask | 380 KeyReleaseMask | ButtonReleaseMask | EnterWindowMask | 381 LeaveWindowMask | PointerMotionMask; 382 383 this.handle = XCreateWindow (runtime.display, rootWindow, posX, posY, _widthInit, _heightInit, 0, depth, 384 InputOutput, visual, CWBackPixel | CWColormap | CWBorderPixel | CWEventMask, 385 &windowAttribs); 386 387 title = _title; 388 389 Atom wmAtom = XInternAtom(runtime.display, "WM_DELETE_WINDOW", 0); 390 XSetWMProtocols(runtime.display, this.handle, &wmAtom, 1); 391 } 392 393 int getDepth() 394 { 395 return depth; 396 } 397 398 Visual* getVisual() 399 { 400 return visual; 401 } 402 403 ~this() 404 { 405 this.destroy(); 406 } 407 override: 408 @property int x() 409 { 410 XWindowAttributes winAttrib; 411 XGetWindowAttributes(runtime.display, this.handle, &winAttrib); 412 413 return winAttrib.x; 414 } 415 416 @property int y() 417 { 418 XWindowAttributes winAttrib; 419 XGetWindowAttributes(runtime.display, this.handle, &winAttrib); 420 421 return winAttrib.y; 422 } 423 424 @property uint width() 425 { 426 XWindowAttributes winAttrib; 427 XGetWindowAttributes(runtime.display, this.handle, &winAttrib); 428 429 return winAttrib.width; 430 } 431 432 @property uint height() 433 { 434 XWindowAttributes winAttrib; 435 XGetWindowAttributes(runtime.display, this.handle, &winAttrib); 436 437 return winAttrib.height; 438 } 439 440 @property void fullscreen(bool value) 441 { 442 XEvent event; 443 444 const wmState = XInternAtom(runtime.display, 445 "_NET_WM_STATE", 0); 446 const wmFullscreen = XInternAtom( runtime.display, 447 "_NET_WM_STATE_FULLSCREEN", 0); 448 449 event.xany.type = ClientMessage; 450 event.xclient.message_type = wmState; 451 event.xclient.format = 32; 452 event.xclient.window = this.handle; 453 event.xclient.data.l[1] = wmFullscreen; 454 event.xclient.data.l[3] = 0; 455 456 event.xclient.data.l[0] = value; 457 458 XSendEvent(runtime.display,runtime.rootWindow,0, 459 SubstructureNotifyMask | SubstructureRedirectMask, &event); 460 461 this._fullscreen = value; 462 } 463 464 @property bool fullscreen() 465 { 466 return this._fullscreen; 467 } 468 469 @property void resizable(bool value) 470 { 471 long flags; 472 473 scope XSizeHints* sh = XAllocSizeHints(); 474 scope(exit) XFree(sh); 475 476 XGetWMNormalHints(runtime.display, this.handle, sh, &flags); 477 478 if(!value) 479 { 480 sh.flags |= PMinSize | PMaxSize; 481 sh.min_width = this.width; 482 sh.max_width = this.width; 483 sh.min_height = this.height; 484 sh.max_height = this.height; 485 }else 486 { 487 sh.flags &= ~(PMinSize | PMaxSize); 488 } 489 490 this._resizable = value; 491 XSetWMNormalHints(runtime.display, this.handle, sh); 492 } 493 494 @property bool resizable() 495 { 496 return this._resizable; 497 } 498 499 @property void border(bool value) 500 { 501 import std.conv : to; 502 503 struct MWMHints { 504 ulong flags; 505 ulong functions; 506 ulong decorations; 507 long inputMode; 508 ulong status; 509 } 510 511 const hint = MWMHints(1 << 1, 0, value.to!ulong, 0, 0); 512 const wmHINTS = XInternAtom(runtime.display, "_MOTIF_WM_HINTS", 0); 513 514 XChangeProperty(runtime.display, this.handle, wmHINTS, wmHINTS, 32, 515 PropModeReplace, cast(ubyte*) &hint, MWMHints.sizeof / long.sizeof); 516 517 this._border = value; 518 } 519 520 @property bool border() 521 { 522 return this._border; 523 } 524 525 @property void title(string value) 526 { 527 XStoreName(runtime.display, this.handle, value.toUTFz!(char*)); 528 XSetIconName(runtime.display, this.handle, value.toUTFz!(char*)); 529 530 this._title = value; 531 } 532 533 @property string title() 534 { 535 return this._title; 536 } 537 538 @property void alwaysOnTop(bool value) 539 { 540 const wmState = XInternAtom(runtime.display, "_NET_WM_STATE", 0); 541 const wmAbove = XInternAtom(runtime.display, "_NET_WM_STATE_ABOVE", 0); 542 543 XEvent event; 544 event.xclient.type = ClientMessage; 545 event.xclient.serial = 0; 546 event.xclient.send_event = true; 547 event.xclient.display = runtime.display; 548 event.xclient.window = this.handle; 549 event.xclient.message_type = wmState; 550 event.xclient.format = 32; 551 event.xclient.data.l[0] = value; 552 event.xclient.data.l[1] = wmAbove; 553 event.xclient.data.l[2 .. 5] = 0; 554 555 XSendEvent( runtime.display, runtime.rootWindow, false, 556 SubstructureRedirectMask | SubstructureNotifyMask, &event); 557 XFlush(runtime.display); 558 559 this._alwaysTop = value; 560 } 561 562 @property bool alwaysOnTop() 563 { 564 return this._alwaysTop; 565 } 566 567 void icon(Image iconimage) 568 { 569 import tida.color; 570 571 ulong[] pixels = [ cast(ulong) iconimage.width, 572 cast(ulong) iconimage.height]; 573 574 foreach(pixel; iconimage.pixels) 575 pixels ~= pixel.to!(ulong, PixelFormat.ARGB); 576 577 const first = XInternAtom(runtime.display, "_NET_WM_ICON", 0); 578 const second = XInternAtom(runtime.display, "CARDINAL", 0); 579 580 XChangeProperty(runtime.display, this.handle, first, second, 32, 581 PropModeReplace, cast(ubyte*) pixels, 582 cast(int) pixels.length); 583 } 584 585 @property void context(IContext ctx) 586 { 587 this._context = ctx; 588 glXMakeCurrent(runtime.display, this.handle, (cast(Context) ctx)._context); 589 } 590 591 @property IContext context() 592 { 593 return this._context; 594 } 595 596 void resize(uint w, uint h) 597 { 598 XResizeWindow(runtime.display, this.handle, w, h); 599 } 600 601 void move(int xposition, int yposition) 602 { 603 XMoveWindow(runtime.display, this.handle, xposition, yposition); 604 } 605 606 void show() 607 { 608 XMapWindow(runtime.display, this.handle); 609 XClearWindow(runtime.display, this.handle); 610 } 611 612 void hide() 613 { 614 XUnmapWindow(runtime.display, this.handle); 615 } 616 617 void swapBuffers() 618 { 619 import dglx.glx : glXSwapBuffers; 620 621 glXSwapBuffers(runtime.display, this.handle); 622 } 623 624 void destroy() 625 { 626 XDestroyWindow(runtime.display, this.handle); 627 this.handle = 0; 628 } 629 } 630 631 version(Windows) 632 class Context : IContext 633 { 634 import tida.runtime; 635 import core.sys.windows.windows; 636 import std.exception : enforce; 637 638 private: 639 GraphicsAttributes attributes; 640 HDC deviceHandle; 641 642 PIXELFORMATDESCRIPTOR pfd; 643 644 alias FwglChoosePixelFormatARB = extern(C) bool function( HDC hdc, 645 int *piAttribIList, 646 float *pfAttribFList, 647 uint nMaxFormats, 648 int *piFormats, 649 uint *nNumFormats); 650 651 alias FwglGetExtensionsStringARB = extern(C) char* function(HDC hdc); 652 653 alias FwglCreateContextAttribsARB = extern(C) HGLRC function(HDC, HGLRC, int*); 654 655 FwglChoosePixelFormatARB wglChoosePixelFormatARB; 656 FwglGetExtensionsStringARB wglGetExtensionsStringARB; 657 FwglCreateContextAttribsARB wglCreateContextAttribsARB; 658 659 enum 660 { 661 WGL_DRAW_TO_WINDOW_ARB = 0x2001, 662 WGL_RED_BITS_ARB = 0x2015, 663 WGL_GREEN_BITS_ARB = 0x2017, 664 WGL_BLUE_BITS_ARB = 0x2019, 665 WGL_ALPHA_BITS_ARB = 0x201B, 666 WGL_DOUBLE_BUFFER_ARB = 0x2011, 667 WGL_DEPTH_BITS_ARB = 0x2022, 668 WGL_CONTEXT_MAJOR_VERSION_ARB = 0x2091, 669 WGL_CONTEXT_MINOR_VERSION_ARB = 0x2092, 670 WGL_CONTEXT_FLAGS_ARB = 0x2094, 671 WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB = 0x0002, 672 WGL_SUPPORT_OPENGL_ARB = 0x2010, 673 WGL_COLOR_BITS_ARB = 0x2014, 674 WGL_STENCIL_BITS_ARB = 0x2023, 675 WGL_ACCELERATION_ARB = 0x2003, 676 WGL_FULL_ACCELERATION_ARB = 0x2027, 677 WGL_PIXEL_TYPE_ARB = 0x2013, 678 WGL_TYPE_RGBA_ARB = 0x202B, 679 WGL_CONTEXT_PROFILE_MASK_ARB = 0x9126, 680 WGL_CONTEXT_CORE_PROFILE_BIT_ARB = 0x00000001 681 } 682 683 public: 684 HGLRC _context; 685 686 @trusted: 687 ~this() 688 { 689 destroy(); 690 } 691 override: 692 void setAttributes(GraphicsAttributes attributes) 693 { 694 this.attributes = attributes; 695 696 const flags = 697 (attributes.doubleBuffer ? 698 (PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL) : 699 (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL)); 700 701 pfd.nSize = PIXELFORMATDESCRIPTOR.sizeof; 702 pfd.nVersion = 1; 703 pfd.dwFlags = flags; 704 pfd.iPixelType = PFD_TYPE_RGBA; 705 pfd.cRedBits = cast(ubyte) this.attributes.redSize; 706 pfd.cGreenBits = cast(ubyte) this.attributes.greenSize; 707 pfd.cBlueBits = cast(ubyte) this.attributes.blueSize; 708 pfd.cAlphaBits = cast(ubyte) this.attributes.alphaSize; 709 pfd.cDepthBits = cast(ubyte) this.attributes.depthSize; 710 pfd.cStencilBits = cast(ubyte) this.attributes.stencilSize; 711 pfd.iLayerType = PFD_MAIN_PLANE; 712 } 713 714 void create(IWindow window) 715 { 716 scope handle = (cast(Window) window).handle; 717 deviceHandle = (cast(Window) window).dc; 718 auto chsPixel = ChoosePixelFormat(deviceHandle, &pfd); 719 enforce!Exception(chsPixel != 0, ConfFindError); 720 721 SetPixelFormat(deviceHandle, chsPixel, &pfd); 722 723 scope ctx = wglCreateContext(deviceHandle); 724 wglMakeCurrent(deviceHandle, ctx); 725 726 void* data = wglGetProcAddress("wglGetExtensionsStringARB"); 727 enforce!Exception(data,"wglGetExtensionsStringARB pointer is null"); 728 wglGetExtensionsStringARB = cast(FwglGetExtensionsStringARB) data; 729 data = null; 730 731 data = wglGetProcAddress("wglChoosePixelFormatARB"); 732 enforce!Exception(data,"wglChoosePixelFormatARB pointer is null"); 733 wglChoosePixelFormatARB = cast(FwglChoosePixelFormatARB) data; 734 data = null; 735 736 data = wglGetProcAddress("wglCreateContextAttribsARB"); 737 enforce!Exception(data,"wglCreateContextAttribsARB pointer is null"); 738 wglCreateContextAttribsARB = cast(FwglCreateContextAttribsARB) data; 739 data = null; 740 741 int[] iattrib = 742 [ 743 WGL_SUPPORT_OPENGL_ARB, true, 744 WGL_DRAW_TO_WINDOW_ARB, true, 745 WGL_DOUBLE_BUFFER_ARB, attributes.doubleBuffer, 746 WGL_RED_BITS_ARB, attributes.redSize, 747 WGL_GREEN_BITS_ARB, attributes.greenSize, 748 WGL_BLUE_BITS_ARB, attributes.blueSize, 749 WGL_ALPHA_BITS_ARB, attributes.alphaSize, 750 WGL_DEPTH_BITS_ARB, attributes.depthSize, 751 WGL_COLOR_BITS_ARB, attributes.colorDepth, 752 WGL_STENCIL_BITS_ARB, attributes.stencilSize, 753 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, 754 0 755 ]; 756 757 uint nNumFormats; 758 int nPixelFormat; 759 wglChoosePixelFormatARB(deviceHandle, iattrib.ptr, 760 null, 761 1, &nPixelFormat, 762 &nNumFormats); 763 enforce(nPixelFormat, "nPixelFormats error!"); 764 765 DescribePixelFormat(deviceHandle, nPixelFormat, pfd.sizeof, &pfd); 766 SetPixelFormat(deviceHandle, nPixelFormat, &pfd); 767 768 int[] attrib = 769 [ 770 WGL_CONTEXT_MAJOR_VERSION_ARB, this.attributes.glmajor, 771 WGL_CONTEXT_MINOR_VERSION_ARB, this.attributes.glminor, 772 WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, 773 WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 774 0 775 ]; 776 this._context = wglCreateContextAttribsARB( deviceHandle, 777 null, 778 attrib.ptr); 779 enforce(this._context, "ContextARB is not a create!"); 780 781 wglMakeCurrent(null, null); 782 wglDeleteContext(ctx); 783 } 784 785 void destroy() 786 { 787 wglDeleteContext(_context); 788 } 789 } 790 791 __gshared Window _wndptr; 792 793 version(Windows) 794 class Window : IWindow 795 { 796 import tida.runtime; 797 import tida.image; 798 import tida.color; 799 800 import std.utf : toUTFz; 801 import std.exception : enforce; 802 import core.sys.windows.windows; 803 804 pragma(lib, "opengl32.lib"); 805 806 private: 807 uint _widthInit; 808 uint _heightInit; 809 810 string _title; 811 812 bool _fullscreen = false; 813 bool _border = true; 814 bool _resizable = true; 815 bool _alwaysTop = false; 816 817 IContext _context; 818 819 LONG style; 820 LONG oldStyle; 821 WINDOWPLACEMENT wpc; 822 823 public: 824 HWND handle; 825 HDC dc; 826 bool isClose = false; 827 bool isResize = false; 828 829 this(uint w, uint h, string caption) 830 { 831 this._widthInit = w; 832 this._heightInit = h; 833 _title = caption; 834 } 835 836 @trusted: 837 void create(int posX, int posY) 838 { 839 import std.traits : Signed; 840 841 extern(Windows) auto _wndProc(HWND hWnd, uint message, WPARAM wParam, LPARAM lParam) 842 { 843 switch (message) 844 { 845 case WM_CLOSE: 846 if (_wndptr is null || _wndptr.__vptr is null) return 0; 847 848 _wndptr.sendCloseEvent(); 849 return 0; 850 851 case WM_SIZE: 852 if (_wndptr is null || _wndptr.__vptr is null) return 0; 853 854 _wndptr.isResize = true; 855 return 0; 856 857 default: 858 return DefWindowProc(hWnd, message, wParam, lParam); 859 } 860 } 861 862 alias WinFun = extern (Windows) Signed!size_t function(void*, uint, size_t, Signed!size_t) nothrow @system; 863 864 WNDCLASSEX wc; 865 866 wc.cbSize = wc.sizeof; 867 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 868 wc.lpfnWndProc = cast(WinFun) &_wndProc; 869 wc.hInstance = runtime.instance; 870 wc.hCursor = LoadCursor(null, IDC_ARROW); 871 wc.lpszClassName = _title.toUTFz!(wchar*); 872 873 RegisterClassEx(&wc); 874 875 this.handle = CreateWindow( _title.toUTFz!(wchar*), 876 _title.toUTFz!(wchar*), 877 WS_CAPTION | WS_SYSMENU | WS_CLIPSIBLINGS | 878 WS_CLIPCHILDREN | WS_THICKFRAME, 879 posX, posY, this._widthInit, 880 this._heightInit, null, null, 881 runtime.instance, null); 882 883 enforce!Exception(this.handle, "Window is not create!"); 884 885 dc = GetDC(this.handle); 886 887 _wndptr = this; 888 } 889 890 void sendCloseEvent() 891 { 892 this.isClose = true; 893 } 894 895 override: 896 @property int x() 897 { 898 RECT rect; 899 GetWindowRect(this.handle, &rect); 900 901 return rect.left; 902 } 903 904 @property int y() 905 { 906 RECT rect; 907 GetWindowRect(this.handle, &rect); 908 909 return rect.top; 910 } 911 912 @property uint width() 913 { 914 RECT rect; 915 GetWindowRect(this.handle, &rect); 916 917 return rect.right - rect.left; 918 } 919 920 @property uint height() 921 { 922 RECT rect; 923 GetWindowRect(this.handle, &rect); 924 925 return rect.bottom - rect.top; 926 } 927 928 @property void fullscreen(bool value) 929 { 930 if (value) 931 { 932 GetWindowPlacement(this.handle, &wpc); 933 934 if(style == 0) 935 style = GetWindowLong(this.handle, GWL_STYLE); 936 if(oldStyle == 0) 937 oldStyle = GetWindowLong(this.handle, GWL_EXSTYLE); 938 939 auto NewHWNDStyle = style; 940 NewHWNDStyle &= ~WS_BORDER; 941 NewHWNDStyle &= ~WS_DLGFRAME; 942 NewHWNDStyle &= ~WS_THICKFRAME; 943 944 auto NewHWNDStyleEx = oldStyle; 945 NewHWNDStyleEx &= ~WS_EX_WINDOWEDGE; 946 947 SetWindowLong( this.handle, GWL_STYLE, 948 NewHWNDStyle | WS_POPUP ); 949 SetWindowLong( this.handle, GWL_EXSTYLE, 950 NewHWNDStyleEx | WS_EX_TOPMOST); 951 952 ShowWindow(this.handle, SHOW_FULLSCREEN); 953 } else 954 { 955 SetWindowLong(this.handle, GWL_STYLE, style); 956 SetWindowLong(this.handle, GWL_EXSTYLE, oldStyle); 957 ShowWindow(this.handle, SW_SHOWNORMAL); 958 SetWindowPlacement(this.handle, &wpc); 959 960 style = 0; 961 oldStyle = 0; 962 } 963 964 this._fullscreen = value; 965 } 966 967 @property bool fullscreen() 968 { 969 return this._fullscreen; 970 } 971 972 @property void resizable(bool value) 973 { 974 auto lStyle = GetWindowLong(this.handle, GWL_STYLE); 975 976 if (value) 977 lStyle |= WS_THICKFRAME; 978 else 979 lStyle &= ~(WS_THICKFRAME); 980 981 SetWindowLong(this.handle, GWL_STYLE, lStyle); 982 983 this._resizable = value; 984 } 985 986 @property bool resizable() 987 { 988 return this._resizable; 989 } 990 991 @property void border(bool value) 992 { 993 auto style = GetWindowLong(this.handle, GWL_STYLE); 994 995 if (!value) 996 style &= ~( 997 WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | 998 WS_MAXIMIZEBOX | WS_SYSMENU 999 ); 1000 else 1001 style |= ( 1002 WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | 1003 WS_MAXIMIZEBOX | WS_SYSMENU 1004 ); 1005 1006 SetWindowLong(this.handle, GWL_STYLE, style); 1007 1008 SetWindowPos( this.handle, null, 0, 0, 0, 0, 1009 SWP_FRAMECHANGED | SWP_NOMOVE | 1010 SWP_NOSIZE | SWP_NOZORDER | 1011 SWP_NOOWNERZORDER); 1012 1013 this._border = value; 1014 } 1015 1016 @property bool border() 1017 { 1018 return this._border; 1019 } 1020 1021 @property void title(string value) 1022 { 1023 SetWindowTextA(this.handle, title.toUTFz!(char*)); 1024 1025 this._title = value; 1026 } 1027 1028 @property string title() 1029 { 1030 return this._title; 1031 } 1032 1033 @property void alwaysOnTop(bool value) 1034 { 1035 SetWindowPos( this.handle, 1036 value ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, 1037 SWP_NOMOVE | SWP_NOSIZE); 1038 1039 this._alwaysTop = value; 1040 } 1041 1042 @property bool alwaysOnTop() 1043 { 1044 return this._alwaysTop; 1045 } 1046 1047 @property void icon(Image iconimage) 1048 { 1049 HICON icon; 1050 1051 ubyte[] pixels = iconimage.bytes!(PixelFormat.BGRA); 1052 1053 ICONINFO icInfo; 1054 1055 auto bitmap = CreateBitmap( iconimage.width, 1056 iconimage.height, 1057 1,32,cast(PCVOID) pixels); 1058 1059 icInfo.hbmColor = bitmap; 1060 icInfo.hbmMask = CreateBitmap(iconimage.width,iconimage.height,1,1,null); 1061 1062 icon = CreateIconIndirect(&icInfo); 1063 1064 SendMessage(handle, WM_SETICON, ICON_SMALL, cast(LPARAM) icon); 1065 SendMessage(handle, WM_SETICON, ICON_BIG, cast(LPARAM) icon); 1066 } 1067 1068 @property void context(IContext ctx) 1069 { 1070 wglMakeCurrent(GetDC(this.handle),(cast(Context) ctx)._context); 1071 1072 this._context = ctx; 1073 } 1074 1075 @property IContext context() 1076 { 1077 return this._context; 1078 } 1079 1080 void resize(uint w, uint h) 1081 { 1082 SetWindowPos(this.handle, null, x, y ,w, h, 0); 1083 } 1084 1085 void move(int xposition, int yposition) 1086 { 1087 SetWindowPos(this.handle, null, xposition, yposition, width, height, 0); 1088 } 1089 1090 void show() 1091 { 1092 ShowWindow(this.handle, 1); 1093 } 1094 1095 void hide() 1096 { 1097 ShowWindow(this.handle, SW_HIDE); 1098 } 1099 1100 void swapBuffers() 1101 { 1102 SwapBuffers(dc); 1103 } 1104 1105 void destroy() 1106 { 1107 DestroyWindow(this.handle); 1108 this.handle = null; 1109 } 1110 } 1111 1112 /++ 1113 Creating a window in the window manager. When setting a parameter in a template, 1114 it can create both its regular version and with hardware graphics acceleration. 1115 1116 Params: 1117 type = Method of creation. 1118 `WithoutContext` - Only the window is created. 1119 The context is created after. 1120 `WithContext` - Creates both a window and a graphics context for 1121 using hardware graphics acceleration. 1122 window = Window pointer. 1123 posX = Position in the plane of the desktop along the x-axis. 1124 posY = Position in the plane of the desktop along the y-axis. 1125 1126 Throws: 1127 `Exception` If a window has not been created in the process 1128 (and this also applies to the creation of a graphical context). 1129 1130 Examples: 1131 --- 1132 windowInitialize!WithoutContext(window, 100, 100); /// Without context 1133 ... 1134 windowInitialize!WithContext(window, 100, 100); /// With context 1135 --- 1136 +/ 1137 void windowInitialize(int type = WithoutContext)( Window window, 1138 int posX, 1139 int posY) @trusted 1140 { 1141 version(Posix) { 1142 import tida.runtime; 1143 import x11.X, x11.Xlib, x11.Xutil; 1144 1145 scope XVisualInfo* vinfo = new XVisualInfo(); 1146 vinfo.visual = XDefaultVisual(runtime.display, runtime.displayID); 1147 vinfo.depth = XDefaultDepth(runtime.display, runtime.displayID); 1148 1149 window.createFromXVisual(vinfo); 1150 1151 destroy(vinfo); 1152 } 1153 else 1154 window.create(posX, posY); 1155 1156 static if(type == WithContext) 1157 { 1158 GraphicsAttributes attribs = AttribBySizeOfTheColor!8; 1159 attribs.glmajor = 4; 1160 attribs.glminor = 5; 1161 1162 Context context; 1163 1164 void ctxCreate() { 1165 context = new Context(); 1166 context.setAttributes(attribs); 1167 context.create(window); 1168 } 1169 1170 try 1171 { 1172 ctxCreate(); 1173 } catch(Exception e) 1174 { 1175 attribs.glmajor = 3; 1176 attribs.glminor = 3; 1177 1178 try 1179 { 1180 ctxCreate(); 1181 } catch(Exception e) 1182 { 1183 attribs.glmajor = 3; 1184 attribs.glminor = 0; 1185 1186 ctxCreate(); 1187 } 1188 } 1189 1190 window.context = context; 1191 } 1192 1193 window.show(); 1194 }