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