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