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