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