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