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