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 
828     this(uint w, uint h, string caption)
829     {
830         this._widthInit = w;
831         this._heightInit = h;
832         _title = caption;
833     }
834 
835 @trusted:
836     void create(int posX, int posY)
837     {
838         import std.traits : Signed;
839 
840         extern(Windows) auto _wndProc(HWND hWnd, uint message, WPARAM wParam, LPARAM lParam)
841         {
842             switch (message)
843             {
844                 case WM_CLOSE:
845                     if (_wndptr is null || _wndptr.__vptr is null) return 0;
846                     
847                     _wndptr.sendCloseEvent();
848                     return 0;
849 
850                 default:
851                     return DefWindowProc(hWnd, message, wParam, lParam);
852             }
853         }
854 
855         alias WinFun = extern (Windows) Signed!size_t function(void*, uint, size_t, Signed!size_t) nothrow @system;
856 
857         WNDCLASSEX wc;
858 
859         wc.cbSize = wc.sizeof;
860         wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
861         wc.lpfnWndProc = cast(WinFun) &_wndProc;
862         wc.hInstance = runtime.instance;
863         wc.hCursor = LoadCursor(null, IDC_ARROW);
864         wc.lpszClassName = _title.toUTFz!(wchar*);
865 
866         RegisterClassEx(&wc);
867 
868         this.handle = CreateWindow( _title.toUTFz!(wchar*), 
869                                     _title.toUTFz!(wchar*),
870                                     WS_CAPTION | WS_SYSMENU | WS_CLIPSIBLINGS | 
871                                     WS_CLIPCHILDREN | WS_THICKFRAME,
872                                     posX, posY, this._widthInit, 
873                                     this._heightInit, null, null, 
874                                     runtime.instance, null);
875                  
876         enforce!Exception(this.handle, "Window is not create!");
877 
878         dc = GetDC(this.handle);
879 
880         _wndptr = this;
881     }
882 
883     void sendCloseEvent()
884     {
885         this.isClose = true;
886     }
887 
888 override:
889     @property int x()
890     {
891         RECT rect;
892         GetWindowRect(this.handle, &rect);
893 
894         return rect.left;
895     }
896 
897     @property int y()
898     {
899         RECT rect;
900         GetWindowRect(this.handle, &rect);
901 
902         return rect.top;
903     }
904 
905     @property uint width()
906     {
907         RECT rect;
908         GetWindowRect(this.handle, &rect);
909 
910         return rect.right - rect.left;
911     }
912 
913     @property uint height()
914     {
915         RECT rect;
916         GetWindowRect(this.handle, &rect);
917 
918         return rect.bottom - rect.top;
919     }
920 
921     @property void fullscreen(bool value)
922     {
923         if (value) 
924         {
925             GetWindowPlacement(this.handle, &wpc);
926 
927             if(style == 0)
928                 style = GetWindowLong(this.handle, GWL_STYLE);
929             if(oldStyle == 0)
930                 oldStyle = GetWindowLong(this.handle, GWL_EXSTYLE);
931 
932             auto NewHWNDStyle = style;
933             NewHWNDStyle &= ~WS_BORDER;
934             NewHWNDStyle &= ~WS_DLGFRAME;
935             NewHWNDStyle &= ~WS_THICKFRAME;
936 
937             auto NewHWNDStyleEx = oldStyle;
938             NewHWNDStyleEx &= ~WS_EX_WINDOWEDGE;
939 
940             SetWindowLong(  this.handle, GWL_STYLE, 
941                             NewHWNDStyle | WS_POPUP );
942             SetWindowLong(  this.handle, GWL_EXSTYLE, 
943                             NewHWNDStyleEx | WS_EX_TOPMOST);
944 
945             ShowWindow(this.handle, SHOW_FULLSCREEN);
946         } else 
947         {
948             SetWindowLong(this.handle, GWL_STYLE, style);
949             SetWindowLong(this.handle, GWL_EXSTYLE, oldStyle);
950             ShowWindow(this.handle, SW_SHOWNORMAL);
951             SetWindowPlacement(this.handle, &wpc);
952 
953             style = 0;
954             oldStyle = 0;
955         }
956 
957         this._fullscreen = value;
958     }
959 
960     @property bool fullscreen()
961     {
962         return this._fullscreen;
963     }
964 
965     @property void resizable(bool value)
966     {
967         auto lStyle = GetWindowLong(this.handle, GWL_STYLE);
968         
969         if (value) 
970             lStyle |= WS_THICKFRAME;
971         else 
972             lStyle &= ~(WS_THICKFRAME);
973 
974         SetWindowLong(this.handle, GWL_STYLE, lStyle);
975 
976         this._resizable = value;
977     }
978 
979     @property bool resizable()
980     {
981         return this._resizable;
982     }
983 
984     @property void border(bool value)
985     {
986         auto style = GetWindowLong(this.handle, GWL_STYLE);
987 
988         if (!value)
989             style &=    ~(  
990                             WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | 
991                             WS_MAXIMIZEBOX | WS_SYSMENU
992                         );
993         else
994             style |=    (
995                             WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | 
996                             WS_MAXIMIZEBOX | WS_SYSMENU
997                         );
998 
999         SetWindowLong(this.handle, GWL_STYLE, style);
1000 
1001         SetWindowPos(   this.handle, null, 0, 0, 0, 0,
1002                         SWP_FRAMECHANGED | SWP_NOMOVE |
1003                         SWP_NOSIZE | SWP_NOZORDER |
1004                         SWP_NOOWNERZORDER);
1005 
1006         this._border = value;
1007     }
1008 
1009     @property bool border()
1010     {
1011         return this._border;
1012     }
1013 
1014     @property void title(string value)
1015     {
1016         SetWindowTextA(this.handle, title.toUTFz!(char*));
1017 
1018         this._title = value;
1019     }
1020 
1021     @property string title()
1022     {
1023         return this._title;
1024     }
1025 
1026     @property void alwaysOnTop(bool value)
1027     {
1028         SetWindowPos(   this.handle, 
1029                         value ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, 
1030                         SWP_NOMOVE | SWP_NOSIZE);
1031 
1032         this._alwaysTop = value;
1033     }
1034 
1035     @property bool alwaysOnTop()
1036     {
1037         return this._alwaysTop;
1038     }
1039 
1040     @property void icon(Image iconimage)
1041     {
1042         HICON icon;
1043 
1044         ubyte[] pixels = iconimage.bytes!(PixelFormat.BGRA);
1045 
1046         ICONINFO icInfo;
1047 
1048         auto bitmap = CreateBitmap( iconimage.width,
1049                                     iconimage.height,
1050                                     1,32,cast(PCVOID) pixels);
1051 
1052         icInfo.hbmColor = bitmap;
1053         icInfo.hbmMask = CreateBitmap(iconimage.width,iconimage.height,1,1,null);
1054 
1055         icon = CreateIconIndirect(&icInfo);
1056 
1057         SendMessage(handle, WM_SETICON, ICON_SMALL, cast(LPARAM) icon);
1058         SendMessage(handle, WM_SETICON, ICON_BIG, cast(LPARAM) icon);
1059     }
1060 
1061     @property void context(IContext ctx)
1062     {
1063         wglMakeCurrent(GetDC(this.handle),(cast(Context) ctx)._context);
1064 
1065         this._context = ctx;
1066     }
1067 
1068     @property IContext context()
1069     {
1070         return this._context;
1071     }
1072 
1073     void resize(uint w, uint h)
1074     {
1075         SetWindowPos(this.handle, null, x, y ,w, h, 0);
1076     }
1077 
1078     void move(int xposition, int yposition)
1079     {
1080         SetWindowPos(this.handle, null, xposition, yposition, width, height, 0);
1081     }
1082 
1083     void show()
1084     {
1085         ShowWindow(this.handle, 1);
1086     }
1087 
1088     void hide()
1089     {
1090         ShowWindow(this.handle, SW_HIDE);
1091     }
1092 
1093     void swapBuffers()
1094     {
1095         SwapBuffers(dc);
1096     }
1097 
1098     void destroy()
1099     {
1100         DestroyWindow(this.handle);
1101         this.handle = null;
1102     }
1103 }
1104 
1105 /++
1106 Creating a window in the window manager. When setting a parameter in a template, 
1107 it can create both its regular version and with hardware graphics acceleration.
1108 
1109 Params:
1110     type =  Method of creation. 
1111             `WithoutContext` -  Only the window is created. 
1112                                 The context is created after.
1113             `WithContext` - Creates both a window and a graphics context for 
1114                             using hardware graphics acceleration.
1115     window = Window pointer.
1116     posX = Position in the plane of the desktop along the x-axis.
1117     posY = Position in the plane of the desktop along the y-axis.
1118 
1119 Throws:
1120 `Exception` If a window has not been created in the process 
1121 (and this also applies to the creation of a graphical context).
1122 
1123 Examples:
1124 ---
1125 windowInitialize!WithoutContext(window, 100, 100); /// Without context
1126 ...
1127 windowInitialize!WithContext(window, 100, 100); /// With context
1128 ---
1129 +/
1130 void windowInitialize(int type = WithoutContext)(   Window window, 
1131                                                     int posX, 
1132                                                     int posY) @trusted
1133 {
1134     version(Posix) {
1135         import tida.runtime;
1136         import x11.X, x11.Xlib, x11.Xutil;
1137 
1138         scope XVisualInfo* vinfo = new XVisualInfo();
1139         vinfo.visual = XDefaultVisual(runtime.display, runtime.displayID);
1140         vinfo.depth = XDefaultDepth(runtime.display, runtime.displayID);
1141         
1142         window.createFromXVisual(vinfo);
1143 
1144         destroy(vinfo);
1145     }
1146     else
1147         window.create(posX, posY);
1148     
1149     static if(type == WithContext)
1150     {
1151         GraphicsAttributes attribs = AttribBySizeOfTheColor!8;
1152         attribs.glmajor = 4;
1153         attribs.glminor = 5;
1154 
1155         Context context;
1156         
1157         void ctxCreate() {
1158             context = new Context();
1159             context.setAttributes(attribs);
1160             context.create(window);
1161         }
1162 
1163         try
1164         {
1165             ctxCreate();
1166         } catch(Exception e)
1167         {
1168             attribs.glmajor = 3;
1169             attribs.glminor = 3;
1170 
1171             try
1172             {
1173                 ctxCreate();
1174             } catch(Exception e)
1175             {
1176                 attribs.glmajor = 3;
1177                 attribs.glminor = 0;
1178                 
1179                 ctxCreate();
1180             }
1181         }
1182 
1183         window.context = context;
1184     }
1185 
1186     window.show();
1187 }