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