ecere/Window: Change to how children cycles are added
[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    private void _SetCaption(char * format, va_list args)
6960    {
6961       if(this)
6962       {
6963          delete caption;
6964          if(format)
6965          {
6966             char caption[MAX_F_STRING];
6967             vsnprintf(caption, sizeof(caption), format, args);
6968             caption[sizeof(caption)-1] = 0;
6969
6970             this.caption = CopyString(caption);
6971          }
6972          if(created)
6973             UpdateCaption();
6974
6975          firewatchers caption;
6976       }
6977    }
6978
6979    /*deprecated*/ void SetText(char * format, ...)
6980    {
6981       va_list args;
6982       va_start(args, format);
6983       _SetCaption(format, args);
6984       va_end(args);
6985    }
6986
6987    void SetCaption(char * format, ...)
6988    {
6989       va_list args;
6990       va_start(args, format);
6991       _SetCaption(format, args);
6992       va_end(args);
6993    }
6994
6995    bool Grab(Bitmap bitmap, Box box, bool decorations)
6996    {
6997       bool result = false;
6998       if(display || this == guiApp.desktop)
6999       {
7000          Box clip = {MININT, MININT, MAXINT, MAXINT};
7001
7002          if(box != null)
7003             clip = box;
7004
7005          if(!decorations)
7006             clip.Clip(clientArea);
7007          else
7008             clip.Clip(this.box);
7009
7010          if(rootWindow != this)
7011          {
7012             clip.left   += absPosition.y;
7013             clip.top    += absPosition.y;
7014             clip.right  += absPosition.x;
7015             clip.bottom += absPosition.y;
7016          }
7017
7018          clip.left += decorations ? 0 : clientStart.x;
7019          clip.top += decorations ? 0 : clientStart.y;
7020          clip.right += decorations ? 0 : clientStart.x;
7021          clip.bottom += decorations ? 0 : clientStart.y;
7022
7023          if(display && display.flags.flipping)
7024          {
7025             rootWindow.Update(null);
7026             rootWindow.UpdateDisplay();
7027          }
7028
7029          if(!display)
7030          {
7031             Window window { };
7032             window.Create();
7033             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top, 
7034                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7035             delete window;
7036          }
7037          else
7038             result = display.Grab(bitmap, clip.left, clip.top, 
7039                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7040
7041          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
7042          {
7043             if(!bitmap.Convert(null, pixelFormat888, null))
7044                result = false;
7045          }
7046       }
7047       return result;
7048    }
7049
7050    void GetMousePosition(int * x, int * y)
7051    {
7052       int mouseX = 0, mouseY = 0;
7053       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
7054       {
7055          if(guiApp.driver)
7056             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
7057          if(this != guiApp.desktop)
7058          {
7059             mouseX -= absPosition.x + clientStart.x;
7060             mouseY -= absPosition.y + clientStart.y;
7061          }
7062       }
7063       if(x) *x = mouseX;
7064       if(y) *y = mouseY;
7065    }
7066
7067    DialogResult DoModal()
7068    {
7069       DialogResult returnCode = 0;
7070       int terminated = terminateX;
7071       isModal = true;
7072       incref this;
7073       while(!destroyed && guiApp.driver != null)
7074       {
7075          if(terminateX != terminated)
7076          {
7077             terminated = terminateX;
7078             guiApp.desktop.Destroy(0);
7079             if(guiApp.desktop.created)
7080             {
7081                terminated = 0;
7082                //printf("Resetting terminate X to 0\n");
7083                terminateX = 0;
7084             }
7085             break;
7086          }
7087
7088          guiApp.UpdateDisplay();
7089          if(!guiApp.ProcessInput(false))
7090             guiApp.Wait();
7091       }
7092       returnCode = this.returnCode;
7093       delete this;
7094       return returnCode;
7095    }
7096
7097    void DoModalStart()
7098    {
7099       isModal = true;
7100       incref this;
7101    }
7102
7103    bool DoModalLoop()
7104    {
7105       return !destroyed && guiApp.driver != null && terminateX < 2;
7106    }
7107
7108    DialogResult DoModalEnd()
7109    {
7110       DialogResult returnCode = this.returnCode;
7111       delete this;
7112       return returnCode;
7113    }
7114
7115    // --- Window manipulation ---
7116    /*bool GetDisabled()
7117    {
7118       bool disabled = this.disabled;
7119       Window window;
7120       for(window = this; (window = window.master); )
7121       {
7122          if(window.disabled)
7123          {
7124             disabled = true;
7125             break;
7126          }
7127       }
7128       return disabled;
7129    }*/
7130
7131    // --- Mouse Manipulation ---
7132    void GetNCMousePosition(int * x, int * y)
7133    {
7134       GetMousePosition(x, y);
7135       if(x) *x += clientStart.x;
7136       if(y) *y += clientStart.y;
7137    }
7138
7139    // --- Carets manipulation ---
7140    void GetCaretPosition(Point caretPos)
7141    {
7142       caretPos = this.caretPos;
7143    }
7144
7145    int GetCaretSize(void)
7146    {
7147       return caretSize;
7148    }
7149
7150    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
7151    {
7152       Destroy(button.id);
7153       return true;
7154    }
7155
7156    bool CloseConfirmation(bool parentClosing)
7157    {
7158       bool result = true;
7159       OldLink slave;
7160       Window child;
7161
7162       if(closing)
7163          return false;
7164       if(terminateX > 1)
7165          return true;
7166          
7167       closing = true;
7168
7169       if(!OnClose(parentClosing))
7170          result = false;
7171
7172       // If you want to skip this, simply set modifiedDocument to false in OnClose
7173       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7174       {
7175          DialogResult dialogRes;
7176          char message[1024];
7177          if(fileName)
7178             sprintf(message, $"Save changes to %s?", fileName);
7179          else
7180             sprintf(message, $"Save changes to Untitled %d?", documentID);
7181
7182          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption ? parent.caption : rootWindow.caption, contents = message }.Modal();
7183
7184          if(dialogRes == yes)
7185          {
7186             // TOFIX: Precomp error if brackets are taken out
7187             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7188          }
7189          else if(dialogRes == cancel)
7190             result = false;
7191       }
7192
7193       if(result)
7194       {
7195          for(slave = slaves.first; slave; slave = slave.next)
7196          {
7197             Window w = slave.data;
7198             if((w.parent == this || !w.IsDescendantOf(this)) && !w.CloseConfirmation(true))
7199             {
7200                // ((Window)slave.data).CloseConfirmation(true);
7201                result = false;
7202                break;
7203             }
7204          }
7205       }
7206
7207       if(result)
7208       {
7209          for(child = children.first; child; child = child.next)
7210             if(child.master != this && !child.CloseConfirmation(true))
7211             {
7212                result = false;
7213                break;
7214             }
7215       }
7216       closing = false;
7217       return result;
7218    }
7219
7220    // Static methods... move them somewhere else?
7221    void ::RestoreCaret()
7222    {
7223       if(guiApp.caretOwner)
7224          guiApp.caretOwner.UpdateCaret(false, false);
7225    }
7226
7227    void ::FreeMouseRange()
7228    {
7229       guiApp.interfaceDriver.SetMouseRange(null, null);
7230    }
7231
7232    // Menu Methods
7233    bool MenuFileClose(MenuItem selection, Modifiers mods)
7234    {
7235       Window document = activeChild;
7236       if(document)
7237          document.Destroy(0);
7238       return true;
7239    }
7240
7241    bool MenuFileExit(MenuItem selection, Modifiers mods)
7242    {
7243       Destroy(0);
7244       return true;
7245    }
7246
7247    bool MenuFileSave(MenuItem selection, Modifiers mods)
7248    {
7249       if(fileName)
7250       {
7251          fileMonitor.fileName = null;
7252          saving = true;
7253
7254          if(OnSaveFile(fileName))
7255          {
7256             //if(OnFileModified != Window::OnFileModified)
7257             {
7258                saving = false;
7259                fileMonitor.fileName = fileName;
7260             }
7261             return true;
7262          }
7263          else
7264          {
7265             MessageBox dialog { master = master, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7266             DialogResult answer = dialog.Modal();
7267             saving = false;
7268             if(answer != yes) return (bool)answer;
7269          }
7270       }
7271       return MenuFileSaveAs(selection, mods);
7272    }
7273
7274    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7275    {
7276       DialogResult result = (DialogResult)bool::true;
7277       FileDialog fileDialog = saveDialog;
7278
7279       if(!fileDialog)
7280          fileDialog = FileDialog {};
7281       if(fileDialog)
7282       {
7283          incref fileDialog;
7284          if(fileName)
7285             fileDialog.filePath = fileName;
7286          else
7287          {
7288             char filePath[MAX_FILENAME];
7289             sprintf(filePath, "Untitled %d", documentID);
7290             fileDialog.filePath = filePath;
7291          }
7292          fileMonitor.fileName = null;
7293
7294          fileDialog.type = save;
7295          fileDialog.text = $"Save As";
7296
7297          while(true)
7298          {
7299             fileDialog.master = master.parent ? master : this;
7300             if(fileDialog.Modal() == ok)
7301             {
7302                char * filePath = fileDialog.filePath;
7303                saving = true;
7304                if(OnSaveFile(filePath))
7305                {
7306                   saving = false;
7307                   property::fileName = filePath;
7308                   NotifySaved(master, this, filePath);
7309                   break;
7310                }
7311                else
7312                {
7313                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7314                   DialogResult answer = dialog.Modal();
7315                   saving = false;
7316                   if(answer != yes) 
7317                   {
7318                      result = answer;
7319                      break;
7320                   }
7321                }
7322             }
7323             else
7324             {
7325                result = cancel;
7326                break;
7327             }
7328          }
7329          //if(OnFileModified != Window::OnFileModified && fileName)
7330          {
7331             if(fileName)
7332                fileMonitor.fileName = fileName;
7333          }
7334          delete fileDialog;
7335       }
7336       return (bool)result; // Actually returning result from Yes/NoCancel message box
7337    }
7338
7339    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7340    {
7341       Window document = activeChild;
7342       Window next;
7343       for(document = children.first; document; document = next)
7344       {
7345          next = document.next;
7346          if(document.style.isDocument || document.fileName)
7347             document.MenuFileSave(selection, mods);
7348       }
7349       return true;
7350    }
7351
7352    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7353    {
7354       Window document;
7355
7356       for(document = children.first; document; document = document.next)
7357          //if(document.style.isDocument && document.state == minimized)
7358          if(document.style.isActiveClient && document.state == minimized)
7359             document.SetState(minimized, false, mods);
7360       return true;
7361    }
7362
7363    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7364    {
7365       Window document = activeChild;
7366       if(document)
7367       {
7368          Window firstDocument = null;
7369          Window child;
7370          OldLink cycle = document.cycle.prev;
7371          int id = 0;
7372          while(true)
7373          {
7374             child = cycle.data;
7375             if(child.style.isActiveClient && !child.style.hidden)
7376             {
7377                Window last;
7378
7379                firstDocument = child;
7380                if(child.state == minimized)
7381                   child.SetState(minimized, false, mods);
7382                else
7383                {
7384                   child.positionID = id++;
7385                   child.SetState(normal, false, mods);
7386                   child.anchor.left.type = cascade;
7387                   {
7388                      int x, y, w, h;
7389                      child.normalSizeAnchor = *&child.sizeAnchor;
7390                      child.normalAnchor = child.anchor;
7391
7392                      // Break the anchors for moveable/resizable windows
7393                      if(child.style.fixed)
7394                      {
7395                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7396
7397                         (*&child.normalAnchor).left = x;
7398                         (*&child.normalAnchor).top = y;
7399                         (*&child.normalAnchor).right.type = none;
7400                         (*&child.normalAnchor).bottom.type = none;
7401
7402                         child.normalSizeAnchor.isClientW = false;
7403                         child.normalSizeAnchor.isClientH = false;
7404                         child.normalSizeAnchor.size.w = w;
7405                         child.normalSizeAnchor.size.h = h;
7406                         child.anchored = false;
7407                      }
7408
7409                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7410                      {
7411                         child.stateAnchor = child.normalAnchor;
7412                         child.stateSizeAnchor = child.normalSizeAnchor;
7413
7414                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7415                         child.Position(x, y, w, h, true, true, true, true, false, false);
7416                      }
7417                   }
7418                }
7419
7420                last = children.last;
7421                if(!child.style.stayOnTop)
7422                   for(; last && last.style.stayOnTop; last = last.prev);
7423                children.Move(child, last);
7424                childrenOrder.Move(child.order, childrenOrder.last);
7425             }
7426             if(cycle == document.cycle) break;
7427             cycle = cycle.prev;
7428          }
7429          if(firstDocument)
7430             firstDocument.Activate();
7431       }
7432       return true;
7433    }
7434
7435    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7436    {
7437       if(style.hasClose)
7438          Destroy(0);
7439       return true;
7440    }
7441
7442    // Close all closes all active clients, not all documents
7443    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7444    {
7445       Window next, document;
7446
7447       for(document = children.first; document; document = next)
7448       {
7449          for(next = document.next; next && !(next.style.isActiveClient; next = next.next);
7450          if(document.style.isActiveClient)
7451             if(!document.Destroy(0) && !document.style.hidden)
7452                return false;
7453       }
7454       return true;
7455    }
7456
7457    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7458    {
7459       if(style.hasMaximize && state != maximized)
7460          SetState(maximized, 0, 0);
7461       return true;
7462    }
7463
7464    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7465    {
7466       if(style.hasMinimize && state != minimized)
7467       {
7468          SetState(minimized, 0, 0);
7469          parent.CycleChildren(false, true, false, true);
7470       }
7471       return true;
7472    }
7473
7474    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7475    {
7476       MenuMoveOrSize(false, selection ? true : false);
7477       return true;
7478    }
7479
7480    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7481    {
7482       CycleChildren(false, true, false, true);
7483       return true;
7484    }
7485
7486    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7487    {
7488       CycleChildren(true, true, false, true);
7489       return true;
7490    }
7491
7492    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7493    {
7494       MenuMoveOrSize(true, true);
7495       return true;
7496    }
7497
7498    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7499    {
7500       if(state != normal)
7501          SetState(normal, 0, 0);
7502       return true;
7503    }
7504
7505    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7506    {
7507       Window document;
7508       int64 id = selection.id;
7509       OldLink cycle = activeClient.cycle;
7510       int c = 0;
7511       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7512       while(true)
7513       {
7514          Window sibling = cycle.data;
7515          if(sibling.style.isActiveClient && sibling.visible && !sibling.style.nonClient)
7516          {
7517             if(c == id)
7518                break;
7519             c++;
7520          }
7521          cycle = cycle.next;
7522       }
7523       document = cycle.data;
7524       document.Activate();
7525       
7526       //if(activeChild.state == maximized)
7527       //  document.SetState(maximized, false, mods);
7528       //else if(document.state == minimized)
7529       //   document.SetState(normal, false, mods);
7530       return true;
7531    }
7532
7533    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7534    {
7535       stayOnTop = !style.stayOnTop;
7536       return true;
7537    }
7538
7539    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7540    {
7541       Window document = activeChild;
7542       if(document)
7543       {
7544          Window firstDocument = null;
7545          OldLink cycle = document.cycle;
7546          int id = 0;
7547          while(true)
7548          {
7549             Window child = cycle.data;
7550             if(child.style.isActiveClient && !child.style.hidden)
7551             {
7552                if(!firstDocument) firstDocument = child;
7553                if(child.state == minimized)
7554                   child.SetState(minimized, false, mods);
7555                else
7556                {
7557                   child.positionID = id++;
7558                   child.SetState(normal, false, mods);
7559                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7560
7561                   child.anchor.left.type = hTiled;
7562                   {
7563                      int x, y, w, h;
7564                      child.normalSizeAnchor = *&child.sizeAnchor;
7565                      child.normalAnchor = child.anchor;
7566
7567                      // Break the anchors for moveable/resizable windows
7568                      if(child.style.fixed)
7569                      {
7570                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7571
7572                         (*&child.normalAnchor).left = x;
7573                         (*&child.normalAnchor).top = y;
7574                         (*&child.normalAnchor).right.type = none;
7575                         (*&child.normalAnchor).bottom.type = none;
7576                         child.normalSizeAnchor.isClientW = false;
7577                         child.normalSizeAnchor.isClientH = false;
7578                         child.normalSizeAnchor.size.w = w;
7579                         child.normalSizeAnchor.size.h = h;
7580                         child.anchored = false;
7581                      }
7582
7583                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7584                      {
7585                         child.stateAnchor = child.normalAnchor;
7586                         child.stateSizeAnchor = child.normalSizeAnchor;
7587
7588                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7589                         child.Position(x,y, w, h, true, true, true, true, false, true);
7590                      }
7591                   }
7592                }
7593             }
7594             if((cycle = cycle.next) == document.cycle) break;
7595          }
7596          if(firstDocument)
7597             firstDocument.Activate();
7598       }
7599       return true;
7600    }
7601
7602    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
7603    {
7604       Window document = activeChild;
7605       if(document)
7606       {
7607          Window firstDocument = null;
7608          Window child;
7609          OldLink cycle = document.cycle;
7610          int id = 0;
7611          while(true)
7612          {
7613             child = cycle.data;
7614             //if(child.style.isDocument)
7615             if(child.style.isActiveClient && !child.style.hidden)
7616             {
7617                if(!firstDocument) firstDocument = child;
7618                if(child.state == minimized)
7619                   child.SetState(minimized, false, mods);
7620                else
7621                {
7622                   child.positionID = id++;
7623                   child.SetState(normal, false, mods);
7624                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7625
7626                   child.anchor.left.type = vTiled;
7627                   {
7628                      int x, y, w, h;
7629                      child.normalSizeAnchor = *&child.sizeAnchor;
7630                      child.normalAnchor = child.anchor;
7631
7632                      // Break the anchors for moveable/resizable windows
7633                      if(child.style.fixed)
7634                      {
7635                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7636
7637                         (*&child.normalAnchor).left = x;
7638                         (*&child.normalAnchor).top = y;
7639                         (*&child.normalAnchor).right.type = none;
7640                         (*&child.normalAnchor).bottom.type = none;
7641                         child.normalSizeAnchor.isClientW = false;
7642                         child.normalSizeAnchor.isClientH = false;
7643                         child.normalSizeAnchor.size.w = w;
7644                         child.normalSizeAnchor.size.h = h;
7645                         child.anchored = false;
7646                      }
7647
7648                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7649                      {
7650                         child.stateAnchor = child.normalAnchor;
7651                         child.stateSizeAnchor = child.normalSizeAnchor;
7652
7653                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7654                         child.Position(x,y, w, h, true, true, true, true, false, true);
7655                      }
7656                   }
7657                }
7658             }
7659             if((cycle = cycle.next) == document.cycle) break;
7660          }
7661          if(firstDocument)
7662             firstDocument.Activate();
7663       }
7664       return true;
7665    }
7666
7667    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
7668    {
7669       WindowList dialog { master = this };
7670       Window document = (Window)dialog.Modal();
7671       if(document)
7672       {
7673          if(activeChild.state == maximized)
7674             document.SetState(maximized, false, mods);
7675          else if(document.state == minimized)
7676             document.SetState(normal, false, mods);
7677          document.Activate();
7678       }
7679       return true;
7680    }
7681
7682    // Virtual Methods
7683    virtual bool OnCreate(void);
7684    virtual void OnDestroy(void);
7685    virtual void OnDestroyed(void);
7686    virtual bool OnClose(bool parentClosing);
7687    virtual bool OnStateChange(WindowState state, Modifiers mods);
7688    virtual bool OnPostCreate(void);
7689    virtual bool OnMoving(int *x, int *y, int w, int h);
7690    virtual bool OnResizing(int *width, int *height);
7691    virtual void OnResize(int width, int height);
7692    virtual void OnPosition(int x, int y, int width, int height);
7693    virtual bool OnLoadGraphics(void);
7694    virtual void OnApplyGraphics(void);
7695    virtual void OnUnloadGraphics(void);
7696    virtual void OnRedraw(Surface surface);
7697    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
7698    virtual void OnActivateClient(Window client, Window previous);
7699    virtual bool OnKeyDown(Key key, unichar ch);
7700    virtual bool OnKeyUp(Key key, unichar ch);
7701    virtual bool OnKeyHit(Key key, unichar ch);
7702    virtual bool OnSysKeyDown(Key key, unichar ch);
7703    virtual bool OnSysKeyUp(Key key, unichar ch);
7704    virtual bool OnSysKeyHit(Key key, unichar ch);
7705    virtual bool OnMouseOver(int x, int y, Modifiers mods);
7706    virtual bool OnMouseLeave(Modifiers mods);
7707    virtual bool OnMouseMove(int x, int y, Modifiers mods);
7708    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
7709    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
7710    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
7711    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
7712    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
7713    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
7714    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
7715    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
7716    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
7717    virtual void OnMouseCaptureLost(void);
7718    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
7719    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
7720    virtual void OnDrawOverChildren(Surface surface);
7721    virtual bool OnFileModified(FileChange fileChange, char * param);
7722    virtual bool OnSaveFile(char * fileName);
7723
7724    // Virtual Methods -- Children management (To support Stacker, for lack of built-in auto-layout)
7725    // Note: A 'client' would refer to isActiveClient, rather than
7726    // being confined to the 'client area' (nonClient == false)
7727    virtual void OnChildAddedOrRemoved(Window child, bool removed);
7728    virtual void OnChildVisibilityToggled(Window child, bool visible);
7729    virtual void OnChildResized(Window child, int x, int y, int w, int h);
7730
7731    // Skins Virtual Functions
7732    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
7733    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
7734    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
7735    {
7736       *cw = *w;
7737       *ch = *h;      
7738    }
7739    virtual void ShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7740    virtual void PreShowDecorations(Font captionFont, Surface surface, char * name, bool active, bool moving);
7741    virtual bool IsMouseMoving(int x, int y, int w, int h)
7742    {
7743       return false;
7744    }
7745    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY)
7746    {
7747       return false;
7748    }
7749    virtual void UpdateNonClient();
7750    virtual void SetBox(Box box);
7751    virtual bool IsInside(int x, int y)
7752    {
7753       return box.IsPointInside({x, y});
7754    }
7755    virtual bool IsOpaque()
7756    {
7757       return (!style.drawBehind || background.a == 255);
7758    }
7759
7760    // Notifications
7761    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
7762    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
7763    virtual void Window::NotifySaved(Window window, char * filePath);
7764
7765    // Public Methods
7766
7767    // Properties
7768    property Window parent
7769    {
7770       property_category $"Layout"
7771       set
7772       {
7773          if(value || guiApp.desktop)
7774          {
7775             Window last;
7776             Window oldParent = parent;
7777             Anchor anchor = this.anchor;
7778
7779             if(value && value.IsDescendantOf(this)) return;
7780             if(value && value == this)
7781                return;
7782             if(!value) value = guiApp.desktop;
7783
7784             if(value == oldParent) return;
7785
7786             if(!master || (master == this.parent && master == guiApp.desktop))
7787                property::master = value;
7788             
7789             if(parent)
7790             {
7791                parent.children.Remove(this);
7792
7793                parent.Update(
7794                {
7795                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7796                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
7797                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
7798                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
7799                });
7800             }
7801
7802             last = value.children.last;
7803
7804             if(style.isDocument)
7805             {
7806                if(parent)
7807                   parent.numDocuments--;
7808                documentID = value.GetDocumentID();
7809             }
7810
7811             if(style.isActiveClient && !style.hidden)
7812             {
7813                if(parent && parent != guiApp.desktop && !(style.hidden))
7814                {
7815                   if(state == minimized) parent.numIcons--;
7816                   parent.numPositions--;
7817                }
7818             }
7819
7820             if(!style.stayOnTop)
7821                for(; last && last.style.stayOnTop; last = last.prev);
7822
7823             value.children.Insert(last, this);
7824
7825             // *** NEW HERE: ***
7826             if(cycle)
7827                parent.childrenCycle.Delete(cycle);
7828             if(order)
7829                parent.childrenOrder.Delete(order);
7830             cycle = null;
7831             order = null;
7832             // *** TODO: Added this here to solve crash on setting parent to null before destroying/destructing ***
7833             //           Should something else be done?
7834             if(parent && parent.activeChild == this)
7835                parent.activeChild = null;
7836             if(parent && parent.activeClient == this)
7837                parent.activeClient = null;
7838
7839             //if(created)
7840             {
7841                if(created)
7842                {
7843                   int x = position.x, y = position.y, w = size.w, h = size.h;
7844                   
7845                   int vpw, vph;
7846
7847                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
7848                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
7849                   
7850                   vpw = value.clientSize.w;
7851                   vph = value.clientSize.h;
7852                   if(style.nonClient)
7853                   {
7854                      vpw = value.size.w;
7855                      vph = value.size.h;
7856                   }
7857                   else if(style.fixed)
7858                   {
7859                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
7860                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
7861                   }
7862
7863                   anchor = this.anchor;
7864
7865                   if(anchor.left.type == offset)            anchor.left.distance = x;
7866                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
7867                   if(anchor.top.type == offset)             anchor.top.distance = y;
7868                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
7869                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
7870                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
7871                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
7872                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
7873                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
7874                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
7875
7876                   if(!anchor.left.type && !anchor.right.type)
7877                   {
7878                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
7879                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
7880                   }
7881                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
7882                   if(!anchor.top.type && !anchor.bottom.type)
7883                   {
7884                      anchor.vert.distance = (y + h / 2) - (vph / 2);
7885                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
7886                   }
7887                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
7888                }
7889                parent = value;
7890                parent.OnChildAddedOrRemoved(this, false);
7891
7892                // *** NEW HERE ***
7893                if(!style.inactive)
7894                {
7895                   if(!style.noCycle)
7896                      parent.childrenCycle.Insert(
7897                         // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
7898                         //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
7899                         null,
7900                         cycle = OldLink { data = this });
7901                   parent.childrenOrder.Insert(
7902                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last, 
7903                      order = OldLink { data = this });
7904                }
7905
7906                if(!style.hidden && style.isActiveClient)
7907                {
7908                   positionID = parent.GetPositionID(this);
7909                   parent.numPositions++;
7910                   if(state == minimized) parent.numIcons--;
7911                }
7912
7913                // *** FONT INHERITANCE ***
7914                if(!setFont && oldParent) 
7915                   stopwatching(oldParent, font);
7916
7917                if(systemFont)
7918                {
7919                   RemoveResource(systemFont);
7920                   delete systemFont;
7921                }
7922                // TESTING WITH WATCHERS:
7923                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7924                // usedFont = setFont ? setFont : (systemFont);
7925
7926                if(!usedFont)
7927                {
7928                   if(guiApp.currentSkin)
7929                   {
7930                      systemFont = guiApp.currentSkin.SystemFont();
7931                      incref systemFont;
7932                   }
7933                   usedFont = systemFont;
7934                   AddResource(systemFont);
7935                }
7936
7937                if(!setFont)
7938                   watch(value)
7939                   {
7940                      font
7941                      {
7942                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
7943                         firewatchers font;
7944                         Update(null);
7945                      }
7946                   };
7947                
7948                firewatchers font;
7949
7950
7951                if(value.rootWindow && value.rootWindow.display && rootWindow)
7952                {
7953                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) || 
7954                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
7955                   
7956                   if(reloadGraphics)
7957                      UnloadGraphics(false);
7958                   SetupDisplay();
7959                   if(reloadGraphics)
7960                      LoadGraphics(false, false);
7961                      
7962                   /*
7963                   if(value.rootWindow != rootWindow)
7964                      DisplayModeChanged();
7965                   else
7966                   */
7967                }
7968                scrolledPos.x = MININT; // Prevent parent update
7969                {
7970                   bool anchored = this.anchored;
7971                   property::anchor = anchor;
7972                   this.anchored = anchored;
7973                }
7974                /*
7975                {
7976                   int x, y, w, h;
7977                   if(guiApp.currentSkin)
7978                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
7979
7980                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
7981                   Position(x, y, w, h, true, true, true, true, false, true);
7982                }
7983                */
7984
7985             }
7986             // else parent = value;
7987             if(oldParent)
7988                oldParent.OnChildAddedOrRemoved(this, true);
7989          }
7990       }
7991       get { return parent; }
7992    };
7993
7994    property Window master
7995    {
7996       property_category $"Behavior"
7997       set
7998       {
7999          //if(this == value) return;
8000          if(value && value.IsSlaveOf(this)) return;
8001
8002          if(master != value)
8003          {
8004             if(master)
8005             {
8006                OldLink slaveHolder;
8007                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
8008                   if(slaveHolder.data == this)
8009                   {
8010                      master.slaves.Delete(slaveHolder);
8011                      break;
8012                   }
8013             }
8014
8015             if(value)
8016             {
8017                value.slaves.Add(OldLink { data = this });
8018
8019                if(hotKey)
8020                {
8021                   if(master)
8022                      master.hotKeys.Remove(hotKey);
8023                   value.hotKeys.Add(hotKey);
8024                   hotKey = null;
8025                }
8026                if(master && master.defaultControl == this)
8027                   master.defaultControl = null;
8028
8029                if(style.isDefault && !value.defaultControl)
8030                   value.defaultControl = this;
8031             }
8032          }
8033          master = value;
8034       }
8035       get { return master ? master : parent; }
8036    };
8037
8038    property char * caption
8039    {
8040       property_category $"Appearance"
8041       watchable
8042       set
8043       {
8044          delete caption;
8045          if(value)
8046          {
8047             caption = new char[strlen(value)+1];
8048             if(caption)
8049                strcpy(caption, value);
8050          }
8051          if(created)
8052             UpdateCaption();
8053       }
8054       get { return caption; }
8055    };
8056
8057    property Key hotKey
8058    {
8059       property_category $"Behavior"
8060       set
8061       {
8062          setHotKey = value;
8063          if(created)
8064          {
8065             if(value)
8066             {
8067                if(!hotKey)
8068                   master.hotKeys.Add(hotKey = HotKeySlot { });
8069                if(hotKey)
8070                {
8071                   hotKey.key = value;
8072                   hotKey.window = this;
8073                }
8074             }
8075             else if(hotKey)
8076             {
8077                master.hotKeys.Delete(hotKey);
8078                hotKey = null;
8079             }
8080          }
8081       }
8082       get { return hotKey ? hotKey.key : 0; }
8083    };
8084
8085    property Color background
8086    {
8087       property_category $"Appearance"
8088       set
8089       {
8090          background.color = value;
8091          firewatchers;
8092          if(created)
8093          {
8094             Update(null);
8095             if(this == rootWindow)
8096                guiApp.interfaceDriver.SetRootWindowColor(this);
8097          }
8098       }
8099       get { return background.color; }
8100    };
8101
8102    property Percentage opacity
8103    {
8104       property_category $"Appearance"
8105       set
8106       {
8107          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
8108          drawBehind = (background.a == 255) ? false : true;
8109       }
8110       get { return background.a / 255.0f; }
8111    };
8112
8113    property Color foreground
8114    {
8115       property_category $"Appearance"
8116       set
8117       {
8118          foreground = value;
8119          firewatchers;
8120          if(created)
8121             Update(null);
8122       }
8123       get { return foreground; }
8124    };
8125
8126    property BorderStyle borderStyle
8127    {
8128       property_category $"Appearance"
8129       set
8130       {
8131          if(!((BorderBits)value).fixed)
8132          {
8133             style.hasClose = false;
8134             style.hasMaximize = false;
8135             style.hasMinimize = false;
8136             nativeDecorations = false;
8137          }
8138          style.borderBits = value;
8139          if(created)
8140          {
8141             int x, y, w, h;
8142             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8143
8144             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8145             Position(x, y, w, h, true, true, true, true, false, true);
8146             CreateSystemChildren();
8147          }
8148       }
8149       get { return (BorderStyle)style.borderBits; } 
8150    };
8151
8152    property Size minClientSize
8153    {
8154       property_category $"Layout"
8155       set { minSize = value; }
8156       get { value = minSize; }
8157    };
8158
8159    property Size maxClientSize
8160    {
8161       property_category $"Layout"
8162       set { maxSize = value; }
8163       get { value = maxSize; }
8164    };
8165
8166    property bool hasMaximize
8167    {
8168       property_category $"Window Style"
8169       set
8170       {
8171          style.hasMaximize = value;
8172          if(value) { style.fixed = true; style.contour = true; }
8173          if(created)
8174          {
8175             int x, y, w, h;
8176             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8177
8178             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8179             Position(x, y, w, h, true, true, true, true, false, true);
8180
8181             CreateSystemChildren();
8182          }
8183       }
8184       get { return style.hasMaximize; }
8185    };
8186
8187    property bool hasMinimize
8188    {
8189       property_category $"Window Style"
8190       set
8191       {
8192          style.hasMinimize = value;
8193          if(value) { style.fixed = true; style.contour = true; }
8194          if(created)
8195          {
8196             int x, y, w, h;
8197             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8198
8199             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8200             Position(x, y, w, h, true, true, true, true, false, true);
8201
8202             CreateSystemChildren();
8203          }
8204       }
8205       get { return style.hasMinimize;  }
8206    };
8207
8208    property bool hasClose
8209    {
8210       property_category $"Window Style"
8211       set
8212       {
8213          style.hasClose = value;
8214          if(value) { style.fixed = true; style.contour = true; }
8215          if(created)
8216          {
8217             int x, y, w, h;
8218             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8219             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8220             Position(x, y, w, h, true, true, true, true, false, true);
8221             CreateSystemChildren();
8222          }
8223       }
8224       get { return style.hasClose; }
8225    };
8226    
8227    property bool nonClient
8228    {
8229       property_category $"Layout"
8230       set
8231       {
8232          style.nonClient = value;
8233          if(value)
8234             style.stayOnTop = true;
8235       }
8236       get { return style.nonClient; }
8237    };
8238
8239    property bool inactive
8240    {
8241       property_category $"Behavior"
8242       set
8243       {
8244          if(value) 
8245          {
8246             // *** NEW HERE: ***
8247             if(!style.inactive)
8248             {
8249                if(cycle)
8250                   parent.childrenCycle.Delete(cycle);
8251                if(order)
8252                   parent.childrenOrder.Delete(order);
8253                cycle = null;
8254                order = null;
8255             }
8256
8257             if(created)
8258             {
8259                active = false; // true;
8260                if(parent.activeChild == this)
8261                   parent.activeChild = null;
8262                if(parent.activeClient == this)
8263                   parent.activeClient = null;
8264             }
8265          }
8266          else
8267          {
8268             if(style.inactive)
8269             {
8270                if(!style.noCycle)
8271                {
8272                   parent.childrenCycle.Insert(
8273                      // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8274                      //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null, 
8275                      null,
8276                      cycle = OldLink { data = this });
8277                }
8278                parent.childrenOrder.Insert(
8279                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8280                   order = OldLink { data = this });
8281             }
8282          }
8283          style.inactive = value;
8284       }
8285       get { return style.inactive; }
8286    };
8287
8288    property bool clickThrough
8289    {
8290       property_category $"Behavior"
8291       set { style.clickThrough = value; }
8292       get { return style.clickThrough; }
8293    };
8294
8295    property bool isRemote
8296    {
8297       property_category $"Behavior"
8298       set { style.isRemote = value; }
8299       get { return style.isRemote; }
8300    };
8301
8302    property bool noCycle
8303    {
8304       property_category $"Behavior"
8305       set { style.noCycle = value; }
8306       get { return style.noCycle; }
8307    };
8308
8309    property bool isModal
8310    {
8311       property_category $"Behavior"
8312       set { style.modal = value; }
8313       get { return style.modal; }
8314    };
8315
8316    property bool interim
8317    {
8318       property_category $"Behavior"
8319       set { style.interim = value; }
8320       get { return style.interim; }
8321    };
8322
8323    property bool tabCycle
8324    {
8325       property_category $"Behavior"
8326       set { style.tabCycle = value; }
8327       get { return style.tabCycle; }
8328    };
8329      
8330    property bool isDefault
8331    {
8332       property_category $"Behavior"
8333       set
8334       {
8335          if(master)
8336          {
8337             if(value)
8338             {
8339                Window sibling;
8340                /*for(sibling = parent.children.first; sibling; sibling = sibling.next)
8341                   if(sibling != this && sibling.style.isDefault)
8342                      sibling.style.isDefault = false;*/
8343                if(master.defaultControl)
8344                   master.defaultControl.style.isDefault = false;
8345                master.defaultControl = this;
8346             }
8347             else if(master.defaultControl == this)
8348                master.defaultControl = null;
8349
8350             // Update(null);
8351          }
8352          style.isDefault = value;
8353          if(created)
8354             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8355       }
8356       get { return style.isDefault; }
8357    };
8358
8359    property bool drawBehind
8360    {
8361       property_category $"Window Style"
8362       set { style.drawBehind = value; }
8363       get { return style.drawBehind; }
8364    };
8365
8366    property bool hasMenuBar
8367    {
8368       property_category $"Window Style"
8369       set
8370       {
8371          if(value) 
8372          {
8373             if(!menu)
8374             {
8375                menu = Menu { };
8376                incref menu;
8377             }
8378             if(created && !menuBar)
8379             {
8380                menuBar =
8381                   PopupMenu 
8382                   {
8383                      this, menu = menu,
8384                      isMenuBar = true,
8385                      anchor = Anchor { top = 23, left = 1, right = 1 },
8386                      size.h = 24,
8387                      inactive = true, nonClient = true                            
8388                   };
8389                menuBar.Create();
8390             }
8391          }
8392          else if(created && menuBar)
8393          {
8394             menuBar.Destroy(0);
8395             menuBar = null;
8396          }
8397          style.hasMenuBar = value;
8398       }
8399       get { return style.hasMenuBar; }
8400    };
8401
8402    property bool hasStatusBar
8403    {
8404       property_category $"Window Style"
8405       set
8406       {
8407          if(value)
8408          {
8409             if(!statusBar)
8410             {
8411                statusBar = StatusBar { this };
8412                incref statusBar;
8413                if(created)
8414                   statusBar.Create();
8415             }
8416          }
8417          else if(statusBar)
8418             delete statusBar;
8419          style.hasStatusBar = value;
8420       }
8421       get { return style.hasStatusBar; }
8422    };
8423    property bool stayOnTop
8424    {
8425       property_category $"Window Style"
8426       set
8427       {
8428          if(value)
8429          {
8430             if(created && !style.stayOnTop)
8431             {
8432                if(rootWindow == this)
8433                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8434                else if(parent.children.last != this)
8435                {
8436                   parent.children.Move(this, parent.children.last);
8437                   Update(null);
8438                }
8439             }
8440             style.stayOnTop = true;
8441          }
8442          else
8443          {
8444             if(created && style.stayOnTop)
8445             {
8446                if(rootWindow == this)
8447                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8448                else
8449                {
8450                   Window last;
8451                   if(order)
8452                   {
8453                      OldLink order;
8454                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev; 
8455                          order && ((Window)order.data).style.stayOnTop;
8456                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8457                       last = order ? order.data : null;
8458                   }
8459                   else
8460                   {
8461                      for(last = parent.children.last; 
8462                          last && last.style.stayOnTop;
8463                          last = last.prev);
8464                   }
8465
8466                   parent.children.Move(this, last);
8467                   Update(null);
8468                }
8469             }
8470             style.stayOnTop = false;
8471          }
8472       }
8473       get { return style.stayOnTop; }
8474    };
8475
8476    property Menu menu
8477    {
8478       property_category $"Window Style"
8479       set
8480       {
8481          delete menu;
8482          if(value)
8483          {
8484             menu = value;
8485             incref menu;
8486          }
8487
8488          if(menuBar && !value)
8489          {
8490             menuBar.Destroy(0);
8491             menuBar = null;
8492          }
8493          if(created)
8494          {
8495             if(!menuBar && style.hasMenuBar && value)
8496             {
8497                menuBar = PopupMenu
8498                          { 
8499                             this, menu = value, isMenuBar = true, 
8500                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24, 
8501                             inactive = true, nonClient = true
8502                          };
8503                 menuBar.Create();
8504             }
8505             UpdateActiveDocument(null);
8506          }
8507       }
8508       get { return menu; }
8509    };
8510
8511    property FontResource font
8512    {
8513       property_category $"Appearance"
8514       watchable
8515       isset { return setFont ? true : false; }
8516       set
8517       {
8518          if(this)
8519          {
8520             if(value && !setFont) { stopwatching(parent, font); }
8521             else if(!value && setFont)
8522             {
8523                watch(parent)
8524                {
8525                   font
8526                   {
8527                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8528                      firewatchers font;
8529                      Update(null);
8530                   }
8531                };
8532             }
8533
8534             if(setFont)
8535             {
8536                RemoveResource(setFont);
8537                delete setFont;
8538             }
8539             if(systemFont)
8540             {
8541                RemoveResource(systemFont);
8542                delete systemFont;
8543             }
8544             setFont = value;
8545             if(setFont)
8546             {
8547                incref setFont;
8548                AddResource(setFont);
8549             }
8550
8551             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8552             if(!usedFont)
8553             {
8554                systemFont = guiApp.currentSkin.SystemFont();
8555                incref systemFont;
8556                usedFont = systemFont;
8557                AddResource(systemFont);
8558             }
8559
8560             firewatchers;
8561
8562             Update(null);
8563          }
8564       }
8565       get { return usedFont; }
8566    };
8567
8568    property SizeAnchor sizeAnchor
8569    {
8570       property_category $"Layout"
8571       isset
8572       {
8573          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8574                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8575             sizeAnchor.isClientW != sizeAnchor.isClientH;
8576       }
8577       set
8578       {
8579          int x, y, w, h;
8580          sizeAnchor = value;
8581
8582          normalSizeAnchor = sizeAnchor;
8583
8584          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8585          {
8586             stateAnchor = normalAnchor;
8587             stateSizeAnchor = normalSizeAnchor;
8588
8589             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8590             Position(x,y, w, h, true, true, true, true, false, true);
8591          }
8592       }
8593       get
8594       {
8595          value =
8596          {
8597             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
8598             sizeAnchor.isClientW,
8599             sizeAnchor.isClientH
8600          };
8601       }
8602    };
8603
8604    property Size size
8605    {
8606       property_category $"Layout"
8607       isset
8608       {
8609          Anchor thisAnchor = anchor;
8610          SizeAnchor thisSizeAnchor = sizeAnchor;
8611          bool leftRight = (anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none);
8612          bool topBottom = (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none);
8613          bool isClient = !sizeAnchor.isClientW && !sizeAnchor.isClientH;
8614          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8615                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8616             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8617       }
8618       set
8619       {
8620          int x, y, w, h;
8621
8622          sizeAnchor.isClientW = false;
8623          sizeAnchor.isClientH = false;
8624          sizeAnchor.size = value;
8625
8626          normalSizeAnchor = sizeAnchor;
8627
8628          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
8629          {
8630             stateAnchor = normalAnchor;
8631             stateSizeAnchor = normalSizeAnchor;
8632
8633             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8634             Position(x, y, w, h, true, true, true, true, false, true);
8635             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
8636          }
8637       }
8638       get { value = size; }
8639    };
8640
8641    property Size clientSize
8642    {
8643       property_category $"Layout"
8644       isset
8645       {
8646          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) || 
8647                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8648             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
8649       }
8650       set
8651       {
8652          int x, y, w, h;
8653          sizeAnchor.isClientW = true;
8654          sizeAnchor.isClientH = true;
8655          sizeAnchor.size = value;
8656
8657          normalSizeAnchor = sizeAnchor;
8658
8659          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8660          {
8661             stateAnchor = normalAnchor;
8662             stateSizeAnchor = normalSizeAnchor;
8663
8664             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8665             Position(x,y, w, h, true, true, true, true, false, true);
8666          }
8667       }
8668       get { value = clientSize; }
8669    };
8670
8671    property Size initSize { get { value = sizeAnchor.size; } };
8672
8673    property Anchor anchor
8674    {
8675       property_category $"Layout"
8676       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
8677
8678       set
8679       {
8680          if(value != null)
8681          {
8682             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
8683             {
8684                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
8685                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
8686             }
8687             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
8688             {
8689                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
8690                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
8691             }
8692             anchor = value;
8693
8694             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type)) 
8695             {
8696                anchor.left.distance = 0;
8697                anchor.horz.type = 0;
8698             }
8699             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
8700             {
8701                anchor.top.distance = 0;
8702                anchor.vert.type = 0;
8703             }
8704
8705             anchored = true;
8706
8707             //if(created)
8708             {
8709                int x, y, w, h;
8710
8711                normalAnchor = anchor;
8712                
8713                // Break the anchors for moveable/resizable windows
8714                /*if(style.fixed ) //&& value.left.type == cascade)
8715                {
8716                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
8717
8718                   this.anchor = normalAnchor = Anchor { left = x, top = y };
8719                   normalSizeAnchor = SizeAnchor { { w, h } };
8720                   anchored = false;
8721                }*/
8722                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8723                {
8724                   stateAnchor = normalAnchor;
8725                   stateSizeAnchor = normalSizeAnchor;
8726
8727                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8728                   Position(x, y, w, h, true, true, true, true, false, true);
8729                }
8730             }
8731          }
8732          else
8733          {
8734             anchored = false;
8735          }
8736       }
8737       get { value = this ? anchor : Anchor { }; }
8738    };
8739
8740    property Point position
8741    {
8742       property_category $"Layout"
8743       set
8744       {
8745          if(value == null) return;
8746
8747          anchor.left = value.x;
8748          anchor.top  = value.y;
8749          anchor.right.type = none;
8750          anchor.bottom.type = none;
8751          //if(created)
8752          {
8753             int x, y, w, h;
8754
8755             normalAnchor = anchor;
8756
8757             // Break the anchors for moveable/resizable windows
8758             /*
8759             if(style.fixed)
8760             {
8761                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8762
8763                normalAnchor.left = x;
8764                normalAnchor.top = y;
8765                normalAnchor.right.type = none;
8766                normalAnchor.bottom.type = none;
8767                normalSizeAnchor.size.width = w;
8768                normalSizeAnchor.size.height = h;
8769                anchored = false;
8770             }
8771             */
8772             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8773             {
8774                stateAnchor = normalAnchor;
8775                stateSizeAnchor = normalSizeAnchor;
8776
8777                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8778                Position(x,y, w, h, true, true, true, true, false, true);
8779             }
8780          }
8781       }
8782       get { value = position; }
8783    };
8784
8785    property bool disabled
8786    {
8787       property_category $"Behavior"
8788       set
8789       {
8790          if(this && disabled != value)
8791          {
8792             disabled = value;
8793             if(created)
8794                Update(null);
8795          }
8796       }
8797       get { return (bool)disabled; }
8798    };
8799
8800    property bool isEnabled
8801    {
8802       get
8803       {
8804          Window parent;
8805          for(parent = this; parent; parent = parent.parent)
8806             if(parent.disabled)
8807                return false;
8808          return true;
8809       }
8810    };
8811
8812    property WindowState state
8813    {
8814       property_category $"Behavior"
8815       set { SetState(value, false, 0); }
8816       get { return this ? state : 0; }
8817    };
8818
8819    property bool visible
8820    {
8821       property_category $"Behavior"
8822       set
8823       {
8824          if(this && !value && !style.hidden && parent)
8825          {
8826             bool wasActiveChild = parent.activeChild == this;
8827             Window client = null;
8828
8829             style.hidden = true;
8830             if(style.isActiveClient)
8831             {
8832                parent.numPositions--;
8833                if(state == minimized) parent.numIcons--;
8834             }
8835
8836             if(created)
8837             {
8838                OldLink prevOrder = null;
8839
8840                if(rootWindow == this)
8841                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
8842                else
8843                {
8844                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
8845                   if(style.nonClient)
8846                   {
8847                      box.left   -= parent.clientStart.x;
8848                      box.top    -= parent.clientStart.y;
8849                      box.right  -= parent.clientStart.x;
8850                      box.bottom -= parent.clientStart.y;
8851                   }
8852                   parent.Update(box);
8853                }
8854                if(_isModal && master && master.modalSlave == this)
8855                   master.modalSlave = null;
8856
8857                if(order)
8858                {
8859                   OldLink tmpPrev = order.prev;
8860                   client = tmpPrev ? tmpPrev.data : null;
8861                   if(client && !client.style.hidden && !client.destroyed && client.created)
8862                      prevOrder = tmpPrev;
8863                   for(;;)
8864                   {
8865                      client = tmpPrev ? tmpPrev.data : null;
8866                      if(client == this) { client = null; break; }
8867                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
8868                      {
8869                         tmpPrev = client.order.prev;
8870                      }
8871                      else
8872                      {
8873                         if(client)
8874                            prevOrder = tmpPrev;
8875                         break;
8876                      }
8877                   }
8878
8879                   // If this window can be an active client, make sure the next window we activate can also be one
8880                   if(!style.nonClient && style.isActiveClient)
8881                   {
8882                      tmpPrev = prevOrder;
8883                      for(;;)
8884                      {
8885                         client = tmpPrev ? tmpPrev.data : null;
8886                         if(client == this) { client = null; break; }
8887                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
8888                         {
8889                            tmpPrev = client.order.prev;
8890                         }
8891                         else 
8892                         {
8893                            if(client)
8894                               prevOrder = tmpPrev;
8895                            break;
8896                         }
8897                      }
8898                      if(client && client.style.hidden) client = null;
8899                   }
8900                }
8901
8902                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
8903                {
8904                   if(order && prevOrder && prevOrder.data != this)
8905                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
8906                   else
8907                      ActivateEx(false, false, false, true, null, null);
8908
8909                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
8910                   if(parent.activeClient == this)
8911                   {
8912                      parent.activeClient = null;
8913                      parent.UpdateActiveDocument(null);
8914                   }
8915                }
8916                else if(parent.activeClient == this)
8917                {
8918                   parent.activeClient = client;
8919                   parent.UpdateActiveDocument(this);
8920                }
8921
8922                // *** Not doing this anymore ***
8923               /*
8924                if(cycle)
8925                   parent.childrenCycle.Delete(cycle);
8926                if(order)
8927                   parent.childrenOrder.Delete(order);
8928                cycle = null;
8929                order = null;
8930                */
8931                
8932                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8933             }
8934
8935             firewatchers;
8936          }
8937          else if(this && value && style.hidden)
8938          {
8939             style.hidden = false;
8940             if(created)
8941             {
8942                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8943                if(rootWindow == this)
8944                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
8945
8946                if(_isModal && master)
8947                   master.modalSlave = this;
8948
8949                if(style.isActiveClient)
8950                {
8951                   positionID = parent.GetPositionID(this);
8952                   parent.numPositions++;
8953                   if(state == minimized) parent.numIcons++;
8954                }
8955
8956                // *** NOT DOING THIS ANYMORE ***
8957                /*
8958                if(!(style.inactive))
8959                {
8960                   if(!(style.noCycle))
8961                   {
8962                      cycle = parent.childrenCycle.AddAfter(
8963                         (parent.activeChild && parent.activeChild.cycle) ? 
8964                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
8965                      cycle.data = this;
8966                   }
8967                   order = parent.childrenOrder.AddAfter(
8968                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8969                      sizeof(OldLink));
8970                   order.data = this;
8971                }
8972                */
8973      
8974                /*
8975                if(true || !parent.activeChild)
8976                   ActivateEx(true, false, true, true, null, null);
8977                */
8978                if(creationActivation == activate)
8979                   ActivateEx(true, false, true, true, null, null);
8980                else if(creationActivation == flash && !object)
8981                   Flash();               
8982
8983                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
8984                Update(null);
8985
8986                // rootWindow.
8987                ConsequentialMouseMove(false);
8988             }
8989
8990             firewatchers;
8991          }
8992          else if(this)
8993             style.hidden = !value;
8994       }
8995
8996       get { return (style.hidden || !setVisible) ? false : true; }
8997    };
8998     
8999    property bool isDocument
9000    {
9001       property_category $"Document"
9002       set { style.isDocument = value; }
9003       get { return style.isDocument; }
9004    };
9005
9006    property bool mergeMenus
9007    {
9008       property_category $"Window Style"
9009       set { mergeMenus = value; }
9010       get { return (bool)mergeMenus; }
9011    };
9012
9013    property bool hasHorzScroll
9014    {
9015       property_category $"Window Style"
9016       set
9017       {
9018          if(value)
9019          {
9020             if(!style.hasHorzScroll && created)
9021             {
9022                CreateSystemChildren();         
9023                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9024             }
9025          }
9026          else if(style.hasHorzScroll)
9027          {
9028             sbh.Destroy(0);
9029             sbh = null;
9030             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9031          }
9032          style.hasHorzScroll = value;
9033       }
9034
9035       get { return style.hasHorzScroll; }
9036    };
9037
9038    property bool hasVertScroll
9039    {
9040       property_category $"Window Style"
9041       set
9042       {
9043          if(value)
9044          {
9045             if(!style.hasVertScroll && created)
9046             {
9047                style.hasVertScroll = true;
9048                CreateSystemChildren();
9049                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9050             }
9051          }
9052          else if(style.hasVertScroll)
9053          {
9054             sbv.Destroy(0);
9055             sbv = null;
9056             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9057          }
9058          style.hasVertScroll = value;
9059       }
9060       get { return style.hasVertScroll; }
9061    };
9062
9063    property bool dontHideScroll
9064    {
9065       property_category $"Behavior"
9066       set
9067       {
9068          scrollFlags.dontHide = value;
9069          if(value)
9070          {
9071             //UpdateScrollBars(true, true);
9072             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9073          }
9074          else
9075          {
9076             // UpdateScrollBars(true, true);
9077             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9078          }
9079       }
9080       get { return scrollFlags.dontHide; }
9081    };
9082
9083    property bool dontScrollVert
9084    {
9085       property_category $"Behavior"
9086       set { style.dontScrollVert = value; }
9087       get { return style.dontScrollVert; }
9088    };
9089    property bool dontScrollHorz
9090    {
9091       property_category $"Behavior"
9092       set { style.dontScrollHorz = value; }
9093       get { return style.dontScrollHorz; }
9094    };
9095
9096    property bool snapVertScroll
9097    {
9098       property_category $"Behavior"
9099       set
9100       {
9101          scrollFlags.snapY = value;
9102          if(sbv) sbv.snap = value;
9103       }
9104       get { return scrollFlags.snapY; }
9105    };
9106    property bool snapHorzScroll
9107    {
9108        property_category $"Behavior"
9109       set
9110       {
9111          scrollFlags.snapX = value;
9112          if(sbh) sbh.snap = value;
9113       }
9114       get { return scrollFlags.snapX; }
9115    };
9116
9117    property Point scroll
9118    {
9119       property_category $"Behavior"
9120       set { SetScrollPosition(value.x, value.y); }
9121       get { value = scroll; }
9122    };
9123
9124    property bool modifyVirtualArea
9125    {
9126       property_category $"Behavior"
9127       set { modifyVirtArea = value; }
9128       get { return (bool)modifyVirtArea; }
9129    };
9130
9131    property bool dontAutoScrollArea
9132    {
9133       property_category $"Behavior"
9134       // Activating a child control out of view will automatically scroll to make it in view
9135       set { noAutoScrollArea = value; }
9136       get { return (bool)noAutoScrollArea; }
9137    };
9138
9139    property char * fileName
9140    {
9141       property_category $"Document"
9142       set
9143       {
9144          if(menu && ((!fileName && value) || (fileName && !value)))
9145          {
9146             MenuItem item = menu.FindItem(MenuFileSave, 0);
9147             if(item) item.disabled = !modifiedDocument && value;
9148          }
9149
9150          delete fileName;
9151
9152          if(value && value[0])
9153             fileName = CopyString(value);
9154
9155          if(parent && this == parent.activeClient)
9156             parent.UpdateActiveDocument(null);
9157          else
9158             UpdateCaption();
9159
9160          // if(style.isDocument)
9161          if(!saving)
9162             fileMonitor.fileName = value;
9163       }
9164       get { return fileName; }
9165    };
9166
9167    property int64 id
9168    {
9169       property_category $"Data"
9170       set { id = value; }
9171       get { return id; }
9172    };
9173
9174    property bool modifiedDocument
9175    {
9176       property_category $"Document"
9177       set
9178       {
9179          if(style.isDocument || fileName)
9180          {
9181             if(menu)
9182             {
9183                MenuItem item = menu.FindItem(MenuFileSave, 0);
9184                if(item) item.disabled = !value && fileName;
9185             }
9186          }
9187
9188          if(modifiedDocument != value)
9189          {
9190             modifiedDocument = value;
9191             if(style.isDocument || fileName)
9192                UpdateCaption();
9193          }
9194       }
9195       get { return (bool)modifiedDocument; }
9196    };
9197
9198    property bool showInTaskBar
9199    {
9200       property_category $"Window Style"
9201       set { style.showInTaskBar = value; }
9202       get { return (style.showInTaskBar; }
9203    };
9204    property FileDialog saveDialog { set { saveDialog = value; } };
9205    property bool isActiveClient
9206    {
9207       property_category $"Behavior"
9208       set { style.isActiveClient = value; }
9209       get { return style.isActiveClient; }
9210    };
9211
9212    property Cursor cursor
9213    {
9214       property_category $"Appearance"
9215       set
9216       {
9217          cursor = value;
9218          SelectMouseCursor();
9219       }
9220       get { return cursor; }
9221    };      
9222
9223 //#if !defined(ECERE_VANILLA)
9224    property char * name
9225    {
9226       property_category $"Design"
9227       get
9228       {
9229          return (this && object) ? object.name : null;
9230       }
9231       set
9232       {
9233          if(activeDesigner)
9234             activeDesigner.RenameObject(object, value);
9235       }
9236    };
9237 //#endif
9238    property char * displayDriver
9239    {
9240       property_category $"Behavior"
9241       set
9242       {
9243          dispDriver = GetDisplayDriver(value);
9244          //DisplayModeChanged();
9245       }
9246       get
9247       {
9248          return dispDriver ? dispDriver.name : null;
9249       }
9250    }
9251
9252    // RUNTIME PROPERTIES
9253    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9254    property Size scrollArea
9255    {
9256       property_category $"Behavior"
9257       set
9258       {
9259          if(value != null)
9260             SetScrollArea(value.w, value.h, false);
9261          else
9262             SetScrollArea(0,0, true);
9263       }
9264       get { value = scrollArea; }
9265       isset
9266       {
9267          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9268       }
9269    };
9270    property bool is3D
9271    {
9272       property_category $"Layout"
9273       set { if(this) is3D = value; }
9274       get { return (bool)is3D; }
9275    };
9276
9277    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9278                                                                                                             
9279    // Will be merged with font later
9280    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9281    property Point clientStart { get { value = clientStart; } };
9282    property Point absPosition { get { value = absPosition; } };
9283    property Anchor normalAnchor { get {value = normalAnchor; } };
9284    // property Size normalSizeAnchor { get { value = normalSizeAnchor; } };
9285    property bool active { get { return (bool)active; } };
9286    property bool created { get { return (bool)created; } };
9287    property bool destroyed { get { return (bool)destroyed; } };
9288    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9289    property Window firstChild { get { return children.first; } };   
9290    property Window lastChild { get { return children.last; } };   
9291    property Window activeClient { get { return activeClient; } };
9292    property Window activeChild { get { return activeChild; } };
9293    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9294    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9295    property ScrollBar horzScroll { get { return sbh; } };
9296    property ScrollBar vertScroll { get { return sbv; } };
9297    property StatusBar statusBar { get { return statusBar; } };
9298    property Window rootWindow { get { return rootWindow; } };   
9299    property bool closing { get { return (bool)closing; } set { closing = value; } };
9300    property int documentID { get { return documentID; } };
9301    property Window previous { get { return prev; } }
9302    property Window next { get { return next; } }
9303    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9304    property PopupMenu menuBar { get { return menuBar; } }
9305    property ScrollBar sbv { get { return sbv; } }
9306    property ScrollBar sbh { get { return sbh; } }
9307    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9308    property void * systemHandle { get { return windowHandle; } }
9309    property Button minimizeButton { get { return sysButtons[0]; } };
9310    property Button maximizeButton { get { return sysButtons[1]; } };   
9311    property Button closeButton { get { return sysButtons[2]; } };
9312    property BitmapResource icon
9313    {
9314       get { return icon; }
9315       set
9316       {
9317          icon = value;
9318          if(icon) incref icon;
9319          if(created)
9320             guiApp.interfaceDriver.SetIcon(this, value);
9321       }
9322    };
9323    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9324    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; } };
9325    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9326    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9327    property bool nativeDecorations
9328    {
9329       get { return (bool)nativeDecorations; }
9330       set { nativeDecorations = value; }
9331 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
9332       isset
9333       {
9334          //return (nativeDecorations && (rootWindow == this || (formDesigner && activeDesigner && ((FormDesigner)activeDesigner.classDesigner).form && parent == ((FormDesigner)activeDesigner.classDesigner).form.parent))) != style.fixed;
9335          bool result = false;
9336          if(nativeDecorations)
9337          {
9338             if(rootWindow == this)
9339                result = true;
9340             else
9341             {
9342                if(formDesigner && activeDesigner)
9343                {
9344                   FormDesigner cd = (FormDesigner)activeDesigner.classDesigner;
9345                   Window form = cd ? cd.form : null;
9346                   if(form && parent == form.parent)
9347                      result = true;
9348                }
9349             }
9350          }
9351          return result != style.fixed;
9352       }
9353 #endif
9354    };
9355    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9356
9357    property char * text
9358    {
9359       property_category $"Deprecated"
9360       watchable
9361       set { property::caption = value; }
9362       get { return property::caption; }
9363    }
9364 private:
9365    // Data
9366    //char * yo;
9367    Window prev, next;
9368    WindowBits style;       // Window Style
9369    char * caption;            // Name / Caption
9370    Window parent;    // Parent window
9371    OldList children;          // List of children in Z order
9372    Window activeChild;     // Child window having focus
9373    Window activeClient;
9374    Window previousActive;  // Child active prior to activating the default child
9375    Window master;          // Window owning and receiving notifications concerning this window
9376    OldList slaves;            // List of windows belonging to this window
9377    Display display;        // Display this window is drawn into
9378
9379    Point position;         // Position in parent window client area
9380    Point absPosition;      // Absolute position
9381    Point clientStart;      // Client area position from (0,0) in this window
9382    Size size;              // Size
9383    Size clientSize;        // Client area size
9384    Size scrollArea;        // Virtual Scroll area size
9385    Size reqScrollArea;     // Requested virtual area size
9386    Point scroll;           // Virtual area scrolling position
9387    ScrollBar sbh, sbv;        // Scrollbar window handles
9388    Cursor cursor;        // Mouse cursor used for this window
9389    WindowState state;
9390    PopupMenu menuBar;
9391    StatusBar statusBar;
9392    Button sysButtons[3];
9393    char * fileName;
9394    Box clientArea;         // Client Area box clipped to parent
9395    Key setHotKey;
9396    HotKeySlot hotKey;        // HotKey for this window
9397    int numDocuments;
9398    int numPositions;
9399    Menu menu;
9400    ScrollFlags scrollFlags;// Window Scrollbar Flags
9401    int64 id;                 // Control ID
9402    int documentID;
9403    ColorAlpha background;  // Background color used to draw the window area
9404    Color foreground;
9405    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9406    OldList childrenCycle;     // Cycling order
9407    OldLink cycle;             // Element of parent's cycling order
9408    OldList childrenOrder;     // Circular Z-Order
9409    OldLink order;             // Element of parent's circular Z-Order
9410    Window modalSlave;      // Slave window blocking this window's interaction
9411
9412    Window rootWindow;      // Topmost system managed window
9413    void * windowHandle;    // System window handle
9414
9415    DialogResult returnCode;// Return code for modal windows
9416   
9417    Point sbStep;           // Scrollbar line scrolling steps
9418
9419    Anchor stateAnchor;
9420    SizeAnchor stateSizeAnchor;
9421
9422    Anchor normalAnchor;
9423    SizeAnchor normalSizeAnchor;
9424
9425    Size skinMinSize;       // Minimal window size based on style
9426    Point scrolledPos;      // Scrolled position
9427    Box box;                // Window box clipped to parent
9428    Box * against;          // What to clip the box to
9429
9430    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9431    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9432    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9433    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9434    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9435    Point scrolledArea;     // Distance to scroll area by
9436    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9437
9438    OldList hotKeys;           // List of the hotkeys of all children
9439    Window defaultControl;  // Default child control
9440    Size minSize;
9441    Size maxSize;
9442
9443    ColorAlpha * palette;   // Color palette used for this window
9444
9445    int caretSize;          // Size of caret, non zero if a caret is present
9446    Point caretPos;         // Caret position
9447
9448    void * systemParent;    // Parent System Window for embedded windows
9449
9450    int iconID;
9451    int numIcons;
9452    int positionID;
9453
9454    Mutex mutex;
9455    WindowState lastState;
9456
9457    FileMonitor fileMonitor
9458    {
9459       this, FileChange { modified = true };
9460
9461       bool OnFileNotify(FileChange action, char * param)
9462       {
9463          incref this;
9464          fileMonitor.StopMonitoring();
9465          if(OnFileModified(action, param))
9466             fileMonitor.StartMonitoring();
9467          delete this;
9468          return true;
9469       }
9470    };
9471    FontResource setFont, systemFont;
9472    FontResource usedFont;
9473    FontResource captionFont;
9474    OldList resources;
9475    FileDialog saveDialog;
9476    Anchor anchor;
9477    SizeAnchor sizeAnchor;
9478
9479    // FormDesigner data
9480    ObjectInfo object;
9481    Window control;
9482    Extent * tempExtents; //[4];
9483    BitmapResource icon;
9484    void * windowData;
9485    CreationActivationOption creationActivation;
9486    struct
9487    {
9488       bool active:1;            // true if window and ancestors are active
9489       bool acquiredInput:1;     // true if the window is processing state based input
9490       bool modifiedDocument:1;
9491       bool disabled:1;          // true if window cannot interact
9492       bool isForegroundWindow:1;// true while a root window is being activated
9493       bool visible:1;           // Visibility flag
9494       bool destroyed:1;         // true if window is being destroyed
9495       bool anchored:1;          // true if this window is repositioned when the parent resizes
9496       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9497       bool mouseInside:1;
9498       bool positioned:1;
9499       bool created:1;
9500       bool is3D:1;
9501       bool mergeMenus:1;
9502       bool modifyVirtArea:1;
9503       bool noAutoScrollArea:1;
9504       bool closing:1;
9505       bool autoCreate:1;
9506       bool setVisible:1;      // FOR FORM DESIGNER
9507       bool wasCreated:1;
9508       bool fullRender:1;
9509       bool moveable:1;
9510       bool alphaBlend:1;
9511       bool composing:1;
9512       bool useSharedMemory:1;
9513       bool resized:1;
9514       bool saving:1;
9515       bool nativeDecorations:1;
9516       bool manageDisplay:1;
9517       bool formDesigner:1; // True if we this is running in the form editor
9518    }; 
9519
9520    // Checks used internally for them not to take effect in FormDesigner
9521    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
9522    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
9523
9524    WindowController controller;
9525    public property WindowController controller { get { return controller; } set { delete controller; controller = value; if(controller) incref controller; } }
9526 };
9527
9528 public class CommonControl : Window
9529 {
9530    // creationActivation = doNothing;
9531
9532    ToolTip toolTip;
9533    public property String toolTip
9534    {
9535       property_category $"Appearance"
9536       set
9537       {
9538          if(created) CommonControl::OnDestroy();
9539          delete toolTip;
9540          toolTip = value ? ToolTip { tip = value; } : null;
9541          incref toolTip;
9542          if(created) CommonControl::OnCreate();
9543       }
9544       get { return toolTip ? toolTip.tip : null; }
9545    }
9546
9547    void OnDestroy()
9548    {
9549       if(toolTip)
9550          // (Very) Ugly work around for the fact that the parent watcher
9551          // won't fire when it's already been disconnected...
9552          eInstance_FireSelfWatchers(toolTip,
9553             __ecereProp___ecereNameSpace__ecere__gui__Window_parent);
9554    }
9555
9556    bool OnCreate()
9557    {
9558       if(toolTip)
9559          toolTip.parent = this;
9560       return true;
9561    }
9562    ~CommonControl()
9563    {
9564       delete toolTip;
9565    }
9566 };
9567
9568 public class Percentage : float
9569 {
9570    char * OnGetString(char * string, float * fieldData, bool * needClass)
9571    {
9572       int c;
9573       int last = 0;
9574       sprintf(string, "%.2f", this);
9575       c = strlen(string)-1;
9576       for( ; c >= 0; c--)
9577       {
9578          if(string[c] != '0') 
9579             last = Max(last, c);
9580          if(string[c] == '.')
9581          {
9582             if(last == c)
9583                string[c] = 0;
9584             else
9585                string[last+1] = 0;
9586             break;
9587          }
9588       }
9589       return string;
9590    }
9591 };
9592
9593 public void ApplySkin(Class c, char * name, void ** vTbl)
9594 {
9595    char className[1024];
9596    Class sc;
9597    OldLink d;
9598    int m;
9599
9600    subclass(Window) wc = (subclass(Window))c;
9601    subclass(Window) base = (subclass(Window))c.base;
9602
9603    sprintf(className, "%sSkin_%s", name, c.name);
9604    wc.pureVTbl = c._vTbl;
9605    c._vTbl = new void *[c.vTblSize];
9606    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
9607    sc = eSystem_FindClass(c.module.application, className);
9608    
9609    if(vTbl)
9610    {
9611       for(m = 0; m < c.base.vTblSize; m++)
9612       {
9613          if(c._vTbl[m] == base.pureVTbl[m])
9614             c._vTbl[m] = vTbl[m];
9615       }
9616    }
9617    if(sc)
9618    {
9619       for(m = 0; m < c.vTblSize; m++)
9620       {
9621          if(sc._vTbl[m] != wc.pureVTbl[m])
9622             c._vTbl[m] = sc._vTbl[m];
9623       }
9624    }
9625       
9626    for(d = c.derivatives.first; d; d = d.next)
9627    {
9628       ApplySkin(d.data, name, c._vTbl);
9629    }
9630 }
9631
9632 public void UnapplySkin(Class c)
9633 {
9634    char className[1024];
9635    Class sc;
9636    subclass(Window) wc = (subclass(Window))c;
9637    subclass(Window) base = (subclass(Window))c.base;
9638    OldLink d;
9639
9640    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
9641    {
9642       delete c._vTbl;
9643       c._vTbl = wc.pureVTbl;
9644       wc.pureVTbl = null;
9645    }
9646
9647    for(d = c.derivatives.first; d; d = d.next)
9648    {
9649       UnapplySkin(d.data);
9650    }
9651 }
9652 /*
9653 void CheckFontIntegrity(Window window)
9654 {
9655    Window c;
9656    if(window)
9657    {
9658       if(window.usedFont && window.usedFont.font == 0xecececec)
9659       {
9660          FontResource uf = window.usedFont;
9661          char * className = window._class.name;
9662          char * text = window.text;
9663          Print("");
9664       }
9665       for(c = window.firstChild; c; c = c.next)
9666          CheckFontIntegrity(c);
9667    }
9668 }*/
9669
9670 public class ControllableWindow : Window
9671 {
9672    /*WindowController controller;
9673    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
9674    ~ControllableWindow() { delete controller; }*/
9675 }
9676
9677 class WindowControllerInterface : ControllableWindow
9678 {
9679    bool OnKeyDown(Key key, unichar ch)
9680    {
9681       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyDown)((Window)controller.controlled, controller, key, ch);
9682       if(result)
9683          result = ((bool (*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown])(controller.window, key, ch);
9684       return result;
9685    }
9686
9687    bool OnKeyUp(Key key, unichar ch)
9688    {
9689       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyUp)((Window)controller.controlled, controller, key, ch);
9690       if(result)
9691          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp])(controller.window, key, ch);
9692       return result;
9693    }
9694
9695    bool OnKeyHit(Key key, unichar ch)
9696    {
9697       bool result = ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyHit)((Window)controller.controlled, controller, key, ch);
9698       if(result)
9699          result = ((bool(*)(Window, Key, unichar))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit])(controller.window, key, ch);
9700       return result;
9701    }
9702
9703    bool OnMouseMove(int x, int y, Modifiers mods)
9704    {
9705       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMouseMove)((Window)controller.controlled, controller, x, y, mods);
9706       if(result)
9707          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove])(controller.window, x, y, mods);
9708       return result;
9709    }
9710
9711    bool OnLeftButtonDown(int x, int y, Modifiers mods)
9712    {
9713       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonDown)((Window)controller.controlled, controller, x, y, mods);
9714       if(result)
9715          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown])(controller.window, x, y, mods);
9716       return result;
9717    }
9718
9719    bool OnLeftButtonUp(int x, int y, Modifiers mods)
9720    {
9721       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonUp)((Window)controller.controlled, controller, x, y, mods);
9722       if(result)
9723          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp])(controller.window, x, y, mods);
9724       return result;
9725    }
9726
9727    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
9728    {
9729       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9730       if(result)
9731          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick])(controller.window, x, y, mods);
9732       return result;
9733    }
9734
9735    bool OnRightButtonDown(int x, int y, Modifiers mods)
9736    {
9737       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonDown)((Window)controller.controlled, controller, x, y, mods);
9738       if(result)
9739          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown])(controller.window, x, y, mods);
9740       return result;
9741    }
9742
9743    bool OnRightButtonUp(int x, int y, Modifiers mods)
9744    {
9745       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonUp)((Window)controller.controlled, controller, x, y, mods);
9746       if(result)
9747          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp])(controller.window, x, y, mods);
9748       return result;
9749    }
9750
9751    bool OnRightDoubleClick(int x, int y, Modifiers mods)
9752    {
9753       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9754       if(result)
9755          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick])(controller.window, x, y, mods);
9756       return result;
9757    }
9758
9759    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
9760    {
9761       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonDown)((Window)controller.controlled, controller, x, y, mods);
9762       if(result)
9763          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown])(controller.window, x, y, mods);
9764       return result;
9765    }
9766
9767    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
9768    {
9769       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonUp)((Window)controller.controlled, controller, x, y, mods);
9770       if(result)
9771          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp])(controller.window, x, y, mods);
9772       return result;
9773    }
9774
9775    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
9776    {
9777       bool result = ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleDoubleClick)((Window)controller.controlled, controller, x, y, mods);
9778       if(result)
9779          result = ((bool(*)(Window, int, int, Modifiers))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick])(controller.window, x, y, mods);
9780       return result;
9781    }
9782
9783    void OnResize(int width, int height)
9784    {
9785       ((void(*)(Window, WindowController, int, int))(void *)controller.OnResize)((Window)controller.controlled, controller, width, height);
9786       ((void(*)(Window, int, int))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize])(controller.window, width, height);
9787    }
9788
9789    void OnRedraw(Surface surface)
9790    {
9791       ((void(*)(Window, WindowController, Surface))(void *)controller.OnRedraw)((Window)controller.controlled, controller, surface);
9792       ((void(*)(Window, Surface))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw])(controller.window, surface);
9793    }
9794
9795    bool OnCreate()
9796    {
9797       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnCreate)((Window)controller.controlled, controller);
9798       if(result)
9799          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate])(controller.window);
9800       return result;
9801    }
9802
9803    bool OnLoadGraphics()
9804    {
9805       bool result = ((bool(*)(Window, WindowController))(void *)controller.OnLoadGraphics)((Window)controller.controlled, controller);
9806       if(result)
9807          result = ((bool(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics])(controller.window);
9808       return result;
9809    }
9810
9811    void OnUnloadGraphics()
9812    {
9813       ((void(*)(Window, WindowController))(void *)controller.OnUnloadGraphics)((Window)controller.controlled, controller);
9814       ((void(*)(Window))(void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics])(controller.window);
9815    }
9816 }
9817
9818 public class WindowController<class V>
9819 {
9820 public:
9821    property Window window
9822    {
9823       set
9824       {
9825          uint size = class(Window).vTblSize;
9826          if(value)
9827          {
9828             windowVTbl = new void *[size];
9829             memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
9830             if(value._vTbl == value._class._vTbl)
9831             {
9832                value._vTbl = new void *[value._class.vTblSize];
9833                memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
9834             }
9835             {
9836                int c;
9837                for(c = 0; c < size; c++)
9838                {
9839                   void * function = class(WindowControllerInterface)._vTbl[c];
9840                   if(function != DefaultFunction)
9841                      value._vTbl[c] = function;
9842                   else
9843                      value._vTbl[c] = windowVTbl[c];
9844                }
9845             }
9846          }
9847          else
9848             memcpy(value._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
9849          window = value;
9850       }
9851       get { return window; }
9852    }
9853    property V controlled
9854    {
9855       set { controlled = value; }
9856       get { return controlled; }
9857    }
9858    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
9859    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
9860    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
9861    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
9862    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
9863    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
9864    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9865    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
9866    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
9867    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9868    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
9869    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
9870    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
9871    virtual void V::OnResize(WindowController controller, int width, int height);
9872    virtual void V::OnRedraw(WindowController controller, Surface surface);
9873    virtual bool V::OnCreate(WindowController controller);
9874    virtual bool V::OnLoadGraphics(WindowController controller);
9875    virtual void V::OnUnloadGraphics(WindowController controller);
9876
9877 private:
9878    int (** windowVTbl)();   
9879    V controlled;
9880    Window window;
9881
9882    ~WindowController()
9883    {
9884       delete windowVTbl;
9885    }
9886 }