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 }