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