ecere; samples: Initial Android Support
[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       bool switchMode = true;
502 #if defined(__ANDROID__)
503       switchMode = false;
504 #endif
505       if(guiApp)
506          guiApp.Initialize(switchMode);
507
508       if(guiApp && guiApp.currentSkin && ((subclass(Window))_class).pureVTbl)
509       {
510          if(_vTbl == ((subclass(Window))_class).pureVTbl)
511          {
512             _vTbl = _class._vTbl;
513          }
514          else if(_vTbl != _class._vTbl)
515          {
516             int m;
517             for(m = 0; m < _class.vTblSize; m++)
518             {
519                if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m])
520                   _vTbl[m] = _class._vTbl[m];
521             }
522          }
523       }
524       
525       //tempExtents[0] = { /*first = -1, last = -1, free = -1*/ };
526       //tempExtents[1] = { /*first = -1, last = -1, free = -1*/ };
527       //tempExtents[2] = { /*first = -1, last = -1, free = -1*/ };
528       //tempExtents[3] = { /*first = -1, last = -1, free = -1*/ };
529
530       setVisible = true;
531
532       // caption = CopyString(class.name);
533
534       children.offset = (byte*)&prev - (byte*)this;
535       childrenOrder.circ = true;
536       childrenCycle.circ = true;
537
538       maxSize = Size { MAXINT, MAXINT };
539       background = white;
540       foreground = black;
541       
542       //style.isActiveClient = true;
543       mergeMenus = true;
544       autoCreate = true;
545       modifyVirtArea = true;
546       manageDisplay = true;
547       nativeDecorations = true;
548
549       // scrollFlags = ScrollFlags { snapX = true, snapY = true };
550       sbStep.x = sbStep.y = 8;
551
552       if(guiApp)  // dynamic_cast<GuiApplication>(thisModule)
553       {
554          cursor = guiApp.GetCursor(arrow);
555          property::parent = guiApp.desktop;
556       }
557    }
558
559    ~Window()
560    {
561       Window child;
562       OldLink slave;
563       ResPtr ptr;
564
565       if(parent)
566       {
567          stopwatching(parent, font);
568          if(parent.activeChild == this)
569             parent.activeChild = null;
570          if(parent.activeClient == this)
571             parent.activeClient = null;
572       }
573
574       if(!destroyed)
575       { 
576          // Prevent destructor from being called again...
577          incref this;
578          incref this;
579          DestroyEx(0);
580       }
581
582       /////////////////////////////////
583       if(master)
584       {
585          OldLink slave = master.slaves.FindLink(this);
586          master.slaves.Delete(slave);
587          master = null;
588       }
589
590       if(parent)
591       {
592          if(cycle)
593             parent.childrenCycle.Remove(cycle);
594          if(order)
595             parent.childrenOrder.Remove(order);
596          parent.children.Remove(this);
597          parent = null;
598       }
599       delete cycle;
600       delete order;
601       /////////////////////////////////
602
603       while(ptr = resources.first)
604       {
605          delete ptr.resource;
606          resources.Delete(ptr);
607       }
608
609       usedFont = null;
610       delete setFont;
611       delete systemFont;
612
613       for(child = children.first; child; child = child.next)
614       {
615          // child.stopwatching(this, font);
616          if(child.parent)
617             eInstance_StopWatching(this, __ecereProp___ecereNameSpace__ecere__gui__Window_font, child);
618          // Don't want property here
619          *&child.parent = null;
620       }
621
622       while(slave = slaves.first)
623       {
624          // Don't want property here
625          *&((Window)slave.data).master = null;
626          slaves.Delete(slave);
627       }
628
629       // Because we do a decref in DestroyEx...
630       if(!destroyed)
631       {
632          incref this;
633          incref this;
634          DestroyEx(0);
635       }
636
637       // Why was this commented?
638       //if(this != guiApp.desktop)
639       {
640          delete caption;
641          delete fileName;
642       }
643
644       delete menu;
645       delete statusBar;
646
647       OnDestroyed();
648       delete mutex;
649       delete icon;
650
651       if(((subclass(Window))_class).pureVTbl)
652       {
653          if(_vTbl == _class._vTbl)
654          {
655             _vTbl = ((subclass(Window))_class).pureVTbl;
656          }
657          else
658          {
659             int m;
660             for(m = 0; m < _class.vTblSize; m++)
661             {
662                if(_vTbl[m] == _class._vTbl[m])
663                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
664             }
665          }
666       }
667       if(_vTbl == ((subclass(Window))_class).pureVTbl || _vTbl == _class._vTbl)
668          _vTbl = null;
669
670       dirtyArea.Free(null);
671       renderArea.Free(null);
672       overRenderArea.Free(null);
673       clipExtent.Free(null);
674       scrollExtent.Free(null);
675       dirtyBack.Free(null);
676
677       if(tempExtents)
678       {
679          tempExtents[0].Free(null);
680          tempExtents[1].Free(null);
681          tempExtents[2].Free(null);
682          tempExtents[3].Free(null);
683          delete tempExtents;
684       }
685    }
686
687 //#if !defined(ECERE_VANILLA)
688    char * OnGetString(char * stringOutput, void * fieldData, bool * needClass)
689    {
690       if(this == activeDesigner)
691          return "(Desktop)";
692       else 
693       {
694          char * name = property::name;
695          return name ? name : "";
696       }
697    }
698 //#endif
699
700 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
701    bool OnGetDataFromString(char * string)
702    {
703       FormDesigner designer = (FormDesigner)activeDesigner.classDesigner;
704       if(string[0])
705       {
706          if(!strcmp(string, "this") || !strcmp(string, designer.form.name))
707             this = designer.form;
708          else if(!strcmpi(string, "(Desktop)"))
709             this = activeDesigner;
710          else
711             return activeDesigner.FindObject(&this, string);
712       }
713       return true;
714    }
715 #endif
716
717    // --- Window updates system ---
718
719    // Setup a bitmap for Redrawing on client area of Window
720    Surface Redraw(Box box)
721    {
722       Surface surface = null;
723       Box mox = box;
724       Box clientArea = this.clientArea;
725
726       SetBox(clientArea);
727
728       mox.left   -= clientStart.x;
729       mox.top    -= clientStart.y;
730       mox.right  -= clientStart.x;
731       mox.bottom -= clientStart.y;
732
733       mox.Clip(clientArea);
734       // mox.ClipOffset(against, scrolledPos.x, scrolledPos.y);
735
736       if((!guiApp.fullScreenMode || guiApp.desktop.active) && display && mox.right >= mox.left && mox.bottom >= mox.top)
737       {
738          int x = absPosition.x + clientStart.x;
739          int y = absPosition.y + clientStart.y;
740          if(rootWindow.nativeDecorations && rootWindow.windowHandle)
741          {
742             x -= rootWindow.clientStart.x;
743             y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
744          }
745          if(!guiApp.fullScreenMode || is3D)
746          {
747             x -= rootWindow.absPosition.x;
748             y -= rootWindow.absPosition.y;
749
750             if(rootWindow.is3D)
751             {
752                x += rootWindow.parent.clientStart.x;
753                y += rootWindow.parent.clientStart.y;
754                /*
755                mox.left += rootWindow.parent.clientStart.x;
756                mox.top += rootWindow.parent.clientStart.y;
757                mox.right += rootWindow.parent.clientStart.x;
758                mox.bottom += rootWindow.parent.clientStart.y;
759                */
760             }
761          }
762
763          surface = display.GetSurface(x, y, mox);
764          /*if(surface)
765          {
766             surface.width = clientSize.w;
767             surface.height = clientSize.h;
768          }*/
769       }
770       return surface;
771    }
772
773    // Setup a bitmap for Redrawing on full Window
774    Surface RedrawFull(Box box)
775    {
776       Surface surface = null;
777       Box mox;
778       if(box != null)
779          box.Clip(this.box);
780       else
781          box = &this.box;
782       mox = box;
783
784       if((!guiApp.fullScreenMode || guiApp.desktop.active) && display && box.right >= box.left && box.bottom >= box.top)
785       {
786          int x = absPosition.x;
787          int y = absPosition.y;
788          if(rootWindow.nativeDecorations && rootWindow.windowHandle)
789          {
790             x -= rootWindow.clientStart.x;
791             y -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
792          }
793          if(!guiApp.fullScreenMode || is3D)
794          {
795             x -= rootWindow.absPosition.x;
796             y -= rootWindow.absPosition.y;
797             if(rootWindow.is3D)
798             {
799                x += rootWindow.parent.clientStart.x;
800                y += rootWindow.parent.clientStart.y;
801                /*
802                mox.left += rootWindow.parent.clientStart.x;
803                mox.top += rootWindow.parent.clientStart.y;
804                mox.right += rootWindow.parent.clientStart.x;
805                mox.bottom += rootWindow.parent.clientStart.y;
806                */
807             }
808          }
809
810          surface = display.GetSurface(x, y, mox);
811          /*if(surface)
812          {
813             surface.width = size.w;
814             surface.height = size.h;
815          }*/
816       }
817       return surface;
818    }
819
820    void FigureCaption(char * caption)
821    {
822       Window activeClient = null;
823
824       caption[0] = '\0';
825       if(this.caption)
826          strcpy(caption, this.caption);
827       if(style.isDocument || fileName)
828       {
829          if(caption[0]) strcat(caption, " - ");
830          if(fileName)
831             strcat(caption, fileName);
832          else
833          {
834             char title[256];
835             sprintf(title, "Untitled %d", documentID);
836             strcat(caption, title);
837          }
838          if(modifiedDocument)
839             strcat(caption, " *");
840       }
841
842       if(menuBar)
843       {
844          for(activeClient = this.activeClient; activeClient && !((BorderBits)activeClient.borderStyle).fixed; activeClient = activeClient.activeClient);
845       }
846       if(activeClient && activeClient.state == maximized)
847       {
848          if(activeClient.caption)
849          {
850             if(caption[0]) strcat(caption, " - ");
851             strcat(caption, activeClient.caption);
852          }
853          if(activeClient.style.isDocument || activeClient.fileName)
854          {
855             if(caption[0]) strcat(caption, " - ");
856             strcat(caption, "[");
857             if(activeClient.fileName)
858                strcat(caption, activeClient.fileName);
859             else
860             {
861                char title[256];
862                sprintf(title, "Untitled %d", activeClient.documentID);
863                strcat(caption, title);
864             }
865             if(activeClient.modifiedDocument)
866                strcat(caption, " *");
867             strcat(caption, "]");
868          }
869       }
870    }
871
872    // Code for returning dirty from ScrollDisplay:
873       /*
874       for(d = 0; d<scrollExtent.count; d++)
875       {
876          Box * box = &scrollExtent.boxes[d];
877          if(scroll.x < 0)
878          {
879             Box update
880             {
881                box.left, box.top,
882                Min(box.right, box.left-scroll.x),box.bottom
883             };
884             dirtyArea.UnionBox(update);
885          }
886          else if(scroll.x)
887          {
888             Box update
889             {
890                Max(box.left, box.right-scroll.x), box.top,
891                box.right, box.bottom
892             };
893             dirtyArea.UnionBox(update);
894          }
895
896          if(scroll.y < 0)
897          {
898             Box update
899             {
900                box.left, box.top,
901                box.right, Min(box.bottom, box.top-scroll.y),
902             };
903             dirtyArea.UnionBox(update);
904          }
905          else if(scroll.y)
906          {
907             Box update
908             {
909                box.left, Max(box.top, box.bottom-scroll.y),
910                box.right, box.bottom
911             };
912             dirtyArea.UnionBox(update);
913          }
914       }
915       */
916
917    void UpdateDecorations(void)
918    {
919       // TODO: *** TEMPORARY HACK ***
920       /*
921       if(parent)
922          parent.Update(null);
923       */
924
925       // Top
926       Update({ -clientStart.x, -clientStart.y, -clientStart.x + size.w-1, 0 });
927       // Bottom
928       Update({ -clientStart.x, clientSize.h, -clientStart.x + size.w-1, -clientStart.y + size.h-1 });
929       // Left
930       Update({ -clientStart.x,0, -1, clientSize.h-1 });
931       // Right
932       Update({ clientSize.w, 0, -clientStart.x + size.w-1, clientSize.h-1 });
933    }
934
935    // Returns w & h for Position
936    void ComputeAnchors(Anchor anchor, SizeAnchor sizeAnchor, int *ox, int *oy, int *ow, int *oh)
937    {
938       Window parent = this.parent ? this.parent : guiApp.desktop;
939       int vpw = parent ? parent.clientSize.w : 0;
940       int vph = parent ? parent.clientSize.h : 0;
941       int pw = parent ? parent.clientSize.w : 0;
942       int ph = parent ? parent.clientSize.h : 0;
943       int w = sizeAnchor.size.w, h = sizeAnchor.size.h;
944       int x = anchor.left.distance, y = anchor.top.distance;
945       float ex, ey;
946       MinMaxValue ew = 0, eh = 0;
947       int numCascade;
948       float cascadeW, cascadeH;
949       int numTiling;
950       int tilingW, tilingH, tilingSplit, tilingLastH;
951       int addX = 0, addY = 0;
952
953       if(parent && rootWindow == this && guiApp && guiApp.interfaceDriver)
954       {
955          Window masterWindow = this;
956          Box box { addX, addY, addX + vpw - 1, addY + vph - 1 };
957          if(!visible)
958          {
959             if(master == guiApp.desktop)
960                masterWindow = guiApp.desktop.activeChild;
961             else
962                masterWindow = master.rootWindow;
963             if(!masterWindow) masterWindow = this;
964          }
965          guiApp.interfaceDriver.GetScreenArea(masterWindow, box);
966          if((anchor.left.type == offset && anchor.right.type == offset) || anchor.left.type == none)
967          {
968             addX = box.left;
969             pw = vpw = box.right - box.left + 1;
970          }
971          if((anchor.top.type == offset && anchor.bottom.type == offset) || anchor.top.type == none)
972          {
973             addY = box.top;
974             ph = vph = box.bottom - box.top + 1;
975          }
976       }
977       
978       if(!parent)
979       {
980          *ow = w;
981          *oh = h;
982
983          *ox = x;
984          *oy = y;
985          return;
986       }
987
988       if(style.nonClient)
989       {
990          vpw = pw = parent.size.w;
991          vph = ph = parent.size.h;
992       }
993       else if(!style.fixed /*|| style.isDocument*/)
994       {
995          if(!style.dontScrollHorz && parent.scrollArea.w) vpw = parent.scrollArea.w;
996          if(!style.dontScrollVert && parent.scrollArea.h) vph = parent.scrollArea.h;
997       }
998 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
999       if(is3D)
1000       {
1001          Desktop3D_FixSize(&pw, &ph);
1002          Desktop3D_FixSize(&vpw, &vph);
1003       }
1004 #endif
1005       if(pw < skinMinSize.w) pw = skinMinSize.w;
1006       if(ph < skinMinSize.h) ph = skinMinSize.h;
1007       if(vpw < skinMinSize.w) vpw = skinMinSize.w;
1008       if(vph < skinMinSize.h) vph = skinMinSize.h;
1009
1010       // TODO: Must fix what we're snapping
1011       if(guiApp.textMode)
1012       {
1013          if(anchor.left.type)
1014          {
1015             SNAPUP(x, textCellW);
1016          }
1017          else if(anchor.right.type)
1018          {
1019             SNAPDOWN(x, textCellW);
1020          }
1021
1022          if(anchor.top.type)
1023          {
1024             SNAPUP(y, textCellH);   
1025          }
1026          else if(anchor.bottom.type)
1027          {
1028             SNAPDOWN(y, textCellH);
1029          }
1030       }
1031
1032       // This is required to get proper initial decoration size using native decorations on Windows
1033       if(nativeDecorations && windowHandle && guiApp && guiApp.interfaceDriver && !visible)
1034          guiApp.interfaceDriver.PositionRootWindow(this, x, y, Max(1, size.w), Max(1, size.h), true, true);
1035       GetDecorationsSize(&ew, &eh);
1036
1037       if(anchor.left.type >= cascade && (state == normal /*|| state == Hidden*/))
1038       {
1039          if(parent.sbv && !parent.sbv.style.hidden) 
1040             pw += guiApp.currentSkin.VerticalSBW();
1041          if(parent.sbh && !parent.sbh.style.hidden)
1042             ph += guiApp.currentSkin.HorizontalSBH();
1043
1044          if(anchor.left.type == cascade)
1045          {
1046             w = (int)(pw * 0.80);
1047             h = (int)(ph * 0.80);
1048          }
1049          else if(anchor.left.type >= vTiled)
1050          {
1051             int leftOver;
1052             int x2, y2;
1053
1054             numTiling = parent.numPositions - parent.numIcons;
1055             if(parent.numIcons) ph -= guiApp.textMode ? 16 : 24;
1056             if(anchor.left.type == vTiled)
1057             {
1058                tilingH = (int)sqrt(numTiling);
1059                tilingW = numTiling / tilingH;
1060             }
1061             else
1062             {
1063                tilingW = (int)sqrt(numTiling);
1064                tilingH = numTiling / tilingW;
1065             }
1066
1067             leftOver = numTiling - tilingH * tilingW;
1068             if(leftOver)
1069             {
1070                tilingSplit = (tilingW - leftOver) * tilingH;
1071                tilingLastH = tilingH+1;
1072             }
1073             else
1074                tilingSplit = numTiling;
1075
1076             if(positionID >= tilingSplit)
1077             {
1078                x = pw * (tilingSplit / tilingH + (positionID - tilingSplit) / tilingLastH)/tilingW;
1079                y = ph * ((positionID - tilingSplit) % tilingLastH) / tilingLastH;
1080                x2 = pw * (tilingSplit/tilingH + (positionID - tilingSplit) / tilingLastH + 1)/tilingW;
1081                y2 = ph * (((positionID - tilingSplit) % tilingLastH) + 1) / tilingLastH;
1082             }
1083             else
1084             {
1085                x = pw * (positionID / tilingH) / tilingW;
1086                y = ph * (positionID % tilingH) / tilingH;
1087                x2 = pw * (positionID / tilingH + 1) / tilingW;
1088                y2 = ph * ((positionID % tilingH) + 1) / tilingH;
1089             }
1090             if(guiApp.textMode)
1091             {
1092                SNAPDOWN(x, textCellW);
1093                SNAPDOWN(y, textCellH);
1094                SNAPDOWN(x2, textCellW);
1095                SNAPDOWN(y2, textCellH);
1096             }
1097             w = x2 - x;
1098             h = y2 - y;
1099          }
1100       }
1101       else
1102       {
1103          if(sizeAnchor.isClientW) w += ew;
1104          if(sizeAnchor.isClientH) h += eh;
1105          
1106          if(anchor.left.type == offset)
1107             x = anchor.left.distance;
1108          else if(anchor.left.type == relative)
1109             x = (anchor.left.percent < 0) ? ((int)(vpw * anchor.left.percent - 0.5)) : (int)(vpw * anchor.left.percent + 0.5);
1110          else if(anchor.right.type == relative)
1111             // ex = (anchor.right.percent < 0) ? ((int)(vpw * anchor.right.percent + 0)) : ((int)(vpw * anchor.right.percent + 0));
1112             ex = (anchor.right.percent < 0) ? ((int)(vpw * (1.0-anchor.right.percent) + 0)) : ((int)(vpw * (1.0-anchor.right.percent) + 0));
1113          else if(anchor.right.type == offset)
1114             ex = vpw - anchor.right.distance;
1115
1116          if(anchor.top.type == offset)
1117             y = anchor.top.distance;
1118          else if(anchor.top.type == relative)
1119             y = (anchor.top.percent < 0) ? ((int)(vph * anchor.top.percent - 0.5)) : ((int)(vph * anchor.top.percent + 0.5));
1120          else if(anchor.bottom.type == relative)
1121             //ey = (anchor.bottom.percent < 0) ? ((int)(vph * anchor.bottom.percent + 0)) : ((int)(vph * anchor.bottom.percent + 0));
1122             ey = (anchor.bottom.percent < 0) ? ((int)(vph * (1.0-anchor.bottom.percent) + 0)) : ((int)(vph * (1.0-anchor.bottom.percent) + 0));
1123          else if(anchor.bottom.type == offset)
1124             ey = vph - anchor.bottom.distance;
1125
1126          if(anchor.left.type && anchor.right.type)
1127          {
1128             switch(anchor.right.type)
1129             {
1130                case relative: 
1131                   ex = pw * (1.0f-anchor.right.percent); 
1132                   w = Max((int)(ex + 0.5) - x, 0);
1133                   break;
1134                case offset:
1135                   ex = vpw - anchor.right.distance;
1136                   w = Max((int)(ex + 0.5) - x, 0);
1137                   break;
1138             }
1139          }
1140          if(anchor.top.type && anchor.bottom.type)
1141          {
1142             switch(anchor.bottom.type)
1143             {
1144                case relative:
1145                   ey = ph * (1.0f-anchor.bottom.percent);
1146                   h = Max((int)(ey + 0.5) - y, 0);
1147                   break;
1148                case offset:
1149                   ey = vph - anchor.bottom.distance;
1150                   h = Max((int)(ey + 0.5) - y, 0);
1151                   break;
1152             }
1153          }
1154       }
1155
1156       w -= ew;
1157       h -= eh; 
1158
1159       if(state == normal /*|| state == Hidden*/)
1160       {
1161          bool addSbV = false, addSbH = false;
1162
1163          if(sizeAnchor.isClientW || (anchor.left.type && anchor.right.type))  w = Max(w, 1); else w = Max(w, 0);
1164          if(sizeAnchor.isClientH || (anchor.top.type && anchor.bottom.type))  h = Max(h, 1); else h = Max(h, 0);
1165
1166          w = Max(w, minSize.w);
1167          h = Max(h, minSize.h);
1168          w = Min(w, maxSize.w);
1169          h = Min(h, maxSize.h);
1170
1171          if((sizeAnchor.isClientW || !w || (anchor.left.type && anchor.right.type)) && reqScrollArea.h > h /*&& w*/ && sbv) 
1172          {
1173             if(w) w -= guiApp.currentSkin.VerticalSBW();
1174             addSbV = true;
1175          }
1176          if((sizeAnchor.isClientH || !h ||  (anchor.top.type && anchor.bottom.type)) && reqScrollArea.w > w /*&& h*/ && sbh) 
1177          {
1178             if(h) h -= guiApp.currentSkin.HorizontalSBH();
1179             addSbH = true;
1180          }
1181
1182          if(!OnResizing(&w, &h))
1183          {
1184             w = clientSize.w;
1185             h = clientSize.h;
1186          }
1187
1188          if((addSbV)) // || reqScrollArea.h > h) && sbv) 
1189             w += guiApp.currentSkin.VerticalSBW();
1190          if((addSbH)) // || reqScrollArea.w > w) && sbh)
1191             h += guiApp.currentSkin.HorizontalSBH();
1192
1193          w = Max(w, skinMinSize.w);
1194          h = Max(h, skinMinSize.h);
1195       }
1196       else
1197       {
1198          w = Max(w, 0);
1199          h = Max(h, 0);
1200       }
1201
1202       w += ew;
1203       h += eh; 
1204
1205       if(guiApp.textMode)
1206       {
1207          SNAPDOWN(w, textCellW);
1208          SNAPDOWN(h, textCellH);
1209       }
1210
1211       if(anchor.left.type == cascade && (state == normal /*|| state == Hidden*/))
1212       {
1213          if(parent.numIcons) ph -= guiApp.textMode ? 16 : 24;
1214
1215          numCascade = Min(
1216             (pw - w) / CASCADE_SPACE, 
1217             (ph - h) / CASCADE_SPACE);
1218          
1219          if(guiApp.textMode)
1220          {
1221                int cascW, cascH;
1222                numCascade++;
1223                cascW = (pw - w) / (numCascade-1);
1224                cascH = (ph - h) / (numCascade-1);
1225                SNAPDOWN(cascW, textCellW);
1226                SNAPDOWN(cascH, textCellH);
1227                cascadeW = (float)cascW;
1228                cascadeH = (float)cascH;
1229          }
1230          else
1231          {
1232             numCascade = Max(numCascade, 2);
1233             cascadeW = (float)(pw - w) / (numCascade-1);
1234             cascadeH = (float)(ph - h) / (numCascade-1);
1235          }
1236
1237          x = (int)((positionID % numCascade) * cascadeW);
1238          y = (int)((positionID % numCascade) * cascadeH);
1239       }
1240       else if(anchor.left.type < vTiled)
1241       {
1242          if(!anchor.left.type || anchor.horz.type == middleRelative)
1243          {
1244             if(!anchor.right.type)
1245             {
1246                if(anchor.horz.type == middleRelative)
1247                   x = (int)(vpw * (0.5 + anchor.horz.percent) - w / 2);
1248                else
1249                   x = vpw / 2 + anchor.horz.distance - w / 2;
1250             }
1251             else
1252                x = (int)(ex - w);
1253          }
1254
1255          // case A_EDGE: x = x - w; break;
1256
1257          if(!anchor.top.type || anchor.vert.type == middleRelative)
1258          {
1259             if(!anchor.bottom.type)
1260             {
1261                if(anchor.vert.type == middleRelative)
1262                   y = (int)(vph * (0.5 + anchor.vert.percent) - h / 2);
1263                else
1264                   y = vph / 2 + anchor.vert.distance - h / 2;      
1265             }
1266             else
1267                y = (int)(ey - h);
1268          }
1269
1270          // case A_EDGE: y = y - h; break;
1271       }
1272
1273       if((state == normal /*|| state == Hidden*/) && !OnMoving(&x, &y, w, h))
1274       {
1275          x = position.x;
1276          y = position.y;
1277       }
1278
1279       if(guiApp.textMode)
1280       {
1281          SNAPDOWN(x, textCellW);
1282          SNAPDOWN(y, textCellH);
1283       }
1284
1285       x += addX;
1286       y += addY;
1287
1288       *ow = w;
1289       *oh = h;
1290
1291       *ox = x;
1292       *oy = y;
1293
1294       if(anchored && style.fixed && style.isActiveClient)
1295          anchored = false;
1296    }
1297
1298    // --- Carets ---
1299    void UpdateCaret(bool forceUpdate, bool erase)
1300    {
1301       static Window lastWindow = null;
1302       static int caretX, caretY, caretSize;
1303
1304       if(guiApp && guiApp.caretOwner == this)
1305       {
1306          int x = caretPos.x - scroll.x;
1307          int y = caretPos.y - scroll.y;
1308
1309          if((erase || this.caretSize) &&
1310             x >= clientArea.left && x <= clientArea.right && 
1311             y >= clientArea.top  && y <= clientArea.bottom)
1312          {
1313             if(!erase)
1314             {
1315                guiApp.interfaceDriver.SetCaret(
1316                   x + absPosition.x + clientStart.x, 
1317                   y + absPosition.y + clientStart.y, this.caretSize);
1318                guiApp.caretEnabled = true;
1319             }
1320             if(erase || lastWindow != this || caretX != x || caretY != y || caretSize != this.caretSize || forceUpdate)
1321             {
1322                Box updateBox;
1323
1324                if(lastWindow != this)
1325                {
1326                   updateBox.left = x + 1;
1327                   updateBox.top = y;
1328                   updateBox.right = x + 2;
1329                   updateBox.bottom = y + this.caretSize - 1;
1330                }
1331                else
1332                {
1333                   updateBox.left = Min(x + 1, caretX + 1);
1334                   updateBox.top = Min(y, caretY);
1335                   updateBox.right = Max(x + 2, caretX + 2);
1336                   updateBox.bottom = Max(y + this.caretSize - 1, caretY + caretSize - 1);
1337                }
1338
1339                guiApp.caretOwner.Update(updateBox);
1340
1341                if(!erase)
1342                {
1343                   lastWindow = this;
1344                   caretX = x;
1345                   caretY = y;
1346                   caretSize = this.caretSize;
1347                }
1348             }
1349          }
1350          else
1351          {
1352             guiApp.interfaceDriver.SetCaret(0,0,0);
1353             guiApp.caretEnabled = false;
1354             lastWindow = null;
1355          }
1356       }
1357    }
1358
1359    void SetPosition(int x, int y, int w, int h, bool modifyArea, bool modifyThisArea, bool modifyClientArea)
1360    {
1361       Window child;
1362
1363       // Set position
1364       scrolledPos.x = position.x = x;
1365       scrolledPos.y = position.y = y;
1366
1367       clientSize.w = size.w = w;
1368       clientSize.h = size.h = h;
1369
1370       if(parent && !style.nonClient)
1371       {
1372          //if(!style.fixed || style.isDocument)
1373          {
1374             if(!style.dontScrollHorz) scrolledPos.x -= parent.scroll.x;
1375             if(!style.dontScrollVert) scrolledPos.y -= parent.scroll.y;
1376          }
1377       }
1378
1379       clientStart.x = clientStart.y = 0;
1380
1381       SetWindowArea(&clientStart.x, &clientStart.y, &size.w, &size.h, &clientSize.w, &clientSize.h);
1382
1383       //if(!activeClient || activeClient.state != maximized)
1384       if(!noAutoScrollArea)
1385       {
1386          // Check if scroll area must be modified
1387          if(guiApp && !guiApp.modeSwitching && (sbv || sbh))
1388          {
1389             bool foundChild = false;
1390             int w = 0, h = 0;
1391             int cw = clientSize.w;// + ((!sbv || sbv.range > 1) ? guiApp.currentSkin.VerticalSBW() : 0);
1392             int ch = clientSize.h;// + ((!sbh || sbh.rangw > 1) ? guiApp.currentSkin.HorizontalSBH() : 0);
1393             for(child = children.first; child; child = child.next)
1394             {
1395                if(child.modifyVirtArea && !child.style.hidden && child.created && /*!child.anchored &&*/
1396                   !child.style.dontScrollHorz && !child.style.dontScrollVert && !child.style.nonClient)
1397                {
1398                   if(child.stateAnchor.right.type == none && child.stateAnchor.left.type == offset)
1399                      w = Max(w, child.position.x + child.size.w);
1400                   else if(child.stateAnchor.right.type == none && child.stateAnchor.left.type == none)
1401                      w = Max(w, Max(child.position.x, 0) + child.size.w);
1402                   if(child.stateAnchor.bottom.type == none && child.stateAnchor.top.type == offset)
1403                      h = Max(h, child.position.y + child.size.h);
1404                   else if(child.stateAnchor.bottom.type == none && child.stateAnchor.top.type == none)
1405                      h = Max(h, Max(child.position.y, 0) + child.size.h);
1406
1407                   foundChild = true;
1408                }
1409             }
1410             if(foundChild && (w > cw || h > ch))
1411             {
1412                //if((w > reqScrollArea.w) || (h > reqScrollArea.w))
1413                {
1414                   int stepX = sbStep.x, stepY = sbStep.y;
1415                   // Needed to make snapped down position match the skin's check of client area 
1416                   // against realvirtual
1417                   if(guiApp.textMode)
1418                   {
1419                      SNAPDOWN(stepX, textCellW);
1420                      SNAPDOWN(stepY, textCellH);
1421                      stepX = Max(stepX, textCellW);
1422                      stepY = Max(stepY, textCellH);
1423                   }
1424                   if(scrollFlags.snapX)
1425                      SNAPUP(w, stepX);
1426                   if(scrollFlags.snapY)
1427                      SNAPUP(h, stepY);
1428
1429                   reqScrollArea.w = w;
1430                   reqScrollArea.h = h;
1431                }
1432             }
1433             else if(reqScrollArea.w || reqScrollArea.h)
1434             {
1435                reqScrollArea.w = 0;
1436                reqScrollArea.h = 0;
1437                SetScrollPosition(0,0);
1438             }
1439          }
1440       }
1441
1442       // Automatic MDI Client Scrolling Area Adjustment
1443       if(parent && !parent.noAutoScrollArea)
1444       {
1445          if(modifyArea && modifyVirtArea /*&& !anchored*/ && (parent.sbv || parent.sbh) && 
1446             !style.dontScrollHorz && !style.dontScrollVert && !style.nonClient)
1447          {
1448             Window parent = this.parent;
1449             int w = parent.reqScrollArea.w;
1450             int h = parent.reqScrollArea.h;
1451
1452             if(stateAnchor.right.type == none && stateAnchor.left.type == offset)
1453                w = Max(w, position.x + size.w);
1454             else if(stateAnchor.right.type == none && stateAnchor.left.type == none)
1455                w = Max(w, Max(position.x, 0) + size.w);
1456             if(stateAnchor.bottom.type == none && stateAnchor.top.type == offset)
1457                h = Max(h, position.y + size.h);
1458             else if(stateAnchor.bottom.type == none && stateAnchor.top.type == none)
1459                h = Max(h, Max(position.y, 0) + size.h);
1460
1461             if((w > parent.clientSize.w && w > parent.reqScrollArea.w) || 
1462                (h > parent.clientSize.h && h > parent.reqScrollArea.h))
1463             {
1464                /*bool resize = false;
1465                int stepX = parent.sbStep.x, stepY = parent.sbStep.y;
1466                // Needed to make snapped down position match the skin's check of client area 
1467                // against realvirtual
1468                if(guiApp.textMode)
1469                {
1470                   SNAPDOWN(stepX, textCellW);
1471                   SNAPDOWN(stepY, textCellH);
1472                   stepX = Max(stepX, textCellW);
1473                   stepY = Max(stepY, textCellH);
1474                }
1475                if(parent.scrollFlags.snapX)
1476                   SNAPUP(w, stepX);
1477                if(parent.scrollFlags.snapY)
1478                   SNAPUP(h, stepY);
1479                if(parent.reqScrollArea.w != w || parent.reqScrollArea.h != h)
1480                {
1481                   parent.reqScrollArea.w = w;
1482                   parent.reqScrollArea.h = h;*/
1483
1484                  // parent.UpdateScrollBars(true, true);
1485                   parent.Position(parent.position.x, parent.position.y, parent.size.w, parent.size.h, 
1486                      false, true, true, true, false, false);
1487                   return;
1488                //}
1489             }
1490             else 
1491                GetRidOfVirtualArea();
1492          }
1493       }
1494       if(modifyThisArea)
1495          UpdateScrollBars(modifyThisArea, false);
1496       else if(guiApp.currentSkin)
1497       {
1498          SetWindowArea(
1499             &clientStart.x, &clientStart.y, &size.w, &size.h, &clientSize.w, &clientSize.h);
1500
1501          if(sbv && (scrollFlags.dontHide || sbv.range > 1))
1502             clientSize.w -= guiApp.currentSkin.VerticalSBW();
1503          if(sbh && (scrollFlags.dontHide || sbh.range > 1))
1504             clientSize.h -= guiApp.currentSkin.HorizontalSBH();
1505       }
1506
1507       scrollArea.w = Max(clientSize.w, reqScrollArea.w);
1508       scrollArea.h = Max(clientSize.h, reqScrollArea.h);
1509
1510       absPosition = scrolledPos;
1511       if(guiApp && guiApp.driver != null && guiApp.interfaceDriver)
1512          guiApp.interfaceDriver.OffsetWindow(this, &absPosition.x, &absPosition.y);
1513
1514       if(this != guiApp.desktop && parent)
1515       {
1516          absPosition.x += parent.absPosition.x;
1517          absPosition.y += parent.absPosition.y;
1518          if(!style.nonClient && this != guiApp.desktop)
1519          {
1520             absPosition.x += parent.clientStart.x;
1521             absPosition.y += parent.clientStart.y;
1522          }
1523       }
1524
1525       box = Box { 0, 0, size.w - 1, size.h - 1 };
1526       SetBox(box);
1527
1528       if(against)
1529       {
1530          // Clip against parent's client area
1531          box.ClipOffset(against, scrolledPos.x, scrolledPos.y);
1532       }
1533       // Compute client area in this window coordinate system
1534       clientArea.left = 0;
1535       clientArea.top = 0;
1536       clientArea.right = clientSize.w - 1;
1537       clientArea.bottom = clientSize.h - 1;
1538
1539       // Clip against parent's client area
1540       if(against)
1541          clientArea.ClipOffset(against, scrolledPos.x + clientStart.x, scrolledPos.y + clientStart.y);
1542
1543       if(is3D)
1544       {
1545          //absPosition.x -= parent.clientStart.x;
1546          //absPosition.y -= parent.clientStart.y;
1547       }
1548
1549       // Adjust all children
1550       for(child = children.first; child; child = child.next)
1551          child.SetPosition(child.position.x, child.position.y, child.size.w, child.size.h, false, true, true);
1552
1553       UpdateCaret(false, false);
1554    }
1555
1556    void GetRidOfVirtualArea(void)
1557    {
1558       if(parent && !parent.destroyed && style.fixed &&
1559          !style.dontScrollHorz && !style.dontScrollVert && !style.nonClient &&
1560          parent.reqScrollArea.w && parent.reqScrollArea.h)
1561       {
1562          if(!parent.noAutoScrollArea)
1563          {
1564             Window child;
1565             bool found = false;
1566             for(child = children.first; child; child = child.next)
1567             {
1568                if(child.modifyVirtArea && !child.style.dontScrollHorz && !child.style.dontScrollVert && !child.style.nonClient)
1569                {
1570                   if(child.position.x + child.size.w > parent.clientSize.w + ((!parent.sbv || parent.sbv.style.hidden) ? 0 : guiApp.currentSkin.VerticalSBW()) ||
1571                      child.position.y + child.size.h > parent.clientSize.h + ((!parent.sbh || parent.sbh.style.hidden) ? 0 : guiApp.currentSkin.HorizontalSBH()))
1572                   {
1573                      found = true;
1574                      break;
1575                   }
1576                }
1577             }
1578             //if(!found)
1579             {
1580                Window parent = this.parent;
1581                parent.Position(
1582                   parent.position.x, parent.position.y, parent.size.w, parent.size.h, 
1583                   false, true, true, true, false, false);
1584                /*
1585                parent.SetScrollArea(0,0,true);
1586                parent.SetScrollPosition(0,0);
1587                */
1588             }
1589          }
1590       }
1591    }
1592    public void ExternalPosition(int x, int y, int w, int h)
1593    {
1594       Position(x, y, w, h, false, true, true, true, false, false);
1595    }
1596
1597    // (w, h): Full window size
1598    bool Position(int x, int y, int w, int h, bool force, bool processAnchors, bool modifyArea, bool updateScrollBars, bool thisOnly, bool changeRootWindow)
1599    {
1600       bool result = false;
1601       int oldCW = clientSize.w, oldCH = clientSize.h;
1602       bool clientResized, windowResized, windowMoved;
1603       Window child;
1604       bool realResized = size.w != w || size.h != h;
1605
1606       // TOCHECK: This wasn't in ecere.dll
1607       //if(!parent) return true;
1608       if(destroyed) return false;
1609
1610       windowMoved = position.x != x || position.y != y || force;
1611
1612       // windowResized = realResized || force;
1613       windowResized = size.w != w || size.h != h || force;
1614      
1615       if(rootWindow != this && display && !display.flags.flipping && scrolledPos.x != MININT)
1616       {
1617          if(style.nonClient)
1618          {
1619             Box box
1620             { 
1621                scrolledPos.x - parent.clientStart.x + this.box.left, scrolledPos.y - parent.clientStart.y + this.box.top, 
1622                scrolledPos.x - parent.clientStart.x + this.box.right,
1623                scrolledPos.y - parent.clientStart.y + this.box.bottom 
1624             };
1625             parent.Update(box);
1626          }
1627          else
1628          {
1629             Box box { scrolledPos.x + this.box.left, scrolledPos.y + this.box.top, scrolledPos.x + this.box.right, scrolledPos.y + this.box.bottom};
1630             parent.Update(box);
1631          }
1632       }
1633
1634       SetPosition(x, y, w, h, true, modifyArea, updateScrollBars);
1635
1636       clientResized = oldCW != clientSize.w || oldCH != clientSize.h || force;
1637       if(clientResized && this == rootWindow && nativeDecorations && rootWindow.windowHandle)
1638          windowResized = true;
1639
1640       if(display && rootWindow != this)
1641          Update(null);
1642
1643       if(guiApp && guiApp.windowMoving)
1644       {
1645          if(guiApp.windowMoving.style.nonClient)
1646             guiApp.windowMoving.parent.SetMouseRangeToWindow();
1647          else
1648             guiApp.windowMoving.parent.SetMouseRangeToClient();
1649       }
1650
1651       if(!positioned)
1652       {
1653          positioned = true;
1654          if(clientResized)
1655          {
1656             if(!thisOnly)
1657             {
1658                // Buttons bitmap resources crash if we do this while switching mode
1659                if(!guiApp || !guiApp.modeSwitching)
1660                   UpdateNonClient();
1661
1662                // Process Anchored Children
1663                if(processAnchors)
1664                {
1665                   int x,y,w,h;
1666                   for(child = children.first; child; child = child.next)
1667                   {
1668                      if(child.created && 
1669                      ((child.stateAnchor.left.type != offset ||
1670                        child.stateAnchor.top.type != offset ||
1671                        child.stateAnchor.right.type != none ||
1672                        child.stateAnchor.bottom.type != none) ||
1673                         child.state == maximized || child.state == minimized))
1674                      {
1675                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor,
1676                            &x, &y, &w, &h);
1677                         // child.Position(x, y, w, h, false, true, true, true, false);
1678                         // This must be true cuz otherwise we're gonna miss everything since we SetPosition recursively already
1679                         child.Position(x, y, w, h, true, true, true, true, false, true /*false*/);
1680                      }
1681                   }
1682                }
1683             }
1684
1685             // Is this gonna cause other problems? Commented out for the FileDialog end bevel bug
1686             //if(updateScrollBars)
1687             if(created)
1688                OnResize(clientSize.w, clientSize.h);
1689          }
1690          if((clientResized || windowMoved) && created)
1691             OnPosition(position.x, position.y, clientSize.w, clientSize.h);
1692    /*
1693          if(guiApp.interimWindow && guiApp.interimWindow.master.rootWindow == this)
1694          {
1695             Window master = guiApp.interimWindow.master;
1696             master.OnPosition(master.position.x, master.position.y, master.clientSize.w, master.clientSize.h);
1697          }
1698    */
1699          if(rootWindow == this && !is3D)
1700          {
1701             /*if(style.interim)
1702             {
1703                x -= guiApp.desktop.absPosition.x;
1704                y -= guiApp.desktop.absPosition.y;
1705             }*/
1706             //guiApp.Log("Position %s\n", caption);
1707             if(windowHandle)
1708             {
1709                if(windowResized || windowMoved)
1710                   if(display && !display.flags.memBackBuffer && changeRootWindow)
1711                      guiApp.interfaceDriver.PositionRootWindow(this, x, y, w, h, windowMoved, windowResized); //realResized);
1712
1713                if(!guiApp.fullScreenMode && this != guiApp.desktop && (windowResized || windowMoved))
1714                   for(child = parent.children.first; child && child != this; child = child.next)
1715                      if(child.rootWindow)
1716                         guiApp.interfaceDriver.UpdateRootWindow(child.rootWindow);
1717             }
1718
1719             if(display)
1720             {
1721                if(windowMoved || windowResized)
1722                {
1723                   display.Lock(true /*false*/);
1724                }
1725                if(windowMoved)
1726                   display.Position(absPosition.x, absPosition.y);
1727                   //display.Position(absPosition.x + clientStart.x, absPosition.y + clientStart.y);
1728                if(windowResized)
1729                {
1730                   // result = realResized ? display.Resize(size.w, size.h) : true;
1731                   if(nativeDecorations && rootWindow.windowHandle)
1732                   {
1733                      int w = clientSize.w, h = clientSize.h;
1734                      if(hasMenuBar) h += skinMenuHeight;
1735                      if(hasStatusBar) h += statusBarHeight;
1736                      if(sbv && sbv.visible) w += sbv.size.w;
1737                      if(sbh && sbh.visible) h += sbh.size.h;
1738                      result = manageDisplay ? display.Resize(w, h) : true;
1739                   }
1740                   else
1741                      result = manageDisplay ? display.Resize(size.w, size.h) : true;
1742                   resized = true;
1743                   Update(null);
1744                }
1745                else if(clientResized)
1746                   Update(clientArea);
1747                // --- Major Slow Down / Fix OpenGL Resizing Main Window Lag
1748                
1749                /*
1750                if(!guiApp.fullScreenMode && !guiApp.modeSwitching && this == rootWindow)
1751                   UpdateDisplay();
1752                */
1753                
1754                if(windowMoved || windowResized)
1755                {
1756                   display.Unlock();
1757                }
1758             }
1759             if(guiApp.driver && changeRootWindow && windowHandle)
1760             {
1761                if(windowResized || windowMoved)
1762                   if(!display || display.flags.memBackBuffer)
1763                      guiApp.interfaceDriver.PositionRootWindow(this, 
1764                         x, y, w, h, windowMoved, windowResized);
1765                guiApp.interfaceDriver.UpdateRootWindow(this);
1766             }
1767             for(child = children.first; child; child = child.next)
1768             {
1769                if(child.is3D && child.created)
1770                {
1771                   // Copy Display Content
1772                   child.display.displaySystem = display.displaySystem;
1773                   child.display.window = display.window;
1774                   child.display.current = display.current;
1775                   child.display.width = display.width;
1776                   child.display.height = display.height;
1777                   child.display.driverData = display.driverData;
1778                   child.display.mutex = null;
1779                }
1780             }
1781          }
1782          else
1783             result = true;
1784          positioned = false;
1785       }
1786       return result;
1787    }
1788
1789    void UpdateScrollBars(bool flag, bool fullThing)
1790    {
1791       int rvw, rvh;
1792       bool resizeH = false, resizeV = false;
1793       bool scrolled = false;
1794       rvw = (activeChild && activeChild.state == maximized) ? 0 : reqScrollArea.w;
1795       rvh = (activeChild && activeChild.state == maximized) ? 0 : reqScrollArea.h;
1796
1797       if(destroyed) return;
1798       if(guiApp.currentSkin)
1799       {
1800          MinMaxValue cw = 0, ch = 0;
1801          bool sbvVisible, sbhVisible;
1802          int rangeH, rangeV;
1803          int positionH, positionV;
1804
1805          // First get client area with no respect to scroll bars
1806
1807          if(flag)
1808          {
1809             SetWindowArea(
1810                &clientStart.x, &clientStart.y, &size.w, &size.h, &cw, &ch);
1811
1812             if(scrollFlags.dontHide)
1813             {
1814                if(sbv)
1815                   cw -= guiApp.currentSkin.VerticalSBW();
1816                if(sbh)
1817                   ch -= guiApp.currentSkin.HorizontalSBH();
1818
1819                // Update the scrollbar visibility
1820                if(sbh)
1821                {
1822                   sbh.seen = cw;
1823                   sbh.total = rvw;
1824                   rangeH = sbh.range;
1825                   sbh.disabled = rangeH <= 1;
1826                   if(sbh.style.hidden)
1827                   {
1828                      resizeH = true;
1829                   }
1830                }
1831                if(sbv)
1832                {
1833                   sbv.seen = ch;
1834                   sbv.total = rvh;
1835                   rangeV = sbv.range;
1836                   sbv.disabled = rangeV <= 1;
1837                   if(sbv.style.hidden)
1838                   {
1839                      resizeV = true;
1840                   }
1841                }
1842             }
1843             else
1844             {
1845                int oldHRange = sbh ? sbh.range : 0;
1846                int oldVRange = sbv ? sbv.range : 0;
1847                // Then start off with horizontal scrollbar range
1848                if(sbh)
1849                {
1850                   positionH = sbh.thumbPosition;
1851
1852                   /*
1853                   sbh.seen = cw;
1854                   sbh.total = rvw;
1855                   */
1856                   SBSetSeen(sbh, cw);
1857                   SBSetTotal(sbh, rvw);
1858                   rangeH = sbh.range;
1859                   if(rangeH > 1)
1860                      ch -= guiApp.currentSkin.HorizontalSBH();
1861                }
1862
1863                // Do the same for vertical scrollbar
1864                if(sbv)
1865                {
1866                   positionV = sbv.thumbPosition;
1867                   /*
1868                   sbv.seen = ch;
1869                   sbv.total = rvh;
1870                   */
1871                   SBSetSeen(sbv, ch);
1872                   SBSetTotal(sbv, rvh);
1873                   rangeV = sbv.range;
1874                   if(rangeV > 1)
1875                   {
1876                      cw -= guiApp.currentSkin.VerticalSBW();
1877                      // Maybe we need to set the range on the horizontal scrollbar again
1878                      if(sbh)
1879                      {
1880                         /*
1881                         sbh.seen = cw;
1882                         sbh.total = rvw;
1883                         */
1884                         SBSetSeen(sbh, cw);
1885                         SBSetTotal(sbh, rvw);
1886                         //sbh.Action(setRange, positionH, 0);
1887                         if(rangeH <= 1 && sbh.range > 1)
1888                         {
1889                            ch -= guiApp.currentSkin.HorizontalSBH();
1890                            /*
1891                            sbv.seen = ch;
1892                            sbv.total = rvh;
1893                            */
1894                            SBSetSeen(sbv, ch);
1895                            SBSetTotal(sbv, rvh);
1896                            rangeV = sbv.range;
1897                            //sbv.Action(setRange, positionV, 0);
1898                         }
1899                         rangeH = sbh.range;
1900                      }
1901                   }
1902                   if(sbh && sbh.range != oldHRange) sbh.Action(setRange, positionH, 0);
1903                   if(sbv && sbv.range != oldVRange) sbv.Action(setRange, positionV, 0);
1904                }
1905
1906                // Update the scrollbar visibility
1907                if(!scrollFlags.dontHide)
1908                {
1909                   if(sbh && ((rangeH <= 1 && !sbh.style.hidden) || (rangeH > 1 && sbh.style.hidden)))
1910                   {
1911                      resizeH = true;
1912                   }
1913                   if(sbv && ((rangeV <= 1 && !sbv.style.hidden) || (rangeV > 1 && sbv.style.hidden)))
1914                   {
1915                      resizeV = true;
1916                   }
1917                }
1918             }
1919
1920             if(guiApp.currentSkin)
1921             {
1922                clientSize.w = cw;
1923                clientSize.h = ch;
1924             }
1925
1926             if(resizeH)
1927                sbhVisible = sbh.style.hidden ? true : false;
1928             if(resizeV)
1929                sbvVisible = sbv.style.hidden ? true : false;
1930
1931             // Do our resize here
1932             if(flag && (resizeH || resizeV) && fullThing)
1933             {
1934                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, false);
1935                
1936                if(!positioned)
1937                {
1938                   positioned = true;
1939                   OnResize(clientSize.w, clientSize.h);
1940                   positioned = false;
1941                }
1942             }
1943       
1944             if(resizeH && sbh)
1945                sbh.visible = sbhVisible;
1946             if(resizeV && sbv)
1947                sbv.visible = sbvVisible;
1948          }
1949          scrollArea.w = Max(clientSize.w, reqScrollArea.w);
1950          scrollArea.h = Max(clientSize.h, reqScrollArea.h);
1951
1952          if(sbh)
1953             sbh.pageStep = clientSize.w;
1954          if(sbv)
1955             sbv.pageStep = clientSize.h;
1956
1957          // Notify doesn't handle setRange anymore... process it here
1958          if(sbh)
1959          {
1960             int positionH = sbh.thumbPosition;
1961             if(scroll.x != positionH)
1962             {
1963                OnHScroll(setRange, positionH, 0);
1964                scrolled = true;
1965             }
1966             if(guiApp.textMode)
1967                SNAPDOWN(positionH, textCellW);
1968             scroll.x = positionH;
1969          }
1970          else
1971          {
1972             int x = scroll.x;
1973             int range;
1974             int seen = clientSize.w, total = reqScrollArea.w;
1975             seen = Max(1,seen);
1976
1977             if(scrollFlags.snapX)
1978                SNAPDOWN(seen, sbStep.x);
1979
1980             if(!total) total = seen;
1981             range = total - seen + 1;
1982
1983             range = Max(range, 1);
1984             if(x < 0) x = 0;
1985             if(x >= range) x = range - 1;
1986
1987             if(scrollFlags.snapX)
1988                SNAPUP(x, sbStep.x);
1989
1990             if(scroll.x != x)
1991             {
1992                OnHScroll(setRange, x, 0);
1993             }
1994
1995             if(guiApp.textMode)
1996             {
1997                SNAPDOWN(x, textCellW);
1998             }
1999             scroll.x = x;
2000          }
2001          if(sbv)
2002          {
2003             int positionV = sbv.thumbPosition;
2004             if(scroll.y != positionV)
2005             {
2006                OnVScroll(setRange, positionV, 0);
2007                scrolled = true;
2008             }
2009             if(guiApp.textMode)
2010                SNAPDOWN(positionV, textCellH);
2011             scroll.y = positionV;
2012          }
2013          else
2014          {
2015             int y = scroll.y;
2016             int range;
2017             int seen = clientSize.h, total = reqScrollArea.h;
2018             seen = Max(1,seen);
2019
2020             if(scrollFlags.snapY)
2021                SNAPDOWN(seen, sbStep.y);
2022
2023             if(!total) total = seen;
2024             range = total - seen + 1;
2025             range = Max(range, 1);
2026             if(y < 0) y = 0;
2027             if(y >= range) y = range - 1;
2028
2029             if(scrollFlags.snapY)
2030                SNAPUP(y, sbStep.y);
2031
2032             if(scroll.y != y)
2033             {
2034                OnVScroll(setRange, y, 0);
2035             }
2036
2037             if(guiApp.textMode)
2038             {
2039                SNAPDOWN(y, textCellH);
2040             }
2041             scroll.y = y;
2042          }
2043
2044          /*
2045          if(scrolled || (resizeH || resizeV))   // This ensures children anchored to bottom/right gets repositioned correctly
2046          {
2047             Window child;
2048             for(child = children.first; child; child = child.next)
2049             {
2050                if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2051                {
2052                   int x,y,w,h;
2053                   child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
2054                   child.Position(x, y, w, h, false, true, false, true, false, false);
2055                }
2056             }
2057          }
2058          */
2059       }
2060
2061       // Process Scrollbars
2062
2063       if(sbh) // && !sbh.style.hidden
2064       {
2065          if(!sbh.anchored)
2066             sbh.Move(clientStart.x, clientStart.y + clientSize.h, clientSize.w,0);
2067          // Need to set the range again (should improve...) since the scrollbars didn't have
2068          // the right size when UpdateScrollArea set the range on it
2069          if(flag)
2070          {
2071             sbh.seen = clientSize.w;
2072             sbh.total = rvw;
2073          }
2074       }
2075       if(sbv) // && !sbv.state.hidden
2076       {
2077          if(!sbv.anchored)
2078             sbv.Move(clientStart.x + clientSize.w, clientStart.y, 0, clientSize.h);
2079          // Need to set the range again (should improve...) since the scrollbars didn't have
2080          // the right size when UpdateScrollArea set the range on it
2081          if(flag)
2082          {
2083             sbv.seen = clientSize.h;
2084             sbv.total = rvh;
2085          }
2086       }
2087
2088       // TESTING THIS LOWER
2089       if(scrolled || (resizeH || resizeV))   // This ensures children anchored to bottom/right gets repositioned correctly
2090       {
2091          Window child;
2092          for(child = children.first; child; child = child.next)
2093          {
2094             if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2095             {
2096                int x,y,w,h;
2097                child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
2098                child.Position(x, y, w, h, false, true, false, true, false, false);
2099             }
2100          }
2101       }
2102    }
2103
2104    bool MaximizeButtonClicked(Button button, int x, int y, Modifiers mods)
2105    {
2106       SetState(maximized, false, mods);
2107       return false;
2108    }
2109
2110    bool RestoreButtonClicked(Button button, int x, int y, Modifiers mods)
2111    {
2112       SetState(normal, false, mods);
2113       return false;
2114    }
2115
2116    bool MinimizeButtonClicked(Button button, int x, int y, Modifiers mods)
2117    {
2118       SetState(minimized, false, mods);
2119       parent.CycleChildren(false, true, false, true);
2120       return false;
2121    }
2122
2123    void ScrollBarNotification(ScrollBar control, ScrollBarAction action, int position, Key keyFlags)
2124    {
2125       Window child;
2126       // Scroll bar notifications
2127       if(action != setRange)
2128       {
2129          bool changed = false;
2130
2131          if(control == sbh)
2132          {
2133             if(scroll.x != position)
2134             {
2135                OnHScroll(action, position, keyFlags);
2136                changed = true;
2137             }
2138             if(guiApp.textMode)
2139             {
2140                SNAPDOWN(position, textCellW);
2141             }
2142             scroll.x = position;
2143          }
2144          else
2145          {
2146             if(scroll.y != position)
2147             {
2148                OnVScroll(action, position, keyFlags);
2149                changed = true;
2150             }
2151             if(guiApp.textMode)
2152             {
2153                SNAPDOWN(position, textCellH);
2154             }
2155             scroll.y = position;
2156          }
2157          if(changed)
2158          {
2159             bool childMove = false;
2160             for(child = children.first; child; child = child.next)
2161             {
2162                if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2163                {
2164                   int x,y,w,h;
2165                   child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
2166                   child.Position(x, y, w, h, false, true, false, true, false, false);
2167                   childMove = true;
2168                }
2169             }
2170             // Testing this patch out to solve MDI workspace redraw bugs
2171             // We were already supposed to be updating parent's affected area in Position() but it doesn't seem to be working
2172             // Scroll offsets to blame?
2173             if(childMove)
2174                Update(null);
2175          }
2176          UpdateCaret(false, false);
2177       }
2178       else
2179       {
2180          // Testing this patch out to solve MDI workspace redraw bugs
2181          for(child = children.first; child; child = child.next)
2182          {
2183             if(!child.style.nonClient && child.state != maximized && (!child.style.dontScrollHorz || !child.style.dontScrollVert))
2184             {
2185                Update(null);
2186                break;
2187             }
2188          }         
2189       }
2190    }
2191
2192    Window GetParentMenuBar()
2193    {
2194       Window result = this;
2195       bool notActiveClient = false;
2196       Window menuBarParent;
2197       for(menuBarParent = this; menuBarParent; menuBarParent = menuBarParent.parent)
2198       {
2199          if(menuBarParent.menuBar) { result = notActiveClient ? null : menuBarParent.menuBar; break; }
2200          if(menuBarParent.parent && /*menuBarParent != */!menuBarParent.parent.activeClient)
2201             notActiveClient = true;
2202       }
2203       return result;
2204    }
2205
2206    void CreateSystemChildren(void)
2207    {
2208       Window parent = this;
2209       bool scrollBarChanged = false;
2210       bool hasClose = false, hasMaxMin = false;
2211       Point scroll = this.scroll;
2212
2213       if(state == maximized)
2214          parent = GetParentMenuBar();
2215
2216       if(parent)
2217       {
2218          if(style.hasClose) hasClose = true;
2219          if(style.hasMaximize || style.hasMinimize)
2220          {
2221             hasClose = true;
2222             hasMaxMin = true;
2223          }
2224       }
2225
2226       if(sysButtons[2] && (!hasClose || sysButtons[2].parent != parent))
2227       {
2228          sysButtons[2].Destroy(0);
2229          sysButtons[2] = null;
2230       }
2231       if(sysButtons[1] && (!hasMaxMin || sysButtons[1].parent != parent))
2232       {
2233          sysButtons[1].Destroy(0);
2234          sysButtons[1] = null;
2235       }
2236       if(sysButtons[0] && (!hasMaxMin || sysButtons[0].parent != parent))
2237       {
2238          sysButtons[0].Destroy(0);
2239          sysButtons[0] = null;
2240       }
2241       //return;
2242       if(hasClose && parent)
2243       {
2244          if(!sysButtons[2])
2245          {
2246             sysButtons[2] = 
2247                Button
2248                {
2249                   parent, master = this,
2250                   inactive = true, nonClient = true, visible = false;
2251
2252                   bool NotifyClicked(Button button, int x, int y, Modifiers mods)
2253                   {
2254                      Destroy(0);
2255                      return true;
2256                   }
2257                };
2258             if(this.parent == guiApp.desktop)
2259                sysButtons[2].hotKey = altF4;
2260             else if(style.isActiveClient)
2261                sysButtons[2].hotKey = ctrlF4;
2262             sysButtons[2].Create();
2263          }
2264          
2265          sysButtons[2].symbol = 'X';
2266          sysButtons[2].disabled = !style.hasClose;
2267       }
2268
2269       if(hasMaxMin && parent)
2270       {
2271          SkinBitmap skin;
2272          unichar symbol;
2273          bool (* method)(Window window, Button button, int x, int y, Modifiers mods);
2274          if(state == maximized) 
2275          {
2276             skin = restore;
2277             method = RestoreButtonClicked;
2278             symbol = '\x12';
2279          }
2280          else
2281          {
2282             skin = maximize;
2283             method = MaximizeButtonClicked;
2284             symbol = '\x18';
2285          }
2286          if(!sysButtons[1])
2287          {
2288             sysButtons[1] =
2289                Button
2290                {
2291                   parent, master = this,
2292                   hotKey = altEnter, inactive = true, nonClient = true, visible = false
2293                };
2294             sysButtons[1].Create();
2295          }
2296          sysButtons[1].NotifyClicked = method;
2297
2298          sysButtons[1].symbol = symbol;
2299          sysButtons[1].disabled = !style.hasMaximize;
2300       }
2301
2302       if(hasMaxMin && parent)
2303       {
2304          SkinBitmap skin;
2305          unichar symbol;
2306          bool (* method)(Window window, Button button, int x, int y, Modifiers mods);
2307          if (state == minimized) 
2308          {
2309             skin = restore;
2310             method = RestoreButtonClicked;
2311             symbol = '\x12';
2312          }
2313          else
2314          {
2315             skin = minimize;
2316             method = MinimizeButtonClicked;
2317             symbol = '\x19';
2318          }
2319          if(!sysButtons[0])
2320          {
2321             sysButtons[0] =
2322                Button
2323                {
2324                   parent, master = this,
2325                   hotKey = altM, inactive = true, nonClient = true, visible = false
2326                };
2327             sysButtons[0].Create();
2328          }
2329          sysButtons[0].NotifyClicked = method;
2330
2331          sysButtons[0].symbol = symbol;
2332          sysButtons[0].disabled = !style.hasMinimize;
2333       }
2334
2335       // Create the scrollbars
2336       if(style.hasHorzScroll && !sbh)
2337       {
2338          sbh =
2339             ScrollBar
2340             {
2341                this,
2342                direction = horizontal,
2343                windowOwned = true,
2344                inactive = true,
2345                nonClient = true,
2346                snap = scrollFlags.snapX,
2347                NotifyScrolling = ScrollBarNotification
2348             };
2349          sbh.Create();
2350          scrollBarChanged = true;
2351       }
2352       else if(sbh && !style.hasHorzScroll)
2353       {
2354          sbh.Destroy(0);
2355          sbh = null;
2356       }
2357
2358       if(style.hasVertScroll && !sbv)
2359       {
2360          sbv =
2361             ScrollBar
2362             {
2363                this,
2364                direction = vertical,
2365                windowOwned = true,
2366                inactive = true,
2367                nonClient = true,
2368                snap = scrollFlags.snapY,
2369                NotifyScrolling = ScrollBarNotification
2370             };
2371          sbv.Create();
2372          scrollBarChanged = true;
2373       }
2374       else if(sbv && !style.hasVertScroll)
2375       {
2376          sbv.Destroy(0);
2377          sbv = null;
2378       }
2379       if(scrollBarChanged)
2380       {
2381          SetScrollLineStep(sbStep.x, sbStep.y);   
2382          UpdateScrollBars(true, true);
2383       }   
2384       UpdateNonClient();
2385
2386       if(scrollBarChanged)
2387       {
2388          if(sbh) sbh.thumbPosition = scroll.x;
2389          if(sbv) sbv.thumbPosition = scroll.y;
2390       }
2391    }
2392
2393    void UpdateCaption(void)
2394    {
2395       if(rootWindow == this)
2396       {
2397          char caption[2048];
2398          FigureCaption(caption);
2399          guiApp.interfaceDriver.SetRootWindowCaption(this, caption);
2400       }
2401       UpdateDecorations();
2402       if(parent)
2403       {
2404          if(parent.activeClient == this) // Added this last check
2405          {
2406             if(parent.rootWindow == parent)
2407             {
2408                char caption[2048];
2409                parent.FigureCaption(caption);
2410                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
2411             }
2412             else
2413                parent.UpdateCaption();
2414          }
2415          parent.UpdateDecorations();
2416       }
2417    }
2418
2419    void UpdateActiveDocument(Window previous)
2420    {
2421       Window activeClient = this.activeClient;
2422       Window activeChild = this.activeChild;
2423       if(menuBar)
2424       {
2425          UpdateCaption();
2426          if(!destroyed)
2427          {
2428             if(activeClient)
2429                activeClient.CreateSystemChildren();
2430             if(previous)
2431                previous.CreateSystemChildren();
2432          }
2433       }
2434
2435       if(menu)
2436       {
2437          MenuItem item;
2438          bool disabled;
2439
2440          if(menu)
2441             menu.Clean(this);
2442
2443          // Build window list
2444          if(activeClient)
2445          {
2446             Menu windowMenu = menu.FindMenu("Window");
2447             if(windowMenu)
2448             {
2449                OldLink cycle;
2450                int id;
2451                for(id = 0, cycle = activeClient.cycle; cycle && id<10;)
2452                {
2453                   MenuItem item;
2454                   Window document = cycle.data;
2455                   if(!document.style.nonClient && document.style.isActiveClient && document.visible)
2456                   {
2457                      char name[2048], caption[2048];
2458                      document.FigureCaption(caption);
2459                      sprintf(name, "%d %s", id+1, caption);
2460                      windowMenu.AddDynamic(MenuItem 
2461                         { 
2462                            copyText = true, text = name, hotKey = Key { k1 + id }, id = id++, 
2463                            NotifySelect = MenuWindowSelectWindow 
2464                         }, this, false);
2465                   }
2466                   cycle = cycle.next;
2467                   if(activeClient.cycle == cycle) break;
2468                }
2469             }
2470          }
2471          
2472          if((!previous && activeClient) || !activeClient)
2473          {
2474             if(!activeClient)
2475                disabled = true;
2476             else
2477                disabled = false;
2478             item = menu.FindItem(MenuWindowCloseAll, 0);
2479             if(item) item.disabled = false;
2480             item = menu.FindItem(MenuWindowNext, 0);
2481             if(item) item.disabled = false;
2482             item = menu.FindItem(MenuWindowPrevious, 0);
2483             if(item) item.disabled = false;
2484             item = menu.FindItem(MenuWindowCascade, 0);
2485             if(item) item.disabled = false;
2486             item = menu.FindItem(MenuWindowTileHorz, 0);
2487             if(item) item.disabled = false;
2488             item = menu.FindItem(MenuWindowTileVert, 0);
2489             if(item) item.disabled = false;
2490             item = menu.FindItem(MenuWindowArrangeIcons, 0);
2491             if(item) item.disabled = false;
2492             item = menu.FindItem(MenuWindowWindows, 0);
2493             if(item) item.disabled = false;
2494          }      
2495
2496          item = menu.FindItem(MenuFileClose, 0);
2497          if(item) item.disabled = !activeClient || !activeClient.style.hasClose;
2498          item = menu.FindItem(MenuFileSaveAll, 0);
2499          if(item) item.disabled = numDocuments < 1;
2500
2501          if(activeClient && activeClient.menu && activeClient.state != minimized)
2502          {
2503             if(mergeMenus)
2504             {
2505                //activeClient.menu.Clean(activeClient);
2506                menu.Merge(activeClient.menu, true, activeClient);
2507             }
2508          }
2509
2510          if(activeChild && activeChild != activeClient && activeChild.menu && activeChild.state != minimized)
2511          {
2512             if(mergeMenus)
2513                menu.Merge(activeChild.menu, true, activeChild);
2514          }
2515       }
2516       // This is called again for a child window change, with same active client
2517       OnActivateClient(activeClient, previous);
2518       if(!menuBar && !((BorderBits)borderStyle).fixed && parent && parent.activeClient == this)
2519          parent.UpdateActiveDocument(null);
2520    }
2521
2522    void _ShowDecorations(Box box, bool post)
2523    {
2524       if(rootWindow == this && nativeDecorations) return;
2525       if(visible && this != guiApp.desktop)
2526       {
2527          Surface surface = RedrawFull(box);
2528          if(surface)
2529          {
2530             char caption[2048];
2531             FigureCaption(caption);
2532             
2533             if(post)
2534                ShowDecorations(captionFont.font,
2535                   surface,
2536                   caption,
2537                   active, //parent.activeClient == this
2538                   guiApp.windowMoving == this);
2539             else
2540                PreShowDecorations(captionFont.font,
2541                   surface,
2542                   caption,
2543                   active, //parent.activeClient == this
2544                   guiApp.windowMoving == this);
2545                
2546             delete surface;
2547          }
2548       }
2549    }
2550
2551    void UpdateExtent(Box refresh)
2552    {
2553       Surface surface = null;
2554
2555       if(!manageDisplay) { OnRedraw(null);return; }
2556       _ShowDecorations(refresh, false);
2557
2558       surface = Redraw(refresh);               
2559       // Opaque background: just fill before EW_REDRAW (clear?)
2560       if(surface) 
2561       {
2562          surface.SetBackground(background);
2563          surface.SetForeground(foreground);
2564          surface.DrawingChar(' ');
2565          if(this == rootWindow)
2566          {
2567             if(style.drawBehind || background.a)
2568             {
2569                int a = background.a;
2570                // Premultiply alpha for clear color
2571                surface.SetBackground({ (byte)a, { (byte)(a*background.color.r/255), (byte)(a*background.color.g/255), (byte)(a*background.color.b/255) } });
2572                surface.Clear(colorBuffer);
2573                surface.SetBackground(background);
2574             }
2575          }
2576          else if(background.a)
2577          {
2578 #ifdef _DEBUG
2579             /*
2580             background.color = { (byte)GetRandom(0,255), (byte)GetRandom(0,255), (byte)GetRandom(0,255) };
2581             surface.SetForeground((background.color.r > 128 || background.color.g > 128) ? black : white);
2582             */
2583 #endif
2584             if(display.flags.alpha && background.a < 255 && background)
2585             {
2586                surface.Area(0,0,clientSize.w, clientSize.h);
2587                /*if(style.clearDepthBuffer)
2588                   surface.Clear(depthBuffer);*/
2589             }
2590             else if(/*style.clearDepthBuffer || */background.a)
2591             {
2592                int a = background.a;
2593                // surface.Clear((style.clearDepthBuffer ? depthBuffer : 0) | (background.a ? colorBuffer : 0));
2594                // Premultiply alpha for clear color
2595                surface.SetBackground({ (byte)a, { (byte)(a*background.color.r/255), (byte)(a*background.color.g/255), (byte)(a*background.color.b/255) } });
2596                surface.Clear(colorBuffer);
2597                surface.SetBackground(background);
2598             }
2599          }
2600
2601          // Default Settings
2602          surface.TextFont(usedFont.font);
2603          surface.TextOpacity(false);
2604
2605          OnRedraw(surface);
2606
2607          // Draw the caret ...
2608          if(!disabled && this == guiApp.caretOwner && guiApp.caretEnabled /*&& !guiApp.interimWindow*/ && !guiApp.currentSkin.textMode)
2609          {
2610             // surface.SetBackground(0xFFFFFF - background.color);
2611             surface.SetBackground(~background.color);
2612             surface.Area(
2613                caretPos.x - scroll.x + 1, caretPos.y - scroll.y,
2614                caretPos.x - scroll.x + 2, caretPos.y - scroll.y + caretSize - 1);
2615          }
2616          delete surface;
2617       }
2618    }
2619
2620    void DrawOverChildren(Box refresh)
2621    {
2622       Surface surface = Redraw(refresh);               
2623       if(surface) 
2624       {
2625          // Default Settings
2626          surface.DrawingChar(' ');
2627          surface.SetBackground(background);
2628          surface.SetForeground(foreground);
2629
2630          surface.TextFont(usedFont.font);
2631          surface.TextOpacity(false);
2632
2633          OnDrawOverChildren(surface);
2634
2635          delete surface;
2636
2637       }
2638       _ShowDecorations(refresh, true);
2639    }
2640
2641    void ComputeClipExtents(void)
2642    {
2643       Window child;
2644       Extent clipExtent { /*first = -1, last = -1, free = -1*/ };
2645
2646       clipExtent.Copy(this.clipExtent);
2647       
2648       for(child = children.last; child; child = child.prev)
2649       {
2650          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2651          {
2652             bool opaque = child.IsOpaque(); // TODO: acess background directly 
2653             int dx = child.absPosition.x - absPosition.x, dy = child.absPosition.y - absPosition.y;
2654
2655             child.clipExtent.Copy(clipExtent);
2656             child.clipExtent.Offset(-dx, -dy);
2657             child.clipExtent.IntersectBox(child.box);
2658
2659             child.ComputeClipExtents();
2660
2661             if(opaque && !child.style.nonClient)
2662             {
2663                // Adjust the box for the parent:
2664                Box box { child.box.left + dx, child.box.top + dy, child.box.right + dx, child.box.bottom + dy };
2665                clipExtent.ExcludeBox(box, rootWindow.tempExtents[0]);
2666             }
2667             
2668          }
2669       }
2670       // ??? Only do this for overlapped window or if parent has with clip children flag
2671
2672       // Do this if window has clip children flag on (default false?)
2673       // this.clipExtent = clipExtent;
2674
2675       clipExtent.Free(null);
2676    }
2677
2678    void ComputeRenderAreaNonOpaque(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate)
2679    {
2680       bool opaque = IsOpaque();
2681       Window child;
2682       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2683       if(rootWindow.nativeDecorations && rootWindow.windowHandle)
2684       {
2685          offsetX -= rootWindow.clientStart.x;
2686          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2687       }
2688
2689
2690       for(child = children.last; child; child = child.prev)
2691       {
2692          ColorAlpha background = *(ColorAlpha *)&child.background;
2693          bool opaque = child.IsOpaque();
2694          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2695          {
2696             if(!opaque)
2697             {
2698                // Adjust renderArea to the root window level
2699                Extent * renderArea = &rootWindow.tempExtents[1];
2700
2701                int offsetX = child.absPosition.x - rootWindow.absPosition.x, offsetY = child.absPosition.y - rootWindow.absPosition.y;
2702                if(child.rootWindow.nativeDecorations && rootWindow.windowHandle)
2703                {
2704                   offsetX -= child.rootWindow.clientStart.x;
2705                   offsetY -= child.rootWindow.clientStart.y - (child.rootWindow.hasMenuBar ? skinMenuHeight : 0);
2706                }
2707
2708                /*
2709                Extent childRenderArea;
2710                
2711                if(backBufferUpdate != null)
2712                {
2713                   childRenderArea.Copy(backBufferUpdate);
2714                   childRenderArea.Offset(-offsetX, -offsetY);
2715                }
2716                else
2717                   childRenderArea.Copy(child.dirtyArea);
2718
2719                // Add extent forced by transparency to the dirty area, adjusting dirty extent to the window
2720                renderArea.Copy(dirtyExtent);
2721                renderArea.Offset(-offsetX, -offsetY);
2722                childRenderArea.Union(renderArea);
2723                renderArea.Free();
2724
2725                // Intersect with the clip extent
2726                childRenderArea.Intersection(child.clipExtent);
2727                */
2728
2729                renderArea->Copy(child.dirtyArea /*childRenderArea*/);
2730                renderArea->Offset(offsetX, offsetY);
2731                dirtyExtent.Union(renderArea, rootWindow.tempExtents[0]);
2732                // overDirtyExtent.Union(renderArea);
2733                renderArea->Empty();
2734                // childRenderArea.Free();
2735
2736                //child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2737             }
2738          }
2739       }
2740
2741       for(child = children.last; child; child = child.prev)
2742       {
2743          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2744          {
2745             child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2746          }
2747       }
2748    }
2749
2750    void ComputeRenderArea(Extent dirtyExtent, Extent overDirtyExtent, Extent backBufferUpdate)
2751    {
2752       bool opaque = IsOpaque();
2753       Extent * dirtyExtentWindow = &rootWindow.tempExtents[1];
2754       Window child;
2755       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2756       if(rootWindow.nativeDecorations && rootWindow.windowHandle)
2757       {
2758          offsetX -= rootWindow.clientStart.x;
2759          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2760       }
2761
2762 #if 0
2763       for(child = children.last; child; child = child.prev)
2764       {
2765          //child.ComputeRenderAreaNonOpaque(dirtyExtent, overDirtyExtent, backBufferUpdate);
2766          /*
2767          ColorAlpha background = *(ColorAlpha *)&child.background;
2768          bool opaque = child.IsOpaque();
2769          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2770          {
2771             if(!opaque)
2772             {
2773                int offsetX = child.absPosition.x - rootWindow.absPosition.x, offsetY = child.absPosition.y - rootWindow.absPosition.y;
2774                // Adjust renderArea to the root window level
2775                Extent renderArea;
2776                renderArea.Copy(child.dirtyArea);
2777                renderArea.Offset(offsetX, offsetY);
2778                dirtyExtent.Union(renderArea);
2779                overDirtyExtent.Union(renderArea);
2780                renderArea.Free();
2781             }
2782          }*/
2783       }
2784 #endif
2785       for(child = children.last; child; child = child.prev)
2786       {
2787          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow)
2788          {
2789             child.ComputeRenderArea(dirtyExtent, overDirtyExtent, backBufferUpdate);
2790          }
2791       }
2792
2793       if(backBufferUpdate != null)
2794       {
2795          renderArea.Copy(backBufferUpdate);
2796          renderArea.Offset(-offsetX, -offsetY);
2797          
2798          overRenderArea.Copy(backBufferUpdate);
2799          overRenderArea.Offset(-offsetX, -offsetY);
2800          
2801          
2802       }
2803       else
2804       {
2805          renderArea.Copy(dirtyArea);
2806          
2807          overRenderArea.Copy(dirtyArea);
2808       }
2809
2810       // Add extent forced by transparency to the dirty area, adjusting dirty extent to the window
2811       dirtyExtentWindow->Copy(dirtyExtent);
2812       dirtyExtentWindow->Offset(-offsetX, -offsetY);
2813       renderArea.Union(dirtyExtentWindow, rootWindow.tempExtents[0]);
2814       dirtyExtentWindow->Empty();
2815
2816       // Intersect with the clip extent
2817       renderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2818
2819       /*
2820       if(renderArea.count > 10)
2821       {
2822          BoxItem extentBox;
2823          printf("\nToo many extents (%d):\n", renderArea.count);
2824
2825          //extent.UnionBox({ 112, 6, 304, 7 }, rootWindow.tempExtents[0]);
2826          //extent.UnionBox({ 112, 8, 304, 17 }, rootWindow.tempExtents[0]);
2827          //printf("Test\n");
2828
2829          {
2830             int c;
2831             for(c = 0; c<10; c++)
2832             {
2833                Extent extent { };
2834                FASTLIST_LOOP(renderArea, extentBox)
2835                {
2836                   extent.UnionBox(extentBox.box, rootWindow.tempExtents[0]);
2837                }
2838                renderArea.Copy(extent);
2839
2840                FASTLIST_LOOP(renderArea, extentBox)
2841                {
2842       #ifdef _DEBUG
2843                   printf("(%d, %d) - (%d, %d)\n", 
2844                      extentBox.box.left, extentBox.box.top, 
2845                      extentBox.box.right, extentBox.box.bottom);
2846       #endif
2847                }
2848
2849                printf("\nNow %d\n", renderArea.count);
2850             }
2851          }
2852       }
2853       */
2854       
2855       // WHY WAS THIS COMMENTED ??
2856
2857       // Add extent forced by DrawOverChildren to the dirty area, adjusting dirty extent to the window
2858       dirtyExtentWindow->Copy(overDirtyExtent);
2859       dirtyExtentWindow->Offset(-offsetX, -offsetY);
2860       overRenderArea.Union(dirtyExtentWindow, rootWindow.tempExtents[0]);
2861       dirtyExtentWindow->Empty();
2862
2863       // Intersect with the clip extent
2864       overRenderArea.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2865       
2866
2867       if(opaque)
2868       {
2869          // Scrolling
2870          if(scrollExtent.count)
2871          {
2872             // Subtract render extent from scrolling extent
2873             scrollExtent.Exclusion(renderArea, rootWindow.tempExtents[0]);
2874
2875             if(backBufferUpdate == null)
2876             {
2877                Extent * dirty = &rootWindow.tempExtents[3];
2878                BoxItem scrollBox;
2879
2880                // Intersect scrolling extent with clip extent
2881                scrollExtent.Intersection(clipExtent, rootWindow.tempExtents[0], rootWindow.tempExtents[1], rootWindow.tempExtents[2]);
2882
2883                // offset this scroll to be at the root window level
2884                scrollExtent.Offset(offsetX, offsetY);
2885                // Add area that was scrolled to the dirty extents of the back buffer
2886                rootWindow.dirtyBack.Union(scrollExtent, rootWindow.tempExtents[0]);
2887
2888                dirty->Empty();
2889
2890                // Will need scrolledArea.x & scrolledArea.y to support multiple scrolls
2891                for(scrollBox = (BoxItem)scrollExtent.first; scrollBox; scrollBox = (BoxItem)scrollBox.next)
2892                   display.Scroll(scrollBox.box, scrolledArea.x, scrolledArea.y, dirty);
2893
2894                scrolledArea.x = 0;
2895                scrolledArea.y = 0;
2896
2897                scrollExtent.Empty();
2898
2899                // Add the exposed extent to the window render area
2900                dirty->Offset(-offsetX, -offsetY);
2901                renderArea.Union(dirty, rootWindow.tempExtents[0]);
2902                dirty->Empty();
2903             }
2904          }
2905
2906          // Subtract the window's box from the transparency forced extent
2907          dirtyExtent.ExcludeBox({box.left + offsetX, box.top + offsetY, box.right + offsetX, box.bottom + offsetY }, rootWindow.tempExtents[0]);
2908       }
2909       /*else
2910       {
2911          Extent renderArea;
2912
2913          renderArea.Copy(this.renderArea);
2914          renderArea.Offset(offsetX, offsetY);
2915          dirtyExtent.Union(renderArea);
2916          renderArea.Free();
2917       }*/
2918       
2919       
2920       {
2921          Extent renderArea { };
2922          
2923          renderArea.Copy(overRenderArea);
2924          renderArea.Offset(offsetX, offsetY);
2925          overDirtyExtent.Union(renderArea, rootWindow.tempExtents[0]);
2926          renderArea.Empty();
2927       }
2928       
2929
2930       if(backBufferUpdate != null)
2931       {
2932          // Remove render area from dirty area
2933          dirtyArea.Exclusion(renderArea, rootWindow.tempExtents[0]);
2934
2935          dirtyArea.Exclusion(overRenderArea, rootWindow.tempExtents[0]);
2936       }
2937       else
2938          dirtyArea.Empty();
2939
2940       clipExtent.Empty();
2941    /*
2942       // Remove the window render area from the dirty extents of the back buffer
2943       rootWindow.dirtyBack.Exclusion(renderArea);
2944    */
2945    }
2946
2947    void Render(Extent updateExtent)
2948    {
2949       BoxItem extentBox;
2950       Window child;
2951       Window rootWindow = this.rootWindow;
2952       int offsetX = absPosition.x - rootWindow.absPosition.x, offsetY = absPosition.y - rootWindow.absPosition.y;
2953       if(rootWindow.nativeDecorations && rootWindow.windowHandle)
2954       {
2955          offsetX -= rootWindow.clientStart.x;
2956          offsetY -= rootWindow.clientStart.y - (rootWindow.hasMenuBar ? skinMenuHeight : 0);
2957       }
2958
2959       if(rootWindow.fullRender)
2960       {
2961          UpdateExtent(box);
2962          dirtyArea.Empty();
2963       }
2964       else
2965       {
2966 #ifdef _DEBUG
2967          /*
2968          background = Color { (byte)GetRandom(0,255), (byte)GetRandom(0,255), (byte)GetRandom(0,255) };
2969          foreground = (background.color.r > 128 || background.color.g > 128) ? black : white;
2970          */
2971 #endif
2972             
2973 #ifdef _DEBUG
2974          /*if(renderArea.count)
2975             printf("\n\nRendering %s (%x):\n------------------------------------------\n", _class.name, this);*/
2976 #endif
2977             
2978          for(extentBox = (BoxItem)renderArea.first; extentBox; extentBox = (BoxItem)extentBox.next)
2979          {
2980             Box box = extentBox.box;
2981
2982 #ifdef _DEBUG
2983                /*printf("(%d, %d) - (%d, %d)\n", 
2984                   extentBox.box.left, extentBox.box.top, 
2985                   extentBox.box.right, extentBox.box.bottom);*/
2986 #endif
2987                
2988             UpdateExtent(box);
2989
2990             box.left += offsetX;
2991             box.top += offsetY;
2992             box.right += offsetX;
2993             box.bottom += offsetY;
2994
2995             if(updateExtent != null)
2996                updateExtent.UnionBox(box, rootWindow.tempExtents[0]);
2997          }
2998       }
2999
3000       for(child = children.first; child; child = child.next)
3001          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow && !child.nonClient)
3002             child.Render(updateExtent);
3003
3004       if(rootWindow.fullRender)
3005          DrawOverChildren(box);
3006       else
3007       {
3008          // TO DO: There's an issue about draw over children...
3009          // TO DO: Don't wanna go through this if method isn't used
3010          for(extentBox = (BoxItem)overRenderArea.first; extentBox; extentBox = (BoxItem)extentBox.next)
3011          //FASTLIST_LOOP(/*renderArea */overRenderArea, extentBox)
3012          {
3013             Box box = extentBox.box;
3014
3015             DrawOverChildren(box);
3016
3017             box.left += offsetX;
3018             box.top += offsetY;
3019             box.right += offsetX;
3020             box.bottom += offsetY;
3021
3022             if(updateExtent != null)
3023                updateExtent.UnionBox(box, rootWindow.tempExtents[0]);
3024          }
3025       }
3026       for(child = children.first; child; child = child.next)
3027          if(!child.style.hidden && child.created && !child.is3D && child.rootWindow && child.nonClient)
3028             child.Render(updateExtent);
3029
3030       renderArea.Empty();
3031       overRenderArea.Empty();
3032    }
3033
3034    public void UpdateDisplay(void)
3035    {
3036       if(!manageDisplay) { OnRedraw(null);return; }
3037       if(rootWindow && this != rootWindow) 
3038          rootWindow.UpdateDisplay();
3039       else if(display)
3040       {
3041          Extent dirtyExtent { /*first = -1, last = -1, free = -1*/ };  // Extent that needs to be forced due to transparency
3042          Extent overExtent { /*first = -1, last = -1, free = -1*/ };  // Extent that forced for DrawOverChildren
3043          BoxItem extentBox;
3044
3045          dirtyExtent.Clear();
3046          overExtent.Clear();
3047
3048          clipExtent.AddBox(box);
3049
3050          display.StartUpdate();
3051
3052          if(!rootWindow.fullRender)
3053          {
3054             ComputeClipExtents();
3055             ComputeRenderAreaNonOpaque(dirtyExtent, overExtent, null);
3056             ComputeRenderArea(dirtyExtent, overExtent, null);
3057          }
3058          else
3059             clipExtent.Free(null);                     
3060
3061          dirtyExtent.Free(null);
3062          overExtent.Free(null);
3063
3064          if(display.flags.flipping)
3065          {
3066             Render(null);
3067             display.Update(null);
3068          }
3069          else
3070          {
3071             Extent updateExtent { /*first = -1, last = -1, free = -1*/ }; // Extent that needs to be updated
3072             updateExtent.Clear();
3073
3074             Render(updateExtent);
3075             if(fullRender)
3076                updateExtent.UnionBox(this.box, tempExtents[0]);
3077             
3078 #ifdef _DEBUG
3079             //printf("\n\nUpdate:\n------------------------------------------\n");
3080 #endif
3081             
3082             //FASTLIST_LOOP(updateExtent, extentBox)
3083             for(extentBox = (BoxItem)updateExtent.first; extentBox; extentBox = (BoxItem)extentBox.next)
3084             {
3085 #ifdef _DEBUG
3086                /*printf("Updating (%d, %d) - (%d, %d)\n", 
3087                   extentBox.box.left, extentBox.box.top, 
3088                   extentBox.box.right, extentBox.box.bottom);*/
3089 #endif
3090                
3091                display.Update(extentBox.box);
3092                
3093             }
3094             updateExtent.Free(null);
3095          }
3096
3097          display.EndUpdate();
3098          dirtyBack.Empty();
3099
3100          dirty = false;
3101          resized = false;
3102       }
3103    }
3104
3105    void UpdateBackDisplay(Box box)
3106    {
3107       if(display)
3108       {
3109          Extent dirtyExtent;
3110          Extent overExtent;
3111          Extent intersection { /*first = -1, last = -1, free = -1*/ };
3112
3113          //printf("UpdateBackDisplay going through!\n");
3114          display.StartUpdate();
3115
3116          if(resized)
3117          {
3118             intersection.Copy(dirtyBack);
3119             intersection.IntersectBox(box);
3120          
3121             dirtyExtent.Clear();
3122             overExtent.Clear();
3123
3124             clipExtent.AddBox(box);
3125          
3126             if(!rootWindow.fullRender)
3127             {
3128                ComputeClipExtents();
3129                ComputeRenderArea(dirtyExtent, overExtent, intersection);
3130             }
3131             else
3132                clipExtent.Free(null);
3133
3134             intersection.Free(null);
3135             dirtyExtent.Free(null);
3136             overExtent.Free(null);
3137
3138             Render(null);
3139          }
3140
3141          if(display.flags.flipping)
3142             display.Update(null);
3143          else
3144          {
3145             rootWindow.display.Update(box);
3146          }
3147
3148          display.EndUpdate();
3149
3150          if(resized)
3151          {
3152             dirtyBack.ExcludeBox(box, rootWindow.tempExtents[0]);
3153             if(dirtyBack.count > MAX_DIRTY_BACK)
3154             {
3155                BoxItem extentBox, next;
3156                BoxItem first = (BoxItem)ACCESS_ITEM(dirtyBack, dirtyBack.first);
3157                for(extentBox = (BoxItem)dirtyBack.first; extentBox; extentBox = next)
3158                {
3159                   next = (BoxItem)extentBox.next;
3160                   if(extentBox != first)
3161                   {
3162                      if(extentBox.box.left < first.box.left)
3163                         first.box.left = extentBox.box.left;
3164                      if(extentBox.box.top < first.box.top)
3165                         first.box.top = extentBox.box.top;
3166                      if(extentBox.box.right > first.box.right)
3167                         first.box.right = extentBox.box.right;
3168                      if(extentBox.box.bottom > first.box.bottom)
3169                         first.box.bottom = extentBox.box.bottom;
3170                      dirtyBack.Delete(extentBox);
3171                   }
3172                }
3173             }
3174             resized = false;
3175          }
3176       }
3177    }
3178
3179    // --- Window positioning ---
3180    // --- Window identification ---
3181
3182    // Returns window at position "Position"
3183    Window GetAtPosition(int x, int y, bool clickThru, bool acceptDisabled, Window last)
3184    {
3185       Window child, result = null;
3186       Box box = this.box;
3187       box.left += absPosition.x;
3188       box.right += absPosition.x;
3189       box.top += absPosition.y;
3190       box.bottom += absPosition.y;
3191
3192       if(!destroyed && visible && (acceptDisabled || !disabled))
3193       {
3194          int lx = x - absPosition.x;
3195          int ly = y - absPosition.y;
3196          if(IsInside(lx, ly))
3197          // if(box.IsPointInside(Point{x, y}))
3198          {
3199             if(!clickThru || !style.clickThrough) result = (this == last) ? null : this;
3200             // If the window is disabled, stop looking in children (for acceptDisabled mode)
3201             if(!disabled)
3202             {
3203                for(child = (last && last.parent == this) ? last.previous : children.last; child; child = child.prev)
3204                {
3205                   if(child != statusBar && child.rootWindow == rootWindow)
3206                   {
3207                      Window childResult = child.GetAtPosition(x, y, clickThru, acceptDisabled, last);
3208                      if(childResult) 
3209                         return childResult;
3210                   }
3211                }
3212                if(clickThru)
3213                {
3214                   for(child = (last && last.parent == this) ? last.previous : children.last; child; child = child.prev)
3215                   {
3216                      if(child != statusBar && child.rootWindow == rootWindow)
3217                      {
3218                         Window childResult = child.GetAtPosition(x, y, false, acceptDisabled, last);
3219                         if(childResult)
3220                            return childResult;
3221                      }
3222                   }
3223                }
3224             }
3225          }
3226       }
3227       return result;
3228    }
3229
3230    Window FindModal(void)
3231    {
3232       Window modalWindow = this, check;
3233       Window check2 = null;
3234       for(check = this; check.master; check = check.master)
3235       {
3236          if(check.master.modalSlave && check.master.modalSlave.created && check != check.master.modalSlave)
3237          {
3238             modalWindow = check.master.modalSlave;
3239             check = modalWindow;
3240          }
3241          // TESTING THIS FOR DROPBOX...
3242          if(!rootWindow || !rootWindow.style.interim)
3243          {
3244             for(check2 = check; check2.activeChild; check2 = check2.activeChild)
3245             {
3246                if(check2.modalSlave && check2.modalSlave.created)
3247                {
3248                   modalWindow = check2.modalSlave;
3249                   break;
3250                }
3251             }
3252          }
3253       }
3254
3255       /*
3256       if(modalWindow == this)
3257       {
3258          for(check = this; check.activeChild; check = check.activeChild)
3259          {
3260             if(check.modalSlave)
3261             {
3262                modalWindow = check.modalSlave;
3263                break;
3264             }
3265          }
3266       }
3267       */
3268       for(; modalWindow.modalSlave && modalWindow.modalSlave.created; modalWindow = modalWindow.modalSlave);
3269       return (modalWindow == this || this == guiApp.interimWindow || IsDescendantOf(modalWindow)) ? null : modalWindow;
3270    }
3271
3272    void StopMoving(void)
3273    {
3274       if(this == guiApp.windowMoving)
3275       {
3276          guiApp.windowMoving = null;
3277          UpdateDecorations();
3278          SetMouseRange(null);
3279          if(rootWindow)
3280          {
3281             if(rootWindow.active)
3282                guiApp.interfaceDriver.StopMoving(rootWindow);
3283          }
3284          ReleaseCapture();
3285          guiApp.resizeX = guiApp.resizeY = guiApp.resizeEndX = guiApp.resizeEndY = false;
3286          guiApp.windowIsResizing = false;
3287       }
3288    }
3289
3290    void SelectMouseCursor(void)
3291    {
3292       int x,y;
3293       Window mouseWindow;
3294       Window modalWindow;
3295       Window cursorWindow = null;
3296       bool rx, ry, rex, rey;
3297
3298       guiApp.desktop.GetMousePosition(&x, &y);
3299       mouseWindow = rootWindow ? rootWindow.GetAtPosition(x,y, true, false, null) : null;
3300
3301       if((guiApp.windowMoving && !guiApp.windowIsResizing) || guiApp.windowScrolling)
3302          guiApp.SetCurrentCursor(guiApp.systemCursors[moving]);
3303       else if(mouseWindow)
3304       {
3305          modalWindow = mouseWindow.FindModal();
3306          x -= mouseWindow.absPosition.x;
3307          y -= mouseWindow.absPosition.y;
3308          if(guiApp.windowIsResizing)
3309          {
3310             rex = guiApp.resizeEndX;
3311             rey = guiApp.resizeEndY;
3312             rx = guiApp.resizeX;
3313             ry = guiApp.resizeY;
3314             if((rex && rey) || (rx && ry))
3315                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
3316             else if((rex && ry) || (rx && rey))
3317                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
3318             else if((ry || rey) && (!rx && !rex))
3319                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
3320             else if((rx || rex) && (!ry && !rey))
3321                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
3322          }
3323          else if(!modalWindow && !guiApp.windowCaptured &&
3324             mouseWindow.IsMouseResizing(x, y, mouseWindow.size.w, mouseWindow.size.h,
3325                &rx, &ry, &rex, &rey))
3326          {
3327             if((rex && rey) || (rx && ry))
3328                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
3329             else if((rex && ry) || (rx && rey))
3330                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
3331             else if((ry || rey) && (!rx && !rex))
3332                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
3333             else if((rx || rex) && (!ry && !rey))
3334                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
3335          }
3336          else if(!guiApp.windowCaptured && !modalWindow && !guiApp.interimWindow)
3337          {
3338             if(!mouseWindow.clientArea.IsPointInside({x - mouseWindow.clientStart.x, y - mouseWindow.clientStart.y}))
3339                cursorWindow = mouseWindow.parent;
3340             else
3341                cursorWindow = mouseWindow;
3342          }
3343          else if(!guiApp.interimWindow)
3344             cursorWindow = guiApp.windowCaptured;
3345          if(cursorWindow)
3346          {
3347             for(; !cursorWindow.cursor && !cursorWindow.style.nonClient; cursorWindow = cursorWindow.parent);
3348             guiApp.SetCurrentCursor(cursorWindow.cursor ? cursorWindow.cursor : guiApp.systemCursors[arrow]);
3349          }
3350          else if(modalWindow)
3351          {
3352             guiApp.SetCurrentCursor(guiApp.systemCursors[arrow]);
3353          }
3354          else if(guiApp.interimWindow)
3355          {
3356             if(guiApp.interimWindow.cursor)
3357                guiApp.SetCurrentCursor(guiApp.interimWindow.cursor);
3358             else
3359                guiApp.SetCurrentCursor(mouseWindow.cursor ? mouseWindow.cursor : guiApp.systemCursors[arrow]);
3360          }
3361       }
3362    }
3363
3364    // --- State based input ---
3365    bool AcquireInputEx(bool state)
3366    {
3367       bool result;
3368       if(state) 
3369       {
3370          guiApp.interfaceDriver.GetMousePosition(&guiApp.acquiredMouseX, &guiApp.acquiredMouseY);
3371          guiApp.interfaceDriver.SetMousePosition(clientSize.w/2 + absPosition.x, clientSize.h/2 + absPosition.y);
3372       }
3373       result = guiApp.interfaceDriver.AcquireInput(rootWindow, state);
3374       if(result)
3375          guiApp.acquiredWindow = state ? this : null;
3376       if(state && result)
3377       {
3378          SetMouseRangeToClient();
3379          guiApp.interfaceDriver.SetMouseCursor((SystemCursor)-1);
3380       }
3381       else
3382       {
3383          FreeMouseRange();
3384          SelectMouseCursor();
3385       }
3386       if(!state) guiApp.interfaceDriver.SetMousePosition(guiApp.acquiredMouseX, guiApp.acquiredMouseY);
3387       return result;
3388    }
3389
3390    // --- Window activation ---
3391    bool PropagateActive(bool active, Window previous, bool * goOnWithActivation, bool direct)
3392    {
3393       bool result = true;
3394       if(!parent || !parent.style.inactive)
3395       {
3396          Window parent = this.parent;
3397
3398          /*
3399          if(rootWindow == this)
3400             Log(active ? "active\n" : "inactive\n");
3401          */
3402
3403          // Testing this here...
3404          if(!parent || parent == guiApp.desktop || parent.active)
3405          {
3406             this.active = active;
3407          }
3408
3409          // TESTING THIS HERE
3410          UpdateDecorations();
3411          if(result = OnActivate(active, previous, goOnWithActivation, direct) && *goOnWithActivation && master)
3412             result = NotifyActivate(master, this, active, previous);
3413          else
3414          {
3415             this.active = !active;
3416          }
3417
3418          if(result)
3419          {
3420             if(!parent || parent == guiApp.desktop || parent.active)
3421             {
3422                this.active = active;
3423                if(acquiredInput)
3424                   AcquireInputEx(active);
3425                if(active)
3426                {
3427                   if(caretSize)
3428                   {
3429                      if(guiApp.caretOwner)
3430                      {
3431                         Box extent 
3432                         {
3433                            guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 1, 
3434                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + 1,
3435                            guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 2, 
3436                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + guiApp.caretOwner.caretSize - 1
3437                         };
3438                         guiApp.caretOwner.Update(extent);
3439                      }
3440
3441                      if(visible || !guiApp.caretOwner)
3442                         guiApp.caretOwner = this;
3443                      UpdateCaret(false, false);
3444                   }
3445                }
3446             }
3447             else
3448             {
3449                this.active = false;
3450                if(acquiredInput)
3451                   AcquireInputEx(active);
3452             }
3453             if(!active && guiApp.caretOwner == this)
3454             {
3455                UpdateCaret(false, true);
3456                guiApp.caretOwner = null;
3457                guiApp.interfaceDriver.SetCaret(0,0,0);
3458                guiApp.caretEnabled = false;
3459             }
3460
3461             if(!style.interim)
3462             {
3463                if(!active && parent && parent.activeChild && parent.activeChild != this)
3464                   if(!parent.activeChild.PropagateActive(false, previous, goOnWithActivation, true) || !*goOnWithActivation)
3465                   {
3466                      return false;
3467                   }
3468             }
3469
3470             if(!active && menuBar)
3471             {
3472                bool goOn;
3473                menuBar.OnActivate(false, null, &goOn, true);
3474                menuBar.NotifyActivate(menuBar.master, menuBar, false, null);
3475             }
3476
3477             if(activeChild)
3478             {
3479                Window aChild = activeChild;
3480                incref aChild;
3481                if(!aChild.PropagateActive(active, previous, goOnWithActivation, false) || !*goOnWithActivation)
3482                {
3483                   delete aChild;
3484                   return false;
3485                }
3486                delete aChild;
3487             }
3488          }
3489       }
3490       return result;
3491    }
3492
3493    void ConsequentialMouseMove(bool kbMoving)
3494    {
3495       if(rootWindow)
3496       {
3497          if(kbMoving || !guiApp.windowMoving)
3498          {
3499             Modifiers mods {};
3500             int x,y;
3501             if(rootWindow == guiApp.desktop || rootWindow.parent == guiApp.desktop)
3502             {
3503                guiApp.interfaceDriver.GetMousePosition(&x, &y);
3504
3505                if(guiApp.windowMoving || rootWindow.GetAtPosition(x, y, true, false, null))
3506                   rootWindow.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &mods, true, false);
3507             }
3508          }
3509       }
3510    }
3511
3512    bool IsDescendantOf(Window ancestor)
3513    {
3514       Window window;
3515       for(window = this; window && window != ancestor; window = window.parent);
3516       return window == ancestor;
3517    }
3518
3519    bool IsSlaveOf(Window master)
3520    {
3521       Window window;
3522       for(window = this; window && window != master; window = window.master);
3523       return window == master;
3524    }
3525
3526    bool ActivateEx(bool active, bool activateParent, bool moveInactive, bool activateRoot, Window external, Window externalSwap)
3527    {
3528       bool result = true;
3529
3530       if(this && !destroyed /*&& state != Hidden*/)
3531       {
3532          Window swap = externalSwap;
3533
3534          incref this;
3535
3536          if(parent)
3537          {
3538             if(!active)
3539                StopMoving();
3540             if(activateParent && 
3541                (parent.activeChild != this || 
3542                (guiApp.interimWindow && !IsDescendantOf(guiApp.interimWindow))) &&
3543                active && _isModal &&
3544                parent != master && master)
3545                master.ActivateEx(true, true, false, activateRoot, external, externalSwap);
3546
3547             if(active)
3548             {
3549                if(parent)
3550                {
3551                   bool real = parent.activeChild != this;
3552
3553                   // TEST THIS: New activateParent check here!!! CAUSED MENUS NOT GOING AWAY
3554                   if(!style.inactive && /*activateParent && */guiApp.interimWindow && 
3555                      !IsDescendantOf(guiApp.interimWindow) && 
3556                      !IsSlaveOf(guiApp.interimWindow))
3557                   {
3558                      Window interimWindow = guiApp.interimWindow;
3559                      while(interimWindow && interimWindow != this)
3560                      {
3561                         Window master = interimWindow.master;
3562                         bool goOn = true;
3563                         guiApp.interimWindow = null;
3564                         if(guiApp.caretOwner)
3565                            guiApp.caretOwner.UpdateCaret(false, false);
3566
3567                         incref interimWindow;
3568                         if(!interimWindow.PropagateActive(false, this, &goOn, true))
3569                         {
3570                            result = false;
3571                            real = false;
3572                         }
3573                         delete interimWindow;
3574                         interimWindow = (master && master.style.interim) ? master : null;
3575                      }
3576                   }
3577                   if(style.interim)
3578                   {
3579                      guiApp.interimWindow = this;
3580                      /*guiApp.interfaceDriver.SetCaret(0,0,0);
3581                      guiApp.caretEnabled = false;*/
3582                      UpdateCaret(false, true);
3583                   }
3584
3585                   if(real)
3586                   {
3587                      bool acquireInput = false;
3588                      bool maximize =
3589                         parent.activeChild &&
3590                         parent.activeChild.state == maximized &&
3591                         parent != guiApp.desktop;
3592
3593                      if(!style.inactive) // (!style.isRemote || parent.active || parent.style.hidden))
3594                      {
3595                         if(!style.interim)
3596                         {
3597                            if(!swap && parent)
3598                               swap = parent.activeChild;
3599                            if(swap && swap.destroyed) swap = null;
3600                            if(swap && swap != this)
3601                            {
3602                               bool goOn = true;
3603                               if(!swap.PropagateActive(false, this, &goOn, true))
3604                                  swap = parent.activeChild;
3605                               if(!goOn)
3606                               {
3607                                  delete this;
3608                                  return false;
3609                               }
3610                            }
3611                            else
3612                               swap = null;
3613                         }
3614
3615                         if(!parent || parent.activeChild != this || style.interim)
3616                         {
3617                            bool goOn = true;
3618                            result = PropagateActive(true, swap, &goOn, true);
3619                            if(!result && !goOn) 
3620                            {
3621                               delete this;
3622                               return false;
3623                            }
3624                            acquireInput = true;
3625                         }
3626                      }
3627
3628                      if(style.hasMaximize && parent != guiApp.desktop)
3629                      {
3630                         if(maximize)
3631                            SetState(maximized, false, 0);
3632                         else if(state != maximized)
3633                         {
3634                            Window child;
3635                            for(child = parent.children.first; child; child = child.next)
3636                            {
3637                               if(this != child && child.state == maximized)
3638                                  child.SetState(normal, false, 0);
3639                            }
3640                         }
3641                      }
3642                   }
3643                   if(result)
3644                   {
3645                      if(!style.inactive && !style.interim /*&& (!style.isRemote || parent.active || parent.style.hidden)*/)
3646                      {
3647                         Window previous = parent.activeClient;
3648                         parent.activeChild = this;
3649                         if(!style.nonClient /*&& style.isActiveClient*/)
3650                         {
3651                            if(!style.hidden)
3652                            {
3653                               if(style.isActiveClient)
3654                                  parent.activeClient = this;
3655                               // Moved UpdateActiveDocument inside hidden check
3656                               // To prevent activating previous window while creating a new one
3657                               // (It was messing up the privateModule in the CodeEditor)
3658                               parent.UpdateActiveDocument(previous);
3659                            }
3660                         }
3661                      }
3662                   }
3663
3664                   //if(!style.isRemote)
3665                   {
3666                      if(rootWindow != this)
3667                      {
3668                         if(activateParent && parent && !parent.active /*parent != parent.parent.activeChild*/)
3669                            parent.ActivateEx(true, true, moveInactive, activateRoot, external, externalSwap);
3670                      }
3671                      else if(!guiApp.fullScreenMode)
3672                      {
3673                         Window modalRoot = FindModal();
3674                         if(!modalRoot) modalRoot = this;
3675                         if(!modalRoot.isForegroundWindow)
3676                         {
3677                            modalRoot.isForegroundWindow = true;
3678                            // To check : Why is parent null?
3679                            if(activateRoot && modalRoot.parent && !modalRoot.parent.display && external != modalRoot)
3680                            {
3681                               guiApp.interfaceDriver.ActivateRootWindow(modalRoot);
3682                            }
3683                            modalRoot.isForegroundWindow = false;
3684                         }
3685                      }
3686                   }
3687                
3688                   if(result && real && (!style.inactive || moveInactive) && parent)
3689                   {
3690                      Window last = parent.children.last;
3691
3692                      if(!style.stayOnTop)
3693                         for(; last && last.style.stayOnTop; last = last.prev);
3694                      
3695                      parent.children.Move(this, last);
3696
3697                      // Definitely don't want that:   why not?
3698                      Update(null);
3699
3700                      if(order)
3701                         parent.childrenOrder.Move(order, parent.childrenOrder.last);
3702                   }
3703                }
3704             }
3705             else 
3706             {
3707                if(!parent || style.interim || (parent.activeChild == this && !style.inactive))
3708                {
3709                   bool goOn = true;
3710                   if(!style.interim)
3711                   {
3712                      if(parent)
3713                      {
3714                         parent.activeChild = null;
3715                         if(!style.nonClient /*&& style.isActiveClient*/)
3716                         {
3717                            Window previous = parent.activeClient;
3718                            if(style.isActiveClient)
3719                               parent.activeClient = null;
3720                            parent.UpdateActiveDocument(previous);
3721                         }
3722                      }
3723                   }
3724                   if(this == guiApp.interimWindow)
3725                   {
3726                      guiApp.interimWindow = null;
3727                      if(guiApp.caretOwner)
3728                         guiApp.caretOwner.UpdateCaret(false, false);
3729                   }
3730                   if(!PropagateActive(false, externalSwap, &goOn, true) || !goOn)
3731                   {
3732                      delete this;
3733                      return false;
3734                   }
3735                }
3736             }
3737             if(!active || !swap)
3738                UpdateDecorations();
3739             if(swap)
3740                swap.UpdateDecorations();
3741
3742             if(active && rootWindow != this)
3743                ConsequentialMouseMove(false);
3744          }
3745          delete this;
3746       }
3747       return true;
3748    }
3749
3750    // --- Input Messages ---
3751    void ::UpdateMouseMove(int mouseX, int mouseY, bool consequential)
3752    {
3753       static bool reEntrancy = false;
3754       if(reEntrancy) return;
3755
3756       reEntrancy = true;
3757
3758       guiApp.cursorUpdate = true;
3759       if(guiApp.windowScrolling && !consequential)
3760       {
3761          guiApp.windowScrolling.SetScrollPosition(
3762             (guiApp.windowScrolling.sbh) ? 
3763                (guiApp.windowScrollingBefore.x - mouseX + guiApp.windowScrollingStart.x) : 0,
3764             (guiApp.windowScrolling.sbv) ? 
3765                (guiApp.windowScrollingBefore.y - mouseY + guiApp.windowScrollingStart.y) : 0);
3766       }
3767       if(guiApp.windowMoving)
3768       {
3769          if(mouseX != guiApp.movingLast.x || mouseY != guiApp.movingLast.y)
3770          {
3771             Window window = guiApp.windowMoving;
3772             int rx, ry;
3773             int w = window.size.w;
3774             int h = window.size.h;
3775             int aw, ah;
3776             MinMaxValue ew, eh;
3777             int x, y;
3778
3779             rx = mouseX - guiApp.windowMovingStart.x;
3780             ry = mouseY - guiApp.windowMovingStart.y;
3781
3782             // Size
3783             window.GetDecorationsSize(&ew, &eh);
3784
3785             if(guiApp.windowIsResizing)
3786             {
3787                x = window.scrolledPos.x;
3788                y = window.scrolledPos.y;
3789
3790                if(guiApp.resizeX)
3791                {
3792                   aw = Max(guiApp.windowResizingBefore.w - rx,window.skinMinSize.w);
3793                   rx = guiApp.windowResizingBefore.w - aw;
3794                   rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x;
3795                   w = guiApp.windowResizingBefore.w - rx;
3796                }
3797                if(guiApp.resizeY)
3798                {
3799                   ah = Max(guiApp.windowResizingBefore.h - ry,window.skinMinSize.h);
3800                   ry = guiApp.windowResizingBefore.h - ah;
3801                   ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y;
3802                   ry = Max(ry, -guiApp.windowMovingBefore.y);
3803                   h = guiApp.windowResizingBefore.h - ry;
3804                }
3805                if(guiApp.resizeEndX)
3806                {
3807                   w = guiApp.windowResizingBefore.w + rx;
3808                   w = Max(w,1-x);
3809                }
3810                if(guiApp.resizeEndY) h = guiApp.windowResizingBefore.h + ry;
3811
3812                w -= ew;
3813                h -= eh;
3814
3815                w = Max(w, 1);
3816                h = Max(h, 1);
3817
3818                w = Max(w, window.minSize.w);
3819                h = Max(h, window.minSize.h);
3820                w = Min(w, window.maxSize.w);
3821                h = Min(h, window.maxSize.h);
3822
3823                if(!window.OnResizing(&w, &h))
3824                {
3825                   w = window.clientSize.w;
3826                   h = window.clientSize.h;
3827                }
3828
3829                w = Max(w, window.skinMinSize.w);
3830                h = Max(h, window.skinMinSize.h);
3831
3832                w += ew;
3833                h += eh;
3834
3835                if(guiApp.textMode)
3836                {
3837                   SNAPDOWN(w, textCellW);
3838                   SNAPDOWN(h, textCellH);
3839                }
3840
3841                if(guiApp.resizeX)
3842                {
3843                   aw = Max(w,window.skinMinSize.w);
3844                   rx = guiApp.windowResizingBefore.w - aw;
3845                   rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x;
3846                   w = guiApp.windowResizingBefore.w - rx;
3847                }
3848                if(guiApp.resizeY)
3849                {
3850                   ah = Max(h,window.skinMinSize.h);
3851                   ry = guiApp.windowResizingBefore.h - ah;
3852                   ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y;
3853                   ry = Max(ry, -guiApp.windowMovingBefore.y);
3854                   h = guiApp.windowResizingBefore.h - ry;
3855                }
3856             }
3857          
3858             // Position
3859             if(!guiApp.windowIsResizing || guiApp.resizeX)
3860                x = guiApp.windowMovingBefore.x + rx;
3861             if(!guiApp.windowIsResizing || guiApp.resizeY)
3862                y = guiApp.windowMovingBefore.y + ry;
3863
3864             if(!guiApp.windowIsResizing)
3865             {
3866                // Limit
3867                if(window.parent == guiApp.desktop && guiApp.virtualScreen.w)
3868                {
3869                   x = Min(x, (guiApp.virtualScreen.w + guiApp.virtualScreenPos.x) -1);
3870                   y = Min(y, (guiApp.virtualScreen.h + guiApp.virtualScreenPos.y) -1);
3871                   x = Max(x,-(w-1) + guiApp.virtualScreenPos.x);
3872                   y = Max(y,-(h-1) + guiApp.virtualScreenPos.y);
3873                }
3874                else
3875                {
3876                   x = Min(x, (window.parent.reqScrollArea.w ? window.parent.reqScrollArea.w : window.parent.clientSize.w) -1);
3877                   y = Min(y, (window.parent.reqScrollArea.h ? window.parent.reqScrollArea.h : window.parent.clientSize.h) -1);
3878                   x = Max(x,-(w-1));
3879                   y = Max(y,-(h-1));
3880                }
3881             }
3882
3883             if(!guiApp.windowIsResizing || (guiApp.resizeX || guiApp.resizeY))
3884             {
3885                if(!window.OnMoving(&x, &y, w, h))
3886                {
3887                   x = window.scrolledPos.x;
3888                   y = window.scrolledPos.y;
3889                }
3890             }
3891
3892             if(guiApp.textMode)
3893             {
3894                SNAPDOWN(x, textCellW);
3895                SNAPDOWN(y, textCellH);
3896             }
3897
3898             if(!window.style.nonClient)
3899             {
3900                if(!window.style.fixed /*|| window.style.isDocument*/)
3901                {
3902                   if(!window.style.dontScrollHorz)
3903                      x += window.parent.scroll.x;
3904                   if(!window.style.dontScrollVert)
3905                      y += window.parent.scroll.y;
3906                }
3907             }
3908
3909             // Break the anchors for moveable/resizable windows
3910             // Will probably cause problem with IDE windows... Will probably need a way to specify if anchors should break
3911             if(window.style.fixed) 
3912             {
3913                if(window.state == normal)
3914                {
3915                   window.normalAnchor = Anchor { left = x, top = y };
3916                   window.normalSizeAnchor = SizeAnchor { { w, h } };
3917                   window.anchored = false;
3918                }
3919             }
3920
3921             window.stateAnchor = Anchor { left = x, top = y };
3922             window.stateSizeAnchor = SizeAnchor { { w, h } };
3923
3924             window.Position(x, y, w, h, false, true, guiApp.windowIsResizing, guiApp.windowIsResizing, false, true);
3925             // TOCHECK: Investigate why the following only redraws the scrollbars
3926             //window.Position(x, y, w, h, false, true, true, true, false, true);
3927
3928             guiApp.movingLast.x = mouseX;
3929             guiApp.movingLast.y = mouseY;
3930          }
3931       }
3932       reEntrancy = false;
3933    }
3934
3935    public bool MouseMessage(uint method, int x, int y, Modifiers * mods, bool consequential, bool activate)
3936    {
3937       bool result = true;
3938       bool wasMoving = guiApp.windowMoving ? true : false;
3939       bool wasScrolling = guiApp.windowScrolling ? true : false;
3940       Window w = null;
3941       while(result && w != this)
3942       {
3943          Window msgWindow = GetAtPosition(x,y, false, true, w);
3944          Window trueWindow = GetAtPosition(x,y, false, false, w);
3945          bool windowDragged = false;
3946          Window window;
3947          delete w;
3948          w = msgWindow;
3949          if(w) incref w;
3950          window = (w && !w.disabled) ? w : null;
3951          
3952          if(trueWindow) incref trueWindow;
3953
3954          if(consequential) mods->isSideEffect = true;
3955
3956          UpdateMouseMove(x, y, consequential);
3957
3958          if(guiApp.windowCaptured && (guiApp.windowCaptured.rootWindow == this))
3959          {
3960             if(!guiApp.windowCaptured.isEnabled)
3961                guiApp.windowCaptured.ReleaseCapture();
3962             else
3963                window = guiApp.windowCaptured;
3964          }
3965
3966          if(trueWindow && activate &&
3967             (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown ||
3968              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown ||
3969              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown ||
3970              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick))
3971          {
3972             if(mods->alt && !mods->ctrl && !mods->shift)
3973             {
3974                Window moved = trueWindow;
3975                for(moved = trueWindow; moved; moved = moved.parent)
3976                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
3977                      break;
3978                if(moved) 
3979                {
3980                   window = moved;
3981                   windowDragged = true;
3982
3983                   // Cancel the ALT menu toggling...
3984                   window.rootWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
3985                }
3986             }
3987          }
3988
3989          if(window && activate &&
3990             (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown ||
3991              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown ||
3992              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown ||
3993              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick))
3994          {
3995             Window modalWindow = window.FindModal();
3996
3997             /*if(mods->alt && !mods->shift && !mods->ctrl)
3998             {
3999                Window moved = window;
4000                for(moved = window; moved; moved = moved.parent)
4001                   if(method == OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
4002                      break;
4003                if(moved) 
4004                {
4005                   window = moved;
4006                   windowDragged = true;
4007
4008                   // Cancel the ALT menu toggling...
4009                   window.rootWindow.KeyMessage(OnKeyDown, 0, 0);
4010                }
4011             }*/
4012
4013             if(!windowDragged)
4014             {
4015                Window activateWindow = modalWindow ? modalWindow : window;
4016                if(activateWindow && !activateWindow.isRemote)
4017                {
4018                   bool doActivation = true;
4019                   //bool needToDoActivation = false;
4020                   Window check = activateWindow;
4021
4022                   for(check = activateWindow; check && check != guiApp.desktop; check = check.parent)
4023                   {
4024                      if(!check.style.inactive)
4025                      {
4026                         //needToDoActivation = true;
4027                         if(check.active)
4028                            doActivation = false;
4029                         break;
4030                      }
4031                   }
4032                   /*
4033                   if(!needToDoActivation)
4034                      doActivation = false;
4035                   */
4036
4037                   if((doActivation && (activateWindow.parent != guiApp.desktop || guiApp.fullScreen)) || 
4038                      (guiApp.interimWindow && !window.IsDescendantOf(guiApp.interimWindow)))
4039                   {
4040                      // Let the OnLeftButtonDown do the activating instead
4041                      if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)
4042                      {
4043                         window = null;
4044                         result = true;
4045                      }
4046                      else
4047                      //if(activate)
4048                      {
4049                         incref activateWindow;
4050                         if(!activateWindow.ActivateEx(true, true, false, true, null, null))
4051                         {
4052                            delete activateWindow;
4053                            delete trueWindow;
4054                            return false;
4055                         }
4056                         if(activateWindow._refCount == 1)
4057                         {
4058                            delete activateWindow;
4059                            delete trueWindow;
4060                            return false;
4061                         }
4062                         delete activateWindow;
4063                      }
4064                      mods->isActivate = true;
4065                   }
4066                }
4067             }
4068             if(!modalWindow && window && !window.destroyed)
4069             {
4070                if(!guiApp.windowCaptured || windowDragged)
4071                {
4072                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown)
4073                   {
4074                      bool moving = ((window.state != maximized &&
4075                            window.IsMouseMoving(
4076                         x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
4077                         || (guiApp.windowMoving && !guiApp.windowIsResizing);
4078
4079                      if(!moving && window.IsMouseResizing(
4080                         x - window.absPosition.x,
4081                         y - window.absPosition.y,
4082                         window.size.w, window.size.h,
4083                         &guiApp.resizeX, &guiApp.resizeY, &guiApp.resizeEndX, &guiApp.resizeEndY))
4084                      {
4085                         guiApp.windowIsResizing = true;
4086                         guiApp.windowResizingBefore.w = window.size.w;
4087                         guiApp.windowResizingBefore.h = window.size.h;
4088                      }
4089                      if(guiApp.windowIsResizing || windowDragged || moving)
4090                      {
4091                         window.Capture();
4092                         guiApp.windowMoving = window;
4093                         guiApp.windowMovingStart.x = guiApp.movingLast.x = x;
4094                         guiApp.windowMovingStart.y = guiApp.movingLast.y = y;
4095                         guiApp.windowMovingBefore.x = window.position.x;//s;
4096                         guiApp.windowMovingBefore.y = window.position.y;//s;
4097                         if(guiApp.windowMoving == guiApp.windowMoving.rootWindow)
4098                            guiApp.interfaceDriver.StartMoving(guiApp.windowMoving.rootWindow, 0,0,false);
4099                      }
4100                   }
4101                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown)
4102                   {
4103                      if(window.style.fixed &&
4104                         (windowDragged || 
4105                         window.IsMouseMoving(
4106                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
4107                      {
4108                         window.ShowSysMenu(x, y);
4109                         result = false;
4110                      }
4111                   }
4112                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown)
4113                   {
4114                      if(window.sbv || window.sbh)
4115                      {
4116                         window.Capture();
4117                         guiApp.windowScrolling = window;
4118                         guiApp.windowScrollingStart.x = x;
4119                         guiApp.windowScrollingStart.y = y;
4120                         guiApp.windowScrollingBefore.x = window.scroll.x;
4121                         guiApp.windowScrollingBefore.y = window.scroll.y;
4122                      }
4123                   }
4124                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)
4125                   {
4126                      if(window.style.hasMaximize && 
4127                         window.IsMouseMoving( 
4128                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h))
4129                      {
4130                         window.SetState(
4131                            (window.state == maximized) ? normal : maximized, false, *mods);
4132                         result = false;
4133                      }
4134                   }
4135                }
4136             }
4137             else
4138                window = null;
4139             if(guiApp.windowMoving) 
4140             {
4141                if(guiApp.windowMoving.parent)
4142                {
4143                   if(guiApp.windowMoving.style.nonClient)
4144                      guiApp.windowMoving.parent.SetMouseRangeToWindow();
4145                   else
4146                      guiApp.windowMoving.parent.SetMouseRangeToClient();
4147                }
4148                else
4149                   FreeMouseRange();
4150                window.UpdateDecorations();
4151             }
4152          }
4153          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp)
4154          {
4155             // Log("\n*** LEFT BUTTON UP ***\n");
4156             if(guiApp.windowMoving)
4157                guiApp.windowMoving.StopMoving();
4158          }
4159          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp)
4160          {
4161             if(guiApp.windowScrolling)
4162             {
4163                Window windowScrolling = guiApp.windowScrolling;
4164                guiApp.windowScrolling = null;
4165                windowScrolling.ReleaseCapture();
4166             }
4167          }
4168
4169          if(!result || (window && window.destroyed)) window = null;
4170
4171          if(window && window.FindModal())
4172             window = null;
4173
4174          if(trueWindow && trueWindow.FindModal())
4175             delete trueWindow;
4176          
4177          /*if(trueWindow)
4178             incref trueWindow;
4179          */
4180
4181          /*
4182          msgWindow = GetAtPosition(x,y, true, false);
4183          if(msgWindow)
4184             msgWindow.SelectMouseCursor();
4185          */
4186
4187          if(guiApp.windowCaptured || trueWindow)
4188          {
4189             Window prevWindow = guiApp.prevWindow;
4190             if(guiApp.prevWindow && trueWindow != guiApp.prevWindow)
4191             {
4192                guiApp.prevWindow.mouseInside = false;
4193                guiApp.prevWindow = null;
4194
4195                // Eventually fix this not to include captured?
4196                if(!prevWindow.OnMouseLeave(*mods))
4197                   result = false;
4198             }
4199             if(result && trueWindow && !trueWindow.destroyed/* && trueWindow == window*/)
4200             {
4201                Box box = trueWindow.box;
4202                box.left += trueWindow.absPosition.x;
4203                box.right += trueWindow.absPosition.x;
4204                box.top += trueWindow.absPosition.y;
4205                box.bottom += trueWindow.absPosition.y;
4206
4207                if(box.IsPointInside({x, y}) && trueWindow != /*guiApp.*/prevWindow /*!trueWindow.mouseInside*/)
4208                {
4209                   int overX = x - (trueWindow.absPosition.x + trueWindow.clientStart.x);
4210                   int overY = y - (trueWindow.absPosition.y + trueWindow.clientStart.y);
4211
4212                   overX = Max(Min(overX, 32767),-32768);
4213                   overY = Max(Min(overY, 32767),-32768);
4214
4215                   trueWindow.mouseInside = true;
4216                   if(!trueWindow.OnMouseOver(overX, overY, *mods))
4217                      result = false;
4218                }
4219             }
4220             if(trueWindow && trueWindow._refCount > 1 && !trueWindow.destroyed)
4221                guiApp.prevWindow = trueWindow;
4222             else
4223                guiApp.prevWindow = null;
4224          }
4225          SelectMouseCursor();
4226
4227          if(window && !guiApp.windowMoving && !wasMoving && !wasScrolling)
4228          {
4229             int clientX = x - (window.absPosition.x + window.clientStart.x);
4230             int clientY = y - (window.absPosition.y + window.clientStart.y);
4231
4232             bool (* MouseMethod)(Window instance, int x, int y, Modifiers mods);
4233
4234             clientX = Max(Min(clientX, 32767),-32768);
4235             clientY = Max(Min(clientY, 32767),-32768);
4236
4237             MouseMethod = (void *)window._vTbl[method];
4238
4239             if(MouseMethod /*&& !consequential*/ && !window.disabled)
4240             {
4241                incref window;
4242                if(!MouseMethod(window, clientX, clientY, *mods))
4243                   result = false;
4244                delete window;
4245             }
4246          }
4247          delete trueWindow;
4248          /*
4249          if(result && w && w.clickThrough && w.parent)
4250             w = w.parent;
4251          else
4252             break;
4253          */
4254          if(!result || !w || !w.clickThrough)
4255             break;
4256       }
4257       delete w;
4258       return result;
4259    }
4260
4261    // --- Mouse cursor management ---
4262
4263    bool KeyMessage(uint method, Key key, unichar character)
4264    {
4265       bool status = true;
4266       if(!parent)
4267       {
4268          if(guiApp.interimWindow)
4269             this = guiApp.interimWindow;
4270       }
4271 #ifdef _DEBUG
4272       if((SmartKey)key != alt && (SmartKey)key != Key::control && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && parent && this != parent.menuBar)
4273          Print("");
4274 #endif
4275
4276       if(!style.inactive || rootWindow != this)
4277       {
4278          bool (*KeyMethod)(Window window, Key key, unichar ch) = (void *)_vTbl[method];
4279          Window modalWindow = FindModal();
4280          Window interimMaster = master ? master.rootWindow : null;
4281
4282          incref this;
4283
4284          if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4285             status = OnSysKeyDown(key, character);
4286          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4287             status = OnSysKeyHit(key, character);
4288          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4289             status = OnSysKeyUp(key, character);
4290          if(!status)
4291          {
4292             delete this;
4293             return true;
4294          }
4295
4296          // Process Key Message for Internal UI Keyboard actions
4297          if(status && !destroyed && menuBar && state != minimized)
4298          {
4299             // Disable the ALT
4300             if((SmartKey)key != alt) 
4301                menuBar.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
4302             if(menuBar.focus)
4303             {
4304                SmartKey sk = (SmartKey) key;
4305                if((character && !key.alt && !key.ctrl) || sk == left || sk == right || sk == up || sk == down || sk == home || sk == end || sk == escape || sk == alt)
4306                {
4307                   status = menuBar.KeyMessage(method, key, character);
4308                   status = false;
4309                }
4310                else
4311                {
4312                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4313                      menuBar.OnKeyHit(escape, 0);
4314                }
4315                if(!menuBar.focus && guiApp.caretOwner)
4316                   guiApp.caretOwner.UpdateCaret(true, false);
4317             }
4318          }
4319          if(!destroyed && status)
4320          {
4321             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4322             {
4323                switch(key)
4324                {
4325                   case left: case up: case right: case down:
4326                      if(guiApp.windowMoving == this)
4327                      {
4328                         int step = 1; //8;
4329                         int w = guiApp.windowMoving.size.w;
4330                         int h = guiApp.windowMoving.size.h;
4331                         int x = guiApp.windowMoving.scrolledPos.x;
4332                         int y = guiApp.windowMoving.scrolledPos.y;
4333
4334                         if(guiApp.textMode)
4335                         {
4336                            if(key == down || key == up)
4337                               step = Max(step, textCellH);
4338                            else
4339                               step = Max(step, textCellW);
4340                         }
4341
4342                         if(guiApp.windowIsResizing)
4343                         {
4344                            switch(key)
4345                            {
4346                               case left: w-=step; break;
4347                               case right: w+=step; break;
4348                               case up: h-=step;   break;
4349                               case down: h+=step; break;
4350                            }
4351                         }
4352                         else
4353                         {
4354                            switch(key)
4355                            {
4356                               case left: x-=step; break;
4357                               case right: x+=step; break;
4358                               case up: y-=step;   break;
4359                               case down: y+=step; break;
4360                            }
4361                         }
4362
4363                         if(guiApp.resizeX) x += w - guiApp.windowMoving.size.w;
4364                         if(guiApp.resizeY) y += h - guiApp.windowMoving.size.h;
4365
4366                         if(!guiApp.windowIsResizing || guiApp.resizeX)
4367                            x = (x - guiApp.windowMovingBefore.x) + guiApp.windowMovingStart.x;
4368                         else
4369                            x = (w - guiApp.windowResizingBefore.w) + guiApp.windowMovingStart.x;
4370
4371                         if(!guiApp.windowIsResizing || guiApp.resizeY)
4372                            y = (y - guiApp.windowMovingBefore.y) + guiApp.windowMovingStart.y;
4373                         else                           
4374                            y = (h - guiApp.windowResizingBefore.h) + guiApp.windowMovingStart.y;
4375
4376                         guiApp.interfaceDriver.SetMousePosition(x, y);
4377                         ConsequentialMouseMove(true);
4378
4379                         status = false;
4380                      }
4381                      break;
4382                   case escape:
4383                   case enter:
4384                   case keyPadEnter:
4385                      if(guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4386                      {
4387                         guiApp.windowMoving.StopMoving();
4388                         ConsequentialMouseMove(false);
4389                   
4390                         status = false;
4391                      }
4392                      break;
4393                   case altSpace:
4394                      if(style.fixed)
4395                      {
4396                         ShowSysMenu(absPosition.x, absPosition.y);
4397                         status = false;
4398                      }
4399                      break;
4400                }
4401             }
4402          }
4403
4404          if(!destroyed && status && state != minimized)
4405          {
4406             // Process all the way down the children
4407             if(activeChild && !activeChild.disabled)
4408             {
4409                status = activeChild.KeyMessage(method, key, character);
4410             }
4411             if(status && activeClient && activeChild != activeClient && !activeClient.disabled && (key.alt || key.ctrl) &&
4412                key.code != left && key.code != right && key.code != up && key.code != down)
4413             {
4414                status = activeClient.KeyMessage(method, key, character);
4415             }
4416
4417             // Default Control
4418             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4419             {
4420                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && !defaultControl.disabled && state != minimized)
4421                   // && defaultControl != activeChild)
4422                {
4423                   delete previousActive;
4424                   previousActive = activeChild;
4425                   if(previousActive) incref previousActive;
4426
4427                   ConsequentialMouseMove(false);
4428                   if((defaultControl.active ||
4429                      defaultControl.ActivateEx(true, true, false, true, null, null)) && !defaultControl.disabled)
4430                      defaultControl.KeyMessage(method, defaultKey, character);
4431                   status = false;                       
4432                }
4433             }
4434          }
4435
4436          if(!destroyed && status && (!modalWindow || this == guiApp.desktop))
4437          {
4438             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4439             {
4440                switch(key)
4441                {
4442                   case altMinus:
4443                      if(style.fixed)
4444                      {
4445                         ShowSysMenu(absPosition.x, absPosition.y);
4446                         status = false;
4447                      }
4448                      break;
4449                   //case f5:
4450                   /*
4451                   case shiftF5:
4452                      if(this != guiApp.desktop)
4453                      {
4454                         if(!guiApp.windowMoving && !guiApp.windowCaptured)
4455                         {
4456                            if(state != maximized && (key.shift ? style.sizeable : style.fixed))
4457                            {
4458                               MenuMoveOrSize(key.shift, true);
4459                               status = false;
4460                            }
4461                         }
4462                         else if(guiApp.windowMoving)
4463                         {
4464                            guiApp.windowMoving.StopMoving();
4465                            ConsequentialMouseMove(false);
4466                            status = false;
4467                         }
4468                      }
4469                      break;
4470                   */
4471                }
4472             }
4473             if(!destroyed && status && state != minimized)
4474             {
4475                if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4476                {
4477                   switch(key)
4478                   {
4479                      case tab: case shiftTab:
4480                      {
4481                         Window cycleParent = this;
4482                         if(this == guiApp.interimWindow && !master.style.interim && !cycleParent.style.tabCycle)
4483                            cycleParent = master.parent;
4484                         
4485                         if(!guiApp.windowCaptured && cycleParent.style.tabCycle)
4486                         {
4487                            if(cycleParent.CycleChildren(!key.shift, false, false, true))
4488                            {
4489                               Window child = cycleParent.activeChild;
4490
4491                               // Scroll the window to include the active control
4492                               /*
4493                               if(cycleParent.sbh && !child.style.dontScrollHorz)
4494                               {
4495                                  if(child.scrolledPos.x < 0)
4496                                     cycleParent.sbh.Action(Position, 
4497                                        cycleParent.scroll.x + child.scrolledPos.x, 0);
4498                                  else if(child.scrolledPos.x + child.size.w > cycleParent.clientSize.w)
4499                                     cycleParent.sbh.Action(Position,
4500                                        cycleParent.scroll.x + child.scrolledPos.x + child.size.w - cycleParent.clientSize.w, 0);
4501                               }
4502                               if(cycleParent.sbv && !child.style.dontScrollVert)
4503                               {
4504                                  if(child.scrolledPos.y < 0)
4505                                     cycleParent.sbv.Action(Position, 
4506                                        cycleParent.scroll.y + child.scrolledPos.y, 0);
4507                                  else if(child.scrolledPos.y + child.size.w > window.clientSize.h)
4508                                     cycleParent.sbv.Action(Position,
4509                                        cycleParent.scroll.y + child.scrolledPos.y+child.size.h - cycleParent.clientSize.h, 0);
4510                               }
4511                               */
4512                               cycleParent.ConsequentialMouseMove(false);
4513                               status = false;
4514                            }
4515                         }
4516                         break;
4517                      }
4518                      case f6: case shiftF6:
4519                         if(!guiApp.windowMoving /*!guiApp.windowCaptured*/)
4520                         {
4521                            // NOT NEEDED... guiApp.windowMoving.ReleaseCapture();
4522                            if(parent == guiApp.desktop)
4523                               if(guiApp.desktop.CycleChildren(key.shift, true, false, true))
4524                               {
4525                                  status = false;
4526                                  break;
4527                               }
4528                            if(style.tabCycle)
4529                            {
4530                               delete this;
4531                               return true;
4532                            }
4533                            if(CycleChildren(key.shift, true, false, true))
4534                            {
4535                               status = false;
4536                               break;
4537                            }
4538                         }
4539                         break;
4540                      /*
4541                      // mIRC Style Window Shortcuts
4542                      case alt1: case alt2: case alt3: case alt4: case alt5:
4543                      case alt6: case alt7: case alt8: case alt9: case alt0:
4544                      {
4545                         if(numPositions)
4546                         {
4547                            Window document;
4548                            for(document = children.first; document; document = document.next)
4549                            {
4550                               if(document.style.isDocument && document.documentID - 1 == key.code - k1)
4551                               {
4552                                  if(document == activeChild)
4553                                  {
4554                                     if(document.state == minimized)
4555                                        document.SetState(normal, false, key);
4556                                     else
4557                                     {
4558                                        document.SetState(minimized, false, key);
4559                                        CycleChildren(false, true, false);
4560                                     }
4561                                  }
4562                                  else
4563                                  {
4564                                     if(activeChild.state == maximized && document.style.hasMaximize)
4565                                        document.SetState(maximized, false, key);
4566                                     else if(document.state == minimized)
4567                                        document.SetState(normal, false, key);
4568                                     document.Activate();
4569                                  }
4570                                  status = false;
4571                                  break;
4572                               }
4573                            }
4574                         }
4575                         break;            
4576                      }
4577                      */
4578                   }
4579                }
4580             }
4581          }
4582
4583          if(!destroyed && status)
4584          {
4585             if(state == minimized)
4586             {
4587                delete this;
4588                return true;
4589             }
4590             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4591             {
4592                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && previousActive)
4593                {
4594                   if(defaultControl.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, character))
4595                      previousActive.ActivateEx(true, false, false, true, null, null);
4596                   delete previousActive;
4597                   status = false;
4598                }
4599             }
4600          }
4601
4602          if(!destroyed && status)
4603          {
4604             status = ProcessHotKeys(method, key, character);
4605          }
4606          if(!destroyed && status && !modalWindow && state != minimized)
4607          {
4608             if(KeyMethod)
4609                status = KeyMethod(this, key, character);
4610             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4611                status = OnKeyHit(key, character);
4612             if(!destroyed && status && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit))
4613             {
4614                bool result = false;
4615                switch(key)
4616                {
4617                   case ctrlUp: case ctrlDown:
4618                      if(sbv && !guiApp.windowScrolling)
4619                         result = sbv.Action((key == ctrlUp) ? up : down, 0, key);
4620                      break;
4621                   case wheelUp: case wheelDown:
4622                      if(sbv && !guiApp.windowScrolling)
4623                      {
4624                         result = sbv.Action((key == wheelUp) ? wheelUp : wheelDown, 0, key);
4625                         // Do we want to do a consequential move regardless of result in this case?
4626                         ConsequentialMouseMove(false);
4627                      }
4628                      break;
4629                   case ctrlPageUp: case ctrlPageDown:
4630                      if(sbh && !guiApp.windowScrolling)
4631                         result = sbh.Action((key == ctrlPageUp) ? up : down, 0, key);
4632                      break;
4633                }
4634                if(result)
4635                {
4636                   ConsequentialMouseMove(false);
4637                   status = false;
4638                }
4639             }
4640          }
4641          if(status && !destroyed && menuBar && state != minimized)
4642             status = menuBar.KeyMessage(method, key, character);
4643
4644          if(style.interim && /*destroyed && */status && interimMaster)
4645          {
4646             // Testing this... for Ctrl-O to open dialog when autocompletion listbox is popped...
4647             status = interimMaster.KeyMessage(method, key, character);
4648          }
4649          delete this;
4650       }
4651       return status;
4652    }
4653
4654    bool ProcessHotKeys(uint method, Key key, unichar character)
4655    {
4656       bool status = true;
4657       HotKeySlot hotKey;
4658
4659       for(hotKey = hotKeys.first; hotKey; hotKey = hotKey.next)
4660          if((hotKey.key == key || (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp && hotKey.key.code == key.code)) &&
4661             !hotKey.window.disabled && (hotKey.window.style.nonClient || state != minimized))
4662          {
4663             Window hotKeyWindow = hotKey.window;
4664             Window parent = hotKeyWindow.parent;
4665             Window prevActiveWindow = activeChild;
4666             // For when sys buttons are placed inside the menu bar
4667             if(parent && parent._class == class(PopupMenu))
4668                parent = parent.parent;
4669
4670             // 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
4671             if(hotKeyWindow.style.hidden && (!hotKeyWindow.style.nonClient || !parent || !parent.nativeDecorations || (hotKeyWindow != parent.sysButtons[2] && hotKeyWindow != parent.sysButtons[1])))
4672                continue;
4673
4674             if(prevActiveWindow) incref prevActiveWindow;
4675             incref hotKeyWindow;
4676             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && !hotKeyWindow.style.nonClient)
4677                if(!hotKeyWindow.ActivateEx(true, true, false, true, null, null))
4678                {
4679                   status = false;
4680                   delete hotKeyWindow;
4681                   delete prevActiveWindow;
4682                   break;
4683                }
4684
4685             if(hotKeyWindow.style.nonClient && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4686                method = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
4687             if(!hotKeyWindow.KeyMessage(method, Key::hotKey, character))
4688             {
4689                // *********   WORKING ON THIS   ***********
4690                if(prevActiveWindow && !guiApp.interimWindow)
4691                   prevActiveWindow.ActivateEx(true, false, false, false, null, null);
4692                status = false;
4693             }
4694             else if(hotKeyWindow.style.inactive)
4695                status = hotKeyWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, Key::hotKey, character);
4696
4697             delete prevActiveWindow;
4698             delete hotKeyWindow;
4699             // For Key Ups, don't set status to false... (e.g.: Releasing Enter vs AltEnter hot key)
4700             if(method != __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4701                status = false;
4702             break;
4703          }
4704       if(status && tabCycle)
4705       {
4706          Window child;
4707          for(child = children.first; child; child = child.next)
4708          {
4709             if(child.tabCycle && !child.ProcessHotKeys(method, key, character))
4710             {
4711                status = false;
4712                break;
4713             }
4714          }
4715       }
4716       return status;
4717    }
4718
4719
4720    // --- Windows and graphics initialization / termination ---
4721    bool SetupRoot(void)
4722    {
4723       Window child;
4724
4725       // Setup relationship with outside world (bb root || !bb)
4726       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop || 
4727          (_displayDriver && dispDriver != parent.dispDriver))
4728       {
4729          rootWindow = this;
4730          if(!tempExtents)
4731             tempExtents = new0 Extent[4];
4732          against = null;
4733       }
4734       else
4735       {
4736          /*if(guiApp.fullScreenMode)
4737             rootWindow = guiApp.desktop;
4738          else*/
4739          //rootWindow = parent.created ? parent.rootWindow : null;
4740          rootWindow = parent.rootWindow;
4741
4742          if(style.nonClient)
4743             against = &parent.box;
4744          else
4745             against = &parent.clientArea;
4746       }
4747
4748       for(child = children.first; child; child = child.next)
4749          child.SetupRoot();
4750
4751       return (rootWindow && (rootWindow == this || rootWindow.created)) ? true : false;
4752    }
4753
4754    bool Setup(bool positionChildren)
4755    {
4756       bool result = false;
4757       Window child;
4758
4759       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || (guiApp.fullScreenMode && (this == guiApp.desktop || (_displayDriver && dispDriver != parent.dispDriver))))
4760       {
4761          subclass(DisplayDriver) dDriver = (dispDriver && !formDesigner) ? dispDriver : GetDisplayDriver(guiApp.defaultDisplayDriver);
4762          DisplaySystem displaySystem = dDriver ? dDriver.displaySystem : null;
4763
4764          windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this);
4765
4766          // This was here, is it really needed?
4767          //guiApp.interfaceDriver.ActivateRootWindow(this);
4768
4769          if(!displaySystem)
4770          {
4771             displaySystem = DisplaySystem {};
4772             if(!displaySystem.Create(dDriver.name, guiApp.fullScreenMode ? windowHandle : windowHandle /*null*/, guiApp.fullScreenMode))
4773             {
4774                delete displaySystem;
4775             }
4776          }
4777          if(displaySystem)
4778          {
4779             display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, windowDriverData = windowData };
4780             if(display.Create(displaySystem, windowHandle))
4781                result = true;
4782             else
4783             {
4784                delete display;
4785             }
4786          }
4787          // Sometimes icon does not show up on Windows XP if we set here...
4788          // guiApp.interfaceDriver.SetIcon(this, icon);
4789       }
4790       else if(this != guiApp.desktop)
4791       {
4792          display = rootWindow ? rootWindow.display : null;
4793          result = true;
4794       }
4795       else
4796          result = true;
4797
4798       if(guiApp.acquiredWindow && rootWindow == guiApp.acquiredWindow.rootWindow)
4799          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, true);
4800
4801       for(child = children.first; child; child = child.next)
4802       {
4803          if(child.created && !child.Setup(false))
4804             result = false; 
4805       }
4806       return result;
4807    }
4808
4809    bool SetupDisplay(void)
4810    {
4811 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
4812       if(is3D) return Window3D_SetupDisplay(this); else 
4813 #endif   
4814       if(SetupRoot())
4815          return Setup(true);
4816       return false;
4817    }
4818
4819    class_data void ** pureVTbl;
4820
4821    bool LoadGraphics(bool creation, bool resetAnchors)
4822    {
4823       bool result = false;
4824       bool success = false;
4825       Window child;
4826       WindowState stateBackup = state;
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 }