1 module dlangui.platforms.common.startup;
2 
3 import dlangui.core.config;
4 import dlangui.core.events;
5 import dlangui.widgets.styles;
6 import dlangui.graphics.fonts;
7 import dlangui.graphics.resources;
8 import dlangui.widgets.widget;
9 import std.utf : toUTF32;
10 
11 private immutable dstring DLANGUI_VERSION_VALUE = toUTF32(import("DLANGUI_VERSION"));
12 extern(C) @property dstring DLANGUI_VERSION() {
13     return DLANGUI_VERSION_VALUE;
14 }
15 
16 static if (BACKEND_GUI) {
17 import dlangui.graphics.ftfonts;
18 
19 version (Windows) {
20 
21     /// initialize font manager - default implementation
22     /// On win32 - first it tries to init freetype, and falls back to win32 fonts.
23     /// On linux/mac - tries to init freetype with some hardcoded font paths
24     extern(C) bool initFontManager() {
25         import core.sys.windows.windows;
26         import std.utf;
27         import dlangui.platforms.windows.win32fonts;
28         try {
29             /// testing freetype font manager
30             static if (ENABLE_FREETYPE) {
31                 Log.v("Trying to init FreeType font manager");
32 
33                 import dlangui.graphics.ftfonts;
34                 // trying to create font manager
35                 Log.v("Creating FreeTypeFontManager");
36                 FreeTypeFontManager ftfontMan = new FreeTypeFontManager();
37 
38                 import core.sys.windows.shlobj;
39                 string fontsPath = "c:\\Windows\\Fonts\\";
40                 static if (true) { // SHGetFolderPathW not found in shell32.lib
41                     WCHAR[MAX_PATH] szPath;
42                     static if (false) {
43                         const CSIDL_FLAG_NO_ALIAS = 0x1000;
44                         const CSIDL_FLAG_DONT_UNEXPAND = 0x2000;
45                         if(SUCCEEDED(SHGetFolderPathW(NULL,
46                                     CSIDL_FONTS|CSIDL_FLAG_NO_ALIAS|CSIDL_FLAG_DONT_UNEXPAND,
47                                     NULL,
48                                     0,
49                                     szPath.ptr)))
50                         {
51                             fontsPath = toUTF8(fromWStringz(szPath));
52                         }
53                     } else {
54                         if (GetWindowsDirectory(szPath.ptr, MAX_PATH - 1)) {
55                             fontsPath = toUTF8(fromWStringz(szPath));
56                             Log.i("Windows directory: ", fontsPath);
57                             fontsPath ~= "\\Fonts\\";
58                             Log.i("Fonts directory: ", fontsPath);
59                         }
60                     }
61                 }
62                 Log.v("Registering fonts");
63                 ftfontMan.registerFont(fontsPath ~ "arial.ttf",     FontFamily.SansSerif, "Arial", false, FontWeight.Normal);
64                 ftfontMan.registerFont(fontsPath ~ "arialbd.ttf",   FontFamily.SansSerif, "Arial", false, FontWeight.Bold);
65                 ftfontMan.registerFont(fontsPath ~ "arialbi.ttf",   FontFamily.SansSerif, "Arial", true, FontWeight.Bold);
66                 ftfontMan.registerFont(fontsPath ~ "ariali.ttf",    FontFamily.SansSerif, "Arial", true, FontWeight.Normal);
67                 ftfontMan.registerFont(fontsPath ~ "cour.ttf",      FontFamily.MonoSpace, "Courier New", false, FontWeight.Normal);
68                 ftfontMan.registerFont(fontsPath ~ "courbd.ttf",    FontFamily.MonoSpace, "Courier New", false, FontWeight.Bold);
69                 ftfontMan.registerFont(fontsPath ~ "courbi.ttf",    FontFamily.MonoSpace, "Courier New", true, FontWeight.Bold);
70                 ftfontMan.registerFont(fontsPath ~ "couri.ttf",     FontFamily.MonoSpace, "Courier New", true, FontWeight.Normal);
71                 ftfontMan.registerFont(fontsPath ~ "times.ttf",     FontFamily.Serif, "Times New Roman", false, FontWeight.Normal);
72                 ftfontMan.registerFont(fontsPath ~ "timesbd.ttf",   FontFamily.Serif, "Times New Roman", false, FontWeight.Bold);
73                 ftfontMan.registerFont(fontsPath ~ "timesbi.ttf",   FontFamily.Serif, "Times New Roman", true, FontWeight.Bold);
74                 ftfontMan.registerFont(fontsPath ~ "timesi.ttf",    FontFamily.Serif, "Times New Roman", true, FontWeight.Normal);
75                 ftfontMan.registerFont(fontsPath ~ "consola.ttf",   FontFamily.MonoSpace, "Consolas", false, FontWeight.Normal);
76                 ftfontMan.registerFont(fontsPath ~ "consolab.ttf",  FontFamily.MonoSpace, "Consolas", false, FontWeight.Bold);
77                 ftfontMan.registerFont(fontsPath ~ "consolai.ttf",  FontFamily.MonoSpace, "Consolas", true, FontWeight.Normal);
78                 ftfontMan.registerFont(fontsPath ~ "consolaz.ttf",  FontFamily.MonoSpace, "Consolas", true, FontWeight.Bold);
79                 ftfontMan.registerFont(fontsPath ~ "verdana.ttf",   FontFamily.SansSerif, "Verdana", false, FontWeight.Normal);
80                 ftfontMan.registerFont(fontsPath ~ "verdanab.ttf",  FontFamily.SansSerif, "Verdana", false, FontWeight.Bold);
81                 ftfontMan.registerFont(fontsPath ~ "verdanai.ttf",  FontFamily.SansSerif, "Verdana", true, FontWeight.Normal);
82                 ftfontMan.registerFont(fontsPath ~ "verdanaz.ttf",  FontFamily.SansSerif, "Verdana", true, FontWeight.Bold);
83                 if (ftfontMan.registeredFontCount()) {
84                     FontManager.instance = ftfontMan;
85                 } else {
86                     Log.w("No fonts registered in FreeType font manager. Disabling FreeType.");
87                     destroy(ftfontMan);
88                 }
89             }
90         } catch (Exception e) {
91             Log.e("Cannot create FreeTypeFontManager - falling back to win32");
92         }
93 
94         // use Win32 font manager
95         if (FontManager.instance is null) {
96             FontManager.instance = new Win32FontManager();
97         }
98         return true;
99     }
100 
101 } else {
102     import dlangui.graphics.ftfonts;
103     bool registerFonts(FreeTypeFontManager ft, string path) {
104         import std.file;
105         if (!exists(path) || !isDir(path))
106             return false;
107         ft.registerFont(path ~ "DejaVuSans.ttf", FontFamily.SansSerif, "DejaVuSans", false, FontWeight.Normal);
108         ft.registerFont(path ~ "DejaVuSans-Bold.ttf", FontFamily.SansSerif, "DejaVuSans", false, FontWeight.Bold);
109         ft.registerFont(path ~ "DejaVuSans-Oblique.ttf", FontFamily.SansSerif, "DejaVuSans", true, FontWeight.Normal);
110         ft.registerFont(path ~ "DejaVuSans-BoldOblique.ttf", FontFamily.SansSerif, "DejaVuSans", true, FontWeight.Bold);
111         ft.registerFont(path ~ "DejaVuSansMono.ttf", FontFamily.MonoSpace, "DejaVuSansMono", false, FontWeight.Normal);
112         ft.registerFont(path ~ "DejaVuSansMono-Bold.ttf", FontFamily.MonoSpace, "DejaVuSansMono", false, FontWeight.Bold);
113         ft.registerFont(path ~ "DejaVuSansMono-Oblique.ttf", FontFamily.MonoSpace, "DejaVuSansMono", true, FontWeight.Normal);
114         ft.registerFont(path ~ "DejaVuSansMono-BoldOblique.ttf", FontFamily.MonoSpace, "DejaVuSansMono", true, FontWeight.Bold);
115         return true;
116     }
117 
118 	string[] findFontsInDirectory(string dir) {
119 		import dlangui.core.files;
120 		import std.file : DirEntry;
121 		DirEntry[] entries;
122         try {
123             entries = listDirectory(dir, AttrFilter.files, ["*.ttf"]);
124         } catch(Exception e) {
125             return null;
126         }
127 
128 		string[] res;
129 		foreach(entry; entries) {
130 			res ~= entry.name;
131 		}
132 		return res;
133 	}
134 
135 	void registerFontsFromDirectory(FreeTypeFontManager ft, string dir) {
136 		string[] fontFiles = findFontsInDirectory(dir);
137 		Log.d("Fonts in ", dir, " : ", fontFiles);
138 		foreach(file; fontFiles)
139 			ft.registerFont(file);
140 	}
141 
142     /// initialize font manager - default implementation
143     /// On win32 - first it tries to init freetype, and falls back to win32 fonts.
144     /// On linux/mac - tries to init freetype with some hardcoded font paths
145     extern(C) bool initFontManager() {
146         FreeTypeFontManager ft = new FreeTypeFontManager();
147 
148         if (!registerFontConfigFonts(ft)) {
149             // TODO: use FontConfig
150             Log.w("No fonts found using FontConfig. Trying hardcoded paths.");
151 			version (Android) {
152 				ft.registerFontsFromDirectory("/system/fonts");
153 			} else {
154 	            ft.registerFonts("/usr/share/fonts/truetype/dejavu/");
155 	            ft.registerFonts("/usr/share/fonts/TTF/");
156 	            ft.registerFonts("/usr/share/fonts/dejavu/");
157 	            ft.registerFonts("/usr/share/fonts/truetype/ttf-dejavu/"); // let it compile on Debian Wheezy
158 			}
159             version(OSX) {
160                 ft.registerFont("/Library/Fonts/Arial.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Normal, true);
161                 ft.registerFont("/Library/Fonts/Arial Bold.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Bold, true);
162                 ft.registerFont("/Library/Fonts/Arial Italic.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Normal, true);
163                 ft.registerFont("/Library/Fonts/Arial Bold Italic.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Bold, true);
164                 ft.registerFont("/Library/Fonts/Arial.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Normal, true);
165                 ft.registerFont("/Library/Fonts/Arial Bold.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Bold, true);
166                 ft.registerFont("/Library/Fonts/Arial Italic.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Normal, true);
167                 ft.registerFont("/Library/Fonts/Arial Bold Italic.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Bold, true);
168                 ft.registerFont("/Library/Fonts/Arial Narrow.ttf", FontFamily.SansSerif, "Arial Narrow", false, FontWeight.Normal, true);
169                 ft.registerFont("/Library/Fonts/Arial Narrow Bold.ttf", FontFamily.SansSerif, "Arial Narrow", false, FontWeight.Bold, true);
170                 ft.registerFont("/Library/Fonts/Arial Narrow Italic.ttf", FontFamily.SansSerif, "Arial Narrow", true, FontWeight.Normal, true);
171                 ft.registerFont("/Library/Fonts/Arial Narrow Bold Italic.ttf", FontFamily.SansSerif, "Arial Narrow", true, FontWeight.Bold, true);
172                 ft.registerFont("/Library/Fonts/Courier New.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Normal, true);
173                 ft.registerFont("/Library/Fonts/Courier New Bold.ttf", FontFamily.MonoSpace, "Courier New", false, FontWeight.Bold, true);
174                 ft.registerFont("/Library/Fonts/Courier New Italic.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Normal, true);
175                 ft.registerFont("/Library/Fonts/Courier New Bold Italic.ttf", FontFamily.MonoSpace, "Courier New", true, FontWeight.Bold, true);
176                 ft.registerFont("/Library/Fonts/Georgia.ttf", FontFamily.Serif, "Georgia", false, FontWeight.Normal, true);
177                 ft.registerFont("/Library/Fonts/Georgia Bold.ttf", FontFamily.Serif, "Georgia", false, FontWeight.Bold, true);
178                 ft.registerFont("/Library/Fonts/Georgia Italic.ttf", FontFamily.Serif, "Georgia", true, FontWeight.Normal, true);
179                 ft.registerFont("/Library/Fonts/Georgia Bold Italic.ttf", FontFamily.Serif, "Georgia", true, FontWeight.Bold, true);
180                 ft.registerFont("/Library/Fonts/Comic Sans MS.ttf", FontFamily.SansSerif, "Comic Sans", false, FontWeight.Normal, true);
181                 ft.registerFont("/Library/Fonts/Comic Sans MS Bold.ttf", FontFamily.SansSerif, "Comic Sans", false, FontWeight.Bold, true);
182                 ft.registerFont("/Library/Fonts/Tahoma.ttf", FontFamily.SansSerif, "Tahoma", false, FontWeight.Normal, true);
183                 ft.registerFont("/Library/Fonts/Tahoma Bold.ttf", FontFamily.SansSerif, "Tahoma", false, FontWeight.Bold, true);
184 
185                 ft.registerFont("/Library/Fonts/Microsoft/Arial.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Normal, true);
186                 ft.registerFont("/Library/Fonts/Microsoft/Arial Bold.ttf", FontFamily.SansSerif, "Arial", false, FontWeight.Bold, true);
187                 ft.registerFont("/Library/Fonts/Microsoft/Arial Italic.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Normal, true);
188                 ft.registerFont("/Library/Fonts/Microsoft/Arial Bold Italic.ttf", FontFamily.SansSerif, "Arial", true, FontWeight.Bold, true);
189                 ft.registerFont("/Library/Fonts/Microsoft/Calibri.ttf", FontFamily.SansSerif, "Calibri", false, FontWeight.Normal, true);
190                 ft.registerFont("/Library/Fonts/Microsoft/Calibri Bold.ttf", FontFamily.SansSerif, "Calibri", false, FontWeight.Bold, true);
191                 ft.registerFont("/Library/Fonts/Microsoft/Calibri Italic.ttf", FontFamily.SansSerif, "Calibri", true, FontWeight.Normal, true);
192                 ft.registerFont("/Library/Fonts/Microsoft/Calibri Bold Italic.ttf", FontFamily.SansSerif, "Calibri", true, FontWeight.Bold, true);
193                 ft.registerFont("/Library/Fonts/Microsoft/Times New Roman.ttf", FontFamily.Serif, "Times New Roman", false, FontWeight.Normal, true);
194                 ft.registerFont("/Library/Fonts/Microsoft/Times New Roman Bold.ttf", FontFamily.Serif, "Times New Roman", false, FontWeight.Bold, true);
195                 ft.registerFont("/Library/Fonts/Microsoft/Times New Roman Italic.ttf", FontFamily.Serif, "Times New Roman", true, FontWeight.Normal, true);
196                 ft.registerFont("/Library/Fonts/Microsoft/Times New Roman Bold Italic.ttf", FontFamily.Serif, "Times New Roman", true, FontWeight.Bold, true);
197                 ft.registerFont("/Library/Fonts/Microsoft/Verdana.ttf", FontFamily.SansSerif, "Verdana", false, FontWeight.Normal, true);
198                 ft.registerFont("/Library/Fonts/Microsoft/Verdana Bold.ttf", FontFamily.SansSerif, "Verdana", false, FontWeight.Bold, true);
199                 ft.registerFont("/Library/Fonts/Microsoft/Verdana Italic.ttf", FontFamily.SansSerif, "Verdana", true, FontWeight.Normal, true);
200                 ft.registerFont("/Library/Fonts/Microsoft/Verdana Bold Italic.ttf", FontFamily.SansSerif, "Verdana", true, FontWeight.Bold, true);
201 
202                 ft.registerFont("/Library/Fonts/Microsoft/Consolas.ttf", FontFamily.MonoSpace, "Consolas", false, FontWeight.Normal, true);
203                 ft.registerFont("/Library/Fonts/Microsoft/Consolas Bold.ttf", FontFamily.MonoSpace, "Consolas", false, FontWeight.Bold, true);
204                 ft.registerFont("/Library/Fonts/Microsoft/Consolas Italic.ttf", FontFamily.MonoSpace, "Consolas", true, FontWeight.Normal, true);
205                 ft.registerFont("/Library/Fonts/Microsoft/Consolas Bold Italic.ttf", FontFamily.MonoSpace, "Consolas", true, FontWeight.Bold, true);
206 
207                 ft.registerFont("/System/Library/Fonts/Menlo.ttc", FontFamily.MonoSpace, "Menlo", false, FontWeight.Normal, true);
208             }
209         }
210 
211         if (!ft.registeredFontCount)
212             return false;
213 
214         FontManager.instance = ft;
215         return true;
216     }
217 }
218 }
219 
220 /// initialize logging (for win32 - to file ui.log, for other platforms - stderr; log level is TRACE for debug builds, and WARN for release builds)
221 extern (C) void initLogs() {
222     static if (BACKEND_CONSOLE) {
223         static import std.stdio;
224         debug {
225             Log.setFileLogger(new std.stdio.File("ui.log", "w"));
226             Log.i("Debug build. Logging to file ui.log");
227             Log.setLogLevel(LogLevel.Trace);
228         } else {
229             // no logging unless version ForceLogs is set
230             version(ForceLogs) {
231                 Log.setFileLogger(new std.stdio.File("ui.log", "w"));
232                 Log.i("Logging to file ui.log");
233                 //Log.setLogLevel(LogLevel.Trace);
234             }
235         }
236     } else {
237         static import std.stdio;
238         version (Windows) {
239             debug {
240                 Log.setFileLogger(new std.stdio.File("ui.log", "w"));
241             } else {
242                 // no logging unless version ForceLogs is set
243                 version(ForceLogs) {
244                     Log.setFileLogger(new std.stdio.File("ui.log", "w"));
245                     Log.i("Logging to file ui.log");
246                 }
247             }
248         } else version(Android) {
249             Log.setLogTag("dlangui");
250             Log.setLogLevel(LogLevel.Trace);
251         } else {
252             Log.setStderrLogger();
253         }
254         debug {
255             Log.setLogLevel(LogLevel.Trace);
256         } else {
257             version(ForceLogs) {
258                 Log.setLogLevel(LogLevel.Trace);
259                 Log.i("Log level: trace");
260             } else {
261                 Log.setLogLevel(LogLevel.Warn);
262                 Log.i("Log level: warn");
263             }
264         }
265     }
266     Log.i("Logger is initialized");
267 }
268 
269 /// call this on application initialization
270 extern (C) void initResourceManagers() {
271     Log.d("initResourceManagers()");
272     import dlangui.graphics.fonts;
273     _gamma65 = new glyph_gamma_table!65(1.0);
274     _gamma256 = new glyph_gamma_table!256(1.0);
275     static if (ENABLE_FREETYPE) {
276         import dlangui.graphics.ftfonts;
277         STD_FONT_FACES = [
278             "Arial": 12,
279             "Times New Roman": 12,
280             "Courier New": 10,
281             "DejaVu Serif": 10,
282             "DejaVu Sans": 10,
283             "DejaVu Sans Mono": 10,
284             "Liberation Serif": 11,
285             "Liberation Sans": 11,
286             "Liberation Mono": 11,
287             "Verdana": 10,
288             "Menlo": 13,
289             "Consolas": 12,
290             "DejaVuSansMono": 10,
291             "Lucida Sans Typewriter": 10,
292             "Lucida Console": 12,
293             "FreeMono": 8,
294             "FreeSans": 8,
295             "FreeSerif": 8,
296         ];
297     }
298     static if (ENABLE_OPENGL) {
299         import dlangui.graphics.gldrawbuf;
300         initGLCaches();
301     }
302     import dlangui.graphics.resources;
303     embedStandardDlangUIResources();
304     static if (BACKEND_GUI) {
305         _imageCache = new ImageCache();
306     }
307     _drawableCache = new DrawableCache();
308     static if (BACKEND_GUI) {
309         version (Windows) {
310             import dlangui.platforms.windows.win32fonts;
311             initWin32FontsTables();
312         }
313     }
314 
315     Log.d("Calling initSharedResourceManagers()");
316     initSharedResourceManagers();
317 
318     Log.d("Calling initStandardEditorActions()");
319     import dlangui.widgets.editors;
320     initStandardEditorActions();
321 
322     Log.d("Calling registerStandardWidgets()");
323     registerStandardWidgets();
324 
325 
326     Log.d("initResourceManagers() -- finished");
327 }
328 
329 /// register standard widgets to use in DML
330 void registerStandardWidgets() {
331     Log.d("Registering standard widgets for DML");
332     import dlangui.widgets.metadata;
333     import dlangui.widgets.widget;
334     import dlangui.widgets.layouts;
335     import dlangui.widgets.controls;
336     import dlangui.widgets.scrollbar;
337     import dlangui.widgets.lists;
338     import dlangui.widgets.combobox;
339     import dlangui.widgets.editors;
340     import dlangui.widgets.grid;
341     import dlangui.widgets.groupbox;
342     import dlangui.widgets.progressbar;
343     import dlangui.dialogs.filedlg;
344     import dlangui.widgets.menu;
345     import dlangui.widgets.tree;
346     import dlangui.widgets.tabs;
347     mixin(registerWidgets!(FileNameEditLine, DirEditLine, //dlangui.dialogs.filedlg
348                            ComboBox, ComboEdit, //dlangui.widgets.combobox
349                            Widget, TextWidget, MultilineTextWidget, Button, ImageWidget, ImageButton, ImageCheckButton, ImageTextButton,
350                            SwitchButton, RadioButton, CheckBox, HSpacer, VSpacer, CanvasWidget, // dlangui.widgets.controls
351                            ScrollBar, SliderWidget, // dlangui.widgets.scrollbar
352                            EditLine, EditBox, LogWidget,//dlangui.widgets.editors
353                            GroupBox, // dlangui.widgets.groupbox
354                            ProgressBarWidget, // dlangui.widgets.progressbar
355                            StringGridWidget, //dlangui.widgets.grid
356                            VerticalLayout, HorizontalLayout, TableLayout, FrameLayout, // dlangui.widgets.layouts
357                            ListWidget, StringListWidget,//dlangui.widgets.lists
358                            MainMenu, //dlangui.widgets.menu
359                            TreeWidget, // dlangui.widgets.tree
360                            TabWidget, // dlangui.widgets.tabs
361                            )("void registerWidgets"));
362     registerWidgets();
363 }
364 
365 /// call this from shared static this()
366 extern (C) void initSharedResourceManagers() {
367     //Log.d("initSharedResourceManagers()");
368     //import dlangui.core.i18n;
369     //if (!i18n) {
370     //    Log.d("Creating i18n object");
371     //    i18n = new shared UIStringTranslator();
372     //}
373 }
374 
375 shared static this() {
376     //initSharedResourceManagers();
377 }
378 
379 /// call this when all resources are supposed to be freed to report counts of non-freed resources by type
380 extern (C) void releaseResourcesOnAppExit() {
381 
382     //
383     debug setAppShuttingDownFlag();
384 
385     debug {
386         if (Widget.instanceCount() > 0) {
387             Log.e("Non-zero Widget instance count when exiting: ", Widget.instanceCount);
388         }
389     }
390 
391     currentTheme = null;
392     drawableCache = null;
393     static if (BACKEND_GUI) {
394         imageCache = null;
395     }
396     FontManager.instance = null;
397     static if (ENABLE_OPENGL) {
398         import dlangui.graphics.gldrawbuf;
399         destroyGLCaches();
400     }
401 
402     debug {
403         if (DrawBuf.instanceCount > 0) {
404             Log.e("Non-zero DrawBuf instance count when exiting: ", DrawBuf.instanceCount);
405         }
406         if (Style.instanceCount > 0) {
407             Log.e("Non-zero Style instance count when exiting: ", Style.instanceCount);
408         }
409         if (ImageDrawable.instanceCount > 0) {
410             Log.e("Non-zero ImageDrawable instance count when exiting: ", ImageDrawable.instanceCount);
411         }
412         if (Drawable.instanceCount > 0) {
413             Log.e("Non-zero Drawable instance count when exiting: ", Drawable.instanceCount);
414         }
415         static if (ENABLE_FREETYPE) {
416             import dlangui.graphics.ftfonts;
417             if (FreeTypeFontFile.instanceCount > 0) {
418                 Log.e("Non-zero FreeTypeFontFile instance count when exiting: ", FreeTypeFontFile.instanceCount);
419             }
420             if (FreeTypeFont.instanceCount > 0) {
421                 Log.e("Non-zero FreeTypeFont instance count when exiting: ", FreeTypeFont.instanceCount);
422             }
423         }
424     }
425 }
426 
427 version(unittest) {
428     version (Windows) {
429         mixin APP_ENTRY_POINT;
430 
431         /// entry point for dlangui based application
432         extern (C) int UIAppMain(string[] args) {
433             // just to enable running unit tests
434             import core.runtime;
435             import std.stdio;
436             if (!runModuleUnitTests()) {
437                 writeln("Error occured in unit tests. Press enter.");
438                 readln();
439                 return 1;
440             }
441             return 0;
442         }
443     }
444 }
445 
446