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