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