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