1 module unde.global_state;
2 
3 import unde.lib;
4 import unde.lsblk;
5 import unde.clickable;
6 import unde.path_mnt;
7 import unde.font;
8 import unde.marks;
9 import unde.slash;
10 import unde.command_line.lib;
11 import unde.file_manager.events;
12 import unde.keybar.lib;
13 import unde.keybar.settings;
14 import unde.guitk.lib;
15 
16 import std.format;
17 import std.conv;
18 import std.stdio;
19 import core.stdc.stdlib;
20 import core.stdc..string;
21 import core.stdc.errno;
22 import core.thread;
23 version (Posix)
24 {
25 	import core.sys.posix.unistd: fork;
26 }
27 import core.sys.posix.sys.ioctl;
28 import std..string;
29 import std.concurrency;
30 import std.datetime;
31 import std.math;
32 import std.container.slist;
33 import std.regex;
34 import std.exception;
35 import std.process;
36 
37 import berkeleydb.all;
38 import derelict.sdl2.sdl;
39 import derelict.sdl2.ttf;
40 import derelict.sdl2.image;
41 
42 version (Windows)
43 {
44 	struct winsize
45 	{
46 	    int ws_col;
47 	    int ws_row;
48 	    int ws_xpixel;
49 	    int ws_ypixel;
50 	}
51 }
52 
53 public import core.sys.posix.sys.types;
54 
55 import std.file;
56 
57 struct Texture_Tick
58 {
59     int w, h;
60     SDL_Rect[] chars;
61     SDL_Texture* texture;
62     long tick;
63 }
64 
65 mixin template init_deinitBDB(bool main_thread = false)
66 {
67     DbEnv dbenv;
68     Db db_map;
69     Db db_marks;
70     Db db_commands;
71     Db db_command_output;
72 
73     void initBDB(bool force_recover = false)
74     {
75         string home = environment["HOME"];
76         version(Windows)
77         {
78 	    if (!home.startsWith("C:\\cygwin\\home") &&
79 			!home.startsWith("D:\\cygwin\\home") &&
80             !home.startsWith("C:\\cygwin64\\home") &&
81 			!home.startsWith("D:\\cygwin64\\home"))
82             {
83                 throw new Exception("Please run under Cygwin environment. Read README.");
84             }
85         }
86 
87         try{
88             mkdir(home ~ "/.unde");
89         } catch (Exception file)
90         {
91         }
92 
93         try{
94             mkdir(home ~ "/.unde/bdb/");
95         } catch (Exception file)
96         {
97         }
98 
99         bool recover = force_recover;
100         bool goto_recover = false;
101 recover:
102         if (main_thread)
103         {
104             if (recover)
105             {
106                 writefln("Open Database. Recover mode enabled. Please wait...");
107             }
108             else
109             {
110                 writefln("Open Database. If it takes long, try `./unde --force_recover`");
111             }
112         }
113 
114         dbenv = new DbEnv(0);
115 
116         dbenv.log_set_config(DB_LOG_AUTO_REMOVE, 1);
117         dbenv.set_memory_max(16*1024*1024);
118         dbenv.set_lk_detect(DB_LOCK_MAXLOCKS);
119 
120         uint env_flags = DB_CREATE |    /* Create the environment if it does 
121                                     * not already exist. */
122                     DB_INIT_TXN  | /* Initialize transactions */
123                     DB_INIT_LOCK | /* Initialize locking. */
124                     DB_INIT_LOG  | /* Initialize logging */
125                     DB_INIT_MPOOL| /* Initialize the in-memory cache. */
126                     (recover?DB_RECOVER:0);
127 
128         dbenv.open(home ~ "/.unde/bdb/", env_flags, octal!666);
129 
130         db_map = new Db(dbenv, 0);
131         db_map.open(null, "map.db", null, DB_BTREE, DB_CREATE | 
132                         DB_AUTO_COMMIT /*| DB_MULTIVERSION*/, octal!600);
133 
134         db_marks = new Db(dbenv, 0);
135         db_marks.open(null, "marks.db", null, DB_BTREE, DB_CREATE | 
136                         DB_AUTO_COMMIT /*| DB_MULTIVERSION*/, octal!600);
137 
138         db_commands = new Db(dbenv, 0);
139         db_commands.open(null, "commands.db", null, DB_BTREE, DB_CREATE | 
140                         DB_AUTO_COMMIT /*| DB_MULTIVERSION*/, octal!600);
141 
142         db_command_output = new Db(dbenv, 0);
143         db_command_output.open(null, "command_output.db", null, DB_BTREE, DB_CREATE | 
144                         DB_AUTO_COMMIT /*| DB_MULTIVERSION*/, octal!600);
145 
146         txn = dbenv.txn_begin(null);
147 
148         try
149         {
150             Dbt key, data;
151             string opened_str = "opened";
152             key = opened_str;
153 
154             int opened = 0;
155 
156             if (!main_thread || !recover)
157             {
158                 auto res = db_marks.get(txn, &key, &data);
159                 if (res == 0)
160                 {
161                     opened = data.to!int;
162                 }
163             }
164 
165             if (main_thread && opened != 0 && !recover)
166             {
167                 recover = true;
168                 txn.abort();
169                 txn = null;
170                 db_command_output.close();
171                 db_commands.close();
172                 db_marks.close();
173                 db_map.close();
174                 dbenv.close();
175                 goto recover;
176             }
177 
178             opened++;
179             data = opened;
180             auto res = db_marks.put(txn, &key, &data);
181             if (res != 0)
182             {
183                 throw new Exception("Oh, no, can't to write new value of opened");
184             }
185         }
186         catch (Exception exp)
187         {
188             goto_recover = true;
189         }
190 
191         if (main_thread && !recover && goto_recover)
192         {
193             recover = true;
194             txn.abort();
195             txn = null;
196             db_command_output.close();
197             db_commands.close();
198             db_marks.close();
199             db_map.close();
200             dbenv.close();
201             goto recover;
202         }
203 
204         txn.commit();
205         txn = null;
206 
207         if (main_thread)
208         {
209             writefln("Clean logs.");
210             dbenv.log_archive(DB_ARCH_REMOVE);
211             writefln("Database opened.");
212         }
213     }
214 
215     void deInitBDB()
216     {
217         if (txn)
218         {
219             txn.abort();
220             txn = null;
221         }
222         txn = dbenv.txn_begin(null);
223         try
224         {
225             Dbt key, data;
226             string opened_str = "opened";
227             key = opened_str;
228 
229             int opened = 0;
230 
231             auto res = db_marks.get(txn, &key, &data);
232             if (res == 0)
233             {
234                 opened = data.to!int;
235             }
236 
237             opened--;
238 
239             data = opened;
240             res = db_marks.put(txn, &key, &data);
241             if (res != 0)
242             {
243                 throw new Exception("Oh, no, can't to write new value of opened");
244             }
245         }
246         catch (Exception exp)
247         {
248         }
249 
250         txn.commit();
251         txn = null;
252 
253         db_command_output.close();
254         db_commands.close();
255         db_marks.close();
256         db_map.close();
257         dbenv.close();
258         dbenv = null;
259         db_command_output = null;
260         db_commands = null;
261         db_marks = null;
262         db_map = null;
263     }
264 }
265 
266 mixin template recommit()
267 {
268     bool txn_on = true;
269     DbTxn txn;
270     int OIT; // operations in transaction
271     long beginned;
272     SysTime txn_started;
273 
274     bool is_time_to_recommit()
275     {
276         if (!txn_on) return false;
277         return OIT > 100 || OIT > 0 && (Clock.currTime() - txn_started) > 200.msecs;
278     }
279 
280     void recommit()
281     {
282         if (!txn_on) return;
283         if (OIT > 100 || OIT > 0 && (Clock.currTime() - txn_started) > 200.msecs)
284         {
285             commit();
286         }
287         if (txn is null)
288         {
289             txn = dbenv.txn_begin(null);
290             txn_started = Clock.currTime();
291         }
292     }
293 
294     void commit()
295     {
296         if (!txn_on) return;
297         //writefln("Tid=%s, OIT=%d, time=%s", thisTid, OIT, Clock.currTime() - txn_started);
298         if (txn !is null)
299         {
300             txn.commit();
301             txn = null;
302             OIT = 0;
303         }
304     }
305 
306     void abort()
307     {
308         //writefln("Tid=%s, OIT=%d, time=%s", thisTid, OIT, Clock.currTime() - txn_started);
309         if (txn !is null)
310         {
311             txn.abort();
312             txn = null;
313             OIT = 0;
314         }
315     }
316 }
317 
318 struct CopyMapInfo
319 {
320     string path;
321     bool[Tid] sent;
322     bool move;
323     Tid from;
324 }
325 
326 class ScannerGlobalState
327 {
328     LsblkInfo[string] lsblk;
329     CopyMapInfo[string] copy_map;
330     Tid parent_tid;
331     bool finish;
332     bool one_level;
333 
334     mixin init_deinitBDB;
335     mixin recommit;
336 
337     this()
338     {
339         initBDB();
340     }
341 
342     ~this()
343     {
344         deInitBDB();
345     }
346 }
347 
348 class FMGlobalState
349 {
350     LsblkInfo[string] lsblk;
351     bool finish;
352 
353     mixin init_deinitBDB;
354     mixin recommit;
355 
356     this()
357     {
358         initBDB();
359     }
360 
361     ~this()
362     {
363         deInitBDB();
364     }
365 }
366 
367 class CMDGlobalState
368 {
369     bool finish;
370 
371     mixin init_deinitBDB;
372     mixin recommit;
373 
374     this()
375     {
376         initBDB();
377     }
378 
379     ~this()
380     {
381         deInitBDB();
382     }
383 }
384 
385 enum NameType
386 {
387     CreateDirectory,
388     Copy,
389     Move
390 }
391 
392 struct EnterName
393 {
394     NameType type;
395     string name;
396     int pos;
397 }
398 
399 struct AnimationInfo
400 {
401     NameType type;
402     int stage;
403     string parent;
404     bool from_calculated;
405     bool to_calculated;
406     SDL_Rect from;
407     SDL_Rect to;
408     long last_frame_time;
409     double frame = 0.0;
410 }
411 
412 struct RepeatStuffs
413 {
414     long start_press;
415     long last_process;
416     SDL_Event event;
417 }
418 
419 struct ConsoleMessage
420 {
421     SDL_Color color;
422     string message;
423     uint from;
424     SDL_Texture *texture;
425     int w, h;
426 }
427 
428 enum State
429 {
430     FileManager,
431     ImageViewer,
432     TextViewer
433 }
434 
435 struct Image_Viewer_State{
436     PathMnt path;
437     SDL_Rect rect;
438     Texture_Tick *texture_tick;
439     RectSize rectsize;
440 
441     ssize_t level;
442     ssize_t[] positions;
443     string[][] files;
444     ssize_t sel;
445     string[] selections;
446 
447     long last_image_cache_use;
448     Texture_Tick[string] image_cache;
449 };
450 
451 struct Text_Viewer_State{
452     PathMnt path;
453     int fontsize = 9;
454     bool wraplines;
455     int x, y;
456     RectSize rectsize;
457 
458     ssize_t level;
459     ssize_t[] positions;
460     string[][] files;
461     ssize_t sel;
462     string[] selections;
463 
464     long last_redraw;
465     SDL_Texture *texture;
466 
467     ssize_t mouse_offset;
468     ssize_t start_selection;
469     ssize_t end_selection;
470     ssize_t first_click;
471 
472     Font font;
473 }
474 
475 struct CmdOutPos
476 {
477     ulong cmd_id;
478     ulong out_id;
479     ssize_t pos;
480 
481     int opCmp(CmdOutPos rhs)
482     {
483         if (cmd_id > rhs.cmd_id)
484             return 1;
485         else if (cmd_id < rhs.cmd_id)
486             return -1;
487         else
488         {
489             if (out_id > rhs.out_id)
490                 return 1;
491             else if (out_id < rhs.out_id)
492                 return -1;
493             else
494             {
495                 if (pos > rhs.pos)
496                     return 1;
497                 if (pos < rhs.pos)
498                     return -1;
499                 else
500                     return 0;
501             }
502         }
503     }
504 
505 }
506 
507 struct Command_Line_State{
508     int fontsize = 9;
509     bool font_changed;
510 
511     bool enter;
512     string command;
513     string complete;
514     string edited_command;
515     ssize_t pos;
516 
517     string cwd;
518     ulong hist_cmd_id;
519     ssize_t hist_pos;
520 
521     ulong nav_skip_cmd_id;
522     ulong nav_cmd_id;
523     ulong nav_out_id;
524 
525     CmdOutPos mouse;
526     CmdOutPos first_click;
527     CmdOutPos start_selection;
528     CmdOutPos end_selection;
529 
530     ssize_t cmd_mouse_pos;
531     ssize_t cmd_first_click;
532     ssize_t cmd_start_selection = -1;
533     ssize_t cmd_end_selection = -1;
534     SDL_Rect cmd_rect;
535 
536     double mouse_rel_y;
537     long y;
538     long neg_y;
539 
540     long last_enter;
541 
542     bool terminal;
543 
544     bool just_started_input;
545 
546     long last_redraw;
547     SDL_Texture *texture;
548 
549     Tid command_in_focus_tid;
550     ulong command_in_focus_id;
551 
552     long last_left_click;
553     long last_right_click;
554     long last_ctrl;
555     int moved_while_click;
556 
557     void delegate() on_click;
558 
559     bool ctrl_mode;
560     bool search_mode;
561     string search;
562 
563     winsize ws;
564 }
565 
566 enum Modifiers
567 {
568     Left_Ctrl  = 0x0001,
569     Right_Ctrl = 0x0002,
570     Left_Shift = 0x0004,
571     Right_Shift= 0x0008,
572     Left_Alt   = 0x0010,
573     Right_Alt  = 0x0020,
574     CapsLock   = 0x0040,
575     Left_Win   = 0x0080,
576     Right_Win  = 0x0100,
577     Space      = 0x0200,
578     Menu       = 0x0400,
579     ScrollLock = 0x0800,
580 }
581 
582 class GlobalState
583 {
584 	SDL_Window* window;
585     SDL_Renderer* renderer;
586     SDL_Texture* surf_texture;
587     bool finish = false;
588     string start_cwd;
589     string[] args;
590     bool restart;
591     uint frame; //Frame which renders
592     uint time; //Time from start of program in ms
593     immutable msize = 128;
594 
595     string desktop;
596     string[string] mime_applications;
597     State state;
598     Image_Viewer_State image_viewer;
599     Text_Viewer_State text_viewer;
600     Command_Line_State command_line;
601     KeyBar_Buttons keybar;
602     UIPage[string] uipages;
603 
604     CoordinatesPlusScale screen;
605     double mousex, mousey;
606     int mouse_screen_x, mouse_screen_y;
607     long last_mouse_down;
608     long last_left_click;
609     long last_right_click;
610     long last_middle_click;
611     long last_key_press;
612     int key_press;
613     int moved_while_click;
614     uint flags;
615     uint mouse_buttons;
616     LsblkInfo[string] lsblk;
617 
618     SList!Clickable clickable_list;
619     SList!Clickable new_clickable_list;
620 
621     SList!Clickable double_clickable_list;
622     SList!Clickable new_double_clickable_list;
623 
624     SList!Clickable right_clickable_list;
625     SList!Clickable new_right_clickable_list;
626 
627     SList!Clickable double_right_clickable_list;
628     SList!Clickable new_double_right_clickable_list;
629 
630     SList!Clickable middle_clickable_list;
631     SList!Clickable new_middle_clickable_list;
632 
633     ulong msg_stamp; // RU: Время ранее которого сообщения считать просмотренными
634     ulong last_escape;
635 
636     Selection[] selection_list;
637     DRect[string] selection_hash;
638     bool[string] selection_sub;
639     int selection_lsof; //list size on finish
640     int selection_finish;
641     int selection_stage = 2;
642 
643     ConsoleMessage[] messages;
644 
645     bool[string] interface_flags;
646     bool dirty;
647     bool redraw_fast;
648 
649     Tid[] scanners;
650     Tid[string] rescanners;
651     string[][Tid] removers;
652     string[][Tid] copiers;
653     string[][Tid] movers;
654     string[][Tid] changers_rights;
655     string[Tid] commands;
656     ulong[Tid] delete_commands;
657     Tid[ulong] tid_by_command_id;
658     Pid[] pids;
659     CopyMapInfo[string] copy_map;
660     EnterName[string] enter_names;
661     AnimationInfo[string] animation_info;
662     RepeatStuffs repeat;
663 
664     bool mark;
665     bool gomark;
666     bool unmark;
667     ushort modifiers;
668     @property bool ctrl() { return (modifiers & (Modifiers.Left_Ctrl | Modifiers.Right_Ctrl)) != 0; }
669     @property bool shift() { return (modifiers & (Modifiers.Left_Shift | Modifiers.Right_Shift)) != 0; }
670     @property bool alt() { return (modifiers & (Modifiers.Left_Alt)) != 0; }
671     @property bool alt_gr() { return (modifiers & (Modifiers.Right_Alt)) != 0; }
672     bool shift_copy_or_move;
673     DRect  current_path_rect;
674     string current_path;
675     string full_current_path;
676     string main_path = SL;
677     PathMnt path;
678     DRect apply_rect;
679     SortType sort;
680     CoordinatesPlusScale surf;
681     SDL_Texture* texture;
682     SDL_Texture* texture_white;
683     SDL_Texture* texture_black;
684     SDL_Texture* texture_blue;
685     SDL_Texture* texture_cursor;
686     SDL_Texture* texture_gray;
687     Gradient grad;
688 
689     void createWindow()
690     {
691         //The window we'll be rendering to
692         window = SDL_CreateWindow(
693             "unDE",                            // window title
694             SDL_WINDOWPOS_UNDEFINED,           // initial x position
695             SDL_WINDOWPOS_UNDEFINED,           // initial y position
696             0,                                 // width, in pixels
697             0,                                 // height, in pixels
698             SDL_WINDOW_FULLSCREEN_DESKTOP | 
699             SDL_WINDOW_RESIZABLE               // flags
700         );
701         if( window == null )
702         {
703             throw new Exception(format("Error while create window: %s",
704                     SDL_GetError().to!string()));
705         }
706     }
707 
708     void createRenderer()
709     {
710         /* To render we need only renderer (which connected to window) and
711            surfaces to draw it */
712         renderer = SDL_CreateRenderer(
713                 window, 
714                 -1, 
715                 SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE
716         );
717         if (!renderer)
718         {
719             writefln("Error while create accelerated renderer: %s",
720                     SDL_GetError().to!string());
721             renderer = SDL_CreateRenderer(
722                     window, 
723                     -1, 
724                     SDL_RENDERER_TARGETTEXTURE
725             );
726         }
727         if (!renderer)
728         {
729             throw new Exception(format("Error while create renderer: %s",
730                     SDL_GetError().to!string()));
731         }
732 
733         int r = SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
734         if (r < 0)
735         {
736             throw new Exception(
737                     format("Error while set render draw blend mode: %s",
738                     SDL_GetError().to!string()));
739         }
740 
741         SDL_bool res = SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
742         if (!res)
743         {
744             throw new Exception(
745                     format("Can't set filter mode"));
746         }
747     }
748 
749     void createTextures()
750     {
751         SDL_Surface* surface = SDL_CreateRGBSurface(0,
752                 1,
753                 1,
754                 32, 0x00FF0000, 0X0000FF00, 0X000000FF, 0XFF000000);
755 
756         (cast(uint*) surface.pixels)[0] = 0x80FFFFFF;
757 
758         texture_white =
759             SDL_CreateTextureFromSurface(renderer, surface);
760 
761         (cast(uint*) surface.pixels)[0] = 0xAA000000;
762 
763         texture_black =
764             SDL_CreateTextureFromSurface(renderer, surface);
765 
766         (cast(uint*) surface.pixels)[0] = 0x800000FF;
767 
768         texture_blue =
769             SDL_CreateTextureFromSurface(renderer, surface);
770 
771         (cast(uint*) surface.pixels)[0] = 0xFFA0A0FF;
772 
773         texture_cursor =
774             SDL_CreateTextureFromSurface(renderer, surface);
775 
776         (cast(uint*) surface.pixels)[0] = 0x80808080;
777 
778         texture_gray =
779             SDL_CreateTextureFromSurface(renderer, surface);
780 
781         text_viewer.texture = SDL_CreateTexture(renderer,
782                 SDL_PIXELFORMAT_ARGB8888,
783                 SDL_TEXTUREACCESS_TARGET,
784                 screen.w,
785                 screen.h);
786         if( !text_viewer.texture )
787         {
788             throw new Exception(format("Error while creating text_viewer.texture: %s",
789                     SDL_GetError().to!string() ));
790         }
791 
792         command_line.texture = SDL_CreateTexture(renderer,
793                 SDL_PIXELFORMAT_ARGB8888,
794                 SDL_TEXTUREACCESS_TARGET,
795                 screen.w,
796                 screen.h);
797         if( !command_line.texture )
798         {
799             throw new Exception(format("Error while creating command_line.texture: %s",
800                     SDL_GetError().to!string() ));
801         }
802 
803         SDL_FreeSurface(surface);
804     }
805 
806     void initSDL()
807     {
808         DerelictSDL2.load();
809         
810         if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER ) < 0 )
811         {
812             throw new Exception(format("Error while SDL initializing: %s",
813                     SDL_GetError().to!string() ));
814         }
815 
816         createWindow();
817         createRenderer();
818 
819         SDL_GetWindowSize(window, &screen.w, &screen.h);
820         screen.w -= 192;
821 
822         createTextures();
823 
824         surf.w = 2*screen.w;
825         surf.h = 2*screen.h;
826         surf_texture = SDL_CreateTexture(renderer,
827                 SDL_PIXELFORMAT_ARGB8888,
828                 SDL_TEXTUREACCESS_TARGET,
829                 surf.w,
830                 surf.h);
831         if( !surf_texture )
832         {
833             throw new Exception(format("Error while creating surf_texture: %s",
834                     SDL_GetError().to!string() ));
835         }
836 
837         texture = SDL_CreateTexture(renderer,
838                 SDL_PIXELFORMAT_ARGB8888,
839                 SDL_TEXTUREACCESS_TARGET,
840                 surf.w,
841                 surf.h);
842         if( !texture )
843         {
844             throw new Exception(format("Error while creating surf_texture: %s",
845                     SDL_GetError().to!string() ));
846         }
847     }
848 
849     void deInitSDL()
850     {
851         SDL_DestroyTexture(text_viewer.texture),
852         SDL_DestroyTexture(texture_blue);
853         SDL_DestroyTexture(texture_black);
854         SDL_DestroyTexture(texture_white);
855         SDL_DestroyTexture(texture);
856         SDL_DestroyTexture(surf_texture);
857         SDL_DestroyRenderer(renderer);
858         SDL_DestroyWindow(window);
859         SDL_Quit();
860     }
861 
862     void initSDLImage()
863     {
864         DerelictSDL2Image.load();
865 
866         auto flags = IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF;
867         int initted = IMG_Init(flags);
868         if((initted&flags) != flags) {
869             if (!(IMG_INIT_JPG & initted))
870                 writefln("IMG_Init: Failed to init required jpg support!");
871             if (!(IMG_INIT_PNG & initted))
872                 writefln("IMG_Init: Failed to init required png support!");
873             if (!(IMG_INIT_TIF & initted))
874                 writefln("IMG_Init: Failed to init required tif support!");
875             throw new Exception(format("IMG_Init: %s\n",
876                         IMG_GetError().to!string()));
877         }
878     }
879 
880     void initSDLTTF()
881     {
882         text_viewer.font = new Font(renderer);
883     }
884 
885     void initAllSDLLibs()
886     {
887         initSDL();
888         initSDLImage();
889         initSDLTTF();
890     }
891 
892     void deInitAllSDLLibs()
893     {
894         IMG_Quit();
895         deInitSDL();
896     }
897 
898     mixin init_deinitBDB!true;
899     mixin recommit;
900 
901     void initGradient()
902     {
903         /* Gradient Initialize */
904         grad.add(SDL_Color(  0, 255, 255, 255), 0.0);
905         grad.add(SDL_Color(  0, 255,   0, 255), 3.0);
906         grad.add(SDL_Color(255, 255,   0, 255), 6.0);
907         grad.add(SDL_Color(255,   0,   0, 255), 9.0);
908         grad.add(SDL_Color(255,   0, 255, 255), 12.0);
909     }
910 
911     void initScreenAndSurf()
912     {
913         path = PathMnt(SL);
914         apply_rect = DRect(0, 0, 1024*1024, 1024*1024);
915 
916         screen.x = 0;
917         screen.y = 0;
918         screen.scale = 2 * 1024*1024 / screen.w;
919 
920         surf.x = 0;
921         surf.y = 0;
922         surf.scale = 1;
923     }
924 
925     void loadMimeApplications()
926     {
927         try
928         {
929             string home = environment["HOME"];
930             auto file = File(home ~ "/.unde/mime");
931             foreach (line; file.byLine())
932             {
933                 auto match = matchFirst(line, regex(`([^ ]*) *= *(.*)`));
934                 if (match)
935                 {
936                     mime_applications[match[1].idup()] = match[2].idup();
937                 }
938             }
939         }
940         catch(ErrnoException e)
941         {
942             writefln("~/.unde/mime NOT FOUND");
943             writefln(q{Example of line "text/plain = gvim"});
944         }
945     }
946 
947     void getCurrentDesktop()
948     {
949         string current_desktop = "current_desktop"; 
950         Dbt key = current_desktop;
951         Dbt data;
952 
953         auto res = db_marks.get(null, &key, &data);
954 
955         desktop = "1";
956         if (res == 0)
957         {
958             desktop = data.to!(string).idup();
959         }
960 
961 	if (desktop.length != 1 || desktop[0] < '0' || desktop[0] > '9')
962         {
963 	    writefln("WARNING! current_desktop = %s", desktop);
964             desktop = "1";
965         }
966 
967         go_mark(this, desktop);
968     }
969 
970     this(bool force_recover = false)
971     {
972         start_cwd = getcwd();
973         txn_on = false;
974         msg_stamp = Clock.currTime().toUnixTime();
975         initBDB(force_recover);
976         initAllSDLLibs();
977         initGradient();
978         initScreenAndSurf();
979         loadMimeApplications();
980         .lsblk(this.lsblk);
981         getCurrentDesktop();
982         update_winsize(this);
983         keybar = new KeyBar_Buttons(this, renderer, start_cwd);
984         setup_keybar_filemanager_default(this);
985         uipages["keybar_settings"] = create_keybar_settings_ui(this);
986     }
987 
988     ~this()
989     {
990         deInitBDB();
991         deInitAllSDLLibs();
992         if (restart)
993         {
994 	    version (Posix)
995 	    {
996 		    writefln("Restart");
997 		    int r = fork();
998 		    if (r < 0)
999 		    {
1000 			throw new Exception("fork() error: " ~ fromStringz(strerror(errno)).idup());
1001 		    }
1002 		    else if (r == 0)
1003 		    {
1004 			Thread.sleep(2.seconds);
1005 			chdir(start_cwd);
1006 			execv(args[0], args);
1007 			assert(0);
1008 		    }
1009 	    }
1010 	    else version (Windows)
1011 	    {
1012 		    writefln("Restart in windows version not supported. Exit.");
1013 	    }
1014         }
1015     }
1016 }
1017