ecere/gui/Window: (#708) Fix for update bugs on scrolling in Installer
[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          }
3242       }
3243       return result;
3244    }
3245
3246    Window FindModal(void)
3247    {
3248       Window modalWindow = this, check;
3249       Window check2 = null;
3250       for(check = this; check.master; check = check.master)
3251       {
3252          if(check.master.modalSlave && check.master.modalSlave.created && check != check.master.modalSlave)
3253          {
3254             modalWindow = check.master.modalSlave;
3255             check = modalWindow;
3256          }
3257          // TESTING THIS FOR DROPBOX...
3258          if(!rootWindow || !rootWindow.style.interim)
3259          {
3260             for(check2 = check; check2.activeChild; check2 = check2.activeChild)
3261             {
3262                if(check2.modalSlave && check2.modalSlave.created)
3263                {
3264                   modalWindow = check2.modalSlave;
3265                   break;
3266                }
3267             }
3268          }
3269       }
3270
3271       /*
3272       if(modalWindow == this)
3273       {
3274          for(check = this; check.activeChild; check = check.activeChild)
3275          {
3276             if(check.modalSlave)
3277             {
3278                modalWindow = check.modalSlave;
3279                break;
3280             }
3281          }
3282       }
3283       */
3284       for(; modalWindow.modalSlave && modalWindow.modalSlave.created; modalWindow = modalWindow.modalSlave);
3285       return (modalWindow == this || this == guiApp.interimWindow || IsDescendantOf(modalWindow)) ? null : modalWindow;
3286    }
3287
3288    void StopMoving(void)
3289    {
3290       if(this == guiApp.windowMoving)
3291       {
3292          guiApp.windowMoving = null;
3293          UpdateDecorations();
3294          SetMouseRange(null);
3295          if(rootWindow)
3296          {
3297             if(rootWindow.active)
3298                guiApp.interfaceDriver.StopMoving(rootWindow);
3299          }
3300          ReleaseCapture();
3301          guiApp.resizeX = guiApp.resizeY = guiApp.resizeEndX = guiApp.resizeEndY = false;
3302          guiApp.windowIsResizing = false;
3303       }
3304    }
3305
3306    void SelectMouseCursor(void)
3307    {
3308       int x,y;
3309       Window mouseWindow;
3310       Window modalWindow;
3311       Window cursorWindow = null;
3312       bool rx, ry, rex, rey;
3313
3314       guiApp.desktop.GetMousePosition(&x, &y);
3315       mouseWindow = rootWindow ? rootWindow.GetAtPosition(x,y, true, false, null) : null;
3316
3317       if((guiApp.windowMoving && !guiApp.windowIsResizing) || guiApp.windowScrolling)
3318          guiApp.SetCurrentCursor(guiApp.systemCursors[moving]);
3319       else if(mouseWindow)
3320       {
3321          modalWindow = mouseWindow.FindModal();
3322          x -= mouseWindow.absPosition.x;
3323          y -= mouseWindow.absPosition.y;
3324          if(guiApp.windowIsResizing)
3325          {
3326             rex = guiApp.resizeEndX;
3327             rey = guiApp.resizeEndY;
3328             rx = guiApp.resizeX;
3329             ry = guiApp.resizeY;
3330             if((rex && rey) || (rx && ry))
3331                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
3332             else if((rex && ry) || (rx && rey))
3333                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
3334             else if((ry || rey) && (!rx && !rex))
3335                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
3336             else if((rx || rex) && (!ry && !rey))
3337                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
3338          }
3339          else if(!modalWindow && !guiApp.windowCaptured &&
3340             mouseWindow.IsMouseResizing(x, y, mouseWindow.size.w, mouseWindow.size.h,
3341                &rx, &ry, &rex, &rey))
3342          {
3343             if((rex && rey) || (rx && ry))
3344                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNWSE]);
3345             else if((rex && ry) || (rx && rey))
3346                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNESW]);
3347             else if((ry || rey) && (!rx && !rex))
3348                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeNS]);
3349             else if((rx || rex) && (!ry && !rey))
3350                guiApp.SetCurrentCursor(guiApp.systemCursors[sizeWE]);
3351          }
3352          else if(!guiApp.windowCaptured && !modalWindow && !guiApp.interimWindow)
3353          {
3354             if(!mouseWindow.clientArea.IsPointInside({x - mouseWindow.clientStart.x, y - mouseWindow.clientStart.y}))
3355                cursorWindow = mouseWindow.parent;
3356             else
3357                cursorWindow = mouseWindow;
3358          }
3359          else if(!guiApp.interimWindow)
3360             cursorWindow = guiApp.windowCaptured;
3361          if(cursorWindow)
3362          {
3363             for(; !cursorWindow.cursor && !cursorWindow.style.nonClient; cursorWindow = cursorWindow.parent);
3364             guiApp.SetCurrentCursor(cursorWindow.cursor ? cursorWindow.cursor : guiApp.systemCursors[arrow]);
3365          }
3366          else if(modalWindow)
3367          {
3368             guiApp.SetCurrentCursor(guiApp.systemCursors[arrow]);
3369          }
3370          else if(guiApp.interimWindow)
3371          {
3372             if(guiApp.interimWindow.cursor)
3373                guiApp.SetCurrentCursor(guiApp.interimWindow.cursor);
3374             else
3375                guiApp.SetCurrentCursor(mouseWindow.cursor ? mouseWindow.cursor : guiApp.systemCursors[arrow]);
3376          }
3377       }
3378    }
3379
3380    // --- State based input ---
3381    bool AcquireInputEx(bool state)
3382    {
3383       bool result;
3384       if(state) 
3385       {
3386          guiApp.interfaceDriver.GetMousePosition(&guiApp.acquiredMouseX, &guiApp.acquiredMouseY);
3387          guiApp.interfaceDriver.SetMousePosition(clientSize.w/2 + absPosition.x, clientSize.h/2 + absPosition.y);
3388       }
3389       result = guiApp.interfaceDriver.AcquireInput(rootWindow, state);
3390       if(result)
3391          guiApp.acquiredWindow = state ? this : null;
3392       if(state && result)
3393       {
3394          SetMouseRangeToClient();
3395          guiApp.interfaceDriver.SetMouseCursor((SystemCursor)-1);
3396       }
3397       else
3398       {
3399          FreeMouseRange();
3400          SelectMouseCursor();
3401       }
3402       if(!state) guiApp.interfaceDriver.SetMousePosition(guiApp.acquiredMouseX, guiApp.acquiredMouseY);
3403       return result;
3404    }
3405
3406    // --- Window activation ---
3407    bool PropagateActive(bool active, Window previous, bool * goOnWithActivation, bool direct)
3408    {
3409       bool result = true;
3410       if(!parent || !parent.style.inactive)
3411       {
3412          Window parent = this.parent;
3413
3414          /*
3415          if(rootWindow == this)
3416             Log(active ? "active\n" : "inactive\n");
3417          */
3418
3419          // Testing this here...
3420          if(!parent || parent == guiApp.desktop || parent.active)
3421          {
3422             this.active = active;
3423          }
3424
3425          // TESTING THIS HERE
3426          UpdateDecorations();
3427          if(result = OnActivate(active, previous, goOnWithActivation, direct) && *goOnWithActivation && master)
3428             result = NotifyActivate(master, this, active, previous);
3429          else
3430          {
3431             this.active = !active;
3432          }
3433
3434          if(result)
3435          {
3436             if(!parent || parent == guiApp.desktop || parent.active)
3437             {
3438                this.active = active;
3439                if(acquiredInput)
3440                   AcquireInputEx(active);
3441                if(active)
3442                {
3443                   if(caretSize)
3444                   {
3445                      if(guiApp.caretOwner)
3446                      {
3447                         Box extent 
3448                         {
3449                            guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 1, 
3450                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + 1,
3451                            guiApp.caretOwner.caretPos.x - guiApp.caretOwner.scroll.x + 2, 
3452                            guiApp.caretOwner.caretPos.y - guiApp.caretOwner.scroll.y + guiApp.caretOwner.caretSize - 1
3453                         };
3454                         guiApp.caretOwner.Update(extent);
3455                      }
3456
3457                      if(visible || !guiApp.caretOwner)
3458                         guiApp.caretOwner = this;
3459                      UpdateCaret(false, false);
3460                   }
3461                }
3462             }
3463             else
3464             {
3465                this.active = false;
3466                if(acquiredInput)
3467                   AcquireInputEx(active);
3468             }
3469             if(!active && guiApp.caretOwner == this)
3470             {
3471                UpdateCaret(false, true);
3472                guiApp.caretOwner = null;
3473                guiApp.interfaceDriver.SetCaret(0,0,0);
3474                guiApp.caretEnabled = false;
3475             }
3476
3477             if(!style.interim)
3478             {
3479                if(!active && parent && parent.activeChild && parent.activeChild != this)
3480                   if(!parent.activeChild.PropagateActive(false, previous, goOnWithActivation, true) || !*goOnWithActivation)
3481                   {
3482                      return false;
3483                   }
3484             }
3485
3486             if(!active && menuBar)
3487             {
3488                bool goOn;
3489                menuBar.OnActivate(false, null, &goOn, true);
3490                menuBar.NotifyActivate(menuBar.master, menuBar, false, null);
3491             }
3492
3493             if(activeChild)
3494             {
3495                Window aChild = activeChild;
3496                incref aChild;
3497                if(!aChild.PropagateActive(active, previous, goOnWithActivation, false) || !*goOnWithActivation)
3498                {
3499                   delete aChild;
3500                   return false;
3501                }
3502                delete aChild;
3503             }
3504          }
3505       }
3506       return result;
3507    }
3508
3509    void ConsequentialMouseMove(bool kbMoving)
3510    {
3511       if(rootWindow)
3512       {
3513          if(kbMoving || !guiApp.windowMoving)
3514          {
3515             Modifiers mods {};
3516             int x,y;
3517             if(rootWindow == guiApp.desktop || rootWindow.parent == guiApp.desktop)
3518             {
3519                guiApp.interfaceDriver.GetMousePosition(&x, &y);
3520
3521                if(guiApp.windowMoving || rootWindow.GetAtPosition(x, y, true, false, null))
3522                   rootWindow.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove, x, y, &mods, true, false);
3523             }
3524          }
3525       }
3526    }
3527
3528    bool IsDescendantOf(Window ancestor)
3529    {
3530       Window window;
3531       for(window = this; window && window != ancestor; window = window.parent);
3532       return window == ancestor;
3533    }
3534
3535    bool IsSlaveOf(Window master)
3536    {
3537       Window window;
3538       for(window = this; window && window != master; window = window.master);
3539       return window == master;
3540    }
3541
3542    bool ActivateEx(bool active, bool activateParent, bool moveInactive, bool activateRoot, Window external, Window externalSwap)
3543    {
3544       bool result = true;
3545
3546       if(this && !destroyed /*&& state != Hidden*/)
3547       {
3548          Window swap = externalSwap;
3549
3550          incref this;
3551
3552          if(parent)
3553          {
3554             if(!active)
3555                StopMoving();
3556             if(activateParent && 
3557                (parent.activeChild != this || 
3558                (guiApp.interimWindow && !IsDescendantOf(guiApp.interimWindow))) &&
3559                active && _isModal &&
3560                parent != master && master)
3561                master.ActivateEx(true, true, false, activateRoot, external, externalSwap);
3562
3563             if(active)
3564             {
3565                if(parent)
3566                {
3567                   bool real = parent.activeChild != this;
3568
3569                   // TEST THIS: New activateParent check here!!! CAUSED MENUS NOT GOING AWAY
3570                   if(!style.inactive && /*activateParent && */guiApp.interimWindow && 
3571                      !IsDescendantOf(guiApp.interimWindow) && 
3572                      !IsSlaveOf(guiApp.interimWindow))
3573                   {
3574                      Window interimWindow = guiApp.interimWindow;
3575                      while(interimWindow && interimWindow != this)
3576                      {
3577                         Window master = interimWindow.master;
3578                         bool goOn = true;
3579                         guiApp.interimWindow = null;
3580                         if(guiApp.caretOwner)
3581                            guiApp.caretOwner.UpdateCaret(false, false);
3582
3583                         incref interimWindow;
3584                         if(!interimWindow.PropagateActive(false, this, &goOn, true))
3585                         {
3586                            result = false;
3587                            real = false;
3588                         }
3589                         delete interimWindow;
3590                         interimWindow = (master && master.style.interim) ? master : null;
3591                      }
3592                   }
3593                   if(style.interim)
3594                   {
3595                      guiApp.interimWindow = this;
3596                      /*guiApp.interfaceDriver.SetCaret(0,0,0);
3597                      guiApp.caretEnabled = false;*/
3598                      UpdateCaret(false, true);
3599                   }
3600
3601                   if(real)
3602                   {
3603                      bool acquireInput = false;
3604                      bool maximize =
3605                         parent.activeChild &&
3606                         parent.activeChild.state == maximized &&
3607                         parent != guiApp.desktop;
3608
3609                      if(!style.inactive) // (!style.isRemote || parent.active || parent.style.hidden))
3610                      {
3611                         if(!style.interim)
3612                         {
3613                            if(!swap && parent)
3614                               swap = parent.activeChild;
3615                            if(swap && swap.destroyed) swap = null;
3616                            if(swap && swap != this)
3617                            {
3618                               bool goOn = true;
3619                               if(!swap.PropagateActive(false, this, &goOn, true))
3620                                  swap = parent.activeChild;
3621                               if(!goOn)
3622                               {
3623                                  delete this;
3624                                  return false;
3625                               }
3626                            }
3627                            else
3628                               swap = null;
3629                         }
3630
3631                         if(!parent || parent.activeChild != this || style.interim)
3632                         {
3633                            bool goOn = true;
3634                            result = PropagateActive(true, swap, &goOn, true);
3635                            if(!result && !goOn) 
3636                            {
3637                               delete this;
3638                               return false;
3639                            }
3640                            acquireInput = true;
3641                         }
3642                      }
3643
3644                      if(style.hasMaximize && parent != guiApp.desktop)
3645                      {
3646                         if(maximize)
3647                            SetState(maximized, false, 0);
3648                         else if(state != maximized)
3649                         {
3650                            Window child;
3651                            for(child = parent.children.first; child; child = child.next)
3652                            {
3653                               if(this != child && child.state == maximized)
3654                                  child.SetState(normal, false, 0);
3655                            }
3656                         }
3657                      }
3658                   }
3659                   if(result)
3660                   {
3661                      if(!style.inactive && !style.interim /*&& (!style.isRemote || parent.active || parent.style.hidden)*/)
3662                      {
3663                         Window previous = parent.activeClient;
3664                         parent.activeChild = this;
3665                         if(!style.nonClient /*&& style.isActiveClient*/)
3666                         {
3667                            if(!style.hidden)
3668                            {
3669                               if(style.isActiveClient)
3670                                  parent.activeClient = this;
3671                               // Moved UpdateActiveDocument inside hidden check
3672                               // To prevent activating previous window while creating a new one
3673                               // (It was messing up the privateModule in the CodeEditor)
3674                               parent.UpdateActiveDocument(previous);
3675                            }
3676                         }
3677                      }
3678                   }
3679
3680                   //if(!style.isRemote)
3681                   {
3682                      if(rootWindow != this)
3683                      {
3684                         if(activateParent && parent && !parent.active /*parent != parent.parent.activeChild*/)
3685                            parent.ActivateEx(true, true, moveInactive, activateRoot, external, externalSwap);
3686                      }
3687                      else if(!guiApp.fullScreenMode)
3688                      {
3689                         Window modalRoot = FindModal();
3690                         if(!modalRoot) modalRoot = this;
3691                         if(!modalRoot.isForegroundWindow)
3692                         {
3693                            modalRoot.isForegroundWindow = true;
3694                            // To check : Why is parent null?
3695                            if(activateRoot && modalRoot.parent && !modalRoot.parent.display && external != modalRoot)
3696                            {
3697                               guiApp.interfaceDriver.ActivateRootWindow(modalRoot);
3698                            }
3699                            modalRoot.isForegroundWindow = false;
3700                         }
3701                      }
3702                   }
3703                
3704                   if(result && real && (!style.inactive || moveInactive) && parent)
3705                   {
3706                      Window last = parent.children.last;
3707
3708                      if(!style.stayOnTop)
3709                         for(; last && last.style.stayOnTop; last = last.prev);
3710                      
3711                      parent.children.Move(this, last);
3712
3713                      // Definitely don't want that:   why not?
3714                      Update(null);
3715
3716                      if(order)
3717                         parent.childrenOrder.Move(order, parent.childrenOrder.last);
3718                   }
3719                }
3720             }
3721             else 
3722             {
3723                if(!parent || style.interim || (parent.activeChild == this && !style.inactive))
3724                {
3725                   bool goOn = true;
3726                   if(!style.interim)
3727                   {
3728                      if(parent)
3729                      {
3730                         parent.activeChild = null;
3731                         if(!style.nonClient /*&& style.isActiveClient*/)
3732                         {
3733                            Window previous = parent.activeClient;
3734                            if(style.isActiveClient)
3735                               parent.activeClient = null;
3736                            parent.UpdateActiveDocument(previous);
3737                         }
3738                      }
3739                   }
3740                   if(this == guiApp.interimWindow)
3741                   {
3742                      guiApp.interimWindow = null;
3743                      if(guiApp.caretOwner)
3744                         guiApp.caretOwner.UpdateCaret(false, false);
3745                   }
3746                   if(!PropagateActive(false, externalSwap, &goOn, true) || !goOn)
3747                   {
3748                      delete this;
3749                      return false;
3750                   }
3751                }
3752             }
3753             if(!active || !swap)
3754                UpdateDecorations();
3755             if(swap)
3756                swap.UpdateDecorations();
3757
3758             if(active && rootWindow != this)
3759                ConsequentialMouseMove(false);
3760          }
3761          delete this;
3762       }
3763       return true;
3764    }
3765
3766    // --- Input Messages ---
3767    void ::UpdateMouseMove(int mouseX, int mouseY, bool consequential)
3768    {
3769       static bool reEntrancy = false;
3770       if(reEntrancy) return;
3771
3772       reEntrancy = true;
3773
3774       guiApp.cursorUpdate = true;
3775       if(guiApp.windowScrolling && !consequential)
3776       {
3777          guiApp.windowScrolling.SetScrollPosition(
3778             (guiApp.windowScrolling.sbh) ? 
3779                (guiApp.windowScrollingBefore.x - mouseX + guiApp.windowScrollingStart.x) : 0,
3780             (guiApp.windowScrolling.sbv) ? 
3781                (guiApp.windowScrollingBefore.y - mouseY + guiApp.windowScrollingStart.y) : 0);
3782       }
3783       if(guiApp.windowMoving)
3784       {
3785          if(mouseX != guiApp.movingLast.x || mouseY != guiApp.movingLast.y)
3786          {
3787             Window window = guiApp.windowMoving;
3788             int rx, ry;
3789             int w = window.size.w;
3790             int h = window.size.h;
3791             int aw, ah;
3792             MinMaxValue ew, eh;
3793             int x, y;
3794
3795             rx = mouseX - guiApp.windowMovingStart.x;
3796             ry = mouseY - guiApp.windowMovingStart.y;
3797
3798             // Size
3799             window.GetDecorationsSize(&ew, &eh);
3800
3801             if(guiApp.windowIsResizing)
3802             {
3803                x = window.scrolledPos.x;
3804                y = window.scrolledPos.y;
3805
3806                if(guiApp.resizeX)
3807                {
3808                   aw = Max(guiApp.windowResizingBefore.w - rx,window.skinMinSize.w);
3809                   rx = guiApp.windowResizingBefore.w - aw;
3810                   rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x;
3811                   w = guiApp.windowResizingBefore.w - rx;
3812                }
3813                if(guiApp.resizeY)
3814                {
3815                   ah = Max(guiApp.windowResizingBefore.h - ry,window.skinMinSize.h);
3816                   ry = guiApp.windowResizingBefore.h - ah;
3817                   ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y;
3818                   ry = Max(ry, -guiApp.windowMovingBefore.y);
3819                   h = guiApp.windowResizingBefore.h - ry;
3820                }
3821                if(guiApp.resizeEndX)
3822                {
3823                   w = guiApp.windowResizingBefore.w + rx;
3824                   w = Max(w,1-x);
3825                }
3826                if(guiApp.resizeEndY) h = guiApp.windowResizingBefore.h + ry;
3827
3828                w -= ew;
3829                h -= eh;
3830
3831                w = Max(w, 1);
3832                h = Max(h, 1);
3833
3834                w = Max(w, window.minSize.w);
3835                h = Max(h, window.minSize.h);
3836                w = Min(w, window.maxSize.w);
3837                h = Min(h, window.maxSize.h);
3838
3839                if(!window.OnResizing(&w, &h))
3840                {
3841                   w = window.clientSize.w;
3842                   h = window.clientSize.h;
3843                }
3844
3845                w = Max(w, window.skinMinSize.w);
3846                h = Max(h, window.skinMinSize.h);
3847
3848                w += ew;
3849                h += eh;
3850
3851                if(guiApp.textMode)
3852                {
3853                   SNAPDOWN(w, textCellW);
3854                   SNAPDOWN(h, textCellH);
3855                }
3856
3857                if(guiApp.resizeX)
3858                {
3859                   aw = Max(w,window.skinMinSize.w);
3860                   rx = guiApp.windowResizingBefore.w - aw;
3861                   rx = Min(guiApp.windowMovingBefore.x + rx, window.parent.clientSize.w-1) - guiApp.windowMovingBefore.x;
3862                   w = guiApp.windowResizingBefore.w - rx;
3863                }
3864                if(guiApp.resizeY)
3865                {
3866                   ah = Max(h,window.skinMinSize.h);
3867                   ry = guiApp.windowResizingBefore.h - ah;
3868                   ry = Min(guiApp.windowMovingBefore.y + ry, window.parent.clientSize.h-1) - guiApp.windowMovingBefore.y;
3869                   ry = Max(ry, -guiApp.windowMovingBefore.y);
3870                   h = guiApp.windowResizingBefore.h - ry;
3871                }
3872             }
3873          
3874             // Position
3875             if(!guiApp.windowIsResizing || guiApp.resizeX)
3876                x = guiApp.windowMovingBefore.x + rx;
3877             if(!guiApp.windowIsResizing || guiApp.resizeY)
3878                y = guiApp.windowMovingBefore.y + ry;
3879
3880             if(!guiApp.windowIsResizing)
3881             {
3882                // Limit
3883                if(window.parent == guiApp.desktop && guiApp.virtualScreen.w)
3884                {
3885                   x = Min(x, (guiApp.virtualScreen.w + guiApp.virtualScreenPos.x) -1);
3886                   y = Min(y, (guiApp.virtualScreen.h + guiApp.virtualScreenPos.y) -1);
3887                   x = Max(x,-(w-1) + guiApp.virtualScreenPos.x);
3888                   y = Max(y,-(h-1) + guiApp.virtualScreenPos.y);
3889                }
3890                else
3891                {
3892                   x = Min(x, (window.parent.reqScrollArea.w ? window.parent.reqScrollArea.w : window.parent.clientSize.w) -1);
3893                   y = Min(y, (window.parent.reqScrollArea.h ? window.parent.reqScrollArea.h : window.parent.clientSize.h) -1);
3894                   x = Max(x,-(w-1));
3895                   y = Max(y,-(h-1));
3896                }
3897             }
3898
3899             if(!guiApp.windowIsResizing || (guiApp.resizeX || guiApp.resizeY))
3900             {
3901                if(!window.OnMoving(&x, &y, w, h))
3902                {
3903                   x = window.scrolledPos.x;
3904                   y = window.scrolledPos.y;
3905                }
3906             }
3907
3908             if(guiApp.textMode)
3909             {
3910                SNAPDOWN(x, textCellW);
3911                SNAPDOWN(y, textCellH);
3912             }
3913
3914             if(!window.style.nonClient)
3915             {
3916                if(!window.style.fixed /*|| window.style.isDocument*/)
3917                {
3918                   if(!window.style.dontScrollHorz)
3919                      x += window.parent.scroll.x;
3920                   if(!window.style.dontScrollVert)
3921                      y += window.parent.scroll.y;
3922                }
3923             }
3924
3925             // Break the anchors for moveable/resizable windows
3926             // Will probably cause problem with IDE windows... Will probably need a way to specify if anchors should break
3927             if(window.style.fixed) 
3928             {
3929                if(window.state == normal)
3930                {
3931                   window.normalAnchor = Anchor { left = x, top = y };
3932                   window.normalSizeAnchor = SizeAnchor { { w, h } };
3933                   window.anchored = false;
3934                }
3935             }
3936
3937             window.stateAnchor = Anchor { left = x, top = y };
3938             window.stateSizeAnchor = SizeAnchor { { w, h } };
3939
3940             window.Position(x, y, w, h, false, true, guiApp.windowIsResizing, guiApp.windowIsResizing, false, true);
3941             // TOCHECK: Investigate why the following only redraws the scrollbars
3942             //window.Position(x, y, w, h, false, true, true, true, false, true);
3943
3944             guiApp.movingLast.x = mouseX;
3945             guiApp.movingLast.y = mouseY;
3946          }
3947       }
3948       reEntrancy = false;
3949    }
3950
3951    public bool MouseMessage(uint method, int x, int y, Modifiers * mods, bool consequential, bool activate)
3952    {
3953       bool result = true;
3954       bool wasMoving = guiApp.windowMoving ? true : false;
3955       bool wasScrolling = guiApp.windowScrolling ? true : false;
3956       Window w = null;
3957       while(result && w != this)
3958       {
3959          Window msgWindow = GetAtPosition(x,y, false, true, w);
3960          Window trueWindow = GetAtPosition(x,y, false, false, w);
3961          bool windowDragged = false;
3962          Window window;
3963          delete w;
3964          w = msgWindow;
3965          if(w) incref w;
3966          window = (w && !w.disabled) ? w : null;
3967          
3968          if(trueWindow) incref trueWindow;
3969
3970          if(consequential) mods->isSideEffect = true;
3971
3972          UpdateMouseMove(x, y, consequential);
3973
3974          if(guiApp.windowCaptured && (guiApp.windowCaptured.rootWindow == this))
3975          {
3976             if(!guiApp.windowCaptured.isEnabled)
3977                guiApp.windowCaptured.ReleaseCapture();
3978             else
3979                window = guiApp.windowCaptured;
3980          }
3981
3982          if(trueWindow && activate &&
3983             (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown ||
3984              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown ||
3985              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown ||
3986              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick))
3987          {
3988             if(mods->alt && !mods->ctrl && !mods->shift)
3989             {
3990                Window moved = trueWindow;
3991                for(moved = trueWindow; moved; moved = moved.parent)
3992                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
3993                      break;
3994                if(moved) 
3995                {
3996                   window = moved;
3997                   windowDragged = true;
3998
3999                   // Cancel the ALT menu toggling...
4000                   window.rootWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
4001                }
4002             }
4003          }
4004
4005          if(window && activate &&
4006             (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown ||
4007              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown ||
4008              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown ||
4009              method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick))
4010          {
4011             Window modalWindow = window.FindModal();
4012
4013             /*if(mods->alt && !mods->shift && !mods->ctrl)
4014             {
4015                Window moved = window;
4016                for(moved = window; moved; moved = moved.parent)
4017                   if(method == OnRightButtonDown || ((moved.style.fixed || moved.moveable) && moved.state != maximized)) 
4018                      break;
4019                if(moved) 
4020                {
4021                   window = moved;
4022                   windowDragged = true;
4023
4024                   // Cancel the ALT menu toggling...
4025                   window.rootWindow.KeyMessage(OnKeyDown, 0, 0);
4026                }
4027             }*/
4028
4029             if(!windowDragged)
4030             {
4031                Window activateWindow = modalWindow ? modalWindow : window;
4032                if(activateWindow && !activateWindow.isRemote)
4033                {
4034                   bool doActivation = true;
4035                   //bool needToDoActivation = false;
4036                   Window check = activateWindow;
4037
4038                   for(check = activateWindow; check && check != guiApp.desktop; check = check.parent)
4039                   {
4040                      if(!check.style.inactive)
4041                      {
4042                         //needToDoActivation = true;
4043                         if(check.active)
4044                            doActivation = false;
4045                         break;
4046                      }
4047                   }
4048                   /*
4049                   if(!needToDoActivation)
4050                      doActivation = false;
4051                   */
4052
4053                   if((doActivation && (activateWindow.parent != guiApp.desktop || guiApp.fullScreen)) || 
4054                      (guiApp.interimWindow && !window.IsDescendantOf(guiApp.interimWindow)))
4055                   {
4056                      // Let the OnLeftButtonDown do the activating instead
4057                      if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)
4058                      {
4059                         window = null;
4060                         result = true;
4061                      }
4062                      else
4063                      //if(activate)
4064                      {
4065                         incref activateWindow;
4066                         if(!activateWindow.ActivateEx(true, true, false, true, null, null))
4067                         {
4068                            delete activateWindow;
4069                            delete trueWindow;
4070                            return false;
4071                         }
4072                         if(activateWindow._refCount == 1)
4073                         {
4074                            delete activateWindow;
4075                            delete trueWindow;
4076                            return false;
4077                         }
4078                         delete activateWindow;
4079                         // Trouble with clickThrough, siblings and activation (Fix for nicktick scrolling, siblings/activation endless loops, #844)
4080                         activate = false;
4081                      }
4082                      mods->isActivate = true;
4083                   }
4084                }
4085             }
4086             if(!modalWindow && window && !window.destroyed)
4087             {
4088                if(!guiApp.windowCaptured || windowDragged)
4089                {
4090                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown)
4091                   {
4092                      bool moving = ((window.state != maximized &&
4093                            window.IsMouseMoving(
4094                         x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
4095                         || (guiApp.windowMoving && !guiApp.windowIsResizing);
4096
4097                      if(!moving && window.IsMouseResizing(
4098                         x - window.absPosition.x,
4099                         y - window.absPosition.y,
4100                         window.size.w, window.size.h,
4101                         &guiApp.resizeX, &guiApp.resizeY, &guiApp.resizeEndX, &guiApp.resizeEndY))
4102                      {
4103                         guiApp.windowIsResizing = true;
4104                         guiApp.windowResizingBefore.w = window.size.w;
4105                         guiApp.windowResizingBefore.h = window.size.h;
4106                      }
4107                      if(guiApp.windowIsResizing || windowDragged || moving)
4108                      {
4109                         window.Capture();
4110                         guiApp.windowMoving = window;
4111                         guiApp.windowMovingStart.x = guiApp.movingLast.x = x;
4112                         guiApp.windowMovingStart.y = guiApp.movingLast.y = y;
4113                         guiApp.windowMovingBefore.x = window.position.x;//s;
4114                         guiApp.windowMovingBefore.y = window.position.y;//s;
4115                         if(guiApp.windowMoving == guiApp.windowMoving.rootWindow)
4116                            guiApp.interfaceDriver.StartMoving(guiApp.windowMoving.rootWindow, 0,0,false);
4117                      }
4118                   }
4119                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown)
4120                   {
4121                      if(window.style.fixed &&
4122                         (windowDragged || 
4123                         window.IsMouseMoving(
4124                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h)))
4125                      {
4126                         window.ShowSysMenu(x, y);
4127                         result = false;
4128                      }
4129                   }
4130                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown)
4131                   {
4132                      if(window.sbv || window.sbh)
4133                      {
4134                         window.Capture();
4135                         guiApp.windowScrolling = window;
4136                         guiApp.windowScrollingStart.x = x;
4137                         guiApp.windowScrollingStart.y = y;
4138                         guiApp.windowScrollingBefore.x = window.scroll.x;
4139                         guiApp.windowScrollingBefore.y = window.scroll.y;
4140                      }
4141                   }
4142                   else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick)
4143                   {
4144                      if(window.style.hasMaximize && 
4145                         window.IsMouseMoving( 
4146                            x - window.absPosition.x, y - window.absPosition.y, window.size.w, window.size.h))
4147                      {
4148                         window.SetState(
4149                            (window.state == maximized) ? normal : maximized, false, *mods);
4150                         result = false;
4151                      }
4152                   }
4153                }
4154             }
4155             else
4156                window = null;
4157             if(guiApp.windowMoving) 
4158             {
4159                if(guiApp.windowMoving.parent)
4160                {
4161                   if(guiApp.windowMoving.style.nonClient)
4162                      guiApp.windowMoving.parent.SetMouseRangeToWindow();
4163                   else
4164                      guiApp.windowMoving.parent.SetMouseRangeToClient();
4165                }
4166                else
4167                   FreeMouseRange();
4168                window.UpdateDecorations();
4169             }
4170          }
4171          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp)
4172          {
4173             // Log("\n*** LEFT BUTTON UP ***\n");
4174             if(guiApp.windowMoving)
4175                guiApp.windowMoving.StopMoving();
4176          }
4177          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp)
4178          {
4179             if(guiApp.windowScrolling)
4180             {
4181                Window windowScrolling = guiApp.windowScrolling;
4182                guiApp.windowScrolling = null;
4183                windowScrolling.ReleaseCapture();
4184             }
4185          }
4186
4187          if(!result || (window && window.destroyed)) window = null;
4188
4189          if(window && window.FindModal())
4190             window = null;
4191
4192          if(trueWindow && trueWindow.FindModal())
4193             delete trueWindow;
4194          
4195          /*if(trueWindow)
4196             incref trueWindow;
4197          */
4198
4199          /*
4200          msgWindow = GetAtPosition(x,y, true, false);
4201          if(msgWindow)
4202             msgWindow.SelectMouseCursor();
4203          */
4204
4205          if(guiApp.windowCaptured || trueWindow)
4206          {
4207             Window prevWindow = guiApp.prevWindow;
4208             if(guiApp.prevWindow && trueWindow != guiApp.prevWindow)
4209             {
4210                guiApp.prevWindow.mouseInside = false;
4211                guiApp.prevWindow = null;
4212
4213                // Eventually fix this not to include captured?
4214                if(!prevWindow.OnMouseLeave(*mods))
4215                   result = false;
4216             }
4217             if(result && trueWindow && !trueWindow.destroyed/* && trueWindow == window*/)
4218             {
4219                Box box = trueWindow.box;
4220                box.left += trueWindow.absPosition.x;
4221                box.right += trueWindow.absPosition.x;
4222                box.top += trueWindow.absPosition.y;
4223                box.bottom += trueWindow.absPosition.y;
4224
4225                if(box.IsPointInside({x, y}) && trueWindow != /*guiApp.*/prevWindow /*!trueWindow.mouseInside*/)
4226                {
4227                   int overX = x - (trueWindow.absPosition.x + trueWindow.clientStart.x);
4228                   int overY = y - (trueWindow.absPosition.y + trueWindow.clientStart.y);
4229
4230                   overX = Max(Min(overX, 32767),-32768);
4231                   overY = Max(Min(overY, 32767),-32768);
4232
4233                   trueWindow.mouseInside = true;
4234                   if(!trueWindow.OnMouseOver(overX, overY, *mods))
4235                      result = false;
4236                }
4237             }
4238             if(trueWindow && trueWindow._refCount > 1 && !trueWindow.destroyed)
4239                guiApp.prevWindow = trueWindow;
4240             else
4241                guiApp.prevWindow = null;
4242          }
4243          SelectMouseCursor();
4244
4245          if(window && !guiApp.windowMoving && !wasMoving && !wasScrolling)
4246          {
4247             int clientX = x - (window.absPosition.x + window.clientStart.x);
4248             int clientY = y - (window.absPosition.y + window.clientStart.y);
4249
4250             bool (* MouseMethod)(Window instance, int x, int y, Modifiers mods);
4251
4252             clientX = Max(Min(clientX, 32767),-32768);
4253             clientY = Max(Min(clientY, 32767),-32768);
4254
4255             MouseMethod = (void *)window._vTbl[method];
4256
4257             if(MouseMethod /*&& !consequential*/ && !window.disabled)
4258             {
4259                incref window;
4260                if(!MouseMethod(window, clientX, clientY, *mods))
4261                   result = false;
4262                delete window;
4263             }
4264          }
4265          delete trueWindow;
4266          /*
4267          if(result && w && w.clickThrough && w.parent)
4268             w = w.parent;
4269          else
4270             break;
4271          */
4272          if(!result || !w || !w.clickThrough)
4273             break;
4274       }
4275       delete w;
4276       return result;
4277    }
4278
4279    // --- Mouse cursor management ---
4280
4281    bool KeyMessage(uint method, Key key, unichar character)
4282    {
4283       bool status = true;
4284       if(!parent)
4285       {
4286          if(guiApp.interimWindow)
4287             this = guiApp.interimWindow;
4288       }
4289 #ifdef _DEBUG
4290       if((SmartKey)key != alt && (SmartKey)key != Key::control && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && parent && this != parent.menuBar)
4291          Print("");
4292 #endif
4293
4294       if(!style.inactive || rootWindow != this)
4295       {
4296          bool (*KeyMethod)(Window window, Key key, unichar ch) = (void *)_vTbl[method];
4297          Window modalWindow = FindModal();
4298          Window interimMaster = master ? master.rootWindow : null;
4299
4300          incref this;
4301
4302          if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4303             status = OnSysKeyDown(key, character);
4304          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4305             status = OnSysKeyHit(key, character);
4306          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4307             status = OnSysKeyUp(key, character);
4308          if(!status)
4309          {
4310             delete this;
4311             return true;
4312          }
4313
4314          // Process Key Message for Internal UI Keyboard actions
4315          if(status && !destroyed && menuBar && state != minimized)
4316          {
4317             // Disable the ALT
4318             if((SmartKey)key != alt) 
4319                menuBar.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
4320             if(menuBar.focus)
4321             {
4322                SmartKey sk = (SmartKey) key;
4323                if((character && !key.alt && !key.ctrl) || sk == left || sk == right || sk == up || sk == down || sk == home || sk == end || sk == escape || sk == alt)
4324                {
4325                   status = menuBar.KeyMessage(method, key, character);
4326                   status = false;
4327                }
4328                else
4329                {
4330                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4331                      menuBar.OnKeyHit(escape, 0);
4332                }
4333                if(!menuBar.focus && guiApp.caretOwner)
4334                   guiApp.caretOwner.UpdateCaret(true, false);
4335             }
4336          }
4337          if(!destroyed && status)
4338          {
4339             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4340             {
4341                switch(key)
4342                {
4343                   case left: case up: case right: case down:
4344                      if(guiApp.windowMoving == this)
4345                      {
4346                         int step = 1; //8;
4347                         int w = guiApp.windowMoving.size.w;
4348                         int h = guiApp.windowMoving.size.h;
4349                         int x = guiApp.windowMoving.scrolledPos.x;
4350                         int y = guiApp.windowMoving.scrolledPos.y;
4351
4352                         if(guiApp.textMode)
4353                         {
4354                            if(key == down || key == up)
4355                               step = Max(step, textCellH);
4356                            else
4357                               step = Max(step, textCellW);
4358                         }
4359
4360                         if(guiApp.windowIsResizing)
4361                         {
4362                            switch(key)
4363                            {
4364                               case left: w-=step; break;
4365                               case right: w+=step; break;
4366                               case up: h-=step;   break;
4367                               case down: h+=step; break;
4368                            }
4369                         }
4370                         else
4371                         {
4372                            switch(key)
4373                            {
4374                               case left: x-=step; break;
4375                               case right: x+=step; break;
4376                               case up: y-=step;   break;
4377                               case down: y+=step; break;
4378                            }
4379                         }
4380
4381                         if(guiApp.resizeX) x += w - guiApp.windowMoving.size.w;
4382                         if(guiApp.resizeY) y += h - guiApp.windowMoving.size.h;
4383
4384                         if(!guiApp.windowIsResizing || guiApp.resizeX)
4385                            x = (x - guiApp.windowMovingBefore.x) + guiApp.windowMovingStart.x;
4386                         else
4387                            x = (w - guiApp.windowResizingBefore.w) + guiApp.windowMovingStart.x;
4388
4389                         if(!guiApp.windowIsResizing || guiApp.resizeY)
4390                            y = (y - guiApp.windowMovingBefore.y) + guiApp.windowMovingStart.y;
4391                         else                           
4392                            y = (h - guiApp.windowResizingBefore.h) + guiApp.windowMovingStart.y;
4393
4394                         guiApp.interfaceDriver.SetMousePosition(x, y);
4395                         ConsequentialMouseMove(true);
4396
4397                         status = false;
4398                      }
4399                      break;
4400                   case escape:
4401                   case enter:
4402                   case keyPadEnter:
4403                      if(guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4404                      {
4405                         guiApp.windowMoving.StopMoving();
4406                         ConsequentialMouseMove(false);
4407                   
4408                         status = false;
4409                      }
4410                      break;
4411                   case altSpace:
4412                      if(style.fixed)
4413                      {
4414                         ShowSysMenu(absPosition.x, absPosition.y);
4415                         status = false;
4416                      }
4417                      break;
4418                }
4419             }
4420          }
4421
4422          if(!destroyed && status && state != minimized)
4423          {
4424             // Process all the way down the children
4425             if(activeChild && !activeChild.disabled)
4426             {
4427                status = activeChild.KeyMessage(method, key, character);
4428             }
4429             if(status && activeClient && activeChild != activeClient && !activeClient.disabled && (key.alt || key.ctrl) &&
4430                key.code != left && key.code != right && key.code != up && key.code != down)
4431             {
4432                status = activeClient.KeyMessage(method, key, character);
4433             }
4434
4435             // Default Control
4436             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4437             {
4438                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && !defaultControl.disabled && state != minimized)
4439                   // && defaultControl != activeChild)
4440                {
4441                   delete previousActive;
4442                   previousActive = activeChild;
4443                   if(previousActive) incref previousActive;
4444
4445                   ConsequentialMouseMove(false);
4446                   if((defaultControl.active ||
4447                      defaultControl.ActivateEx(true, true, false, true, null, null)) && !defaultControl.disabled)
4448                      defaultControl.KeyMessage(method, defaultKey, character);
4449                   status = false;                       
4450                }
4451             }
4452          }
4453
4454          if(!destroyed && status && (!modalWindow || this == guiApp.desktop))
4455          {
4456             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4457             {
4458                switch(key)
4459                {
4460                   case altMinus:
4461                      if(style.fixed)
4462                      {
4463                         ShowSysMenu(absPosition.x, absPosition.y);
4464                         status = false;
4465                      }
4466                      break;
4467                   //case f5:
4468                   /*
4469                   case shiftF5:
4470                      if(this != guiApp.desktop)
4471                      {
4472                         if(!guiApp.windowMoving && !guiApp.windowCaptured)
4473                         {
4474                            if(state != maximized && (key.shift ? style.sizeable : style.fixed))
4475                            {
4476                               MenuMoveOrSize(key.shift, true);
4477                               status = false;
4478                            }
4479                         }
4480                         else if(guiApp.windowMoving)
4481                         {
4482                            guiApp.windowMoving.StopMoving();
4483                            ConsequentialMouseMove(false);
4484                            status = false;
4485                         }
4486                      }
4487                      break;
4488                   */
4489                }
4490             }
4491             if(!destroyed && status && state != minimized)
4492             {
4493                if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4494                {
4495                   switch(key)
4496                   {
4497                      case tab: case shiftTab:
4498                      {
4499                         Window cycleParent = this;
4500                         if(this == guiApp.interimWindow && master && !master.style.interim && !cycleParent.style.tabCycle && master.parent)
4501                            cycleParent = master.parent;
4502                         
4503                         if(!guiApp.windowCaptured && cycleParent.style.tabCycle)
4504                         {
4505                            if(cycleParent.CycleChildren(!key.shift, false, false, true))
4506                            {
4507                               Window child = cycleParent.activeChild;
4508
4509                               // Scroll the window to include the active control
4510                               /*
4511                               if(cycleParent.sbh && !child.style.dontScrollHorz)
4512                               {
4513                                  if(child.scrolledPos.x < 0)
4514                                     cycleParent.sbh.Action(Position, 
4515                                        cycleParent.scroll.x + child.scrolledPos.x, 0);
4516                                  else if(child.scrolledPos.x + child.size.w > cycleParent.clientSize.w)
4517                                     cycleParent.sbh.Action(Position,
4518                                        cycleParent.scroll.x + child.scrolledPos.x + child.size.w - cycleParent.clientSize.w, 0);
4519                               }
4520                               if(cycleParent.sbv && !child.style.dontScrollVert)
4521                               {
4522                                  if(child.scrolledPos.y < 0)
4523                                     cycleParent.sbv.Action(Position, 
4524                                        cycleParent.scroll.y + child.scrolledPos.y, 0);
4525                                  else if(child.scrolledPos.y + child.size.w > window.clientSize.h)
4526                                     cycleParent.sbv.Action(Position,
4527                                        cycleParent.scroll.y + child.scrolledPos.y+child.size.h - cycleParent.clientSize.h, 0);
4528                               }
4529                               */
4530                               cycleParent.ConsequentialMouseMove(false);
4531                               status = false;
4532                            }
4533                         }
4534                         break;
4535                      }
4536                      case f6: case shiftF6:
4537                         if(!guiApp.windowMoving /*!guiApp.windowCaptured*/)
4538                         {
4539                            // NOT NEEDED... guiApp.windowMoving.ReleaseCapture();
4540                            if(parent == guiApp.desktop)
4541                               if(guiApp.desktop.CycleChildren(key.shift, true, false, true))
4542                               {
4543                                  status = false;
4544                                  break;
4545                               }
4546                            if(style.tabCycle)
4547                            {
4548                               delete this;
4549                               return true;
4550                            }
4551                            if(CycleChildren(key.shift, true, false, true))
4552                            {
4553                               status = false;
4554                               break;
4555                            }
4556                         }
4557                         break;
4558                      /*
4559                      // mIRC Style Window Shortcuts
4560                      case alt1: case alt2: case alt3: case alt4: case alt5:
4561                      case alt6: case alt7: case alt8: case alt9: case alt0:
4562                      {
4563                         if(numPositions)
4564                         {
4565                            Window document;
4566                            for(document = children.first; document; document = document.next)
4567                            {
4568                               if(document.style.isDocument && document.documentID - 1 == key.code - k1)
4569                               {
4570                                  if(document == activeChild)
4571                                  {
4572                                     if(document.state == minimized)
4573                                        document.SetState(normal, false, key);
4574                                     else
4575                                     {
4576                                        document.SetState(minimized, false, key);
4577                                        CycleChildren(false, true, false);
4578                                     }
4579                                  }
4580                                  else
4581                                  {
4582                                     if(activeChild.state == maximized && document.style.hasMaximize)
4583                                        document.SetState(maximized, false, key);
4584                                     else if(document.state == minimized)
4585                                        document.SetState(normal, false, key);
4586                                     document.Activate();
4587                                  }
4588                                  status = false;
4589                                  break;
4590                               }
4591                            }
4592                         }
4593                         break;            
4594                      }
4595                      */
4596                   }
4597                }
4598             }
4599          }
4600
4601          if(!destroyed && status)
4602          {
4603             if(state == minimized)
4604             {
4605                delete this;
4606                return true;
4607             }
4608             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4609             {
4610                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && previousActive)
4611                {
4612                   if(defaultControl.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, character))
4613                      previousActive.ActivateEx(true, false, false, true, null, null);
4614                   delete previousActive;
4615                   status = false;
4616                }
4617             }
4618          }
4619
4620          if(!destroyed && status)
4621          {
4622             status = ProcessHotKeys(method, key, character);
4623          }
4624          if(!destroyed && status && !modalWindow && state != minimized)
4625          {
4626             if(KeyMethod)
4627                status = KeyMethod(this, key, character);
4628             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4629                status = OnKeyHit(key, character);
4630             if(!destroyed && status && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit))
4631             {
4632                bool result = false;
4633                switch(key)
4634                {
4635                   case ctrlUp: case ctrlDown:
4636                      if(sbv && !guiApp.windowScrolling)
4637                         result = sbv.Action((key == ctrlUp) ? up : down, 0, key);
4638                      break;
4639                   case wheelUp: case wheelDown:
4640                      if(sbv && !guiApp.windowScrolling)
4641                      {
4642                         result = sbv.Action((key == wheelUp) ? wheelUp : wheelDown, 0, key);
4643                         // Do we want to do a consequential move regardless of result in this case?
4644                         ConsequentialMouseMove(false);
4645                      }
4646                      break;
4647                   case ctrlPageUp: case ctrlPageDown:
4648                      if(sbh && !guiApp.windowScrolling)
4649                         result = sbh.Action((key == ctrlPageUp) ? up : down, 0, key);
4650                      break;
4651                }
4652                if(result)
4653                {
4654                   ConsequentialMouseMove(false);
4655                   status = false;
4656                }
4657             }
4658          }
4659          if(status && !destroyed && menuBar && state != minimized)
4660             status = menuBar.KeyMessage(method, key, character);
4661
4662          if(style.interim && /*destroyed && */status && interimMaster)
4663          {
4664             // Testing this... for Ctrl-O to open dialog when autocompletion listbox is popped...
4665             status = interimMaster.KeyMessage(method, key, character);
4666          }
4667          delete this;
4668       }
4669       return status;
4670    }
4671
4672    bool ProcessHotKeys(uint method, Key key, unichar character)
4673    {
4674       bool status = true;
4675       HotKeySlot hotKey;
4676
4677       for(hotKey = hotKeys.first; hotKey; hotKey = hotKey.next)
4678          if((hotKey.key == key || (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp && hotKey.key.code == key.code)) &&
4679             !hotKey.window.disabled && (hotKey.window.style.nonClient || state != minimized))
4680          {
4681             Window hotKeyWindow = hotKey.window;
4682             Window parent = hotKeyWindow.parent;
4683             Window prevActiveWindow = activeChild;
4684             // For when sys buttons are placed inside the menu bar
4685             if(parent && parent._class == class(PopupMenu))
4686                parent = parent.parent;
4687
4688             // 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
4689             if(hotKeyWindow.style.hidden && (!hotKeyWindow.style.nonClient || !parent || !parent.nativeDecorations || (hotKeyWindow != parent.sysButtons[2] && hotKeyWindow != parent.sysButtons[1])))
4690                continue;
4691
4692             if(prevActiveWindow) incref prevActiveWindow;
4693             incref hotKeyWindow;
4694             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && !hotKeyWindow.style.nonClient)
4695                if(!hotKeyWindow.ActivateEx(true, true, false, true, null, null))
4696                {
4697                   status = false;
4698                   delete hotKeyWindow;
4699                   delete prevActiveWindow;
4700                   break;
4701                }
4702
4703             if(hotKeyWindow.style.nonClient && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4704                method = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
4705             if(!hotKeyWindow.KeyMessage(method, Key::hotKey, character))
4706             {
4707                // *********   WORKING ON THIS   ***********
4708                if(prevActiveWindow && !guiApp.interimWindow)
4709                   prevActiveWindow.ActivateEx(true, false, false, false, null, null);
4710                status = false;
4711             }
4712             else if(hotKeyWindow.style.inactive)
4713                status = hotKeyWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, Key::hotKey, character);
4714
4715             delete prevActiveWindow;
4716             delete hotKeyWindow;
4717             // For Key Ups, don't set status to false... (e.g.: Releasing Enter vs AltEnter hot key)
4718             if(method != __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4719                status = false;
4720             break;
4721          }
4722       if(status && tabCycle)
4723       {
4724          Window child;
4725          for(child = children.first; child; child = child.next)
4726          {
4727             if(child.tabCycle && !child.ProcessHotKeys(method, key, character))
4728             {
4729                status = false;
4730                break;
4731             }
4732          }
4733       }
4734       return status;
4735    }
4736
4737
4738    // --- Windows and graphics initialization / termination ---
4739    bool SetupRoot(void)
4740    {
4741       Window child;
4742
4743       // Setup relationship with outside world (bb root || !bb)
4744       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop || 
4745          (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver))
4746       {
4747          rootWindow = this;
4748          if(!tempExtents)
4749             tempExtents = new0 Extent[4];
4750          against = null;
4751       }
4752       else
4753       {
4754          /*if(guiApp.fullScreenMode)
4755             rootWindow = guiApp.desktop;
4756          else*/
4757          //rootWindow = parent.created ? parent.rootWindow : null;
4758          rootWindow = parent.rootWindow;
4759
4760          if(style.nonClient)
4761             against = &parent.box;
4762          else
4763             against = &parent.clientArea;
4764       }
4765
4766       for(child = children.first; child; child = child.next)
4767          child.SetupRoot();
4768
4769       return (rootWindow && (rootWindow == this || rootWindow.created)) ? true : false;
4770    }
4771
4772    bool Setup(bool positionChildren)
4773    {
4774       bool result = false;
4775       Window child;
4776
4777       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || (guiApp.fullScreenMode && (this == guiApp.desktop || (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver))))
4778       {
4779          subclass(DisplayDriver) dDriver = (dispDriver && !formDesigner) ? dispDriver : GetDisplayDriver(guiApp.defaultDisplayDriver);
4780          DisplaySystem displaySystem = dDriver ? dDriver.displaySystem : null;
4781
4782          windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this);
4783
4784          // This was here, is it really needed?
4785          //guiApp.interfaceDriver.ActivateRootWindow(this);
4786
4787          if(!displaySystem)
4788          {
4789             displaySystem = DisplaySystem {};
4790             if(!displaySystem.Create(dDriver.name, guiApp.fullScreenMode ? windowHandle : windowHandle /*null*/, guiApp.fullScreenMode))
4791             {
4792                delete displaySystem;
4793             }
4794          }
4795          if(displaySystem)
4796          {
4797             display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, windowDriverData = windowData };
4798             if(display.Create(displaySystem, windowHandle))
4799                result = true;
4800             else
4801             {
4802                delete display;
4803             }
4804          }
4805          // Sometimes icon does not show up on Windows XP if we set here...
4806          // guiApp.interfaceDriver.SetIcon(this, icon);
4807       }
4808       else if(this != guiApp.desktop)
4809       {
4810          display = rootWindow ? rootWindow.display : null;
4811          result = true;
4812       }
4813       else
4814          result = true;
4815
4816       if(guiApp.acquiredWindow && rootWindow == guiApp.acquiredWindow.rootWindow)
4817          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, true);
4818
4819       for(child = children.first; child; child = child.next)
4820       {
4821          if(child.created && !child.Setup(false))
4822             result = false; 
4823       }
4824       return result;
4825    }
4826
4827    bool SetupDisplay(void)
4828    {
4829 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
4830       if(is3D) return Window3D_SetupDisplay(this); else 
4831 #endif   
4832       if(SetupRoot())
4833          return Setup(true);
4834       return false;
4835    }
4836
4837    class_data void ** pureVTbl;
4838
4839    bool LoadGraphics(bool creation, bool resetAnchors)
4840    {
4841       bool result = false;
4842       bool success = false;
4843       Window child;
4844       WindowState stateBackup = state;
4845
4846       if(((subclass(Window))_class).pureVTbl)
4847       {
4848          if(_vTbl == _class._vTbl)
4849          {
4850             _vTbl = ((subclass(Window))_class).pureVTbl;
4851          }
4852          else
4853          {
4854             int m;
4855             for(m = 0; m < _class.vTblSize; m++)
4856             {
4857                if(_vTbl[m] == _class._vTbl[m])
4858                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
4859             }
4860          }
4861       }
4862       if(guiApp.currentSkin && ((subclass(Window))_class).pureVTbl)
4863       {
4864          if(_vTbl == ((subclass(Window))_class).pureVTbl)
4865          {
4866             _vTbl = _class._vTbl;
4867          }
4868          else
4869          {
4870             int m;
4871             for(m = 0; m < _class.vTblSize; m++)
4872             {
4873                if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m])
4874                   _vTbl[m] = _class._vTbl[m];
4875             }
4876          }
4877       }
4878       
4879       if(guiApp.fullScreenMode || this != guiApp.desktop)
4880       {
4881          SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
4882          if(display)
4883          {
4884             ResPtr ptr;
4885             success = true;
4886
4887             display.Lock(false);
4888             if(rootWindow == this)
4889             {
4890                // Set Color Palette
4891                display.SetPalette(palette, true);
4892
4893                // Load Cursors
4894                /*
4895                if(guiApp.fullScreenMode && this == guiApp.desktop)
4896                {
4897                   int c;
4898                   Cursor cursor;
4899
4900                   for(c=0; c<SystemCursor::enumSize; c++)
4901                      if(!guiApp.systemCursors[c].bitmap)
4902                      {
4903                         guiApp.systemCursors[c].bitmapName = guiApp.currentSkin.CursorsBitmaps(c,
4904                            &guiApp.systemCursors[c].hotSpotX,&guiApp.systemCursors[c].hotSpotY, &guiApp.systemCursors[c].paletteShades);
4905                         if(guiApp.systemCursors[c].bitmapName)
4906                         {
4907                            guiApp.systemCursors[c].bitmap = eBitmap_LoadT(guiApp.systemCursors[c].bitmapName, null,
4908                               guiApp.systemCursors[c].paletteShades ? null : guiApp.desktop.display.displaySystem);
4909                            if(guiApp.systemCursors[c].bitmap)
4910                               guiApp.systemCursors[c].bitmap.paletteShades = guiApp.systemCursors[c].paletteShades;
4911                            else
4912                               success = false;
4913                         }
4914                      }
4915                   for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
4916                   {
4917                      cursor.bitmap = eBitmap_LoadT(cursor.bitmapName, null, 
4918                         cursor.paletteShades ? null : guiApp.desktop.display.displaySystem);
4919                      if(cursor.bitmap)
4920                         cursor.bitmap.paletteShades = cursor.paletteShades;
4921                      else
4922                         success = false;
4923                   }
4924                   guiApp.cursorUpdate = true;
4925
4926                   display.Unlock();
4927                   ConsequentialMouseMove(false);
4928                   display.Lock(true);
4929                }
4930                */
4931             }
4932
4933             // Load Window Graphic Resources
4934             
4935             /*
4936             if(usedFont == setFont || usedFont == window.systemFont)
4937                RemoveResource(usedFont);
4938             */
4939             if(setFont)
4940                RemoveResource(setFont); // TESTING setFont instead of usedFont);
4941
4942             if(systemFont)
4943                RemoveResource(systemFont);
4944             
4945             if(captionFont)
4946                RemoveResource(captionFont);
4947
4948             for(ptr = resources.first; ptr; ptr = ptr.next)
4949             {
4950                ptr.loaded = display.displaySystem.LoadResource(ptr.resource);
4951             }
4952             if(setFont)
4953                AddResource(setFont);
4954             if(systemFont)
4955                AddResource(systemFont);
4956
4957             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
4958
4959             firewatchers font;
4960
4961             /*
4962             if(!setFont)
4963             {
4964                //if(master && master.font)
4965                if(parent && parent.font)
4966                {
4967                   font = FontResource
4968                   {
4969                      faceName = parent.font.faceName,
4970                      size = parent.font.size,
4971                      bold = parent.font.bold,
4972                      italic = parent.font.italic,
4973                      underline = parent.font.underline
4974                   };
4975                   //font = parent.font;
4976                   watch(parent) { font { } };
4977                }
4978                else
4979                   font = guiApp.currentSkin.SystemFont();
4980                AddResource(font);
4981
4982                firewatchers font;
4983             }
4984             */
4985
4986             captionFont = guiApp.currentSkin ? guiApp.currentSkin.CaptionFont() : null;
4987             AddResource(captionFont);
4988
4989             if(OnLoadGraphics())
4990             {
4991                int x,y,w,h;
4992
4993                display.Unlock();
4994
4995                //SetScrollLineStep(sbStep.x, sbStep.y);
4996                
4997                if(this != guiApp.desktop)
4998                {
4999                   if(resetAnchors)
5000                   {
5001                      normalAnchor = anchor;
5002                      normalSizeAnchor = sizeAnchor;
5003                   }
5004
5005                   // Break the anchors for moveable/resizable windows
5006                   /*
5007                   if(style.fixed && style.isDocument)
5008                   {
5009                      ComputeAnchors(ax, ay, aw, ah, &x, &y, &w, &h);
5010                      ax = x;
5011                      ay = y;
5012                      aw = w;
5013                      ah = h;
5014                      anchored = false;
5015                   }
5016                   */
5017                   switch(state)
5018                   {
5019                      case maximized:
5020                      
5021                         stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5022                         stateSizeAnchor = SizeAnchor {};
5023                         break;
5024                      
5025                      case minimized:
5026                      {
5027                         int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5028
5029                         stateAnchor = 
5030                            Anchor 
5031                            {
5032                               left = (iconID % maxIcons) * MINIMIZED_WIDTH,
5033                               bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24)
5034                            };
5035                         
5036                         stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5037                         break;
5038                      }
5039                      case normal:
5040                         stateAnchor = normalAnchor;
5041                         stateSizeAnchor = normalSizeAnchor;
5042                         break;
5043                   }
5044                   position = Point { };
5045                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5046
5047                }
5048                else
5049                {
5050                   x = scrolledPos.x;
5051                   y = scrolledPos.y;
5052                   w = size.w;
5053                   h = size.h;
5054                }
5055
5056                if(Position(x, y, w, h, true, false, true, true, true, true))
5057                {
5058                   if((this != guiApp.desktop || guiApp.fullScreenMode) && rootWindow == this)
5059                   {
5060                      if(!style.hidden)
5061                         guiApp.interfaceDriver.SetRootWindowState(this, normal, true);
5062                   }
5063
5064                   Update(null);
5065
5066                   result = true;
5067                }
5068             }
5069             else
5070             {
5071                result = false;
5072                display.Unlock();
5073             }
5074          }
5075       }
5076       else
5077       {
5078          success = result = true;
5079       }
5080
5081       if(!creation && result)
5082       {
5083          // Load menu bar first because sys buttons are on it...
5084          if(menuBar)
5085          {
5086             if(!menuBar.LoadGraphics(false, resetAnchors))
5087             {
5088                result = false;
5089                success = false;
5090             }
5091          }
5092          for(child = children.first; child; child = child.next)
5093          {
5094             if(child.created && child != menuBar && !child.LoadGraphics(false, resetAnchors))
5095             {
5096                result = false;
5097                success = false;
5098             }
5099          }
5100          if(!creation)
5101             CreateSystemChildren();
5102
5103          OnApplyGraphics();
5104       }
5105       if(this == guiApp.desktop && !guiApp.fullScreenMode)
5106       {
5107          if(activeChild)
5108             guiApp.interfaceDriver.ActivateRootWindow(activeChild);
5109       }
5110       /*
5111       TODO:
5112       if(!success)
5113          //guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, caption);
5114          guiApp.LogErrorCode(IERR_GRAPHICS_LOADING_FAILED, class.name);
5115       */
5116
5117       // Do this here to avoid problems on Windows
5118       if(stateBackup == maximized)
5119          property::state = maximized;
5120       return result;
5121    }
5122
5123    void UnloadGraphics(bool destroyWindows)
5124    {
5125       Window child;
5126
5127       // Free children's graphics
5128       for(child = children.first; child; child = child.next)
5129          child.UnloadGraphics(destroyWindows);
5130
5131       if(display)
5132          display.Lock(false);
5133
5134       // Free cursors
5135       if(guiApp.fullScreenMode && this == guiApp.desktop)
5136       {
5137          Cursor cursor;
5138          SystemCursor c;
5139
5140          for(c=0; c<SystemCursor::enumSize; c++)
5141             if(guiApp.systemCursors[c].bitmap)
5142                delete guiApp.systemCursors[c].bitmap;
5143
5144          for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
5145             delete cursor.bitmap;
5146
5147          guiApp.cursorBackground.Free();
5148       }
5149
5150       if(display && display.displaySystem)
5151       {
5152          ResPtr ptr;
5153
5154          for(ptr = resources.first; ptr; ptr = ptr.next)
5155          {
5156             if(ptr.loaded)
5157             {
5158                display.displaySystem.UnloadResource(ptr.resource, ptr.loaded);
5159                ptr.loaded = null;
5160             }
5161          }
5162
5163          // Free window graphics
5164          OnUnloadGraphics();
5165
5166          // Free skin graphics
5167          if(rootWindow == this)
5168          {
5169             DisplaySystem displaySystem = display.displaySystem;
5170             if(is3D)
5171             {
5172                display.driverData = null;
5173                display.displaySystem = null;
5174             }
5175             display.Unlock();
5176             delete display;
5177             if(displaySystem && !displaySystem.numDisplays && !is3D)
5178                delete displaySystem;
5179          }
5180          else
5181          {
5182             display.Unlock();
5183             display = null;
5184          }
5185       }
5186
5187       if(guiApp.acquiredWindow && this == guiApp.acquiredWindow.rootWindow)
5188          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, false);
5189
5190       if(this == guiApp.desktop || parent == guiApp.desktop)
5191       {
5192          if((guiApp.fullScreenMode || this != guiApp.desktop) && rootWindow == this && windowHandle && destroyWindows)
5193             guiApp.interfaceDriver.DestroyRootWindow(this);
5194       }
5195    }
5196
5197    // --- Window Hiding ---
5198
5199    void SetVisibility(bool state)
5200    {
5201       bool visible = (style.hidden || !created) ? false : state;
5202       if(visible != this.visible)
5203       {
5204          Window child;
5205
5206          this.visible = visible;
5207          for(child = children.first; child; child = child.next)
5208             child.SetVisibility(visible);
5209          Update(null);
5210          ConsequentialMouseMove(false);
5211          if(parent && !nonClient) parent.OnChildVisibilityToggled(this, visible);
5212       }
5213    }
5214
5215    // --- Windows and graphics initialization / termination ---
5216
5217    bool DisplayModeChanged(void)
5218    {
5219       bool result = false;
5220       if(!guiApp.fullScreenMode && !guiApp.modeSwitching/* && guiApp.desktop.active*/)
5221       {
5222          guiApp.modeSwitching = true;
5223          UnloadGraphics(false);
5224          if(SetupDisplay())
5225             if(LoadGraphics(false, false))
5226                result = true;
5227          guiApp.modeSwitching = false;
5228       }
5229       return result;
5230    }
5231
5232    // --- Window updates system ---
5233
5234    void UpdateDirty(Box updateBox)
5235    {
5236       if(!manageDisplay) { OnRedraw(null);return; }
5237       if(visible)
5238       {
5239          if(display && (!guiApp.fullScreenMode || guiApp.desktop.active) && !guiApp.modeSwitching)
5240          {
5241             display.Lock(true);
5242             if(display.flags.flipping)
5243             {
5244                Update(null);
5245                rootWindow.UpdateDisplay();
5246             }
5247             else
5248                UpdateBackDisplay(updateBox);
5249
5250             if(guiApp.fullScreenMode)
5251             {
5252                guiApp.cursorUpdate = true;
5253                guiApp.PreserveAndDrawCursor();
5254             }
5255             if(guiApp.fullScreenMode)
5256                guiApp.RestoreCursorBackground();
5257             display.Unlock();
5258          }
5259       }
5260    }
5261
5262    // This function is strictly called as a result of system window activation
5263    bool ExternalActivate(bool active, bool activateRoot, Window window, Window swap)
5264    {
5265       bool result = true;
5266       Window interimMaster = null;
5267       Window interimWindow = guiApp.interimWindow;
5268       if(interimWindow && interimWindow.master)
5269          interimMaster = interimWindow.master.rootWindow;
5270
5271       if(active && state == minimized) // && (!window.nativeDecorations || window.rootWindow != window)
5272          // SetState(normal, false, 0);
5273          SetState(lastState, false, 0);
5274
5275       if(interimMaster && swap == interimMaster && interimMaster.IsSlaveOf(window))
5276          return false;
5277
5278       incref this;
5279       /* WTH is this doing here?
5280       while(swap && swap.activeChild)
5281       {
5282          swap = swap.activeChild;         
5283       }
5284       */
5285       // TESTING THIS BEFORE...
5286       if(interimWindow && this == interimMaster)
5287       {
5288          if(active)
5289          {
5290             // Window interimSwap = this;
5291             Window menuBar = this.menuBar;
5292             if(menuBar && interimWindow.master == menuBar)
5293             {
5294                /*
5295                while(interimSwap && interimSwap.activeChild)
5296                   interimSwap = interimSwap.activeChild;
5297
5298                result = interimWindow.ActivateEx(false, false, false, activateRoot, null,
5299                (menuBar && interimWindow.master == menuBar) ? menuBar : interimSwap);
5300                */
5301                result = /*interimWindow.*/ActivateEx(false, false, false, activateRoot, null, menuBar);
5302                //result = ActivateEx(true, true, false, activateRoot, window, null);
5303             }
5304          }
5305       }
5306       else
5307          // Testing & FindModal() here: broke reactivating when a modal dialog is up (didn't root activate dialog)
5308          result = ActivateEx(active, active, false, activateRoot /*&& FindModal()*/, window, swap);
5309
5310       if(interimWindow == this && interimMaster && !active)
5311       {
5312          while(interimMaster && interimMaster.interim && interimMaster.master)
5313          {
5314             // printf("Going up one master %s\n", interimMaster._class.name);
5315             interimMaster = interimMaster.master.rootWindow;
5316          }
5317          // printf("Unactivating interim master %s (%x)\n", interimMaster._class.name, interimMaster);
5318          interimMaster.ActivateEx(active, active, false, activateRoot, window, swap);
5319       }
5320       delete this;
5321       return result;
5322    }
5323
5324    bool DestroyEx(int64 returnCode)
5325    {
5326       OldLink slave;
5327       Timer timer, nextTimer;
5328       Window child;
5329       OldLink prevOrder = null;
5330       Window client = null;
5331
5332       if(parent) stopwatching(parent, font); 
5333
5334       // if(window.modalSlave) return false;
5335       if(destroyed || !created)
5336       {
5337          if(master)
5338          {
5339             /*
5340             if(destroyed)
5341             {
5342                OldLink slave = master.slaves.FindLink(this);
5343                master.slaves.Delete(slave);
5344             }
5345             */
5346             // TOFIX IMMEDIATELY: COMMENTED THIS OUT... causes problem second time creating file dialog
5347             //master = null;
5348          }
5349          return true;
5350       }
5351
5352       this.returnCode = (DialogResult)returnCode;
5353
5354       AcquireInput(false);
5355
5356       destroyed = true;
5357       if(hotKey)
5358       {
5359          master.hotKeys.Delete(hotKey);
5360          hotKey = null;
5361       }
5362
5363       if(guiApp.prevWindow == this)
5364       {
5365          guiApp.prevWindow = null;
5366          OnMouseLeave(0);
5367       }
5368       if(guiApp.caretOwner == this) 
5369       {
5370          guiApp.interfaceDriver.SetCaret(0,0,0);
5371          UpdateCaret(false, true);
5372          guiApp.caretEnabled = false;
5373       }
5374
5375       /*
5376       if(cycle)
5377          parent.childrenCycle.Remove(cycle);
5378       */
5379       if(order)
5380       {
5381          OldLink tmpPrev = order.prev;
5382          if(tmpPrev && !(((Window)tmpPrev.data).style.hidden) && !(((Window)tmpPrev.data).destroyed) && (((Window)tmpPrev.data).created))
5383             prevOrder = tmpPrev;
5384          for(;;)
5385          {
5386             client = tmpPrev ? tmpPrev.data : null;
5387             if(client == this) { client = null; break; }
5388             if(client && (client.style.hidden || client.destroyed || !client.created))
5389                tmpPrev = client.order.prev;
5390             else
5391             {
5392                if(client)
5393                   prevOrder = tmpPrev;
5394                break;
5395             }
5396          }
5397
5398          // If this window can be an active client, make sure the next window we activate can also be one
5399          if(!style.nonClient && style.isActiveClient)
5400          {
5401             tmpPrev = prevOrder;
5402             for(;;)
5403             {
5404                client = tmpPrev ? tmpPrev.data : null;
5405                if(client == this) { client = null; break; }
5406                if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
5407                   tmpPrev = client.order.prev;
5408                else 
5409                {
5410                   if(client)
5411                      prevOrder = tmpPrev;
5412                   break;
5413                }
5414             }
5415             if(client && client.style.hidden) client = null;
5416          }
5417          // parent.childrenOrder.Remove(order);
5418       }
5419
5420       if(parent && style.isActiveClient && visible)
5421       {
5422          if(state == minimized) parent.numIcons--;
5423          parent.numPositions--;
5424       }
5425
5426       // TESTING THIS HERE!
5427       created = false;
5428       visible = false;
5429
5430       // If no display, don't bother deactivating stuff (causes unneeded problems when trying
5431       // to create a window inside a rootwindow that's being destroyed)
5432       // DISABLED THIS BECAUSE OF CREATING WINDOW IN DESKTOP IN WINDOWED MODE
5433
5434       if(master && !master.destroyed /*&&
5435          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5436       {
5437          if(master.defaultControl == this)
5438             master.defaultControl = null;
5439       }
5440       if(parent)
5441          parent.OnChildAddedOrRemoved(this, true);
5442       if(parent && !parent.destroyed /*&&
5443          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5444       {
5445          if((parent.activeChild == this /*|| parent.activeClient == this */|| guiApp.interimWindow == this))
5446          {
5447             if(order && prevOrder && prevOrder.data != this && active)
5448             {
5449                //((Window)prevOrder.data).ActivateEx(true, false, false, false /*true*/, null);
5450
5451                ((Window)prevOrder.data).ActivateEx(true, false, false, (rootWindow == this) ? true : false, null, null);
5452                if(parent.activeClient == this)
5453                {
5454                   parent.activeClient = null;
5455                   parent.UpdateActiveDocument(null);
5456                }
5457             }
5458             else 
5459             {
5460                if(guiApp.interimWindow == this)
5461                {
5462                   bool goOn = true;
5463                   PropagateActive(false, null, &goOn, true);
5464                }
5465                else
5466                {
5467                   //if(window.parent.activeChild == window)
5468                      parent.activeChild = null;
5469                   if(!style.nonClient /*&& style.isActiveClient*/)
5470                   {
5471                      Window previous = parent.activeClient;
5472                      if(style.isActiveClient)
5473                         parent.activeClient = null;
5474                      parent.UpdateActiveDocument(previous);
5475                   }
5476                }
5477             }
5478          }
5479          else if(parent.activeClient == this)
5480          {
5481             parent.activeClient = client;
5482             parent.UpdateActiveDocument(this);
5483
5484          }
5485       }
5486       if(guiApp.interimWindow == this)
5487       {
5488          guiApp.interimWindow = null;
5489          if(guiApp.caretOwner)
5490          {
5491             Window desktop = guiApp.desktop;
5492             if(desktop.activeChild && desktop.activeChild.menuBar && !desktop.activeChild.menuBar.focus)
5493                guiApp.caretOwner.UpdateCaret(false, false);
5494          }
5495       }
5496
5497       active = false;
5498       if(_isModal && master && master.modalSlave == this)
5499          master.modalSlave = null;
5500
5501       if(parent)
5502       {
5503          if(!guiApp.caretOwner && parent.caretSize)
5504          {
5505             guiApp.caretOwner = parent;
5506             parent.UpdateCaret(false, false);
5507             parent.Update(null);
5508          }
5509
5510          // Why was this commented out?
5511          GetRidOfVirtualArea();
5512       }
5513       /*
5514       delete cycle;
5515       delete order;
5516       */
5517       dirtyArea.Free(null);
5518       dirtyBack.Free(null);
5519       scrollExtent.Free(null);
5520
5521       /* ATTEMPTING TO MOVE THAT ABOVE
5522       created = false;
5523       visible = false;
5524       */
5525
5526       /*
5527       OnDestroy();
5528       {
5529          //Window next;
5530          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5531          for(;(child = window.children.first);)
5532          {
5533             for(; child && (child.destroyed || !child.created); child = child.next);
5534             if(child)
5535                child.DestroyEx(0);
5536             else
5537                break;
5538          }
5539       }
5540       */
5541
5542       UnloadGraphics(true);
5543
5544       if(previousActive)
5545          delete previousActive;
5546
5547       menuBar = null;
5548       // statusBar = null;
5549       sbv = sbh = null;
5550
5551       if(master && !master.destroyed)
5552       {
5553          //master.NotifyDestroyed(this, this.returnCode);
5554          NotifyDestroyed(master, this, this.returnCode);
5555       }
5556
5557       for(timer = guiApp.windowTimers.first; timer; timer = nextTimer)
5558       {
5559          nextTimer = timer.next;
5560          if(timer.window == this)
5561          {
5562             // WHY WERE WE SETTING THIS TO NULL? NO MORE WINDOW WHEN RECREATING...
5563             // timer.window = null;
5564             timer.Stop();
5565             //delete timer;
5566          }
5567       }
5568
5569       if(this == guiApp.windowMoving)
5570          StopMoving();
5571
5572       if(guiApp.windowCaptured == this)
5573          ReleaseCapture();
5574          //guiApp.windowCaptured = null;
5575
5576       if(rootWindow != this && rootWindow)
5577          rootWindow.ConsequentialMouseMove(false);
5578
5579       rootWindow = null;
5580
5581       OnDestroy();
5582
5583       {
5584          //Window next;
5585          //for(child = children.first; next = child ? child.next : null, child; child = next)
5586          for(;(child = children.first); )
5587          {
5588             for(; child && (child.destroyed || !child.created); child = child.next);
5589             if(child)
5590                child.DestroyEx(0);
5591             else
5592                break;
5593          }
5594       }
5595
5596       // master = null;
5597
5598       /* // MOVED THIS UP...
5599       {
5600          //Window next;
5601          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5602          for(;(child = window.children.first); )
5603          {
5604             for(; child && (child.destroyed || !child.created); child = child.next);
5605             if(child)
5606                child.DestroyEx(0);
5607             else
5608                break;
5609          }
5610       }
5611       */
5612
5613       while((slave = slaves.first))
5614       {
5615          for(; slave && (((Window)slave.data).destroyed || !((Window)slave.data).created); slave = slave.next);
5616          if(slave)
5617             ((Window)slave.data).DestroyEx(0);
5618          else
5619             break;
5620       }
5621
5622       if(guiApp.caretOwner == this)
5623          guiApp.caretOwner = null;
5624
5625       sysButtons[0] = null;
5626       sysButtons[1] = null;
5627       sysButtons[2] = null;
5628       activeChild = null;
5629
5630       if(rootWindow != this)
5631       {
5632          Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
5633          if(style.nonClient)
5634          {
5635             box.left   -= parent.clientStart.x;
5636             box.top    -= parent.clientStart.y;
5637             box.right  -= parent.clientStart.x;
5638             box.bottom -= parent.clientStart.y;
5639          }
5640          if(parent) parent.Update(box);
5641       }
5642       /*
5643       if(master)
5644       {
5645          OldLink slave = master.slaves.FindVoid(this);
5646          master.slaves.Delete(slave);
5647          master = null;
5648       }
5649
5650       if(parent)
5651       {
5652          parent.children.Remove(this);
5653          parent = null;
5654       }
5655       */
5656
5657       //autoCreate = false;
5658       //created = false;
5659
5660       // SHOULD THIS BE HERE? FIXED CRASH WITH GOTO DIALOG
5661       if(((subclass(Window))_class).pureVTbl)
5662       {
5663          if(_vTbl == _class._vTbl)
5664          {
5665             _vTbl = ((subclass(Window))_class).pureVTbl;
5666          }
5667          else
5668          {
5669             int m;
5670             for(m = 0; m < _class.vTblSize; m++)
5671             {
5672                if(_vTbl[m] == _class._vTbl[m])
5673                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
5674             }
5675          }
5676       }
5677
5678       delete this;
5679       return true;
5680    }
5681
5682    void SetStateEx(WindowState newState, bool activate)
5683    {
5684       int x,y,w,h;
5685       WindowState prevState = state;
5686
5687       state = newState;
5688
5689       if(prevState != newState)
5690          lastState = prevState;
5691
5692       if(rootWindow != this || !nativeDecorations || !windowHandle)
5693       {
5694          if(style.isActiveClient && !style.hidden && prevState == minimized)
5695             parent.numIcons--;
5696
5697          // This block used to be at the end of the function... moved it for flicker problem in X
5698          // ------------------------------------------------------
5699          switch(state)
5700          {
5701             case normal:
5702                stateAnchor = normalAnchor;
5703                stateSizeAnchor = normalSizeAnchor;
5704                break;
5705             case maximized:
5706                stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5707                stateSizeAnchor = SizeAnchor {};
5708                break;
5709             case minimized:
5710             {
5711                int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5712                Window child;
5713                int size = 256;
5714                byte * idBuffer = new0 byte[size];
5715                int c;
5716                for(child = parent.children.first; child; child = child.next)
5717                {
5718                   if(child != this && child.state == minimized)
5719                   {
5720                      if(child.iconID > size - 2)
5721                      {
5722                         idBuffer = renew0 idBuffer byte[size*2];
5723                         memset(idBuffer + size, 0, size);
5724                         size *= 2;
5725                      }
5726                      idBuffer[child.iconID] = (byte)bool::true;
5727                   }
5728                }
5729                for(c = 0; c<size; c++)
5730                   if(!idBuffer[c])
5731                      break;
5732                iconID = c;
5733                delete idBuffer;
5734                if(style.isActiveClient && !style.hidden)
5735                   parent.numIcons++;
5736
5737                stateAnchor = Anchor { left = (iconID % maxIcons) * MINIMIZED_WIDTH, bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24) };
5738                stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5739                break;
5740             }
5741          }
5742          // TOCHECK: Why was this here?
5743          //position.x = (tx > 0) ? tx & 0xFFFFF : tx;
5744          //position.y = (ty > 0) ? ty & 0xFFFFF : ty;
5745          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5746
5747          Position(x, y, w, h, true, true, true, true, false, true);
5748
5749          if(!style.inactive && !style.interim && this == parent.activeClient)
5750             parent.UpdateActiveDocument(null);
5751       }
5752
5753       CreateSystemChildren();
5754       // ------------------------------------------------------
5755    }
5756
5757    int GetPositionID(Window forChild)
5758    {
5759       Window child;
5760       int size = 256;
5761       byte * idBuffer = new0 byte[size];
5762       int c;
5763
5764       for(child = children.first; child; child = child.next)
5765       {
5766          if(child.style.isActiveClient && !child.style.hidden && child != forChild)
5767          {
5768             if(child.positionID > size - 2)
5769             {
5770                idBuffer = renew0 idBuffer byte[size*2];
5771                memset(idBuffer + size, 0, size);
5772                size *= 2;
5773             }
5774             idBuffer[child.positionID] = (byte)bool::true;
5775          }
5776       }
5777       for(c = 0; c<size; c++)
5778          if(!idBuffer[c])
5779             break;
5780       delete idBuffer;
5781       return c;
5782    }
5783
5784    // --- Window related graphics ---
5785
5786    void SetPalette(ColorAlpha * newPalette, bool colorMatch)
5787    {
5788       palette = newPalette;
5789       if(rootWindow.display)
5790          rootWindow.display.SetPalette(palette, colorMatch);
5791    }
5792
5793    public bool AcquireInput(bool acquired)
5794    {
5795       bool result = true;
5796       if(acquiredInput != acquired)
5797       {
5798          if(active || (!visible && creationActivation == activate))
5799             result = AcquireInputEx(acquired);
5800          /*if(!result)
5801          {
5802             Print("");
5803          }*/
5804          acquiredInput = acquired ? result : !result;
5805       }
5806       return result;
5807    }
5808
5809    void ListChildren(ListBox listBox)
5810    {
5811       Window child;
5812       char caption[2048];
5813       for(child = children.first; child; child = child.next)
5814       {
5815          if(child.cycle && !child.style.nonClient && child.style.isActiveClient && child.visible)
5816          {
5817             DataRow row = listBox.AddRow();
5818             row.tag = (int64)child;
5819             child.FigureCaption(caption);
5820             row.SetData(null, caption);
5821          }
5822       }
5823    }
5824
5825    void UpdateVisual(Box extent)
5826    {
5827       if(guiApp.driver != null)
5828       {
5829          if(guiApp.fullScreenMode && guiApp.desktop.display)
5830          {
5831             guiApp.desktop.mutex.Wait();
5832             guiApp.desktop.display.Lock(true);
5833          
5834             Update(extent);
5835             if(guiApp.desktop.active)
5836             {
5837                if(guiApp.desktop.dirty || guiApp.cursorUpdate)
5838                {
5839                   if(guiApp.desktop.display.flags.flipping)
5840                      guiApp.desktop.Update(null);
5841                   guiApp.desktop.UpdateDisplay();
5842                   guiApp.cursorUpdate = true;
5843                }
5844                if(guiApp.cursorUpdate || guiApp.desktop.dirty)
5845                {
5846                   guiApp.PreserveAndDrawCursor();
5847                   // guiApp.desktop.display.ShowScreen();
5848                   guiApp.cursorUpdate = false;
5849                   guiApp.desktop.dirty = false;
5850                   guiApp.RestoreCursorBackground();
5851                }
5852             }
5853          
5854             guiApp.desktop.display.Unlock();
5855             guiApp.desktop.mutex.Release();
5856          }
5857          else
5858          {
5859             Window rootWindow = this.rootWindow;
5860             rootWindow.mutex.Wait();
5861             display.Lock(true);
5862          
5863             Update(extent);
5864             if(guiApp.waiting)
5865                guiApp.SignalEvent();
5866             else
5867             {
5868                guiApp.waitMutex.Wait();
5869                guiApp.interfaceDriver.Lock(rootWindow);
5870                if(!rootWindow.style.hidden && rootWindow.dirty)
5871                {
5872                   if(rootWindow.display)
5873                   {
5874                      rootWindow.UpdateDisplay();
5875                      //rootWindow.display.ShowScreen(null);
5876                   }
5877                   rootWindow.dirty = false;
5878                }
5879                guiApp.interfaceDriver.Unlock(rootWindow);
5880                guiApp.waitMutex.Release();
5881             }
5882             display.Unlock();
5883             rootWindow.mutex.Release();
5884          }
5885       }
5886    }
5887
5888    void UnlockDisplay(void)
5889    {
5890       guiApp.interfaceDriver.Unlock(rootWindow);
5891    }
5892
5893    void LockDisplay(void)
5894    {
5895       guiApp.interfaceDriver.Lock(rootWindow);
5896    }
5897
5898    Surface GetSurface(Box box)
5899    {
5900       return Redraw((box == null) ? this.box : box);
5901    }
5902
5903    void SetMousePosition(int x, int y)
5904    {
5905       guiApp.interfaceDriver.SetMousePosition(x + absPosition.x + clientStart.x, y + absPosition.y + clientStart.y);
5906    }
5907
5908    /*
5909    void IntegrationActivate(bool active)
5910    {
5911       if(!guiApp.modeSwitching && !guiApp.fullScreenMode)
5912       {
5913          isForegroundWindow = true;
5914          ActivateEx(active, active, false, false, null, null);
5915          isForegroundWindow = false;
5916       }  
5917    }
5918    */
5919
5920    Window QueryCapture(void)
5921    {
5922       return guiApp.windowCaptured;
5923    }
5924
5925    int GetDocumentID(void)
5926    {
5927       Window child;
5928       int size = 256;
5929       byte * idBuffer = new0 byte[size];
5930       int c;
5931
5932       for(child = children.first; child; child = child.next)
5933       {
5934          // TO CHECK: Do we want a documentID when we already have a file name?
5935          if(child.style.isDocument && !child.fileName)
5936          {
5937             if(child.documentID-1 > size - 2)
5938             {
5939                idBuffer = renew0 idBuffer byte[size*2];
5940                memset(idBuffer + size, 0, size);
5941                size *= 2;
5942             }
5943             idBuffer[child.documentID-1] = 1;
5944          }
5945       }
5946       for(c = 0; c<size; c++)
5947          if(!idBuffer[c])
5948             break;
5949       numDocuments++;
5950       delete idBuffer;
5951       return c + 1;
5952    }
5953
5954    void SetInitSize(Size size)
5955    {
5956       int x, y, w, h;
5957       sizeAnchor.size = size;
5958       normalSizeAnchor = sizeAnchor;
5959
5960       // Break the anchors for moveable/resizable windows
5961       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
5962       {
5963          stateAnchor = normalAnchor;
5964          stateSizeAnchor = normalSizeAnchor;
5965
5966          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5967          Position(x,y, w, h, true, true, true, true, false, true);
5968       }
5969    }
5970
5971    void MenuMoveOrSize(bool resize, bool setCursorPosition)
5972    {
5973       if(this != guiApp.desktop && state != maximized && (resize ? (state != minimized && style.sizable) : (style.fixed || moveable)))
5974       {
5975          guiApp.windowIsResizing = resize;
5976          guiApp.windowMoving = this;
5977          guiApp.windowMovingStart = guiApp.movingLast = absPosition;
5978          if(guiApp.windowIsResizing)
5979          {
5980             guiApp.windowMovingStart.x += size.w - 1;
5981             guiApp.windowMovingStart.y += size.h - 1;
5982          }
5983          guiApp.windowMovingBefore = scrolledPos;
5984          guiApp.windowResizingBefore = size;
5985          guiApp.windowMoving.UpdateDecorations();
5986          if(guiApp.windowIsResizing) 
5987             guiApp.resizeEndX = guiApp.resizeEndY = true;
5988
5989          if(setCursorPosition)
5990             guiApp.interfaceDriver.SetMousePosition(guiApp.windowMovingStart.x, guiApp.windowMovingStart.y);
5991          else
5992          {
5993             int x, y;
5994             guiApp.interfaceDriver.GetMousePosition(&x, &y);
5995             guiApp.windowMovingStart.x += x - absPosition.x;
5996             guiApp.windowMovingStart.y += y - absPosition.y;
5997          } 
5998
5999          if(guiApp.windowMoving)
6000          {
6001             if(guiApp.windowMoving.style.nonClient)
6002                guiApp.windowMoving.parent.SetMouseRangeToWindow();
6003             else
6004                guiApp.windowMoving.parent.SetMouseRangeToClient();
6005          }
6006
6007          Capture();
6008
6009          if(this == rootWindow)
6010             guiApp.interfaceDriver.StartMoving(rootWindow, guiApp.windowMovingStart.x, guiApp.windowMovingStart.y, true);
6011       }
6012    }
6013
6014 public:
6015    // normal Methods
6016    bool Create()
6017    {
6018       bool result = false;
6019
6020       if(created)
6021          result = true;
6022       else if(guiApp && guiApp.driver != null)
6023       {
6024          void * systemParent = null;
6025          OldLink slaveHolder;
6026          Window last;
6027          bool visible = !style.hidden;
6028
6029          if(style.embedded) 
6030          {
6031             systemParent = parent;
6032             parent = guiApp.desktop;
6033          }
6034          last = parent ? parent.children.last : null;
6035
6036          if((parent && parent != guiApp.desktop && !parent.created) ||
6037             (master && master != guiApp.desktop && !master.created))
6038             return false;
6039
6040          if(parent)
6041             stopwatching(parent, font);
6042
6043          if(!parent)
6044             property::parent = guiApp.desktop;
6045          if(!master) master = parent;
6046
6047          if(_isModal && master.modalSlave)
6048             property::master = master.modalSlave;
6049             //return false;
6050
6051          if(parent)
6052             parent.children.Remove(this);
6053          if(master)
6054          {
6055             for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
6056                if(slaveHolder.data == this)
6057                {
6058                   master.slaves.Delete(slaveHolder);
6059                   break;
6060                }
6061          }
6062
6063          if(parent == guiApp.desktop && !mutex)
6064             mutex = Mutex {};
6065
6066          if(style.isDocument)
6067          {
6068             if(parent)
6069                parent.numDocuments--;
6070             documentID = parent.GetDocumentID();
6071          }
6072
6073          if(!style.stayOnTop)
6074             for(; last && last.style.stayOnTop; last = last.prev);
6075
6076          parent.children.Insert((last == this) ? null : last, this);
6077          //parent.children.Add(this);
6078
6079          if(!dispDriver)
6080             dispDriver = parent.dispDriver;
6081          destroyed = false;
6082          if(_isModal)
6083             master.modalSlave = this;
6084
6085          box = Box { MAXINT, MAXINT, MININT, MININT }; //-MAXINT, -MAXINT };
6086
6087          incref this;
6088          incref this;
6089
6090          master.slaves.Add(slaveHolder = OldLink { data = this });
6091          if(slaveHolder)
6092          {
6093             if(setHotKey)
6094             {
6095                master.hotKeys.Add(hotKey = HotKeySlot { key = setHotKey, window = this });
6096             }
6097             if(style.isDefault && !master.defaultControl)
6098                master.defaultControl = this;
6099
6100             stateAnchor = normalAnchor = anchor;
6101             stateSizeAnchor = normalSizeAnchor = sizeAnchor;
6102
6103             // TOCHECK: Why is this here?
6104             //position.x = (ax > 0) ? ax & 0xFFFFF : ax;
6105             //position.y = (ay > 0) ? ay & 0xFFFFF : ay;
6106
6107             this.visible = false;
6108             style.hidden = true;
6109     
6110             //created = true;
6111             // autoCreate = true;
6112             wasCreated = true;
6113             if(SetupDisplay())
6114             {
6115                created = true;
6116                if(OnCreate())
6117                {
6118                   /*
6119                   if(parent == guiApp.desktop)
6120                      Log("LoadGraphics %s\n", caption);
6121                   */
6122                   if(LoadGraphics(true, false))
6123                   {
6124                      if(!setFont)
6125                      {
6126                         watch(parent)
6127                         {
6128                            font
6129                            {
6130                               usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
6131                               firewatchers font;
6132                               Update(null);
6133                            }
6134                         };
6135                      }
6136
6137                      if(style.hasMenuBar /*&& menu*/)
6138                      {
6139                         menuBar = 
6140                            PopupMenu
6141                            {
6142                               this,
6143                               menu = menu, isMenuBar = true, anchor = Anchor { top = 23, left = 1, right = 1 },
6144                               interim = false, inactive = true, nonClient = true, size.h = 24
6145                            };
6146                         menuBar.Create();
6147                      }
6148
6149                      if(statusBar)
6150                         statusBar.Create();
6151                      
6152                      // Create the system buttons
6153                      CreateSystemChildren();
6154
6155                      UpdateActiveDocument(null);
6156
6157                      if(style.isDocument)
6158                      {
6159                         if(menu)
6160                         {
6161                            MenuItem item = menu.FindItem(MenuFileSave, 0);
6162                            if(item) item.disabled = !modifiedDocument && fileName;
6163                         }
6164                      }
6165
6166                      /*
6167                      if(parent == guiApp.desktop)
6168                         Log("Preemptive SetState %s\n", caption);
6169                      */
6170
6171                      // Preemptive Set State to ensure proper anchoring
6172                      SetStateEx(state, false);
6173                      /*
6174                      style.hidden = true;
6175                      visible = false;
6176                      */
6177
6178                      {
6179                         Window child, next;
6180                         for(child = children.first; child; child = next)
6181                         {
6182                            next = child.next;
6183                            if(!child.created && (child.autoCreate || child.wasCreated))
6184                               child.Create();
6185                         }
6186                      }
6187
6188                      {
6189                         OldLink link, next;
6190                         for(link = slaves.first; link; link = next)
6191                         {
6192                            Window slave = link.data;
6193                            next = link.next;
6194                            if(!slave.created && (slave.autoCreate || slave.wasCreated))
6195                            {
6196                               if(slave.Create())
6197                                  // Things might have happened that invalidated 'next'...
6198                                  // Start over the search for slaves to create.
6199                                  // (Added this to fix crash with Stacker & Toolbar)
6200                                  next = slaves.first;
6201                            }
6202                         }
6203                      }
6204
6205                      if(OnPostCreate())
6206                         OnApplyGraphics();
6207
6208                      /*
6209                      if(parent == guiApp.desktop)
6210                         Log("Real SetState %s\n", caption);
6211                      */
6212
6213                      if(isActiveClient && visible)
6214                      {
6215                         parent.numPositions--;
6216                         if(state == minimized) parent.numIcons--;
6217                      }
6218
6219                      parent.OnChildAddedOrRemoved(this, false);
6220
6221                      // Real set state & activate for proper display & activation
6222                      property::visible = visible;
6223                      //  SetState(state & 0x00000003, true, 0);
6224                      guiApp.interfaceDriver.SetIcon(this, icon);
6225
6226                      if(visible)
6227                      {
6228                         UpdateCaption();
6229                         /*if(rootWindow == this)
6230                            guiApp.interfaceDriver.ActivateRootWindow(this);
6231                         else*/
6232                         if(creationActivation == activate)
6233                            ActivateEx(true, false, true, true, null, null);
6234                         else if(creationActivation == flash)
6235                            Flash();
6236                      }
6237
6238                      if(!destroyed)
6239                         rootWindow.ConsequentialMouseMove(false);
6240
6241                      result = true;
6242                   }
6243                }
6244             }
6245          }
6246          /*
6247          if(!result)
6248          {
6249             Destroy(0);
6250             guiApp.LogErrorCode(IERR_WINDOW_CREATION_FAILED, caption);
6251          }
6252          */
6253
6254          if(!result)
6255          {
6256             // Testing this here... Otherwise a failed LoadGraphics stalls the application
6257             created = false;
6258             //style.hidden = true; // !visible;
6259             style.hidden = !visible;
6260             if(master.modalSlave == this)
6261                master.modalSlave = null;
6262          }
6263          delete this;
6264       }
6265       return result;
6266    }
6267
6268    void WriteCaption(Surface surface, int x, int y)
6269    {
6270       if(caption)
6271          Interface::WriteKeyedTextDisabled(surface, x,y, caption, hotKey ? hotKey.key : 0, !isEnabled);
6272    }
6273
6274    void Update(Box region)
6275    {
6276       if(this)
6277       {
6278          Window rootWindow;
6279
6280          rootWindow = this.rootWindow;
6281
6282          // rootWindow.mutex.Wait();
6283          if(!destroyed && visible && display)
6284          {
6285             Window child;
6286             Box realBox;
6287             
6288             // Testing this to avoid repetitve full update to take time...
6289             if(dirtyArea.count == 1)
6290             {
6291                BoxItem item = (BoxItem)ACCESS_ITEM(dirtyArea, dirtyArea.first);
6292                if(item.box.left <= box.left &&
6293                   item.box.top <= box.top &&
6294                   item.box.right >= box.right &&
6295                   item.box.bottom >= box.bottom)
6296                {
6297                   rootWindow.dirty = true;
6298                   return;
6299                }
6300             }
6301
6302             if(display.flags.flipping && !rootWindow.dirty)
6303             {
6304                if(this == rootWindow)
6305                   region = null;
6306                else
6307                {
6308                   rootWindow.Update(null);
6309                   return;
6310                }
6311             }
6312             
6313             rootWindow.dirty = true;
6314
6315             if(region != null)
6316             {
6317                realBox = region;
6318                realBox.left += clientStart.x;
6319                realBox.top += clientStart.y;
6320                realBox.right += clientStart.x;
6321                realBox.bottom += clientStart.y;
6322                realBox.Clip(box);
6323             }
6324             else
6325                realBox = box;
6326
6327             if(realBox.right >= realBox.left && 
6328                realBox.bottom >= realBox.top)
6329             {
6330                // if(!rootWindow.fullRender)
6331                   dirtyArea.UnionBox(realBox, rootWindow.tempExtents[0]);
6332
6333                for(child = children.first; child; child = child.next)
6334                {
6335                   if(!child.is3D)
6336                   {
6337                      Box box = realBox;
6338                      box.left -= child.absPosition.x - absPosition.x;
6339                      box.top -= child.absPosition.y - absPosition.y;
6340                      box.right -= child.absPosition.x - absPosition.x;
6341                      box.bottom -= child.absPosition.y - absPosition.y;
6342                      if(box.right >= child.box.left && box.left <= child.box.right &&
6343                         box.bottom >= child.box.top && box.top <= child.box.bottom)
6344                      {
6345                         box.left -= child.clientStart.x;
6346                         box.top -= child.clientStart.y;
6347                         box.right -= child.clientStart.x;
6348                         box.bottom -= child.clientStart.y;
6349                         child.Update(box);
6350                      }
6351                   }
6352                }
6353
6354                realBox.left += absPosition.x - rootWindow.absPosition.x;
6355                realBox.top += absPosition.y - rootWindow.absPosition.y;
6356                realBox.right += absPosition.x - rootWindow.absPosition.x;
6357                realBox.bottom += absPosition.y - rootWindow.absPosition.y;
6358                rootWindow.dirtyBack.UnionBox(realBox, rootWindow.tempExtents[0]);
6359             }
6360          }
6361          else if(this == guiApp.desktop)
6362          {
6363             Window window;
6364             for(window = children.first; window; window = window.next)
6365             {
6366                if(!window.is3D)
6367                {
6368                   if(region != null)
6369                   {
6370                      Box childBox = region;
6371
6372                      childBox.left    -= window.absPosition.x - guiApp.desktop.absPosition.x;
6373                      childBox.top     -= window.absPosition.y - guiApp.desktop.absPosition.y;
6374                      childBox.right   -= window.absPosition.x - guiApp.desktop.absPosition.x;
6375                      childBox.bottom  -= window.absPosition.y - guiApp.desktop.absPosition.y;
6376        
6377                      window.Update(childBox);
6378                   }
6379                   else
6380                      window.Update(null);
6381                }
6382             }
6383          }
6384
6385          // rootWindow.mutex.Release();
6386       }
6387    }
6388
6389    bool Capture(void)
6390    {
6391       bool result = true;
6392       if(guiApp.windowCaptured != this)
6393       {
6394          if(guiApp.windowCaptured)
6395             result = false;
6396          else
6397          {
6398             //Logf("Captured %s (%s)\n", caption, class.name);
6399             guiApp.interfaceDriver.SetMouseCapture(rootWindow);
6400             guiApp.windowCaptured = this;
6401          }
6402       }
6403       return result;
6404    }
6405
6406    bool Destroy(int64 code)
6407    {
6408       //if(created)
6409       if(this)
6410       {
6411          if(!destroyed && !CloseConfirmation(false)) return false;
6412          incref this;
6413          if(DestroyEx(code))
6414          {
6415             // TOCHECK: Should autoCreate be set to false here?
6416             autoCreate = false;
6417             wasCreated = false;
6418             delete this;
6419             return true;
6420          }
6421          delete this;
6422       }
6423       return false;
6424    }
6425
6426    void Move(int x, int y, int w, int h)
6427    {
6428       normalAnchor = Anchor { left = x, top = y };
6429       normalSizeAnchor = SizeAnchor { size = { w, h } };
6430
6431       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6432       {
6433          if(destroyed) return;
6434
6435          stateAnchor = normalAnchor;
6436          stateSizeAnchor = normalSizeAnchor;
6437
6438          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6439          Position(x,y, w, h, true, true, true, true, false, true);
6440       }
6441    }
6442
6443    DialogResult Modal(void)
6444    {
6445       isModal = true;
6446       if(Create())
6447          return DoModal();
6448
6449       // FIXES MEMORY LEAK IF Create() FAILED
6450       incref this;
6451       delete this;
6452       return 0;
6453    }
6454
6455    void SetScrollArea(int width, int height, bool snapToStep)
6456    {
6457       bool resize = false;
6458       if(snapToStep)
6459       {
6460          int stepX = sbStep.x, stepY = sbStep.y;
6461          // Needed to make snapped down position match the skin's check of client area 
6462          // against realvirtual
6463          if(guiApp.textMode)
6464          {
6465             SNAPDOWN(stepX, textCellW);
6466             SNAPDOWN(stepY, textCellH);
6467             stepX = Max(stepX, textCellW);
6468             stepY = Max(stepY, textCellH);
6469          }
6470          if(scrollFlags.snapX)
6471             SNAPUP(width, stepX);
6472          if(scrollFlags.snapY)
6473             SNAPUP(height, stepY);
6474       }
6475
6476       reqScrollArea.w = width;
6477       reqScrollArea.h = height;
6478       noAutoScrollArea = (width > 0 || height > 0);
6479
6480       UpdateScrollBars(true, true);
6481    }
6482
6483    void SetScrollPosition(int x, int y)
6484    {
6485       if(sbh)
6486          sbh.Action(setPosition, x, 0);
6487       else
6488       {
6489          int range;
6490          int seen = clientSize.w, total = reqScrollArea.w;
6491          seen = Max(1,seen);
6492          if(scrollFlags.snapX)
6493             SNAPDOWN(seen, sbStep.x);
6494
6495          if(!total) total = seen;
6496          range = total - seen + 1;
6497          range = Max(range, 1);
6498          if(x < 0) x = 0;
6499          if(x >= range) x = range - 1;
6500
6501          if(scrollFlags.snapX)
6502             SNAPUP(x, sbStep.x);
6503
6504          if(scroll.x != x)
6505             OnHScroll(setPosition, x, 0);
6506
6507          if(guiApp.textMode)
6508          {
6509             SNAPDOWN(x, textCellW);
6510          }
6511          scroll.x = x;
6512       }
6513
6514       if(sbv)
6515          sbv.Action(setPosition, y, 0);
6516       else
6517       {
6518          int range;
6519          int seen = clientSize.h, total = reqScrollArea.h;
6520          seen = Max(1,seen);
6521
6522          if(scrollFlags.snapY)
6523             SNAPDOWN(seen, sbStep.y);
6524
6525          if(!total) total = seen;
6526          range = total - seen + 1;
6527          range = Max(range, 1);
6528          if(y < 0) y = 0;
6529          if(y >= range) y = range - 1;
6530
6531          if(scrollFlags.snapY)
6532             SNAPUP(y, sbStep.y);
6533
6534          if(scroll.y != y)
6535             OnVScroll(setPosition, y, 0);
6536          if(guiApp.textMode)
6537          {
6538             SNAPDOWN(y, textCellH);
6539          }
6540          scroll.y = y;
6541       }
6542       if(!sbh || !sbv)
6543          UpdateCaret(false, false);
6544    }
6545
6546    void SetScrollLineStep(int stepX, int stepY)
6547    {
6548       sbStep.x = stepX;
6549       sbStep.y = stepY;
6550       if(guiApp.textMode)
6551       {
6552          SNAPDOWN(stepX, textCellW);
6553          SNAPDOWN(stepY, textCellH);
6554          stepX = Max(stepX, textCellW);
6555          stepY = Max(stepY, textCellH);
6556       }
6557       if(sbh)
6558          sbh.lineStep = stepX;
6559       if(sbv)
6560          sbv.lineStep = stepY;
6561    }
6562
6563    void SetState(WindowState newState, bool activate, Modifiers mods)
6564    {
6565       if(created)
6566       {
6567          if(state == newState || OnStateChange(newState, mods))
6568          {
6569             WindowState prevState = state;
6570
6571             StopMoving();
6572
6573             // This used to be at the end of the brackets... moved for X, testing...
6574             // This has the effect of activating the window through the system...
6575             if(rootWindow == this)
6576                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
6577       
6578             SetStateEx(newState, activate);
6579
6580             if(rootWindow == this && !rootWindow.nativeDecorations)
6581             {
6582                int x = position.x, y = position.y;
6583                /*if(style.interim)
6584                {
6585                   x -= guiApp.desktop.absPosition.x;
6586                   y -= guiApp.desktop.absPosition.y;
6587                }*/
6588                guiApp.interfaceDriver.PositionRootWindow(this, x, y, size.w, size.h, true, true);
6589             }
6590
6591             //state = newState;
6592             //state = prevState;
6593
6594             if(state != maximized && style.hasMaximize)
6595             {
6596                Window child;
6597                for(child = parent.children.first; child; child = child.next)
6598                {
6599                   if(child != this && child.state == maximized)
6600                      child.SetStateEx(normal, false);
6601                }
6602             }
6603
6604             if(!style.nonClient && (sbv || sbh) && this != parent.sbv && this != parent.sbh)
6605                parent.UpdateScrollBars(true, true);
6606
6607             /*
6608             // Do we really need this stuff here? 
6609             // Shouldn't the Activate stuff take care of it?              
6610             if(parent.rootWindow == parent && style)
6611             {
6612                char caption[2048];
6613                parent.FigureCaption(caption);
6614                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
6615                parent.UpdateDecorations();
6616             }         
6617             */
6618
6619             rootWindow.ConsequentialMouseMove(false);
6620          }
6621       }
6622       else
6623          state = newState;
6624    }
6625
6626    BitmapResource GetIcon(SkinBitmap iconID)
6627    {
6628       return guiApp.currentSkin.GetBitmap(iconID);
6629    }
6630
6631    void SetMouseRange(Box range)
6632    {
6633       if(range || guiApp.fullScreenMode)
6634       {
6635          Box clip;
6636          if(range != null)
6637          {
6638             clip.left   = range.left + absPosition.x + clientStart.x;
6639             clip.top    = range.top + absPosition.y + clientStart.y;
6640             clip.right  = range.right + absPosition.x + clientStart.x;
6641             clip.bottom = range.bottom + absPosition.y + clientStart.y;
6642          }
6643          else
6644          {
6645             clip.left   = guiApp.desktop.box.left;
6646             clip.top    = guiApp.desktop.box.top;
6647             clip.right  = guiApp.desktop.box.right;
6648             clip.bottom = guiApp.desktop.box.bottom;
6649          }
6650          guiApp.interfaceDriver.SetMouseRange(rootWindow, clip);
6651       }
6652       else
6653          guiApp.interfaceDriver.SetMouseRange(rootWindow, null);
6654    }
6655
6656    void SetMouseRangeToClient(void)
6657    {
6658       if(guiApp.fullScreenMode || this != guiApp.desktop)
6659       {
6660          Box box {0, 0, clientSize.w - 1, clientSize.h - 1 };
6661          box.Clip(clientArea);
6662          SetMouseRange(box);
6663       }
6664       else
6665          SetMouseRange(null);
6666    }
6667
6668    void SetMouseRangeToWindow(void)
6669    {
6670       Box box { -clientStart.x, -clientStart.y, size.w-1, size.h-1 };
6671       if(this == guiApp.desktop)
6672          SetMouseRangeToClient();
6673       else
6674          SetMouseRange(box);
6675    }
6676
6677    // x, y: Desktop Coordinates
6678    void ShowSysMenu(int x, int y)
6679    {
6680       Menu menu { };
6681       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
6682       MenuItem
6683       {
6684          menu, $"Restore", r, NotifySelect = MenuWindowRestore, 
6685          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
6686       };
6687       MenuItem
6688       {
6689          menu, $"Move", m, NotifySelect = MenuWindowMove, 
6690          disabled = !style.fixed || state == maximized
6691       };
6692       MenuItem
6693       {
6694          menu, $"Size", s, NotifySelect = MenuWindowSize, 
6695          disabled = !style.sizable || state != normal
6696       };
6697       MenuItem
6698       {
6699          menu, $"Minimize", n, NotifySelect = MenuWindowMinimize, 
6700          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
6701       };
6702       MenuItem
6703       {
6704          menu, $"Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize, 
6705          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
6706       };
6707       MenuItem
6708       {
6709          menu, $"Stay On Top", t, NotifySelect = MenuWindowStayOnTop, 
6710          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
6711       };
6712       MenuDivider { menu };
6713       MenuItem
6714       {
6715          menu, $"Close", c, (parent == guiApp.desktop) ? altF4 : ( style.isActiveClient ? ctrlF4 : 0), NotifySelect = MenuWindowClose,
6716          bold = true, disabled = !style.hasClose, bitmap = guiApp.currentSkin.GetBitmap(close)
6717       };
6718       windowMenu.Create();
6719    }
6720
6721    void Activate(void)
6722    {
6723       ActivateEx(true, true, true, true, null, null);
6724    }
6725
6726    void MakeActive(void)
6727    {
6728       ActivateEx(true, false, true, false, null, null);
6729    }
6730
6731    void SoftActivate(void)
6732    {
6733       if(guiApp.desktop.active)
6734          Activate();
6735       else if(!active)
6736          Flash();
6737    }
6738
6739    void Deactivate(void)
6740    {
6741       ActivateEx(false, true, true, true, null, null);
6742    }
6743
6744    void Flash(void)
6745    {
6746       guiApp.interfaceDriver.FlashRootWindow(rootWindow);
6747    }
6748
6749    bool CycleChildren(bool backward, bool clientOnly, bool tabCycleOnly, bool cycleParents)
6750    {
6751       bool result = false;
6752       if(activeChild && activeChild.cycle)
6753       {
6754          Window modalWindow, child = activeChild;
6755          if(!clientOnly /*&& parent.tabCycle*/)
6756          {
6757             Window next = child;
6758             while(true)
6759             {
6760                if(next.cycle == (backward ? childrenCycle.first : childrenCycle.last))
6761                {
6762                   if(cycleParents)
6763                   {
6764                      if(parent && parent.CycleChildren(backward, false, true, true))
6765                         return true;
6766                      break;
6767                   }
6768                   else
6769                      return false;
6770                }
6771                if(backward)
6772                   next = next.cycle.prev.data;
6773                else
6774                   next = next.cycle.next.data;
6775                if(!next.disabled && !next.inactive /*isRemote*/ && next.created && !next.nonClient && (!clientOnly || next.style.isActiveClient) && !next.style.hidden && next.FindModal() != activeChild)
6776                   break;
6777             }
6778          }
6779          /*
6780          if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) && 
6781             parent.tabCycle && parent.CycleChildren(backward, false, false))
6782             return true;
6783          */
6784
6785          if(tabCycleOnly && !tabCycle) return false;
6786
6787          while(child)
6788          {
6789             while(true)
6790             {
6791                if(backward)
6792                   child = child.cycle.prev.data;
6793                else
6794                   child = child.cycle.next.data;
6795                if(child == child.parent.activeChild)
6796                   return result;
6797                else if(!child.disabled && child.created && (!clientOnly || child.style.isActiveClient) && !child.style.hidden && child.FindModal() != activeChild)
6798                   break;
6799             }
6800             modalWindow = child.FindModal();
6801             if(!modalWindow)
6802             {
6803                // Scroll the window to include the active control
6804                if(sbh && !child.style.dontScrollHorz)
6805                {
6806                   if(child.scrolledPos.x < 0)
6807                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x, 0);
6808                   else if(child.scrolledPos.x + child.size.w > clientSize.w)
6809                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x + child.size.w - clientSize.w, 0);
6810                }
6811                if(sbv && !child.style.dontScrollVert)
6812                {
6813                   if(child.scrolledPos.y < 0)
6814                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y, 0);
6815                   else if(child.scrolledPos.y + child.size.h > clientSize.h)
6816                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y + child.size.h - clientSize.h, 0);
6817                }
6818             }
6819             result = true;
6820             child = modalWindow ? modalWindow : child;
6821             child.ActivateEx(true, true, true, true, null, null);
6822             if(child.tabCycle && child.childrenCycle.first)
6823                child = ((OldLink)(backward ? child.childrenCycle.first : child.childrenCycle.last)).data;
6824             else
6825                break;
6826          }
6827       }
6828       else
6829          return false;
6830
6831       ConsequentialMouseMove(false);
6832       return result;
6833    }
6834
6835    void AddResource(Resource resource)
6836    {
6837       if(resource)
6838       {
6839          ResPtr ptr { resource = resource };
6840          resources.Add(ptr);
6841          incref resource;
6842
6843          // Load Graphics here if window is created already
6844          if(/*created && */display)
6845          {
6846             display.Lock(false);
6847             ptr.loaded = display.displaySystem.LoadResource(resource);
6848             display.Unlock();
6849          }
6850          /*
6851          // Temporary hack to load font right away for listbox in dropbox ...
6852          else if(master && master.display)
6853          {
6854             master.display.Lock(false);
6855             master.display.displaySystem.LoadResource(resource);
6856             master.display.Unlock();
6857          }
6858          */
6859       }
6860    }
6861
6862    void RemoveResource(Resource resource)
6863    {
6864       if(resource)
6865       {
6866          ResPtr ptr;
6867          for(ptr = resources.first; ptr; ptr = ptr.next)
6868          {
6869             if(ptr.resource == resource)
6870                break;
6871          }
6872
6873          if(ptr)
6874          {
6875             // Unload Graphics here if window is created already
6876             if(/*created && */display)
6877             {
6878                if(ptr.loaded)
6879                {
6880                   display.Lock(false);
6881                   display.displaySystem.UnloadResource(resource, ptr.loaded);
6882                   display.Unlock();
6883                   ptr.loaded = null;
6884                }
6885             }
6886             delete resource;
6887             resources.Delete(ptr);
6888          }
6889       }
6890    }
6891
6892    void SetCaret(int x, int y, int size)
6893    {
6894       if(!destroyed)
6895       {
6896          caretPos.x = x;
6897          caretPos.y = y;
6898          caretSize = size;
6899          if(active && !style.interim)
6900          {
6901             if(visible || !guiApp.caretOwner)
6902                guiApp.caretOwner = size ? this : null;
6903             if(size)
6904                UpdateCaret(false, false);
6905             else
6906             {
6907                guiApp.interfaceDriver.SetCaret(0,0,0);
6908                UpdateCaret(false, true);
6909                guiApp.caretEnabled = false;
6910             }
6911          }
6912          else if(style.inactive && active)
6913          {
6914             guiApp.interfaceDriver.SetCaret(0,0,0);
6915             UpdateCaret(false, true);
6916             guiApp.caretEnabled = false;
6917          }
6918       }
6919    }
6920
6921    void Scroll(int x, int y)
6922    {
6923       bool opaque = !style.drawBehind || background.a;
6924       if(opaque && display && display.flags.scrolling)
6925       {
6926          Box box = clientArea;
6927          box.left += clientStart.x;
6928          box.top += clientStart.y;
6929          box.right += clientStart.x;
6930          box.bottom += clientStart.y;
6931
6932          //scrollExtent.Free(null);
6933          scrollExtent.AddBox(box);
6934          scrolledArea.x += x;
6935          scrolledArea.y += y;
6936
6937          //scrollExtent.Free();
6938          //scrollExtent.AddBox(clientArea);
6939          //scrollExtent.Offset(clientStart.x, clientStart.y);
6940          //scrolledArea.x = x;
6941          //scrolledArea.y = y;
6942       }
6943       else
6944          Update(clientArea);
6945
6946       if(rootWindow)
6947          rootWindow.dirty = true;
6948    }
6949
6950    void ReleaseCapture()
6951    {
6952       if(guiApp && guiApp.windowCaptured && guiApp.windowCaptured == this)
6953       {
6954          Window oldCaptured = guiApp.windowCaptured;
6955          guiApp.windowCaptured = null;
6956          guiApp.prevWindow = null;
6957          incref oldCaptured;
6958
6959          //guiApp.Log("Released Capture\n");
6960
6961          guiApp.interfaceDriver.SetMouseCapture(null);
6962
6963          //oldCaptured.OnMouseCaptureLost();
6964
6965          if(oldCaptured)
6966             oldCaptured.ConsequentialMouseMove(false);
6967          delete oldCaptured;
6968       }
6969    }
6970
6971    private void _SetCaption(char * format, va_list args)
6972    {
6973       if(this)
6974       {
6975          delete caption;
6976          if(format)
6977          {
6978             char caption[MAX_F_STRING];
6979             vsnprintf(caption, sizeof(caption), format, args);
6980             caption[sizeof(caption)-1] = 0;
6981
6982             this.caption = CopyString(caption);
6983          }
6984          if(created)
6985             UpdateCaption();
6986
6987          firewatchers caption;
6988       }
6989    }
6990
6991    /*deprecated*/ void SetText(char * format, ...)
6992    {
6993       va_list args;
6994       va_start(args, format);
6995       _SetCaption(format, args);
6996       va_end(args);
6997    }
6998
6999    void SetCaption(char * format, ...)
7000    {
7001       va_list args;
7002       va_start(args, format);
7003       _SetCaption(format, args);
7004       va_end(args);
7005    }
7006
7007    bool Grab(Bitmap bitmap, Box box, bool decorations)
7008    {
7009       bool result = false;
7010       if(display || this == guiApp.desktop)
7011       {
7012          Box clip = {MININT, MININT, MAXINT, MAXINT};
7013
7014          if(box != null)
7015             clip = box;
7016
7017          if(!decorations)
7018             clip.Clip(clientArea);
7019          else
7020             clip.Clip(this.box);
7021
7022          if(rootWindow != this)
7023          {
7024             clip.left   += absPosition.y;
7025             clip.top    += absPosition.y;
7026             clip.right  += absPosition.x;
7027             clip.bottom += absPosition.y;
7028          }
7029
7030          clip.left += decorations ? 0 : clientStart.x;
7031          clip.top += decorations ? 0 : clientStart.y;
7032          clip.right += decorations ? 0 : clientStart.x;
7033          clip.bottom += decorations ? 0 : clientStart.y;
7034
7035          if(display && display.flags.flipping)
7036          {
7037             rootWindow.Update(null);
7038             rootWindow.UpdateDisplay();
7039          }
7040
7041          if(!display)
7042          {
7043             Window window { };
7044             window.Create();
7045             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top, 
7046                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7047             delete window;
7048          }
7049          else
7050             result = display.Grab(bitmap, clip.left, clip.top, 
7051                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7052
7053          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
7054          {
7055             if(!bitmap.Convert(null, pixelFormat888, null))
7056                result = false;
7057          }
7058       }
7059       return result;
7060    }
7061
7062    void GetMousePosition(int * x, int * y)
7063    {
7064       int mouseX = 0, mouseY = 0;
7065       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
7066       {
7067          if(guiApp.driver)
7068             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
7069          if(this != guiApp.desktop)
7070          {
7071             mouseX -= absPosition.x + clientStart.x;
7072             mouseY -= absPosition.y + clientStart.y;
7073          }
7074       }
7075       if(x) *x = mouseX;
7076       if(y) *y = mouseY;
7077    }
7078
7079    DialogResult DoModal()
7080    {
7081       DialogResult returnCode = 0;
7082       int terminated = terminateX;
7083       isModal = true;
7084       incref this;
7085       while(!destroyed && guiApp.driver != null)
7086       {
7087          if(terminateX != terminated)
7088          {
7089             terminated = terminateX;
7090             guiApp.desktop.Destroy(0);
7091             if(guiApp.desktop.created)
7092             {
7093                terminated = 0;
7094                //printf("Resetting terminate X to 0\n");
7095                terminateX = 0;
7096             }
7097             break;
7098          }
7099
7100          guiApp.UpdateDisplay();
7101          if(!guiApp.ProcessInput(false))
7102             guiApp.Wait();
7103       }
7104       returnCode = this.returnCode;
7105       delete this;
7106       return returnCode;
7107    }
7108
7109    void DoModalStart()
7110    {
7111       isModal = true;
7112       incref this;
7113    }
7114
7115    bool DoModalLoop()
7116    {
7117       return !destroyed && guiApp.driver != null && terminateX < 2;
7118    }
7119
7120    DialogResult DoModalEnd()
7121    {
7122       DialogResult returnCode = this.returnCode;
7123       delete this;
7124       return returnCode;
7125    }
7126
7127    // --- Window manipulation ---
7128    /*bool GetDisabled()
7129    {
7130       bool disabled = this.disabled;
7131       Window window;
7132       for(window = this; (window = window.master); )
7133       {
7134          if(window.disabled)
7135          {
7136             disabled = true;
7137             break;
7138          }
7139       }
7140       return disabled;
7141    }*/
7142
7143    // --- Mouse Manipulation ---
7144    void GetNCMousePosition(int * x, int * y)
7145    {
7146       GetMousePosition(x, y);
7147       if(x) *x += clientStart.x;
7148       if(y) *y += clientStart.y;
7149    }
7150
7151    // --- Carets manipulation ---
7152    void GetCaretPosition(Point caretPos)
7153    {
7154       caretPos = this.caretPos;
7155    }
7156
7157    int GetCaretSize(void)
7158    {
7159       return caretSize;
7160    }
7161
7162    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
7163    {
7164       Destroy(button.id);
7165       return true;
7166    }
7167
7168    bool CloseConfirmation(bool parentClosing)
7169    {
7170       bool result = true;
7171       OldLink slave;
7172       Window child;
7173
7174       if(closing)
7175          return false;
7176       if(terminateX > 1)
7177          return true;
7178          
7179       closing = true;
7180
7181       if(!OnClose(parentClosing))
7182          result = false;
7183
7184       // If you want to skip this, simply set modifiedDocument to false in OnClose
7185       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7186       {
7187          DialogResult dialogRes;
7188          char message[1024];
7189          if(fileName)
7190             sprintf(message, $"Save changes to %s?", fileName);
7191          else
7192             sprintf(message, $"Save changes to Untitled %d?", documentID);
7193
7194          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption ? parent.caption : rootWindow.caption, contents = message }.Modal();
7195
7196          if(dialogRes == yes)
7197          {
7198             // TOFIX: Precomp error if brackets are taken out
7199             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7200          }
7201          else if(dialogRes == cancel)
7202             result = false;
7203       }
7204
7205       if(result)
7206       {
7207          for(slave = slaves.first; slave; slave = slave.next)
7208          {
7209             Window w = slave.data;
7210             if((w.parent == this || !w.IsDescendantOf(this)) && !w.CloseConfirmation(true))
7211             {
7212                // ((Window)slave.data).CloseConfirmation(true);
7213                result = false;
7214                break;
7215             }
7216          }
7217       }
7218
7219       if(result)
7220       {
7221          for(child = children.first; child; child = child.next)
7222             if(child.master != this && !child.CloseConfirmation(true))
7223             {
7224                result = false;
7225                break;
7226             }
7227       }
7228       closing = false;
7229       return result;
7230    }
7231
7232    // Static methods... move them somewhere else?
7233    void ::RestoreCaret()
7234    {
7235       if(guiApp.caretOwner)
7236          guiApp.caretOwner.UpdateCaret(false, false);
7237    }
7238
7239    void ::FreeMouseRange()
7240    {
7241       guiApp.interfaceDriver.SetMouseRange(null, null);
7242    }
7243
7244    // Menu Methods
7245    bool MenuFileClose(MenuItem selection, Modifiers mods)
7246    {
7247       Window document = activeChild;
7248       if(document)
7249          document.Destroy(0);
7250       return true;
7251    }
7252
7253    bool MenuFileExit(MenuItem selection, Modifiers mods)
7254    {
7255       Destroy(0);
7256       return true;
7257    }
7258
7259    bool MenuFileSave(MenuItem selection, Modifiers mods)
7260    {
7261       if(fileName)
7262       {
7263          fileMonitor.fileName = null;
7264          saving = true;
7265
7266          if(OnSaveFile(fileName))
7267          {
7268             //if(OnFileModified != Window::OnFileModified)
7269             {
7270                saving = false;
7271                fileMonitor.fileName = fileName;
7272             }
7273             return true;
7274          }
7275          else
7276          {
7277             MessageBox dialog { master = master, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7278             DialogResult answer = dialog.Modal();
7279             saving = false;
7280             if(answer != yes) return (bool)answer;
7281          }
7282       }
7283       return MenuFileSaveAs(selection, mods);
7284    }
7285
7286    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7287    {
7288       DialogResult result = (DialogResult)bool::true;
7289       FileDialog fileDialog = saveDialog;
7290
7291       if(!fileDialog)
7292          fileDialog = FileDialog {};
7293       if(fileDialog)
7294       {
7295          incref fileDialog;
7296          if(fileName)
7297             fileDialog.filePath = fileName;
7298          else
7299          {
7300             char filePath[MAX_FILENAME];
7301             sprintf(filePath, "Untitled %d", documentID);
7302             fileDialog.filePath = filePath;
7303          }
7304          fileMonitor.fileName = null;
7305
7306          fileDialog.type = save;
7307          fileDialog.text = $"Save As";
7308
7309          while(true)
7310          {
7311             fileDialog.master = master.parent ? master : this;
7312             if(fileDialog.Modal() == ok)
7313             {
7314                char * filePath = fileDialog.filePath;
7315                saving = true;
7316                if(OnSaveFile(filePath))
7317                {
7318                   saving = false;
7319                   property::fileName = filePath;
7320                   NotifySaved(master, this, filePath);
7321                   break;
7322                }
7323                else
7324                {
7325                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7326                   DialogResult answer = dialog.Modal();
7327                   saving = false;
7328                   if(answer != yes) 
7329                   {
7330                      result = answer;
7331                      break;
7332                   }
7333                }
7334             }
7335             else
7336             {
7337                result = cancel;
7338                break;
7339             }
7340          }
7341          //if(OnFileModified != Window::OnFileModified && fileName)
7342          {
7343             if(fileName)
7344                fileMonitor.fileName = fileName;
7345          }
7346          delete fileDialog;
7347       }
7348       return (bool)result; // Actually returning result from Yes/NoCancel message box
7349    }
7350
7351    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7352    {
7353       Window document = activeChild;
7354       Window next;
7355       for(document = children.first; document; document = next)
7356       {
7357          next = document.next;
7358          if(document.style.isDocument || document.fileName)
7359             document.MenuFileSave(selection, mods);
7360       }
7361       return true;
7362    }
7363
7364    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7365    {
7366       Window document;
7367
7368       for(document = children.first; document; document = document.next)
7369          //if(document.style.isDocument && document.state == minimized)
7370          if(document.style.isActiveClient && document.state == minimized)
7371             document.SetState(minimized, false, mods);
7372       return true;
7373    }
7374
7375    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7376    {
7377       Window document = activeChild;
7378       if(document)
7379       {
7380          Window firstDocument = null;
7381          Window child;
7382          OldLink cycle = document.cycle.prev;
7383          int id = 0;
7384          while(true)
7385          {
7386             child = cycle.data;
7387             if(child.style.isActiveClient && !child.style.hidden)
7388             {
7389                Window last;
7390
7391                firstDocument = child;
7392                if(child.state == minimized)
7393                   child.SetState(minimized, false, mods);
7394                else
7395                {
7396                   child.positionID = id++;
7397                   child.SetState(normal, false, mods);
7398                   child.anchor.left.type = cascade;
7399                   {
7400                      int x, y, w, h;
7401                      child.normalSizeAnchor = *&child.sizeAnchor;
7402                      child.normalAnchor = child.anchor;
7403
7404                      // Break the anchors for moveable/resizable windows
7405                      if(child.style.fixed)
7406                      {
7407                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7408
7409                         (*&child.normalAnchor).left = x;
7410                         (*&child.normalAnchor).top = y;
7411                         (*&child.normalAnchor).right.type = none;
7412                         (*&child.normalAnchor).bottom.type = none;
7413
7414                         child.normalSizeAnchor.isClientW = false;
7415                         child.normalSizeAnchor.isClientH = false;
7416                         child.normalSizeAnchor.size.w = w;
7417                         child.normalSizeAnchor.size.h = h;
7418                         child.anchored = false;
7419                      }
7420
7421                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7422                      {
7423                         child.stateAnchor = child.normalAnchor;
7424                         child.stateSizeAnchor = child.normalSizeAnchor;
7425
7426                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7427                         child.Position(x, y, w, h, true, true, true, true, false, false);
7428                      }
7429                   }
7430                }
7431
7432                last = children.last;
7433                if(!child.style.stayOnTop)
7434                   for(; last && last.style.stayOnTop; last = last.prev);
7435                children.Move(child, last);
7436                childrenOrder.Move(child.order, childrenOrder.last);
7437             }
7438             if(cycle == document.cycle) break;
7439             cycle = cycle.prev;
7440          }
7441          if(firstDocument)
7442             firstDocument.Activate();
7443       }
7444       return true;
7445    }
7446
7447    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7448    {
7449       if(style.hasClose)
7450          Destroy(0);
7451       return true;
7452    }
7453
7454    // Close all closes all active clients, not all documents
7455    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7456    {
7457       Window next, document;
7458
7459       for(document = children.first; document; document = next)
7460       {
7461          for(next = document.next; next && !(next.style.isActiveClient; next = next.next);
7462          if(document.style.isActiveClient)
7463             if(!document.Destroy(0) && !document.style.hidden)
7464                return false;
7465       }
7466       return true;
7467    }
7468
7469    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7470    {
7471       if(style.hasMaximize && state != maximized)
7472          SetState(maximized, 0, 0);
7473       return true;
7474    }
7475
7476    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7477    {
7478       if(style.hasMinimize && state != minimized)
7479       {
7480          SetState(minimized, 0, 0);
7481          parent.CycleChildren(false, true, false, true);
7482       }
7483       return true;
7484    }
7485
7486    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7487    {
7488       MenuMoveOrSize(false, selection ? true : false);
7489       return true;
7490    }
7491
7492    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7493    {
7494       CycleChildren(false, true, false, true);
7495       return true;
7496    }
7497
7498    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7499    {
7500       CycleChildren(true, true, false, true);
7501       return true;
7502    }
7503
7504    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7505    {
7506       MenuMoveOrSize(true, true);
7507       return true;
7508    }
7509
7510    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7511    {
7512       if(state != normal)
7513          SetState(normal, 0, 0);
7514       return true;
7515    }
7516
7517    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7518    {
7519       Window document;
7520       int64 id = selection.id;
7521       OldLink cycle = activeClient.cycle;
7522       int c = 0;
7523       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7524       while(true)
7525       {
7526          Window sibling = cycle.data;
7527          if(sibling.style.isActiveClient && sibling.visible && !sibling.style.nonClient)
7528          {
7529             if(c == id)
7530                break;
7531             c++;
7532          }
7533          cycle = cycle.next;
7534       }
7535       document = cycle.data;
7536       document.Activate();
7537       
7538       //if(activeChild.state == maximized)
7539       //  document.SetState(maximized, false, mods);
7540       //else if(document.state == minimized)
7541       //   document.SetState(normal, false, mods);
7542       return true;
7543    }
7544
7545    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7546    {
7547       stayOnTop = !style.stayOnTop;
7548       return true;
7549    }
7550
7551    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7552    {
7553       Window document = activeChild;
7554       if(document)
7555       {
7556          Window firstDocument = null;
7557          OldLink cycle = document.cycle;
7558          int id = 0;
7559          while(true)
7560          {
7561             Window child = cycle.data;
7562             if(child.style.isActiveClient && !child.style.hidden)
7563             {
7564                if(!firstDocument) firstDocument = child;
7565                if(child.state == minimized)
7566                   child.SetState(minimized, false, mods);
7567                else
7568                {
7569                   child.positionID = id++;
7570                   child.SetState(normal, false, mods);
7571                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7572
7573                   child.anchor.left.type = hTiled;
7574                   {
7575                      int x, y, w, h;
7576                      child.normalSizeAnchor = *&child.sizeAnchor;
7577                      child.normalAnchor = child.anchor;
7578
7579                      // Break the anchors for moveable/resizable windows
7580                      if(child.style.fixed)
7581                      {
7582                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7583
7584                         (*&child.normalAnchor).left = x;
7585                         (*&child.normalAnchor).top = y;
7586                         (*&child.normalAnchor).right.type = none;
7587                         (*&child.normalAnchor).bottom.type = none;
7588                         child.normalSizeAnchor.isClientW = false;
7589                         child.normalSizeAnchor.isClientH = false;
7590                         child.normalSizeAnchor.size.w = w;
7591                         child.normalSizeAnchor.size.h = h;
7592                         child.anchored = false;
7593                      }
7594
7595                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7596                      {
7597                         child.stateAnchor = child.normalAnchor;
7598                         child.stateSizeAnchor = child.normalSizeAnchor;
7599
7600                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7601                         child.Position(x,y, w, h, true, true, true, true, false, true);
7602                      }
7603                   }
7604                }
7605             }
7606             if((cycle = cycle.next) == document.cycle) break;
7607          }
7608          if(firstDocument)
7609             firstDocument.Activate();
7610       }
7611       return true;
7612    }
7613
7614    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
7615    {
7616       Window document = activeChild;
7617       if(document)
7618       {
7619          Window firstDocument = null;
7620          Window child;
7621          OldLink cycle = document.cycle;
7622          int id = 0;
7623          while(true)
7624          {
7625             child = cycle.data;
7626             //if(child.style.isDocument)
7627             if(child.style.isActiveClient && !child.style.hidden)
7628             {
7629                if(!firstDocument) firstDocument = child;
7630                if(child.state == minimized)
7631                   child.SetState(minimized, false, mods);
7632                else
7633                {
7634                   child.positionID = id++;
7635                   child.SetState(normal, false, mods);
7636                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7637
7638                   child.anchor.left.type = vTiled;
7639                   {
7640                      int x, y, w, h;
7641                      child.normalSizeAnchor = *&child.sizeAnchor;
7642                      child.normalAnchor = child.anchor;
7643
7644                      // Break the anchors for moveable/resizable windows
7645                      if(child.style.fixed)
7646                      {
7647                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7648
7649                         (*&child.normalAnchor).left = x;
7650                         (*&child.normalAnchor).top = y;
7651                         (*&child.normalAnchor).right.type = none;
7652                         (*&child.normalAnchor).bottom.type = none;
7653                         child.normalSizeAnchor.isClientW = false;
7654                         child.normalSizeAnchor.isClientH = false;
7655                         child.normalSizeAnchor.size.w = w;
7656                         child.normalSizeAnchor.size.h = h;
7657                         child.anchored = false;
7658                      }
7659
7660                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7661                      {
7662                         child.stateAnchor = child.normalAnchor;
7663                         child.stateSizeAnchor = child.normalSizeAnchor;
7664
7665                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7666                         child.Position(x,y, w, h, true, true, true, true, false, true);
7667                      }
7668                   }
7669                }
7670             }
7671             if((cycle = cycle.next) == document.cycle) break;
7672          }
7673          if(firstDocument)
7674             firstDocument.Activate();
7675       }
7676       return true;
7677    }
7678
7679    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
7680    {
7681       WindowList dialog { master = this };
7682       Window document = (Window)dialog.Modal();
7683       if(document)
7684       {
7685          if(activeChild.state == maximized)
7686             document.SetState(maximized, false, mods);
7687          else if(document.state == minimized)
7688             document.SetState(normal, false, mods);
7689          document.Activate();
7690       }
7691       return true;
7692    }
7693
7694    // Virtual Methods
7695    virtual bool OnCreate(void);
7696    virtual void OnDestroy(void);
7697    virtual void OnDestroyed(void);
7698    virtual bool OnClose(bool parentClosing);
7699    virtual bool OnStateChange(WindowState state, Modifiers mods);
7700    virtual bool OnPostCreate(void);
7701    virtual bool OnMoving(int *x, int *y, int w, int h);
7702    virtual bool OnResizing(int *width, int *height);
7703    virtual void OnResize(int width, int height);
7704    virtual void OnPosition(int x, int y, int width, int height);
7705    virtual bool OnLoadGraphics(void);
7706    virtual void OnApplyGraphics(void);
7707    virtual void OnUnloadGraphics(void);
7708    virtual void OnRedraw(Surface surface);
7709    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
7710    virtual void OnActivateClient(Window client, Window previous);
7711    virtual bool OnKeyDown(Key key, unichar ch);
7712    virtual bool OnKeyUp(Key key, unichar ch);
7713    virtual bool OnKeyHit(Key key, unichar ch);
7714    virtual bool OnSysKeyDown(Key key, unichar ch);
7715    virtual bool OnSysKeyUp(Key key, unichar ch);
7716    virtual bool OnSysKeyHit(Key key, unichar ch);
7717    virtual bool OnMouseOver(int x, int y, Modifiers mods);
7718    virtual bool OnMouseLeave(Modifiers mods);
7719    virtual bool OnMouseMove(int x, int y, Modifiers mods);
7720    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
7721    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
7722    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
7723    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
7724    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
7725    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
7726    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
7727    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
7728    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
7729    virtual void OnMouseCaptureLost(void);
7730    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
7731    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
7732    virtual void OnDrawOverChildren(Surface surface);
7733    virtual bool OnFileModified(FileChange fileChange, char * param);
7734    virtual bool OnSaveFile(char * fileName);
7735
7736    // Virtual Methods -- Children management (To support Stacker, for lack of built-in auto-layout)
7737    // Note: A 'client' would refer to isActiveClient, rather than
7738    // being confined to the 'client area' (nonClient == false)
7739    virtual void OnChildAddedOrRemoved(Window child, bool removed);
7740    virtual void OnChildVisibilityToggled(Window child, bool visible);
7741    virtual void OnChildResized(Window child, int x, int y, int w, int h);
7742
7743    // Skins Virtual Functions
7744    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
7745    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
7746    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
7747    {
7748       *cw = *w;
7749       *ch = *h;      
7750    }
7751    virtual void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7752    virtual void PreShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7753    virtual bool IsMouseMoving(int x, int y, int w, int h)
7754    {
7755       return false;
7756    }
7757    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY)
7758    {
7759       return false;
7760    }
7761    virtual void UpdateNonClient();
7762    virtual void SetBox(Box box);
7763    virtual bool IsInside(int x, int y)
7764    {
7765       return box.IsPointInside({x, y});
7766    }
7767    virtual bool IsOpaque()
7768    {
7769       return (!style.drawBehind || background.a == 255);
7770    }
7771
7772    // Notifications
7773    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
7774    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
7775    virtual void Window::NotifySaved(Window window, char * filePath);
7776
7777    // Public Methods
7778
7779    // Properties
7780    property Window parent
7781    {
7782       property_category $"Layout"
7783       set
7784       {
7785          if(value || guiApp.desktop)
7786          {
7787             Window last;
7788             Window oldParent = parent;
7789             Anchor anchor = this.anchor;
7790
7791             if(value && value.IsDescendantOf(this)) return;
7792             if(value && value == this)
7793                return;
7794             if(!value) value = guiApp.desktop;
7795
7796             if(value == oldParent) return;
7797
7798             if(!master || (master == this.parent && master == guiApp.desktop))
7799                property::master = value;
7800             
7801             if(parent)
7802             {
7803                parent.children.Remove(this);
7804
7805                parent.Update(
7806                {
7807                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7808                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
7809                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7810                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
7811                });
7812             }
7813
7814             last = value.children.last;
7815
7816             if(style.isDocument)
7817             {
7818                if(parent)
7819                   parent.numDocuments--;
7820                documentID = value.GetDocumentID();
7821             }
7822
7823             if(style.isActiveClient && !style.hidden)
7824             {
7825                if(parent && parent != guiApp.desktop && !(style.hidden))
7826                {
7827                   if(state == minimized) parent.numIcons--;
7828                   parent.numPositions--;
7829                }
7830             }
7831
7832             if(!style.stayOnTop)
7833                for(; last && last.style.stayOnTop; last = last.prev);
7834
7835             value.children.Insert(last, this);
7836
7837             // *** NEW HERE: ***
7838             if(cycle)
7839                parent.childrenCycle.Delete(cycle);
7840             if(order)
7841                parent.childrenOrder.Delete(order);
7842             cycle = null;
7843             order = null;
7844             // *** TODO: Added this here to solve crash on setting parent to null before destroying/destructing ***
7845             //           Should something else be done?
7846             if(parent && parent.activeChild == this)
7847                parent.activeChild = null;
7848             if(parent && parent.activeClient == this)
7849                parent.activeClient = null;
7850
7851             //if(created)
7852             {
7853                if(created)
7854                {
7855                   int x = position.x, y = position.y, w = size.w, h = size.h;
7856                   
7857                   int vpw, vph;
7858
7859                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
7860                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
7861                   
7862                   vpw = value.clientSize.w;
7863                   vph = value.clientSize.h;
7864                   if(style.nonClient)
7865                   {
7866                      vpw = value.size.w;
7867                      vph = value.size.h;
7868                   }
7869                   else if(style.fixed)
7870                   {
7871                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
7872                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
7873                   }
7874
7875                   anchor = this.anchor;
7876
7877                   if(anchor.left.type == offset)            anchor.left.distance = x;
7878                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
7879                   if(anchor.top.type == offset)             anchor.top.distance = y;
7880                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
7881                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
7882                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
7883                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
7884                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
7885                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
7886                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
7887
7888                   if(!anchor.left.type && !anchor.right.type)
7889                   {
7890                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
7891                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
7892                   }
7893                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
7894                   if(!anchor.top.type && !anchor.bottom.type)
7895                   {
7896                      anchor.vert.distance = (y + h / 2) - (vph / 2);
7897                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
7898                   }
7899                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
7900                }
7901                parent = value;
7902                parent.OnChildAddedOrRemoved(this, false);
7903
7904                // *** NEW HERE ***
7905                if(!style.inactive)
7906                {
7907                   if(!style.noCycle)
7908                      parent.childrenCycle.Insert(
7909                         // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
7910                         //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
7911                         null,
7912                         cycle = OldLink { data = this });
7913                   parent.childrenOrder.Insert(
7914                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last, 
7915                      order = OldLink { data = this });
7916                }
7917
7918                if(!style.hidden && style.isActiveClient)
7919                {
7920                   positionID = parent.GetPositionID(this);
7921                   parent.numPositions++;
7922                   if(state == minimized) parent.numIcons--;
7923                }
7924
7925                // *** FONT INHERITANCE ***
7926                if(!setFont && oldParent) 
7927                   stopwatching(oldParent, font);
7928
7929                if(systemFont)
7930                {
7931                   RemoveResource(systemFont);
7932                   delete systemFont;
7933                }
7934                // TESTING WITH WATCHERS:
7935                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7936                // usedFont = setFont ? setFont : (systemFont);
7937
7938                if(!usedFont)
7939                {
7940                   if(guiApp.currentSkin)
7941                   {
7942                      systemFont = guiApp.currentSkin.SystemFont();
7943                      incref systemFont;
7944                   }
7945                   usedFont = systemFont;
7946                   AddResource(systemFont);
7947                }
7948
7949                if(!setFont)
7950                   watch(value)
7951                   {
7952                      font
7953                      {
7954                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7955                         firewatchers font;
7956                         Update(null);
7957                      }
7958                   };
7959                
7960                firewatchers font;
7961
7962
7963                if(value.rootWindow && value.rootWindow.display && rootWindow)
7964                {
7965                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) || 
7966                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
7967                   
7968                   if(reloadGraphics)
7969                      UnloadGraphics(false);
7970                   SetupDisplay();
7971                   if(reloadGraphics)
7972                      LoadGraphics(false, false);
7973                      
7974                   /*
7975                   if(value.rootWindow != rootWindow)
7976                      DisplayModeChanged();
7977                   else
7978                   */
7979                }
7980                scrolledPos.x = MININT; // Prevent parent update
7981                {
7982                   bool anchored = this.anchored;
7983                   property::anchor = anchor;
7984                   this.anchored = anchored;
7985                }
7986                /*
7987                {
7988                   int x, y, w, h;
7989                   if(guiApp.currentSkin)
7990                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
7991
7992                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
7993                   Position(x, y, w, h, true, true, true, true, false, true);
7994                }
7995                */
7996
7997             }
7998             // else parent = value;
7999             if(oldParent)
8000                oldParent.OnChildAddedOrRemoved(this, true);
8001          }
8002       }
8003       get { return parent; }
8004    };
8005
8006    property Window master
8007    {
8008       property_category $"Behavior"
8009       set
8010       {
8011          //if(this == value) return;
8012          if(value && value.IsSlaveOf(this)) return;
8013
8014          if(master != value)
8015          {
8016             if(master)
8017             {
8018                OldLink slaveHolder;
8019                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
8020                   if(slaveHolder.data == this)
8021                   {
8022                      master.slaves.Delete(slaveHolder);
8023                      break;
8024                   }
8025             }
8026
8027             if(value)
8028             {
8029                value.slaves.Add(OldLink { data = this });
8030
8031                if(hotKey)
8032                {
8033                   if(master)
8034                      master.hotKeys.Remove(hotKey);
8035                   value.hotKeys.Add(hotKey);
8036                   hotKey = null;
8037                }
8038                if(master && master.defaultControl == this)
8039                   master.defaultControl = null;
8040
8041                if(style.isDefault && !value.defaultControl)
8042                   value.defaultControl = this;
8043             }
8044          }
8045          master = value;
8046       }
8047       get { return master ? master : parent; }
8048    };
8049
8050    property char * caption
8051    {
8052       property_category $"Appearance"
8053       watchable
8054       set
8055       {
8056          delete caption;
8057          if(value)
8058          {
8059             caption = new char[strlen(value)+1];
8060             if(caption)
8061                strcpy(caption, value);
8062          }
8063          if(created)
8064             UpdateCaption();
8065       }
8066       get { return caption; }
8067    };
8068
8069    property Key hotKey
8070    {
8071       property_category $"Behavior"
8072       set
8073       {
8074          setHotKey = value;
8075          if(created)
8076          {
8077             if(value)
8078             {
8079                if(!hotKey)
8080                   master.hotKeys.Add(hotKey = HotKeySlot { });
8081                if(hotKey)
8082                {
8083                   hotKey.key = value;
8084                   hotKey.window = this;
8085                }
8086             }
8087             else if(hotKey)
8088             {
8089                master.hotKeys.Delete(hotKey);
8090                hotKey = null;
8091             }
8092          }
8093       }
8094       get { return hotKey ? hotKey.key : 0; }
8095    };
8096
8097    property Color background
8098    {
8099       property_category $"Appearance"
8100       set
8101       {
8102          background.color = value;
8103          firewatchers;
8104          if(created)
8105          {
8106             Update(null);
8107             if(this == rootWindow)
8108                guiApp.interfaceDriver.SetRootWindowColor(this);
8109          }
8110       }
8111       get { return background.color; }
8112    };
8113
8114    property Percentage opacity
8115    {
8116       property_category $"Appearance"
8117       set
8118       {
8119          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
8120          drawBehind = (background.a == 255) ? false : true;
8121       }
8122       get { return background.a / 255.0f; }
8123    };
8124
8125    property Color foreground
8126    {
8127       property_category $"Appearance"
8128       set
8129       {
8130          foreground = value;
8131          firewatchers;
8132          if(created)
8133             Update(null);
8134       }
8135       get { return foreground; }
8136    };
8137
8138    property BorderStyle borderStyle
8139    {
8140       property_category $"Appearance"
8141       set
8142       {
8143          if(!((BorderBits)value).fixed)
8144          {
8145             style.hasClose = false;
8146             style.hasMaximize = false;
8147             style.hasMinimize = false;
8148             nativeDecorations = false;
8149          }
8150          style.borderBits = value;
8151          if(created)
8152          {
8153             int x, y, w, h;
8154             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8155
8156             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8157             Position(x, y, w, h, true, true, true, true, false, true);
8158             CreateSystemChildren();
8159          }
8160       }
8161       get { return (BorderStyle)style.borderBits; } 
8162    };
8163
8164    property Size minClientSize
8165    {
8166       property_category $"Layout"
8167       set { minSize = value; }
8168       get { value = minSize; }
8169    };
8170
8171    property Size maxClientSize
8172    {
8173       property_category $"Layout"
8174       set { maxSize = value; }
8175       get { value = maxSize; }
8176    };
8177
8178    property bool hasMaximize
8179    {
8180       property_category $"Window Style"
8181       set
8182       {
8183          style.hasMaximize = value;
8184          if(value) { style.fixed = true; style.contour = true; }
8185          if(created)
8186          {
8187             int x, y, w, h;
8188             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8189
8190             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8191             Position(x, y, w, h, true, true, true, true, false, true);
8192
8193             CreateSystemChildren();
8194          }
8195       }
8196       get { return style.hasMaximize; }
8197    };
8198
8199    property bool hasMinimize
8200    {
8201       property_category $"Window Style"
8202       set
8203       {
8204          style.hasMinimize = value;
8205          if(value) { style.fixed = true; style.contour = true; }
8206          if(created)
8207          {
8208             int x, y, w, h;
8209             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8210
8211             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8212             Position(x, y, w, h, true, true, true, true, false, true);
8213
8214             CreateSystemChildren();
8215          }
8216       }
8217       get { return style.hasMinimize;  }
8218    };
8219
8220    property bool hasClose
8221    {
8222       property_category $"Window Style"
8223       set
8224       {
8225          style.hasClose = value;
8226          if(value) { style.fixed = true; style.contour = true; }
8227          if(created)
8228          {
8229             int x, y, w, h;
8230             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8231             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8232             Position(x, y, w, h, true, true, true, true, false, true);
8233             CreateSystemChildren();
8234          }
8235       }
8236       get { return style.hasClose; }
8237    };
8238    
8239    property bool nonClient
8240    {
8241       property_category $"Layout"
8242       set
8243       {
8244          style.nonClient = value;
8245          if(value)
8246             style.stayOnTop = true;
8247       }
8248       get { return style.nonClient; }
8249    };
8250
8251    property bool inactive
8252    {
8253       property_category $"Behavior"
8254       set
8255       {
8256          if(value) 
8257          {
8258             // *** NEW HERE: ***
8259             if(!style.inactive)
8260             {
8261                if(cycle)
8262                   parent.childrenCycle.Delete(cycle);
8263                if(order)
8264                   parent.childrenOrder.Delete(order);
8265                cycle = null;
8266                order = null;
8267             }
8268
8269             if(created)
8270             {
8271                active = false; // true;
8272                if(parent.activeChild == this)
8273                   parent.activeChild = null;
8274                if(parent.activeClient == this)
8275                   parent.activeClient = null;
8276             }
8277          }
8278          else
8279          {
8280             if(style.inactive)
8281             {
8282                if(!style.noCycle)
8283                {
8284                   parent.childrenCycle.Insert(
8285                      // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8286                      //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
8287                      null,
8288                      cycle = OldLink { data = this });
8289                }
8290                parent.childrenOrder.Insert(
8291                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8292                   order = OldLink { data = this });
8293             }
8294          }
8295          style.inactive = value;
8296       }
8297       get { return style.inactive; }
8298    };
8299
8300    property bool clickThrough
8301    {
8302       property_category $"Behavior"
8303       set { style.clickThrough = value; }
8304       get { return style.clickThrough; }
8305    };
8306
8307    property bool isRemote
8308    {
8309       property_category $"Behavior"
8310       set { style.isRemote = value; }
8311       get { return style.isRemote; }
8312    };
8313
8314    property bool noCycle
8315    {
8316       property_category $"Behavior"
8317       set { style.noCycle = value; }
8318       get { return style.noCycle; }
8319    };
8320
8321    property bool isModal
8322    {
8323       property_category $"Behavior"
8324       set { style.modal = value; }
8325       get { return style.modal; }
8326    };
8327
8328    property bool interim
8329    {
8330       property_category $"Behavior"
8331       set { style.interim = value; }
8332       get { return style.interim; }
8333    };
8334
8335    property bool tabCycle
8336    {
8337       property_category $"Behavior"
8338       set { style.tabCycle = value; }
8339       get { return style.tabCycle; }
8340    };
8341      
8342    property bool isDefault
8343    {
8344       property_category $"Behavior"
8345       set
8346       {
8347          if(master)
8348          {
8349             if(value)
8350             {
8351                Window sibling;
8352                /*for(sibling = parent.children.first; sibling; sibling = sibling.next)
8353                   if(sibling != this && sibling.style.isDefault)
8354                      sibling.style.isDefault = false;*/
8355                if(master.defaultControl)
8356                   master.defaultControl.style.isDefault = false;
8357                master.defaultControl = this;
8358             }
8359             else if(master.defaultControl == this)
8360                master.defaultControl = null;
8361
8362             // Update(null);
8363          }
8364          style.isDefault = value;
8365          if(created)
8366             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8367       }
8368       get { return style.isDefault; }
8369    };
8370
8371    property bool drawBehind
8372    {
8373       property_category $"Window Style"
8374       set { style.drawBehind = value; }
8375       get { return style.drawBehind; }
8376    };
8377
8378    property bool hasMenuBar
8379    {
8380       property_category $"Window Style"
8381       set
8382       {
8383          if(value) 
8384          {
8385             if(!menu)
8386             {
8387                menu = Menu { };
8388                incref menu;
8389             }
8390             if(created && !menuBar)
8391             {
8392                menuBar =
8393                   PopupMenu 
8394                   {
8395                      this, menu = menu,
8396                      isMenuBar = true,
8397                      anchor = Anchor { top = 23, left = 1, right = 1 },
8398                      size.h = 24,
8399                      inactive = true, nonClient = true                            
8400                   };
8401                menuBar.Create();
8402             }
8403          }
8404          else if(created && menuBar)
8405          {
8406             menuBar.Destroy(0);
8407             menuBar = null;
8408          }
8409          style.hasMenuBar = value;
8410       }
8411       get { return style.hasMenuBar; }
8412    };
8413
8414    property bool hasStatusBar
8415    {
8416       property_category $"Window Style"
8417       set
8418       {
8419          if(value)
8420          {
8421             if(!statusBar)
8422             {
8423                statusBar = StatusBar { this };
8424                incref statusBar;
8425                if(created)
8426                   statusBar.Create();
8427             }
8428          }
8429          else if(statusBar)
8430             delete statusBar;
8431          style.hasStatusBar = value;
8432       }
8433       get { return style.hasStatusBar; }
8434    };
8435    property bool stayOnTop
8436    {
8437       property_category $"Window Style"
8438       set
8439       {
8440          if(value)
8441          {
8442             if(created && !style.stayOnTop)
8443             {
8444                if(rootWindow == this)
8445                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8446                else if(parent.children.last != this)
8447                {
8448                   parent.children.Move(this, parent.children.last);
8449                   Update(null);
8450                }
8451             }
8452             style.stayOnTop = true;
8453          }
8454          else
8455          {
8456             if(created && style.stayOnTop)
8457             {
8458                if(rootWindow == this)
8459                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8460                else
8461                {
8462                   Window last;
8463                   if(order)
8464                   {
8465                      OldLink order;
8466                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev; 
8467                          order && ((Window)order.data).style.stayOnTop;
8468                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8469                       last = order ? order.data : null;
8470                   }
8471                   else
8472                   {
8473                      for(last = parent.children.last; 
8474                          last && last.style.stayOnTop;
8475                          last = last.prev);
8476                   }
8477
8478                   parent.children.Move(this, last);
8479                   Update(null);
8480                }
8481             }
8482             style.stayOnTop = false;
8483          }
8484       }
8485       get { return style.stayOnTop; }
8486    };
8487
8488    property Menu menu
8489    {
8490       property_category $"Window Style"
8491       set
8492       {
8493          delete menu;
8494          if(value)
8495          {
8496             menu = value;
8497             incref menu;
8498          }
8499
8500          if(menuBar && !value)
8501          {
8502             menuBar.Destroy(0);
8503             menuBar = null;
8504          }
8505          if(created)
8506          {
8507             if(!menuBar && style.hasMenuBar && value)
8508             {
8509                menuBar = PopupMenu
8510                          { 
8511                             this, menu = value, isMenuBar = true, 
8512                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24, 
8513                             inactive = true, nonClient = true
8514                          };
8515                 menuBar.Create();
8516             }
8517             UpdateActiveDocument(null);
8518          }
8519       }
8520       get { return menu; }
8521    };
8522
8523    property FontResource font
8524    {
8525       property_category $"Appearance"
8526       watchable
8527       isset { return setFont ? true : false; }
8528       set
8529       {
8530          if(this)
8531          {
8532             if(value && !setFont) { stopwatching(parent, font); }
8533             else if(!value && setFont)
8534             {
8535                watch(parent)
8536                {
8537                   font
8538                   {
8539                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8540                      firewatchers font;
8541                      Update(null);
8542                   }
8543                };
8544             }
8545
8546             if(setFont)
8547             {
8548                RemoveResource(setFont);
8549                delete setFont;
8550             }
8551             if(systemFont)
8552             {
8553                RemoveResource(systemFont);
8554                delete systemFont;
8555             }
8556             setFont = value;
8557             if(setFont)
8558             {
8559                incref setFont;
8560                AddResource(setFont);
8561             }
8562
8563             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8564             if(!usedFont)
8565             {
8566                systemFont = guiApp.currentSkin.SystemFont();
8567                incref systemFont;
8568                usedFont = systemFont;
8569                AddResource(systemFont);
8570             }
8571
8572             firewatchers;
8573
8574             Update(null);
8575          }
8576       }
8577       get { return usedFont; }
8578    };
8579
8580    property SizeAnchor sizeAnchor
8581    {
8582       property_category $"Layout"
8583       isset
8584       {
8585          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8586                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8587             sizeAnchor.isClientW != sizeAnchor.isClientH;
8588       }
8589       set
8590       {
8591          int x, y, w, h;
8592          sizeAnchor = value;
8593
8594          normalSizeAnchor = sizeAnchor;
8595
8596          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8597          {
8598             stateAnchor = normalAnchor;
8599             stateSizeAnchor = normalSizeAnchor;
8600
8601             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8602             Position(x,y, w, h, true, true, true, true, false, true);
8603          }
8604       }
8605       get
8606       {
8607          value =
8608          {
8609             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
8610             sizeAnchor.isClientW,
8611             sizeAnchor.isClientH
8612          };
8613       }
8614    };
8615
8616    property Size size
8617    {
8618       property_category $"Layout"
8619       isset
8620       {
8621          Anchor thisAnchor = anchor;
8622          SizeAnchor thisSizeAnchor = sizeAnchor;
8623          bool leftRight = (anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none);
8624          bool topBottom = (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none);
8625          bool isClient = !sizeAnchor.isClientW && !sizeAnchor.isClientH;
8626          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8627                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8628             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8629       }
8630       set
8631       {
8632          int x, y, w, h;
8633
8634          sizeAnchor.isClientW = false;
8635          sizeAnchor.isClientH = false;
8636          sizeAnchor.size = value;
8637
8638          normalSizeAnchor = sizeAnchor;
8639
8640          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
8641          {
8642             stateAnchor = normalAnchor;
8643             stateSizeAnchor = normalSizeAnchor;
8644
8645             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8646             Position(x, y, w, h, true, true, true, true, false, true);
8647             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
8648          }
8649       }
8650       get { value = size; }
8651    };
8652
8653    property Size clientSize
8654    {
8655       property_category $"Layout"
8656       isset
8657       {
8658          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8659                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8660             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8661       }
8662       set
8663       {
8664          int x, y, w, h;
8665          sizeAnchor.isClientW = true;
8666          sizeAnchor.isClientH = true;
8667          sizeAnchor.size = value;
8668
8669          normalSizeAnchor = sizeAnchor;
8670
8671          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8672          {
8673             stateAnchor = normalAnchor;
8674             stateSizeAnchor = normalSizeAnchor;
8675
8676             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8677             Position(x,y, w, h, true, true, true, true, false, true);
8678          }
8679       }
8680       get { value = clientSize; }
8681    };
8682
8683    property Size initSize { get { value = sizeAnchor.size; } };
8684
8685    property Anchor anchor
8686    {
8687       property_category $"Layout"
8688       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
8689
8690       set
8691       {
8692          if(value != null)
8693          {
8694             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
8695             {
8696                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
8697                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
8698             }
8699             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
8700             {
8701                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
8702                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
8703             }
8704             anchor = value;
8705
8706             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type)) 
8707             {
8708                anchor.left.distance = 0;
8709                anchor.horz.type = 0;
8710             }
8711             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
8712             {
8713                anchor.top.distance = 0;
8714                anchor.vert.type = 0;
8715             }
8716
8717             anchored = true;
8718
8719             //if(created)
8720             {
8721                int x, y, w, h;
8722
8723                normalAnchor = anchor;
8724                
8725                // Break the anchors for moveable/resizable windows
8726                /*if(style.fixed ) //&& value.left.type == cascade)
8727                {
8728                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
8729
8730                   this.anchor = normalAnchor = Anchor { left = x, top = y };
8731                   normalSizeAnchor = SizeAnchor { { w, h } };
8732                   anchored = false;
8733                }*/
8734                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8735                {
8736                   stateAnchor = normalAnchor;
8737                   stateSizeAnchor = normalSizeAnchor;
8738
8739                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8740                   Position(x, y, w, h, true, true, true, true, false, true);
8741                }
8742             }
8743          }
8744          else
8745          {
8746             anchored = false;
8747          }
8748       }
8749       get { value = this ? anchor : Anchor { }; }
8750    };
8751
8752    property Point position
8753    {
8754       property_category $"Layout"
8755       set
8756       {
8757          if(value == null) return;
8758
8759          anchor.left = value.x;
8760          anchor.top  = value.y;
8761          anchor.right.type = none;
8762          anchor.bottom.type = none;
8763          //if(created)
8764          {
8765             int x, y, w, h;
8766
8767             normalAnchor = anchor;
8768
8769             // Break the anchors for moveable/resizable windows
8770             /*
8771             if(style.fixed)
8772             {
8773                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8774
8775                normalAnchor.left = x;
8776                normalAnchor.top = y;
8777                normalAnchor.right.type = none;
8778                normalAnchor.bottom.type = none;
8779                normalSizeAnchor.size.width = w;
8780                normalSizeAnchor.size.height = h;
8781                anchored = false;
8782             }
8783             */
8784             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8785             {
8786                stateAnchor = normalAnchor;
8787                stateSizeAnchor = normalSizeAnchor;
8788
8789                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8790                Position(x,y, w, h, true, true, true, true, false, true);
8791             }
8792          }
8793       }
8794       get { value = position; }
8795    };
8796
8797    property bool disabled
8798    {
8799       property_category $"Behavior"
8800       set
8801       {
8802          if(this && disabled != value)
8803          {
8804             disabled = value;
8805             if(created)
8806                Update(null);
8807          }
8808       }
8809       get { return (bool)disabled; }
8810    };
8811
8812    property bool isEnabled
8813    {
8814       get
8815       {
8816          Window parent;
8817          for(parent = this; parent; parent = parent.parent)
8818             if(parent.disabled)
8819                return false;
8820          return true;
8821       }
8822    };
8823
8824    property WindowState state
8825    {
8826       property_category $"Behavior"
8827       set { SetState(value, false, 0); }
8828       get { return this ? state : 0; }
8829    };
8830
8831    property bool visible
8832    {
8833       property_category $"Behavior"
8834       set
8835       {
8836          if(this && !value && !style.hidden && parent)
8837          {
8838             bool wasActiveChild = parent.activeChild == this;
8839             Window client = null;
8840
8841             style.hidden = true;
8842             if(style.isActiveClient)
8843             {
8844                parent.numPositions--;
8845                if(state == minimized) parent.numIcons--;
8846             }
8847
8848             if(created)
8849             {
8850                OldLink prevOrder = null;
8851
8852                if(rootWindow == this)
8853                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
8854                else
8855                {
8856                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
8857                   if(style.nonClient)
8858                   {
8859                      box.left   -= parent.clientStart.x;
8860                      box.top    -= parent.clientStart.y;
8861                      box.right  -= parent.clientStart.x;
8862                      box.bottom -= parent.clientStart.y;
8863                   }
8864                   parent.Update(box);
8865                }
8866                if(_isModal && master && master.modalSlave == this)
8867                   master.modalSlave = null;
8868
8869                if(order)
8870                {
8871                   OldLink tmpPrev = order.prev;
8872                   client = tmpPrev ? tmpPrev.data : null;
8873                   if(client && !client.style.hidden && !client.destroyed && client.created)
8874                      prevOrder = tmpPrev;
8875                   for(;;)
8876                   {
8877                      client = tmpPrev ? tmpPrev.data : null;
8878                      if(client == this) { client = null; break; }
8879                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
8880                      {
8881                         tmpPrev = client.order.prev;
8882                      }
8883                      else
8884                      {
8885                         if(client)
8886                            prevOrder = tmpPrev;
8887                         break;
8888                      }
8889                   }
8890
8891                   // If this window can be an active client, make sure the next window we activate can also be one
8892                   if(!style.nonClient && style.isActiveClient)
8893                   {
8894                      tmpPrev = prevOrder;
8895                      for(;;)
8896                      {
8897                         client = tmpPrev ? tmpPrev.data : null;
8898                         if(client == this) { client = null; break; }
8899                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
8900                         {
8901                            tmpPrev = client.order.prev;
8902                         }
8903                         else 
8904                         {
8905                            if(client)
8906                               prevOrder = tmpPrev;
8907                            break;
8908                         }
8909                      }
8910                      if(client && client.style.hidden) client = null;
8911                   }
8912                }
8913
8914                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
8915                {
8916                   if(order && prevOrder && prevOrder.data != this)
8917                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
8918                   else
8919                      ActivateEx(false, false, false, true, null, null);
8920
8921                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
8922                   if(parent.activeClient == this)
8923                   {
8924                      parent.activeClient = null;
8925                      parent.UpdateActiveDocument(null);
8926                   }
8927                }
8928                else if(parent.activeClient == this)
8929                {
8930                   parent.activeClient = client;
8931                   parent.UpdateActiveDocument(this);
8932                }
8933
8934                // *** Not doing this anymore ***
8935               /*
8936                if(cycle)
8937                   parent.childrenCycle.Delete(cycle);
8938                if(order)
8939                   parent.childrenOrder.Delete(order);
8940                cycle = null;
8941                order = null;
8942                */
8943                
8944                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8945             }
8946
8947             firewatchers;
8948          }
8949          else if(this && value && style.hidden)
8950          {
8951             style.hidden = false;
8952             if(created)
8953             {
8954                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8955                if(rootWindow == this)
8956                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
8957
8958                if(_isModal && master)
8959                   master.modalSlave = this;
8960
8961                if(style.isActiveClient)
8962                {
8963                   positionID = parent.GetPositionID(this);
8964                   parent.numPositions++;
8965                   if(state == minimized) parent.numIcons++;
8966                }
8967
8968                // *** NOT DOING THIS ANYMORE ***
8969                /*
8970                if(!(style.inactive))
8971                {
8972                   if(!(style.noCycle))
8973                   {
8974                      cycle = parent.childrenCycle.AddAfter(
8975                         (parent.activeChild && parent.activeChild.cycle) ? 
8976                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
8977                      cycle.data = this;
8978                   }
8979                   order = parent.childrenOrder.AddAfter(
8980                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8981                      sizeof(OldLink));
8982                   order.data = this;
8983                }
8984                */
8985      
8986                /*
8987                if(true || !parent.activeChild)
8988                   ActivateEx(true, false, true, true, null, null);
8989                */
8990                if(creationActivation == activate)
8991                   ActivateEx(true, false, true, true, null, null);
8992                else if(creationActivation == flash && !object)
8993                   Flash();               
8994
8995                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8996                Update(null);
8997
8998                // rootWindow.
8999                ConsequentialMouseMove(false);
9000             }
9001
9002             firewatchers;
9003          }
9004          else if(this)
9005             style.hidden = !value;
9006       }
9007
9008       get { return (style.hidden || !setVisible) ? false : true; }
9009    };
9010     
9011    property bool isDocument
9012    {
9013       property_category $"Document"
9014       set { style.isDocument = value; }
9015       get { return style.isDocument; }
9016    };
9017
9018    property bool mergeMenus
9019    {
9020       property_category $"Window Style"
9021       set { mergeMenus = value; }
9022       get { return (bool)mergeMenus; }
9023    };
9024
9025    property bool hasHorzScroll
9026    {
9027       property_category $"Window Style"
9028       set
9029       {
9030          if(value)
9031          {
9032             if(!style.hasHorzScroll && created)
9033             {
9034                CreateSystemChildren();         
9035                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9036             }
9037          }
9038          else if(style.hasHorzScroll)
9039          {
9040             sbh.Destroy(0);
9041             sbh = null;
9042             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9043          }
9044          style.hasHorzScroll = value;
9045       }
9046
9047       get { return style.hasHorzScroll; }
9048    };
9049
9050    property bool hasVertScroll
9051    {
9052       property_category $"Window Style"
9053       set
9054       {
9055          if(value)
9056          {
9057             if(!style.hasVertScroll && created)
9058             {
9059                style.hasVertScroll = true;
9060                CreateSystemChildren();
9061                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9062             }
9063          }
9064          else if(style.hasVertScroll)
9065          {
9066             sbv.Destroy(0);
9067             sbv = null;
9068             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9069          }
9070          style.hasVertScroll = value;
9071       }
9072       get { return style.hasVertScroll; }
9073    };
9074
9075    property bool dontHideScroll
9076    {
9077       property_category $"Behavior"
9078       set
9079       {
9080          scrollFlags.dontHide = value;
9081          if(value)
9082          {
9083             //UpdateScrollBars(true, true);
9084             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9085          }
9086          else
9087          {
9088             // UpdateScrollBars(true, true);
9089             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9090          }
9091       }
9092       get { return scrollFlags.dontHide; }
9093    };
9094
9095    property bool dontScrollVert
9096    {
9097       property_category $"Behavior"
9098       set { style.dontScrollVert = value; }
9099       get { return style.dontScrollVert; }
9100    };
9101    property bool dontScrollHorz
9102    {
9103       property_category $"Behavior"
9104       set { style.dontScrollHorz = value; }
9105       get { return style.dontScrollHorz; }
9106    };
9107
9108    property bool snapVertScroll
9109    {
9110       property_category $"Behavior"
9111       set
9112       {
9113          scrollFlags.snapY = value;
9114          if(sbv) sbv.snap = value;
9115       }
9116       get { return scrollFlags.snapY; }
9117    };
9118    property bool snapHorzScroll
9119    {
9120        property_category $"Behavior"
9121       set
9122       {
9123          scrollFlags.snapX = value;
9124          if(sbh) sbh.snap = value;
9125       }
9126       get { return scrollFlags.snapX; }
9127    };
9128
9129    property Point scroll
9130    {
9131       property_category $"Behavior"
9132       set { SetScrollPosition(value.x, value.y); }
9133       get { value = scroll; }
9134    };
9135
9136    property bool modifyVirtualArea
9137    {
9138       property_category $"Behavior"
9139       set { modifyVirtArea = value; }
9140       get { return (bool)modifyVirtArea; }
9141    };
9142
9143    property bool dontAutoScrollArea
9144    {
9145       property_category $"Behavior"
9146       // Activating a child control out of view will automatically scroll to make it in view
9147       set { noAutoScrollArea = value; }
9148       get { return (bool)noAutoScrollArea; }
9149    };
9150
9151    property char * fileName
9152    {
9153       property_category $"Document"
9154       set
9155       {
9156          if(menu && ((!fileName && value) || (fileName && !value)))
9157          {
9158             MenuItem item = menu.FindItem(MenuFileSave, 0);
9159             if(item) item.disabled = !modifiedDocument && value;
9160          }
9161
9162          delete fileName;
9163
9164          if(value && value[0])
9165             fileName = CopyString(value);
9166
9167          if(parent && this == parent.activeClient)
9168             parent.UpdateActiveDocument(null);
9169          else
9170             UpdateCaption();
9171
9172          // if(style.isDocument)
9173          if(!saving)
9174             fileMonitor.fileName = value;
9175       }
9176       get { return fileName; }
9177    };
9178
9179    property int64 id
9180    {
9181       property_category $"Data"
9182       set { id = value; }
9183       get { return id; }
9184    };
9185
9186    property bool modifiedDocument
9187    {
9188       property_category $"Document"
9189       set
9190       {
9191          if(style.isDocument || fileName)
9192          {
9193             if(menu)
9194             {
9195                MenuItem item = menu.FindItem(MenuFileSave, 0);
9196                if(item) item.disabled = !value && fileName;
9197             }
9198          }
9199
9200          if(modifiedDocument != value)
9201          {
9202             modifiedDocument = value;
9203             if(style.isDocument || fileName)
9204                UpdateCaption();
9205          }
9206       }
9207       get { return (bool)modifiedDocument; }
9208    };
9209
9210    property bool showInTaskBar
9211    {
9212       property_category $"Window Style"
9213       set { style.showInTaskBar = value; }
9214       get { return (style.showInTaskBar; }
9215    };
9216    property FileDialog saveDialog { set { saveDialog = value; } };
9217    property bool isActiveClient
9218    {
9219       property_category $"Behavior"
9220       set { style.isActiveClient = value; }
9221       get { return style.isActiveClient; }
9222    };
9223
9224    property Cursor cursor
9225    {
9226       property_category $"Appearance"
9227       set
9228       {
9229          cursor = value;
9230          SelectMouseCursor();
9231       }
9232       get { return cursor; }
9233    };      
9234
9235 //#if !defined(ECERE_VANILLA)
9236    property char * name
9237    {
9238       property_category $"Design"
9239       get
9240       {
9241          return (this && object) ? object.name : null;
9242       }
9243       set
9244       {
9245          if(activeDesigner)
9246             activeDesigner.RenameObject(object, value);
9247       }
9248    };
9249 //#endif
9250    property char * displayDriver
9251    {
9252       property_category $"Behavior"
9253       set
9254       {
9255          dispDriver = GetDisplayDriver(value);
9256          //DisplayModeChanged();
9257       }
9258       get
9259       {
9260          return dispDriver ? dispDriver.name : null;
9261       }
9262    }
9263
9264    // RUNTIME PROPERTIES
9265    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9266    property Size scrollArea
9267    {
9268       property_category $"Behavior"
9269       set
9270       {
9271          if(value != null)
9272             SetScrollArea(value.w, value.h, false);
9273          else
9274             SetScrollArea(0,0, true);
9275       }
9276       get { value = scrollArea; }
9277       isset
9278       {
9279          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9280       }
9281    };
9282    property bool is3D
9283    {
9284       property_category $"Layout"
9285       set { if(this) is3D = value; }
9286       get { return (bool)is3D; }
9287    };
9288
9289    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9290                                                                                                             
9291    // Will be merged with font later
9292    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9293    property Point clientStart { get { value = clientStart; } };
9294    property Point absPosition { get { value = absPosition; } };
9295    property Anchor normalAnchor { get {value = normalAnchor; } };
9296    // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
9297    property bool active { get { return (bool)active; } };
9298    property bool created { get { return (bool)created; } };
9299    property bool destroyed { get { return (bool)destroyed; } };
9300    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9301    property Window firstChild { get { return children.first; } };   
9302    property Window lastChild { get { return children.last; } };   
9303    property Window activeClient { get { return activeClient; } };
9304    property Window activeChild { get { return activeChild; } };
9305    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9306    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9307    property ScrollBar horzScroll { get { return sbh; } };
9308    property ScrollBar vertScroll { get { return sbv; } };
9309    property StatusBar statusBar { get { return statusBar; } };
9310    property Window rootWindow { get { return rootWindow; } };   
9311    property bool closing { get { return (bool)closing; } set { closing = value; } };
9312    property int documentID { get { return documentID; } };
9313    property Window previous { get { return prev; } }
9314    property Window next { get { return next; } }
9315    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9316    property PopupMenu menuBar { get { return menuBar; } }
9317    property ScrollBar sbv { get { return sbv; } }
9318    property ScrollBar sbh { get { return sbh; } }
9319    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9320    property void * systemHandle { get { return windowHandle; } }
9321    property Button minimizeButton { get { return sysButtons[0]; } };
9322    property Button maximizeButton { get { return sysButtons[1]; } };   
9323    property Button closeButton { get { return sysButtons[2]; } };
9324    property BitmapResource icon
9325    {
9326       get { return icon; }
9327       set
9328       {
9329          icon = value;
9330          if(icon) incref icon;
9331          if(created)
9332             guiApp.interfaceDriver.SetIcon(this, value);
9333       }
9334    };
9335    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9336    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
9337    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9338    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9339    property bool nativeDecorations
9340    {
9341       get { return (bool)nativeDecorations; }
9342       set { nativeDecorations = value; }
9343 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
9344       isset
9345       {
9346          //return (nativeDecorations && (rootWindow == this || (formDesigner && activeDesigner && ((FormDesigner)activeDesigner.classDesigner).form && parent == ((FormDesigner)activeDesigner.classDesigner).form.parent))) != style.fixed;
9347          bool result = false;
9348          if(nativeDecorations)
9349          {
9350             if(rootWindow == this)
9351                result = true;
9352             else
9353             {
9354                if(formDesigner && activeDesigner)
9355                {
9356                   FormDesigner cd = (FormDesigner)activeDesigner.classDesigner;
9357                   Window form = cd ? cd.form : null;
9358                   if(form && parent == form.parent)
9359                      result = true;
9360                }
9361             }
9362          }
9363          return result != style.fixed;
9364       }
9365 #endif
9366    };
9367    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9368
9369    property char * text
9370    {
9371       property_category $"Deprecated"
9372       watchable
9373       set { property::caption = value; }
9374       get { return property::caption; }
9375    }
9376 private:
9377    // Data
9378    //char * yo;
9379    Window prev, next;
9380    WindowBits style;       // Window Style
9381    char * caption;            // Name / Caption
9382    Window parent;    // Parent window
9383    OldList children;          // List of children in Z order
9384    Window activeChild;     // Child window having focus
9385    Window activeClient;
9386    Window previousActive;  // Child active prior to activating the default child
9387    Window master;          // Window owning and receiving notifications concerning this window
9388    OldList slaves;            // List of windows belonging to this window
9389    Display display;        // Display this window is drawn into
9390
9391    Point position;         // Position in parent window client area
9392    Point absPosition;      // Absolute position
9393    Point clientStart;      // Client area position from (0,0) in this window
9394    Size size;              // Size
9395    Size clientSize;        // Client area size
9396    Size scrollArea;        // Virtual Scroll area size
9397    Size reqScrollArea;     // Requested virtual area size
9398    Point scroll;           // Virtual area scrolling position
9399    ScrollBar sbh, sbv;        // Scrollbar window handles
9400    Cursor cursor;        // Mouse cursor used for this window
9401    WindowState state;
9402    PopupMenu menuBar;
9403    StatusBar statusBar;
9404    Button sysButtons[3];
9405    char * fileName;
9406    Box clientArea;         // Client Area box clipped to parent
9407    Key setHotKey;
9408    HotKeySlot hotKey;        // HotKey for this window
9409    int numDocuments;
9410    int numPositions;
9411    Menu menu;
9412    ScrollFlags scrollFlags;// Window Scrollbar Flags
9413    int64 id;                 // Control ID
9414    int documentID;
9415    ColorAlpha background;  // Background color used to draw the window area
9416    Color foreground;
9417    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9418    OldList childrenCycle;     // Cycling order
9419    OldLink cycle;             // Element of parent's cycling order
9420    OldList childrenOrder;     // Circular Z-Order
9421    OldLink order;             // Element of parent's circular Z-Order
9422    Window modalSlave;      // Slave window blocking this window's interaction
9423
9424    Window rootWindow;      // Topmost system managed window
9425    void * windowHandle;    // System window handle
9426
9427    DialogResult returnCode;// Return code for modal windows
9428   
9429    Point sbStep;           // Scrollbar line scrolling steps
9430
9431    Anchor stateAnchor;
9432    SizeAnchor stateSizeAnchor;
9433
9434    Anchor normalAnchor;
9435    SizeAnchor normalSizeAnchor;
9436
9437    Size skinMinSize;       // Minimal window size based on style
9438    Point scrolledPos;      // Scrolled position
9439    Box box;                // Window box clipped to parent
9440    Box * against;          // What to clip the box to
9441
9442    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9443    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9444    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9445    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9446    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9447    Point scrolledArea;     // Distance to scroll area by
9448    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9449
9450    OldList hotKeys;           // List of the hotkeys of all children
9451    Window defaultControl;  // Default child control
9452    Size minSize;
9453    Size maxSize;
9454
9455    ColorAlpha * palette;   // Color palette used for this window
9456
9457    int caretSize;          // Size of caret, non zero if a caret is present
9458    Point caretPos;         // Caret position
9459
9460    void * systemParent;    // Parent System Window for embedded windows
9461
9462    int iconID;
9463    int numIcons;
9464    int positionID;
9465
9466    Mutex mutex;
9467    WindowState lastState;
9468
9469    FileMonitor fileMonitor
9470    {
9471       this, FileChange { modified = true };
9472
9473       bool OnFileNotify(FileChange action, char * param)
9474       {
9475          incref this;
9476          fileMonitor.StopMonitoring();
9477          if(OnFileModified(action, param))
9478             fileMonitor.StartMonitoring();
9479          delete this;
9480          return true;
9481       }
9482    };
9483    FontResource setFont, systemFont;
9484    FontResource usedFont;
9485    FontResource captionFont;
9486    OldList resources;
9487    FileDialog saveDialog;
9488    Anchor anchor;
9489    SizeAnchor sizeAnchor;
9490
9491    // FormDesigner data
9492    ObjectInfo object;
9493    Window control;
9494    Extent * tempExtents; //[4];
9495    BitmapResource icon;
9496    void * windowData;
9497    CreationActivationOption creationActivation;
9498    struct
9499    {
9500       bool active:1;            // true if window and ancestors are active
9501       bool acquiredInput:1;     // true if the window is processing state based input
9502       bool modifiedDocument:1;
9503       bool disabled:1;          // true if window cannot interact
9504       bool isForegroundWindow:1;// true while a root window is being activated
9505       bool visible:1;           // Visibility flag
9506       bool destroyed:1;         // true if window is being destroyed
9507       bool anchored:1;          // true if this window is repositioned when the parent resizes
9508       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9509       bool mouseInside:1;
9510       bool positioned:1;
9511       bool created:1;
9512       bool is3D:1;
9513       bool mergeMenus:1;
9514       bool modifyVirtArea:1;
9515       bool noAutoScrollArea:1;
9516       bool closing:1;
9517       bool autoCreate:1;
9518       bool setVisible:1;      // FOR FORM DESIGNER
9519       bool wasCreated:1;
9520       bool fullRender:1;
9521       bool moveable:1;
9522       bool alphaBlend:1;
9523       bool composing:1;
9524       bool useSharedMemory:1;
9525       bool resized:1;
9526       bool saving:1;
9527       bool nativeDecorations:1;
9528       bool manageDisplay:1;
9529       bool formDesigner:1; // True if we this is running in the form editor
9530    }; 
9531
9532    // Checks used internally for them not to take effect in FormDesigner
9533    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
9534    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
9535
9536    WindowController controller;
9537    public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
9538 };
9539
9540 public class CommonControl : Window
9541 {
9542    // creationActivation = doNothing;
9543
9544    ToolTip toolTip;
9545    public property String toolTip
9546    {
9547       property_category $"Appearance"
9548       set
9549       {
9550          if(created) CommonControl::OnDestroy();
9551          delete toolTip;
9552          toolTip = value ? ToolTip { tip = value; } : null;
9553          incref toolTip;
9554          if(created) CommonControl::OnCreate();
9555       }
9556       get { return toolTip ? toolTip.tip : null; }
9557    }
9558
9559    void OnDestroy()
9560    {
9561       if(toolTip)
9562          // (Very) Ugly work around for the fact that the parent watcher
9563          // won't fire when it's already been disconnected...
9564          eInstance_FireSelfWatchers(toolTip,
9565             __ecereProp___ecereNameSpace__ecere__gui__Window_parent);
9566    }
9567
9568    bool OnCreate()
9569    {
9570       if(toolTip)
9571          toolTip.parent = this;
9572       return true;
9573    }
9574    ~CommonControl()
9575    {
9576       delete toolTip;
9577    }
9578 };
9579
9580 public class Percentage : float
9581 {
9582    char * OnGetString(char * string, float * fieldData, bool * needClass)
9583    {
9584       int c;
9585       int last = 0;
9586       sprintf(string, "%.2f", this);
9587       c = strlen(string)-1;
9588       for( ; c >= 0; c--)
9589       {
9590          if(string[c] != '0') 
9591             last = Max(last, c);
9592          if(string[c] == '.')
9593          {
9594             if(last == c)
9595                string[c] = 0;
9596             else
9597                string[last+1] = 0;
9598             break;
9599          }
9600       }
9601       return string;
9602    }
9603 };
9604
9605 public void ApplySkin(Class c, char * name, void ** vTbl)
9606 {
9607    char className[1024];
9608    Class sc;
9609    OldLink d;
9610    int m;
9611
9612    subclass(Window) wc = (subclass(Window))c;
9613    subclass(Window) base = (subclass(Window))c.base;
9614
9615    sprintf(className, "%sSkin_%s", name, c.name);
9616    wc.pureVTbl = c._vTbl;
9617    c._vTbl = new void *[c.vTblSize];
9618    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
9619    sc = eSystem_FindClass(c.module.application, className);
9620    
9621    if(vTbl)
9622    {
9623       for(m = 0; m < c.base.vTblSize; m++)
9624       {
9625          if(c._vTbl[m] == base.pureVTbl[m])
9626             c._vTbl[m] = vTbl[m];
9627       }
9628    }
9629    if(sc)
9630    {
9631       for(m = 0; m < c.vTblSize; m++)
9632       {
9633          if(sc._vTbl[m] != wc.pureVTbl[m])
9634             c._vTbl[m] = sc._vTbl[m];
9635       }
9636    }
9637       
9638    for(d = c.derivatives.first; d; d = d.next)
9639    {
9640       ApplySkin(d.data, name, c._vTbl);
9641    }
9642 }
9643
9644 public void UnapplySkin(Class c)
9645 {
9646    char className[1024];
9647    Class sc;
9648    subclass(Window) wc = (subclass(Window))c;
9649    subclass(Window) base = (subclass(Window))c.base;
9650    OldLink d;
9651
9652    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
9653    {
9654       delete c._vTbl;
9655       c._vTbl = wc.pureVTbl;
9656       wc.pureVTbl = null;
9657    }
9658
9659    for(d = c.derivatives.first; d; d = d.next)
9660    {
9661       UnapplySkin(d.data);
9662    }
9663 }
9664 /*
9665 void CheckFontIntegrity(Window window)
9666 {
9667    Window c;
9668    if(window)
9669    {
9670       if(window.usedFont && window.usedFont.font == 0xecececec)
9671       {
9672          FontResource uf = window.usedFont;
9673          char * className = window._class.name;
9674          char * text = window.text;
9675          Print("");
9676       }
9677       for(c = window.firstChild; c; c = c.next)
9678          CheckFontIntegrity(c);
9679    }
9680 }*/
9681
9682 public class ControllableWindow : Window
9683 {
9684    /*WindowController controller;
9685    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
9686    ~ControllableWindow() { delete controller; }*/
9687 }
9688
9689 class WindowControllerInterface : ControllableWindow
9690 {
9691    bool OnKeyDown(Key key, unichar ch)
9692    {
9693       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyDown)((Window)controller.controlled, controller, key, ch);
9694       if(result)
9695          result = ((bool (*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown])(controller.window, key, ch);
9696       return result;
9697    }
9698
9699    bool OnKeyUp(Key key, unichar ch)
9700    {
9701       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyUp)((Window)controller.controlled, controller, key, ch);
9702       if(result)
9703          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp])(controller.window, key, ch);
9704       return result;
9705    }
9706
9707    bool OnKeyHit(Key key, unichar ch)
9708    {
9709       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyHit)((Window)controller.controlled, controller, key, ch);
9710       if(result)
9711          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit])(controller.window, key, ch);
9712       return result;
9713    }
9714
9715    bool OnMouseMove(int x, int y, Modifiers mods)
9716    {
9717       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMouseMove)((Window)controller.controlled, controller, x, y, mods);
9718       if(result)
9719          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove])(controller.window, x, y, mods);
9720       return result;
9721    }
9722
9723    bool OnLeftButtonDown(int x, int y, Modifiers mods)
9724    {
9725       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonDown)((Window)controller.controlled, controller, x, y, mods);
9726       if(result)
9727          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown])(controller.window, x, y, mods);
9728       return result;
9729    }
9730
9731    bool OnLeftButtonUp(int x, int y, Modifiers mods)
9732    {
9733       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonUp)((Window)controller.controlled, controller, x, y, mods);
9734       if(result)
9735          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp])(controller.window, x, y, mods);
9736       return result;
9737    }
9738
9739    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
9740    {
9741       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9742       if(result)
9743          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick])(controller.window, x, y, mods);
9744       return result;
9745    }
9746
9747    bool OnRightButtonDown(int x, int y, Modifiers mods)
9748    {
9749       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonDown)((Window)controller.controlled, controller, x, y, mods);
9750       if(result)
9751          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown])(controller.window, x, y, mods);
9752       return result;
9753    }
9754
9755    bool OnRightButtonUp(int x, int y, Modifiers mods)
9756    {
9757       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonUp)((Window)controller.controlled, controller, x, y, mods);
9758       if(result)
9759          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp])(controller.window, x, y, mods);
9760       return result;
9761    }
9762
9763    bool OnRightDoubleClick(int x, int y, Modifiers mods)
9764    {
9765       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9766       if(result)
9767          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick])(controller.window, x, y, mods);
9768       return result;
9769    }
9770
9771    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
9772    {
9773       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonDown)((Window)controller.controlled, controller, x, y, mods);
9774       if(result)
9775          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown])(controller.window, x, y, mods);
9776       return result;
9777    }
9778
9779    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
9780    {
9781       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonUp)((Window)controller.controlled, controller, x, y, mods);
9782       if(result)
9783          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp])(controller.window, x, y, mods);
9784       return result;
9785    }
9786
9787    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
9788    {
9789       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9790       if(result)
9791          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick])(controller.window, x, y, mods);
9792       return result;
9793    }
9794
9795    void OnResize(int width, int height)
9796    {
9797       ((void(*)(Window, WindowController, int, int))(void *)controller.OnResize)((Window)controller.controlled, controller, width, height);
9798       ((void(*)(Window, int, int))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize])(controller.window, width, height);
9799    }
9800
9801    void OnRedraw(Surface surface)
9802    {
9803       ((void(*)(Window, WindowController, Surface))(void *)controller.OnRedraw)((Window)controller.controlled, controller, surface);
9804       ((void(*)(Window, Surface))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw])(controller.window, surface);
9805    }
9806
9807    bool OnCreate()
9808    {
9809       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnCreate)((Window)controller.controlled, controller);
9810       if(result)
9811          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate])(controller.window);
9812       return result;
9813    }
9814
9815    bool OnLoadGraphics()
9816    {
9817       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnLoadGraphics)((Window)controller.controlled, controller);
9818       if(result)
9819          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics])(controller.window);
9820       return result;
9821    }
9822
9823    void OnUnloadGraphics()
9824    {
9825       ((void(*)(Window, WindowController))(void *)controller.OnUnloadGraphics)((Window)controller.controlled, controller);
9826       ((void(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics])(controller.window);
9827    }
9828 }
9829
9830 public class WindowController<class V>
9831 {
9832 public:
9833    property Window window
9834    {
9835       set
9836       {
9837          uint size = class(Window).vTblSize;
9838          if(value)
9839          {
9840             windowVTbl = new void *[size];
9841             memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
9842             if(value._vTbl == value._class._vTbl)
9843             {
9844                value._vTbl = new void *[value._class.vTblSize];
9845                memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
9846             }
9847             {
9848                int c;
9849                for(c = 0; c < size; c++)
9850                {
9851                   void * function = class(WindowControllerInterface)._vTbl[c];
9852                   if(function != DefaultFunction)
9853                      value._vTbl[c] = function;
9854                   else
9855                      value._vTbl[c] = windowVTbl[c];
9856                }
9857             }
9858          }
9859          else
9860             memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
9861          window = value;
9862       }
9863       get { return window; }
9864    }
9865    property V controlled
9866    {
9867       set { controlled = value; }
9868       get { return controlled; }
9869    }
9870    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
9871    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
9872    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
9873    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
9874    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
9875    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
9876    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9877    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
9878    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
9879    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9880    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
9881    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
9882    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9883    virtual void V::OnResize(WindowController controller, int width, int height);
9884    virtual void V::OnRedraw(WindowController controller, Surface surface);
9885    virtual bool V::OnCreate(WindowController controller);
9886    virtual bool V::OnLoadGraphics(WindowController controller);
9887    virtual void V::OnUnloadGraphics(WindowController controller);
9888
9889 private:
9890    int (** windowVTbl)();   
9891    V controlled;
9892    Window window;
9893
9894    ~WindowController()
9895    {
9896       delete windowVTbl;
9897    }
9898 }