ecere/gui: Alternate Timer leak fix: Stop all timers in GuiApplication's destructor
[sdk] / ecere / src / gui / Window.ec
1 namespace gui;
2
3 import "Display"
4
5 import "Anchor"
6 import "Key"
7 import "GuiApplication"
8 import "Interface"
9 import "Skin"
10 import "Timer"
11 import "Cursor"
12 import "ClipBoard"
13
14 import "Button"
15 import "ListBox"
16 import "DropBox"
17 import "Label"
18 import "Picture"
19 import "ScrollBar"
20 import "Button"
21 import "Menu"
22 import "StatusBar"
23 import "ProgressBar"
24 import "EditBox"
25 import "DataBox"
26 import "ToolTip"
27
28 #if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
29 import "Desktop3D"
30 #endif
31
32 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
33 import "FormDesigner"
34 #endif
35
36 import "FileDialog"
37 import "MessageBox"
38 import "WindowList"
39 import "i18n"
40
41 // Had to define this here for native decorations support, because the menu bar is part of total decoration's size, but not part of the system decorations
42 define skinMenuHeight = 25;
43 define statusBarHeight = 18;
44
45 default extern int __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
46
47 public enum DialogResult { cancel, yes, no, ok };
48
49 public class MouseButtons
50 {
51 public:
52    bool left:1, right:1, middle:1;
53 };
54
55 public struct SizeAnchor
56 {
57    Size size;
58    bool isClientW, isClientH;
59 };
60
61 #include <stdarg.h>
62
63 #define SNAPDOWN(x, d) \
64       if(Abs(x) % (d)) \
65       { \
66          if(x < 0) x -= ((d) - Abs(x) % (d)); else x -= x % (d); \
67       }
68
69 #define SNAPUP(x, d) \
70       if(Abs(x) % (d)) \
71       { \
72          if(x > 0) x += ((d) - Abs(x) % (d)); else x += x % (d); \
73       }
74
75 /*static */define MAX_DIRTY_BACK = 10;
76
77 /////////////////////////////////////////////////////////////////////////////
78 ////////// EXTENT MANIPULATION //////////////////////////////////////////////
79 /////////////////////////////////////////////////////////////////////////////
80
81 #define ACCESS_ITEM(l, id) \
82    id
83
84 #define FASTLIST_LOOP(l, v)      \
85    for(v = (BoxItem)l.first; v; v = (BoxItem)v.next)
86
87 #define FASTLIST_LOOPN(l, v, n) \
88    for(v = (BoxItem)l.first, n = (BoxItem)(v ? v.next : null); v; v = (BoxItem)next, n = (BoxItem)(v ? v.next : null))
89
90 /*
91 #define ACCESS_ITEM(l, id) \
92       ((FastItem)(((id) == -1) ? null : (((byte *)((l).items)) + (id) * (l).itemSize)))
93
94 #define FASTLIST_LOOP(l, v)      \
95    for(v = (void *)ACCESS_ITEM((l), (l).first); v; v = (void *)ACCESS_ITEM((l), v.next))
96
97 #define FASTLIST_LOOPN(l, v, n) \
98    for( v = (void *)ACCESS_ITEM((l), (l).first), \
99         n = v ? ((void *)ACCESS_ITEM((l), v.next)): null; \
100         v; v = n, n = n ? (void *)ACCESS_ITEM((l), n.next) : null)
101
102
103 private class FastItem : struct
104 {
105    int prev, next;
106 };
107
108 private struct FastList
109 {
110    FastItem items;
111    int first, last;
112    int free;
113    int count, size, itemSize;
114
115    void Clear(void)
116    {
117       count = 0;
118       size = 0;
119       items = null;
120       first = last = free = -1;
121       itemSize = 0;
122    }
123
124    void Empty(void)
125    {
126       FastItem item, next;
127       Free();
128       // FASTLIST_LOOPN(this, item, next) { Delete(item); };
129    }
130
131    FastItem Add(uint itemSize)
132    {
133       FastItem item;
134       if(free == -1 || !size)
135       {
136          int c;
137          int newSize;
138                
139          if(size)
140          {
141             newSize = (size + (size >> 1));
142             items = (FastItem)renew items byte[newSize * itemSize];
143          }
144          else
145          {
146             newSize = 4;
147             this.itemSize = itemSize;
148             items = (FastItem)new byte[newSize * itemSize];
149          }
150
151          for(c = size; c<newSize-1; c++)
152          {
153             ACCESS_ITEM(this, c).prev = -1;
154             ACCESS_ITEM(this, c).next = c+1;
155          }
156          ACCESS_ITEM(this, c).prev = -1;
157          ACCESS_ITEM(this, c).next = -1;
158          free = size;
159          size = newSize;
160       }
161       item = ACCESS_ITEM(this, free);
162       item.prev = last;
163       if(item.prev != -1)
164          ACCESS_ITEM(this, item.prev).next = free;
165       if(first == -1)
166          first = free;
167       last = free;
168       free = item.next;
169       item.next = -1;
170       count++;
171       return item;
172    }
173
174    void Delete(FastItem item)
175    {
176       if(item.prev != -1)
177          ACCESS_ITEM(this, item.prev).next = item.next;
178       if(item.next != -1)
179          ACCESS_ITEM(this, item.next).prev = item.prev;
180
181       if(ACCESS_ITEM(this, first) == item)
182          first = item.next;
183       if(ACCESS_ITEM(this, last) == item)
184          last = item.prev;
185       count--;
186
187       item.next = free;
188       free = ((byte *)item - (byte *)items) / itemSize;
189    }
190
191    void Free(void)
192    {
193       delete items;
194       size = 0;
195       count = 0;
196       free = first = last = -1;
197    }
198 };
199 */
200 private class BoxItem : Item //FastItem
201 {
202    Box box;
203 };
204
205 public /*private */struct Extent : OldList //FastList
206 {
207    void Empty()
208    {
209       Free(null);
210    }
211
212    void AddBox(Box box)
213    {
214       //BoxItem extentBox = (BoxItem)Add(sizeof(class BoxItem));
215       Add(BoxItem { box = box });
216    }
217
218    void Copy(Extent source)
219    {
220       BoxItem extentBox;
221
222       // Clear();
223       Empty();
224       //FASTLIST_LOOP(source, extentBox)
225       for(extentBox = (BoxItem)source.first; extentBox; extentBox = (BoxItem)extentBox.next)
226          AddBox(extentBox.box);
227    }
228
229    void IntersectBox(Box box)
230    {
231       // Clip all boxes of extent against inside of the new box
232       BoxItem extentBox, next;
233
234       //FASTLIST_LOOPN(this, extentBox, next)   // Macros still mess up the parser!
235       for(extentBox = (BoxItem)this.first; extentBox; extentBox = next)
236       {
237          next = (BoxItem)extentBox.next;
238          if(box.left > extentBox.box.left) extentBox.box.left = box.left;
239          if(box.top > extentBox.box.top) extentBox.box.top = box.top;
240          if(box.right < extentBox.box.right) extentBox.box.right = box.right;
241          if(box.bottom < extentBox.box.bottom) extentBox.box.bottom = box.bottom;
242          if(extentBox.box.right < extentBox.box.left || extentBox.box.bottom < extentBox.box.top)
243             Delete(extentBox);
244       }
245    }
246
247    void ExcludeBox(Box box, Extent temp)
248    {
249       BoxItem extentBox;
250
251       temp.Copy(this);
252       Empty();
253       
254       for(extentBox = (BoxItem)temp.first; extentBox; extentBox = (BoxItem)extentBox.next)
255       {
256          if(extentBox.box.left < box.right && extentBox.box.right > box.left && 
257             extentBox.box.top < box.bottom && extentBox.box.bottom > box.top)
258          {
259             // Top box
260             if(extentBox.box.top < box.top && extentBox.box.bottom >= box.top)
261             {
262                Box newBox
263                {
264                   extentBox.box.left, extentBox.box.top, 
265                   extentBox.box.right, Min(extentBox.box.bottom, box.top -1)
266                };
267                AddBox(newBox);
268             }
269
270             // Bottom box
271             if(extentBox.box.bottom > box.bottom && extentBox.box.top <= box.bottom)
272             {
273                Box newBox
274                {
275                   extentBox.box.left, Max(extentBox.box.top,box.bottom +1),
276                   extentBox.box.right, extentBox.box.bottom
277                };
278                AddBox(newBox);
279             }
280
281             // Middle boxes
282             if(extentBox.box.bottom >= box.top && extentBox.box.top <= box.bottom)
283             {
284                // Left box
285                if(extentBox.box.left < box.left && extentBox.box.right >= box.left)
286                {
287                   Box newBox
288                   {
289                      extentBox.box.left, Max(extentBox.box.top, box.top),
290                      Min(extentBox.box.right, box.left-1), Min(extentBox.box.bottom, box.bottom)
291                   };
292                   AddBox(newBox);
293                }
294
295                // Right box
296                if(extentBox.box.right > box.right && extentBox.box.left <= box.right)
297                {
298                   Box newBox
299                   {
300                      Max(extentBox.box.left, box.right+1), Max(extentBox.box.top, box.top),
301                      extentBox.box.right, Min(extentBox.box.bottom, box.bottom)
302                   };
303                   AddBox(newBox);
304                }
305             }
306          }
307          else
308          {
309             AddBox(extentBox.box);
310          }
311       }
312       temp.Empty();
313    }
314
315    void UnionBox(Box box, Extent temp)
316    {
317       BoxItem extentBox, next;
318
319       // First pass: check if this box is not already covered by one of the extent's box
320       for(extentBox = (BoxItem)this.first; extentBox; extentBox = (BoxItem)extentBox.next)
321       {
322          if(extentBox.box.left <= box.left && extentBox.box.right >= box.right && 
323             extentBox.box.top <= box.top && extentBox.box.bottom >= box.bottom)
324          {
325             // No change
326             return;
327          }
328       }
329         
330       // Second pass: only keep boxes not completely covered in the new box
331       for(extentBox = (BoxItem)this.first; extentBox; extentBox = next)
332       {
333          next = (BoxItem)extentBox.next;
334          if(extentBox.box.left >= box.left && extentBox.box.right <= box.right &&
335             extentBox.box.top >= box.top && extentBox.box.bottom <= box.bottom)
336             Delete(extentBox);
337       }
338
339       // Add the exclusion to the extent
340       ExcludeBox(box, temp);
341
342       // Add the new box
343       if(box.bottom >= box.top && box.right >= box.left)
344       {
345          // Optimization: if the resulting boxes touch, add them smarter
346          for(extentBox = (BoxItem)this.first; extentBox; extentBox = (BoxItem)extentBox.next)
347          {
348             if(box.top == extentBox.box.top && box.bottom == extentBox.box.bottom)
349             {
350                if(Abs(box.right - extentBox.box.left) <= 1)
351                {
352                   extentBox.box.left = box.left;
353                   break;
354                }
355                else if(Abs(box.left - extentBox.box.right) <= 1)
356                {
357                   extentBox.box.right = box.right;
358                   break;
359                }
360             }
361             else if(box.left == extentBox.box.left && box.right == extentBox.box.right)
362             {
363                if(Abs(box.bottom - extentBox.box.top) <= 1)
364                {
365                   extentBox.box.top = box.top;
366                   break;
367                }
368                else if(Abs(box.top - extentBox.box.bottom) <= 1)
369                {
370                   extentBox.box.bottom = box.bottom;
371                   break;
372                }
373             }
374          }
375          
376          // Else, add it
377          if(!extentBox)
378             AddBox(box);
379       }
380    }
381
382    void Union(Extent b, Extent temp)
383    {
384       BoxItem extentBox;
385
386       for(extentBox = (BoxItem)b.first; extentBox; extentBox = (BoxItem)extentBox.next)
387          UnionBox(extentBox.box, temp);
388    }
389
390    void Intersection(Extent b, Extent temp, Extent temp2, Extent temp3)
391    {
392       BoxItem extentBox;
393       temp.Copy(this);
394
395       Empty();
396
397       for(extentBox = (BoxItem)b.first; extentBox; extentBox = (BoxItem)extentBox.next)
398       {
399          temp2.Copy(temp);
400          temp2.IntersectBox(extentBox.box);
401          Union(temp2, temp3);
402          temp2.Empty();
403       }
404       temp.Empty();
405    }
406
407    void Exclusion(Extent b, Extent temp)
408    {
409       BoxItem extentBox;   
410       for(extentBox = (BoxItem)b.first; extentBox; extentBox = (BoxItem)extentBox.next)
411          ExcludeBox(extentBox.box, temp);
412    }
413
414    void Offset(int x, int y)
415    {
416       BoxItem extentBox;
417       for(extentBox = (BoxItem)this.first; extentBox; extentBox = (BoxItem)extentBox.next)
418       {
419          extentBox.box.left += x;
420          extentBox.box.top += y;
421          extentBox.box.right += x;
422          extentBox.box.bottom += y;
423       }
424    }
425 };
426
427 private define MINIMIZED_WIDTH = 160;
428 private define CASCADE_SPACE = 16;
429
430 // namespace Windows;
431
432 private class ScrollFlags
433 {
434    bool snapX:1, snapY:1, dontHide:1;   
435 };
436
437 public class BorderBits { public: bool contour:1, fixed:1, sizable:1, deep:1, bevel:1, thin:1; };
438
439 class WindowBits : BorderBits
440 {
441    BorderBits borderBits:6:0;
442    bool hidden:1, isActiveClient:1, hasHorzScroll:1, hasVertScroll:1, stayOnTop:1, modal:1, isDefault:1, inactive:1, isRemote:1, drawBehind:1;
443    bool interim:1, tabCycle:1, noCycle:1, dontScrollHorz:1, dontScrollVert:1, hasMaximize:1, hasMinimize:1, hasClose:1;
444    bool embedded:1, hasMenuBar:1, isDocument:1, showInTaskBar:1, hasStatusBar:1, nonClient:1, clickThrough:1;
445 };
446
447 public enum BorderStyle : BorderBits
448 {
449    none,
450    contour      = BorderBits { contour = true },
451    fixed        = BorderBits { fixed = true } | contour,
452    sizable      = BorderBits { sizable = true } | fixed,
453    thin         = BorderBits { fixed = true, thin = true } | contour,
454    sizableThin  = BorderBits { sizable = true } | thin,
455    deep         = BorderBits { deep = true },
456    bevel        = BorderBits { bevel = true },
457    sizableDeep  = sizable|deep,
458    sizableBevel = sizable|bevel,
459    fixedDeep    = fixed|deep,
460    fixedBevel   = fixed|bevel,
461    deepContour  = deep|contour
462 };
463
464 public enum CreationActivationOption
465 {
466    activate, flash, doNothing
467 };
468
469 public enum WindowState { normal, minimized, maximized };
470
471 private class ResPtr : struct
472 {
473    ResPtr prev, next;
474    Resource resource;
475    void * loaded;
476 };
477
478 private class HotKeySlot : struct
479 {
480    HotKeySlot prev, next;
481    Window window;
482    Key key;
483 };
484
485 public class Window
486 {
487 private:
488    class_data char * icon;
489    class_no_expansion
490    class_default_property caption;
491    // class_initialize GuiApplication::Initialize;
492    class_designer FormDesigner;
493    class_property char * icon
494    {
495       set { class_data(icon) = value; }
496       get { return class_data(icon); }
497    }
498
499    Window()
500    {
501       if(guiApp) guiApp.Initialize(true);
502
503       if(guiApp && guiApp.currentSkin && ((subclass(Window))_class).pureVTbl)
504       {
505          if(_vTbl == ((subclass(Window))_class).pureVTbl)
506          {
507             _vTbl = _class._vTbl;
508          }
509          else if(_vTbl != _class._vTbl)
510          {
511             int m;
512             for(m = 0; m < _class.vTblSize; m++)
513             {
514                if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m])
515                   _vTbl[m] = _class._vTbl[m];
516             }
517          }
518       }
519       
520       //tempExtents[0] = { /*first = -1, last = -1, free = -1*/ };
521       //tempExtents[1] = { /*first = -1, last = -1, free = -1*/ };
522       //tempExtents[2] = { /*first = -1, last = -1, free = -1*/ };
523       //tempExtents[3] = { /*first = -1, last = -1, free = -1*/ };
524
525       setVisible = true;
526
527       // caption = CopyString(class.name);
528
529       children.offset = (byte*)&prev - (byte*)this;
530       childrenOrder.circ = true;
531       childrenCycle.circ = true;
532
533       maxSize = Size { MAXINT, MAXINT };
534       background = white;
535       foreground = black;
536       
537       //style.isActiveClient = true;
538       mergeMenus = true;
539       autoCreate = true;
540       modifyVirtArea = true;
541       manageDisplay = true;
542       nativeDecorations = true;
543
544       // scrollFlags = ScrollFlags { snapX = true, snapY = true };
545       sbStep.x = sbStep.y = 8;
546
547       if(guiApp)  // dynamic_cast<GuiApplication>(thisModule)
548       {
549          cursor = guiApp.GetCursor(arrow);
550          property::parent = guiApp.desktop;
551       }
552    }
553
554    ~Window()
555    {
556       Window child;
557       OldLink slave;
558       ResPtr ptr;
559
560       if(parent)
561       {
562          stopwatching(parent, font);
563          if(parent.activeChild == this)
564             parent.activeChild = null;
565          if(parent.activeClient == this)
566             parent.activeClient = null;
567       }
568
569       if(!destroyed)
570       { 
571          // Prevent destructor from being called again...
572          incref this;
573          incref this;
574          DestroyEx(0);
575       }
576
577       /////////////////////////////////
578       if(master)
579       {
580          OldLink slave = master.slaves.FindLink(this);
581          master.slaves.Delete(slave);
582          master = null;
583       }
584
585       if(parent)
586       {
587          if(cycle)
588             parent.childrenCycle.Remove(cycle);
589          if(order)
590             parent.childrenOrder.Remove(order);
591          parent.children.Remove(this);
592          parent = null;
593       }
594       delete cycle;
595       delete order;
596       /////////////////////////////////
597
598       while(ptr = resources.first)
599       {
600          delete ptr.resource;
601          resources.Delete(ptr);
602       }
603
604       usedFont = null;
605       delete setFont;
606       delete systemFont;
607
608       for(child = children.first; child; child = child.next)
609       {
610          // child.stopwatching(this, font);
611          if(child.parent)
612             eInstance_StopWatching(this, __ecereProp___ecereNameSpace__ecere__gui__Window_font, child);
613          // Don't want property here
614          *&child.parent = null;
615       }
616
617       while(slave = slaves.first)
618       {
619          // Don't want property here
620          *&((Window)slave.data).master = null;
621          slaves.Delete(slave);
622       }
623
624       // Because we do a decref in DestroyEx...
625       if(!destroyed)
626       {
627          incref this;
628          incref this;
629          DestroyEx(0);
630       }
631
632       // Why was this commented?
633       //if(this != guiApp.desktop)
634       {
635          delete caption;
636          delete fileName;
637       }
638
639       delete menu;
640       delete statusBar;
641
642       OnDestroyed();
643       delete mutex;
644       delete icon;
645
646       if(((subclass(Window))_class).pureVTbl)
647       {
648          if(_vTbl == _class._vTbl)
649          {
650             _vTbl = ((subclass(Window))_class).pureVTbl;
651          }
652          else
653          {
654             int m;
655             for(m = 0; m < _class.vTblSize; m++)
656             {
657                if(_vTbl[m] == _class._vTbl[m])
658                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
659             }
660          }
661       }
662       if(_vTbl == ((subclass(Window))_class).pureVTbl || _vTbl == _class._vTbl)
663          _vTbl = null;
664
665       dirtyArea.Free(null);
666       renderArea.Free(null);
667       overRenderArea.Free(null);
668       clipExtent.Free(null);
669       scrollExtent.Free(null);
670       dirtyBack.Free(null);
671
672       if(tempExtents)
673       {
674          tempExtents[0].Free(null);
675          tempExtents[1].Free(null);
676          tempExtents[2].Free(null);
677          tempExtents[3].Free(null);
678          delete tempExtents;
679       }
680    }
681
682 //#if !defined(ECERE_VANILLA)
683    char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
684    {
685       if(this == activeDesigner)
686          return "(Desktop)";
687       else 
688       {
689          char * name = property::name;
690          return name ? name : "";
691       }
692    }
693 //#endif
694
695 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
696    bool OnGetDataFromString(char * string)
697    {
698       FormDesigner designer = (FormDesigner)activeDesigner.classDesigner;
699       if(string[0])
700       {
701          if(!strcmp(string, "this") || !strcmp(string, designer.form.name))
702             this = designer.form;
703          else if(!strcmpi(string, "(Desktop)"))
704             this = activeDesigner;
705          else
706             return activeDesigner.FindObject(&this, string);
707       }
708       return true;
709    }
710 #endif
711
712    // --- Window updates system ---
713
714    // Setup a bitmap for Redrawing on client area of Window
715    Surface Redraw(Box box)
716    {
717       Surface surface = null;
718       Box mox = box;
719       Box clientArea = this.clientArea;
720
721       SetBox(clientArea);
722
723       mox.left   -= clientStart.x;
724       mox.top    -= clientStart.y;
725       mox.right  -= clientStart.x;
726       mox.bottom -= clientStart.y;
727
728       mox.Clip(clientArea);
729       // mox.ClipOffset(against, scrolledPos.x, scrolledPos.y);
730
731       if((!guiApp.fullScreenMode || guiApp.desktop.active) && display && mox.right >= mox.left && mox.bottom >= mox.top)
732       {
733          int x = absPosition.x + clientStart.x;
734          int y = absPosition.y + clientStart.y;
735          if(rootWindow.nativeDecorations && rootWindow.windowHandle)
736          {
737             x -= rootWindow.clientStart.x;
738             y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
739          }
740          if(!guiApp.fullScreenMode || is3D)
741          {
742             x -= rootWindow.absPosition.x;
743             y -= rootWindow.absPosition.y;
744
745             if(rootWindow.is3D)
746             {
747                x += rootWindow.parent.clientStart.x;
748                y += rootWindow.parent.clientStart.y;
749                /*
750                mox.left += rootWindow.parent.clientStart.x;
751                mox.top += rootWindow.parent.clientStart.y;
752                mox.right += rootWindow.parent.clientStart.x;
753                mox.bottom += rootWindow.parent.clientStart.y;
754                */
755             }
756          }
757
758          surface = display.GetSurface(x, y, mox);
759          /*if(surface)
760          {
761             surface.width = clientSize.w;
762             surface.height = clientSize.h;
763          }*/
764       }
765       return surface;
766    }
767
768    // Setup a bitmap for Redrawing on full Window
769    Surface RedrawFull(Box box)
770    {
771       Surface surface = null;
772       Box mox;
773       if(box != null)
774          box.Clip(this.box);
775       else
776          box = &this.box;
777       mox = box;
778
779       if((!guiApp.fullScreenMode || guiApp.desktop.active) && display && box.right >= box.left && box.bottom >= box.top)
780       {
781          int x = absPosition.x;
782          int y = absPosition.y;
783          if(rootWindow.nativeDecorations && rootWindow.windowHandle)
784          {
785             x -= rootWindow.clientStart.x;
786             y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
787          }
788          if(!guiApp.fullScreenMode || is3D)
789          {
790             x -= rootWindow.absPosition.x;
791             y -= rootWindow.absPosition.y;
792             if(rootWindow.is3D)
793             {
794                x += rootWindow.parent.clientStart.x;
795                y += rootWindow.parent.clientStart.y;
796                /*
797                mox.left += rootWindow.parent.clientStart.x;
798                mox.top += rootWindow.parent.clientStart.y;
799                mox.right += rootWindow.parent.clientStart.x;
800                mox.bottom += rootWindow.parent.clientStart.y;
801                */
802             }
803          }
804
805          surface = display.GetSurface(x, y, mox);
806          /*if(surface)
807          {
808             surface.width = size.w;
809             surface.height = size.h;
810          }*/
811       }
812       return surface;
813    }
814
815    void FigureCaption(char * caption)
816    {
817       Window activeClient = null;
818
819       caption[0] = '\0';
820       if(this.caption)
821          strcpy(caption, this.caption);
822       if(style.isDocument || fileName)
823       {
824          if(caption[0]) strcat(caption, " - ");
825          if(fileName)
826             strcat(caption, fileName);
827          else
828          {
829             char title[256];
830             sprintf(title, "Untitled %d", documentID);
831             strcat(caption, title);
832          }
833          if(modifiedDocument)
834             strcat(caption, " *");
835       }
836
837       if(menuBar)
838       {
839          for(activeClient = this.activeClient; activeClient && !((BorderBits)activeClient.borderStyle).fixed; activeClient = activeClient.activeClient);
840       }
841       if(activeClient && activeClient.state == maximized)
842       {
843          if(activeClient.caption)
844          {
845             if(caption[0]) strcat(caption, " - ");
846             strcat(caption, activeClient.caption);
847          }
848          if(activeClient.style.isDocument || activeClient.fileName)
849          {
850             if(caption[0]) strcat(caption, " - ");
851             strcat(caption, "[");
852             if(activeClient.fileName)
853                strcat(caption, activeClient.fileName);
854             else
855             {
856                char title[256];
857                sprintf(title, "Untitled %d", activeClient.documentID);
858                strcat(caption, title);
859             }
860             if(activeClient.modifiedDocument)
861                strcat(caption, " *");
862             strcat(caption, "]");
863          }
864       }
865    }
866
867    // Code for returning dirty from ScrollDisplay:
868       /*
869       for(d = 0; d<scrollExtent.count; d++)
870       {
871          Box * box = &scrollExtent.boxes[d];
872          if(scroll.x < 0)
873          {
874             Box update
875             {
876                box.left, box.top,
877                Min(box.right, box.left-scroll.x),box.bottom
878             };
879             dirtyArea.UnionBox(update);
880          }
881          else if(scroll.x)
882          {
883             Box update
884             {
885                Max(box.left, box.right-scroll.x), box.top,
886                box.right, box.bottom
887             };
888             dirtyArea.UnionBox(update);
889          }
890
891          if(scroll.y < 0)
892          {
893             Box update
894             {
895                box.left, box.top,
896                box.right, Min(box.bottom, box.top-scroll.y),
897             };
898             dirtyArea.UnionBox(update);
899          }
900          else if(scroll.y)
901          {
902             Box update
903             {
904                box.left, Max(box.top, box.bottom-scroll.y),
905                box.right, box.bottom
906             };
907             dirtyArea.UnionBox(update);
908          }
909       }
910       */
911
912    void UpdateDecorations(void)
913    {
914       // TODO: *** TEMPORARY HACK ***
915       /*
916       if(parent)
917          parent.Update(null);
918       */
919
920       // Top
921       Update({ -clientStart.x, -clientStart.y, -clientStart.x + size.w-1, 0 });
922       // Bottom
923       Update({ -clientStart.x, clientSize.h, -clientStart.x + size.w-1, -clientStart.y + size.h-1 });
924       // Left
925       Update({ -clientStart.x,0, -1, clientSize.h-1 });
926       // Right
927       Update({ clientSize.w, 0, -clientStart.x + size.w-1, clientSize.h-1 });
928    }
929
930    // Returns w & h for Position
931    void ComputeAnchors(Anchor anchor, SizeAnchor sizeAnchor, int *ox, int *oy, int *ow, int *oh)
932    {
933       Window parent = this.parent ? this.parent : guiApp.desktop;
934       int vpw = parent ? parent.clientSize.w : 0;
935       int vph = parent ? parent.clientSize.h : 0;
936       int pw = parent ? parent.clientSize.w : 0;
937       int ph = parent ? parent.clientSize.h : 0;
938       int w = sizeAnchor.size.w, h = sizeAnchor.size.h;
939       int x = anchor.left.distance, y = anchor.top.distance;
940       float ex, ey;
941       MinMaxValue ew = 0, eh = 0;
942       int numCascade;
943       float cascadeW, cascadeH;
944       int numTiling;
945       int tilingW, tilingH, tilingSplit, tilingLastH;
946       int addX = 0, addY = 0;
947
948       if(parent && rootWindow == this && guiApp && guiApp.interfaceDriver)
949       {
950          Window masterWindow = this;
951          Box box { addX, addY, addX + vpw - 1, addY + vph - 1 };
952          if(!visible)
953          {
954             if(master == guiApp.desktop)
955                masterWindow = guiApp.desktop.activeChild;
956             else
957                masterWindow = master.rootWindow;
958             if(!masterWindow) masterWindow = this;
959          }
960          guiApp.interfaceDriver.GetScreenArea(masterWindow, box);
961          if((anchor.left.type == offset && anchor.right.type == offset) || anchor.left.type == none)
962          {
963             addX = box.left;
964             pw = vpw = box.right - box.left + 1;
965          }
966          if((anchor.top.type == offset && anchor.bottom.type == offset) || anchor.top.type == none)
967          {
968             addY = box.top;
969             ph = vph = box.bottom - box.top + 1;
970          }
971       }
972       
973       if(!parent)
974       {
975          *ow = w;
976          *oh = h;
977
978          *ox = x;
979          *oy = y;
980          return;
981       }
982
983       if(style.nonClient)
984       {
985          vpw = pw = parent.size.w;
986          vph = ph = parent.size.h;
987       }
988       else if(!style.fixed /*|| style.isDocument*/)
989       {
990          if(!style.dontScrollHorz && parent.scrollArea.w) vpw = parent.scrollArea.w;
991          if(!style.dontScrollVert && parent.scrollArea.h) vph = parent.scrollArea.h;
992       }
993 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
994       if(is3D)
995       {
996          Desktop3D_FixSize(&pw, &ph);
997          Desktop3D_FixSize(&vpw, &vph);
998       }
999 #endif
1000       if(pw < skinMinSize.w) pw = skinMinSize.w;
1001       if(ph < skinMinSize.h) ph = skinMinSize.h;
1002       if(vpw < skinMinSize.w) vpw = skinMinSize.w;
1003       if(vph < skinMinSize.h) vph = skinMinSize.h;
1004
1005       // TODO: Must fix what we're snapping
1006       if(guiApp.textMode)
1007       {
1008          if(anchor.left.type)
1009          {
1010             SNAPUP(x, textCellW);
1011          }
1012          else if(anchor.right.type)
1013          {
1014             SNAPDOWN(x, textCellW);
1015          }
1016
1017          if(anchor.top.type)
1018          {
1019             SNAPUP(y, textCellH);   
1020          }
1021          else if(anchor.bottom.type)
1022          {
1023             SNAPDOWN(y, textCellH);
1024          }
1025       }
1026
1027       // This is required to get proper initial decoration size using native decorations on Windows
1028       if(nativeDecorations && windowHandle && guiApp && guiApp.interfaceDriver && !visible)
1029          guiApp.interfaceDriver.PositionRootWindow(this, x, y, Max(1, size.w), Max(1, size.h), true, true);
1030       GetDecorationsSize(&ew, &eh);
1031
1032       if(anchor.left.type >= cascade && (state == normal /*|| state == Hidden*/))
1033       {
1034          if(parent.sbv && !parent.sbv.style.hidden) 
1035             pw += guiApp.currentSkin.VerticalSBW();
1036          if(parent.sbh && !parent.sbh.style.hidden)
1037             ph += guiApp.currentSkin.HorizontalSBH();
1038
1039          if(anchor.left.type == cascade)
1040          {
1041             w = (int)(pw * 0.80);
1042             h = (int)(ph * 0.80);
1043          }
1044          else if(anchor.left.type >= vTiled)
1045          {
1046             int leftOver;
1047             int x2, y2;
1048
1049             numTiling = parent.numPositions - parent.numIcons;
1050             if(parent.numIcons) ph -= guiApp.textMode ? 16 : 24;
1051             if(anchor.left.type == vTiled)
1052             {
1053                tilingH = (int)sqrt(numTiling);
1054                tilingW = numTiling / tilingH;
1055             }
1056             else
1057             {
1058                tilingW = (int)sqrt(numTiling);
1059                tilingH = numTiling / tilingW;
1060             }
1061
1062             leftOver = numTiling - tilingH * tilingW;
1063             if(leftOver)
1064             {
1065                tilingSplit = (tilingW - leftOver) * tilingH;
1066                tilingLastH = tilingH+1;
1067             }
1068             else
1069                tilingSplit = numTiling;
1070
1071             if(positionID >= tilingSplit)
1072             {
1073                x = pw * (tilingSplit / tilingH + (positionID - tilingSplit) / tilingLastH)/tilingW;
1074                y = ph * ((positionID - tilingSplit) % tilingLastH) / tilingLastH;
1075                x2 = pw * (tilingSplit/tilingH + (positionID - tilingSplit) / tilingLastH + 1)/tilingW;
1076                y2 = ph * (((positionID - tilingSplit) % tilingLastH) + 1) / tilingLastH;
1077             }
1078             else
1079             {
1080                x = pw * (positionID / tilingH) / tilingW;
1081                y = ph * (positionID % tilingH) / tilingH;
1082                x2 = pw * (positionID / tilingH + 1) / tilingW;
1083                y2 = ph * ((positionID % tilingH) + 1) / tilingH;
1084             }
1085             if(guiApp.textMode)
1086             {
1087                SNAPDOWN(x, textCellW);
1088                SNAPDOWN(y, textCellH);
1089                SNAPDOWN(x2, textCellW);
1090                SNAPDOWN(y2, textCellH);
1091             }
1092             w = x2 - x;
1093             h = y2 - y;
1094          }
1095       }
1096       else
1097       {
1098          if(sizeAnchor.isClientW) w += ew;
1099          if(sizeAnchor.isClientH) h += eh;
1100          
1101          if(anchor.left.type == offset)
1102             x = anchor.left.distance;
1103          else if(anchor.left.type == relative)
1104             x = (anchor.left.percent < 0) ? ((int)(vpw * anchor.left.percent - 0.5)) : (int)(vpw * anchor.left.percent + 0.5);
1105          else if(anchor.right.type == relative)
1106             // ex = (anchor.right.percent < 0) ? ((int)(vpw * anchor.right.percent + 0)) : ((int)(vpw * anchor.right.percent + 0));
1107             ex = (anchor.right.percent < 0) ? ((int)(vpw * (1.0-anchor.right.percent) + 0)) : ((int)(vpw * (1.0-anchor.right.percent) + 0));
1108          else if(anchor.right.type == offset)
1109             ex = vpw - anchor.right.distance;
1110
1111          if(anchor.top.type == offset)
1112             y = anchor.top.distance;
1113          else if(anchor.top.type == relative)
1114             y = (anchor.top.percent < 0) ? ((int)(vph * anchor.top.percent - 0.5)) : ((int)(vph * anchor.top.percent + 0.5));
1115          else if(anchor.bottom.type == relative)
1116             //ey = (anchor.bottom.percent < 0) ? ((int)(vph * anchor.bottom.percent + 0)) : ((int)(vph * anchor.bottom.percent + 0));
1117             ey = (anchor.bottom.percent < 0) ? ((int)(vph * (1.0-anchor.bottom.percent) + 0)) : ((int)(vph * (1.0-anchor.bottom.percent) + 0));
1118          else if(anchor.bottom.type == offset)
1119             ey = vph - anchor.bottom.distance;
1120
1121          if(anchor.left.type && anchor.right.type)
1122          {
1123             switch(anchor.right.type)
1124             {
1125                case relative: 
1126                   ex = pw * (1.0f-anchor.right.percent); 
1127                   w = Max((int)(ex + 0.5) - x, 0);
1128                   break;
1129                case offset:
1130                   ex = vpw - anchor.right.distance;
1131                   w = Max((int)(ex + 0.5) - x, 0);
1132                   break;
1133             }
1134          }
1135          if(anchor.top.type && anchor.bottom.type)
1136          {
1137             switch(anchor.bottom.type)
1138             {
1139                case relative:
1140                   ey = ph * (1.0f-anchor.bottom.percent);
1141                   h = Max((int)(ey + 0.5) - y, 0);
1142                   break;
1143                case offset:
1144                   ey = vph - anchor.bottom.distance;
1145                   h = Max((int)(ey + 0.5) - y, 0);
1146                   break;
1147             }
1148          }
1149       }
1150
1151       w -= ew;
1152       h -= eh; 
1153
1154       if(state == normal /*|| state == Hidden*/)
1155       {
1156          bool addSbV = false, addSbH = false;
1157
1158          if(sizeAnchor.isClientW || (anchor.left.type && anchor.right.type))  w = Max(w, 1); else w = Max(w, 0);
1159          if(sizeAnchor.isClientH || (anchor.top.type && anchor.bottom.type))  h = Max(h, 1); else h = Max(h, 0);
1160
1161          w = Max(w, minSize.w);
1162          h = Max(h, minSize.h);
1163          w = Min(w, maxSize.w);
1164          h = Min(h, maxSize.h);
1165
1166          if((sizeAnchor.isClientW || !w || (anchor.left.type && anchor.right.type)) && reqScrollArea.h > h /*&& w*/ && sbv) 
1167          {
1168             if(w) w -= guiApp.currentSkin.VerticalSBW();
1169             addSbV = true;
1170          }
1171          if((sizeAnchor.isClientH || !h ||  (anchor.top.type && anchor.bottom.type)) && reqScrollArea.w > w /*&& h*/ && sbh) 
1172          {
1173             if(h) h -= guiApp.currentSkin.HorizontalSBH();
1174             addSbH = true;
1175          }
1176
1177          if(!OnResizing(&w, &h))
1178          {
1179             w = clientSize.w;
1180             h = clientSize.h;
1181          }
1182
1183          if((addSbV)) // || reqScrollArea.h > h) && sbv) 
1184             w += guiApp.currentSkin.VerticalSBW();
1185          if((addSbH)) // || reqScrollArea.w > w) && sbh)
1186             h += guiApp.currentSkin.HorizontalSBH();
1187
1188          w = Max(w, skinMinSize.w);
1189          h = Max(h, skinMinSize.h);
1190       }
1191       else
1192       {
1193          w = Max(w, 0);
1194          h = Max(h, 0);
1195       }
1196
1197       w += ew;
1198       h += eh; 
1199
1200       if(guiApp.textMode)
1201       {
1202          SNAPDOWN(w, textCellW);
1203          SNAPDOWN(h, textCellH);
1204       }
1205
1206       if(anchor.left.type == cascade && (state == normal /*|| state == Hidden*/))
1207       {
1208          if(parent.numIcons) ph -= guiApp.textMode ? 16 : 24;
1209
1210          numCascade = Min(
1211             (pw - w) / CASCADE_SPACE, 
1212             (ph - h) / CASCADE_SPACE);
1213          
1214          if(guiApp.textMode)
1215          {
1216                int cascW, cascH;
1217                numCascade++;
1218                cascW = (pw - w) / (numCascade-1);
1219                cascH = (ph - h) / (numCascade-1);
1220                SNAPDOWN(cascW, textCellW);
1221                SNAPDOWN(cascH, textCellH);
1222                cascadeW = (float)cascW;
1223                cascadeH = (float)cascH;
1224          }
1225          else
1226          {
1227             numCascade = Max(numCascade, 2);
1228             cascadeW = (float)(pw - w) / (numCascade-1);
1229             cascadeH = (float)(ph - h) / (numCascade-1);
1230          }
1231
1232          x = (int)((positionID % numCascade) * cascadeW);
1233          y = (int)((positionID % numCascade) * cascadeH);
1234       }
1235       else if(anchor.left.type < vTiled)
1236       {
1237          if(!anchor.left.type || anchor.horz.type == middleRelative)
1238          {
1239             if(!anchor.right.type)
1240             {
1241                if(anchor.horz.type == middleRelative)
1242                   x = (int)(vpw * (0.5 + anchor.horz.percent) - w / 2);
1243                else
1244                   x = vpw / 2 + anchor.horz.distance - w / 2;
1245             }
1246             else
1247                x = (int)(ex - w);
1248          }
1249
1250          // case A_EDGE: x = x - w; break;
1251
1252          if(!anchor.top.type || anchor.vert.type == middleRelative)
1253          {
1254             if(!anchor.bottom.type)
1255             {
1256                if(anchor.vert.type == middleRelative)
1257                   y = (int)(vph * (0.5 + anchor.vert.percent) - h / 2);
1258                else
1259                   y = vph / 2 + anchor.vert.distance - h / 2;      
1260             }
1261             else
1262                y = (int)(ey - h);
1263          }
1264
1265          // case A_EDGE: y = y - h; break;
1266       }
1267
1268       if((state == normal /*|| state == Hidden*/) && !OnMoving(&x, &y, w, h))
1269       {
1270          x = position.x;
1271          y = position.y;
1272       }
1273
1274       if(guiApp.textMode)
1275       {
1276          SNAPDOWN(x, textCellW);
1277          SNAPDOWN(y, textCellH);
1278       }
1279
1280       x += addX;
1281       y += addY;
1282
1283       *ow = w;
1284       *oh = h;
1285
1286       *ox = x;
1287       *oy = y;
1288
1289       if(anchored && style.fixed && style.isActiveClient)
1290          anchored = false;
1291    }
1292
1293    // --- Carets ---
1294    void UpdateCaret(bool forceUpdate, bool erase)
1295    {
1296       static Window lastWindow = null;
1297       static int caretX, caretY, caretSize;
1298
1299       if(guiApp && guiApp.caretOwner == this)
1300       {
1301          int x = caretPos.x - scroll.x;
1302          int y = caretPos.y - scroll.y;
1303
1304          if((erase || this.caretSize) &&
1305             x >= clientArea.left && x <= clientArea.right && 
1306             y >= clientArea.top  && y <= clientArea.bottom)
1307          {
1308             if(!erase)
1309             {
1310                guiApp.interfaceDriver.SetCaret(
1311                   x + absPosition.x + clientStart.x, 
1312                   y + absPosition.y + clientStart.y, this.caretSize);
1313                guiApp.caretEnabled = true;
1314             }
1315             if(erase || lastWindow != this || caretX != x || caretY != y || caretSize != this.caretSize || forceUpdate)
1316             {
1317                Box updateBox;
1318
1319                if(lastWindow != this)
1320                {
1321                   updateBox.left = x + 1;
1322                   updateBox.top = y;
1323                   updateBox.right = x + 2;
1324                   updateBox.bottom = y + this.caretSize - 1;
1325                }
1326                else
1327                {
1328                   updateBox.left = Min(x + 1, caretX + 1);
1329                   updateBox.top = Min(y, caretY);
1330                   updateBox.right = Max(x + 2, caretX + 2);
1331                   updateBox.bottom = Max(y + this.caretSize - 1, caretY + caretSize - 1);
1332                }
1333
1334                guiApp.caretOwner.Update(updateBox);
1335
1336                if(!erase)
1337                {
1338                   lastWindow = this;
1339                   caretX = x;
1340                   caretY = y;
1341                   caretSize = this.caretSize;
1342                }
1343             }
1344          }
1345          else
1346          {
1347             guiApp.interfaceDriver.SetCaret(0,0,0);
1348             guiApp.caretEnabled = false;
1349             lastWindow = null;
1350          }
1351       }
1352    }
1353
1354    void SetPosition(int x, int y, int w, int h, bool modifyArea, bool modifyThisArea, bool modifyClientArea)
1355    {
1356       Window child;
1357
1358       // Set position
1359       scrolledPos.x = position.x = x;
1360       scrolledPos.y = position.y = y;
1361
1362       clientSize.w = size.w = w;
1363       clientSize.h = size.h = h;
1364
1365       if(parent && !style.nonClient)
1366       {
1367          //if(!style.fixed || style.isDocument)
1368          {
1369             if(!style.dontScrollHorz) scrolledPos.x -= parent.scroll.x;
1370             if(!style.dontScrollVert) scrolledPos.y -= parent.scroll.y;
1371          }
1372       }
1373
1374       clientStart.x = clientStart.y = 0;
1375
1376       SetWindowArea(&clientStart.x, &clientStart.y, &size.w, &size.h, &clientSize.w, &clientSize.h);
1377
1378       //if(!activeClient || activeClient.state != maximized)
1379       if(!noAutoScrollArea)
1380       {
1381          // Check if scroll area must be modified
1382          if(guiApp && !guiApp.modeSwitching && (sbv || sbh))
1383          {
1384             bool foundChild = false;
1385             int w = 0, h = 0;
1386             int cw = clientSize.w;// + ((!sbv || sbv.range > 1) ? guiApp.currentSkin.VerticalSBW() : 0);
1387             int ch = clientSize.h;// + ((!sbh || sbh.rangw > 1) ? guiApp.currentSkin.HorizontalSBH() : 0);
1388             for(child = children.first; child; child = child.next)
1389             {
1390                if(child.modifyVirtArea && !child.style.hidden && child.created && /*!child.anchored &&*/
1391                   !child.style.dontScrollHorz && !child.style.dontScrollVert && !child.style.nonClient)
1392                {
1393                   if(child.stateAnchor.right.type == none && child.stateAnchor.left.type == offset)
1394                      w = Max(w, child.position.x + child.size.w);
1395                   else if(child.stateAnchor.right.type == none && child.stateAnchor.left.type == none)
1396                      w = Max(w, Max(child.position.x, 0) + child.size.w);
1397                   if(child.stateAnchor.bottom.type == none && child.stateAnchor.top.type == offset)
1398                      h = Max(h, child.position.y + child.size.h);
1399                   else if(child.stateAnchor.bottom.type == none && child.stateAnchor.top.type == none)
1400                      h = Max(h, Max(child.position.y, 0) + child.size.h);
1401
1402                   foundChild = true;
1403                }
1404             }
1405             if(foundChild && (w > cw || h > ch))
1406             {
1407                //if((w > reqScrollArea.w) || (h > reqScrollArea.w))
1408                {
1409                   int stepX = sbStep.x, stepY = sbStep.y;
1410                   // Needed to make snapped down position match the skin's check of client area 
1411                   // against realvirtual
1412                   if(guiApp.textMode)
1413                   {
1414                      SNAPDOWN(stepX, textCellW);
1415                      SNAPDOWN(stepY, textCellH);
1416                      stepX = Max(stepX, textCellW);
1417                      stepY = Max(stepY, textCellH);
1418                   }
1419                   if(scrollFlags.snapX)
1420                      SNAPUP(w, stepX);
1421                   if(scrollFlags.snapY)
1422                      SNAPUP(h, stepY);
1423
1424                   reqScrollArea.w = w;
1425                   reqScrollArea.h = h;
1426                }
1427             }
1428             else if(reqScrollArea.w || reqScrollArea.h)
1429             {
1430                reqScrollArea.w = 0;
1431                reqScrollArea.h = 0;
1432                SetScrollPosition(0,0);
1433             }
1434          }
1435       }
1436
1437       // Automatic MDI Client Scrolling Area Adjustment
1438       if(parent && !parent.noAutoScrollArea)
1439       {
1440          if(modifyArea && modifyVirtArea /*&& !anchored*/ && (parent.sbv || parent.sbh) && 
1441             !style.dontScrollHorz && !style.dontScrollVert && !style.nonClient)
1442          {
1443             Window parent = this.parent;
1444             int w = parent.reqScrollArea.w;
1445             int h = parent.reqScrollArea.h;
1446
1447             if(stateAnchor.right.type == none && stateAnchor.left.type == offset)
1448                w = Max(w, position.x + size.w);
1449             else if(stateAnchor.right.type == none && stateAnchor.left.type == none)
1450                w = Max(w, Max(position.x, 0) + size.w);
1451             if(stateAnchor.bottom.type == none && stateAnchor.top.type == offset)
1452                h = Max(h, position.y + size.h);
1453             else if(stateAnchor.bottom.type == none && stateAnchor.top.type == none)
1454                h = Max(h, Max(position.y, 0) + size.h);
1455
1456             if((w > parent.clientSize.w && w > parent.reqScrollArea.w) || 
1457                (h > parent.clientSize.h && h > parent.reqScrollArea.h))
1458             {
1459                /*bool resize = false;
1460                int stepX = parent.sbStep.x, stepY = parent.sbStep.y;
1461                // Needed to make snapped down position match the skin's check of client area 
1462                // against realvirtual
1463                if(guiApp.textMode)
1464                {
1465                   SNAPDOWN(stepX, textCellW);
1466                   SNAPDOWN(stepY, textCellH);
1467                   stepX = Max(stepX, textCellW);
1468                   stepY = Max(stepY, textCellH);
1469                }
1470                if(parent.scrollFlags.snapX)
1471                   SNAPUP(w, stepX);
1472                if(parent.scrollFlags.snapY)
1473                   SNAPUP(h, stepY);
1474                if(parent.reqScrollArea.w != w || parent.reqScrollArea.h != h)
1475                {
1476                   parent.reqScrollArea.w = w;
1477                   parent.reqScrollArea.h = h;*/
1478
1479                  // parent.UpdateScrollBars(true, true);
1480                   parent.Position(parent.position.x, parent.position.y, parent.size.w, parent.size.h, 
1481                      false, true, true, true, false, false);
1482                   return;
1483                //}
1484             }
1485             else 
1486                GetRidOfVirtualArea();
1487          }
1488       }
1489       if(modifyThisArea)
1490          UpdateScrollBars(modifyThisArea, false);
1491       else if(guiApp.currentSkin)
1492       {
1493          SetWindowArea(
1494             &clientStart.x, &clientStart.y, &size.w, &size.h, &clientSize.w, &clientSize.h);
1495
1496          if(sbv && (scrollFlags.dontHide || sbv.range > 1))
1497             clientSize.w -= guiApp.currentSkin.VerticalSBW();
1498          if(sbh && (scrollFlags.dontHide || sbh.range > 1))
1499             clientSize.h -= guiApp.currentSkin.HorizontalSBH();
1500       }
1501
1502       scrollArea.w = Max(clientSize.w, reqScrollArea.w);
1503       scrollArea.h = Max(clientSize.h, reqScrollArea.h);
1504
1505       absPosition = scrolledPos;
1506       if(guiApp && guiApp.driver != null && guiApp.interfaceDriver)
1507          guiApp.interfaceDriver.OffsetWindow(this, &absPosition.x, &absPosition.y);
1508
1509       if(this != guiApp.desktop && parent)
1510       {
1511          absPosition.x += parent.absPosition.x;
1512          absPosition.y += parent.absPosition.y;
1513          if(!style.nonClient && this != guiApp.desktop)
1514          {
1515             absPosition.x += parent.clientStart.x;
1516             absPosition.y += parent.clientStart.y;
1517          }
1518       }
1519
1520       box = Box { 0, 0, size.w - 1, size.h - 1 };
1521       SetBox(box);
1522
1523       if(against)
1524       {
1525          // Clip against parent's client area
1526          box.ClipOffset(against, scrolledPos.x, scrolledPos.y);
1527       }
1528       // Compute client area in this window coordinate system
1529       clientArea.left = 0;
1530       clientArea.top = 0;
1531       clientArea.right = clientSize.w - 1;
1532       clientArea.bottom = clientSize.h - 1;
1533
1534       // Clip against parent's client area
1535       if(against)
1536          clientArea.ClipOffset(against, scrolledPos.x + clientStart.x, scrolledPos.y + clientStart.y);
1537
1538       if(is3D)
1539       {
1540          //absPosition.x -= parent.clientStart.x;
1541          //absPosition.y -= parent.clientStart.y;
1542       }
1543
1544       // Adjust all children
1545       for(child = children.first; child; child = child.next)
1546          child.SetPosition(child.position.x, child.position.y, child.size.w, child.size.h, false, true, true);
1547
1548       UpdateCaret(false, false);
1549    }
1550
1551    void GetRidOfVirtualArea(void)
1552    {
1553       if(parent && !parent.destroyed && style.fixed &&
1554          !style.dontScrollHorz && !style.dontScrollVert && !style.nonClient &&
1555          parent.reqScrollArea.w && parent.reqScrollArea.h)
1556       {
1557          if(!parent.noAutoScrollArea)
1558          {
1559             Window child;
1560             bool found = false;
1561             for(child = children.first; child; child = child.next)
1562             {
1563                if(child.modifyVirtArea && !child.style.dontScrollHorz && !child.style.dontScrollVert && !child.style.nonClient)
1564                {
1565                   if(child.position.x + child.size.w > parent.clientSize.w + ((!parent.sbv || parent.sbv.style.hidden) ? 0 : guiApp.currentSkin.VerticalSBW()) ||
1566                      child.position.y + child.size.h > parent.clientSize.h + ((!parent.sbh || parent.sbh.style.hidden) ? 0 : guiApp.currentSkin.HorizontalSBH()))
1567                   {
1568                      found = true;
1569                      break;
1570                   }
1571                }
1572             }
1573             //if(!found)
1574             {
1575                Window parent = this.parent;
1576                parent.Position(
1577                   parent.position.x, parent.position.y, parent.size.w, parent.size.h, 
1578                   false, true, true, true, false, false);
1579                /*
1580                parent.SetScrollArea(0,0,true);
1581                parent.SetScrollPosition(0,0);
1582                */
1583             }
1584          }
1585       }
1586    }
1587    public void ExternalPosition(int x, int y, int w, int h)
1588    {
1589       Position(x, y, w, h, false, true, true, true, false, false);
1590    }
1591
1592    // (w, h): Full window size
1593    bool Position(int x, int y, int w, int h, bool force, bool processAnchors, bool modifyArea, bool updateScrollBars, bool thisOnly, bool changeRootWindow)
1594    {
1595       bool result = false;
1596       int oldCW = clientSize.w, oldCH = clientSize.h;
1597       bool clientResized, windowResized, windowMoved;
1598       Window child;
1599       bool realResized = size.w != w || size.h != h;
1600
1601       // TOCHECK: This wasn't in ecere.dll
1602       //if(!parent) return true;
1603       if(destroyed) return false;
1604
1605       windowMoved = position.x != x || position.y != y || force;
1606
1607       // windowResized = realResized || force;
1608       windowResized = size.w != w || size.h != h || force;
1609      
1610       if(rootWindow != this && display && !display.flags.flipping && scrolledPos.x != MININT)
1611       {
1612          if(style.nonClient)
1613          {
1614             Box box
1615             { 
1616                scrolledPos.x - parent.clientStart.x + this.box.left, scrolledPos.y - parent.clientStart.y + this.box.top, 
1617                scrolledPos.x - parent.clientStart.x + this.box.right,
1618                scrolledPos.y - parent.clientStart.y + this.box.bottom 
1619             };
1620             parent.Update(box);
1621          }
1622          else
1623          {
1624             Box box { scrolledPos.x + this.box.left, scrolledPos.y + this.box.top, scrolledPos.x + this.box.right, scrolledPos.y + this.box.bottom};
1625             parent.Update(box);
1626          }
1627       }
1628
1629       SetPosition(x, y, w, h, true, modifyArea, updateScrollBars);
1630
1631       clientResized = oldCW != clientSize.w || oldCH != clientSize.h || force;
1632       if(clientResized && this == rootWindow && nativeDecorations && rootWindow.windowHandle)
1633          windowResized = true;
1634
1635       if(display && rootWindow != this)
1636          Update(null);
1637
1638       if(guiApp && guiApp.windowMoving)
1639       {
1640          if(guiApp.windowMoving.style.nonClient)
1641             guiApp.windowMoving.parent.SetMouseRangeToWindow();
1642          else
1643             guiApp.windowMoving.parent.SetMouseRangeToClient();
1644       }
1645
1646       if(!positioned)
1647       {
1648          positioned = true;
1649          if(clientResized)
1650          {
1651             if(!thisOnly)
1652             {
1653                // Buttons bitmap resources crash if we do this while switching mode
1654                if(!guiApp || !guiApp.modeSwitching)
1655                   UpdateNonClient();
1656
1657                // Process Anchored Children
1658                if(processAnchors)
1659                {
1660                   int x,y,w,h;
1661                   for(child = children.first; child; child = child.next)
1662                   {
1663                      if(child.created && 
1664                      ((child.stateAnchor.left.type != offset ||
1665                        child.stateAnchor.top.type != offset ||
1666                        child.stateAnchor.right.type != none ||
1667                        child.stateAnchor.bottom.type != none) ||
1668                         child.state == maximized || child.state == minimized))
1669                      {
1670                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor,
1671                            &x, &y, &w, &h);
1672                         // child.Position(x, y, w, h, false, true, true, true, false);
1673                         // This must be true cuz otherwise we're gonna miss everything since we SetPosition recursively already
1674                         child.Position(x, y, w, h, true, true, true, true, false, true /*false*/);
1675                      }
1676                   }
1677                }
1678             }
1679
1680             // Is this gonna cause other problems? Commented out for the FileDialog end bevel bug
1681             //if(updateScrollBars)
1682             if(created)
1683                OnResize(clientSize.w, clientSize.h);
1684          }
1685          if((clientResized || windowMoved) && created)
1686             OnPosition(position.x, position.y, clientSize.w, clientSize.h);
1687    /*
1688          if(guiApp.interimWindow && guiApp.interimWindow.master.rootWindow == this)
1689          {
1690             Window master = guiApp.interimWindow.master;
1691             master.OnPosition(master.position.x, master.position.y, master.clientSize.w, master.clientSize.h);
1692          }
1693    */
1694          if(rootWindow == this && !is3D)
1695          {
1696             /*if(style.interim)
1697             {
1698                x -= guiApp.desktop.absPosition.x;
1699                y -= guiApp.desktop.absPosition.y;
1700             }*/
1701             //guiApp.Log("Position %s\n", caption);
1702             if(windowHandle)
1703             {
1704                if(windowResized || windowMoved)
1705                   if(display && !display.flags.memBackBuffer && changeRootWindow)
1706                      guiApp.interfaceDriver.PositionRootWindow(this, x, y, w, h, windowMoved, windowResized); //realResized);
1707
1708                if(!guiApp.fullScreenMode && this != guiApp.desktop && (windowResized || windowMoved))
1709                   for(child = parent.children.first; child && child != this; child = child.next)
1710                      if(child.rootWindow)
1711                         guiApp.interfaceDriver.UpdateRootWindow(child.rootWindow);
1712             }
1713
1714             if(display)
1715             {
1716                if(windowMoved || windowResized)
1717                {
1718                   display.Lock(true /*false*/);
1719                }
1720                if(windowMoved)
1721                   display.Position(absPosition.x, absPosition.y);
1722                   //display.Position(absPosition.x + clientStart.x, absPosition.y + clientStart.y);
1723                if(windowResized)
1724                {
1725                   // result = realResized ? display.Resize(size.w, size.h) : true;
1726                   if(nativeDecorations && rootWindow.windowHandle)
1727                   {
1728                      int w = clientSize.w, h = clientSize.h;
1729                      if(hasMenuBar) h += skinMenuHeight;
1730                      if(hasStatusBar) h += statusBarHeight;
1731                      if(sbv && sbv.visible) w += sbv.size.w;
1732                      if(sbh && sbh.visible) h += sbh.size.h;
1733                      result = manageDisplay ? display.Resize(w, h) : true;
1734                   }
1735                   else
1736                      result = manageDisplay ? display.Resize(size.w, size.h) : true;
1737                   resized = true;
1738                   Update(null);
1739                }
1740                else if(clientResized)
1741                   Update(clientArea);
1742                // --- Major Slow Down / Fix OpenGL Resizing Main Window Lag
1743                
1744                /*
1745                if(!guiApp.fullScreenMode && !guiApp.modeSwitching && this == rootWindow)
1746                   UpdateDisplay();
1747                */
1748                
1749                if(windowMoved || windowResized)
1750                {
1751                   display.Unlock();
1752                }
1753             }
1754             if(guiApp.driver && changeRootWindow && windowHandle)
1755             {
1756                if(windowResized || windowMoved)
1757                   if(!display || display.flags.memBackBuffer)
1758                      guiApp.interfaceDriver.PositionRootWindow(this, 
1759                         x, y, w, h, windowMoved, windowResized);
1760                guiApp.interfaceDriver.UpdateRootWindow(this);
1761             }
1762             for(child = children.first; child; child = child.next)
1763             {
1764                if(child.is3D && child.created)
1765                {
1766                   // Copy Display Content
1767                   child.display.displaySystem = display.displaySystem;
1768                   child.display.window = display.window;
1769                   child.display.current = display.current;
1770                   child.display.width = display.width;
1771                   child.display.height = display.height;
1772                   child.display.driverData = display.driverData;
1773                   child.display.mutex = null;
1774                }
1775             }
1776          }
1777          else
1778             result = true;
1779          positioned = false;
1780       }
1781       return result;
1782    }
1783
1784    void UpdateScrollBars(bool flag, bool fullThing)
1785    {
1786       int rvw, rvh;
1787       bool resizeH = false, resizeV = false;
1788       bool scrolled = false;
1789       rvw = (activeChild && activeChild.state == maximized) ? 0 : reqScrollArea.w;
1790       rvh = (activeChild && activeChild.state == maximized) ? 0 : reqScrollArea.h;
1791
1792       if(destroyed) return;
1793       if(guiApp.currentSkin)
1794       {
1795          MinMaxValue cw = 0, ch = 0;
1796          bool sbvVisible, sbhVisible;
1797          int rangeH, rangeV;
1798          int positionH, positionV;
1799
1800          // First get client area with no respect to scroll bars
1801
1802          if(flag)
1803          {
1804             SetWindowArea(
1805                &clientStart.x, &clientStart.y, &size.w, &size.h, &cw, &ch);
1806
1807             if(scrollFlags.dontHide)
1808             {
1809                if(sbv)
1810                   cw -= guiApp.currentSkin.VerticalSBW();
1811                if(sbh)
1812                   ch -= guiApp.currentSkin.HorizontalSBH();
1813
1814                // Update the scrollbar visibility
1815                if(sbh)
1816                {
1817                   sbh.seen = cw;
1818                   sbh.total = rvw;
1819                   rangeH = sbh.range;
1820                   sbh.disabled = rangeH <= 1;
1821                   if(sbh.style.hidden)
1822                   {
1823                      resizeH = true;
1824                   }
1825                }
1826                if(sbv)
1827                {
1828                   sbv.seen = ch;
1829                   sbv.total = rvh;
1830                   rangeV = sbv.range;
1831                   sbv.disabled = rangeV <= 1;
1832                   if(sbv.style.hidden)
1833                   {
1834                      resizeV = true;
1835                   }
1836                }
1837             }
1838             else
1839             {
1840                int oldHRange = sbh ? sbh.range : 0;
1841                int oldVRange = sbv ? sbv.range : 0;
1842                // Then start off with horizontal scrollbar range
1843                if(sbh)
1844                {
1845                   positionH = sbh.thumbPosition;
1846
1847                   /*
1848                   sbh.seen = cw;
1849                   sbh.total = rvw;
1850                   */
1851                   SBSetSeen(sbh, cw);
1852                   SBSetTotal(sbh, rvw);
1853                   rangeH = sbh.range;
1854                   if(rangeH > 1)
1855                      ch -= guiApp.currentSkin.HorizontalSBH();
1856                }
1857
1858                // Do the same for vertical scrollbar
1859                if(sbv)
1860                {
1861                   positionV = sbv.thumbPosition;
1862                   /*
1863                   sbv.seen = ch;
1864                   sbv.total = rvh;
1865                   */
1866                   SBSetSeen(sbv, ch);
1867                   SBSetTotal(sbv, rvh);
1868                   rangeV = sbv.range;
1869                   if(rangeV > 1)
1870                   {
1871                      cw -= guiApp.currentSkin.VerticalSBW();
1872                      // Maybe we need to set the range on the horizontal scrollbar again
1873                      if(sbh)
1874                      {
1875                         /*
1876                         sbh.seen = cw;
1877                         sbh.total = rvw;
1878                         */
1879                         SBSetSeen(sbh, cw);
1880                         SBSetTotal(sbh, rvw);
1881                         //sbh.Action(setRange, positionH, 0);
1882                         if(rangeH <= 1 && sbh.range > 1)
1883                         {
1884                            ch -= guiApp.currentSkin.HorizontalSBH();
1885                            /*
1886                            sbv.seen = ch;
1887                            sbv.total = rvh;
1888                            */
1889                            SBSetSeen(sbv, ch);
1890                            SBSetTotal(sbv, rvh);
1891                            rangeV = sbv.range;
1892                            //sbv.Action(setRange, positionV, 0);
1893                         }
1894                         rangeH = sbh.range;
1895                      }
1896                   }
1897                   if(sbh && sbh.range != oldHRange) sbh.Action(setRange, positionH, 0);
1898                   if(sbv && sbv.range != oldVRange) sbv.Action(setRange, positionV, 0);
1899                }
1900
1901                // Update the scrollbar visibility
1902                if(!scrollFlags.dontHide)
1903                {
1904                   if(sbh && ((rangeH <= 1 && !sbh.style.hidden) || (rangeH > 1 && sbh.style.hidden)))
1905                   {
1906                      resizeH = true;
1907                   }
1908                   if(sbv && ((rangeV <= 1 && !sbv.style.hidden) || (rangeV > 1 && sbv.style.hidden)))
1909                   {
1910                      resizeV = true;
1911                   }
1912                }
1913             }
1914
1915             if(guiApp.currentSkin)
1916             {
1917                clientSize.w = cw;
1918                clientSize.h = ch;
1919             }
1920
1921             if(resizeH)
1922                sbhVisible = sbh.style.hidden ? true : false;
1923             if(resizeV)
1924                sbvVisible = sbv.style.hidden ? true : false;
1925
1926             // Do our resize here
1927             if(flag && (resizeH || resizeV) && fullThing)
1928             {
1929                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, false);
1930                
1931                if(!positioned)
1932                {
1933                   positioned = true;
1934                   OnResize(clientSize.w, clientSize.h);
1935                   positioned = false;
1936                }
1937             }
1938       
1939             if(resizeH && sbh)
1940                sbh.visible = sbhVisible;
1941             if(resizeV && sbv)
1942                sbv.visible = sbvVisible;
1943          }
1944          scrollArea.w = Max(clientSize.w, reqScrollArea.w);
1945          scrollArea.h = Max(clientSize.h, reqScrollArea.h);
1946
1947          if(sbh)
1948             sbh.pageStep = clientSize.w;
1949          if(sbv)
1950             sbv.pageStep = clientSize.h;
1951
1952          // Notify doesn't handle setRange anymore... process it here
1953          if(sbh)
1954          {
1955             int positionH = sbh.thumbPosition;
1956             if(scroll.x != positionH)
1957             {
1958                OnHScroll(setRange, positionH, 0);
1959                scrolled = true;
1960             }
1961             if(guiApp.textMode)
1962                SNAPDOWN(positionH, textCellW);
1963             scroll.x = positionH;
1964          }
1965          else
1966          {
1967             int x = scroll.x;
1968             int range;
1969             int seen = clientSize.w, total = reqScrollArea.w;
1970             seen = Max(1,seen);
1971
1972             if(scrollFlags.snapX)
1973                SNAPDOWN(seen, sbStep.x);
1974
1975             if(!total) total = seen;
1976             range = total - seen + 1;
1977
1978             range = Max(range, 1);
1979             if(x < 0) x = 0;
1980             if(x >= range) x = range - 1;
1981
1982             if(scrollFlags.snapX)
1983                SNAPUP(x, sbStep.x);
1984
1985             if(scroll.x != x)
1986             {
1987                OnHScroll(setRange, x, 0);
1988             }
1989
1990             if(guiApp.textMode)
1991             {
1992                SNAPDOWN(x, textCellW);
1993             }
1994             scroll.x = x;
1995          }
1996          if(sbv)
1997          {
1998             int positionV = sbv.thumbPosition;
1999             if(scroll.y != positionV)
2000             {
2001                OnVScroll(setRange, positionV, 0);
2002                scrolled = true;
2003             }
2004             if(guiApp.textMode)
2005                SNAPDOWN(positionV, textCellH);
2006             scroll.y = positionV;
2007          }
2008          else
2009          {
2010             int y = scroll.y;
2011             int range;
2012             int seen = clientSize.h, total = reqScrollArea.h;
2013             seen = Max(1,seen);
2014
2015             if(scrollFlags.snapY)
2016                SNAPDOWN(seen, sbStep.y);
2017
2018             if(!total) total = seen;
2019             range = total - seen + 1;
2020             range = Max(range, 1);
2021             if(y < 0) y = 0;
2022             if(y >= range) y = range - 1;
2023
2024             if(scrollFlags.snapY)
2025                SNAPUP(y, sbStep.y);
2026
2027             if(scroll.y != y)
2028             {
2029                OnVScroll(setRange, y, 0);
2030             }
2031
2032             if(guiApp.textMode)
2033             {
2034                SNAPDOWN(y, textCellH);
2035             }
2036             scroll.y = y;
2037          }
2038
2039          /*
2040          if(scrolled || (resizeH || resizeV))   // This ensures children anchored to bottom/right gets repositioned correctly
2041          {
2042             Window child;
2043             for(child = children.first; child; child = child.next)
2044             {
2045                if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2046                {
2047                   int x,y,w,h;
2048                   child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
2049                   child.Position(x, y, w, h, false, true, false, true, false, false);
2050                }
2051             }
2052          }
2053          */
2054       }
2055
2056       // Process Scrollbars
2057
2058       if(sbh) // && !sbh.style.hidden
2059       {
2060          if(!sbh.anchored)
2061             sbh.Move(clientStart.x, clientStart.y + clientSize.h, clientSize.w,0);
2062          // Need to set the range again (should improve...) since the scrollbars didn't have
2063          // the right size when UpdateScrollArea set the range on it
2064          if(flag)
2065          {
2066             sbh.seen = clientSize.w;
2067             sbh.total = rvw;
2068          }
2069       }
2070       if(sbv) // && !sbv.state.hidden
2071       {
2072          if(!sbv.anchored)
2073             sbv.Move(clientStart.x + clientSize.w, clientStart.y, 0, clientSize.h);
2074          // Need to set the range again (should improve...) since the scrollbars didn't have
2075          // the right size when UpdateScrollArea set the range on it
2076          if(flag)
2077          {
2078             sbv.seen = clientSize.h;
2079             sbv.total = rvh;
2080          }
2081       }
2082
2083       // TESTING THIS LOWER
2084       if(scrolled || (resizeH || resizeV))   // This ensures children anchored to bottom/right gets repositioned correctly
2085       {
2086          Window child;
2087          for(child = children.first; child; child = child.next)
2088          {
2089             if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2090             {
2091                int x,y,w,h;
2092                child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
2093                child.Position(x, y, w, h, false, true, false, true, false, false);
2094             }
2095          }
2096       }
2097    }
2098
2099    bool MaximizeButtonClicked(Button button, int x, int y, Modifiers mods)
2100    {
2101       SetState(maximized, false, mods);
2102       return false;
2103    }
2104
2105    bool RestoreButtonClicked(Button button, int x, int y, Modifiers mods)
2106    {
2107       SetState(normal, false, mods);
2108       return false;
2109    }
2110
2111    bool MinimizeButtonClicked(Button button, int x, int y, Modifiers mods)
2112    {
2113       SetState(minimized, false, mods);
2114       parent.CycleChildren(false, true, false, true);
2115       return false;
2116    }
2117
2118    void ScrollBarNotification(ScrollBar control, ScrollBarAction action, int position, Key keyFlags)
2119    {
2120       Window child;
2121       // Scroll bar notifications
2122       if(action != setRange)
2123       {
2124          bool changed = false;
2125
2126          if(control == sbh)
2127          {
2128             if(scroll.x != position)
2129             {
2130                OnHScroll(action, position, keyFlags);
2131                changed = true;
2132             }
2133             if(guiApp.textMode)
2134             {
2135                SNAPDOWN(position, textCellW);
2136             }
2137             scroll.x = position;
2138          }
2139          else
2140          {
2141             if(scroll.y != position)
2142             {
2143                OnVScroll(action, position, keyFlags);
2144                changed = true;
2145             }
2146             if(guiApp.textMode)
2147             {
2148                SNAPDOWN(position, textCellH);
2149             }
2150             scroll.y = position;
2151          }
2152          if(changed)
2153          {
2154             bool childMove = false;
2155             for(child = children.first; child; child = child.next)
2156             {
2157                if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2158                {
2159                   int x,y,w,h;
2160                   child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
2161                   child.Position(x, y, w, h, false, true, false, true, false, false);
2162                   childMove = true;
2163                }
2164             }
2165             // Testing this patch out to solve MDI workspace redraw bugs
2166             // We were already supposed to be updating parent's affected area in Position() but it doesn't seem to be working
2167             // Scroll offsets to blame?
2168             if(childMove)
2169                Update(null);
2170          }
2171          UpdateCaret(false, false);
2172       }
2173       else
2174       {
2175          // Testing this patch out to solve MDI workspace redraw bugs
2176          for(child = children.first; child; child = child.next)
2177          {
2178             if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2179             {
2180                Update(null);
2181                break;
2182             }
2183          }         
2184       }
2185    }
2186
2187    Window GetParentMenuBar()
2188    {
2189       Window result = this;
2190       bool notActiveClient = false;
2191       Window menuBarParent;
2192       for(menuBarParent = this; menuBarParent; menuBarParent = menuBarParent.parent)
2193       {
2194          if(menuBarParent.menuBar) { result = notActiveClient ? null : menuBarParent.menuBar; break; }
2195          if(menuBarParent.parent && /*menuBarParent != */!menuBarParent.parent.activeClient)
2196             notActiveClient = true;
2197       }
2198       return result;
2199    }
2200
2201    void CreateSystemChildren(void)
2202    {
2203       Window parent = this;
2204       bool scrollBarChanged = false;
2205       bool hasClose = false, hasMaxMin = false;
2206       Point scroll = this.scroll;
2207
2208       if(state == maximized)
2209          parent = GetParentMenuBar();
2210
2211       if(parent)
2212       {
2213          if(style.hasClose) hasClose = true;
2214          if(style.hasMaximize || style.hasMinimize)
2215          {
2216             hasClose = true;
2217             hasMaxMin = true;
2218          }
2219       }
2220
2221       if(sysButtons[2] && (!hasClose || sysButtons[2].parent != parent))
2222       {
2223          sysButtons[2].Destroy(0);
2224          sysButtons[2] = null;
2225       }
2226       if(sysButtons[1] && (!hasMaxMin || sysButtons[1].parent != parent))
2227       {
2228          sysButtons[1].Destroy(0);
2229          sysButtons[1] = null;
2230       }
2231       if(sysButtons[0] && (!hasMaxMin || sysButtons[0].parent != parent))
2232       {
2233          sysButtons[0].Destroy(0);
2234          sysButtons[0] = null;
2235       }
2236       //return;
2237       if(hasClose && parent)
2238       {
2239          if(!sysButtons[2])
2240          {
2241             sysButtons[2] = 
2242                Button
2243                {
2244                   parent, master = this,
2245                   inactive = true, nonClient = true, visible = false;
2246
2247                   bool NotifyClicked(Button button, int x, int y, Modifiers mods)
2248                   {
2249                      Destroy(0);
2250                      return true;
2251                   }
2252                };
2253             if(this.parent == guiApp.desktop)
2254                sysButtons[2].hotKey = altF4;
2255             else if(style.isActiveClient)
2256                sysButtons[2].hotKey = ctrlF4;
2257             sysButtons[2].Create();
2258          }
2259          
2260          sysButtons[2].symbol = 'X';
2261          sysButtons[2].disabled = !style.hasClose;
2262       }
2263
2264       if(hasMaxMin && parent)
2265       {
2266          SkinBitmap skin;
2267          unichar symbol;
2268          bool (* method)(Window window, Button button, int x, int y, Modifiers mods);
2269          if(state == maximized) 
2270          {
2271             skin = restore;
2272             method = RestoreButtonClicked;
2273             symbol = '\x12';
2274          }
2275          else
2276          {
2277             skin = maximize;
2278             method = MaximizeButtonClicked;
2279             symbol = '\x18';
2280          }
2281          if(!sysButtons[1])
2282          {
2283             sysButtons[1] =
2284                Button
2285                {
2286                   parent, master = this,
2287                   hotKey = altEnter, inactive = true, nonClient = true, visible = false
2288                };
2289             sysButtons[1].Create();
2290          }
2291          sysButtons[1].NotifyClicked = method;
2292
2293          sysButtons[1].symbol = symbol;
2294          sysButtons[1].disabled = !style.hasMaximize;
2295       }
2296
2297       if(hasMaxMin && parent)
2298       {
2299          SkinBitmap skin;
2300          unichar symbol;
2301          bool (* method)(Window window, Button button, int x, int y, Modifiers mods);
2302          if (state == minimized) 
2303          {
2304             skin = restore;
2305             method = RestoreButtonClicked;
2306             symbol = '\x12';
2307          }
2308          else
2309          {
2310             skin = minimize;
2311             method = MinimizeButtonClicked;
2312             symbol = '\x19';
2313          }
2314          if(!sysButtons[0])
2315          {
2316             sysButtons[0] =
2317                Button
2318                {
2319                   parent, master = this,
2320                   hotKey = altM, inactive = true, nonClient = true, visible = false
2321                };
2322             sysButtons[0].Create();
2323          }
2324          sysButtons[0].NotifyClicked = method;
2325
2326          sysButtons[0].symbol = symbol;
2327          sysButtons[0].disabled = !style.hasMinimize;
2328       }
2329
2330       // Create the scrollbars
2331       if(style.hasHorzScroll && !sbh)
2332       {
2333          sbh =
2334             ScrollBar
2335             {
2336                this,
2337                direction = horizontal,
2338                windowOwned = true,
2339                inactive = true,
2340                nonClient = true,
2341                snap = scrollFlags.snapX,
2342                NotifyScrolling = ScrollBarNotification
2343             };
2344          sbh.Create();
2345          scrollBarChanged = true;
2346       }
2347       else if(sbh && !style.hasHorzScroll)
2348       {
2349          sbh.Destroy(0);
2350          sbh = null;
2351       }
2352
2353       if(style.hasVertScroll && !sbv)
2354       {
2355          sbv =
2356             ScrollBar
2357             {
2358                this,
2359                direction = vertical,
2360                windowOwned = true,
2361                inactive = true,
2362                nonClient = true,
2363                snap = scrollFlags.snapY,
2364                NotifyScrolling = ScrollBarNotification
2365             };
2366          sbv.Create();
2367          scrollBarChanged = true;
2368       }
2369       else if(sbv && !style.hasVertScroll)
2370       {
2371          sbv.Destroy(0);
2372          sbv = null;
2373       }
2374       if(scrollBarChanged)
2375       {
2376          SetScrollLineStep(sbStep.x, sbStep.y);   
2377          UpdateScrollBars(true, true);
2378       }   
2379       UpdateNonClient();
2380
2381       if(scrollBarChanged)
2382       {
2383          if(sbh) sbh.thumbPosition = scroll.x;
2384          if(sbv) sbv.thumbPosition = scroll.y;
2385       }
2386    }
2387
2388    void UpdateCaption(void)
2389    {
2390       if(rootWindow == this)
2391       {
2392          char caption[2048];
2393          FigureCaption(caption);
2394          guiApp.interfaceDriver.SetRootWindowCaption(this, caption);
2395       }
2396       UpdateDecorations();
2397       if(parent)
2398       {
2399          if(parent.activeClient == this) // Added this last check
2400          {
2401             if(parent.rootWindow == parent)
2402             {
2403                char caption[2048];
2404                parent.FigureCaption(caption);
2405                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
2406             }
2407             else
2408                parent.UpdateCaption();
2409          }
2410          parent.UpdateDecorations();
2411       }
2412    }
2413
2414    void UpdateActiveDocument(Window previous)
2415    {
2416       Window activeClient = this.activeClient;
2417       Window activeChild = this.activeChild;
2418       if(menuBar)
2419       {
2420          UpdateCaption();
2421          if(!destroyed)
2422          {
2423             if(activeClient)
2424                activeClient.CreateSystemChildren();
2425             if(previous)
2426                previous.CreateSystemChildren();
2427          }
2428       }
2429
2430       if(menu)
2431       {
2432          MenuItem item;
2433          bool disabled;
2434
2435          if(menu)
2436             menu.Clean(this);
2437
2438          // Build window list
2439          if(activeClient)
2440          {
2441             Menu windowMenu = menu.FindMenu("Window");
2442             if(windowMenu)
2443             {
2444                OldLink cycle;
2445                int id;
2446                for(id = 0, cycle = activeClient.cycle; cycle && id<10;)
2447                {
2448                   MenuItem item;
2449                   Window document = cycle.data;
2450                   if(!document.style.nonClient && document.style.isActiveClient && document.visible)
2451                   {
2452                      char name[2048], caption[2048];
2453                      document.FigureCaption(caption);
2454                      sprintf(name, "%d %s", id+1, caption);
2455                      windowMenu.AddDynamic(MenuItem 
2456                         { 
2457                            copyText = true, text = name, hotKey = Key { k1 + id }, id = id++, 
2458                            NotifySelect = MenuWindowSelectWindow 
2459                         }, this, false);
2460                   }
2461                   cycle = cycle.next;
2462                   if(activeClient.cycle == cycle) break;
2463                }
2464             }
2465          }
2466          
2467          if((!previous && activeClient) || !activeClient)
2468          {
2469             if(!activeClient)
2470                disabled = true;
2471             else
2472                disabled = false;
2473             item = menu.FindItem(MenuWindowCloseAll, 0);
2474             if(item) item.disabled = false;
2475             item = menu.FindItem(MenuWindowNext, 0);
2476             if(item) item.disabled = false;
2477             item = menu.FindItem(MenuWindowPrevious, 0);
2478             if(item) item.disabled = false;
2479             item = menu.FindItem(MenuWindowCascade, 0);
2480             if(item) item.disabled = false;
2481             item = menu.FindItem(MenuWindowTileHorz, 0);
2482             if(item) item.disabled = false;
2483             item = menu.FindItem(MenuWindowTileVert, 0);
2484             if(item) item.disabled = false;
2485             item = menu.FindItem(MenuWindowArrangeIcons, 0);
2486             if(item) item.disabled = false;
2487             item = menu.FindItem(MenuWindowWindows, 0);
2488             if(item) item.disabled = false;
2489          }      
2490
2491          item = menu.FindItem(MenuFileClose, 0);
2492          if(item) item.disabled = !activeClient || !activeClient.style.hasClose;
2493          item = menu.FindItem(MenuFileSaveAll, 0);
2494          if(item) item.disabled = numDocuments < 1;
2495
2496          if(activeClient && activeClient.menu && activeClient.state != minimized)
2497          {
2498             if(mergeMenus)
2499             {
2500                //activeClient.menu.Clean(activeClient);
2501                menu.Merge(activeClient.menu, true, activeClient);
2502             }
2503          }
2504
2505          if(activeChild && activeChild != activeClient && activeChild.menu && activeChild.state != minimized)
2506          {
2507             if(mergeMenus)
2508                menu.Merge(activeChild.menu, true, activeChild);
2509          }
2510       }
2511       // This is called again for a child window change, with same active client
2512       OnActivateClient(activeClient, previous);
2513       if(!menuBar && !((BorderBits)borderStyle).fixed && parent && parent.activeClient == this)
2514          parent.UpdateActiveDocument(null);
2515    }
2516
2517    void _ShowDecorations(Box box, bool post)
2518    {
2519       if(rootWindow == this && nativeDecorations) return;
2520       if(visible && this != guiApp.desktop)
2521       {
2522          Surface surface = RedrawFull(box);
2523          if(surface)
2524          {
2525             char caption[2048];
2526             FigureCaption(caption);
2527             
2528             if(post)
2529                ShowDecorations(captionFont.font,
2530                   surface,
2531                   caption,
2532                   active, //parent.activeClient == this
2533                   guiApp.windowMoving == this);
2534             else
2535                PreShowDecorations(captionFont.font,
2536                   surface,
2537                   caption,
2538                   active, //parent.activeClient == this
2539                   guiApp.windowMoving == this);
2540                
2541             delete surface;
2542          }
2543       }
2544    }
2545
2546    void UpdateExtent(Box refresh)
2547    {
2548       Surface surface = null;
2549
2550       if(!manageDisplay) { OnRedraw(null);return; }
2551       _ShowDecorations(refresh, false);
2552
2553       surface = Redraw(refresh);               
2554       // Opaque background: just fill before EW_REDRAW (clear?)
2555       if(surface) 
2556       {
2557          surface.SetBackground(background);
2558          surface.SetForeground(foreground);
2559          surface.DrawingChar(' ');
2560          if(this == rootWindow)
2561          {
2562             if(style.drawBehind || background.a)
2563             {
2564                int a = background.a;
2565                // Premultiply alpha for clear color
2566                surface.SetBackground({ (byte)a, { (byte)(a*background.color.r/255), (byte)(a*background.color.g/255), (byte)(a*background.color.b/255) } });
2567                surface.Clear(colorBuffer);
2568                surface.SetBackground(background);
2569             }
2570          }
2571          else if(background.a)
2572          {
2573 #ifdef _DEBUG
2574             /*
2575             background.color = { (byte)GetRandom(0,255), (byte)GetRandom(0,255), (byte)GetRandom(0,255) };
2576             surface.SetForeground((background.color.r > 128 || background.color.g > 128) ? black : white);
2577             */
2578 #endif
2579             if(display.flags.alpha && background.a < 255 && background)
2580             {
2581                surface.Area(0,0,clientSize.w, clientSize.h);
2582                /*if(style.clearDepthBuffer)
2583                   surface.Clear(depthBuffer);*/
2584             }
2585             else if(/*style.clearDepthBuffer || */background.a)
2586             {
2587                int a = background.a;
2588                // surface.Clear((style.clearDepthBuffer ? depthBuffer : 0) | (background.a ? colorBuffer : 0));
2589                // Premultiply alpha for clear color
2590                surface.SetBackground({ (byte)a, { (byte)(a*background.color.r/255), (byte)(a*background.color.g/255), (byte)(a*background.color.b/255) } });
2591                surface.Clear(colorBuffer);
2592                surface.SetBackground(background);
2593             }
2594          }
2595
2596          // Default Settings
2597          surface.TextFont(usedFont.font);
2598          surface.TextOpacity(false);
2599
2600          OnRedraw(surface);
2601
2602          // Draw the caret ...
2603          if(!disabled && this == guiApp.caretOwner && guiApp.caretEnabled /*&& !guiApp.interimWindow*/ && !guiApp.currentSkin.textMode)
2604          {
2605             // surface.SetBackground(0xFFFFFF - background.color);
2606             surface.SetBackground(~background.color);
2607             surface.Area(
2608                caretPos.x - scroll.x + 1, caretPos.y - scroll.y,
2609                caretPos.x - scroll.x + 2, caretPos.y - scroll.y + caretSize - 1);
2610          }
2611          delete surface;
2612       }
2613    }
2614
2615    void DrawOverChildren(Box refresh)
2616    {
2617       Surface surface = Redraw(refresh);               
2618       if(surface) 
2619       {
2620          // Default Settings
2621          surface.DrawingChar(' ');
2622          surface.SetBackground(background);
2623          surface.SetForeground(foreground);
2624
2625          surface.TextFont(usedFont.font);
2626          surface.TextOpacity(false);
2627
2628          OnDrawOverChildren(surface);
2629
2630          delete surface;
2631
2632       }
2633       _ShowDecorations(refresh, true);
2634    }
2635
2636    void ComputeClipExtents(void)
2637    {
2638       Window child;
2639       Extent clipExtent { /*first = -1, last = -1, free = -1*/ };
2640
2641       clipExtent.Copy(this.clipExtent);
2642       
2643       for(child = children.last; child; child = child.prev)
2644       {
2645          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2646          {
2647             bool opaque = child.IsOpaque(); // TODO: acess background directly 
2648             int dx = child.absPosition.x - absPosition.x, dy = child.absPosition.y - absPosition.y;
2649
2650             child.clipExtent.Copy(clipExtent);
2651             child.clipExtent.Offset(-dx, -dy);
2652             child.clipExtent.IntersectBox(child.box);
2653
2654             child.ComputeClipExtents();
2655
2656             if(opaque && !child.style.nonClient)
2657             {
2658                // Adjust the box for the parent:
2659                Box box { child.box.left + dx, child.box.top + dy, child.box.right + dx, child.box.bottom + dy };
2660                clipExtent.ExcludeBox(box, rootWindow.tempExtents[0]);
2661             }
2662             
2663          }
2664       }
2665       // ??? Only do this for overlapped window or if parent has with clip children flag
2666
2667       // Do this if window has clip children flag on (default false?)
2668       // this.clipExtent = clipExtent;
2669
2670       clipExtent.Free(null);
2671    }
2672
2673    void ComputeRenderAreaNonOpaque(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate)
2674    {
2675       bool opaque = IsOpaque();
2676       Window child;
2677       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2678       if(rootWindow.nativeDecorations && rootWindow.windowHandle)
2679       {
2680          offsetX -= rootWindow.clientStart.x;
2681          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2682       }
2683
2684
2685       for(child = children.last; child; child = child.prev)
2686       {
2687          ColorAlpha background = *(ColorAlpha *)&child.background;
2688          bool opaque = child.IsOpaque();
2689          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2690          {
2691             if(!opaque)
2692             {
2693                // Adjust renderArea to the root window level
2694                Extent * renderArea = &rootWindow.tempExtents[1];
2695
2696                int offsetX = child.absPosition.x - rootWindow.absPosition.x, offsetY = child.absPosition.y - rootWindow.absPosition.y;
2697                if(child.rootWindow.nativeDecorations && rootWindow.windowHandle)
2698                {
2699                   offsetX -= child.rootWindow.clientStart.x;
2700                   offsetY -= child.rootWindow.clientStart.y - (child.rootWindow.hasMenuBar ? skinMenuHeight : 0);
2701                }
2702
2703                /*
2704                Extent childRenderArea;
2705                
2706                if(backBufferUpdate != null)
2707                {
2708                   childRenderArea.Copy(backBufferUpdate);
2709                   childRenderArea.Offset(-offsetX, -offsetY);
2710                }
2711                else
2712                   childRenderArea.Copy(child.dirtyArea);
2713
2714                // Add extent forced by transparency to the dirty area, adjusting dirty extent to the window
2715                renderArea.Copy(dirtyExtent);
2716                renderArea.Offset(-offsetX, -offsetY);
2717                childRenderArea.Union(renderArea);
2718                renderArea.Free();
2719
2720                // Intersect with the clip extent
2721                childRenderArea.Intersection(child.clipExtent);
2722                */
2723
2724                renderArea->Copy(child.dirtyArea /*childRenderArea*/);
2725                renderArea->Offset(offsetX, offsetY);
2726                dirtyExtent.Union(renderArea, rootWindow.tempExtents[0]);
2727                // overDirtyExtent.Union(renderArea);
2728                renderArea->Empty();
2729                // childRenderArea.Free();
2730
2731                //child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2732             }
2733          }
2734       }
2735
2736       for(child = children.last; child; child = child.prev)
2737       {
2738          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2739          {
2740             child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2741          }
2742       }
2743    }
2744
2745    void ComputeRenderArea(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate)
2746    {
2747       bool opaque = IsOpaque();
2748       Extent * dirtyExtentWindow = &rootWindow.tempExtents[1];
2749       Window child;
2750       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2751       if(rootWindow.nativeDecorations && rootWindow.windowHandle)
2752       {
2753          offsetX -= rootWindow.clientStart.x;
2754          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2755       }
2756
2757 #if 0
2758       for(child = children.last; child; child = child.prev)
2759       {
2760          //child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2761          /*
2762          ColorAlpha background = *(ColorAlpha *)&child.background;
2763          bool opaque = child.IsOpaque();
2764          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2765          {
2766             if(!opaque)
2767             {
2768                int offsetX = child.absPosition.x - rootWindow.absPosition.x, offsetY = child.absPosition.y - rootWindow.absPosition.y;
2769                // Adjust renderArea to the root window level
2770                Extent renderArea;
2771                renderArea.Copy(child.dirtyArea);
2772                renderArea.Offset(offsetX, offsetY);
2773                dirtyExtent.Union(renderArea);
2774                overDirtyExtent.Union(renderArea);
2775                renderArea.Free();
2776             }
2777          }*/
2778       }
2779 #endif
2780       for(child = children.last; child; child = child.prev)
2781       {
2782          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2783          {
2784             child.ComputeRenderArea(dirtyExtent, overDirtyExtent, backBufferUpdate);
2785          }
2786       }
2787
2788       if(backBufferUpdate != null)
2789       {
2790          renderArea.Copy(backBufferUpdate);
2791          renderArea.Offset(-offsetX, -offsetY);
2792          
2793          overRenderArea.Copy(backBufferUpdate);
2794          overRenderArea.Offset(-offsetX, -offsetY);
2795          
2796          
2797       }
2798       else
2799       {
2800          renderArea.Copy(dirtyArea);
2801          
2802          overRenderArea.Copy(dirtyArea);
2803       }
2804
2805       // Add extent forced by transparency to the dirty area, adjusting dirty extent to the window
2806       dirtyExtentWindow->Copy(dirtyExtent);
2807       dirtyExtentWindow->Offset(-offsetX, -offsetY);
2808       renderArea.Union(dirtyExtentWindow, rootWindow.tempExtents[0]);
2809       dirtyExtentWindow->Empty();
2810
2811       // Intersect with the clip extent
2812       renderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2813
2814       /*
2815       if(renderArea.count > 10)
2816       {
2817          BoxItem extentBox;
2818          printf("\nToo many extents (%d):\n", renderArea.count);
2819
2820          //extent.UnionBox({ 112, 6, 304, 7 }, rootWindow.tempExtents[0]);
2821          //extent.UnionBox({ 112, 8, 304, 17 }, rootWindow.tempExtents[0]);
2822          //printf("Test\n");
2823
2824          {
2825             int c;
2826             for(c = 0; c<10; c++)
2827             {
2828                Extent extent { };
2829                FASTLIST_LOOP(renderArea, extentBox)
2830                {
2831                   extent.UnionBox(extentBox.box, rootWindow.tempExtents[0]);
2832                }
2833                renderArea.Copy(extent);
2834
2835                FASTLIST_LOOP(renderArea, extentBox)
2836                {
2837       #ifdef _DEBUG
2838                   printf("(%d, %d) - (%d, %d)\n", 
2839                      extentBox.box.left, extentBox.box.top, 
2840                      extentBox.box.right, extentBox.box.bottom);
2841       #endif
2842                }
2843
2844                printf("\nNow %d\n", renderArea.count);
2845             }
2846          }
2847       }
2848       */
2849       
2850       // WHY WAS THIS COMMENTED ??
2851
2852       // Add extent forced by DrawOverChildren to the dirty area, adjusting dirty extent to the window
2853       dirtyExtentWindow->Copy(overDirtyExtent);
2854       dirtyExtentWindow->Offset(-offsetX, -offsetY);
2855       overRenderArea.Union(dirtyExtentWindow, rootWindow.tempExtents[0]);
2856       dirtyExtentWindow->Empty();
2857
2858       // Intersect with the clip extent
2859       overRenderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2860       
2861
2862       if(opaque)
2863       {
2864          // Scrolling
2865          if(scrollExtent.count)
2866          {
2867             // Subtract render extent from scrolling extent
2868             scrollExtent.Exclusion(renderArea, rootWindow.tempExtents[0]);
2869
2870             if(backBufferUpdate == null)
2871             {
2872                Extent * dirty = &rootWindow.tempExtents[3];
2873                BoxItem scrollBox;
2874
2875                // Intersect scrolling extent with clip extent
2876                scrollExtent.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2877
2878                // offset this scroll to be at the root window level
2879                scrollExtent.Offset(offsetX, offsetY);
2880                // Add area that was scrolled to the dirty extents of the back buffer
2881                rootWindow.dirtyBack.Union(scrollExtent, rootWindow.tempExtents[0]);
2882
2883                dirty->Empty();
2884
2885                // Will need scrolledArea.x & scrolledArea.y to support multiple scrolls
2886                for(scrollBox = (BoxItem)scrollExtent.first; scrollBox; scrollBox = (BoxItem)scrollBox.next)
2887                   display.Scroll(scrollBox.box, scrolledArea.x, scrolledArea.y, dirty);
2888
2889                scrolledArea.x = 0;
2890                scrolledArea.y = 0;
2891
2892                scrollExtent.Empty();
2893
2894                // Add the exposed extent to the window render area
2895                dirty->Offset(-offsetX, -offsetY);
2896                renderArea.Union(dirty, rootWindow.tempExtents[0]);
2897                dirty->Empty();
2898             }
2899          }
2900
2901          // Subtract the window's box from the transparency forced extent
2902          dirtyExtent.ExcludeBox({box.left + offsetX, box.top + offsetY, box.right + offsetX, box.bottom + offsetY }, rootWindow.tempExtents[0]);
2903       }
2904       /*else
2905       {
2906          Extent renderArea;
2907
2908          renderArea.Copy(this.renderArea);
2909          renderArea.Offset(offsetX, offsetY);
2910          dirtyExtent.Union(renderArea);
2911          renderArea.Free();
2912       }*/
2913       
2914       
2915       {
2916          Extent renderArea { };
2917          
2918          renderArea.Copy(overRenderArea);
2919          renderArea.Offset(offsetX, offsetY);
2920          overDirtyExtent.Union(renderArea, rootWindow.tempExtents[0]);
2921          renderArea.Empty();
2922       }
2923       
2924
2925       if(backBufferUpdate != null)
2926       {
2927          // Remove render area from dirty area
2928          dirtyArea.Exclusion(renderArea, rootWindow.tempExtents[0]);
2929
2930          dirtyArea.Exclusion(overRenderArea, rootWindow.tempExtents[0]);
2931       }
2932       else
2933          dirtyArea.Empty();
2934
2935       clipExtent.Empty();
2936    /*
2937       // Remove the window render area from the dirty extents of the back buffer
2938       rootWindow.dirtyBack.Exclusion(renderArea);
2939    */
2940    }
2941
2942    void Render(Extent updateExtent)
2943    {
2944       BoxItem extentBox;
2945       Window child;
2946       Window rootWindow = this.rootWindow;
2947       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2948       if(rootWindow.nativeDecorations && rootWindow.windowHandle)
2949       {
2950          offsetX -= rootWindow.clientStart.x;
2951          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2952       }
2953
2954       if(rootWindow.fullRender)
2955       {
2956          UpdateExtent(box);
2957          dirtyArea.Empty();
2958       }
2959       else
2960       {
2961 #ifdef _DEBUG
2962          /*
2963          background = Color { (byte)GetRandom(0,255), (byte)GetRandom(0,255), (byte)GetRandom(0,255) };
2964          foreground = (background.color.r > 128 || background.color.g > 128) ? black : white;
2965          */
2966 #endif
2967             
2968 #ifdef _DEBUG
2969          /*if(renderArea.count)
2970             printf("\n\nRendering %s (%x):\n------------------------------------------\n", _class.name, this);*/
2971 #endif
2972             
2973          for(extentBox = (BoxItem)renderArea.first; extentBox; extentBox = (BoxItem)extentBox.next)
2974          {
2975             Box box = extentBox.box;
2976
2977 #ifdef _DEBUG
2978                /*printf("(%d, %d) - (%d, %d)\n", 
2979                   extentBox.box.left, extentBox.box.top, 
2980                   extentBox.box.right, extentBox.box.bottom);*/
2981 #endif
2982                
2983             UpdateExtent(box);
2984
2985             box.left += offsetX;
2986             box.top += offsetY;
2987             box.right += offsetX;
2988             box.bottom += offsetY;
2989
2990             if(updateExtent != null)
2991                updateExtent.UnionBox(box, rootWindow.tempExtents[0]);
2992          }
2993       }
2994
2995       for(child = children.first; child; child = child.next)
2996          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow && !child.nonClient)
2997             child.Render(updateExtent);
2998
2999       if(rootWindow.fullRender)
3000          DrawOverChildren(box);
3001       else
3002       {
3003          // TO DO: There's an issue about draw over children...
3004          // TO DO: Don't wanna go through this if method isn't used
3005          for(extentBox = (BoxItem)overRenderArea.first; extentBox; extentBox = (BoxItem)extentBox.next)
3006          //FASTLIST_LOOP(/*renderArea */overRenderArea, extentBox)
3007          {
3008             Box box = extentBox.box;
3009
3010             DrawOverChildren(box);
3011
3012             box.left += offsetX;
3013             box.top += offsetY;
3014             box.right += offsetX;
3015             box.bottom += offsetY;
3016
3017             if(updateExtent != null)
3018                updateExtent.UnionBox(box, rootWindow.tempExtents[0]);
3019          }
3020       }
3021       for(child = children.first; child; child = child.next)
3022          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow && child.nonClient)
3023             child.Render(updateExtent);
3024
3025       renderArea.Empty();
3026       overRenderArea.Empty();
3027    }
3028
3029    public void UpdateDisplay(void)
3030    {
3031       if(!manageDisplay) { OnRedraw(null);return; }
3032       if(rootWindow && this != rootWindow) 
3033          rootWindow.UpdateDisplay();
3034       else if(display)
3035       {
3036          Extent dirtyExtent { /*first = -1, last = -1, free = -1*/ };  // Extent that needs to be forced due to transparency
3037          Extent overExtent { /*first = -1, last = -1, free = -1*/ };  // Extent that forced for DrawOverChildren
3038          BoxItem extentBox;
3039
3040          dirtyExtent.Clear();
3041          overExtent.Clear();
3042
3043          clipExtent.AddBox(box);
3044
3045          display.StartUpdate();
3046
3047          if(!rootWindow.fullRender)
3048          {
3049             ComputeClipExtents();
3050             ComputeRenderAreaNonOpaque(dirtyExtent, overExtent, null);
3051             ComputeRenderArea(dirtyExtent, overExtent, null);
3052          }
3053          else
3054             clipExtent.Free(null);                     
3055
3056          dirtyExtent.Free(null);
3057          overExtent.Free(null);
3058
3059          if(display.flags.flipping)
3060          {
3061             Render(null);
3062             display.Update(null);
3063          }
3064          else
3065          {
3066             Extent updateExtent { /*first = -1, last = -1, free = -1*/ }; // Extent that needs to be updated
3067             updateExtent.Clear();
3068
3069             Render(updateExtent);
3070             if(fullRender)
3071                updateExtent.UnionBox(this.box, tempExtents[0]);
3072             
3073 #ifdef _DEBUG
3074             //printf("\n\nUpdate:\n------------------------------------------\n");
3075 #endif
3076             
3077             //FASTLIST_LOOP(updateExtent, extentBox)
3078             for(extentBox = (BoxItem)updateExtent.first; extentBox; extentBox = (BoxItem)extentBox.next)
3079             {
3080 #ifdef _DEBUG
3081                /*printf("Updating (%d, %d) - (%d, %d)\n", 
3082                   extentBox.box.left, extentBox.box.top, 
3083                   extentBox.box.right, extentBox.box.bottom);*/
3084 #endif
3085                
3086                display.Update(extentBox.box);
3087                
3088             }
3089             updateExtent.Free(null);
3090          }
3091
3092          display.EndUpdate();
3093          dirtyBack.Empty();
3094
3095          dirty = false;
3096          resized = false;
3097       }
3098    }
3099
3100    void UpdateBackDisplay(Box box)
3101    {
3102       if(display)
3103       {
3104          Extent dirtyExtent;
3105          Extent overExtent;
3106          Extent intersection { /*first = -1, last = -1, free = -1*/ };
3107
3108          //printf("UpdateBackDisplay going through!\n");
3109          display.StartUpdate();
3110
3111          if(resized)
3112          {
3113             intersection.Copy(dirtyBack);
3114             intersection.IntersectBox(box);
3115          
3116             dirtyExtent.Clear();
3117             overExtent.Clear();
3118
3119             clipExtent.AddBox(box);
3120          
3121             if(!rootWindow.fullRender)
3122             {
3123                ComputeClipExtents();
3124                ComputeRenderArea(dirtyExtent, overExtent, intersection);
3125             }
3126             else
3127                clipExtent.Free(null);
3128
3129             intersection.Free(null);
3130             dirtyExtent.Free(null);
3131             overExtent.Free(null);
3132
3133             Render(null);
3134          }
3135
3136          if(display.flags.flipping)
3137             display.Update(null);
3138          else
3139          {
3140             rootWindow.display.Update(box);
3141          }
3142
3143          display.EndUpdate();
3144
3145          if(resized)
3146          {
3147             dirtyBack.ExcludeBox(box, rootWindow.tempExtents[0]);
3148             if(dirtyBack.count > MAX_DIRTY_BACK)
3149             {
3150                BoxItem extentBox, next;
3151                BoxItem first = (BoxItem)ACCESS_ITEM(dirtyBack, dirtyBack.first);
3152                for(extentBox = (BoxItem)dirtyBack.first; extentBox; extentBox = next)
3153                {
3154                   next = (BoxItem)extentBox.next;
3155                   if(extentBox != first)
3156                   {
3157                      if(extentBox.box.left < first.box.left)
3158                         first.box.left = extentBox.box.left;
3159                      if(extentBox.box.top < first.box.top)
3160                         first.box.top = extentBox.box.top;
3161                      if(extentBox.box.right > first.box.right)
3162                         first.box.right = extentBox.box.right;
3163                      if(extentBox.box.bottom > first.box.bottom)
3164                         first.box.bottom = extentBox.box.bottom;
3165                      dirtyBack.Delete(extentBox);
3166                   }
3167                }
3168             }
3169             resized = false;
3170          }
3171       }
3172    }
3173
3174    // --- Window positioning ---
3175    // --- Window identification ---
3176
3177    // Returns window at position "Position"
3178    Window GetAtPosition(int x, int y, bool clickThru, bool acceptDisabled, Window last)
3179    {
3180       Window child, result = null;
3181       Box box = this.box;
3182       box.left += absPosition.x;
3183       box.right += absPosition.x;
3184       box.top += absPosition.y;
3185       box.bottom += absPosition.y;
3186
3187       if(!destroyed && visible && (acceptDisabled || !disabled))
3188       {
3189          int lx = x - absPosition.x;
3190          int ly = y - absPosition.y;
3191          if(IsInside(lx, ly))
3192          // if(box.IsPointInside(Point{x, y}))
3193          {
3194             if(!clickThru || !style.clickThrough) result = (this == last) ? null : this;
3195             // If the window is disabled, stop looking in children (for acceptDisabled mode)
3196             if(!disabled)
3197             {
3198                for(child = (last && last.parent == this) ? last.previous : children.last; child; child = child.prev)
3199                {
3200                   if(child != statusBar && child.rootWindow == rootWindow)
3201                   {
3202                      Window childResult = child.GetAtPosition(x, y, clickThru, acceptDisabled, last);
3203                      if(childResult) 
3204                         return childResult;
3205                   }
3206                }
3207                if(clickThru)
3208                {
3209                   for(child = (last && last.parent == this) ? last.previous : children.last; child; child = child.prev)
3210                   {
3211                      if(child != statusBar && child.rootWindow == rootWindow)
3212                      {
3213                         Window childResult = child.GetAtPosition(x, y, false, acceptDisabled, last);
3214                         if(childResult)
3215                            return childResult;
3216                      }
3217                   }
3218                }
3219             }
3220          }
3221       }
3222       return result;
3223    }
3224
3225    Window FindModal(void)
3226    {
3227       Window modalWindow = this, check;
3228       Window check2 = null;
3229       for(check = this; check.master; check = check.master)
3230       {
3231          if(check.master.modalSlave && check.master.modalSlave.created && check != check.master.modalSlave)
3232          {
3233             modalWindow = check.master.modalSlave;
3234             check = modalWindow;
3235          }
3236          // TESTING THIS FOR DROPBOX...
3237          if(!rootWindow || !rootWindow.style.interim)
3238          {
3239             for(check2 = check; check2.activeChild; check2 = check2.activeChild)
3240             {
3241                if(check2.modalSlave && check2.modalSlave.created)
3242                {
3243                   modalWindow = check2.modalSlave;
3244                   break;
3245                }
3246             }
3247          }
3248       }
3249
3250       /*
3251       if(modalWindow == this)
3252       {
3253          for(check = this; check.activeChild; check = check.activeChild)
3254          {
3255             if(check.modalSlave)
3256             {
3257                modalWindow = check.modalSlave;
3258                break;
3259             }
3260          }
3261       }
3262       */
3263       for(; modalWindow.modalSlave && modalWindow.modalSlave.created; modalWindow = modalWindow.modalSlave);
3264       return (modalWindow == this || this == guiApp.interimWindow || IsDescendantOf(modalWindow)) ? null : modalWindow;
3265    }
3266
3267    void StopMoving(void)
3268    {
3269       if(this == guiApp.windowMoving)
3270       {
3271          guiApp.windowMoving = null;
3272          UpdateDecorations();
3273          SetMouseRange(null);
3274          if(rootWindow)
3275          {
3276             if(rootWindow.active)
3277                guiApp.interfaceDriver.StopMoving(rootWindow);
3278          }
3279          ReleaseCapture();
3280          guiApp.resizeX = guiApp.resizeY = guiApp.resizeEndX = guiApp.resizeEndY = false;
3281          guiApp.windowIsResizing = false;
3282       }
3283    }
3284
3285    void SelectMouseCursor(void)
3286    {
3287       int x,y;
3288       Window mouseWindow;
3289       Window modalWindow;
3290       Window cursorWindow = null;
3291       bool rx, ry, rex, rey;
3292
3293       guiApp.desktop.GetMousePosition(&x, &y);
3294       mouseWindow = rootWindow ? rootWindow.GetAtPosition(x,y, true, false, null) : null;
3295
3296       if((guiApp.windowMoving && !guiApp.windowIsResizing) || guiApp.windowScrolling)
3297          guiApp.SetCurrentCursor(guiApp.systemCursors[moving]);
3298       else if(mouseWindow)
3299       {
3300          modalWindow = mouseWindow.FindModal();
3301          x -= mouseWindow.absPosition.x;
3302          y -= mouseWindow.absPosition.y;
3303          if(guiApp.windowIsResizing)
3304          {
3305             rex = guiApp.resizeEndX;
3306             rey = guiApp.resizeEndY;
3307             rx = guiApp.resizeX;
3308             ry = guiApp.resizeY;
3309             if((rex && rey) || (rx && ry))
3310                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
3311             else if((rex && ry) || (rx && rey))
3312                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
3313             else if((ry || rey) && (!rx && !rex))
3314                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
3315             else if((rx || rex) && (!ry && !rey))
3316                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
3317          }
3318          else if(!modalWindow && !guiApp.windowCaptured &&
3319             mouseWindow.IsMouseResizing(x, y, mouseWindow.size.w, mouseWindow.size.h,
3320                &rx, &ry, &rex, &rey))
3321          {
3322             if((rex && rey) || (rx && ry))
3323                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
3324             else if((rex && ry) || (rx && rey))
3325                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
3326             else if((ry || rey) && (!rx && !rex))
3327                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
3328             else if((rx || rex) && (!ry && !rey))
3329                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
3330          }
3331          else if(!guiApp.windowCaptured && !modalWindow && !guiApp.interimWindow)
3332          {
3333             if(!mouseWindow.clientArea.IsPointInside({x - mouseWindow.clientStart.x, y - mouseWindow.clientStart.y}))
3334                cursorWindow = mouseWindow.parent;
3335             else
3336                cursorWindow = mouseWindow;
3337          }
3338          else if(!guiApp.interimWindow)
3339             cursorWindow = guiApp.windowCaptured;
3340          if(cursorWindow)
3341          {
3342             for(; !cursorWindow.cursor && !cursorWindow.style.nonClient; cursorWindow = cursorWindow.parent);
3343             guiApp.SetCurrentCursor(cursorWindow.cursor ? cursorWindow.cursor : guiApp.systemCursors[arrow]);
3344          }
3345          else if(modalWindow)
3346          {
3347             guiApp.SetCurrentCursor(guiApp.systemCursors[arrow]);
3348          }
3349          else if(guiApp.interimWindow)
3350          {
3351             if(guiApp.interimWindow.cursor)
3352                guiApp.SetCurrentCursor(guiApp.interimWindow.cursor);
3353             else
3354                guiApp.SetCurrentCursor(mouseWindow.cursor ? mouseWindow.cursor : guiApp.systemCursors[arrow]);
3355          }
3356       }
3357    }
3358
3359    // --- State based input ---
3360    bool AcquireInputEx(bool state)
3361    {
3362       bool result;
3363       if(state) 
3364       {
3365          guiApp.interfaceDriver.GetMousePosition(&guiApp.acquiredMouseX, &guiApp.acquiredMouseY);
3366          guiApp.interfaceDriver.SetMousePosition(clientSize.w/2 + absPosition.x, clientSize.h/2 + absPosition.y);
3367       }
3368       result = guiApp.interfaceDriver.AcquireInput(rootWindow, state);
3369       if(result)
3370          guiApp.acquiredWindow = state ? this : null;
3371       if(state && result)
3372       {
3373          SetMouseRangeToClient();
3374          guiApp.interfaceDriver.SetMouseCursor((SystemCursor)-1);
3375       }
3376       else
3377       {
3378          FreeMouseRange();
3379          SelectMouseCursor();
3380       }
3381       if(!state) guiApp.interfaceDriver.SetMousePosition(guiApp.acquiredMouseX, guiApp.acquiredMouseY);
3382       return result;
3383    }
3384
3385    // --- Window activation ---
3386    bool PropagateActive(bool active, Window previous, bool * goOnWithActivation, bool direct)
3387    {
3388       bool result = true;
3389       if(!parent || !parent.style.inactive)
3390       {
3391          Window parent = this.parent;
3392
3393          /*
3394          if(rootWindow == this)
3395             Log(active ? "active\n" : "inactive\n");
3396          */
3397
3398          // Testing this here...
3399          if(!parent || parent == guiApp.desktop || parent.active)
3400          {
3401             this.active = active;
3402          }
3403
3404          // TESTING THIS HERE
3405          UpdateDecorations();
3406          if(result = OnActivate(active, previous, goOnWithActivation, direct) && *goOnWithActivation && master)
3407             result = NotifyActivate(master, this, active, previous);
3408          else
3409          {
3410             this.active = !active;
3411          }
3412
3413          if(result)
3414          {
3415             if(!parent || parent == guiApp.desktop || parent.active)
3416             {
3417                this.active = active;
3418                if(acquiredInput)
3419                   AcquireInputEx(active);
3420                if(active)
3421                {
3422                   if(caretSize)
3423                   {
3424                      if(guiApp.caretOwner)
3425                      {
3426                         Box extent 
3427                         {
3428                            guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 1, 
3429                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + 1,
3430                            guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 2, 
3431                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + guiApp.caretOwner.caretSize - 1
3432                         };
3433                         guiApp.caretOwner.Update(extent);
3434                      }
3435
3436                      if(visible || !guiApp.caretOwner)
3437                         guiApp.caretOwner = this;
3438                      UpdateCaret(false, false);
3439                   }
3440                }
3441             }
3442             else
3443             {
3444                this.active = false;
3445                if(acquiredInput)
3446                   AcquireInputEx(active);
3447             }
3448             if(!active && guiApp.caretOwner == this)
3449             {
3450                UpdateCaret(false, true);
3451                guiApp.caretOwner = null;
3452                guiApp.interfaceDriver.SetCaret(0,0,0);
3453                guiApp.caretEnabled = false;
3454             }
3455
3456             if(!style.interim)
3457             {
3458                if(!active && parent && parent.activeChild && parent.activeChild != this)
3459                   if(!parent.activeChild.PropagateActive(false, previous, goOnWithActivation, true) || !*goOnWithActivation)
3460                   {
3461                      return false;
3462                   }
3463             }
3464
3465             if(!active && menuBar)
3466             {
3467                bool goOn;
3468                menuBar.OnActivate(false, null, &goOn, true);
3469                menuBar.NotifyActivate(menuBar.master, menuBar, false, null);
3470             }
3471
3472             if(activeChild)
3473             {
3474                Window aChild = activeChild;
3475                incref aChild;
3476                if(!aChild.PropagateActive(active, previous, goOnWithActivation, false) || !*goOnWithActivation)
3477                {
3478                   delete aChild;
3479                   return false;
3480                }
3481                delete aChild;
3482             }
3483          }
3484       }
3485       return result;
3486    }
3487
3488    void ConsequentialMouseMove(bool kbMoving)
3489    {
3490       if(rootWindow)
3491       {
3492          if(kbMoving || !guiApp.windowMoving)
3493          {
3494             Modifiers mods {};
3495             int x,y;
3496             if(rootWindow == guiApp.desktop || rootWindow.parent == guiApp.desktop)
3497             {
3498                guiApp.interfaceDriver.GetMousePosition(&x, &y);
3499
3500                if(guiApp.windowMoving || rootWindow.GetAtPosition(x, y, true, false, null))
3501                   rootWindow.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &mods, true, false);
3502             }
3503          }
3504       }
3505    }
3506
3507    bool IsDescendantOf(Window ancestor)
3508    {
3509       Window window;
3510       for(window = this; window && window != ancestor; window = window.parent);
3511       return window == ancestor;
3512    }
3513
3514    bool IsSlaveOf(Window master)
3515    {
3516       Window window;
3517       for(window = this; window && window != master; window = window.master);
3518       return window == master;
3519    }
3520
3521    bool ActivateEx(bool active, bool activateParent, bool moveInactive, bool activateRoot, Window external, Window externalSwap)
3522    {
3523       bool result = true;
3524
3525       if(this && !destroyed /*&& state != Hidden*/)
3526       {
3527          Window swap = externalSwap;
3528
3529          incref this;
3530
3531          if(parent)
3532          {
3533             if(!active)
3534                StopMoving();
3535             if(activateParent && 
3536                (parent.activeChild != this || 
3537                (guiApp.interimWindow && !IsDescendantOf(guiApp.interimWindow))) &&
3538                active && _isModal &&
3539                parent != master && master)
3540                master.ActivateEx(true, true, false, activateRoot, external, externalSwap);
3541
3542             if(active)
3543             {
3544                if(parent)
3545                {
3546                   bool real = parent.activeChild != this;
3547
3548                   // TEST THIS: New activateParent check here!!! CAUSED MENUS NOT GOING AWAY
3549                   if(!style.inactive && /*activateParent && */guiApp.interimWindow && 
3550                      !IsDescendantOf(guiApp.interimWindow) && 
3551                      !IsSlaveOf(guiApp.interimWindow))
3552                   {
3553                      Window interimWindow = guiApp.interimWindow;
3554                      while(interimWindow && interimWindow != this)
3555                      {
3556                         Window master = interimWindow.master;
3557                         bool goOn = true;
3558                         guiApp.interimWindow = null;
3559                         if(guiApp.caretOwner)
3560                            guiApp.caretOwner.UpdateCaret(false, false);
3561
3562                         incref interimWindow;
3563                         if(!interimWindow.PropagateActive(false, this, &goOn, true))
3564                         {
3565                            result = false;
3566                            real = false;
3567                         }
3568                         delete interimWindow;
3569                         interimWindow = (master && master.style.interim) ? master : null;
3570                      }
3571                   }
3572                   if(style.interim)
3573                   {
3574                      guiApp.interimWindow = this;
3575                      /*guiApp.interfaceDriver.SetCaret(0,0,0);
3576                      guiApp.caretEnabled = false;*/
3577                      UpdateCaret(false, true);
3578                   }
3579
3580                   if(real)
3581                   {
3582                      bool acquireInput = false;
3583                      bool maximize =
3584                         parent.activeChild &&
3585                         parent.activeChild.state == maximized &&
3586                         parent != guiApp.desktop;
3587
3588                      if(!style.inactive) // (!style.isRemote || parent.active || parent.style.hidden))
3589                      {
3590                         if(!style.interim)
3591                         {
3592                            if(!swap && parent)
3593                               swap = parent.activeChild;
3594                            if(swap && swap.destroyed) swap = null;
3595                            if(swap && swap != this)
3596                            {
3597                               bool goOn = true;
3598                               if(!swap.PropagateActive(false, this, &goOn, true))
3599                                  swap = parent.activeChild;
3600                               if(!goOn)
3601                               {
3602                                  delete this;
3603                                  return false;
3604                               }
3605                            }
3606                            else
3607                               swap = null;
3608                         }
3609
3610                         if(!parent || parent.activeChild != this || style.interim)
3611                         {
3612                            bool goOn = true;
3613                            result = PropagateActive(true, swap, &goOn, true);
3614                            if(!result && !goOn) 
3615                            {
3616                               delete this;
3617                               return false;
3618                            }
3619                            acquireInput = true;
3620                         }
3621                      }
3622
3623                      if(style.hasMaximize && parent != guiApp.desktop)
3624                      {
3625                         if(maximize)
3626                            SetState(maximized, false, 0);
3627                         else if(state != maximized)
3628                         {
3629                            Window child;
3630                            for(child = parent.children.first; child; child = child.next)
3631                            {
3632                               if(this != child && child.state == maximized)
3633                                  child.SetState(normal, false, 0);
3634                            }
3635                         }
3636                      }
3637                   }
3638                   if(result)
3639                   {
3640                      if(!style.inactive && !style.interim /*&& (!style.isRemote || parent.active || parent.style.hidden)*/)
3641                      {
3642                         Window previous = parent.activeClient;
3643                         parent.activeChild = this;
3644                         if(!style.nonClient /*&& style.isActiveClient*/)
3645                         {
3646                            if(!style.hidden)
3647                            {
3648                               if(style.isActiveClient)
3649                                  parent.activeClient = this;
3650                               // Moved UpdateActiveDocument inside hidden check
3651                               // To prevent activating previous window while creating a new one
3652                               // (It was messing up the privateModule in the CodeEditor)
3653                               parent.UpdateActiveDocument(previous);
3654                            }
3655                         }
3656                      }
3657                   }
3658
3659                   //if(!style.isRemote)
3660                   {
3661                      if(rootWindow != this)
3662                      {
3663                         if(activateParent && parent && !parent.active /*parent != parent.parent.activeChild*/)
3664                            parent.ActivateEx(true, true, moveInactive, activateRoot, external, externalSwap);
3665                      }
3666                      else if(!guiApp.fullScreenMode)
3667                      {
3668                         Window modalRoot = FindModal();
3669                         if(!modalRoot) modalRoot = this;
3670                         if(!modalRoot.isForegroundWindow)
3671                         {
3672                            modalRoot.isForegroundWindow = true;
3673                            // To check : Why is parent null?
3674                            if(activateRoot && modalRoot.parent && !modalRoot.parent.display && external != modalRoot)
3675                            {
3676                               guiApp.interfaceDriver.ActivateRootWindow(modalRoot);
3677                            }
3678                            modalRoot.isForegroundWindow = false;
3679                         }
3680                      }
3681                   }
3682                
3683                   if(result && real && (!style.inactive || moveInactive) && parent)
3684                   {
3685                      Window last = parent.children.last;
3686
3687                      if(!style.stayOnTop)
3688                         for(; last && last.style.stayOnTop; last = last.prev);
3689                      
3690                      parent.children.Move(this, last);
3691
3692                      // Definitely don't want that:   why not?
3693                      Update(null);
3694
3695                      if(order)
3696                         parent.childrenOrder.Move(order, parent.childrenOrder.last);
3697                   }
3698                }
3699             }
3700             else 
3701             {
3702                if(!parent || style.interim || (parent.activeChild == this && !style.inactive))
3703                {
3704                   bool goOn = true;
3705                   if(!style.interim)
3706                   {
3707                      if(parent)
3708                      {
3709                         parent.activeChild = null;
3710                         if(!style.nonClient /*&& style.isActiveClient*/)
3711                         {
3712                            Window previous = parent.activeClient;
3713                            if(style.isActiveClient)
3714                               parent.activeClient = null;
3715                            parent.UpdateActiveDocument(previous);
3716                         }
3717                      }
3718                   }
3719                   if(this == guiApp.interimWindow)
3720                   {
3721                      guiApp.interimWindow = null;
3722                      if(guiApp.caretOwner)
3723                         guiApp.caretOwner.UpdateCaret(false, false);
3724                   }
3725                   if(!PropagateActive(false, externalSwap, &goOn, true) || !goOn)
3726                   {
3727                      delete this;
3728                      return false;
3729                   }
3730                }
3731             }
3732             if(!active || !swap)
3733                UpdateDecorations();
3734             if(swap)
3735                swap.UpdateDecorations();
3736
3737             if(active && rootWindow != this)
3738                ConsequentialMouseMove(false);
3739          }
3740          delete this;
3741       }
3742       return true;
3743    }
3744
3745    // --- Input Messages ---
3746    void ::UpdateMouseMove(int mouseX, int mouseY, bool consequential)
3747    {
3748       static bool reEntrancy = false;
3749       if(reEntrancy) return;
3750
3751       reEntrancy = true;
3752
3753       guiApp.cursorUpdate = true;
3754       if(guiApp.windowScrolling && !consequential)
3755       {
3756          guiApp.windowScrolling.SetScrollPosition(
3757             (guiApp.windowScrolling.sbh) ? 
3758                (guiApp.windowScrollingBefore.x - mouseX + guiApp.windowScrollingStart.x) : 0,
3759             (guiApp.windowScrolling.sbv) ? 
3760                (guiApp.windowScrollingBefore.y - mouseY + guiApp.windowScrollingStart.y) : 0);
3761       }
3762       if(guiApp.windowMoving)
3763       {
3764          if(mouseX != guiApp.movingLast.x || mouseY != guiApp.movingLast.y)
3765          {
3766             Window window = guiApp.windowMoving;
3767             int rx, ry;
3768             int w = window.size.w;
3769             int h = window.size.h;
3770             int aw, ah;
3771             MinMaxValue ew, eh;
3772             int x, y;
3773
3774             rx = mouseX - guiApp.windowMovingStart.x;
3775             ry = mouseY - guiApp.windowMovingStart.y;
3776
3777             // Size
3778             window.GetDecorationsSize(&ew, &eh);
3779
3780             if(guiApp.windowIsResizing)
3781             {
3782                x = window.scrolledPos.x;
3783                y = window.scrolledPos.y;
3784
3785                if(guiApp.resizeX)
3786                {
3787                   aw = Max(guiApp.windowResizingBefore.w - rx,window.skinMinSize.w);
3788                   rx = guiApp.windowResizingBefore.w - aw;
3789                   rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x;
3790                   w = guiApp.windowResizingBefore.w - rx;
3791                }
3792                if(guiApp.resizeY)
3793                {
3794                   ah = Max(guiApp.windowResizingBefore.h - ry,window.skinMinSize.h);
3795                   ry = guiApp.windowResizingBefore.h - ah;
3796                   ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y;
3797                   ry = Max(ry, -guiApp.windowMovingBefore.y);
3798                   h = guiApp.windowResizingBefore.h - ry;
3799                }
3800                if(guiApp.resizeEndX)
3801                {
3802                   w = guiApp.windowResizingBefore.w + rx;
3803                   w = Max(w,1-x);
3804                }
3805                if(guiApp.resizeEndY) h = guiApp.windowResizingBefore.h + ry;
3806
3807                w -= ew;
3808                h -= eh;
3809
3810                w = Max(w, 1);
3811                h = Max(h, 1);
3812
3813                w = Max(w, window.minSize.w);
3814                h = Max(h, window.minSize.h);
3815                w = Min(w, window.maxSize.w);
3816                h = Min(h, window.maxSize.h);
3817
3818                if(!window.OnResizing(&w, &h))
3819                {
3820                   w = window.clientSize.w;
3821                   h = window.clientSize.h;
3822                }
3823
3824                w = Max(w, window.skinMinSize.w);
3825                h = Max(h, window.skinMinSize.h);
3826
3827                w += ew;
3828                h += eh;
3829
3830                if(guiApp.textMode)
3831                {
3832                   SNAPDOWN(w, textCellW);
3833                   SNAPDOWN(h, textCellH);
3834                }
3835
3836                if(guiApp.resizeX)
3837                {
3838                   aw = Max(w,window.skinMinSize.w);
3839                   rx = guiApp.windowResizingBefore.w - aw;
3840                   rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x;
3841                   w = guiApp.windowResizingBefore.w - rx;
3842                }
3843                if(guiApp.resizeY)
3844                {
3845                   ah = Max(h,window.skinMinSize.h);
3846                   ry = guiApp.windowResizingBefore.h - ah;
3847                   ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y;
3848                   ry = Max(ry, -guiApp.windowMovingBefore.y);
3849                   h = guiApp.windowResizingBefore.h - ry;
3850                }
3851             }
3852          
3853             // Position
3854             if(!guiApp.windowIsResizing || guiApp.resizeX)
3855                x = guiApp.windowMovingBefore.x + rx;
3856             if(!guiApp.windowIsResizing || guiApp.resizeY)
3857                y = guiApp.windowMovingBefore.y + ry;
3858
3859             if(!guiApp.windowIsResizing)
3860             {
3861                // Limit
3862                if(window.parent == guiApp.desktop && guiApp.virtualScreen.w)
3863                {
3864                   x = Min(x, (guiApp.virtualScreen.w + guiApp.virtualScreenPos.x) -1);
3865                   y = Min(y, (guiApp.virtualScreen.h + guiApp.virtualScreenPos.y) -1);
3866                   x = Max(x,-(w-1) + guiApp.virtualScreenPos.x);
3867                   y = Max(y,-(h-1) + guiApp.virtualScreenPos.y);
3868                }
3869                else
3870                {
3871                   x = Min(x, (window.parent.reqScrollArea.w ? window.parent.reqScrollArea.w : window.parent.clientSize.w) -1);
3872                   y = Min(y, (window.parent.reqScrollArea.h ? window.parent.reqScrollArea.h : window.parent.clientSize.h) -1);
3873                   x = Max(x,-(w-1));
3874                   y = Max(y,-(h-1));
3875                }
3876             }
3877
3878             if(!guiApp.windowIsResizing || (guiApp.resizeX || guiApp.resizeY))
3879             {
3880                if(!window.OnMoving(&x, &y, w, h))
3881                {
3882                   x = window.scrolledPos.x;
3883                   y = window.scrolledPos.y;
3884                }
3885             }
3886
3887             if(guiApp.textMode)
3888             {
3889                SNAPDOWN(x, textCellW);
3890                SNAPDOWN(y, textCellH);
3891             }
3892
3893             if(!window.style.nonClient)
3894             {
3895                if(!window.style.fixed /*|| window.style.isDocument*/)
3896                {
3897                   if(!window.style.dontScrollHorz)
3898                      x += window.parent.scroll.x;
3899                   if(!window.style.dontScrollVert)
3900                      y += window.parent.scroll.y;
3901                }
3902             }
3903
3904             // Break the anchors for moveable/resizable windows
3905             // Will probably cause problem with IDE windows... Will probably need a way to specify if anchors should break
3906             if(window.style.fixed) 
3907             {
3908                if(window.state == normal)
3909                {
3910                   window.normalAnchor = Anchor { left = x, top = y };
3911                   window.normalSizeAnchor = SizeAnchor { { w, h } };
3912                   window.anchored = false;
3913                }
3914             }
3915
3916             window.stateAnchor = Anchor { left = x, top = y };
3917             window.stateSizeAnchor = SizeAnchor { { w, h } };
3918
3919             window.Position(x, y, w, h, false, true, guiApp.windowIsResizing, guiApp.windowIsResizing, false, true);
3920             // TOCHECK: Investigate why the following only redraws the scrollbars
3921             //window.Position(x, y, w, h, false, true, true, true, false, true);
3922
3923             guiApp.movingLast.x = mouseX;
3924             guiApp.movingLast.y = mouseY;
3925          }
3926       }
3927       reEntrancy = false;
3928    }
3929
3930    public bool MouseMessage(uint method, int x, int y, Modifiers * mods, bool consequential, bool activate)
3931    {
3932       bool result = true;
3933       bool wasMoving = guiApp.windowMoving ? true : false;
3934       bool wasScrolling = guiApp.windowScrolling ? true : false;
3935       Window w = null;
3936       while(result && w != this)
3937       {
3938          Window msgWindow = GetAtPosition(x,y, false, true, w);
3939          Window trueWindow = GetAtPosition(x,y, false, false, w);
3940          bool windowDragged = false;
3941          Window window;
3942          delete w;
3943          w = msgWindow;
3944          if(w) incref w;
3945          window = (w && !w.disabled) ? w : null;
3946          
3947          if(trueWindow) incref trueWindow;
3948
3949          if(consequential) mods->isSideEffect = true;
3950
3951          UpdateMouseMove(x, y, consequential);
3952
3953          if(guiApp.windowCaptured && (guiApp.windowCaptured.rootWindow == this))
3954          {
3955             if(!guiApp.windowCaptured.isEnabled)
3956                guiApp.windowCaptured.ReleaseCapture();
3957             else
3958                window = guiApp.windowCaptured;
3959          }
3960
3961          if(trueWindow && activate &&
3962             (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown ||
3963              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown ||
3964              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown ||
3965              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick))
3966          {
3967             if(mods->alt && !mods->ctrl && !mods->shift)
3968             {
3969                Window moved = trueWindow;
3970                for(moved = trueWindow; moved; moved = moved.parent)
3971                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
3972                      break;
3973                if(moved) 
3974                {
3975                   window = moved;
3976                   windowDragged = true;
3977
3978                   // Cancel the ALT menu toggling...
3979                   window.rootWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
3980                }
3981             }
3982          }
3983
3984          if(window && activate &&
3985             (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown ||
3986              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown ||
3987              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown ||
3988              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick))
3989          {
3990             Window modalWindow = window.FindModal();
3991
3992             /*if(mods->alt && !mods->shift && !mods->ctrl)
3993             {
3994                Window moved = window;
3995                for(moved = window; moved; moved = moved.parent)
3996                   if(method == OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
3997                      break;
3998                if(moved) 
3999                {
4000                   window = moved;
4001                   windowDragged = true;
4002
4003                   // Cancel the ALT menu toggling...
4004                   window.rootWindow.KeyMessage(OnKeyDown, 0, 0);
4005                }
4006             }*/
4007
4008             if(!windowDragged)
4009             {
4010                Window activateWindow = modalWindow ? modalWindow : window;
4011                if(activateWindow && !activateWindow.isRemote)
4012                {
4013                   bool doActivation = true;
4014                   //bool needToDoActivation = false;
4015                   Window check = activateWindow;
4016
4017                   for(check = activateWindow; check && check != guiApp.desktop; check = check.parent)
4018                   {
4019                      if(!check.style.inactive)
4020                      {
4021                         //needToDoActivation = true;
4022                         if(check.active)
4023                            doActivation = false;
4024                         break;
4025                      }
4026                   }
4027                   /*
4028                   if(!needToDoActivation)
4029                      doActivation = false;
4030                   */
4031
4032                   if((doActivation && (activateWindow.parent != guiApp.desktop || guiApp.fullScreen)) || 
4033                      (guiApp.interimWindow && !window.IsDescendantOf(guiApp.interimWindow)))
4034                   {
4035                      // Let the OnLeftButtonDown do the activating instead
4036                      if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)
4037                      {
4038                         window = null;
4039                         result = true;
4040                      }
4041                      else
4042                      //if(activate)
4043                      {
4044                         incref activateWindow;
4045                         if(!activateWindow.ActivateEx(true, true, false, true, null, null))
4046                         {
4047                            delete activateWindow;
4048                            delete trueWindow;
4049                            return false;
4050                         }
4051                         if(activateWindow._refCount == 1)
4052                         {
4053                            delete activateWindow;
4054                            delete trueWindow;
4055                            return false;
4056                         }
4057                         delete activateWindow;
4058                      }
4059                      mods->isActivate = true;
4060                   }
4061                }
4062             }
4063             if(!modalWindow && window && !window.destroyed)
4064             {
4065                if(!guiApp.windowCaptured || windowDragged)
4066                {
4067                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown)
4068                   {
4069                      bool moving = ((window.state != maximized &&
4070                            window.IsMouseMoving(
4071                         x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
4072                         || (guiApp.windowMoving && !guiApp.windowIsResizing);
4073
4074                      if(!moving && window.IsMouseResizing(
4075                         x - window.absPosition.x,
4076                         y - window.absPosition.y,
4077                         window.size.w, window.size.h,
4078                         &guiApp.resizeX, &guiApp.resizeY, &guiApp.resizeEndX, &guiApp.resizeEndY))
4079                      {
4080                         guiApp.windowIsResizing = true;
4081                         guiApp.windowResizingBefore.w = window.size.w;
4082                         guiApp.windowResizingBefore.h = window.size.h;
4083                      }
4084                      if(guiApp.windowIsResizing || windowDragged || moving)
4085                      {
4086                         window.Capture();
4087                         guiApp.windowMoving = window;
4088                         guiApp.windowMovingStart.x = guiApp.movingLast.x = x;
4089                         guiApp.windowMovingStart.y = guiApp.movingLast.y = y;
4090                         guiApp.windowMovingBefore.x = window.position.x;//s;
4091                         guiApp.windowMovingBefore.y = window.position.y;//s;
4092                         if(guiApp.windowMoving == guiApp.windowMoving.rootWindow)
4093                            guiApp.interfaceDriver.StartMoving(guiApp.windowMoving.rootWindow, 0,0,false);
4094                      }
4095                   }
4096                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown)
4097                   {
4098                      if(window.style.fixed &&
4099                         (windowDragged || 
4100                         window.IsMouseMoving(
4101                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
4102                      {
4103                         window.ShowSysMenu(x, y);
4104                         result = false;
4105                      }
4106                   }
4107                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown)
4108                   {
4109                      if(window.sbv || window.sbh)
4110                      {
4111                         window.Capture();
4112                         guiApp.windowScrolling = window;
4113                         guiApp.windowScrollingStart.x = x;
4114                         guiApp.windowScrollingStart.y = y;
4115                         guiApp.windowScrollingBefore.x = window.scroll.x;
4116                         guiApp.windowScrollingBefore.y = window.scroll.y;
4117                      }
4118                   }
4119                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)
4120                   {
4121                      if(window.style.hasMaximize && 
4122                         window.IsMouseMoving( 
4123                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h))
4124                      {
4125                         window.SetState(
4126                            (window.state == maximized) ? normal : maximized, false, *mods);
4127                         result = false;
4128                      }
4129                   }
4130                }
4131             }
4132             else
4133                window = null;
4134             if(guiApp.windowMoving) 
4135             {
4136                if(guiApp.windowMoving.parent)
4137                {
4138                   if(guiApp.windowMoving.style.nonClient)
4139                      guiApp.windowMoving.parent.SetMouseRangeToWindow();
4140                   else
4141                      guiApp.windowMoving.parent.SetMouseRangeToClient();
4142                }
4143                else
4144                   FreeMouseRange();
4145                window.UpdateDecorations();
4146             }
4147          }
4148          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp)
4149          {
4150             // Log("\n*** LEFT BUTTON UP ***\n");
4151             if(guiApp.windowMoving)
4152                guiApp.windowMoving.StopMoving();
4153          }
4154          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp)
4155          {
4156             if(guiApp.windowScrolling)
4157             {
4158                Window windowScrolling = guiApp.windowScrolling;
4159                guiApp.windowScrolling = null;
4160                windowScrolling.ReleaseCapture();
4161             }
4162          }
4163
4164          if(!result || (window && window.destroyed)) window = null;
4165
4166          if(window && window.FindModal())
4167             window = null;
4168
4169          if(trueWindow && trueWindow.FindModal())
4170             delete trueWindow;
4171          
4172          /*if(trueWindow)
4173             incref trueWindow;
4174          */
4175
4176          /*
4177          msgWindow = GetAtPosition(x,y, true, false);
4178          if(msgWindow)
4179             msgWindow.SelectMouseCursor();
4180          */
4181
4182          if(guiApp.windowCaptured || trueWindow)
4183          {
4184             Window prevWindow = guiApp.prevWindow;
4185             if(guiApp.prevWindow && trueWindow != guiApp.prevWindow)
4186             {
4187                guiApp.prevWindow.mouseInside = false;
4188                guiApp.prevWindow = null;
4189
4190                // Eventually fix this not to include captured?
4191                if(!prevWindow.OnMouseLeave(*mods))
4192                   result = false;
4193             }
4194             if(result && trueWindow && !trueWindow.destroyed/* && trueWindow == window*/)
4195             {
4196                Box box = trueWindow.box;
4197                box.left += trueWindow.absPosition.x;
4198                box.right += trueWindow.absPosition.x;
4199                box.top += trueWindow.absPosition.y;
4200                box.bottom += trueWindow.absPosition.y;
4201
4202                if(box.IsPointInside({x, y}) && trueWindow != /*guiApp.*/prevWindow /*!trueWindow.mouseInside*/)
4203                {
4204                   int overX = x - (trueWindow.absPosition.x + trueWindow.clientStart.x);
4205                   int overY = y - (trueWindow.absPosition.y + trueWindow.clientStart.y);
4206
4207                   overX = Max(Min(overX, 32767),-32768);
4208                   overY = Max(Min(overY, 32767),-32768);
4209
4210                   trueWindow.mouseInside = true;
4211                   if(!trueWindow.OnMouseOver(overX, overY, *mods))
4212                      result = false;
4213                }
4214             }
4215             if(trueWindow && trueWindow._refCount > 1 && !trueWindow.destroyed)
4216                guiApp.prevWindow = trueWindow;
4217             else
4218                guiApp.prevWindow = null;
4219          }
4220          SelectMouseCursor();
4221
4222          if(window && !guiApp.windowMoving && !wasMoving && !wasScrolling)
4223          {
4224             int clientX = x - (window.absPosition.x + window.clientStart.x);
4225             int clientY = y - (window.absPosition.y + window.clientStart.y);
4226
4227             bool (* MouseMethod)(Window instance, int x, int y, Modifiers mods);
4228
4229             clientX = Max(Min(clientX, 32767),-32768);
4230             clientY = Max(Min(clientY, 32767),-32768);
4231
4232             MouseMethod = (void *)window._vTbl[method];
4233
4234             if(MouseMethod /*&& !consequential*/ && !window.disabled)
4235             {
4236                incref window;
4237                if(!MouseMethod(window, clientX, clientY, *mods))
4238                   result = false;
4239                delete window;
4240             }
4241          }
4242          delete trueWindow;
4243          /*
4244          if(result && w && w.clickThrough && w.parent)
4245             w = w.parent;
4246          else
4247             break;
4248          */
4249          if(!result || !w || !w.clickThrough)
4250             break;
4251       }
4252       delete w;
4253       return result;
4254    }
4255
4256    // --- Mouse cursor management ---
4257
4258    bool KeyMessage(uint method, Key key, unichar character)
4259    {
4260       bool status = true;
4261       if(!parent)
4262       {
4263          if(guiApp.interimWindow)
4264             this = guiApp.interimWindow;
4265       }
4266 #ifdef _DEBUG
4267       if((SmartKey)key != alt && (SmartKey)key != Key::control && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && parent && this != parent.menuBar)
4268          Print("");
4269 #endif
4270
4271       if(!style.inactive || rootWindow != this)
4272       {
4273          bool (*KeyMethod)(Window window, Key key, unichar ch) = (void *)_vTbl[method];
4274          Window modalWindow = FindModal();
4275          Window interimMaster = master ? master.rootWindow : null;
4276
4277          incref this;
4278
4279          if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4280             status = OnSysKeyDown(key, character);
4281          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4282             status = OnSysKeyHit(key, character);
4283          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4284             status = OnSysKeyUp(key, character);
4285          if(!status)
4286          {
4287             delete this;
4288             return true;
4289          }
4290
4291          // Process Key Message for Internal UI Keyboard actions
4292          if(status && !destroyed && menuBar && state != minimized)
4293          {
4294             // Disable the ALT
4295             if((SmartKey)key != alt) 
4296                menuBar.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
4297             if(menuBar.focus)
4298             {
4299                SmartKey sk = (SmartKey) key;
4300                if((character && !key.alt && !key.ctrl) || sk == left || sk == right || sk == up || sk == down || sk == home || sk == end || sk == escape || sk == alt)
4301                {
4302                   status = menuBar.KeyMessage(method, key, character);
4303                   status = false;
4304                }
4305                else
4306                {
4307                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4308                      menuBar.OnKeyHit(escape, 0);
4309                }
4310                if(!menuBar.focus && guiApp.caretOwner)
4311                   guiApp.caretOwner.UpdateCaret(true, false);
4312             }
4313          }
4314          if(!destroyed && status)
4315          {
4316             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4317             {
4318                switch(key)
4319                {
4320                   case left: case up: case right: case down:
4321                      if(guiApp.windowMoving == this)
4322                      {
4323                         int step = 1; //8;
4324                         int w = guiApp.windowMoving.size.w;
4325                         int h = guiApp.windowMoving.size.h;
4326                         int x = guiApp.windowMoving.scrolledPos.x;
4327                         int y = guiApp.windowMoving.scrolledPos.y;
4328
4329                         if(guiApp.textMode)
4330                         {
4331                            if(key == down || key == up)
4332                               step = Max(step, textCellH);
4333                            else
4334                               step = Max(step, textCellW);
4335                         }
4336
4337                         if(guiApp.windowIsResizing)
4338                         {
4339                            switch(key)
4340                            {
4341                               case left: w-=step; break;
4342                               case right: w+=step; break;
4343                               case up: h-=step;   break;
4344                               case down: h+=step; break;
4345                            }
4346                         }
4347                         else
4348                         {
4349                            switch(key)
4350                            {
4351                               case left: x-=step; break;
4352                               case right: x+=step; break;
4353                               case up: y-=step;   break;
4354                               case down: y+=step; break;
4355                            }
4356                         }
4357
4358                         if(guiApp.resizeX) x += w - guiApp.windowMoving.size.w;
4359                         if(guiApp.resizeY) y += h - guiApp.windowMoving.size.h;
4360
4361                         if(!guiApp.windowIsResizing || guiApp.resizeX)
4362                            x = (x - guiApp.windowMovingBefore.x) + guiApp.windowMovingStart.x;
4363                         else
4364                            x = (w - guiApp.windowResizingBefore.w) + guiApp.windowMovingStart.x;
4365
4366                         if(!guiApp.windowIsResizing || guiApp.resizeY)
4367                            y = (y - guiApp.windowMovingBefore.y) + guiApp.windowMovingStart.y;
4368                         else                           
4369                            y = (h - guiApp.windowResizingBefore.h) + guiApp.windowMovingStart.y;
4370
4371                         guiApp.interfaceDriver.SetMousePosition(x, y);
4372                         ConsequentialMouseMove(true);
4373
4374                         status = false;
4375                      }
4376                      break;
4377                   case escape:
4378                   case enter:
4379                   case keyPadEnter:
4380                      if(guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4381                      {
4382                         guiApp.windowMoving.StopMoving();
4383                         ConsequentialMouseMove(false);
4384                   
4385                         status = false;
4386                      }
4387                      break;
4388                   case altSpace:
4389                      if(style.fixed)
4390                      {
4391                         ShowSysMenu(absPosition.x, absPosition.y);
4392                         status = false;
4393                      }
4394                      break;
4395                }
4396             }
4397          }
4398
4399          if(!destroyed && status && state != minimized)
4400          {
4401             // Process all the way down the children
4402             if(activeChild && !activeChild.disabled)
4403             {
4404                status = activeChild.KeyMessage(method, key, character);
4405             }
4406             if(status && activeClient && activeChild != activeClient && !activeClient.disabled && (key.alt || key.ctrl) &&
4407                key.code != left && key.code != right && key.code != up && key.code != down)
4408             {
4409                status = activeClient.KeyMessage(method, key, character);
4410             }
4411
4412             // Default Control
4413             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4414             {
4415                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && !defaultControl.disabled && state != minimized)
4416                   // && defaultControl != activeChild)
4417                {
4418                   delete previousActive;
4419                   previousActive = activeChild;
4420                   if(previousActive) incref previousActive;
4421
4422                   ConsequentialMouseMove(false);
4423                   if((defaultControl.active ||
4424                      defaultControl.ActivateEx(true, true, false, true, null, null)) && !defaultControl.disabled)
4425                      defaultControl.KeyMessage(method, defaultKey, character);
4426                   status = false;                       
4427                }
4428             }
4429          }
4430
4431          if(!destroyed && status && (!modalWindow || this == guiApp.desktop))
4432          {
4433             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4434             {
4435                switch(key)
4436                {
4437                   case altMinus:
4438                      if(style.fixed)
4439                      {
4440                         ShowSysMenu(absPosition.x, absPosition.y);
4441                         status = false;
4442                      }
4443                      break;
4444                   //case f5:
4445                   /*
4446                   case shiftF5:
4447                      if(this != guiApp.desktop)
4448                      {
4449                         if(!guiApp.windowMoving && !guiApp.windowCaptured)
4450                         {
4451                            if(state != maximized && (key.shift ? style.sizeable : style.fixed))
4452                            {
4453                               MenuMoveOrSize(key.shift, true);
4454                               status = false;
4455                            }
4456                         }
4457                         else if(guiApp.windowMoving)
4458                         {
4459                            guiApp.windowMoving.StopMoving();
4460                            ConsequentialMouseMove(false);
4461                            status = false;
4462                         }
4463                      }
4464                      break;
4465                   */
4466                }
4467             }
4468             if(!destroyed && status && state != minimized)
4469             {
4470                if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4471                {
4472                   switch(key)
4473                   {
4474                      case tab: case shiftTab:
4475                      {
4476                         Window cycleParent = this;
4477                         if(this == guiApp.interimWindow && !master.style.interim && !cycleParent.style.tabCycle)
4478                            cycleParent = master.parent;
4479                         
4480                         if(!guiApp.windowCaptured && cycleParent.style.tabCycle)
4481                         {
4482                            if(cycleParent.CycleChildren(!key.shift, false, false, true))
4483                            {
4484                               Window child = cycleParent.activeChild;
4485
4486                               // Scroll the window to include the active control
4487                               /*
4488                               if(cycleParent.sbh && !child.style.dontScrollHorz)
4489                               {
4490                                  if(child.scrolledPos.x < 0)
4491                                     cycleParent.sbh.Action(Position, 
4492                                        cycleParent.scroll.x + child.scrolledPos.x, 0);
4493                                  else if(child.scrolledPos.x + child.size.w > cycleParent.clientSize.w)
4494                                     cycleParent.sbh.Action(Position,
4495                                        cycleParent.scroll.x + child.scrolledPos.x + child.size.w - cycleParent.clientSize.w, 0);
4496                               }
4497                               if(cycleParent.sbv && !child.style.dontScrollVert)
4498                               {
4499                                  if(child.scrolledPos.y < 0)
4500                                     cycleParent.sbv.Action(Position, 
4501                                        cycleParent.scroll.y + child.scrolledPos.y, 0);
4502                                  else if(child.scrolledPos.y + child.size.w > window.clientSize.h)
4503                                     cycleParent.sbv.Action(Position,
4504                                        cycleParent.scroll.y + child.scrolledPos.y+child.size.h - cycleParent.clientSize.h, 0);
4505                               }
4506                               */
4507                               cycleParent.ConsequentialMouseMove(false);
4508                               status = false;
4509                            }
4510                         }
4511                         break;
4512                      }
4513                      case f6: case shiftF6:
4514                         if(!guiApp.windowMoving /*!guiApp.windowCaptured*/)
4515                         {
4516                            // NOT NEEDED... guiApp.windowMoving.ReleaseCapture();
4517                            if(parent == guiApp.desktop)
4518                               if(guiApp.desktop.CycleChildren(key.shift, true, false, true))
4519                               {
4520                                  status = false;
4521                                  break;
4522                               }
4523                            if(style.tabCycle)
4524                            {
4525                               delete this;
4526                               return true;
4527                            }
4528                            if(CycleChildren(key.shift, true, false, true))
4529                            {
4530                               status = false;
4531                               break;
4532                            }
4533                         }
4534                         break;
4535                      /*
4536                      // mIRC Style Window Shortcuts
4537                      case alt1: case alt2: case alt3: case alt4: case alt5:
4538                      case alt6: case alt7: case alt8: case alt9: case alt0:
4539                      {
4540                         if(numPositions)
4541                         {
4542                            Window document;
4543                            for(document = children.first; document; document = document.next)
4544                            {
4545                               if(document.style.isDocument && document.documentID - 1 == key.code - k1)
4546                               {
4547                                  if(document == activeChild)
4548                                  {
4549                                     if(document.state == minimized)
4550                                        document.SetState(normal, false, key);
4551                                     else
4552                                     {
4553                                        document.SetState(minimized, false, key);
4554                                        CycleChildren(false, true, false);
4555                                     }
4556                                  }
4557                                  else
4558                                  {
4559                                     if(activeChild.state == maximized && document.style.hasMaximize)
4560                                        document.SetState(maximized, false, key);
4561                                     else if(document.state == minimized)
4562                                        document.SetState(normal, false, key);
4563                                     document.Activate();
4564                                  }
4565                                  status = false;
4566                                  break;
4567                               }
4568                            }
4569                         }
4570                         break;            
4571                      }
4572                      */
4573                   }
4574                }
4575             }
4576          }
4577
4578          if(!destroyed && status)
4579          {
4580             if(state == minimized)
4581             {
4582                delete this;
4583                return true;
4584             }
4585             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4586             {
4587                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && previousActive)
4588                {
4589                   if(defaultControl.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, character))
4590                      previousActive.ActivateEx(true, false, false, true, null, null);
4591                   delete previousActive;
4592                   status = false;
4593                }
4594             }
4595          }
4596
4597          if(!destroyed && status)
4598          {
4599             status = ProcessHotKeys(method, key, character);
4600          }
4601          if(!destroyed && status && !modalWindow && state != minimized)
4602          {
4603             if(KeyMethod)
4604                status = KeyMethod(this, key, character);
4605             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4606                status = OnKeyHit(key, character);
4607             if(!destroyed && status && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit))
4608             {
4609                bool result = false;
4610                switch(key)
4611                {
4612                   case ctrlUp: case ctrlDown:
4613                      if(sbv && !guiApp.windowScrolling)
4614                         result = sbv.Action((key == ctrlUp) ? up : down, 0, key);
4615                      break;
4616                   case wheelUp: case wheelDown:
4617                      if(sbv && !guiApp.windowScrolling)
4618                      {
4619                         result = sbv.Action((key == wheelUp) ? wheelUp : wheelDown, 0, key);
4620                         // Do we want to do a consequential move regardless of result in this case?
4621                         ConsequentialMouseMove(false);
4622                      }
4623                      break;
4624                   case ctrlPageUp: case ctrlPageDown:
4625                      if(sbh && !guiApp.windowScrolling)
4626                         result = sbh.Action((key == ctrlPageUp) ? up : down, 0, key);
4627                      break;
4628                }
4629                if(result)
4630                {
4631                   ConsequentialMouseMove(false);
4632                   status = false;
4633                }
4634             }
4635          }
4636          if(status && !destroyed && menuBar && state != minimized)
4637             status = menuBar.KeyMessage(method, key, character);
4638
4639          if(style.interim && /*destroyed && */status && interimMaster)
4640          {
4641             // Testing this... for Ctrl-O to open dialog when autocompletion listbox is popped...
4642             status = interimMaster.KeyMessage(method, key, character);
4643          }
4644          delete this;
4645       }
4646       return status;
4647    }
4648
4649    bool ProcessHotKeys(uint method, Key key, unichar character)
4650    {
4651       bool status = true;
4652       HotKeySlot hotKey;
4653
4654       for(hotKey = hotKeys.first; hotKey; hotKey = hotKey.next)
4655          if((hotKey.key == key || (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp && hotKey.key.code == key.code)) &&
4656             !hotKey.window.disabled && (hotKey.window.style.nonClient || state != minimized))
4657          {
4658             Window hotKeyWindow = hotKey.window;
4659             Window parent = hotKeyWindow.parent;
4660             Window prevActiveWindow = activeChild;
4661             // For when sys buttons are placed inside the menu bar
4662             if(parent && parent._class == class(PopupMenu))
4663                parent = parent.parent;
4664
4665             // Don't process non-visible buttons, but make an exception for the Alt-F4 with Native Decorations turned on; This handles alt+enter as well
4666             if(hotKeyWindow.style.hidden && (!hotKeyWindow.style.nonClient || !parent || !parent.nativeDecorations || (hotKeyWindow != parent.sysButtons[2] && hotKeyWindow != parent.sysButtons[1])))
4667                continue;
4668
4669             if(prevActiveWindow) incref prevActiveWindow;
4670             incref hotKeyWindow;
4671             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && !hotKeyWindow.style.nonClient)
4672                if(!hotKeyWindow.ActivateEx(true, true, false, true, null, null))
4673                {
4674                   status = false;
4675                   delete hotKeyWindow;
4676                   delete prevActiveWindow;
4677                   break;
4678                }
4679
4680             if(hotKeyWindow.style.nonClient && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4681                method = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
4682             if(!hotKeyWindow.KeyMessage(method, Key::hotKey, character))
4683             {
4684                // *********   WORKING ON THIS   ***********
4685                if(prevActiveWindow && !guiApp.interimWindow)
4686                   prevActiveWindow.ActivateEx(true, false, false, false, null, null);
4687                status = false;
4688             }
4689             else if(hotKeyWindow.style.inactive)
4690                status = hotKeyWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, Key::hotKey, character);
4691
4692             delete prevActiveWindow;
4693             delete hotKeyWindow;
4694             // For Key Ups, don't set status to false... (e.g.: Releasing Enter vs AltEnter hot key)
4695             if(method != __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4696                status = false;
4697             break;
4698          }
4699       if(status && tabCycle)
4700       {
4701          Window child;
4702          for(child = children.first; child; child = child.next)
4703          {
4704             if(child.tabCycle && !child.ProcessHotKeys(method, key, character))
4705             {
4706                status = false;
4707                break;
4708             }
4709          }
4710       }
4711       return status;
4712    }
4713
4714
4715    // --- Windows and graphics initialization / termination ---
4716    bool SetupRoot(void)
4717    {
4718       Window child;
4719
4720       // Setup relationship with outside world (bb root || !bb)
4721       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop || 
4722          (_displayDriver && dispDriver != parent.dispDriver))
4723       {
4724          rootWindow = this;
4725          if(!tempExtents)
4726             tempExtents = new0 Extent[4];
4727          against = null;
4728       }
4729       else
4730       {
4731          /*if(guiApp.fullScreenMode)
4732             rootWindow = guiApp.desktop;
4733          else*/
4734          //rootWindow = parent.created ? parent.rootWindow : null;
4735          rootWindow = parent.rootWindow;
4736
4737          if(style.nonClient)
4738             against = &parent.box;
4739          else
4740             against = &parent.clientArea;
4741       }
4742
4743       for(child = children.first; child; child = child.next)
4744          child.SetupRoot();
4745
4746       return (rootWindow && (rootWindow == this || rootWindow.created)) ? true : false;
4747    }
4748
4749    bool Setup(bool positionChildren)
4750    {
4751       bool result = false;
4752       Window child;
4753
4754       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || (guiApp.fullScreenMode && (this == guiApp.desktop || (_displayDriver && dispDriver != parent.dispDriver))))
4755       {
4756          subclass(DisplayDriver) dDriver = (dispDriver && !formDesigner) ? dispDriver : GetDisplayDriver(guiApp.defaultDisplayDriver);
4757          DisplaySystem displaySystem = dDriver ? dDriver.displaySystem : null;
4758
4759          windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this);
4760
4761          // This was here, is it really needed?
4762          //guiApp.interfaceDriver.ActivateRootWindow(this);
4763
4764          if(!displaySystem)
4765          {
4766             displaySystem = DisplaySystem {};
4767             if(!displaySystem.Create(dDriver.name, guiApp.fullScreenMode ? windowHandle : windowHandle /*null*/, guiApp.fullScreenMode))
4768             {
4769                delete displaySystem;
4770             }
4771          }
4772          if(displaySystem)
4773          {
4774             display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, windowDriverData = windowData };
4775             if(display.Create(displaySystem, windowHandle))
4776                result = true;
4777             else
4778             {
4779                delete display;
4780             }
4781          }
4782          // Sometimes icon does not show up on Windows XP if we set here...
4783          // guiApp.interfaceDriver.SetIcon(this, icon);
4784       }
4785       else if(this != guiApp.desktop)
4786       {
4787          display = rootWindow ? rootWindow.display : null;
4788          result = true;
4789       }
4790       else
4791          result = true;
4792
4793       if(guiApp.acquiredWindow && rootWindow == guiApp.acquiredWindow.rootWindow)
4794          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, true);
4795
4796       for(child = children.first; child; child = child.next)
4797       {
4798          if(child.created && !child.Setup(false))
4799             result = false; 
4800       }
4801       return result;
4802    }
4803
4804    bool SetupDisplay(void)
4805    {
4806 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
4807       if(is3D) return Window3D_SetupDisplay(this); else 
4808 #endif   
4809       if(SetupRoot())
4810          return Setup(true);
4811       return false;
4812    }
4813
4814    class_data void ** pureVTbl;
4815
4816    bool LoadGraphics(bool creation, bool resetAnchors)
4817    {
4818       bool result = false;
4819       bool success = false;
4820       Window child;
4821       WindowState stateBackup = state;
4822
4823       /*
4824       if(!rootWindow.created)
4825          printf("");
4826       */
4827       
4828       if(((subclass(Window))_class).pureVTbl)
4829       {
4830          if(_vTbl == _class._vTbl)
4831          {
4832             _vTbl = ((subclass(Window))_class).pureVTbl;
4833          }
4834          else
4835          {
4836             int m;
4837             for(m = 0; m < _class.vTblSize; m++)
4838             {
4839                if(_vTbl[m] == _class._vTbl[m])
4840                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
4841             }
4842          }
4843       }
4844       if(guiApp.currentSkin && ((subclass(Window))_class).pureVTbl)
4845       {
4846          if(_vTbl == ((subclass(Window))_class).pureVTbl)
4847          {
4848             _vTbl = _class._vTbl;
4849          }
4850          else
4851          {
4852             int m;
4853             for(m = 0; m < _class.vTblSize; m++)
4854             {
4855                if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m])
4856                   _vTbl[m] = _class._vTbl[m];
4857             }
4858          }
4859       }
4860       
4861       if(guiApp.fullScreenMode || this != guiApp.desktop)
4862       {
4863          SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
4864          if(display)
4865          {
4866             ResPtr ptr;
4867             success = true;
4868
4869             display.Lock(false);
4870             if(rootWindow == this)
4871             {
4872                // Set Color Palette
4873                display.SetPalette(palette, true);
4874
4875                // Load Cursors
4876                /*
4877                if(guiApp.fullScreenMode && this == guiApp.desktop)
4878                {
4879                   int c;
4880                   Cursor cursor;
4881
4882                   for(c=0; c<SystemCursor::enumSize; c++)
4883                      if(!guiApp.systemCursors[c].bitmap)
4884                      {
4885                         guiApp.systemCursors[c].bitmapName = guiApp.currentSkin.CursorsBitmaps(c,
4886                            &guiApp.systemCursors[c].hotSpotX,&guiApp.systemCursors[c].hotSpotY, &guiApp.systemCursors[c].paletteShades);
4887                         if(guiApp.systemCursors[c].bitmapName)
4888                         {
4889                            guiApp.systemCursors[c].bitmap = eBitmap_LoadT(guiApp.systemCursors[c].bitmapName, null,
4890                               guiApp.systemCursors[c].paletteShades ? null : guiApp.desktop.display.displaySystem);
4891                            if(guiApp.systemCursors[c].bitmap)
4892                               guiApp.systemCursors[c].bitmap.paletteShades = guiApp.systemCursors[c].paletteShades;
4893                            else
4894                               success = false;
4895                         }
4896                      }
4897                   for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
4898                   {
4899                      cursor.bitmap = eBitmap_LoadT(cursor.bitmapName, null, 
4900                         cursor.paletteShades ? null : guiApp.desktop.display.displaySystem);
4901                      if(cursor.bitmap)
4902                         cursor.bitmap.paletteShades = cursor.paletteShades;
4903                      else
4904                         success = false;
4905                   }
4906                   guiApp.cursorUpdate = true;
4907
4908                   display.Unlock();
4909                   ConsequentialMouseMove(false);
4910                   display.Lock(true);
4911                }
4912                */
4913             }
4914
4915             // Load Window Graphic Resources
4916             
4917             /*
4918             if(usedFont == setFont || usedFont == window.systemFont)
4919                RemoveResource(usedFont);
4920             */
4921             if(setFont)
4922                RemoveResource(setFont); // TESTING setFont instead of usedFont);
4923
4924             if(systemFont)
4925                RemoveResource(systemFont);
4926             
4927             if(captionFont)
4928                RemoveResource(captionFont);
4929
4930             for(ptr = resources.first; ptr; ptr = ptr.next)
4931             {
4932                ptr.loaded = display.displaySystem.LoadResource(ptr.resource);
4933             }
4934             if(setFont)
4935                AddResource(setFont);
4936             if(systemFont)
4937                AddResource(systemFont);
4938
4939             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
4940
4941             firewatchers font;
4942
4943             /*
4944             if(!setFont)
4945             {
4946                //if(master && master.font)
4947                if(parent && parent.font)
4948                {
4949                   font = FontResource
4950                   {
4951                      faceName = parent.font.faceName,
4952                      size = parent.font.size,
4953                      bold = parent.font.bold,
4954                      italic = parent.font.italic,
4955                      underline = parent.font.underline
4956                   };
4957                   //font = parent.font;
4958                   watch(parent) { font { } };
4959                }
4960                else
4961                   font = guiApp.currentSkin.SystemFont();
4962                AddResource(font);
4963
4964                firewatchers font;
4965             }
4966             */
4967
4968             captionFont = guiApp.currentSkin.CaptionFont();
4969             AddResource(captionFont);
4970
4971             if(OnLoadGraphics())
4972             {
4973                int x,y,w,h;
4974
4975                display.Unlock();
4976
4977                //SetScrollLineStep(sbStep.x, sbStep.y);
4978                
4979                if(this != guiApp.desktop)
4980                {
4981                   if(resetAnchors)
4982                   {
4983                      normalAnchor = anchor;
4984                      normalSizeAnchor = sizeAnchor;
4985                   }
4986
4987                   // Break the anchors for moveable/resizable windows
4988                   /*
4989                   if(style.fixed && style.isDocument)
4990                   {
4991                      ComputeAnchors(ax, ay, aw, ah, &x, &y, &w, &h);
4992                      ax = x;
4993                      ay = y;
4994                      aw = w;
4995                      ah = h;
4996                      anchored = false;
4997                   }
4998                   */
4999                   switch(state)
5000                   {
5001                      case maximized:
5002                      
5003                         stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5004                         stateSizeAnchor = SizeAnchor {};
5005                         break;
5006                      
5007                      case minimized:
5008                      {
5009                         int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5010
5011                         stateAnchor = 
5012                            Anchor 
5013                            {
5014                               left = (iconID % maxIcons) * MINIMIZED_WIDTH,
5015                               bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24)
5016                            };
5017                         
5018                         stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5019                         break;
5020                      }
5021                      case normal:
5022                         stateAnchor = normalAnchor;
5023                         stateSizeAnchor = normalSizeAnchor;
5024                         break;
5025                   }
5026                   position = Point { };
5027                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5028
5029                }
5030                else
5031                {
5032                   x = scrolledPos.x;
5033                   y = scrolledPos.y;
5034                   w = size.w;
5035                   h = size.h;
5036                }
5037
5038                if(Position(x, y, w, h, true, false, true, true, true, true))
5039                {
5040                   if((this != guiApp.desktop || guiApp.fullScreenMode) && rootWindow == this)
5041                   {
5042                      if(!style.hidden)
5043                         guiApp.interfaceDriver.SetRootWindowState(this, normal, true);
5044                   }
5045
5046                   Update(null);
5047
5048                   result = true;
5049                }
5050             }
5051             else
5052             {
5053                result = false;
5054                display.Unlock();
5055             }
5056          }
5057       }
5058       else
5059       {
5060          success = result = true;
5061       }
5062
5063       if(!creation && result)
5064       {
5065          // Load menu bar first because sys buttons are on it...
5066          if(menuBar)
5067          {
5068             if(!menuBar.LoadGraphics(false, resetAnchors))
5069             {
5070                result = false;
5071                success = false;
5072             }
5073          }
5074          for(child = children.first; child; child = child.next)
5075          {
5076             if(child.created && child != menuBar && !child.LoadGraphics(false, resetAnchors))
5077             {
5078                result = false;
5079                success = false;
5080             }
5081          }
5082          if(!creation)
5083             CreateSystemChildren();
5084
5085          OnApplyGraphics();
5086       }
5087       if(this == guiApp.desktop && !guiApp.fullScreenMode)
5088       {
5089          if(activeChild)
5090             guiApp.interfaceDriver.ActivateRootWindow(activeChild);
5091       }
5092       /*
5093       TODO:
5094       if(!success)
5095          //guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, caption);
5096          guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, class.name);
5097       */
5098
5099       // Do this here to avoid problems on Windows
5100       if(stateBackup == maximized)
5101          property::state = maximized;
5102       return result;
5103    }
5104
5105    void UnloadGraphics(bool destroyWindows)
5106    {
5107       Window child;
5108
5109       // Free children's graphics
5110       for(child = children.first; child; child = child.next)
5111          child.UnloadGraphics(destroyWindows);
5112
5113       if(display)
5114          display.Lock(false);
5115
5116       // Free cursors
5117       if(guiApp.fullScreenMode && this == guiApp.desktop)
5118       {
5119          Cursor cursor;
5120          SystemCursor c;
5121
5122          for(c=0; c<SystemCursor::enumSize; c++)
5123             if(guiApp.systemCursors[c].bitmap)
5124                delete guiApp.systemCursors[c].bitmap;
5125
5126          for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
5127             delete cursor.bitmap;
5128
5129          guiApp.cursorBackground.Free();
5130       }
5131
5132       if(display && display.displaySystem)
5133       {
5134          ResPtr ptr;
5135
5136          for(ptr = resources.first; ptr; ptr = ptr.next)
5137          {
5138             if(ptr.loaded)
5139             {
5140                display.displaySystem.UnloadResource(ptr.resource, ptr.loaded);
5141                ptr.loaded = null;
5142             }
5143          }
5144
5145          // Free window graphics
5146          OnUnloadGraphics();
5147
5148          // Free skin graphics
5149          if(rootWindow == this)
5150          {
5151             DisplaySystem displaySystem = display.displaySystem;
5152             if(is3D)
5153             {
5154                display.driverData = null;
5155                display.displaySystem = null;
5156             }
5157             display.Unlock();
5158             delete display;
5159             if(displaySystem && !displaySystem.numDisplays && !is3D)
5160                delete displaySystem;
5161          }
5162          else
5163          {
5164             display.Unlock();
5165             display = null;
5166          }
5167       }
5168
5169       if(guiApp.acquiredWindow && this == guiApp.acquiredWindow.rootWindow)
5170          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, false);
5171
5172       if(this == guiApp.desktop || parent == guiApp.desktop)
5173       {
5174          if((guiApp.fullScreenMode || this != guiApp.desktop) && rootWindow == this && windowHandle && destroyWindows)
5175             guiApp.interfaceDriver.DestroyRootWindow(this);
5176       }
5177    }
5178
5179    // --- Window Hiding ---
5180
5181    void SetVisibility(bool state)
5182    {
5183       bool visible = (style.hidden || !created) ? false : state;
5184       if(visible != this.visible)
5185       {
5186          Window child;
5187
5188          this.visible = visible;
5189          for(child = children.first; child; child = child.next)
5190             child.SetVisibility(visible);
5191          Update(null);
5192          ConsequentialMouseMove(false);
5193          if(parent && !nonClient) parent.OnChildVisibilityToggled(this, visible);
5194       }
5195    }
5196
5197    // --- Windows and graphics initialization / termination ---
5198
5199    bool DisplayModeChanged(void)
5200    {
5201       bool result = false;
5202       if(!guiApp.fullScreenMode && !guiApp.modeSwitching/* && guiApp.desktop.active*/)
5203       {
5204          guiApp.modeSwitching = true;
5205          UnloadGraphics(false);
5206          if(SetupDisplay())
5207             if(LoadGraphics(false, false))
5208                result = true;
5209          guiApp.modeSwitching = false;
5210       }
5211       return result;
5212    }
5213
5214    // --- Window updates system ---
5215
5216    void UpdateDirty(Box updateBox)
5217    {
5218       if(!manageDisplay) { OnRedraw(null);return; }
5219       if(visible)
5220       {
5221          if(display && (!guiApp.fullScreenMode || guiApp.desktop.active) && !guiApp.modeSwitching)
5222          {
5223             display.Lock(true);
5224             if(display.flags.flipping)
5225             {
5226                Update(null);
5227                rootWindow.UpdateDisplay();
5228             }
5229             else
5230                UpdateBackDisplay(updateBox);
5231
5232             if(guiApp.fullScreenMode)
5233             {
5234                guiApp.cursorUpdate = true;
5235                guiApp.PreserveAndDrawCursor();
5236             }
5237             if(guiApp.fullScreenMode)
5238                guiApp.RestoreCursorBackground();
5239             display.Unlock();
5240          }
5241       }
5242    }
5243
5244    // This function is strictly called as a result of system window activation
5245    bool ExternalActivate(bool active, bool activateRoot, Window window, Window swap)
5246    {
5247       bool result = true;
5248       Window interimMaster = null;
5249       Window interimWindow = guiApp.interimWindow;
5250       if(interimWindow && interimWindow.master)
5251          interimMaster = interimWindow.master.rootWindow;
5252
5253       if(active && state == minimized) // && (!window.nativeDecorations || window.rootWindow != window)
5254          // SetState(normal, false, 0);
5255          SetState(lastState, false, 0);
5256
5257       if(interimMaster && swap == interimMaster && interimMaster.IsSlaveOf(window))
5258          return false;
5259
5260       incref this;
5261       /* WTH is this doing here?
5262       while(swap && swap.activeChild)
5263       {
5264          swap = swap.activeChild;         
5265       }
5266       */
5267       // TESTING THIS BEFORE...
5268       if(interimWindow && this == interimMaster)
5269       {
5270          if(active)
5271          {
5272             // Window interimSwap = this;
5273             Window menuBar = this.menuBar;
5274             if(menuBar && interimWindow.master == menuBar)
5275             {
5276                /*
5277                while(interimSwap && interimSwap.activeChild)
5278                   interimSwap = interimSwap.activeChild;
5279
5280                result = interimWindow.ActivateEx(false, false, false, activateRoot, null,
5281                (menuBar && interimWindow.master == menuBar) ? menuBar : interimSwap);
5282                */
5283                result = /*interimWindow.*/ActivateEx(false, false, false, activateRoot, null, menuBar);
5284                //result = ActivateEx(true, true, false, activateRoot, window, null);
5285             }
5286          }
5287       }
5288       else
5289          // Testing & FindModal() here: broke reactivating when a modal dialog is up (didn't root activate dialog)
5290          result = ActivateEx(active, active, false, activateRoot /*&& FindModal()*/, window, swap);
5291
5292       if(interimWindow == this && interimMaster && !active)
5293       {
5294          while(interimMaster && interimMaster.interim && interimMaster.master)
5295          {
5296             // printf("Going up one master %s\n", interimMaster._class.name);
5297             interimMaster = interimMaster.master.rootWindow;
5298          }
5299          // printf("Unactivating interim master %s (%x)\n", interimMaster._class.name, interimMaster);
5300          interimMaster.ActivateEx(active, active, false, activateRoot, window, swap);
5301       }
5302       delete this;
5303       return result;
5304    }
5305
5306    bool DestroyEx(int returnCode)
5307    {
5308       OldLink slave;
5309       Timer timer, nextTimer;
5310       Window child;
5311       OldLink prevOrder = null;
5312       Window client = null;
5313
5314       if(parent) stopwatching(parent, font); 
5315
5316       // if(window.modalSlave) return false;
5317       if(destroyed || !created)
5318       {
5319          if(master)
5320          {
5321             /*
5322             if(destroyed)
5323             {
5324                OldLink slave = master.slaves.FindLink(this);
5325                master.slaves.Delete(slave);
5326             }
5327             */
5328             // TOFIX IMMEDIATELY: COMMENTED THIS OUT... causes problem second time creating file dialog
5329             //master = null;
5330          }
5331          return true;
5332       }
5333
5334       this.returnCode = (DialogResult)returnCode;
5335
5336       AcquireInput(false);
5337
5338       destroyed = true;
5339       if(hotKey)
5340       {
5341          master.hotKeys.Delete(hotKey);
5342          hotKey = null;
5343       }
5344
5345       if(guiApp.prevWindow == this)
5346       {
5347          guiApp.prevWindow = null;
5348          OnMouseLeave(0);
5349       }
5350       if(guiApp.caretOwner == this) 
5351       {
5352          guiApp.interfaceDriver.SetCaret(0,0,0);
5353          UpdateCaret(false, true);
5354          guiApp.caretEnabled = false;
5355       }
5356
5357       /*
5358       if(cycle)
5359          parent.childrenCycle.Remove(cycle);
5360       */
5361       if(order)
5362       {
5363          OldLink tmpPrev = order.prev;
5364          if(tmpPrev && !(((Window)tmpPrev.data).style.hidden) && !(((Window)tmpPrev.data).destroyed) && (((Window)tmpPrev.data).created))
5365             prevOrder = tmpPrev;
5366          for(;;)
5367          {
5368             client = tmpPrev ? tmpPrev.data : null;
5369             if(client == this) { client = null; break; }
5370             if(client && (client.style.hidden || client.destroyed || !client.created))
5371                tmpPrev = client.order.prev;
5372             else
5373             {
5374                if(client)
5375                   prevOrder = tmpPrev;
5376                break;
5377             }
5378          }
5379
5380          // If this window can be an active client, make sure the next window we activate can also be one
5381          if(!style.nonClient && style.isActiveClient)
5382          {
5383             tmpPrev = prevOrder;
5384             for(;;)
5385             {
5386                client = tmpPrev ? tmpPrev.data : null;
5387                if(client == this) { client = null; break; }
5388                if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
5389                   tmpPrev = client.order.prev;
5390                else 
5391                {
5392                   if(client)
5393                      prevOrder = tmpPrev;
5394                   break;
5395                }
5396             }
5397             if(client && client.style.hidden) client = null;
5398          }
5399          // parent.childrenOrder.Remove(order);
5400       }
5401
5402       if(parent && style.isActiveClient && visible)
5403       {
5404          if(state == minimized) parent.numIcons--;
5405          parent.numPositions--;
5406       }
5407
5408       // TESTING THIS HERE!
5409       created = false;
5410       visible = false;
5411
5412       // If no display, don't bother deactivating stuff (causes unneeded problems when trying
5413       // to create a window inside a rootwindow that's being destroyed)
5414       // DISABLED THIS BECAUSE OF CREATING WINDOW IN DESKTOP IN WINDOWED MODE
5415
5416       if(master && !master.destroyed /*&&
5417          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5418       {
5419          if(master.defaultControl == this)
5420             master.defaultControl = null;
5421       }
5422       if(parent)
5423          parent.OnChildAddedOrRemoved(this, true);
5424       if(parent && !parent.destroyed /*&&
5425          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5426       {
5427          if((parent.activeChild == this /*|| parent.activeClient == this */|| guiApp.interimWindow == this))
5428          {
5429             if(order && prevOrder && prevOrder.data != this && active)
5430             {
5431                //((Window)prevOrder.data).ActivateEx(true, false, false, false /*true*/, null);
5432
5433                ((Window)prevOrder.data).ActivateEx(true, false, false, (rootWindow == this) ? true : false, null, null);
5434                if(parent.activeClient == this)
5435                {
5436                   parent.activeClient = null;
5437                   parent.UpdateActiveDocument(null);
5438                }
5439             }
5440             else 
5441             {
5442                if(guiApp.interimWindow == this)
5443                {
5444                   bool goOn = true;
5445                   PropagateActive(false, null, &goOn, true);
5446                }
5447                else
5448                {
5449                   //if(window.parent.activeChild == window)
5450                      parent.activeChild = null;
5451                   if(!style.nonClient /*&& style.isActiveClient*/)
5452                   {
5453                      Window previous = parent.activeClient;
5454                      if(style.isActiveClient)
5455                         parent.activeClient = null;
5456                      parent.UpdateActiveDocument(previous);
5457                   }
5458                }
5459             }
5460          }
5461          else if(parent.activeClient == this)
5462          {
5463             parent.activeClient = client;
5464             parent.UpdateActiveDocument(this);
5465
5466          }
5467       }
5468       if(guiApp.interimWindow == this)
5469       {
5470          guiApp.interimWindow = null;
5471          if(guiApp.caretOwner)
5472          {
5473             Window desktop = guiApp.desktop;
5474             if(desktop.activeChild && desktop.activeChild.menuBar && !desktop.activeChild.menuBar.focus)
5475                guiApp.caretOwner.UpdateCaret(false, false);
5476          }
5477       }
5478
5479       active = false;
5480       if(_isModal && master && master.modalSlave == this)
5481          master.modalSlave = null;
5482
5483       if(parent)
5484       {
5485          if(!guiApp.caretOwner && parent.caretSize)
5486          {
5487             guiApp.caretOwner = parent;
5488             parent.UpdateCaret(false, false);
5489             parent.Update(null);
5490          }
5491
5492          // Why was this commented out?
5493          GetRidOfVirtualArea();
5494       }
5495       /*
5496       delete cycle;
5497       delete order;
5498       */
5499       dirtyArea.Free(null);
5500       dirtyBack.Free(null);
5501       scrollExtent.Free(null);
5502
5503       /* ATTEMPTING TO MOVE THAT ABOVE
5504       created = false;
5505       visible = false;
5506       */
5507
5508       /*
5509       OnDestroy();
5510       {
5511          //Window next;
5512          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5513          for(;(child = window.children.first);)
5514          {
5515             for(; child && (child.destroyed || !child.created); child = child.next);
5516             if(child)
5517                child.DestroyEx(0);
5518             else
5519                break;
5520          }
5521       }
5522       */
5523
5524       UnloadGraphics(true);
5525
5526       if(previousActive)
5527          delete previousActive;
5528
5529       menuBar = null;
5530       // statusBar = null;
5531       sbv = sbh = null;
5532
5533       if(master && !master.destroyed)
5534       {
5535          //master.NotifyDestroyed(this, this.returnCode);
5536          NotifyDestroyed(master, this, this.returnCode);
5537       }
5538
5539       for(timer = guiApp.windowTimers.first; timer; timer = nextTimer)
5540       {
5541          nextTimer = timer.next;
5542          if(timer.window == this)
5543          {
5544             // WHY WERE WE SETTING THIS TO NULL? NO MORE WINDOW WHEN RECREATING...
5545             // timer.window = null;
5546             timer.Stop();
5547             //delete timer;
5548          }
5549       }
5550
5551       if(this == guiApp.windowMoving)
5552          StopMoving();
5553
5554       if(guiApp.windowCaptured == this)
5555          ReleaseCapture();
5556          //guiApp.windowCaptured = null;
5557
5558       if(rootWindow != this && rootWindow)
5559          rootWindow.ConsequentialMouseMove(false);
5560
5561       rootWindow = null;
5562
5563       OnDestroy();
5564
5565       {
5566          //Window next;
5567          //for(child = children.first; next = child ? child.next : null, child; child = next)
5568          for(;(child = children.first); )
5569          {
5570             for(; child && (child.destroyed || !child.created); child = child.next);
5571             if(child)
5572                child.DestroyEx(0);
5573             else
5574                break;
5575          }
5576       }
5577
5578       // master = null;
5579
5580       /* // MOVED THIS UP...
5581       {
5582          //Window next;
5583          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5584          for(;(child = window.children.first); )
5585          {
5586             for(; child && (child.destroyed || !child.created); child = child.next);
5587             if(child)
5588                child.DestroyEx(0);
5589             else
5590                break;
5591          }
5592       }
5593       */
5594
5595       while((slave = slaves.first))
5596       {
5597          for(; slave && (((Window)slave.data).destroyed || !((Window)slave.data).created); slave = slave.next);
5598          if(slave)
5599             ((Window)slave.data).DestroyEx(0);
5600          else
5601             break;
5602       }
5603
5604       if(guiApp.caretOwner == this)
5605          guiApp.caretOwner = null;
5606
5607       sysButtons[0] = null;
5608       sysButtons[1] = null;
5609       sysButtons[2] = null;
5610       activeChild = null;
5611
5612       if(rootWindow != this)
5613       {
5614          Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
5615          if(style.nonClient)
5616          {
5617             box.left   -= parent.clientStart.x;
5618             box.top    -= parent.clientStart.y;
5619             box.right  -= parent.clientStart.x;
5620             box.bottom -= parent.clientStart.y;
5621          }
5622          if(parent) parent.Update(box);
5623       }
5624       /*
5625       if(master)
5626       {
5627          OldLink slave = master.slaves.FindVoid(this);
5628          master.slaves.Delete(slave);
5629          master = null;
5630       }
5631
5632       if(parent)
5633       {
5634          parent.children.Remove(this);
5635          parent = null;
5636       }
5637       */
5638
5639       //autoCreate = false;
5640       //created = false;
5641
5642       // SHOULD THIS BE HERE? FIXED CRASH WITH GOTO DIALOG
5643       if(((subclass(Window))_class).pureVTbl)
5644       {
5645          if(_vTbl == _class._vTbl)
5646          {
5647             _vTbl = ((subclass(Window))_class).pureVTbl;
5648          }
5649          else
5650          {
5651             int m;
5652             for(m = 0; m < _class.vTblSize; m++)
5653             {
5654                if(_vTbl[m] == _class._vTbl[m])
5655                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
5656             }
5657          }
5658       }
5659
5660       delete this;
5661       return true;
5662    }
5663
5664    void SetStateEx(WindowState newState, bool activate)
5665    {
5666       int x,y,w,h;
5667       WindowState prevState = state;
5668
5669       state = newState;
5670
5671       if(prevState != newState)
5672          lastState = prevState;
5673
5674       if(rootWindow != this || !nativeDecorations || !windowHandle)
5675       {
5676          if(style.isActiveClient && !style.hidden && prevState == minimized)
5677             parent.numIcons--;
5678
5679          // This block used to be at the end of the function... moved it for flicker problem in X
5680          // ------------------------------------------------------
5681          switch(state)
5682          {
5683             case normal:
5684                stateAnchor = normalAnchor;
5685                stateSizeAnchor = normalSizeAnchor;
5686                break;
5687             case maximized:
5688                stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5689                stateSizeAnchor = SizeAnchor {};
5690                break;
5691             case minimized:
5692             {
5693                int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5694                Window child;
5695                int size = 256;
5696                byte * idBuffer = new0 byte[size];
5697                int c;
5698                for(child = parent.children.first; child; child = child.next)
5699                {
5700                   if(child != this && child.state == minimized)
5701                   {
5702                      if(child.iconID > size - 2)
5703                      {
5704                         idBuffer = renew0 idBuffer byte[size*2];
5705                         memset(idBuffer + size, 0, size);
5706                         size *= 2;
5707                      }
5708                      idBuffer[child.iconID] = (byte)bool::true;
5709                   }
5710                }
5711                for(c = 0; c<size; c++)
5712                   if(!idBuffer[c])
5713                      break;
5714                iconID = c;
5715                delete idBuffer;
5716                if(style.isActiveClient && !style.hidden)
5717                   parent.numIcons++;
5718
5719                stateAnchor = Anchor { left = (iconID % maxIcons) * MINIMIZED_WIDTH, bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24) };
5720                stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5721                break;
5722             }
5723          }
5724          // TOCHECK: Why was this here?
5725          //position.x = (tx > 0) ? tx & 0xFFFFF : tx;
5726          //position.y = (ty > 0) ? ty & 0xFFFFF : ty;
5727          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5728
5729          Position(x, y, w, h, true, true, true, true, false, true);
5730
5731          if(!style.inactive && !style.interim && this == parent.activeClient)
5732             parent.UpdateActiveDocument(null);
5733       }
5734
5735       CreateSystemChildren();
5736       // ------------------------------------------------------
5737    }
5738
5739    int GetPositionID(Window forChild)
5740    {
5741       Window child;
5742       int size = 256;
5743       byte * idBuffer = new0 byte[size];
5744       int c;
5745
5746       for(child = children.first; child; child = child.next)
5747       {
5748          if(child.style.isActiveClient && !child.style.hidden && child != forChild)
5749          {
5750             if(child.positionID > size - 2)
5751             {
5752                idBuffer = renew0 idBuffer byte[size*2];
5753                memset(idBuffer + size, 0, size);
5754                size *= 2;
5755             }
5756             idBuffer[child.positionID] = (byte)bool::true;
5757          }
5758       }
5759       for(c = 0; c<size; c++)
5760          if(!idBuffer[c])
5761             break;
5762       delete idBuffer;
5763       return c;
5764    }
5765
5766    // --- Window related graphics ---
5767
5768    void SetPalette(ColorAlpha * newPalette, bool colorMatch)
5769    {
5770       palette = newPalette;
5771       if(rootWindow.display)
5772          rootWindow.display.SetPalette(palette, colorMatch);
5773    }
5774
5775    public bool AcquireInput(bool acquired)
5776    {
5777       bool result = true;
5778       if(acquiredInput != acquired)
5779       {
5780          if(active || (!visible && creationActivation == activate))
5781             result = AcquireInputEx(acquired);
5782          /*if(!result)
5783          {
5784             Print("");
5785          }*/
5786          acquiredInput = acquired ? result : !result;
5787       }
5788       return result;
5789    }
5790
5791    void ListChildren(ListBox listBox)
5792    {
5793       Window child;
5794       char caption[2048];
5795       for(child = children.first; child; child = child.next)
5796       {
5797          if(child.cycle && !child.style.nonClient && child.style.isActiveClient && child.visible)
5798          {
5799             DataRow row = listBox.AddRow();
5800             row.tag = (int)child;
5801             child.FigureCaption(caption);
5802             row.SetData(null, caption);
5803          }
5804       }
5805    }
5806
5807    void UpdateVisual(Box extent)
5808    {
5809       if(guiApp.driver != null)
5810       {
5811          if(guiApp.fullScreenMode && guiApp.desktop.display)
5812          {
5813             guiApp.desktop.mutex.Wait();
5814             guiApp.desktop.display.Lock(true);
5815          
5816             Update(extent);
5817             if(guiApp.desktop.active)
5818             {
5819                if(guiApp.desktop.dirty || guiApp.cursorUpdate)
5820                {
5821                   if(guiApp.desktop.display.flags.flipping)
5822                      guiApp.desktop.Update(null);
5823                   guiApp.desktop.UpdateDisplay();
5824                   guiApp.cursorUpdate = true;
5825                }
5826                if(guiApp.cursorUpdate || guiApp.desktop.dirty)
5827                {
5828                   guiApp.PreserveAndDrawCursor();
5829                   // guiApp.desktop.display.ShowScreen();
5830                   guiApp.cursorUpdate = false;
5831                   guiApp.desktop.dirty = false;
5832                   guiApp.RestoreCursorBackground();
5833                }
5834             }
5835          
5836             guiApp.desktop.display.Unlock();
5837             guiApp.desktop.mutex.Release();
5838          }
5839          else
5840          {
5841             Window rootWindow = this.rootWindow;
5842             rootWindow.mutex.Wait();
5843             display.Lock(true);
5844          
5845             Update(extent);
5846             if(guiApp.waiting)
5847                guiApp.SignalEvent();
5848             else
5849             {
5850                guiApp.waitMutex.Wait();
5851                guiApp.interfaceDriver.Lock(rootWindow);
5852                if(!rootWindow.style.hidden && rootWindow.dirty)
5853                {
5854                   if(rootWindow.display)
5855                   {
5856                      rootWindow.UpdateDisplay();
5857                      //rootWindow.display.ShowScreen(null);
5858                   }
5859                   rootWindow.dirty = false;
5860                }
5861                guiApp.interfaceDriver.Unlock(rootWindow);
5862                guiApp.waitMutex.Release();
5863             }
5864             display.Unlock();
5865             rootWindow.mutex.Release();
5866          }
5867       }
5868    }
5869
5870    void UnlockDisplay(void)
5871    {
5872       guiApp.interfaceDriver.Unlock(rootWindow);
5873    }
5874
5875    void LockDisplay(void)
5876    {
5877       guiApp.interfaceDriver.Lock(rootWindow);
5878    }
5879
5880    Surface GetSurface(Box box)
5881    {
5882       return Redraw((box == null) ? this.box : box);
5883    }
5884
5885    void SetMousePosition(int x, int y)
5886    {
5887       guiApp.interfaceDriver.SetMousePosition(x + absPosition.x + clientStart.x, y + absPosition.y + clientStart.y);
5888    }
5889
5890    /*
5891    void IntegrationActivate(bool active)
5892    {
5893       if(!guiApp.modeSwitching && !guiApp.fullScreenMode)
5894       {
5895          isForegroundWindow = true;
5896          ActivateEx(active, active, false, false, null, null);
5897          isForegroundWindow = false;
5898       }  
5899    }
5900    */
5901
5902    Window QueryCapture(void)
5903    {
5904       return guiApp.windowCaptured;
5905    }
5906
5907    int GetDocumentID(void)
5908    {
5909       Window child;
5910       int size = 256;
5911       byte * idBuffer = new0 byte[size];
5912       int c;
5913
5914       for(child = children.first; child; child = child.next)
5915       {
5916          // TO CHECK: Do we want a documentID when we already have a file name?
5917          if(child.style.isDocument && !child.fileName)
5918          {
5919             if(child.documentID-1 > size - 2)
5920             {
5921                idBuffer = renew0 idBuffer byte[size*2];
5922                memset(idBuffer + size, 0, size);
5923                size *= 2;
5924             }
5925             idBuffer[child.documentID-1] = 1;
5926          }
5927       }
5928       for(c = 0; c<size; c++)
5929          if(!idBuffer[c])
5930             break;
5931       numDocuments++;
5932       delete idBuffer;
5933       return c + 1;
5934    }
5935
5936    void SetInitSize(Size size)
5937    {
5938       int x, y, w, h;
5939       sizeAnchor.size = size;
5940       normalSizeAnchor = sizeAnchor;
5941
5942       // Break the anchors for moveable/resizable windows
5943       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
5944       {
5945          stateAnchor = normalAnchor;
5946          stateSizeAnchor = normalSizeAnchor;
5947
5948          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5949          Position(x,y, w, h, true, true, true, true, false, true);
5950       }
5951    }
5952
5953    void MenuMoveOrSize(bool resize, bool setCursorPosition)
5954    {
5955       if(this != guiApp.desktop && state != maximized && (resize ? (state != minimized && style.sizable) : (style.fixed || moveable)))
5956       {
5957          guiApp.windowIsResizing = resize;
5958          guiApp.windowMoving = this;
5959          guiApp.windowMovingStart = guiApp.movingLast = absPosition;
5960          if(guiApp.windowIsResizing)
5961          {
5962             guiApp.windowMovingStart.x += size.w - 1;
5963             guiApp.windowMovingStart.y += size.h - 1;
5964          }
5965          guiApp.windowMovingBefore = scrolledPos;
5966          guiApp.windowResizingBefore = size;
5967          guiApp.windowMoving.UpdateDecorations();
5968          if(guiApp.windowIsResizing) 
5969             guiApp.resizeEndX = guiApp.resizeEndY = true;
5970
5971          if(setCursorPosition)
5972             guiApp.interfaceDriver.SetMousePosition(guiApp.windowMovingStart.x, guiApp.windowMovingStart.y);
5973          else
5974          {
5975             int x, y;
5976             guiApp.interfaceDriver.GetMousePosition(&x, &y);
5977             guiApp.windowMovingStart.x += x - absPosition.x;
5978             guiApp.windowMovingStart.y += y - absPosition.y;
5979          } 
5980
5981          if(guiApp.windowMoving)
5982          {
5983             if(guiApp.windowMoving.style.nonClient)
5984                guiApp.windowMoving.parent.SetMouseRangeToWindow();
5985             else
5986                guiApp.windowMoving.parent.SetMouseRangeToClient();
5987          }
5988
5989          Capture();
5990
5991          if(this == rootWindow)
5992             guiApp.interfaceDriver.StartMoving(rootWindow, guiApp.windowMovingStart.x, guiApp.windowMovingStart.y, true);
5993       }
5994    }
5995
5996 public:
5997    // normal Methods
5998    bool Create()
5999    {
6000       bool result = false;
6001
6002       if(created)
6003          result = true;
6004       else if(guiApp && guiApp.driver != null)
6005       {
6006          void * systemParent = null;
6007          OldLink slaveHolder;
6008          Window last;
6009          bool visible = !style.hidden;
6010
6011          if(style.embedded) 
6012          {
6013             systemParent = parent;
6014             parent = guiApp.desktop;
6015          }
6016          last = parent ? parent.children.last : null;
6017
6018          if((parent && parent != guiApp.desktop && !parent.created) ||
6019             (master && master != guiApp.desktop && !master.created))
6020             return false;
6021
6022          if(parent)
6023             stopwatching(parent, font);
6024
6025          if(!parent)
6026             property::parent = guiApp.desktop;
6027          if(!master) master = parent;
6028
6029          if(_isModal && master.modalSlave)
6030             property::master = master.modalSlave;
6031             //return false;
6032
6033          if(parent)
6034             parent.children.Remove(this);
6035          if(master)
6036          {
6037             for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
6038                if(slaveHolder.data == this)
6039                {
6040                   master.slaves.Delete(slaveHolder);
6041                   break;
6042                }
6043          }
6044
6045          if(parent == guiApp.desktop && !mutex)
6046             mutex = Mutex {};
6047
6048          if(style.isDocument)
6049          {
6050             if(parent)
6051                parent.numDocuments--;
6052             documentID = parent.GetDocumentID();
6053          }
6054
6055          if(!style.stayOnTop)
6056             for(; last && last.style.stayOnTop; last = last.prev);
6057
6058          parent.children.Insert((last == this) ? null : last, this);
6059          //parent.children.Add(this);
6060
6061          if(!dispDriver)
6062             dispDriver = parent.dispDriver;
6063          destroyed = false;
6064          if(_isModal)
6065             master.modalSlave = this;
6066
6067          box = Box { MAXINT, MAXINT, MININT, MININT }; //-MAXINT, -MAXINT };
6068
6069          incref this;
6070          incref this;
6071
6072          master.slaves.Add(slaveHolder = OldLink { data = this });
6073          if(slaveHolder)
6074          {
6075             if(setHotKey)
6076             {
6077                master.hotKeys.Add(hotKey = HotKeySlot { key = setHotKey, window = this });
6078             }
6079             if(style.isDefault && !master.defaultControl)
6080                master.defaultControl = this;
6081
6082             stateAnchor = normalAnchor = anchor;
6083             stateSizeAnchor = normalSizeAnchor = sizeAnchor;
6084
6085             // TOCHECK: Why is this here?
6086             //position.x = (ax > 0) ? ax & 0xFFFFF : ax;
6087             //position.y = (ay > 0) ? ay & 0xFFFFF : ay;
6088
6089             this.visible = false;
6090             style.hidden = true;
6091     
6092             //created = true;
6093             // autoCreate = true;
6094             wasCreated = true;
6095             if(SetupDisplay())
6096             {
6097                created = true;
6098                if(OnCreate())
6099                {
6100                   /*
6101                   if(parent == guiApp.desktop)
6102                      Log("LoadGraphics %s\n", caption);
6103                   */
6104                   if(LoadGraphics(true, false))
6105                   {
6106                      if(!setFont)
6107                      {
6108                         watch(parent)
6109                         {
6110                            font
6111                            {
6112                               usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
6113                               firewatchers font;
6114                               Update(null);
6115                            }
6116                         };
6117                      }
6118
6119                      if(style.hasMenuBar /*&& menu*/)
6120                      {
6121                         menuBar = 
6122                            PopupMenu
6123                            {
6124                               this,
6125                               menu = menu, isMenuBar = true, anchor = Anchor { top = 23, left = 1, right = 1 },
6126                               interim = false, inactive = true, nonClient = true, size.h = 24
6127                            };
6128                         menuBar.Create();
6129                      }
6130
6131                      if(statusBar)
6132                         statusBar.Create();
6133                      
6134                      // Create the system buttons
6135                      CreateSystemChildren();
6136
6137                      UpdateActiveDocument(null);
6138
6139                      if(style.isDocument)
6140                      {
6141                         if(menu)
6142                         {
6143                            MenuItem item = menu.FindItem(MenuFileSave, 0);
6144                            if(item) item.disabled = !modifiedDocument && fileName;
6145                         }
6146                      }
6147
6148                      /*
6149                      if(parent == guiApp.desktop)
6150                         Log("Preemptive SetState %s\n", caption);
6151                      */
6152
6153                      // Preemptive Set State to ensure proper anchoring
6154                      SetStateEx(state, false);
6155                      /*
6156                      style.hidden = true;
6157                      visible = false;
6158                      */
6159
6160                      {
6161                         Window child, next;
6162                         for(child = children.first; child; child = next)
6163                         {
6164                            next = child.next;
6165                            if(!child.created && (child.autoCreate || child.wasCreated))
6166                               child.Create();
6167                         }
6168                      }
6169
6170                      {
6171                         OldLink link, next;
6172                         for(link = slaves.first; link; link = next)
6173                         {
6174                            Window slave = link.data;
6175                            next = link.next;
6176                            if(!slave.created && (slave.autoCreate || slave.wasCreated))
6177                            {
6178                               if(slave.Create())
6179                                  // Things might have happened that invalidated 'next'...
6180                                  // Start over the search for slaves to create.
6181                                  // (Added this to fix crash with Stacker & Toolbar)
6182                                  next = slaves.first;
6183                            }
6184                         }
6185                      }
6186
6187                      if(OnPostCreate())
6188                         OnApplyGraphics();
6189
6190                      /*
6191                      if(parent == guiApp.desktop)
6192                         Log("Real SetState %s\n", caption);
6193                      */
6194
6195                      if(isActiveClient && visible)
6196                      {
6197                         parent.numPositions--;
6198                         if(state == minimized) parent.numIcons--;
6199                      }
6200
6201                      parent.OnChildAddedOrRemoved(this, false);
6202
6203                      // Real set state & activate for proper display & activation
6204                      property::visible = visible;
6205                      //  SetState(state & 0x00000003, true, 0);
6206                      guiApp.interfaceDriver.SetIcon(this, icon);
6207
6208                      if(visible)
6209                      {
6210                         UpdateCaption();
6211                         /*if(rootWindow == this)
6212                            guiApp.interfaceDriver.ActivateRootWindow(this);
6213                         else*/
6214                         if(creationActivation == activate)
6215                            ActivateEx(true, false, true, true, null, null);
6216                         else if(creationActivation == flash)
6217                            Flash();
6218                      }
6219
6220                      if(!destroyed)
6221                         rootWindow.ConsequentialMouseMove(false);
6222
6223                      result = true;
6224                   }
6225                }
6226             }
6227          }
6228          /*
6229          if(!result)
6230          {
6231             Destroy(0);
6232             guiApp.LogErrorCode(IERR_WINDOW_CREATION_FAILED, caption);
6233          }
6234          */
6235
6236          if(!result)
6237          {
6238             // Testing this here... Otherwise a failed LoadGraphics stalls the application
6239             created = false;
6240             //style.hidden = true; // !visible;
6241             style.hidden = !visible;
6242             if(master.modalSlave == this)
6243                master.modalSlave = null;
6244          }
6245          delete this;
6246       }
6247       return result;
6248    }
6249
6250    void WriteCaption(Surface surface, int x, int y)
6251    {
6252       if(caption)
6253          Interface::WriteKeyedTextDisabled(surface, x,y, caption, hotKey ? hotKey.key : 0, !isEnabled);
6254    }
6255
6256    void Update(Box region)
6257    {
6258       if(this)
6259       {
6260          Window rootWindow;
6261
6262          rootWindow = this.rootWindow;
6263
6264          // rootWindow.mutex.Wait();
6265          if(!destroyed && visible && display)
6266          {
6267             Window child;
6268             Box realBox;
6269             
6270             // Testing this to avoid repetitve full update to take time...
6271             if(dirtyArea.count == 1)
6272             {
6273                BoxItem item = (BoxItem)ACCESS_ITEM(dirtyArea, dirtyArea.first);
6274                if(item.box.left <= box.left &&
6275                   item.box.top <= box.top &&
6276                   item.box.right >= box.right &&
6277                   item.box.bottom >= box.bottom)
6278                {
6279                   rootWindow.dirty = true;
6280                   return;
6281                }
6282             }
6283
6284             if(display.flags.flipping && !rootWindow.dirty)
6285             {
6286                if(this == rootWindow)
6287                   region = null;
6288                else
6289                {
6290                   rootWindow.Update(null);
6291                   return;
6292                }
6293             }
6294             
6295             rootWindow.dirty = true;
6296
6297             if(region != null)
6298             {
6299                realBox = region;
6300                realBox.left += clientStart.x;
6301                realBox.top += clientStart.y;
6302                realBox.right += clientStart.x;
6303                realBox.bottom += clientStart.y;
6304                realBox.Clip(box);
6305             }
6306             else
6307                realBox = box;
6308
6309             if(realBox.right >= realBox.left && 
6310                realBox.bottom >= realBox.top)
6311             {
6312                // if(!rootWindow.fullRender)
6313                   dirtyArea.UnionBox(realBox, rootWindow.tempExtents[0]);
6314
6315                for(child = children.first; child; child = child.next)
6316                {
6317                   if(!child.is3D)
6318                   {
6319                      Box box = realBox;
6320                      box.left -= child.absPosition.x - absPosition.x;
6321                      box.top -= child.absPosition.y - absPosition.y;
6322                      box.right -= child.absPosition.x - absPosition.x;
6323                      box.bottom -= child.absPosition.y - absPosition.y;
6324                      if(box.right >= child.box.left && box.left <= child.box.right &&
6325                         box.bottom >= child.box.top && box.top <= child.box.bottom)
6326                      {
6327                         box.left -= child.clientStart.x;
6328                         box.top -= child.clientStart.y;
6329                         box.right -= child.clientStart.x;
6330                         box.bottom -= child.clientStart.y;
6331                         child.Update(box);
6332                      }
6333                   }
6334                }
6335
6336                realBox.left += absPosition.x - rootWindow.absPosition.x;
6337                realBox.top += absPosition.y - rootWindow.absPosition.y;
6338                realBox.right += absPosition.x - rootWindow.absPosition.x;
6339                realBox.bottom += absPosition.y - rootWindow.absPosition.y;
6340                rootWindow.dirtyBack.UnionBox(realBox, rootWindow.tempExtents[0]);
6341             }
6342          }
6343          else if(this == guiApp.desktop)
6344          {
6345             Window window;
6346             for(window = children.first; window; window = window.next)
6347             {
6348                if(!window.is3D)
6349                {
6350                   if(region != null)
6351                   {
6352                      Box childBox = region;
6353
6354                      childBox.left    -= window.absPosition.x - guiApp.desktop.absPosition.x;
6355                      childBox.top     -= window.absPosition.y - guiApp.desktop.absPosition.y;
6356                      childBox.right   -= window.absPosition.x - guiApp.desktop.absPosition.x;
6357                      childBox.bottom  -= window.absPosition.y - guiApp.desktop.absPosition.y;
6358        
6359                      window.Update(childBox);
6360                   }
6361                   else
6362                      window.Update(null);
6363                }
6364             }
6365          }
6366
6367          // rootWindow.mutex.Release();
6368       }
6369    }
6370
6371    bool Capture(void)
6372    {
6373       bool result = true;
6374       if(guiApp.windowCaptured != this)
6375       {
6376          if(guiApp.windowCaptured)
6377             result = false;
6378          else
6379          {
6380             //Logf("Captured %s (%s)\n", caption, class.name);
6381             guiApp.interfaceDriver.SetMouseCapture(rootWindow);
6382             guiApp.windowCaptured = this;
6383          }
6384       }
6385       return result;
6386    }
6387
6388    bool Destroy(int code)
6389    {
6390       //if(created)
6391       if(this)
6392       {
6393          if(!destroyed && !CloseConfirmation(false)) return false;
6394          incref this;
6395          if(DestroyEx(code))
6396          {
6397             // TOCHECK: Should autoCreate be set to false here?
6398             autoCreate = false;
6399             wasCreated = false;
6400             delete this;
6401             return true;
6402          }
6403          delete this;
6404       }
6405       return false;
6406    }
6407
6408    void Move(int x, int y, int w, int h)
6409    {
6410       normalAnchor = Anchor { left = x, top = y };
6411       normalSizeAnchor = SizeAnchor { size = { w, h } };
6412
6413       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6414       {
6415          if(destroyed) return;
6416
6417          stateAnchor = normalAnchor;
6418          stateSizeAnchor = normalSizeAnchor;
6419
6420          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6421          Position(x,y, w, h, true, true, true, true, false, true);
6422       }
6423    }
6424
6425    DialogResult Modal(void)
6426    {
6427       isModal = true;
6428       if(Create())
6429          return DoModal();
6430
6431       // FIXES MEMORY LEAK IF Create() FAILED
6432       incref this;
6433       delete this;
6434       return 0;
6435    }
6436
6437    void SetScrollArea(int width, int height, bool snapToStep)
6438    {
6439       bool resize = false;
6440       if(snapToStep)
6441       {
6442          int stepX = sbStep.x, stepY = sbStep.y;
6443          // Needed to make snapped down position match the skin's check of client area 
6444          // against realvirtual
6445          if(guiApp.textMode)
6446          {
6447             SNAPDOWN(stepX, textCellW);
6448             SNAPDOWN(stepY, textCellH);
6449             stepX = Max(stepX, textCellW);
6450             stepY = Max(stepY, textCellH);
6451          }
6452          if(scrollFlags.snapX)
6453             SNAPUP(width, stepX);
6454          if(scrollFlags.snapY)
6455             SNAPUP(height, stepY);
6456       }
6457
6458       reqScrollArea.w = width;
6459       reqScrollArea.h = height;
6460       noAutoScrollArea = (width > 0 || height > 0);
6461
6462       UpdateScrollBars(true, true);
6463    }
6464
6465    void SetScrollPosition(int x, int y)
6466    {
6467       if(sbh)
6468          sbh.Action(setPosition, x, 0);
6469       else
6470       {
6471          int range;
6472          int seen = clientSize.w, total = reqScrollArea.w;
6473          seen = Max(1,seen);
6474          if(scrollFlags.snapX)
6475             SNAPDOWN(seen, sbStep.x);
6476
6477          if(!total) total = seen;
6478          range = total - seen + 1;
6479          range = Max(range, 1);
6480          if(x < 0) x = 0;
6481          if(x >= range) x = range - 1;
6482
6483          if(scrollFlags.snapX)
6484             SNAPUP(x, sbStep.x);
6485
6486          if(scroll.x != x)
6487             OnHScroll(setPosition, x, 0);
6488
6489          if(guiApp.textMode)
6490          {
6491             SNAPDOWN(x, textCellW);
6492          }
6493          scroll.x = x;
6494       }
6495
6496       if(sbv)
6497          sbv.Action(setPosition, y, 0);
6498       else
6499       {
6500          int range;
6501          int seen = clientSize.h, total = reqScrollArea.h;
6502          seen = Max(1,seen);
6503
6504          if(scrollFlags.snapY)
6505             SNAPDOWN(seen, sbStep.y);
6506
6507          if(!total) total = seen;
6508          range = total - seen + 1;
6509          range = Max(range, 1);
6510          if(y < 0) y = 0;
6511          if(y >= range) y = range - 1;
6512
6513          if(scrollFlags.snapY)
6514             SNAPUP(y, sbStep.y);
6515
6516          if(scroll.y != y)
6517             OnVScroll(setPosition, y, 0);
6518          if(guiApp.textMode)
6519          {
6520             SNAPDOWN(y, textCellH);
6521          }
6522          scroll.y = y;
6523       }
6524       if(!sbh || !sbv)
6525          UpdateCaret(false, false);
6526    }
6527
6528    void SetScrollLineStep(int stepX, int stepY)
6529    {
6530       sbStep.x = stepX;
6531       sbStep.y = stepY;
6532       if(guiApp.textMode)
6533       {
6534          SNAPDOWN(stepX, textCellW);
6535          SNAPDOWN(stepY, textCellH);
6536          stepX = Max(stepX, textCellW);
6537          stepY = Max(stepY, textCellH);
6538       }
6539       if(sbh)
6540          sbh.lineStep = stepX;
6541       if(sbv)
6542          sbv.lineStep = stepY;
6543    }
6544
6545    void SetState(WindowState newState, bool activate, Modifiers mods)
6546    {
6547       if(created)
6548       {
6549          if(state == newState || OnStateChange(newState, mods))
6550          {
6551             WindowState prevState = state;
6552
6553             StopMoving();
6554
6555             // This used to be at the end of the brackets... moved for X, testing...
6556             // This has the effect of activating the window through the system...
6557             if(rootWindow == this)
6558                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
6559       
6560             SetStateEx(newState, activate);
6561
6562             if(rootWindow == this && !rootWindow.nativeDecorations)
6563             {
6564                int x = position.x, y = position.y;
6565                /*if(style.interim)
6566                {
6567                   x -= guiApp.desktop.absPosition.x;
6568                   y -= guiApp.desktop.absPosition.y;
6569                }*/
6570                guiApp.interfaceDriver.PositionRootWindow(this, x, y, size.w, size.h, true, true);
6571             }
6572
6573             //state = newState;
6574             //state = prevState;
6575
6576             if(state != maximized && style.hasMaximize)
6577             {
6578                Window child;
6579                for(child = parent.children.first; child; child = child.next)
6580                {
6581                   if(child != this && child.state == maximized)
6582                      child.SetStateEx(normal, false);
6583                }
6584             }
6585
6586             if(!style.nonClient && (sbv || sbh) && this != parent.sbv && this != parent.sbh)
6587                parent.UpdateScrollBars(true, true);
6588
6589             /*
6590             // Do we really need this stuff here? 
6591             // Shouldn't the Activate stuff take care of it?              
6592             if(parent.rootWindow == parent && style)
6593             {
6594                char caption[2048];
6595                parent.FigureCaption(caption);
6596                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
6597                parent.UpdateDecorations();
6598             }         
6599             */
6600
6601             rootWindow.ConsequentialMouseMove(false);
6602          }
6603       }
6604       else
6605          state = newState;
6606    }
6607
6608    BitmapResource GetIcon(SkinBitmap iconID)
6609    {
6610       return guiApp.currentSkin.GetBitmap(iconID);
6611    }
6612
6613    void SetMouseRange(Box range)
6614    {
6615       if(range || guiApp.fullScreenMode)
6616       {
6617          Box clip;
6618          if(range != null)
6619          {
6620             clip.left   = range.left + absPosition.x + clientStart.x;
6621             clip.top    = range.top + absPosition.y + clientStart.y;
6622             clip.right  = range.right + absPosition.x + clientStart.x;
6623             clip.bottom = range.bottom + absPosition.y + clientStart.y;
6624          }
6625          else
6626          {
6627             clip.left   = guiApp.desktop.box.left;
6628             clip.top    = guiApp.desktop.box.top;
6629             clip.right  = guiApp.desktop.box.right;
6630             clip.bottom = guiApp.desktop.box.bottom;
6631          }
6632          guiApp.interfaceDriver.SetMouseRange(rootWindow, clip);
6633       }
6634       else
6635          guiApp.interfaceDriver.SetMouseRange(rootWindow, null);
6636    }
6637
6638    void SetMouseRangeToClient(void)
6639    {
6640       if(guiApp.fullScreenMode || this != guiApp.desktop)
6641       {
6642          Box box {0, 0, clientSize.w - 1, clientSize.h - 1 };
6643          box.Clip(clientArea);
6644          SetMouseRange(box);
6645       }
6646       else
6647          SetMouseRange(null);
6648    }
6649
6650    void SetMouseRangeToWindow(void)
6651    {
6652       Box box { -clientStart.x, -clientStart.y, size.w-1, size.h-1 };
6653       if(this == guiApp.desktop)
6654          SetMouseRangeToClient();
6655       else
6656          SetMouseRange(box);
6657    }
6658
6659    // x, y: Desktop Coordinates
6660    void ShowSysMenu(int x, int y)
6661    {
6662       Menu menu { };
6663       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
6664       MenuItem
6665       {
6666          menu, $"Restore", r, NotifySelect = MenuWindowRestore, 
6667          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
6668       };
6669       MenuItem
6670       {
6671          menu, $"Move", m, NotifySelect = MenuWindowMove, 
6672          disabled = !style.fixed || state == maximized
6673       };
6674       MenuItem
6675       {
6676          menu, $"Size", s, NotifySelect = MenuWindowSize, 
6677          disabled = !style.sizable || state != normal
6678       };
6679       MenuItem
6680       {
6681          menu, $"Minimize", n, NotifySelect = MenuWindowMinimize, 
6682          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
6683       };
6684       MenuItem
6685       {
6686          menu, $"Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize, 
6687          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
6688       };
6689       MenuItem
6690       {
6691          menu, $"Stay On Top", t, NotifySelect = MenuWindowStayOnTop, 
6692          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
6693       };
6694       MenuDivider { menu };
6695       MenuItem
6696       {
6697          menu, $"Close", c, (parent == guiApp.desktop) ? altF4 : ( style.isActiveClient ? ctrlF4 : 0), NotifySelect = MenuWindowClose,
6698          bold = true, disabled = !style.hasClose, bitmap = guiApp.currentSkin.GetBitmap(close)
6699       };
6700       windowMenu.Create();
6701    }
6702
6703    void Activate(void)
6704    {
6705       ActivateEx(true, true, true, true, null, null);
6706    }
6707
6708    void MakeActive(void)
6709    {
6710       ActivateEx(true, false, true, false, null, null);
6711    }
6712
6713    void SoftActivate(void)
6714    {
6715       if(guiApp.desktop.active)
6716          Activate();
6717       else if(!active)
6718          Flash();
6719    }
6720
6721    void Deactivate(void)
6722    {
6723       ActivateEx(false, true, true, true, null, null);
6724    }
6725
6726    void Flash(void)
6727    {
6728       guiApp.interfaceDriver.FlashRootWindow(rootWindow);
6729    }
6730
6731    bool CycleChildren(bool backward, bool clientOnly, bool tabCycleOnly, bool cycleParents)
6732    {
6733       bool result = false;
6734       if(activeChild && activeChild.cycle)
6735       {
6736          Window modalWindow, child = activeChild;
6737          if(!clientOnly /*&& parent.tabCycle*/)
6738          {
6739             Window next = child;
6740             while(true)
6741             {
6742                if(next.cycle == (backward ? childrenCycle.first : childrenCycle.last))
6743                {
6744                   if(cycleParents)
6745                   {
6746                      if(parent && parent.CycleChildren(backward, false, true, true))
6747                         return true;
6748                      break;
6749                   }
6750                   else
6751                      return false;
6752                }
6753                if(backward)
6754                   next = next.cycle.prev.data;
6755                else
6756                   next = next.cycle.next.data;
6757                if(!next.disabled && !next.inactive /*isRemote*/ && next.created && !next.nonClient && (!clientOnly || next.style.isActiveClient) && !next.style.hidden && next.FindModal() != activeChild)
6758                   break;
6759             }
6760          }
6761          /*
6762          if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) && 
6763             parent.tabCycle && parent.CycleChildren(backward, false, false))
6764             return true;
6765          */
6766
6767          if(tabCycleOnly && !tabCycle) return false;
6768
6769          while(child)
6770          {
6771             while(true)
6772             {
6773                if(backward)
6774                   child = child.cycle.prev.data;
6775                else
6776                   child = child.cycle.next.data;
6777                if(child == child.parent.activeChild)
6778                   return result;
6779                else if(!child.disabled && child.created && (!clientOnly || child.style.isActiveClient) && !child.style.hidden && child.FindModal() != activeChild)
6780                   break;
6781             }
6782             modalWindow = child.FindModal();
6783             if(!modalWindow)
6784             {
6785                // Scroll the window to include the active control
6786                if(sbh && !child.style.dontScrollHorz)
6787                {
6788                   if(child.scrolledPos.x < 0)
6789                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x, 0);
6790                   else if(child.scrolledPos.x + child.size.w > clientSize.w)
6791                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x + child.size.w - clientSize.w, 0);
6792                }
6793                if(sbv && !child.style.dontScrollVert)
6794                {
6795                   if(child.scrolledPos.y < 0)
6796                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y, 0);
6797                   else if(child.scrolledPos.y + child.size.h > clientSize.h)
6798                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y + child.size.h - clientSize.h, 0);
6799                }
6800             }
6801             result = true;
6802             child = modalWindow ? modalWindow : child;
6803             child.ActivateEx(true, true, true, true, null, null);
6804             if(child.tabCycle && child.childrenCycle.first)
6805                child = ((OldLink)(backward ? child.childrenCycle.first : child.childrenCycle.last)).data;
6806             else
6807                break;
6808          }
6809       }
6810       else
6811          return false;
6812
6813       ConsequentialMouseMove(false);
6814       return result;
6815    }
6816
6817    void AddResource(Resource resource)
6818    {
6819       if(resource)
6820       {
6821          ResPtr ptr { resource = resource };
6822          resources.Add(ptr);
6823          incref resource;
6824
6825          // Load Graphics here if window is created already
6826          if(/*created && */display)
6827          {
6828             display.Lock(false);
6829             ptr.loaded = display.displaySystem.LoadResource(resource);
6830             display.Unlock();
6831          }
6832          /*
6833          // Temporary hack to load font right away for listbox in dropbox ...
6834          else if(master && master.display)
6835          {
6836             master.display.Lock(false);
6837             master.display.displaySystem.LoadResource(resource);
6838             master.display.Unlock();
6839          }
6840          */
6841       }
6842    }
6843
6844    void RemoveResource(Resource resource)
6845    {
6846       if(resource)
6847       {
6848          ResPtr ptr;
6849          for(ptr = resources.first; ptr; ptr = ptr.next)
6850          {
6851             if(ptr.resource == resource)
6852                break;
6853          }
6854
6855          if(ptr)
6856          {
6857             // Unload Graphics here if window is created already
6858             if(/*created && */display)
6859             {
6860                if(ptr.loaded)
6861                {
6862                   display.Lock(false);
6863                   display.displaySystem.UnloadResource(resource, ptr.loaded);
6864                   display.Unlock();
6865                   ptr.loaded = null;
6866                }
6867             }
6868             delete resource;
6869             resources.Delete(ptr);
6870          }
6871       }
6872    }
6873
6874    void SetCaret(int x, int y, int size)
6875    {
6876       if(!destroyed)
6877       {
6878          caretPos.x = x;
6879          caretPos.y = y;
6880          caretSize = size;
6881          if(active && !style.interim)
6882          {
6883             if(visible || !guiApp.caretOwner)
6884                guiApp.caretOwner = size ? this : null;
6885             if(size)
6886                UpdateCaret(false, false);
6887             else
6888             {
6889                guiApp.interfaceDriver.SetCaret(0,0,0);
6890                UpdateCaret(false, true);
6891                guiApp.caretEnabled = false;
6892             }
6893          }
6894          else if(style.inactive && active)
6895          {
6896             guiApp.interfaceDriver.SetCaret(0,0,0);
6897             UpdateCaret(false, true);
6898             guiApp.caretEnabled = false;
6899          }
6900       }
6901    }
6902
6903    void Scroll(int x, int y)
6904    {
6905       bool opaque = !style.drawBehind || background.a;
6906       if(opaque && display && display.flags.scrolling)
6907       {
6908          Box box = clientArea;
6909          box.left += clientStart.x;
6910          box.top += clientStart.y;
6911          box.right += clientStart.x;
6912          box.bottom += clientStart.y;
6913
6914          //scrollExtent.Free(null);
6915          scrollExtent.AddBox(box);
6916          scrolledArea.x += x;
6917          scrolledArea.y += y;
6918
6919          //scrollExtent.Free();
6920          //scrollExtent.AddBox(clientArea);
6921          //scrollExtent.Offset(clientStart.x, clientStart.y);
6922          //scrolledArea.x = x;
6923          //scrolledArea.y = y;
6924       }
6925       else
6926          Update(clientArea);
6927
6928       if(rootWindow)
6929          rootWindow.dirty = true;
6930    }
6931
6932    void ReleaseCapture()
6933    {
6934       if(guiApp && guiApp.windowCaptured && guiApp.windowCaptured == this)
6935       {
6936          Window oldCaptured = guiApp.windowCaptured;
6937          guiApp.windowCaptured = null;
6938          guiApp.prevWindow = null;
6939          incref oldCaptured;
6940
6941          //guiApp.Log("Released Capture\n");
6942
6943          guiApp.interfaceDriver.SetMouseCapture(null);
6944
6945          //oldCaptured.OnMouseCaptureLost();
6946
6947          if(oldCaptured)
6948             oldCaptured.ConsequentialMouseMove(false);
6949          delete oldCaptured;
6950       }
6951    }
6952
6953    void SetText(char * format, ...)
6954    {
6955       if(this)
6956       {
6957          delete caption;
6958          if(format)
6959          {
6960             char caption[MAX_F_STRING];
6961             va_list args;
6962             va_start(args, format);
6963             vsprintf(caption, format, args);
6964             va_end(args);
6965
6966             this.caption = new char[strlen(caption)+1];
6967             if(this.caption)
6968                strcpy(this.caption, caption);
6969          }
6970          if(created)
6971             UpdateCaption();
6972
6973          firewatchers text;
6974       }
6975    }
6976
6977    bool Grab(Bitmap bitmap, Box box, bool decorations)
6978    {
6979       bool result = false;
6980       if(display || this == guiApp.desktop)
6981       {
6982          Box clip = {MININT, MININT, MAXINT, MAXINT};
6983
6984          if(box != null)
6985             clip = box;
6986
6987          if(!decorations)
6988             clip.Clip(clientArea);
6989          else
6990             clip.Clip(this.box);
6991
6992          if(rootWindow != this)
6993          {
6994             clip.left   += absPosition.y;
6995             clip.top    += absPosition.y;
6996             clip.right  += absPosition.x;
6997             clip.bottom += absPosition.y;
6998          }
6999
7000          clip.left += decorations ? 0 : clientStart.x;
7001          clip.top += decorations ? 0 : clientStart.y;
7002          clip.right += decorations ? 0 : clientStart.x;
7003          clip.bottom += decorations ? 0 : clientStart.y;
7004
7005          if(display && display.flags.flipping)
7006          {
7007             rootWindow.Update(null);
7008             rootWindow.UpdateDisplay();
7009          }
7010
7011          if(!display)
7012          {
7013             Window window { };
7014             window.Create();
7015             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top, 
7016                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7017             delete window;
7018          }
7019          else
7020             result = display.Grab(bitmap, clip.left, clip.top, 
7021                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7022
7023          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
7024          {
7025             if(!bitmap.Convert(null, pixelFormat888, null))
7026                result = false;
7027          }
7028       }
7029       return result;
7030    }
7031
7032    void GetMousePosition(int * x, int * y)
7033    {
7034       int mouseX = 0, mouseY = 0;
7035       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
7036       {
7037          if(guiApp.driver)
7038             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
7039          if(this != guiApp.desktop)
7040          {
7041             mouseX -= absPosition.x + clientStart.x;
7042             mouseY -= absPosition.y + clientStart.y;
7043          }
7044       }
7045       if(x) *x = mouseX;
7046       if(y) *y = mouseY;
7047    }
7048
7049    DialogResult DoModal()
7050    {
7051       DialogResult returnCode = 0;
7052       int terminated = terminateX;
7053       isModal = true;
7054       incref this;
7055       while(!destroyed && guiApp.driver != null)
7056       {
7057          if(terminateX != terminated)
7058          {
7059             terminated = terminateX;
7060             guiApp.desktop.Destroy(0);
7061             if(guiApp.desktop.created)
7062             {
7063                terminated = 0;
7064                //printf("Resetting terminate X to 0\n");
7065                terminateX = 0;
7066             }
7067             break;
7068          }
7069
7070          guiApp.UpdateDisplay();
7071          if(!guiApp.ProcessInput(false))
7072             guiApp.Wait();
7073       }
7074       returnCode = this.returnCode;
7075       delete this;
7076       return returnCode;
7077    }
7078
7079    void DoModalStart()
7080    {
7081       isModal = true;
7082       incref this;
7083    }
7084
7085    bool DoModalLoop()
7086    {
7087       return !destroyed && guiApp.driver != null && terminateX < 2;
7088    }
7089
7090    DialogResult DoModalEnd()
7091    {
7092       DialogResult returnCode = this.returnCode;
7093       delete this;
7094       return returnCode;
7095    }
7096
7097    // --- Window manipulation ---
7098    /*bool GetDisabled()
7099    {
7100       bool disabled = this.disabled;
7101       Window window;
7102       for(window = this; (window = window.master); )
7103       {
7104          if(window.disabled)
7105          {
7106             disabled = true;
7107             break;
7108          }
7109       }
7110       return disabled;
7111    }*/
7112
7113    // --- Mouse Manipulation ---
7114    void GetNCMousePosition(int * x, int * y)
7115    {
7116       GetMousePosition(x, y);
7117       if(x) *x += clientStart.x;
7118       if(y) *y += clientStart.y;
7119    }
7120
7121    // --- Carets manipulation ---
7122    void GetCaretPosition(Point caretPos)
7123    {
7124       caretPos = this.caretPos;
7125    }
7126
7127    int GetCaretSize(void)
7128    {
7129       return caretSize;
7130    }
7131
7132    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
7133    {
7134       Destroy(button.id);
7135       return true;
7136    }
7137
7138    bool CloseConfirmation(bool parentClosing)
7139    {
7140       bool result = true;
7141       OldLink slave;
7142       Window child;
7143
7144       if(closing)
7145          return false;
7146       if(terminateX > 1)
7147          return true;
7148          
7149       closing = true;
7150
7151       if(!OnClose(parentClosing))
7152          result = false;
7153
7154       // If you want to skip this, simply set modifiedDocument to false in OnClose
7155       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7156       {
7157          DialogResult dialogRes;
7158          char message[1024];
7159          if(fileName)
7160             sprintf(message, $"Save changes to %s?", fileName);
7161          else
7162             sprintf(message, $"Save changes to Untitled %d?", documentID);
7163
7164          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption ? parent.caption : rootWindow.caption, contents = message }.Modal();
7165
7166          if(dialogRes == yes)
7167          {
7168             // TOFIX: Precomp error if brackets are taken out
7169             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7170          }
7171          else if(dialogRes == cancel)
7172             result = false;
7173       }
7174
7175       if(result)
7176       {
7177          for(slave = slaves.first; slave; slave = slave.next)
7178          {
7179             Window w = slave.data;
7180             if((w.parent == this || !w.IsDescendantOf(this)) && !w.CloseConfirmation(true))
7181             {
7182                // ((Window)slave.data).CloseConfirmation(true);
7183                result = false;
7184                break;
7185             }
7186          }
7187       }
7188
7189       if(result)
7190       {
7191          for(child = children.first; child; child = child.next)
7192             if(child.master != this && !child.CloseConfirmation(true))
7193             {
7194                result = false;
7195                break;
7196             }
7197       }
7198       closing = false;
7199       return result;
7200    }
7201
7202    // Static methods... move them somewhere else?
7203    void ::RestoreCaret()
7204    {
7205       if(guiApp.caretOwner)
7206          guiApp.caretOwner.UpdateCaret(false, false);
7207    }
7208
7209    void ::FreeMouseRange()
7210    {
7211       guiApp.interfaceDriver.SetMouseRange(null, null);
7212    }
7213
7214    // Menu Methods
7215    bool MenuFileClose(MenuItem selection, Modifiers mods)
7216    {
7217       Window document = activeChild;
7218       if(document)
7219          document.Destroy(0);
7220       return true;
7221    }
7222
7223    bool MenuFileExit(MenuItem selection, Modifiers mods)
7224    {
7225       Destroy(0);
7226       return true;
7227    }
7228
7229    bool MenuFileSave(MenuItem selection, Modifiers mods)
7230    {
7231       if(fileName)
7232       {
7233          fileMonitor.fileName = null;
7234          saving = true;
7235
7236          if(OnSaveFile(fileName))
7237          {
7238             //if(OnFileModified != Window::OnFileModified)
7239             {
7240                saving = false;
7241                fileMonitor.fileName = fileName;
7242             }
7243             return true;
7244          }
7245          else
7246          {
7247             MessageBox dialog { master = master, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7248             DialogResult answer = dialog.Modal();
7249             saving = false;
7250             if(answer != yes) return (bool)answer;
7251          }
7252       }
7253       return MenuFileSaveAs(selection, mods);
7254    }
7255
7256    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7257    {
7258       DialogResult result = (DialogResult)bool::true;
7259       FileDialog fileDialog = saveDialog;
7260
7261       if(!fileDialog)
7262          fileDialog = FileDialog {};
7263       if(fileDialog)
7264       {
7265          incref fileDialog;
7266          if(fileName)
7267             fileDialog.filePath = fileName;
7268          else
7269          {
7270             char filePath[MAX_FILENAME];
7271             sprintf(filePath, "Untitled %d", documentID);
7272             fileDialog.filePath = filePath;
7273          }
7274          fileMonitor.fileName = null;
7275
7276          fileDialog.type = save;
7277          fileDialog.text = $"Save As";
7278
7279          while(true)
7280          {
7281             fileDialog.master = master.parent ? master : this;
7282             if(fileDialog.Modal() == ok)
7283             {
7284                char * filePath = fileDialog.filePath;
7285                saving = true;
7286                if(OnSaveFile(filePath))
7287                {
7288                   saving = false;
7289                   property::fileName = filePath;
7290                   NotifySaved(master, this, filePath);
7291                   break;
7292                }
7293                else
7294                {
7295                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7296                   DialogResult answer = dialog.Modal();
7297                   saving = false;
7298                   if(answer != yes) 
7299                   {
7300                      result = answer;
7301                      break;
7302                   }
7303                }
7304             }
7305             else
7306             {
7307                result = cancel;
7308                break;
7309             }
7310          }
7311          //if(OnFileModified != Window::OnFileModified && fileName)
7312          {
7313             if(fileName)
7314                fileMonitor.fileName = fileName;
7315          }
7316          delete fileDialog;
7317       }
7318       return (bool)result; // Actually returning result from Yes/NoCancel message box
7319    }
7320
7321    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7322    {
7323       Window document = activeChild;
7324       Window next;
7325       for(document = children.first; document; document = next)
7326       {
7327          next = document.next;
7328          if(document.style.isDocument || document.fileName)
7329             document.MenuFileSave(selection, mods);
7330       }
7331       return true;
7332    }
7333
7334    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7335    {
7336       Window document;
7337
7338       for(document = children.first; document; document = document.next)
7339          //if(document.style.isDocument && document.state == minimized)
7340          if(document.style.isActiveClient && document.state == minimized)
7341             document.SetState(minimized, false, mods);
7342       return true;
7343    }
7344
7345    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7346    {
7347       Window document = activeChild;
7348       if(document)
7349       {
7350          Window firstDocument = null;
7351          Window child;
7352          OldLink cycle = document.cycle.prev;
7353          int id = 0;
7354          while(true)
7355          {
7356             child = cycle.data;
7357             if(child.style.isActiveClient && !child.style.hidden)
7358             {
7359                Window last;
7360
7361                firstDocument = child;
7362                if(child.state == minimized)
7363                   child.SetState(minimized, false, mods);
7364                else
7365                {
7366                   child.positionID = id++;
7367                   child.SetState(normal, false, mods);
7368                   child.anchor.left.type = cascade;
7369                   {
7370                      int x, y, w, h;
7371                      child.normalSizeAnchor = *&child.sizeAnchor;
7372                      child.normalAnchor = child.anchor;
7373
7374                      // Break the anchors for moveable/resizable windows
7375                      if(child.style.fixed)
7376                      {
7377                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7378
7379                         (*&child.normalAnchor).left = x;
7380                         (*&child.normalAnchor).top = y;
7381                         (*&child.normalAnchor).right.type = none;
7382                         (*&child.normalAnchor).bottom.type = none;
7383
7384                         child.normalSizeAnchor.isClientW = false;
7385                         child.normalSizeAnchor.isClientH = false;
7386                         child.normalSizeAnchor.size.w = w;
7387                         child.normalSizeAnchor.size.h = h;
7388                         child.anchored = false;
7389                      }
7390
7391                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7392                      {
7393                         child.stateAnchor = child.normalAnchor;
7394                         child.stateSizeAnchor = child.normalSizeAnchor;
7395
7396                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7397                         child.Position(x, y, w, h, true, true, true, true, false, false);
7398                      }
7399                   }
7400                }
7401
7402                last = children.last;
7403                if(!child.style.stayOnTop)
7404                   for(; last && last.style.stayOnTop; last = last.prev);
7405                children.Move(child, last);
7406                childrenOrder.Move(child.order, childrenOrder.last);
7407             }
7408             if(cycle == document.cycle) break;
7409             cycle = cycle.prev;
7410          }
7411          if(firstDocument)
7412             firstDocument.Activate();
7413       }
7414       return true;
7415    }
7416
7417    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7418    {
7419       if(style.hasClose)
7420          Destroy(0);
7421       return true;
7422    }
7423
7424    // Close all closes all active clients, not all documents
7425    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7426    {
7427       Window next, document;
7428
7429       for(document = children.first; document; document = next)
7430       {
7431          for(next = document.next; next && !(next.style.isActiveClient; next = next.next);
7432          if(document.style.isActiveClient)
7433             if(!document.Destroy(0) && !document.style.hidden)
7434                return false;
7435       }
7436       return true;
7437    }
7438
7439    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7440    {
7441       if(style.hasMaximize && state != maximized)
7442          SetState(maximized, 0, 0);
7443       return true;
7444    }
7445
7446    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7447    {
7448       if(style.hasMinimize && state != minimized)
7449       {
7450          SetState(minimized, 0, 0);
7451          parent.CycleChildren(false, true, false, true);
7452       }
7453       return true;
7454    }
7455
7456    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7457    {
7458       MenuMoveOrSize(false, selection ? true : false);
7459       return true;
7460    }
7461
7462    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7463    {
7464       CycleChildren(false, true, false, true);
7465       return true;
7466    }
7467
7468    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7469    {
7470       CycleChildren(true, true, false, true);
7471       return true;
7472    }
7473
7474    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7475    {
7476       MenuMoveOrSize(true, true);
7477       return true;
7478    }
7479
7480    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7481    {
7482       if(state != normal)
7483          SetState(normal, 0, 0);
7484       return true;
7485    }
7486
7487    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7488    {
7489       Window document;
7490       int id = selection.id;
7491       OldLink cycle = activeClient.cycle;
7492       int c = 0;
7493       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7494       while(true)
7495       {
7496          Window sibling = cycle.data;
7497          if(sibling.style.isActiveClient && sibling.visible && !sibling.style.nonClient)
7498          {
7499             if(c == id)
7500                break;
7501             c++;
7502          }
7503          cycle = cycle.next;
7504       }
7505       document = cycle.data;
7506       document.Activate();
7507       
7508       //if(activeChild.state == maximized)
7509       //  document.SetState(maximized, false, mods);
7510       //else if(document.state == minimized)
7511       //   document.SetState(normal, false, mods);
7512       return true;
7513    }
7514
7515    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7516    {
7517       stayOnTop = !style.stayOnTop;
7518       return true;
7519    }
7520
7521    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7522    {
7523       Window document = activeChild;
7524       if(document)
7525       {
7526          Window firstDocument = null;
7527          OldLink cycle = document.cycle;
7528          int id = 0;
7529          while(true)
7530          {
7531             Window child = cycle.data;
7532             if(child.style.isActiveClient && !child.style.hidden)
7533             {
7534                if(!firstDocument) firstDocument = child;
7535                if(child.state == minimized)
7536                   child.SetState(minimized, false, mods);
7537                else
7538                {
7539                   child.positionID = id++;
7540                   child.SetState(normal, false, mods);
7541                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7542
7543                   child.anchor.left.type = hTiled;
7544                   {
7545                      int x, y, w, h;
7546                      child.normalSizeAnchor = *&child.sizeAnchor;
7547                      child.normalAnchor = child.anchor;
7548
7549                      // Break the anchors for moveable/resizable windows
7550                      if(child.style.fixed)
7551                      {
7552                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7553
7554                         (*&child.normalAnchor).left = x;
7555                         (*&child.normalAnchor).top = y;
7556                         (*&child.normalAnchor).right.type = none;
7557                         (*&child.normalAnchor).bottom.type = none;
7558                         child.normalSizeAnchor.isClientW = false;
7559                         child.normalSizeAnchor.isClientH = false;
7560                         child.normalSizeAnchor.size.w = w;
7561                         child.normalSizeAnchor.size.h = h;
7562                         child.anchored = false;
7563                      }
7564
7565                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7566                      {
7567                         child.stateAnchor = child.normalAnchor;
7568                         child.stateSizeAnchor = child.normalSizeAnchor;
7569
7570                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7571                         child.Position(x,y, w, h, true, true, true, true, false, true);
7572                      }
7573                   }
7574                }
7575             }
7576             if((cycle = cycle.next) == document.cycle) break;
7577          }
7578          if(firstDocument)
7579             firstDocument.Activate();
7580       }
7581       return true;
7582    }
7583
7584    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
7585    {
7586       Window document = activeChild;
7587       if(document)
7588       {
7589          Window firstDocument = null;
7590          Window child;
7591          OldLink cycle = document.cycle;
7592          int id = 0;
7593          while(true)
7594          {
7595             child = cycle.data;
7596             //if(child.style.isDocument)
7597             if(child.style.isActiveClient && !child.style.hidden)
7598             {
7599                if(!firstDocument) firstDocument = child;
7600                if(child.state == minimized)
7601                   child.SetState(minimized, false, mods);
7602                else
7603                {
7604                   child.positionID = id++;
7605                   child.SetState(normal, false, mods);
7606                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7607
7608                   child.anchor.left.type = vTiled;
7609                   {
7610                      int x, y, w, h;
7611                      child.normalSizeAnchor = *&child.sizeAnchor;
7612                      child.normalAnchor = child.anchor;
7613
7614                      // Break the anchors for moveable/resizable windows
7615                      if(child.style.fixed)
7616                      {
7617                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7618
7619                         (*&child.normalAnchor).left = x;
7620                         (*&child.normalAnchor).top = y;
7621                         (*&child.normalAnchor).right.type = none;
7622                         (*&child.normalAnchor).bottom.type = none;
7623                         child.normalSizeAnchor.isClientW = false;
7624                         child.normalSizeAnchor.isClientH = false;
7625                         child.normalSizeAnchor.size.w = w;
7626                         child.normalSizeAnchor.size.h = h;
7627                         child.anchored = false;
7628                      }
7629
7630                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7631                      {
7632                         child.stateAnchor = child.normalAnchor;
7633                         child.stateSizeAnchor = child.normalSizeAnchor;
7634
7635                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7636                         child.Position(x,y, w, h, true, true, true, true, false, true);
7637                      }
7638                   }
7639                }
7640             }
7641             if((cycle = cycle.next) == document.cycle) break;
7642          }
7643          if(firstDocument)
7644             firstDocument.Activate();
7645       }
7646       return true;
7647    }
7648
7649    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
7650    {
7651       WindowList dialog { master = this };
7652       Window document = (Window)dialog.Modal();
7653       if(document)
7654       {
7655          if(activeChild.state == maximized)
7656             document.SetState(maximized, false, mods);
7657          else if(document.state == minimized)
7658             document.SetState(normal, false, mods);
7659          document.Activate();
7660       }
7661       return true;
7662    }
7663
7664    // Virtual Methods
7665    virtual bool OnCreate(void);
7666    virtual void OnDestroy(void);
7667    virtual void OnDestroyed(void);
7668    virtual bool OnClose(bool parentClosing);
7669    virtual bool OnStateChange(WindowState state, Modifiers mods);
7670    virtual bool OnPostCreate(void);
7671    virtual bool OnMoving(int *x, int *y, int w, int h);
7672    virtual bool OnResizing(int *width, int *height);
7673    virtual void OnResize(int width, int height);
7674    virtual void OnPosition(int x, int y, int width, int height);
7675    virtual bool OnLoadGraphics(void);
7676    virtual void OnApplyGraphics(void);
7677    virtual void OnUnloadGraphics(void);
7678    virtual void OnRedraw(Surface surface);
7679    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
7680    virtual void OnActivateClient(Window client, Window previous);
7681    virtual bool OnKeyDown(Key key, unichar ch);
7682    virtual bool OnKeyUp(Key key, unichar ch);
7683    virtual bool OnKeyHit(Key key, unichar ch);
7684    virtual bool OnSysKeyDown(Key key, unichar ch);
7685    virtual bool OnSysKeyUp(Key key, unichar ch);
7686    virtual bool OnSysKeyHit(Key key, unichar ch);
7687    virtual bool OnMouseOver(int x, int y, Modifiers mods);
7688    virtual bool OnMouseLeave(Modifiers mods);
7689    virtual bool OnMouseMove(int x, int y, Modifiers mods);
7690    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
7691    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
7692    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
7693    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
7694    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
7695    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
7696    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
7697    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
7698    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
7699    virtual void OnMouseCaptureLost(void);
7700    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
7701    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
7702    virtual void OnDrawOverChildren(Surface surface);
7703    virtual bool OnFileModified(FileChange fileChange, char * param);
7704    virtual bool OnSaveFile(char * fileName);
7705
7706    // Virtual Methods -- Children management (To support Stacker, for lack of built-in auto-layout)
7707    // Note: A 'client' would refer to isActiveClient, rather than
7708    // being confined to the 'client area' (nonClient == false)
7709    virtual void OnChildAddedOrRemoved(Window child, bool removed);
7710    virtual void OnChildVisibilityToggled(Window child, bool visible);
7711    virtual void OnChildResized(Window child, int x, int y, int w, int h);
7712
7713    // Skins Virtual Functions
7714    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
7715    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
7716    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
7717    {
7718       *cw = *w;
7719       *ch = *h;      
7720    }
7721    virtual void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7722    virtual void PreShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7723    virtual bool IsMouseMoving(int x, int y, int w, int h);
7724    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY);
7725    virtual void UpdateNonClient();
7726    virtual void SetBox(Box box);
7727    virtual bool IsInside(int x, int y)
7728    {
7729       return box.IsPointInside({x, y});
7730    }
7731    virtual bool IsOpaque()
7732    {
7733       return (!style.drawBehind || background.a == 255);
7734    }
7735
7736    // Notifications
7737    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
7738    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
7739    virtual void Window::NotifySaved(Window window, char * filePath);
7740
7741    // Public Methods
7742
7743    // Properties
7744    property Window parent
7745    {
7746       property_category $"Layout"
7747       set
7748       {
7749          if(value || guiApp.desktop)
7750          {
7751             Window last;
7752             Window oldParent = parent;
7753             Anchor anchor = this.anchor;
7754
7755             if(value && value.IsDescendantOf(this)) return;
7756             if(value && value == this)
7757                return;
7758             if(!value) value = guiApp.desktop;
7759
7760             if(value == oldParent) return;
7761
7762             if(!master || (master == this.parent && master == guiApp.desktop))
7763                property::master = value;
7764             
7765             if(parent)
7766             {
7767                parent.children.Remove(this);
7768
7769                parent.Update(
7770                {
7771                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7772                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
7773                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7774                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
7775                });
7776             }
7777
7778             last = value.children.last;
7779
7780             if(style.isDocument)
7781             {
7782                if(parent)
7783                   parent.numDocuments--;
7784                documentID = value.GetDocumentID();
7785             }
7786
7787             if(style.isActiveClient && !style.hidden)
7788             {
7789                if(parent && parent != guiApp.desktop && !(style.hidden))
7790                {
7791                   if(state == minimized) parent.numIcons--;
7792                   parent.numPositions--;
7793                }
7794             }
7795
7796             if(!style.stayOnTop)
7797                for(; last && last.style.stayOnTop; last = last.prev);
7798
7799             value.children.Insert(last, this);
7800
7801             // *** NEW HERE: ***
7802             if(cycle)
7803                parent.childrenCycle.Delete(cycle);
7804             if(order)
7805                parent.childrenOrder.Delete(order);
7806             cycle = null;
7807             order = null;
7808             // *** TODO: Added this here to solve crash on setting parent to null before destroying/destructing ***
7809             //           Should something else be done?
7810             if(parent && parent.activeChild == this)
7811                parent.activeChild = null;
7812             if(parent && parent.activeClient == this)
7813                parent.activeClient = null;
7814
7815             //if(created)
7816             {
7817                if(created)
7818                {
7819                   int x = position.x, y = position.y, w = size.w, h = size.h;
7820                   
7821                   int vpw, vph;
7822
7823                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
7824                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
7825                   
7826                   vpw = value.clientSize.w;
7827                   vph = value.clientSize.h;
7828                   if(style.nonClient)
7829                   {
7830                      vpw = value.size.w;
7831                      vph = value.size.h;
7832                   }
7833                   else if(style.fixed)
7834                   {
7835                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
7836                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
7837                   }
7838
7839                   anchor = this.anchor;
7840
7841                   if(anchor.left.type == offset)            anchor.left.distance = x;
7842                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
7843                   if(anchor.top.type == offset)             anchor.top.distance = y;
7844                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
7845                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
7846                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
7847                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
7848                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
7849                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
7850                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
7851
7852                   if(!anchor.left.type && !anchor.right.type)
7853                   {
7854                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
7855                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
7856                   }
7857                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
7858                   if(!anchor.top.type && !anchor.bottom.type)
7859                   {
7860                      anchor.vert.distance = (y + h / 2) - (vph / 2);
7861                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
7862                   }
7863                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
7864                }
7865                parent = value;
7866                parent.OnChildAddedOrRemoved(this, false);
7867
7868                // *** NEW HERE ***
7869                if(!style.inactive)
7870                {
7871                   if(!style.noCycle)
7872                      parent.childrenCycle.Insert(
7873                         (parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
7874                         cycle = OldLink { data = this });
7875                   parent.childrenOrder.Insert(
7876                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last, 
7877                      order = OldLink { data = this });
7878                }
7879
7880                if(!style.hidden && style.isActiveClient)
7881                {
7882                   positionID = parent.GetPositionID(this);
7883                   parent.numPositions++;
7884                   if(state == minimized) parent.numIcons--;
7885                }
7886
7887                // *** FONT INHERITANCE ***
7888                if(!setFont && oldParent) 
7889                   stopwatching(oldParent, font);
7890
7891                if(systemFont)
7892                {
7893                   RemoveResource(systemFont);
7894                   delete systemFont;
7895                }
7896                // TESTING WITH WATCHERS:
7897                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7898                // usedFont = setFont ? setFont : (systemFont);
7899
7900                if(!usedFont)
7901                {
7902                   if(guiApp.currentSkin)
7903                   {
7904                      systemFont = guiApp.currentSkin.SystemFont();
7905                      incref systemFont;
7906                   }
7907                   usedFont = systemFont;
7908                   AddResource(systemFont);
7909                }
7910
7911                if(!setFont)
7912                   watch(value)
7913                   {
7914                      font
7915                      {
7916                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7917                         firewatchers font;
7918                         Update(null);
7919                      }
7920                   };
7921                
7922                firewatchers font;
7923
7924
7925                if(value.rootWindow && value.rootWindow.display && rootWindow)
7926                {
7927                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) || 
7928                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
7929                   
7930                   if(reloadGraphics)
7931                      UnloadGraphics(false);
7932                   SetupDisplay();
7933                   if(reloadGraphics)
7934                      LoadGraphics(false, false);
7935                      
7936                   /*
7937                   if(value.rootWindow != rootWindow)
7938                      DisplayModeChanged();
7939                   else
7940                   */
7941                }
7942                scrolledPos.x = MININT; // Prevent parent update
7943                {
7944                   bool anchored = this.anchored;
7945                   property::anchor = anchor;
7946                   this.anchored = anchored;
7947                }
7948                /*
7949                {
7950                   int x, y, w, h;
7951                   if(guiApp.currentSkin)
7952                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
7953
7954                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
7955                   Position(x, y, w, h, true, true, true, true, false, true);
7956                }
7957                */
7958
7959             }
7960             // else parent = value;
7961             if(oldParent)
7962                oldParent.OnChildAddedOrRemoved(this, true);
7963          }
7964       }
7965       get { return parent; }
7966    };
7967
7968    property Window master
7969    {
7970       property_category $"Behavior"
7971       set
7972       {
7973          //if(this == value) return;
7974          if(value && value.IsSlaveOf(this)) return;
7975
7976          if(master != value)
7977          {
7978             if(master)
7979             {
7980                OldLink slaveHolder;
7981                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
7982                   if(slaveHolder.data == this)
7983                   {
7984                      master.slaves.Delete(slaveHolder);
7985                      break;
7986                   }
7987             }
7988
7989             if(value)
7990             {
7991                value.slaves.Add(OldLink { data = this });
7992
7993                if(hotKey)
7994                {
7995                   if(master)
7996                      master.hotKeys.Remove(hotKey);
7997                   value.hotKeys.Add(hotKey);
7998                   hotKey = null;
7999                }
8000                if(master && master.defaultControl == this)
8001                   master.defaultControl = null;
8002
8003                if(style.isDefault && !value.defaultControl)
8004                   value.defaultControl = this;
8005             }
8006          }
8007          master = value;
8008       }
8009       get { return master ? master : parent; }
8010    };
8011
8012    property char * caption
8013    {
8014       property_category $"Appearance"
8015       watchable
8016       set
8017       {
8018          delete caption;
8019          if(value)
8020          {
8021             caption = new char[strlen(value)+1];
8022             if(caption)
8023                strcpy(caption, value);
8024          }
8025          if(created)
8026             UpdateCaption();
8027       }
8028       get { return caption; }
8029    };
8030
8031    property Key hotKey
8032    {
8033       property_category $"Behavior"
8034       set
8035       {
8036          setHotKey = value;
8037          if(created)
8038          {
8039             if(value)
8040             {
8041                if(!hotKey)
8042                   master.hotKeys.Add(hotKey = HotKeySlot { });
8043                if(hotKey)
8044                {
8045                   hotKey.key = value;
8046                   hotKey.window = this;
8047                }
8048             }
8049             else if(hotKey)
8050             {
8051                master.hotKeys.Delete(hotKey);
8052                hotKey = null;
8053             }
8054          }
8055       }
8056       get { return hotKey ? hotKey.key : 0; }
8057    };
8058
8059    property Color background
8060    {
8061       property_category $"Appearance"
8062       set
8063       {
8064          background.color = value;
8065          firewatchers;
8066          if(created)
8067          {
8068             Update(null);
8069             if(this == rootWindow)
8070                guiApp.interfaceDriver.SetRootWindowColor(this);
8071          }
8072       }
8073       get { return background.color; }
8074    };
8075
8076    property Percentage opacity
8077    {
8078       property_category $"Appearance"
8079       set
8080       {
8081          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
8082          drawBehind = (background.a == 255) ? false : true;
8083       }
8084       get { return background.a / 255.0f; }
8085    };
8086
8087    property Color foreground
8088    {
8089       property_category $"Appearance"
8090       set
8091       {
8092          foreground = value;
8093          firewatchers;
8094          if(created)
8095             Update(null);
8096       }
8097       get { return foreground; }
8098    };
8099
8100    property BorderStyle borderStyle
8101    {
8102       property_category $"Appearance"
8103       set
8104       {
8105          if(!((BorderBits)value).fixed)
8106          {
8107             style.hasClose = false;
8108             style.hasMaximize = false;
8109             style.hasMinimize = false;
8110             nativeDecorations = false;
8111          }
8112          style.borderBits = value;
8113          if(created)
8114          {
8115             int x, y, w, h;
8116             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8117
8118             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8119             Position(x, y, w, h, true, true, true, true, false, true);
8120             CreateSystemChildren();
8121          }
8122       }
8123       get { return (BorderStyle)style.borderBits; } 
8124    };
8125
8126    property Size minClientSize
8127    {
8128       property_category $"Layout"
8129       set { minSize = value; }
8130       get { value = minSize; }
8131    };
8132
8133    property Size maxClientSize
8134    {
8135       property_category $"Layout"
8136       set { maxSize = value; }
8137       get { value = maxSize; }
8138    };
8139
8140    property bool hasMaximize
8141    {
8142       property_category $"Window Style"
8143       set
8144       {
8145          style.hasMaximize = value;
8146          if(value) { style.fixed = true; style.contour = true; }
8147          if(created)
8148          {
8149             int x, y, w, h;
8150             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8151
8152             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8153             Position(x, y, w, h, true, true, true, true, false, true);
8154
8155             CreateSystemChildren();
8156          }
8157       }
8158       get { return style.hasMaximize; }
8159    };
8160
8161    property bool hasMinimize
8162    {
8163       property_category $"Window Style"
8164       set
8165       {
8166          style.hasMinimize = value;
8167          if(value) { style.fixed = true; style.contour = true; }
8168          if(created)
8169          {
8170             int x, y, w, h;
8171             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8172
8173             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8174             Position(x, y, w, h, true, true, true, true, false, true);
8175
8176             CreateSystemChildren();
8177          }
8178       }
8179       get { return style.hasMinimize;  }
8180    };
8181
8182    property bool hasClose
8183    {
8184       property_category $"Window Style"
8185       set
8186       {
8187          style.hasClose = value;
8188          if(value) { style.fixed = true; style.contour = true; }
8189          if(created)
8190          {
8191             int x, y, w, h;
8192             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8193             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8194             Position(x, y, w, h, true, true, true, true, false, true);
8195             CreateSystemChildren();
8196          }
8197       }
8198       get { return style.hasClose; }
8199    };
8200    
8201    property bool nonClient
8202    {
8203       property_category $"Layout"
8204       set
8205       {
8206          style.nonClient = value;
8207          if(value)
8208             style.stayOnTop = true;
8209       }
8210       get { return style.nonClient; }
8211    };
8212
8213    property bool inactive
8214    {
8215       property_category $"Behavior"
8216       set
8217       {
8218          if(value) 
8219          {
8220             // *** NEW HERE: ***
8221             if(!style.inactive)
8222             {
8223                if(cycle)
8224                   parent.childrenCycle.Delete(cycle);
8225                if(order)
8226                   parent.childrenOrder.Delete(order);
8227                cycle = null;
8228                order = null;
8229             }
8230
8231             if(created)
8232             {
8233                active = false; // true;
8234                if(parent.activeChild == this)
8235                   parent.activeChild = null;
8236                if(parent.activeClient == this)
8237                   parent.activeClient = null;
8238             }
8239          }
8240          else
8241          {
8242             if(style.inactive)
8243             {
8244                if(!style.noCycle)
8245                {
8246                   parent.childrenCycle.Insert(
8247                      (parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
8248                      cycle = OldLink { data = this });
8249                }
8250                parent.childrenOrder.Insert(
8251                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8252                   order = OldLink { data = this });
8253             }
8254          }
8255          style.inactive = value;
8256       }
8257       get { return style.inactive; }
8258    };
8259
8260    property bool clickThrough
8261    {
8262       property_category $"Behavior"
8263       set { style.clickThrough = value; }
8264       get { return style.clickThrough; }
8265    };
8266
8267    property bool isRemote
8268    {
8269       property_category $"Behavior"
8270       set { style.isRemote = value; }
8271       get { return style.isRemote; }
8272    };
8273
8274    property bool noCycle
8275    {
8276       property_category $"Behavior"
8277       set { style.noCycle = value; }
8278       get { return style.noCycle; }
8279    };
8280
8281    property bool isModal
8282    {
8283       property_category $"Behavior"
8284       set { style.modal = value; }
8285       get { return style.modal; }
8286    };
8287
8288    property bool interim
8289    {
8290       property_category $"Behavior"
8291       set { style.interim = value; }
8292       get { return style.interim; }
8293    };
8294
8295    property bool tabCycle
8296    {
8297       property_category $"Behavior"
8298       set { style.tabCycle = value; }
8299       get { return style.tabCycle; }
8300    };
8301      
8302    property bool isDefault
8303    {
8304       property_category $"Behavior"
8305       set
8306       {
8307          if(master)
8308          {
8309             if(value)
8310             {
8311                Window sibling;
8312                /*for(sibling = parent.children.first; sibling; sibling = sibling.next)
8313                   if(sibling != this && sibling.style.isDefault)
8314                      sibling.style.isDefault = false;*/
8315                if(master.defaultControl)
8316                   master.defaultControl.style.isDefault = false;
8317                master.defaultControl = this;
8318             }
8319             else if(master.defaultControl == this)
8320                master.defaultControl = null;
8321
8322             // Update(null);
8323          }
8324          style.isDefault = value;
8325          if(created)
8326             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8327       }
8328       get { return style.isDefault; }
8329    };
8330
8331    property bool drawBehind
8332    {
8333       property_category $"Window Style"
8334       set { style.drawBehind = value; }
8335       get { return style.drawBehind; }
8336    };
8337
8338    property bool hasMenuBar
8339    {
8340       property_category $"Window Style"
8341       set
8342       {
8343          if(value) 
8344          {
8345             if(!menu)
8346             {
8347                menu = Menu { };
8348                incref menu;
8349             }
8350             if(created && !menuBar)
8351             {
8352                menuBar =
8353                   PopupMenu 
8354                   {
8355                      this, menu = menu,
8356                      isMenuBar = true,
8357                      anchor = Anchor { top = 23, left = 1, right = 1 },
8358                      size.h = 24,
8359                      inactive = true, nonClient = true                            
8360                   };
8361                menuBar.Create();
8362             }
8363          }
8364          else if(created && menuBar)
8365          {
8366             menuBar.Destroy(0);
8367             menuBar = null;
8368          }
8369          style.hasMenuBar = value;
8370       }
8371       get { return style.hasMenuBar; }
8372    };
8373
8374    property bool hasStatusBar
8375    {
8376       property_category $"Window Style"
8377       set
8378       {
8379          if(value)
8380          {
8381             if(!statusBar)
8382             {
8383                statusBar = StatusBar { this };
8384                incref statusBar;
8385                if(created)
8386                   statusBar.Create();
8387             }
8388          }
8389          else if(statusBar)
8390             delete statusBar;
8391          style.hasStatusBar = value;
8392       }
8393       get { return style.hasStatusBar; }
8394    };
8395    property bool stayOnTop
8396    {
8397       property_category $"Window Style"
8398       set
8399       {
8400          if(value)
8401          {
8402             if(created && !style.stayOnTop)
8403             {
8404                if(rootWindow == this)
8405                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8406                else if(parent.children.last != this)
8407                {
8408                   parent.children.Move(this, parent.children.last);
8409                   Update(null);
8410                }
8411             }
8412             style.stayOnTop = true;
8413          }
8414          else
8415          {
8416             if(created && style.stayOnTop)
8417             {
8418                if(rootWindow == this)
8419                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8420                else
8421                {
8422                   Window last;
8423                   if(order)
8424                   {
8425                      OldLink order;
8426                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev; 
8427                          order && ((Window)order.data).style.stayOnTop;
8428                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8429                       last = order ? order.data : null;
8430                   }
8431                   else
8432                   {
8433                      for(last = parent.children.last; 
8434                          last && last.style.stayOnTop;
8435                          last = last.prev);
8436                   }
8437
8438                   parent.children.Move(this, last);
8439                   Update(null);
8440                }
8441             }
8442             style.stayOnTop = false;
8443          }
8444       }
8445       get { return style.stayOnTop; }
8446    };
8447
8448    property Menu menu
8449    {
8450       property_category $"Window Style"
8451       set
8452       {
8453          delete menu;
8454          if(value)
8455          {
8456             menu = value;
8457             incref menu;
8458          }
8459
8460          if(menuBar && !value)
8461          {
8462             menuBar.Destroy(0);
8463             menuBar = null;
8464          }
8465          if(created)
8466          {
8467             if(!menuBar && style.hasMenuBar && value)
8468             {
8469                menuBar = PopupMenu
8470                          { 
8471                             this, menu = value, isMenuBar = true, 
8472                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24, 
8473                             inactive = true, nonClient = true
8474                          };
8475                 menuBar.Create();
8476             }
8477             UpdateActiveDocument(null);
8478          }
8479       }
8480       get { return menu; }
8481    };
8482
8483    property FontResource font
8484    {
8485       property_category $"Appearance"
8486       watchable
8487       isset { return setFont ? true : false; }
8488       set
8489       {
8490          if(this)
8491          {
8492             if(value && !setFont) { stopwatching(parent, font); }
8493             else if(!value && setFont)
8494             {
8495                watch(parent)
8496                {
8497                   font
8498                   {
8499                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8500                      firewatchers font;
8501                      Update(null);
8502                   }
8503                };
8504             }
8505
8506             if(setFont)
8507             {
8508                RemoveResource(setFont);
8509                delete setFont;
8510             }
8511             if(systemFont)
8512             {
8513                RemoveResource(systemFont);
8514                delete systemFont;
8515             }
8516             setFont = value;
8517             if(setFont)
8518             {
8519                incref setFont;
8520                AddResource(setFont);
8521             }
8522
8523             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8524             if(!usedFont)
8525             {
8526                systemFont = guiApp.currentSkin.SystemFont();
8527                incref systemFont;
8528                usedFont = systemFont;
8529                AddResource(systemFont);
8530             }
8531
8532             firewatchers;
8533
8534             Update(null);
8535          }
8536       }
8537       get { return usedFont; }
8538    };
8539
8540    property SizeAnchor sizeAnchor
8541    {
8542       property_category $"Layout"
8543       isset
8544       {
8545          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8546                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8547             sizeAnchor.isClientW != sizeAnchor.isClientH;
8548       }
8549       set
8550       {
8551          int x, y, w, h;
8552          sizeAnchor = value;
8553
8554          normalSizeAnchor = sizeAnchor;
8555
8556          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8557          {
8558             stateAnchor = normalAnchor;
8559             stateSizeAnchor = normalSizeAnchor;
8560
8561             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8562             Position(x,y, w, h, true, true, true, true, false, true);
8563          }
8564       }
8565       get
8566       {
8567          value =
8568          {
8569             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
8570             sizeAnchor.isClientW,
8571             sizeAnchor.isClientH
8572          };
8573       }
8574    };
8575
8576    property Size size
8577    {
8578       property_category $"Layout"
8579       isset
8580       {
8581          Anchor thisAnchor = anchor;
8582          SizeAnchor thisSizeAnchor = sizeAnchor;
8583          bool leftRight = (anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none);
8584          bool topBottom = (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none);
8585          bool isClient = !sizeAnchor.isClientW && !sizeAnchor.isClientH;
8586          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8587                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8588             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8589       }
8590       set
8591       {
8592          int x, y, w, h;
8593
8594          sizeAnchor.isClientW = false;
8595          sizeAnchor.isClientH = false;
8596          sizeAnchor.size = value;
8597
8598          normalSizeAnchor = sizeAnchor;
8599
8600          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
8601          {
8602             stateAnchor = normalAnchor;
8603             stateSizeAnchor = normalSizeAnchor;
8604
8605             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8606             Position(x, y, w, h, true, true, true, true, false, true);
8607             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
8608          }
8609       }
8610       get { value = size; }
8611    };
8612
8613    property Size clientSize
8614    {
8615       property_category $"Layout"
8616       isset
8617       {
8618          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8619                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8620             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8621       }
8622       set
8623       {
8624          int x, y, w, h;
8625          sizeAnchor.isClientW = true;
8626          sizeAnchor.isClientH = true;
8627          sizeAnchor.size = value;
8628
8629          normalSizeAnchor = sizeAnchor;
8630
8631          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8632          {
8633             stateAnchor = normalAnchor;
8634             stateSizeAnchor = normalSizeAnchor;
8635
8636             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8637             Position(x,y, w, h, true, true, true, true, false, true);
8638          }
8639       }
8640       get { value = clientSize; }
8641    };
8642
8643    property Size initSize { get { value = sizeAnchor.size; } };
8644
8645    property Anchor anchor
8646    {
8647       property_category $"Layout"
8648       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
8649
8650       set
8651       {
8652          if(value != null)
8653          {
8654             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
8655             {
8656                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
8657                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
8658             }
8659             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
8660             {
8661                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
8662                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
8663             }
8664             anchor = value;
8665
8666             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type)) 
8667             {
8668                anchor.left.distance = 0;
8669                anchor.horz.type = 0;
8670             }
8671             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
8672             {
8673                anchor.top.distance = 0;
8674                anchor.vert.type = 0;
8675             }
8676
8677             anchored = true;
8678
8679             //if(created)
8680             {
8681                int x, y, w, h;
8682
8683                normalAnchor = anchor;
8684                
8685                // Break the anchors for moveable/resizable windows
8686                /*if(style.fixed ) //&& value.left.type == cascade)
8687                {
8688                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
8689
8690                   this.anchor = normalAnchor = Anchor { left = x, top = y };
8691                   normalSizeAnchor = SizeAnchor { { w, h } };
8692                   anchored = false;
8693                }*/
8694                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8695                {
8696                   stateAnchor = normalAnchor;
8697                   stateSizeAnchor = normalSizeAnchor;
8698
8699                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8700                   Position(x, y, w, h, true, true, true, true, false, true);
8701                }
8702             }
8703          }
8704          else
8705          {
8706             anchored = false;
8707          }
8708       }
8709       get { value = this ? anchor : Anchor { }; }
8710    };
8711
8712    property Point position
8713    {
8714       property_category $"Layout"
8715       set
8716       {
8717          if(value == null) return;
8718
8719          anchor.left = value.x;
8720          anchor.top  = value.y;
8721          anchor.right.type = none;
8722          anchor.bottom.type = none;
8723          //if(created)
8724          {
8725             int x, y, w, h;
8726
8727             normalAnchor = anchor;
8728
8729             // Break the anchors for moveable/resizable windows
8730             /*
8731             if(style.fixed)
8732             {
8733                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8734
8735                normalAnchor.left = x;
8736                normalAnchor.top = y;
8737                normalAnchor.right.type = none;
8738                normalAnchor.bottom.type = none;
8739                normalSizeAnchor.size.width = w;
8740                normalSizeAnchor.size.height = h;
8741                anchored = false;
8742             }
8743             */
8744             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8745             {
8746                stateAnchor = normalAnchor;
8747                stateSizeAnchor = normalSizeAnchor;
8748
8749                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8750                Position(x,y, w, h, true, true, true, true, false, true);
8751             }
8752          }
8753       }
8754       get { value = position; }
8755    };
8756
8757    property bool disabled
8758    {
8759       property_category $"Behavior"
8760       set
8761       {
8762          if(this && disabled != value)
8763          {
8764             disabled = value;
8765             if(created)
8766                Update(null);
8767          }
8768       }
8769       get { return (bool)disabled; }
8770    };
8771
8772    property bool isEnabled
8773    {
8774       get
8775       {
8776          Window parent;
8777          for(parent = this; parent; parent = parent.parent)
8778             if(parent.disabled)
8779                return false;
8780          return true;
8781       }
8782    };
8783
8784    property WindowState state
8785    {
8786       property_category $"Behavior"
8787       set { SetState(value, false, 0); }
8788       get { return this ? state : 0; }
8789    };
8790
8791    property bool visible
8792    {
8793       property_category $"Behavior"
8794       set
8795       {
8796          if(this && !value && !style.hidden && parent)
8797          {
8798             bool wasActiveChild = parent.activeChild == this;
8799             Window client = null;
8800
8801             style.hidden = true;
8802             if(style.isActiveClient)
8803             {
8804                parent.numPositions--;
8805                if(state == minimized) parent.numIcons--;
8806             }
8807
8808             if(created)
8809             {
8810                OldLink prevOrder = null;
8811
8812                if(rootWindow == this)
8813                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
8814                else
8815                {
8816                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
8817                   if(style.nonClient)
8818                   {
8819                      box.left   -= parent.clientStart.x;
8820                      box.top    -= parent.clientStart.y;
8821                      box.right  -= parent.clientStart.x;
8822                      box.bottom -= parent.clientStart.y;
8823                   }
8824                   parent.Update(box);
8825                }
8826                if(_isModal && master && master.modalSlave == this)
8827                   master.modalSlave = null;
8828
8829                if(order)
8830                {
8831                   OldLink tmpPrev = order.prev;
8832                   client = tmpPrev ? tmpPrev.data : null;
8833                   if(client && !client.style.hidden && !client.destroyed && client.created)
8834                      prevOrder = tmpPrev;
8835                   for(;;)
8836                   {
8837                      client = tmpPrev ? tmpPrev.data : null;
8838                      if(client == this) { client = null; break; }
8839                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
8840                      {
8841                         tmpPrev = client.order.prev;
8842                      }
8843                      else
8844                      {
8845                         if(client)
8846                            prevOrder = tmpPrev;
8847                         break;
8848                      }
8849                   }
8850
8851                   // If this window can be an active client, make sure the next window we activate can also be one
8852                   if(!style.nonClient && style.isActiveClient)
8853                   {
8854                      tmpPrev = prevOrder;
8855                      for(;;)
8856                      {
8857                         client = tmpPrev ? tmpPrev.data : null;
8858                         if(client == this) { client = null; break; }
8859                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
8860                         {
8861                            tmpPrev = client.order.prev;
8862                         }
8863                         else 
8864                         {
8865                            if(client)
8866                               prevOrder = tmpPrev;
8867                            break;
8868                         }
8869                      }
8870                      if(client && client.style.hidden) client = null;
8871                   }
8872                }
8873
8874                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
8875                {
8876                   if(order && prevOrder && prevOrder.data != this)
8877                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
8878                   else
8879                      ActivateEx(false, false, false, true, null, null);
8880
8881                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
8882                   if(parent.activeClient == this)
8883                   {
8884                      parent.activeClient = null;
8885                      parent.UpdateActiveDocument(null);
8886                   }
8887                }
8888                else if(parent.activeClient == this)
8889                {
8890                   parent.activeClient = client;
8891                   parent.UpdateActiveDocument(this);
8892                }
8893
8894                // *** Not doing this anymore ***
8895               /*
8896                if(cycle)
8897                   parent.childrenCycle.Delete(cycle);
8898                if(order)
8899                   parent.childrenOrder.Delete(order);
8900                cycle = null;
8901                order = null;
8902                */
8903                
8904                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8905             }
8906
8907             firewatchers;
8908          }
8909          else if(this && value && style.hidden)
8910          {
8911             style.hidden = false;
8912             if(created)
8913             {
8914                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8915                if(rootWindow == this)
8916                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
8917
8918                if(_isModal && master)
8919                   master.modalSlave = this;
8920
8921                if(style.isActiveClient)
8922                {
8923                   positionID = parent.GetPositionID(this);
8924                   parent.numPositions++;
8925                   if(state == minimized) parent.numIcons++;
8926                }
8927
8928                // *** NOT DOING THIS ANYMORE ***
8929                /*
8930                if(!(style.inactive))
8931                {
8932                   if(!(style.noCycle))
8933                   {
8934                      cycle = parent.childrenCycle.AddAfter(
8935                         (parent.activeChild && parent.activeChild.cycle) ? 
8936                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
8937                      cycle.data = this;
8938                   }
8939                   order = parent.childrenOrder.AddAfter(
8940                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8941                      sizeof(OldLink));
8942                   order.data = this;
8943                }
8944                */
8945      
8946                /*
8947                if(true || !parent.activeChild)
8948                   ActivateEx(true, false, true, true, null, null);
8949                */
8950                if(creationActivation == activate)
8951                   ActivateEx(true, false, true, true, null, null);
8952                else if(creationActivation == flash && !object)
8953                   Flash();               
8954
8955                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8956                Update(null);
8957
8958                // rootWindow.
8959                ConsequentialMouseMove(false);
8960             }
8961
8962             firewatchers;
8963          }
8964          else if(this)
8965             style.hidden = !value;
8966       }
8967
8968       get { return (style.hidden || !setVisible) ? false : true; }
8969    };
8970     
8971    property bool isDocument
8972    {
8973       property_category $"Document"
8974       set { style.isDocument = value; }
8975       get { return style.isDocument; }
8976    };
8977
8978    property bool mergeMenus
8979    {
8980       property_category $"Window Style"
8981       set { mergeMenus = value; }
8982       get { return (bool)mergeMenus; }
8983    };
8984
8985    property bool hasHorzScroll
8986    {
8987       property_category $"Window Style"
8988       set
8989       {
8990          if(value)
8991          {
8992             if(!style.hasHorzScroll && created)
8993             {
8994                CreateSystemChildren();         
8995                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
8996             }
8997          }
8998          else if(style.hasHorzScroll)
8999          {
9000             sbh.Destroy(0);
9001             sbh = null;
9002             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9003          }
9004          style.hasHorzScroll = value;
9005       }
9006
9007       get { return style.hasHorzScroll; }
9008    };
9009
9010    property bool hasVertScroll
9011    {
9012       property_category $"Window Style"
9013       set
9014       {
9015          if(value)
9016          {
9017             if(!style.hasVertScroll && created)
9018             {
9019                style.hasVertScroll = true;
9020                CreateSystemChildren();
9021                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9022             }
9023          }
9024          else if(style.hasVertScroll)
9025          {
9026             sbv.Destroy(0);
9027             sbv = null;
9028             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9029          }
9030          style.hasVertScroll = value;
9031       }
9032       get { return style.hasVertScroll; }
9033    };
9034
9035    property bool dontHideScroll
9036    {
9037       property_category $"Behavior"
9038       set
9039       {
9040          scrollFlags.dontHide = value;
9041          if(value)
9042          {
9043             //UpdateScrollBars(true, true);
9044             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9045          }
9046          else
9047          {
9048             // UpdateScrollBars(true, true);
9049             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9050          }
9051       }
9052       get { return scrollFlags.dontHide; }
9053    };
9054
9055    property bool dontScrollVert
9056    {
9057       property_category $"Behavior"
9058       set { style.dontScrollVert = value; }
9059       get { return style.dontScrollVert; }
9060    };
9061    property bool dontScrollHorz
9062    {
9063       property_category $"Behavior"
9064       set { style.dontScrollHorz = value; }
9065       get { return style.dontScrollHorz; }
9066    };
9067
9068    property bool snapVertScroll
9069    {
9070       property_category $"Behavior"
9071       set
9072       {
9073          scrollFlags.snapY = value;
9074          if(sbv) sbv.snap = value;
9075       }
9076       get { return scrollFlags.snapY; }
9077    };
9078    property bool snapHorzScroll
9079    {
9080        property_category $"Behavior"
9081       set
9082       {
9083          scrollFlags.snapX = value;
9084          if(sbh) sbh.snap = value;
9085       }
9086       get { return scrollFlags.snapX; }
9087    };
9088
9089    property Point scroll
9090    {
9091       property_category $"Behavior"
9092       set { SetScrollPosition(value.x, value.y); }
9093       get { value = scroll; }
9094    };
9095
9096    property bool modifyVirtualArea
9097    {
9098       property_category $"Behavior"
9099       set { modifyVirtArea = value; }
9100       get { return (bool)modifyVirtArea; }
9101    };
9102
9103    property bool dontAutoScrollArea
9104    {
9105       property_category $"Behavior"
9106       // Activating a child control out of view will automatically scroll to make it in view
9107       set { noAutoScrollArea = value; }
9108       get { return (bool)noAutoScrollArea; }
9109    };
9110
9111    property char * fileName
9112    {
9113       property_category $"Document"
9114       set
9115       {
9116          if(menu && ((!fileName && value) || (fileName && !value)))
9117          {
9118             MenuItem item = menu.FindItem(MenuFileSave, 0);
9119             if(item) item.disabled = !modifiedDocument && value;
9120          }
9121
9122          delete fileName;
9123
9124          if(value && value[0])
9125             fileName = CopyString(value);
9126
9127          if(parent && this == parent.activeClient)
9128             parent.UpdateActiveDocument(null);
9129          else
9130             UpdateCaption();
9131
9132          // if(style.isDocument)
9133          if(!saving)
9134             fileMonitor.fileName = value;
9135       }
9136       get { return fileName; }
9137    };
9138
9139    property int id
9140    {
9141       property_category $"Data"
9142       set { id = value; }
9143       get { return id; }
9144    };
9145
9146    property bool modifiedDocument
9147    {
9148       property_category $"Document"
9149       set
9150       {
9151          if(style.isDocument || fileName)
9152          {
9153             if(menu)
9154             {
9155                MenuItem item = menu.FindItem(MenuFileSave, 0);
9156                if(item) item.disabled = !value && fileName;
9157             }
9158          }
9159
9160          if(modifiedDocument != value)
9161          {
9162             modifiedDocument = value;
9163             if(style.isDocument || fileName)
9164                UpdateCaption();
9165          }
9166       }
9167       get { return (bool)modifiedDocument; }
9168    };
9169
9170    property bool showInTaskBar
9171    {
9172       property_category $"Window Style"
9173       set { style.showInTaskBar = value; }
9174       get { return (style.showInTaskBar; }
9175    };
9176    property FileDialog saveDialog { set { saveDialog = value; } };
9177    property bool isActiveClient
9178    {
9179       property_category $"Behavior"
9180       set { style.isActiveClient = value; }
9181       get { return style.isActiveClient; }
9182    };
9183
9184    property Cursor cursor
9185    {
9186       property_category $"Appearance"
9187       set
9188       {
9189          cursor = value;
9190          SelectMouseCursor();
9191       }
9192       get { return cursor; }
9193    };      
9194
9195 //#if !defined(ECERE_VANILLA)
9196    property char * name
9197    {
9198       property_category $"Design"
9199       get
9200       {
9201          return (this && object) ? object.name : null;
9202       }
9203       set
9204       {
9205          if(activeDesigner)
9206             activeDesigner.RenameObject(object, value);
9207       }
9208    };
9209 //#endif
9210    property char * displayDriver
9211    {
9212       property_category $"Behavior"
9213       set
9214       {
9215          dispDriver = GetDisplayDriver(value);
9216          //DisplayModeChanged();
9217       }
9218       get
9219       {
9220          return dispDriver ? dispDriver.name : null;
9221       }
9222    }
9223
9224    // RUNTIME PROPERTIES
9225    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9226    property Size scrollArea
9227    {
9228       property_category $"Behavior"
9229       set
9230       {
9231          if(value != null)
9232             SetScrollArea(value.w, value.h, false);
9233          else
9234             SetScrollArea(0,0, true);
9235       }
9236       get { value = scrollArea; }
9237       isset
9238       {
9239          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9240       }
9241    };
9242    property bool is3D
9243    {
9244       property_category $"Layout"
9245       set { if(this) is3D = value; }
9246       get { return (bool)is3D; }
9247    };
9248
9249    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9250                                                                                                             
9251    // Will be merged with font later
9252    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9253    property Point clientStart { get { value = clientStart; } };
9254    property Point absPosition { get { value = absPosition; } };
9255    property Anchor normalAnchor { get {value = normalAnchor; } };
9256    // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
9257    property bool active { get { return (bool)active; } };
9258    property bool created { get { return (bool)created; } };
9259    property bool destroyed { get { return (bool)destroyed; } };
9260    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9261    property Window firstChild { get { return children.first; } };   
9262    property Window lastChild { get { return children.last; } };   
9263    property Window activeClient { get { return activeClient; } };
9264    property Window activeChild { get { return activeChild; } };
9265    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9266    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9267    property ScrollBar horzScroll { get { return sbh; } };
9268    property ScrollBar vertScroll { get { return sbv; } };
9269    property StatusBar statusBar { get { return statusBar; } };
9270    property Window rootWindow { get { return rootWindow; } };   
9271    property bool closing { get { return (bool)closing; } set { closing = value; } };
9272    property int documentID { get { return documentID; } };
9273    property Window previous { get { return prev; } }
9274    property Window next { get { return next; } }
9275    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9276    property PopupMenu menuBar { get { return menuBar; } }
9277    property ScrollBar sbv { get { return sbv; } }
9278    property ScrollBar sbh { get { return sbh; } }
9279    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9280    property void * systemHandle { get { return windowHandle; } }
9281    property Button minimizeButton { get { return sysButtons[0]; } };
9282    property Button maximizeButton { get { return sysButtons[1]; } };   
9283    property Button closeButton { get { return sysButtons[2]; } };
9284    property BitmapResource icon
9285    {
9286       get { return icon; }
9287       set
9288       {
9289          icon = value;
9290          if(icon) incref icon;
9291          if(created)
9292             guiApp.interfaceDriver.SetIcon(this, value);
9293       }
9294    };
9295    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9296    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
9297    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9298    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9299    property bool nativeDecorations
9300    {
9301       get { return (bool)nativeDecorations; }
9302       set { nativeDecorations = value; }
9303 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
9304       isset
9305       {
9306          //return (nativeDecorations && (rootWindow == this || (formDesigner && activeDesigner && ((FormDesigner)activeDesigner.classDesigner).form && parent == ((FormDesigner)activeDesigner.classDesigner).form.parent))) != style.fixed;
9307          bool result = false;
9308          if(nativeDecorations)
9309          {
9310             if(rootWindow == this)
9311                result = true;
9312             else
9313             {
9314                if(formDesigner && activeDesigner)
9315                {
9316                   FormDesigner cd = (FormDesigner)activeDesigner.classDesigner;
9317                   Window form = cd ? cd.form : null;
9318                   if(form && parent == form.parent)
9319                      result = true;
9320                }
9321             }
9322          }
9323          return result != style.fixed;
9324       }
9325 #endif
9326    };
9327    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9328
9329    property char * text
9330    {
9331       property_category $"Deprecated"
9332       watchable
9333       set { property::caption = value; }
9334       get { return property::caption; }
9335    }
9336 private:
9337    // Data
9338    //char * yo;
9339    Window prev, next;
9340    WindowBits style;       // Window Style
9341    char * caption;            // Name / Caption
9342    Window parent;    // Parent window
9343    OldList children;          // List of children in Z order
9344    Window activeChild;     // Child window having focus
9345    Window activeClient;
9346    Window previousActive;  // Child active prior to activating the default child
9347    Window master;          // Window owning and receiving notifications concerning this window
9348    OldList slaves;            // List of windows belonging to this window
9349    Display display;        // Display this window is drawn into
9350
9351    Point position;         // Position in parent window client area
9352    Point absPosition;      // Absolute position
9353    Point clientStart;      // Client area position from (0,0) in this window
9354    Size size;              // Size
9355    Size clientSize;        // Client area size
9356    Size scrollArea;        // Virtual Scroll area size
9357    Size reqScrollArea;     // Requested virtual area size
9358    Point scroll;           // Virtual area scrolling position
9359    public ScrollBar sbh, sbv;        // Scrollbar window handles
9360    Cursor cursor;        // Mouse cursor used for this window
9361    WindowState state;
9362    PopupMenu menuBar;
9363    StatusBar statusBar;
9364    Button sysButtons[3];
9365    char * fileName;
9366    Box clientArea;         // Client Area box clipped to parent
9367    Key setHotKey;
9368    HotKeySlot hotKey;        // HotKey for this window
9369    int numDocuments;
9370    int numPositions;
9371    Menu menu;
9372    ScrollFlags scrollFlags;// Window Scrollbar Flags
9373    int id;                 // Control ID
9374    int documentID;
9375    ColorAlpha background;  // Background color used to draw the window area
9376    Color foreground;
9377    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9378    OldList childrenCycle;     // Cycling order
9379    OldLink cycle;             // Element of parent's cycling order
9380    OldList childrenOrder;     // Circular Z-Order
9381    OldLink order;             // Element of parent's circular Z-Order
9382    Window modalSlave;      // Slave window blocking this window's interaction
9383
9384    Window rootWindow;      // Topmost system managed window
9385    void * windowHandle;    // System window handle
9386
9387    DialogResult returnCode;// Return code for modal windows
9388   
9389    Point sbStep;           // Scrollbar line scrolling steps
9390
9391    Anchor stateAnchor;
9392    SizeAnchor stateSizeAnchor;
9393
9394    Anchor normalAnchor;
9395    SizeAnchor normalSizeAnchor;
9396
9397    Size skinMinSize;       // Minimal window size based on style
9398    Point scrolledPos;      // Scrolled position
9399    Box box;                // Window box clipped to parent
9400    Box * against;          // What to clip the box to
9401
9402    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9403    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9404    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9405    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9406    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9407    Point scrolledArea;     // Distance to scroll area by
9408    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9409
9410    OldList hotKeys;           // List of the hotkeys of all children
9411    Window defaultControl;  // Default child control
9412    Size minSize;
9413    Size maxSize;
9414
9415    ColorAlpha * palette;   // Color palette used for this window
9416
9417    int caretSize;          // Size of caret, non zero if a caret is present
9418    Point caretPos;         // Caret position
9419
9420    void * systemParent;    // Parent System Window for embedded windows
9421
9422    int iconID;
9423    int numIcons;
9424    int positionID;
9425
9426    Mutex mutex;
9427    WindowState lastState;
9428
9429    FileMonitor fileMonitor
9430    {
9431       this, FileChange { modified = true };
9432
9433       bool OnFileNotify(FileChange action, char * param)
9434       {
9435          incref this;
9436          fileMonitor.StopMonitoring();
9437          if(OnFileModified(action, param))
9438             fileMonitor.StartMonitoring();
9439          delete this;
9440          return true;
9441       }
9442    };
9443    FontResource setFont, systemFont;
9444    FontResource usedFont;
9445    FontResource captionFont;
9446    OldList resources;
9447    FileDialog saveDialog;
9448    Anchor anchor;
9449    SizeAnchor sizeAnchor;
9450
9451    // FormDesigner data
9452    ObjectInfo object;
9453    Window control;
9454    Extent * tempExtents; //[4];
9455    BitmapResource icon;
9456    void * windowData;
9457    CreationActivationOption creationActivation;
9458    struct
9459    {
9460       bool active:1;            // true if window and ancestors are active
9461       bool acquiredInput:1;     // true if the window is processing state based input
9462       bool modifiedDocument:1;
9463       bool disabled:1;          // true if window cannot interact
9464       bool isForegroundWindow:1;// true while a root window is being activated
9465       bool visible:1;           // Visibility flag
9466       bool destroyed:1;         // true if window is being destroyed
9467       bool anchored:1;          // true if this window is repositioned when the parent resizes
9468       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9469       bool mouseInside:1;
9470       bool positioned:1;
9471       bool created:1;
9472       bool is3D:1;
9473       bool mergeMenus:1;
9474       bool modifyVirtArea:1;
9475       bool noAutoScrollArea:1;
9476       bool closing:1;
9477       bool autoCreate:1;
9478       bool setVisible:1;      // FOR FORM DESIGNER
9479       bool wasCreated:1;
9480       bool fullRender:1;
9481       bool moveable:1;
9482       bool alphaBlend:1;
9483       bool composing:1;
9484       bool useSharedMemory:1;
9485       bool resized:1;
9486       bool saving:1;
9487       bool nativeDecorations:1;
9488       bool manageDisplay:1;
9489       bool formDesigner:1; // True if we this is running in the form editor
9490    }; 
9491
9492    // Checks used internally for them not to take effect in FormDesigner
9493    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
9494    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
9495
9496    WindowController controller;
9497    public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
9498 };
9499
9500 public class CommonControl : Window
9501 {
9502    // creationActivation = doNothing;
9503
9504    ToolTip toolTip;
9505    public property String toolTip
9506    {
9507       property_category $"Appearance"
9508       set
9509       {
9510          if(created) CommonControl::OnDestroy();
9511          delete toolTip;
9512          toolTip = value ? ToolTip { tip = value; } : null;
9513          incref toolTip;
9514          if(created) CommonControl::OnCreate();
9515       }
9516       get { return toolTip ? toolTip.tip : null; }
9517    }
9518
9519    void OnDestroy()
9520    {
9521       if(toolTip)
9522          // (Very) Ugly work around for the fact that the parent watcher
9523          // won't fire when it's already been disconnected...
9524          eInstance_FireSelfWatchers(toolTip,
9525             __ecereProp___ecereNameSpace__ecere__gui__Window_parent);
9526    }
9527
9528    bool OnCreate()
9529    {
9530       if(toolTip)
9531          toolTip.parent = this;
9532       return true;
9533    }
9534    ~CommonControl()
9535    {
9536       delete toolTip;
9537    }
9538 };
9539
9540 public class Percentage : float
9541 {
9542    char * OnGetString(char * string, float * fieldData, bool * needClass)
9543    {
9544       int c;
9545       int last = 0;
9546       sprintf(string, "%.2f", this);
9547       c = strlen(string)-1;
9548       for( ; c >= 0; c--)
9549       {
9550          if(string[c] != '0') 
9551             last = Max(last, c);
9552          if(string[c] == '.')
9553          {
9554             if(last == c)
9555                string[c] = 0;
9556             else
9557                string[last+1] = 0;
9558             break;
9559          }
9560       }
9561       return string;
9562    }
9563 };
9564
9565 public void ApplySkin(Class c, char * name, void ** vTbl)
9566 {
9567    char className[1024];
9568    Class sc;
9569    OldLink d;
9570    int m;
9571
9572    subclass(Window) wc = (subclass(Window))c;
9573    subclass(Window) base = (subclass(Window))c.base;
9574
9575    sprintf(className, "%sSkin_%s", name, c.name);
9576    wc.pureVTbl = c._vTbl;
9577    c._vTbl = new void *[c.vTblSize];
9578    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
9579    sc = eSystem_FindClass(c.module.application, className);
9580    
9581    if(vTbl)
9582    {
9583       for(m = 0; m < c.base.vTblSize; m++)
9584       {
9585          if(c._vTbl[m] == base.pureVTbl[m])
9586             c._vTbl[m] = vTbl[m];
9587       }
9588    }
9589    if(sc)
9590    {
9591       for(m = 0; m < c.vTblSize; m++)
9592       {
9593          if(sc._vTbl[m] != wc.pureVTbl[m])
9594             c._vTbl[m] = sc._vTbl[m];
9595       }
9596    }
9597       
9598    for(d = c.derivatives.first; d; d = d.next)
9599    {
9600       ApplySkin(d.data, name, c._vTbl);
9601    }
9602 }
9603
9604 public void UnapplySkin(Class c)
9605 {
9606    char className[1024];
9607    Class sc;
9608    subclass(Window) wc = (subclass(Window))c;
9609    subclass(Window) base = (subclass(Window))c.base;
9610    OldLink d;
9611
9612    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
9613    {
9614       delete c._vTbl;
9615       c._vTbl = wc.pureVTbl;
9616       wc.pureVTbl = null;
9617    }
9618
9619    for(d = c.derivatives.first; d; d = d.next)
9620    {
9621       UnapplySkin(d.data);
9622    }
9623 }
9624 /*
9625 void CheckFontIntegrity(Window window)
9626 {
9627    Window c;
9628    if(window)
9629    {
9630       if(window.usedFont && window.usedFont.font == 0xecececec)
9631       {
9632          FontResource uf = window.usedFont;
9633          char * className = window._class.name;
9634          char * text = window.text;
9635          Print("");
9636       }
9637       for(c = window.firstChild; c; c = c.next)
9638          CheckFontIntegrity(c);
9639    }
9640 }*/
9641
9642 public class ControllableWindow : Window
9643 {
9644    /*WindowController controller;
9645    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
9646    ~ControllableWindow() { delete controller; }*/
9647 }
9648
9649 class WindowControllerInterface : ControllableWindow
9650 {
9651    bool OnKeyDown(Key key, unichar ch)
9652    {
9653       bool result = ((int(*)())(void *)controller.OnKeyDown)((void *)controller.controlled, (void *)controller, key, ch);
9654       if(result)
9655          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown](controller.window, key, ch);
9656       return result;
9657    }
9658
9659    bool OnKeyUp(Key key, unichar ch)
9660    {
9661       bool result = ((int(*)())(void *)controller.OnKeyUp)((void *)controller.controlled, (void *)controller, key, ch);
9662       if(result)
9663          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp](controller.window, key, ch);
9664       return result;
9665    }
9666
9667    bool OnKeyHit(Key key, unichar ch)
9668    {
9669       bool result = ((int(*)())(void *)controller.OnKeyHit)((void *)controller.controlled, (void *)controller, key, ch);
9670       if(result)
9671          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit](controller.window, key, ch);
9672       return result;
9673    }
9674
9675    bool OnMouseMove(int x, int y, Modifiers mods)
9676    {
9677       bool result = ((int(*)())(void *)controller.OnMouseMove)((void *)controller.controlled, (void *)controller, x, y, mods);
9678       if(result)
9679          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove](controller.window, x, y, mods);
9680       return result;
9681    }
9682
9683    bool OnLeftButtonDown(int x, int y, Modifiers mods)
9684    {
9685       bool result = ((int(*)())(void *)controller.OnLeftButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9686       if(result)
9687          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown](controller.window, x, y, mods);
9688       return result;
9689    }
9690
9691    bool OnLeftButtonUp(int x, int y, Modifiers mods)
9692    {
9693       bool result = ((int(*)())(void *)controller.OnLeftButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9694       if(result)
9695          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp](controller.window, x, y, mods);
9696       return result;
9697    }
9698
9699    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
9700    {
9701       bool result = ((int(*)())(void *)controller.OnLeftDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9702       if(result)
9703          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick](controller.window, x, y, mods);
9704       return result;
9705    }
9706
9707    bool OnRightButtonDown(int x, int y, Modifiers mods)
9708    {
9709       bool result = ((int(*)())(void *)controller.OnRightButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9710       if(result)
9711          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown](controller.window, x, y, mods);
9712       return result;
9713    }
9714
9715    bool OnRightButtonUp(int x, int y, Modifiers mods)
9716    {
9717       bool result = ((int(*)())(void *)controller.OnRightButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9718       if(result)
9719          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp](controller.window, x, y, mods);
9720       return result;
9721    }
9722
9723    bool OnRightDoubleClick(int x, int y, Modifiers mods)
9724    {
9725       bool result = ((int(*)())(void *)controller.OnRightDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9726       if(result)
9727          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick](controller.window, x, y, mods);
9728       return result;
9729    }
9730
9731    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
9732    {
9733       bool result = ((int(*)())(void *)controller.OnMiddleButtonDown)((void *)controller.controlled, (void *)controller, x, y, mods);
9734       if(result)
9735          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown](controller.window, x, y, mods);
9736       return result;
9737    }
9738
9739    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
9740    {
9741       bool result = ((int(*)())(void *)controller.OnMiddleButtonUp)((void *)controller.controlled, (void *)controller, x, y, mods);
9742       if(result)
9743          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp](controller.window, x, y, mods);
9744       return result;
9745    }
9746
9747    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
9748    {
9749       bool result = ((int(*)())(void *)controller.OnMiddleDoubleClick)((void *)controller.controlled, (void *)controller, x, y, mods);
9750       if(result)
9751          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick](controller.window, x, y, mods);
9752       return result;
9753    }
9754
9755    void OnResize(int width, int height)
9756    {
9757       ((int(*)())(void *)controller.OnResize)((void *)controller.controlled, (void *)controller, width, height);
9758       controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize](controller.window, width, height);
9759    }
9760
9761    void OnRedraw(Surface surface)
9762    {
9763       ((int(*)())(void *)controller.OnRedraw)((void *)controller.controlled, (void *)controller, surface);
9764       controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw](controller.window, surface);
9765    }
9766
9767    bool OnCreate()
9768    {
9769       bool result = ((int(*)())(void *)controller.OnCreate)((void *)controller.controlled, (void *)controller);
9770       if(result)
9771          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate](controller.window);
9772       return result;
9773    }
9774
9775    bool OnLoadGraphics()
9776    {
9777       bool result = ((int(*)())(void *)controller.OnLoadGraphics)((void *)controller.controlled, (void *)controller);
9778       if(result)
9779          result = controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics](controller.window);
9780       return result;
9781    }
9782
9783    void OnUnloadGraphics()
9784    {
9785       ((int(*)())(void *)controller.OnUnloadGraphics)((void *)controller.controlled, (void *)controller);
9786          controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics](controller.window);
9787    }
9788 }
9789
9790 public class WindowController<class V>
9791 {
9792 public:
9793    property Window window
9794    {
9795       set
9796       {
9797          uint size = class(Window).vTblSize;
9798          if(value)
9799          {
9800             windowVTbl = new void *[size];
9801             memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
9802             if(value._vTbl == value._class._vTbl)
9803             {
9804                value._vTbl = new void *[value._class.vTblSize];
9805                memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
9806             }
9807             {
9808                int c;
9809                for(c = 0; c < size; c++)
9810                {
9811                   void * function = class(WindowControllerInterface)._vTbl[c];
9812                   if(function != DefaultFunction)
9813                      value._vTbl[c] = function;
9814                   else
9815                      value._vTbl[c] = windowVTbl[c];
9816                }
9817             }
9818          }
9819          else
9820             memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
9821          window = value;
9822       }
9823       get { return window; }
9824    }
9825    property V controlled
9826    {
9827       set { controlled = value; }
9828       get { return controlled; }
9829    }
9830    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
9831    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
9832    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
9833    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
9834    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
9835    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
9836    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9837    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
9838    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
9839    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9840    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
9841    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
9842    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9843    virtual void V::OnResize(WindowController controller, int width, int height);
9844    virtual void V::OnRedraw(WindowController controller, Surface surface);
9845    virtual bool V::OnCreate(WindowController controller);
9846    virtual bool V::OnLoadGraphics(WindowController controller);
9847    virtual void V::OnUnloadGraphics(WindowController controller);
9848
9849 private:
9850    int (** windowVTbl)();   
9851    V controlled;
9852    Window window;
9853
9854    ~WindowController()
9855    {
9856       delete windowVTbl;
9857    }
9858 }