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