1 /++
2 A module for connecting to the window manager and also loading the necessary 
3 libraries, everything that does runtime, to which other objects can access 
4 the necessary objects.
5 
6 $(LREF runtime) Gives access to runtime. Before that, you need to initialize the 
7 runtime with the $(HREF runtime/ITidaRuntime.initialize,ITidaRuntime.initialize)
8 function if it has not been initialized earlier.
9 
10 The easiest way to initialize:
11 ---
12 void main(string[] args) {
13     TidaRuntime.initialize(args);
14     ...
15 }
16 ---
17 
18 Macros:
19     LREF = <a href="#$1">$1</a>
20     HREF = <a href="$1">$2</a>
21 
22 Authors: $(HREF https://github.com/TodNaz,TodNaz)
23 Copyright: Copyright (c) 2020 - 2021, TodNaz.
24 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT)
25 +/
26 module tida.runtime;
27 
28 __gshared TidaRuntime _runtimeObject;
29 
30 /++
31 Global access to runtime. An object can be called from anywhere, 
32 but cannot be replaced.
33 +/
34 @property TidaRuntime runtime() @trusted
35 {
36     return _runtimeObject;
37 }
38 
39 enum : int
40 {
41     OpenAL = 0, /// Open Audio Library
42     FreeType, /// Free Type Library
43     GLX, /// Graphics library X11
44     EGL /// EGL library wayland
45 }
46 
47 alias LibraryUnite = int; /// 
48 
49 enum AllLibrary = [OpenAL, FreeType, GLX];
50 enum WithoutLibrary  = [GLX];
51 
52 /++
53 The interface of interaction between the program and the window manager.
54 +/
55 interface ITidaRuntime
56 {
57 @safe:
58     /++
59     A function for loading external libraries that are needed when implementing
60     internal functions.
61 
62     Params:
63         libs =  What external libraries need to be loaded. 
64                 (allLibrary to load all external libraries,
65                  WithoutLibrary in order not to load unnecessary 
66                  external libraries.)
67 
68     Throws:
69     $(OBJECTREF Exception) If the libraries were not installed on the machine 
70     being started or they were damaged.
71     +/
72     void loadExternalLibraries(LibraryUnite[] libs);
73 
74     /++
75     Connects to the window manager.
76 
77     Throws:
78     $(OBJECTREF Exception) If the libraries were not installed on the machine 
79     being started or they were damaged. And also if the connection to the 
80     window manager was not successful (for example, there is no such component 
81     in the OS or the connection to an unknown window manager is not supported).
82     +/
83     void connectToWndMng();
84 
85     /++
86     Closes the session with the window manager.
87     +/
88     void closeWndMngSession();
89 
90     /++
91     Arguments given to the program.
92     +/
93     @property string[] mainArguments();
94 
95     /++
96     Accepts program arguments for subsequent operations with them.
97     +/
98     void acceptArguments(string[] arguments);
99 
100 @trusted:
101     /++
102     Runtime initialization. It includes such stages as:
103     1. Loading external libraries.
104     2. Connection to the window manager.
105     3. Preparation of objects for work.
106 
107     Params:
108         arguments = Arguments given to the program.
109         libs = What external libraries need to be loaded. 
110                 (allLibrary to load all external libraries,
111                  WithoutLibrary in order not to load unnecessary 
112                  external libraries.)
113 
114     Throws:
115     $(OBJECTREF Exception) If the libraries were not installed on the machine
116     being started or they were damaged. And also if the connection to the 
117     window manager was not successful (for example, there is no such 
118     component in the OS or the connection to an unknown window manager 
119     is not supported).
120     +/
121     static final void initialize(   string[] arguments  = [], 
122                                     LibraryUnite[] libs = AllLibrary)
123     {
124         _runtimeObject = new TidaRuntime();
125         _runtimeObject.acceptArguments(arguments);
126         _runtimeObject.loadExternalLibraries(libs);
127         _runtimeObject.connectToWndMng();
128     }
129 }
130 
131 /++
132 The interface of interaction between the program and the window manager.
133 +/
134 version (Posix)
135 class TidaRuntime : ITidaRuntime
136 {
137     import x11.X, x11.Xlib, x11.Xutil;
138     import std.exception : enforce;
139     import tida.sound : initSoundlibrary, Device;
140     import tida.text : initFontLibrary;
141 
142     enum SessionType
143     {
144         unknown,
145         x11,
146         wayland
147     }
148 
149     enum SessionWarning =
150     "WARNING! The session is not defined. Perhaps she simply does not exist?";
151 
152 private:
153     Display* _display;
154     int _displayID;
155     string[] arguments;
156     SessionType _session;
157     Device _device;
158 
159 public @trusted:
160     this()
161     {
162         import std.process;
163         import std.stdio : stderr, writeln;
164 
165         auto env = environment.get("XDG_SESSION_TYPE");
166         if (env == "x11")
167         {
168             _session = SessionType.x11;
169         } else
170         if (env == "wayland")
171         {
172             _session = SessionType.wayland;
173         } else
174         {
175             _session = SessionType.unknown;
176             stderr.writeln(SessionWarning);
177         }
178 
179     }
180 
181     override void loadExternalLibraries(LibraryUnite[] libs)
182     {
183         import dglx.glx : loadGLXLibrary;
184 
185         foreach (e; libs)
186         {
187             if (e == OpenAL)
188             {
189                 initSoundlibrary();
190                 _device = new Device();
191                 _device.open();
192             }
193             else
194             if (e == FreeType)
195                 initFontLibrary();
196             else
197             if (e == GLX) {
198                 if (_session == SessionType.x11)
199                     loadGLXLibrary();
200             }
201         }
202     }
203 
204     override void connectToWndMng()
205     {
206         this._display = XOpenDisplay(null);
207         enforce!Exception(this._display,
208         "Failed to connect to window manager.");
209 
210         this._displayID = DefaultScreen(this._display);
211     }
212 
213     override void closeWndMngSession()
214     {
215         XCloseDisplay(this._display);
216         this._display = null;
217         this._displayID = 0;
218     }
219 
220     override void acceptArguments(string[] arguments)
221     {
222         this.arguments = arguments;
223     }
224 
225     @property override string[] mainArguments()
226     {
227         return this.arguments;
228     }
229 
230     @property Window rootWindow()
231     {
232         return RootWindow(_display, _displayID);
233     }
234 @safe:
235     /// An instance for contacting the manager's server.
236     @property Display* display()
237     {
238         return this._display;
239     }
240 
241     /// Default screen number
242     @property int displayID()
243     {
244         return this._displayID;
245     }
246 
247     ~this()
248     {
249         closeWndMngSession();
250     }
251 }
252 
253 version(Windows)
254 class TidaRuntime : ITidaRuntime
255 {
256     import core.sys.windows.windows;
257     import std.exception : enforce;
258     import tida.sound : initSoundlibrary, Device;
259     import tida.text : initFontLibrary;
260 
261 private:
262     HINSTANCE hInstance;
263     string[] arguments;
264     Device _device;
265 
266 public @trusted:
267     override void loadExternalLibraries(LibraryUnite[] libs)
268     {
269         foreach (e; libs)
270         {
271             if (e == OpenAL)
272             {
273                 initSoundlibrary();
274                 _device = new Device();
275                 _device.open();
276             }
277             else
278             if (e == FreeType)
279                 initFontLibrary();
280         }
281     }
282 
283     override void connectToWndMng()
284     {
285         this.hInstance = GetModuleHandle(null);
286         debug {} else
287             ShowWindow(GetConsoleWindow(), SW_HIDE);
288 
289         enforce!Exception(this.hInstance, 
290         "Failed to connect to window manager.");
291     }
292 
293     override void closeWndMngSession()
294     {
295         this.hInstance = null;
296     }
297 
298     override void acceptArguments(string[] arguments)
299     {
300         this.arguments = arguments;
301     }
302 
303     @property override string[] mainArguments()
304     {
305         return this.arguments;
306     }
307 
308 @safe:
309     @property HINSTANCE instance()
310     {
311         return this.hInstance;
312     }
313 }