377815520af4df3cca0866c8a5d3ee8e9e272be7
[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);
8142    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
8143    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
8144    {
8145       *cw = *w;
8146       *ch = *h;
8147    }
8148    virtual void ShowDecorations(Font captionFont, Surface surface, const char * name, bool active, bool moving);
8149    virtual void PreShowDecorations(Font captionFont, Surface surface, const char * name, bool active, bool moving);
8150    virtual bool IsMouseMoving(int x, int y, int w, int h)
8151    {
8152       return false;
8153    }
8154    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY)
8155    {
8156       return false;
8157    }
8158    virtual void UpdateNonClient();
8159    virtual void SetBox(Box box);    // This is used in the MySkin skin
8160    virtual bool IsInside(int x, int y)
8161    {
8162       return box.IsPointInside({x, y});
8163    }
8164    virtual bool IsOpaque()
8165    {
8166       return (!style.drawBehind || background.a == 255);
8167    }
8168
8169    // Notifications
8170    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
8171    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
8172    virtual void Window::NotifySaved(Window window, const char * filePath);
8173
8174    // Public Methods
8175
8176    // Properties
8177    property Window parent
8178    {
8179       property_category $"Layout"
8180       set
8181       {
8182          if(value || guiApp.desktop)
8183          {
8184             Window last;
8185             Window oldParent = parent;
8186             Anchor anchor = this.anchor;
8187
8188             if(value && value.IsDescendantOf(this)) return;
8189             if(value && value == this)
8190                return;
8191             if(!value) value = guiApp.desktop;
8192
8193             if(value == oldParent) return;
8194
8195             if(!master || (master == this.parent && master == guiApp.desktop))
8196                property::master = value;
8197
8198             if(parent)
8199             {
8200                parent.children.Remove(this);
8201
8202                parent.Update(
8203                {
8204                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
8205                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
8206                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
8207                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
8208                });
8209             }
8210
8211             last = value.children.last;
8212
8213             if(style.isDocument)
8214             {
8215                if(parent)
8216                   parent.numDocuments--;
8217                documentID = value.GetDocumentID();
8218             }
8219
8220             if(style.isActiveClient && !style.hidden)
8221             {
8222                if(parent && parent != guiApp.desktop && !(style.hidden))
8223                {
8224                   if(state == minimized) parent.numIcons--;
8225                   parent.numPositions--;
8226                }
8227             }
8228
8229             if(!style.stayOnTop)
8230                for(; last && last.style.stayOnTop; last = last.prev);
8231
8232             value.children.Insert(last, this);
8233
8234             // *** NEW HERE: ***
8235             if(cycle)
8236                parent.childrenCycle.Delete(cycle);
8237             if(order)
8238                parent.childrenOrder.Delete(order);
8239             cycle = null;
8240             order = null;
8241             // *** TODO: Added this here to solve crash on setting parent to null before destroying/destructing ***
8242             //           Should something else be done?
8243             if(parent && parent.activeChild == this)
8244                parent.activeChild = null;
8245             if(parent && parent.activeClient == this)
8246                parent.activeClient = null;
8247
8248             //if(created)
8249             {
8250                if(created)
8251                {
8252                   int x = position.x, y = position.y, w = size.w, h = size.h;
8253
8254                   int vpw, vph;
8255
8256                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
8257                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
8258
8259                   vpw = value.clientSize.w;
8260                   vph = value.clientSize.h;
8261                   if(style.nonClient)
8262                   {
8263                      vpw = value.size.w;
8264                      vph = value.size.h;
8265                   }
8266                   else if(style.fixed)
8267                   {
8268                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
8269                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
8270                   }
8271
8272                   anchor = this.anchor;
8273
8274                   if(anchor.left.type == offset)            anchor.left.distance = x;
8275                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
8276                   if(anchor.top.type == offset)             anchor.top.distance = y;
8277                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
8278                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
8279                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
8280                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
8281                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
8282                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
8283                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
8284
8285                   if(!anchor.left.type && !anchor.right.type)
8286                   {
8287                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
8288                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
8289                   }
8290                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
8291                   if(!anchor.top.type && !anchor.bottom.type)
8292                   {
8293                      anchor.vert.distance = (y + h / 2) - (vph / 2);
8294                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
8295                   }
8296                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
8297                }
8298                parent = value;
8299                parent.OnChildAddedOrRemoved(this, false);
8300
8301                // *** NEW HERE ***
8302                if(!style.inactive)
8303                {
8304                   if(!style.noCycle)
8305                      parent.childrenCycle.Insert(
8306                         // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8307                         //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
8308                         null,
8309                         cycle = OldLink { data = this });
8310                   parent.childrenOrder.Insert(
8311                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8312                      order = OldLink { data = this });
8313                }
8314
8315                if(!style.hidden && style.isActiveClient)
8316                {
8317                   positionID = parent.GetPositionID(this);
8318                   parent.numPositions++;
8319                   if(state == minimized) parent.numIcons--;
8320                }
8321
8322                // *** FONT INHERITANCE ***
8323                if(!setFont && oldParent)
8324                   stopwatching(oldParent, font);
8325
8326                if(systemFont)
8327                {
8328                   RemoveResource(systemFont);
8329                   delete systemFont;
8330                }
8331                // TESTING WITH WATCHERS:
8332                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8333                // usedFont = setFont ? setFont : (systemFont);
8334
8335                if(!usedFont)
8336                {
8337                   if(guiApp.currentSkin)
8338                   {
8339                      systemFont = guiApp.currentSkin.SystemFont();
8340                      incref systemFont;
8341                   }
8342                   usedFont = systemFont;
8343                   AddResource(systemFont);
8344                }
8345
8346                if(!setFont)
8347                   watch(value)
8348                   {
8349                      font
8350                      {
8351                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8352                         firewatchers font;
8353                         Update(null);
8354                      }
8355                   };
8356
8357                firewatchers font;
8358
8359
8360                if(value.rootWindow && value.rootWindow.display && rootWindow && created)
8361                {
8362                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) ||
8363                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
8364
8365                   if(reloadGraphics)
8366                      UnloadGraphics(false);
8367                   SetupDisplay();
8368                   if(reloadGraphics)
8369                      LoadGraphics(false, false);
8370
8371                   /*
8372                   if(value.rootWindow != rootWindow)
8373                      DisplayModeChanged();
8374                   else
8375                   */
8376                }
8377                scrolledPos.x = MININT; // Prevent parent update
8378                {
8379                   bool anchored = this.anchored;
8380                   property::anchor = anchor;
8381                   this.anchored = anchored;
8382                }
8383                /*
8384                {
8385                   int x, y, w, h;
8386                   if(guiApp.currentSkin)
8387                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
8388
8389                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8390                   Position(x, y, w, h, true, true, true, true, false, true);
8391                }
8392                */
8393
8394             }
8395             // else parent = value;
8396             if(oldParent)
8397                oldParent.OnChildAddedOrRemoved(this, true);
8398          }
8399       }
8400       get { return parent; }
8401    };
8402
8403    property Window master
8404    {
8405       property_category $"Behavior"
8406       set
8407       {
8408          //if(this == value) return;
8409          if(value && value.IsSlaveOf(this)) return;
8410
8411          if(master != value)
8412          {
8413             if(master)
8414             {
8415                OldLink slaveHolder;
8416                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
8417                   if(slaveHolder.data == this)
8418                   {
8419                      master.slaves.Delete(slaveHolder);
8420                      break;
8421                   }
8422             }
8423
8424             if(value)
8425             {
8426                value.slaves.Add(OldLink { data = this });
8427
8428                if(hotKey)
8429                {
8430                   if(master)
8431                      master.hotKeys.Remove(hotKey);
8432                   value.hotKeys.Add(hotKey);
8433                   hotKey = null;
8434                }
8435                if(master && master.defaultControl == this)
8436                   master.defaultControl = null;
8437
8438                if(style.isDefault && !value.defaultControl)
8439                   value.defaultControl = this;
8440             }
8441          }
8442          master = value;
8443       }
8444       get { return master ? master : parent; }
8445    };
8446
8447    property const char * caption
8448    {
8449       property_category $"Appearance"
8450       watchable
8451       set
8452       {
8453          delete caption;
8454          if(value)
8455          {
8456             caption = new char[strlen(value)+1];
8457             if(caption)
8458                strcpy(caption, value);
8459          }
8460          if(created)
8461             UpdateCaption();
8462       }
8463       get { return caption; }
8464    };
8465
8466    property Key hotKey
8467    {
8468       property_category $"Behavior"
8469       set
8470       {
8471          setHotKey = value;
8472          if(created)
8473          {
8474             if(value)
8475             {
8476                if(!hotKey)
8477                   master.hotKeys.Add(hotKey = HotKeySlot { });
8478                if(hotKey)
8479                {
8480                   hotKey.key = value;
8481                   hotKey.window = this;
8482                }
8483             }
8484             else if(hotKey)
8485             {
8486                master.hotKeys.Delete(hotKey);
8487                hotKey = null;
8488             }
8489          }
8490       }
8491       get { return hotKey ? hotKey.key : 0; }
8492    };
8493
8494    property Color background
8495    {
8496       property_category $"Appearance"
8497       set
8498       {
8499          background.color = value;
8500          firewatchers;
8501          if(created)
8502          {
8503             Update(null);
8504             if(this == rootWindow)
8505                guiApp.interfaceDriver.SetRootWindowColor(this);
8506          }
8507       }
8508       get { return background.color; }
8509    };
8510
8511    property Percentage opacity
8512    {
8513       property_category $"Appearance"
8514       set
8515       {
8516          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
8517          drawBehind = (background.a == 255) ? false : true;
8518       }
8519       get { return background.a / 255.0f; }
8520    };
8521
8522    property Color foreground
8523    {
8524       property_category $"Appearance"
8525       set
8526       {
8527          foreground = value;
8528          firewatchers;
8529          if(created)
8530             Update(null);
8531       }
8532       get { return foreground; }
8533    };
8534
8535    property BorderStyle borderStyle
8536    {
8537       property_category $"Appearance"
8538       set
8539       {
8540          if(!((BorderBits)value).fixed)
8541          {
8542             style.hasClose = false;
8543             style.hasMaximize = false;
8544             style.hasMinimize = false;
8545             nativeDecorations = false;
8546          }
8547          style.borderBits = value;
8548          if(created)
8549          {
8550             int x, y, w, h;
8551             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8552
8553             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8554             Position(x, y, w, h, true, true, true, true, false, true);
8555             CreateSystemChildren();
8556          }
8557       }
8558       get { return (BorderStyle)style.borderBits; }
8559    };
8560
8561    property Size minClientSize
8562    {
8563       property_category $"Layout"
8564       set { minSize = value; }
8565       get { value = minSize; }
8566    };
8567
8568    property Size maxClientSize
8569    {
8570       property_category $"Layout"
8571       set { maxSize = value; }
8572       get { value = maxSize; }
8573    };
8574
8575    property bool hasMaximize
8576    {
8577       property_category $"Window Style"
8578       set
8579       {
8580          style.hasMaximize = value;
8581          if(value) { style.fixed = true; style.contour = true; }
8582          if(created)
8583          {
8584             int x, y, w, h;
8585             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8586
8587             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8588             Position(x, y, w, h, true, true, true, true, false, true);
8589
8590             CreateSystemChildren();
8591          }
8592       }
8593       get { return style.hasMaximize; }
8594    };
8595
8596    property bool hasMinimize
8597    {
8598       property_category $"Window Style"
8599       set
8600       {
8601          style.hasMinimize = value;
8602          if(value) { style.fixed = true; style.contour = true; }
8603          if(created)
8604          {
8605             int x, y, w, h;
8606             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8607
8608             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8609             Position(x, y, w, h, true, true, true, true, false, true);
8610
8611             CreateSystemChildren();
8612          }
8613       }
8614       get { return style.hasMinimize;  }
8615    };
8616
8617    property bool hasClose
8618    {
8619       property_category $"Window Style"
8620       set
8621       {
8622          style.hasClose = value;
8623          if(value) { style.fixed = true; style.contour = true; }
8624          if(created)
8625          {
8626             int x, y, w, h;
8627             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8628             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8629             Position(x, y, w, h, true, true, true, true, false, true);
8630             CreateSystemChildren();
8631          }
8632       }
8633       get { return style.hasClose; }
8634    };
8635
8636    property bool nonClient
8637    {
8638       property_category $"Layout"
8639       set
8640       {
8641          style.nonClient = value;
8642          if(value)
8643             style.stayOnTop = true;
8644       }
8645       get { return style.nonClient; }
8646    };
8647
8648    property bool inactive
8649    {
8650       property_category $"Behavior"
8651       set
8652       {
8653          if(value)
8654          {
8655             // *** NEW HERE: ***
8656             if(!style.inactive)
8657             {
8658                if(cycle)
8659                   parent.childrenCycle.Delete(cycle);
8660                if(order)
8661                   parent.childrenOrder.Delete(order);
8662                cycle = null;
8663                order = null;
8664             }
8665
8666             if(created)
8667             {
8668                active = false; // true;
8669                if(parent.activeChild == this)
8670                   parent.activeChild = null;
8671                if(parent.activeClient == this)
8672                   parent.activeClient = null;
8673             }
8674          }
8675          else
8676          {
8677             if(style.inactive)
8678             {
8679                if(!style.noCycle)
8680                {
8681                   parent.childrenCycle.Insert(
8682                      // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8683                      //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
8684                      null,
8685                      cycle = OldLink { data = this });
8686                }
8687                parent.childrenOrder.Insert(
8688                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8689                   order = OldLink { data = this });
8690             }
8691          }
8692          style.inactive = value;
8693       }
8694       get { return style.inactive; }
8695    };
8696
8697    property bool clickThrough
8698    {
8699       property_category $"Behavior"
8700       set { style.clickThrough = value; }
8701       get { return style.clickThrough; }
8702    };
8703
8704    property bool isRemote
8705    {
8706       property_category $"Behavior"
8707       set { style.isRemote = value; }
8708       get { return style.isRemote; }
8709    };
8710
8711    property bool noCycle
8712    {
8713       property_category $"Behavior"
8714       set { style.noCycle = value; }
8715       get { return style.noCycle; }
8716    };
8717
8718    property bool isModal
8719    {
8720       property_category $"Behavior"
8721       set { style.modal = value; }
8722       get { return style.modal; }
8723    };
8724
8725    property bool interim
8726    {
8727       property_category $"Behavior"
8728       set { style.interim = value; }
8729       get { return style.interim; }
8730    };
8731
8732    property bool tabCycle
8733    {
8734       property_category $"Behavior"
8735       set { style.tabCycle = value; }
8736       get { return style.tabCycle; }
8737    };
8738
8739    property bool isDefault
8740    {
8741       property_category $"Behavior"
8742       set
8743       {
8744          if(master)
8745          {
8746             if(value)
8747             {
8748                /*Window sibling;
8749                for(sibling = parent.children.first; sibling; sibling = sibling.next)
8750                   if(sibling != this && sibling.style.isDefault)
8751                      sibling.style.isDefault = false;*/
8752                if(master.defaultControl)
8753                   master.defaultControl.style.isDefault = false;
8754                master.defaultControl = this;
8755             }
8756             else if(master.defaultControl == this)
8757                master.defaultControl = null;
8758
8759             // Update(null);
8760          }
8761          style.isDefault = value;
8762          if(created)
8763             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8764       }
8765       get { return style.isDefault; }
8766    };
8767
8768    property bool drawBehind
8769    {
8770       property_category $"Window Style"
8771       set { style.drawBehind = value; }
8772       get { return style.drawBehind; }
8773    };
8774
8775    property bool hasMenuBar
8776    {
8777       property_category $"Window Style"
8778       set
8779       {
8780          if(value)
8781          {
8782             if(!menu)
8783             {
8784                menu = Menu { };
8785                incref menu;
8786             }
8787             if(created && !menuBar)
8788             {
8789                menuBar =
8790                   PopupMenu
8791                   {
8792                      this, menu = menu,
8793                      isMenuBar = true,
8794                      anchor = Anchor { top = 23, left = 1, right = 1 },
8795                      size.h = 24,
8796                      inactive = true, nonClient = true
8797                   };
8798                menuBar.Create();
8799             }
8800          }
8801          else if(created && menuBar)
8802          {
8803             menuBar.Destroy(0);
8804             menuBar = null;
8805          }
8806          style.hasMenuBar = value;
8807       }
8808       get { return style.hasMenuBar; }
8809    };
8810
8811    property bool hasStatusBar
8812    {
8813       property_category $"Window Style"
8814       set
8815       {
8816          if(value)
8817          {
8818             if(!statusBar)
8819             {
8820                statusBar = StatusBar { this };
8821                incref statusBar;
8822                if(created)
8823                   statusBar.Create();
8824             }
8825          }
8826          else if(statusBar)
8827             delete statusBar;
8828          style.hasStatusBar = value;
8829       }
8830       get { return style.hasStatusBar; }
8831    };
8832    property bool stayOnTop
8833    {
8834       property_category $"Window Style"
8835       set
8836       {
8837          if(value)
8838          {
8839             if(created && !style.stayOnTop)
8840             {
8841                if(rootWindow == this)
8842                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8843                else if(parent.children.last != this)
8844                {
8845                   parent.children.Move(this, parent.children.last);
8846                   Update(null);
8847                }
8848             }
8849             style.stayOnTop = true;
8850          }
8851          else
8852          {
8853             if(created && style.stayOnTop)
8854             {
8855                if(rootWindow == this)
8856                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8857                else
8858                {
8859                   Window last;
8860                   if(order)
8861                   {
8862                      OldLink order;
8863                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev;
8864                          order && ((Window)order.data).style.stayOnTop;
8865                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8866                       last = order ? order.data : null;
8867                   }
8868                   else
8869                   {
8870                      for(last = parent.children.last;
8871                          last && last.style.stayOnTop;
8872                          last = last.prev);
8873                   }
8874
8875                   parent.children.Move(this, last);
8876                   Update(null);
8877                }
8878             }
8879             style.stayOnTop = false;
8880          }
8881       }
8882       get { return style.stayOnTop; }
8883    };
8884
8885    property Menu menu
8886    {
8887       property_category $"Window Style"
8888       set
8889       {
8890          delete menu;
8891          if(value)
8892          {
8893             menu = value;
8894             incref menu;
8895          }
8896
8897          if(menuBar && !value)
8898          {
8899             menuBar.Destroy(0);
8900             menuBar = null;
8901          }
8902          if(created)
8903          {
8904             if(!menuBar && style.hasMenuBar && value)
8905             {
8906                menuBar = PopupMenu
8907                          {
8908                             this, menu = value, isMenuBar = true,
8909                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24,
8910                             inactive = true, nonClient = true
8911                          };
8912                 menuBar.Create();
8913             }
8914             UpdateActiveDocument(null);
8915          }
8916       }
8917       get { return menu; }
8918    };
8919
8920    property FontResource font
8921    {
8922       property_category $"Appearance"
8923       watchable
8924       isset { return setFont ? true : false; }
8925       set
8926       {
8927          if(this)
8928          {
8929             if(value && !setFont) { stopwatching(parent, font); }
8930             else if(!value && setFont)
8931             {
8932                watch(parent)
8933                {
8934                   font
8935                   {
8936                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8937                      firewatchers font;
8938                      Update(null);
8939                   }
8940                };
8941             }
8942
8943             if(setFont)
8944             {
8945                RemoveResource(setFont);
8946                delete setFont;
8947             }
8948             if(systemFont)
8949             {
8950                RemoveResource(systemFont);
8951                delete systemFont;
8952             }
8953             setFont = value;
8954             if(setFont)
8955             {
8956                incref setFont;
8957                AddResource(setFont);
8958             }
8959
8960             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8961             if(!usedFont)
8962             {
8963                systemFont = guiApp.currentSkin.SystemFont();
8964                incref systemFont;
8965                usedFont = systemFont;
8966                AddResource(systemFont);
8967             }
8968
8969             firewatchers;
8970
8971             Update(null);
8972          }
8973       }
8974       get { return usedFont; }
8975    };
8976
8977    property SizeAnchor sizeAnchor
8978    {
8979       property_category $"Layout"
8980       isset
8981       {
8982          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8983                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8984             sizeAnchor.isClientW != sizeAnchor.isClientH;
8985       }
8986       set
8987       {
8988          int x, y, w, h;
8989          sizeAnchor = value;
8990
8991          normalSizeAnchor = sizeAnchor;
8992
8993          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8994          {
8995             stateAnchor = normalAnchor;
8996             stateSizeAnchor = normalSizeAnchor;
8997
8998             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8999             Position(x,y, w, h, true, true, true, true, false, true);
9000          }
9001       }
9002       get
9003       {
9004          value =
9005          {
9006             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
9007             sizeAnchor.isClientW,
9008             sizeAnchor.isClientH
9009          };
9010       }
9011    };
9012
9013    property Size size
9014    {
9015       property_category $"Layout"
9016       isset
9017       {
9018          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
9019                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
9020             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
9021       }
9022       set
9023       {
9024          int x, y, w, h;
9025
9026          sizeAnchor.isClientW = false;
9027          sizeAnchor.isClientH = false;
9028          sizeAnchor.size = value;
9029
9030          normalSizeAnchor = sizeAnchor;
9031
9032          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
9033          {
9034             stateAnchor = normalAnchor;
9035             stateSizeAnchor = normalSizeAnchor;
9036
9037             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
9038             Position(x, y, w, h, true, true, true, true, false, true);
9039             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
9040          }
9041       }
9042       get { value = size; }
9043    };
9044
9045    property Size clientSize
9046    {
9047       property_category $"Layout"
9048       isset
9049       {
9050          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
9051                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
9052             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
9053       }
9054       set
9055       {
9056          int x, y, w, h;
9057          sizeAnchor.isClientW = true;
9058          sizeAnchor.isClientH = true;
9059          sizeAnchor.size = value;
9060
9061          normalSizeAnchor = sizeAnchor;
9062
9063          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
9064          {
9065             stateAnchor = normalAnchor;
9066             stateSizeAnchor = normalSizeAnchor;
9067
9068             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
9069             Position(x,y, w, h, true, true, true, true, false, true);
9070             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
9071          }
9072       }
9073       get { value = this ? clientSize : { 0, 0 }; }
9074    };
9075
9076    property Size initSize { get { value = sizeAnchor.size; } };
9077
9078    property Anchor anchor
9079    {
9080       property_category $"Layout"
9081       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
9082
9083       set
9084       {
9085          if(value != null)
9086          {
9087             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
9088             {
9089                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
9090                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
9091             }
9092             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
9093             {
9094                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
9095                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
9096             }
9097             anchor = value;
9098
9099             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type))
9100             {
9101                anchor.left.distance = 0;
9102                anchor.horz.type = 0;
9103             }
9104             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
9105             {
9106                anchor.top.distance = 0;
9107                anchor.vert.type = 0;
9108             }
9109
9110             anchored = true;
9111
9112             //if(created)
9113             {
9114                int x, y, w, h;
9115
9116                normalAnchor = anchor;
9117
9118                // Break the anchors for moveable/resizable windows
9119                /*if(style.fixed ) //&& value.left.type == cascade)
9120                {
9121                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
9122
9123                   this.anchor = normalAnchor = Anchor { left = x, top = y };
9124                   normalSizeAnchor = SizeAnchor { { w, h } };
9125                   anchored = false;
9126                }*/
9127                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
9128                {
9129                   stateAnchor = normalAnchor;
9130                   stateSizeAnchor = normalSizeAnchor;
9131
9132                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
9133                   Position(x, y, w, h, true, true, true, true, false, true);
9134                }
9135             }
9136          }
9137          else
9138          {
9139             anchored = false;
9140          }
9141       }
9142       get { value = this ? anchor : Anchor { }; }
9143    };
9144
9145    property Point position
9146    {
9147       property_category $"Layout"
9148       set
9149       {
9150          if(value == null) return;
9151
9152          anchor.left = value.x;
9153          anchor.top  = value.y;
9154          anchor.right.type = none;
9155          anchor.bottom.type = none;
9156          //if(created)
9157          {
9158             int x, y, w, h;
9159
9160             normalAnchor = anchor;
9161
9162             // Break the anchors for moveable/resizable windows
9163             /*
9164             if(style.fixed)
9165             {
9166                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
9167
9168                normalAnchor.left = x;
9169                normalAnchor.top = y;
9170                normalAnchor.right.type = none;
9171                normalAnchor.bottom.type = none;
9172                normalSizeAnchor.size.width = w;
9173                normalSizeAnchor.size.height = h;
9174                anchored = false;
9175             }
9176             */
9177             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
9178             {
9179                stateAnchor = normalAnchor;
9180                stateSizeAnchor = normalSizeAnchor;
9181
9182                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
9183                Position(x,y, w, h, true, true, true, true, false, true);
9184             }
9185          }
9186       }
9187       get { value = position; }
9188    };
9189
9190    property bool disabled
9191    {
9192       property_category $"Behavior"
9193       set
9194       {
9195          if(this && disabled != value)
9196          {
9197             disabled = value;
9198             if(created)
9199                Update(null);
9200          }
9201       }
9202       get { return (bool)disabled; }
9203    };
9204
9205    property bool isEnabled
9206    {
9207       get
9208       {
9209          Window parent;
9210          for(parent = this; parent; parent = parent.parent)
9211             if(parent.disabled)
9212                return false;
9213          return true;
9214       }
9215    };
9216
9217    property WindowState state
9218    {
9219       property_category $"Behavior"
9220       set { SetState(value, false, 0); }
9221       get { return this ? state : 0; }
9222    };
9223
9224    property bool visible
9225    {
9226       property_category $"Behavior"
9227       set
9228       {
9229          if(this && !value && !style.hidden && parent)
9230          {
9231             bool wasActiveChild = parent.activeChild == this;
9232             Window client = null;
9233
9234             style.hidden = true;
9235             if(style.isActiveClient)
9236             {
9237                parent.numPositions--;
9238                if(state == minimized) parent.numIcons--;
9239             }
9240
9241             if(created)
9242             {
9243                OldLink prevOrder = null;
9244
9245                if(rootWindow == this)
9246                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
9247                else
9248                {
9249                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
9250                   if(style.nonClient)
9251                   {
9252                      box.left   -= parent.clientStart.x;
9253                      box.top    -= parent.clientStart.y;
9254                      box.right  -= parent.clientStart.x;
9255                      box.bottom -= parent.clientStart.y;
9256                   }
9257                   parent.Update(box);
9258                }
9259                if(_isModal && master && master.modalSlave == this)
9260                   master.modalSlave = null;
9261
9262                if(order)
9263                {
9264                   OldLink tmpPrev = order.prev;
9265                   client = tmpPrev ? tmpPrev.data : null;
9266                   if(client && !client.style.hidden && !client.destroyed && client.created)
9267                      prevOrder = tmpPrev;
9268                   for(;;)
9269                   {
9270                      client = tmpPrev ? tmpPrev.data : null;
9271                      if(client == this) { client = null; break; }
9272                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
9273                      {
9274                         tmpPrev = client.order.prev;
9275                      }
9276                      else
9277                      {
9278                         if(client)
9279                            prevOrder = tmpPrev;
9280                         break;
9281                      }
9282                   }
9283
9284                   // If this window can be an active client, make sure the next window we activate can also be one
9285                   if(!style.nonClient && style.isActiveClient)
9286                   {
9287                      tmpPrev = prevOrder;
9288                      for(;;)
9289                      {
9290                         client = tmpPrev ? tmpPrev.data : null;
9291                         if(client == this) { client = null; break; }
9292                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
9293                         {
9294                            tmpPrev = client.order.prev;
9295                         }
9296                         else
9297                         {
9298                            if(client)
9299                               prevOrder = tmpPrev;
9300                            break;
9301                         }
9302                      }
9303                      if(client && client.style.hidden) client = null;
9304                   }
9305                }
9306
9307                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
9308                {
9309                   if(order && prevOrder && prevOrder.data != this)
9310                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
9311                   else
9312                      ActivateEx(false, false, false, true, null, null);
9313
9314                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
9315                   if(parent.activeClient == this)
9316                   {
9317                      parent.activeClient = null;
9318                      parent.UpdateActiveDocument(null);
9319                   }
9320                }
9321                else if(parent.activeClient == this)
9322                {
9323                   parent.activeClient = client;
9324                   parent.UpdateActiveDocument(this);
9325                }
9326
9327                // *** Not doing this anymore ***
9328               /*
9329                if(cycle)
9330                   parent.childrenCycle.Delete(cycle);
9331                if(order)
9332                   parent.childrenOrder.Delete(order);
9333                cycle = null;
9334                order = null;
9335                */
9336
9337                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9338             }
9339
9340             firewatchers;
9341          }
9342          else if(this && value && style.hidden)
9343          {
9344             style.hidden = false;
9345             if(created)
9346             {
9347                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9348                if(rootWindow == this)
9349                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
9350
9351                if(_isModal && master)
9352                   master.modalSlave = this;
9353
9354                if(style.isActiveClient)
9355                {
9356                   positionID = parent.GetPositionID(this);
9357                   parent.numPositions++;
9358                   if(state == minimized) parent.numIcons++;
9359                }
9360
9361                // *** NOT DOING THIS ANYMORE ***
9362                /*
9363                if(!(style.inactive))
9364                {
9365                   if(!(style.noCycle))
9366                   {
9367                      cycle = parent.childrenCycle.AddAfter(
9368                         (parent.activeChild && parent.activeChild.cycle) ?
9369                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
9370                      cycle.data = this;
9371                   }
9372                   order = parent.childrenOrder.AddAfter(
9373                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
9374                      sizeof(OldLink));
9375                   order.data = this;
9376                }
9377                */
9378
9379                /*
9380                if(true || !parent.activeChild)
9381                   ActivateEx(true, false, true, true, null, null);
9382                */
9383                if(creationActivation == activate && guiApp.desktop.active)
9384                   ActivateEx(true, false, true, true, null, null);
9385                else if((creationActivation == activate || creationActivation == flash) && !object)
9386                {
9387                   MakeActive();
9388                   if(this == rootWindow)
9389                      Flash();
9390                }
9391
9392                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9393                Update(null);
9394
9395                // rootWindow.
9396                ConsequentialMouseMove(false);
9397             }
9398
9399             firewatchers;
9400          }
9401          else if(this)
9402             style.hidden = !value;
9403       }
9404
9405       get { return (style.hidden || !setVisible) ? false : true; }
9406    };
9407
9408    property bool isDocument
9409    {
9410       property_category $"Document"
9411       set { style.isDocument = value; if(value) SetupFileMonitor(); }
9412       get { return style.isDocument; }
9413    };
9414
9415    property bool mergeMenus
9416    {
9417       property_category $"Window Style"
9418       set { mergeMenus = value; }
9419       get { return (bool)mergeMenus; }
9420    };
9421
9422    property bool hasHorzScroll
9423    {
9424       property_category $"Window Style"
9425       set
9426       {
9427          if(value)
9428          {
9429             if(!style.hasHorzScroll && created)
9430             {
9431                CreateSystemChildren();
9432                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9433             }
9434          }
9435          else if(style.hasHorzScroll)
9436          {
9437             sbh.Destroy(0);
9438             sbh = null;
9439             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9440          }
9441          style.hasHorzScroll = value;
9442       }
9443
9444       get { return style.hasHorzScroll; }
9445    };
9446
9447    property bool hasVertScroll
9448    {
9449       property_category $"Window Style"
9450       set
9451       {
9452          if(value)
9453          {
9454             if(!style.hasVertScroll && created)
9455             {
9456                style.hasVertScroll = true;
9457                CreateSystemChildren();
9458                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9459             }
9460          }
9461          else if(style.hasVertScroll)
9462          {
9463             sbv.Destroy(0);
9464             sbv = null;
9465             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9466          }
9467          style.hasVertScroll = value;
9468       }
9469       get { return style.hasVertScroll; }
9470    };
9471
9472    property bool dontHideScroll
9473    {
9474       property_category $"Behavior"
9475       set
9476       {
9477          scrollFlags.dontHide = value;
9478          if(value)
9479          {
9480             //UpdateScrollBars(true, true);
9481             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9482          }
9483          else
9484          {
9485             // UpdateScrollBars(true, true);
9486             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9487          }
9488       }
9489       get { return scrollFlags.dontHide; }
9490    };
9491
9492    property bool dontScrollVert
9493    {
9494       property_category $"Behavior"
9495       set { style.dontScrollVert = value; }
9496       get { return style.dontScrollVert; }
9497    };
9498    property bool dontScrollHorz
9499    {
9500       property_category $"Behavior"
9501       set { style.dontScrollHorz = value; }
9502       get { return style.dontScrollHorz; }
9503    };
9504
9505    property bool snapVertScroll
9506    {
9507       property_category $"Behavior"
9508       set
9509       {
9510          scrollFlags.snapY = value;
9511          if(sbv) sbv.snap = value;
9512       }
9513       get { return scrollFlags.snapY; }
9514    };
9515    property bool snapHorzScroll
9516    {
9517        property_category $"Behavior"
9518       set
9519       {
9520          scrollFlags.snapX = value;
9521          if(sbh) sbh.snap = value;
9522       }
9523       get { return scrollFlags.snapX; }
9524    };
9525
9526    property Point scroll
9527    {
9528       property_category $"Behavior"
9529       set { if(this) SetScrollPosition(value.x, value.y); }
9530       get { value = scroll; }
9531    };
9532
9533    property bool modifyVirtualArea
9534    {
9535       property_category $"Behavior"
9536       set { modifyVirtArea = value; }
9537       get { return (bool)modifyVirtArea; }
9538    };
9539
9540    property bool dontAutoScrollArea
9541    {
9542       property_category $"Behavior"
9543       // Activating a child control out of view will automatically scroll to make it in view
9544       set { noAutoScrollArea = value; }
9545       get { return (bool)noAutoScrollArea; }
9546    };
9547
9548    property const char * fileName
9549    {
9550       property_category $"Document"
9551       set
9552       {
9553          SetupFileMonitor();
9554
9555          if(menu && ((!fileName && value) || (fileName && !value)))
9556          {
9557             MenuItem item = menu.FindItem(MenuFileSave, 0);
9558             if(item) item.disabled = !modifiedDocument && value;
9559          }
9560
9561          delete fileName;
9562
9563          if(value && value[0])
9564             fileName = CopyString(value);
9565
9566          if(parent && this == parent.activeClient)
9567             parent.UpdateActiveDocument(null);
9568          else
9569             UpdateCaption();
9570
9571          // if(style.isDocument)
9572 #if !defined(__EMSCRIPTEN__)
9573          if(!saving)
9574             fileMonitor.fileName = value;
9575 #endif
9576       }
9577       get { return fileName; }
9578    };
9579
9580    property int64 id
9581    {
9582       property_category $"Data"
9583       set { id = value; }
9584       get { return id; }
9585    };
9586
9587    property bool modifiedDocument
9588    {
9589       property_category $"Document"
9590       set
9591       {
9592          if(style.isDocument || fileName)
9593          {
9594             if(menu)
9595             {
9596                MenuItem item = menu.FindItem(MenuFileSave, 0);
9597                if(item) item.disabled = !value && fileName;
9598             }
9599          }
9600
9601          if(modifiedDocument != value)
9602          {
9603             modifiedDocument = value;
9604             if(style.isDocument || fileName)
9605                UpdateCaption();
9606          }
9607       }
9608       get { return (bool)modifiedDocument; }
9609    };
9610
9611    property bool showInTaskBar
9612    {
9613       property_category $"Window Style"
9614       set
9615       {
9616          style.showInTaskBar = value;
9617 #if defined(__WIN32__)
9618          Win32UpdateStyle(this);
9619 #endif
9620       }
9621       get { return style.showInTaskBar; }
9622    };
9623    property FileDialog saveDialog { set { saveDialog = value; } };
9624    property bool isActiveClient
9625    {
9626       property_category $"Behavior"
9627       set
9628       {
9629          if(parent && style.isActiveClient != value && !style.hidden)
9630          {
9631             if(value)
9632             {
9633                if(state == minimized) parent.numIcons++;
9634                parent.numPositions++;
9635             }
9636             else
9637             {
9638                if(state == minimized) parent.numIcons--;
9639                parent.numPositions--;
9640             }
9641          }
9642          style.isActiveClient = value;
9643       }
9644       get { return style.isActiveClient; }
9645    };
9646
9647    property Cursor cursor
9648    {
9649       property_category $"Appearance"
9650       set
9651       {
9652          cursor = value;
9653          SelectMouseCursor();
9654       }
9655       get { return cursor; }
9656    };
9657
9658 //#if !defined(ECERE_VANILLA)
9659    property const char * name
9660    {
9661       property_category $"Design"
9662       get
9663       {
9664          return (this && object) ? object.name : null;
9665       }
9666       set
9667       {
9668          if(activeDesigner)
9669             activeDesigner.RenameObject(object, value);
9670       }
9671    };
9672 //#endif
9673    property const char * displayDriver
9674    {
9675       property_category $"Behavior"
9676       set
9677       {
9678          dispDriver = GetDisplayDriver(value);
9679          //DisplayModeChanged();
9680       }
9681       get
9682       {
9683          return dispDriver ? dispDriver.name : null;
9684       }
9685    }
9686
9687    // RUNTIME PROPERTIES
9688    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9689    property Size scrollArea
9690    {
9691       property_category $"Behavior"
9692       set
9693       {
9694          if(value != null)
9695             SetScrollArea(value.w, value.h, false);
9696          else
9697             SetScrollArea(0,0, true);
9698       }
9699       get { value = scrollArea; }
9700       isset
9701       {
9702          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9703       }
9704    };
9705    property bool is3D
9706    {
9707       property_category $"Layout"
9708       set { if(this) is3D = value; }
9709       get { return (bool)is3D; }
9710    };
9711
9712    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9713
9714    // Will be merged with font later
9715    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9716    property Point clientStart { get { value = clientStart; } };
9717    property Point absPosition { get { value = absPosition; } };
9718    property Anchor normalAnchor { get { value = normalAnchor; } };
9719    property SizeAnchor normalSizeAnchor { get { value = normalSizeAnchor; } };
9720    property bool active { get { return (bool)active; } };
9721    property bool created { get { return (bool)created; } };
9722    property bool destroyed { get { return (bool)destroyed; } };
9723    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9724    property Window firstChild { get { return children.first; } };
9725    property Window lastChild { get { return children.last; } };
9726    property Window activeClient { get { return activeClient; } };
9727    property Window activeChild { get { return activeChild; } };
9728    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9729    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9730    property ScrollBar horzScroll { get { return sbh; } };
9731    property ScrollBar vertScroll { get { return sbv; } };
9732    property StatusBar statusBar { get { return statusBar; } };
9733    property Window rootWindow { get { return rootWindow; } };
9734    property bool closing { get { return (bool)closing; } set { closing = value; } };
9735    property int documentID { get { return documentID; } };
9736    property Window previous { get { return prev; } }
9737    property Window next { get { return next; } }
9738    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9739    property PopupMenu menuBar { get { return menuBar; } }
9740    property ScrollBar sbv { get { return sbv; } }
9741    property ScrollBar sbh { get { return sbh; } }
9742    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9743    property void * systemHandle { get { return windowHandle; } }
9744    property Button minimizeButton { get { return sysButtons[0]; } };
9745    property Button maximizeButton { get { return sysButtons[1]; } };
9746    property Button closeButton { get { return sysButtons[2]; } };
9747    property BitmapResource icon
9748    {
9749       get { return icon; }
9750       set
9751       {
9752          icon = value;
9753          if(icon) incref icon;
9754          if(created)
9755             guiApp.interfaceDriver.SetIcon(this, value);
9756       }
9757    };
9758    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9759    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; if(value) nativeDecorations = false; /* Native Decorations are not supported with alphaBlend */ } };
9760    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9761    property GLCapabilities glCapabilities
9762    {
9763       get { return glCapabilities; }
9764       set
9765       {
9766          bool reload = display != null &&
9767             (glCapabilities.nonPow2Textures != value.nonPow2Textures ||
9768              glCapabilities.intAndDouble != value.intAndDouble ||
9769              glCapabilities.vertexBuffer != value.vertexBuffer ||
9770              glCapabilities.compatible != value.compatible ||
9771              glCapabilities.legacyFormats != value.legacyFormats ||
9772              glCapabilities.debug != value.debug ||
9773              glCapabilities.vertexPointer != value.vertexPointer ||
9774              glCapabilities.quads != value.quads);
9775          guiApp.modeSwitching = true;
9776          if(reload)
9777             UnloadGraphics(false);
9778
9779          glCapabilities = value;
9780
9781          if(reload)
9782          {
9783             if(SetupDisplay())
9784                LoadGraphics(false, false);
9785          }
9786          else if(display)
9787             display.glCapabilities = value;
9788          guiApp.modeSwitching = false;
9789       }
9790    };
9791    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9792    property bool nativeDecorations
9793    {
9794       get { return (bool)nativeDecorations; }
9795       set { nativeDecorations = value; }
9796 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
9797       isset
9798       {
9799          //return (nativeDecorations && (rootWindow == this || (formDesigner && activeDesigner && ((FormDesigner)activeDesigner.classDesigner).form && parent == ((FormDesigner)activeDesigner.classDesigner).form.parent))) != style.fixed;
9800          bool result = false;
9801          if(nativeDecorations)
9802          {
9803             if(rootWindow == this)
9804                result = true;
9805             else
9806             {
9807                if(formDesigner && activeDesigner)
9808                {
9809                   FormDesigner cd = (FormDesigner)activeDesigner.classDesigner;
9810                   Window form = cd ? cd.form : null;
9811                   if(form && parent == form.parent)
9812                      result = true;
9813                }
9814             }
9815          }
9816          return result != style.fixed;
9817       }
9818 #endif
9819    };
9820    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9821
9822    property const char * text
9823    {
9824       property_category $"Deprecated"
9825       watchable
9826       set { property::caption = value; }
9827       get { return property::caption; }
9828    }
9829 private:
9830    // Data
9831    //char * yo;
9832    Window prev, next;
9833    WindowBits style;       // Window Style
9834    char * caption;            // Name / Caption
9835    Window parent;    // Parent window
9836    OldList children;          // List of children in Z order
9837    Window activeChild;     // Child window having focus
9838    Window activeClient;
9839    Window previousActive;  // Child active prior to activating the default child
9840    Window master;          // Window owning and receiving notifications concerning this window
9841    OldList slaves;            // List of windows belonging to this window
9842    Display display;        // Display this window is drawn into
9843
9844    Point position;         // Position in parent window client area
9845    Point absPosition;      // Absolute position
9846    Point clientStart;      // Client area position from (0,0) in this window
9847    Size size;              // Size
9848    Size clientSize;        // Client area size
9849    Size scrollArea;        // Virtual Scroll area size
9850    Size reqScrollArea;     // Requested virtual area size
9851    Point scroll;           // Virtual area scrolling position
9852    ScrollBar sbh, sbv;        // Scrollbar window handles
9853    Cursor cursor;        // Mouse cursor used for this window
9854    WindowState state;
9855    PopupMenu menuBar;
9856    StatusBar statusBar;
9857    Button sysButtons[3];
9858    char * fileName;
9859    Box clientArea;         // Client Area box clipped to parent
9860    Key setHotKey;
9861    HotKeySlot hotKey;        // HotKey for this window
9862    int numDocuments;
9863    int numPositions;
9864    Menu menu;
9865    ScrollFlags scrollFlags;// Window Scrollbar Flags
9866    int64 id;                 // Control ID
9867    int documentID;
9868    ColorAlpha background;  // Background color used to draw the window area
9869    Color foreground;
9870    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9871    OldList childrenCycle;     // Cycling order
9872    OldLink cycle;             // Element of parent's cycling order
9873    OldList childrenOrder;     // Circular Z-Order
9874    OldLink order;             // Element of parent's circular Z-Order
9875    Window modalSlave;      // Slave window blocking this window's interaction
9876
9877    Window rootWindow;      // Topmost system managed window
9878    void * windowHandle;    // System window handle
9879
9880    DialogResult returnCode;// Return code for modal windows
9881
9882    Point sbStep;           // Scrollbar line scrolling steps
9883
9884    Anchor stateAnchor;
9885    SizeAnchor stateSizeAnchor;
9886
9887    Anchor normalAnchor;
9888    SizeAnchor normalSizeAnchor;
9889
9890    Size skinMinSize;       // Minimal window size based on style
9891    Point scrolledPos;      // Scrolled position
9892    Box box;                // Window box clipped to parent
9893    Box * against;          // What to clip the box to
9894
9895    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9896    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9897    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9898    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9899    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9900    Point scrolledArea;     // Distance to scroll area by
9901    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9902
9903    OldList hotKeys;           // List of the hotkeys of all children
9904    Window defaultControl;  // Default child control
9905    Size minSize;
9906    Size maxSize;
9907
9908    ColorAlpha * palette;   // Color palette used for this window
9909
9910    int caretSize;          // Size of caret, non zero if a caret is present
9911    Point caretPos;         // Caret position
9912
9913    void * systemParent;    // Parent System Window for embedded windows
9914
9915    int iconID;
9916    int numIcons;
9917    int positionID;
9918
9919 #if !defined(__EMSCRIPTEN__)
9920    Mutex mutex;
9921 #endif
9922    WindowState lastState;
9923
9924 #if !defined(__EMSCRIPTEN__)
9925    FileMonitor fileMonitor;
9926 #endif
9927
9928    FontResource setFont, systemFont;
9929    FontResource usedFont;
9930    FontResource captionFont;
9931    OldList resources;
9932    FileDialog saveDialog;
9933    Anchor anchor;
9934    SizeAnchor sizeAnchor;
9935
9936    // FormDesigner data
9937    ObjectInfo object;
9938    Window control;
9939    Extent * tempExtents; //[4];
9940    BitmapResource icon;
9941    void * windowData;
9942    CreationActivationOption creationActivation;
9943    GLCapabilities glCapabilities;
9944    glCapabilities = { true, true, true, true, true, true, true, true, true /*false*/, true, true, true, true, true, true, true };
9945    struct
9946    {
9947       bool active:1;            // true if window and ancestors are active
9948       bool acquiredInput:1;     // true if the window is processing state based input
9949       bool modifiedDocument:1;
9950       bool disabled:1;          // true if window cannot interact
9951       bool isForegroundWindow:1;// true while a root window is being activated
9952       bool visible:1;           // Visibility flag
9953       bool destroyed:1;         // true if window is being destroyed
9954       bool anchored:1;          // true if this window is repositioned when the parent resizes
9955       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9956       bool mouseInside:1;
9957       bool positioned:1;
9958       bool created:1;
9959       bool is3D:1;
9960       bool mergeMenus:1;
9961       bool modifyVirtArea:1;
9962       bool noAutoScrollArea:1;
9963       bool closing:1;
9964       bool autoCreate:1;
9965       bool setVisible:1;      // FOR FORM DESIGNER
9966       bool wasCreated:1;
9967       bool fullRender:1;
9968       bool moveable:1;
9969       bool alphaBlend:1;
9970       bool composing:1;
9971       bool useSharedMemory:1;
9972       bool resized:1;
9973       bool saving:1;
9974       bool nativeDecorations:1;
9975       bool manageDisplay:1;
9976       bool formDesigner:1; // True if we this is running in the form editor
9977       bool requireRemaximize:1;
9978       bool noConsequential:1;
9979    };
9980
9981    // Checks used internally for them not to take effect in FormDesigner
9982    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
9983    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
9984
9985    WindowController controller;
9986
9987    public property WindowController controller
9988    {
9989       get { return controller; }
9990       set
9991       {
9992          if(controller)
9993             controller.setWindow(null);
9994          delete controller;
9995          controller = value;
9996          if(controller)
9997          {
9998             incref controller;
9999             controller.setWindow(this);
10000          }
10001       }
10002    }
10003
10004    public property bool noConsequential
10005    {
10006       set { noConsequential = value; }
10007       get { return noConsequential; }
10008    }
10009 };
10010
10011 public class CommonControl : Window
10012 {
10013    // creationActivation = doNothing;
10014
10015    ToolTip toolTip;
10016    public property const String toolTip
10017    {
10018       property_category $"Appearance"
10019       set
10020       {
10021          if(created) CommonControl::OnDestroy();
10022          delete toolTip;
10023          toolTip = value ? ToolTip { tip = value; } : null;
10024          incref toolTip;
10025          if(created) CommonControl::OnCreate();
10026       }
10027       get { return toolTip ? toolTip.tip : null; }
10028    }
10029
10030    void OnDestroy()
10031    {
10032       if(toolTip)
10033          // (Very) Ugly work around for the fact that the parent watcher
10034          // won't fire when it's already been disconnected...
10035          eInstance_FireSelfWatchers(toolTip,
10036             __ecereProp___ecereNameSpace__ecere__gui__Window_parent);
10037    }
10038
10039    bool OnCreate()
10040    {
10041       if(toolTip)
10042          toolTip.parent = this;
10043       return true;
10044    }
10045    ~CommonControl()
10046    {
10047       delete toolTip;
10048    }
10049 };
10050
10051 public class Percentage : float
10052 {
10053    const char * OnGetString(char * string, float * fieldData, bool * needClass)
10054    {
10055       int c;
10056       int last = 0;
10057       sprintf(string, "%.2f", this);
10058       c = strlen(string)-1;
10059       for( ; c >= 0; c--)
10060       {
10061          if(string[c] != '0')
10062             last = Max(last, c);
10063          if(string[c] == '.')
10064          {
10065             if(last == c)
10066                string[c] = 0;
10067             else
10068                string[last+1] = 0;
10069             break;
10070          }
10071       }
10072       return string;
10073    }
10074 };
10075
10076 public void ApplySkin(Class c, const char * name, void ** vTbl)
10077 {
10078    char className[1024];
10079    Class sc;
10080    OldLink d;
10081    int m;
10082
10083    subclass(Window) wc = (subclass(Window))c;
10084    subclass(Window) base = (subclass(Window))c.base;
10085
10086    sprintf(className, "%sSkin_%s", name, c.name);
10087    wc.pureVTbl = c._vTbl;
10088    c._vTbl = new void *[c.vTblSize];
10089    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
10090    sc = eSystem_FindClass(c.module.application, className);
10091
10092    if(vTbl)
10093    {
10094       for(m = 0; m < c.base.vTblSize; m++)
10095       {
10096          if(c._vTbl[m] == base.pureVTbl[m])
10097             c._vTbl[m] = vTbl[m];
10098       }
10099    }
10100    if(sc)
10101    {
10102       for(m = 0; m < c.vTblSize; m++)
10103       {
10104          if(sc._vTbl[m] != wc.pureVTbl[m])
10105             c._vTbl[m] = sc._vTbl[m];
10106       }
10107    }
10108
10109    for(d = c.derivatives.first; d; d = d.next)
10110    {
10111       ApplySkin(d.data, name, c._vTbl);
10112    }
10113 }
10114
10115 public void UnapplySkin(Class c)
10116 {
10117    subclass(Window) wc = (subclass(Window))c;
10118    OldLink d;
10119
10120    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
10121    {
10122       delete c._vTbl;
10123       c._vTbl = wc.pureVTbl;
10124       wc.pureVTbl = null;
10125    }
10126
10127    for(d = c.derivatives.first; d; d = d.next)
10128    {
10129       UnapplySkin(d.data);
10130    }
10131 }
10132 /*
10133 void CheckFontIntegrity(Window window)
10134 {
10135    Window c;
10136    if(window)
10137    {
10138       if(window.usedFont && window.usedFont.font == 0xecececec)
10139       {
10140          FontResource uf = window.usedFont;
10141          char * className = window._class.name;
10142          char * text = window.text;
10143          Print("");
10144       }
10145       for(c = window.firstChild; c; c = c.next)
10146          CheckFontIntegrity(c);
10147    }
10148 }*/
10149
10150 public class ControllableWindow : Window
10151 {
10152    /*WindowController controller;
10153    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
10154    ~ControllableWindow() { delete controller; }*/
10155 }
10156
10157 class WindowControllerInterface : ControllableWindow
10158 {
10159    bool OnKeyDown(Key key, unichar ch)
10160    {
10161       bool result = controller.OnKeyDown ? ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyDown)((Window)controller.controlled, controller, key, ch) : true;
10162       if(result)
10163       {
10164          bool (* onKeyDown)(Window, Key, unichar) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown];
10165          if(onKeyDown)
10166             result = onKeyDown(controller.window, key, ch);
10167       }
10168       return result;
10169    }
10170
10171    bool OnKeyUp(Key key, unichar ch)
10172    {
10173       bool result = controller.OnKeyUp ? ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyUp)((Window)controller.controlled, controller, key, ch) : true;
10174       if(result)
10175       {
10176          bool (* onKeyUp)(Window, Key, unichar) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp];
10177          if(onKeyUp)
10178             result = onKeyUp(controller.window, key, ch);
10179       }
10180       return result;
10181    }
10182
10183    bool OnKeyHit(Key key, unichar ch)
10184    {
10185       bool result = controller.OnKeyHit ? ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyHit)((Window)controller.controlled, controller, key, ch) : true;
10186       if(result)
10187       {
10188          bool (* onKeyHit)(Window, Key, unichar) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit];
10189          if(onKeyHit)
10190             result = onKeyHit(controller.window, key, ch);
10191       }
10192       return result;
10193    }
10194
10195    bool OnMouseMove(int x, int y, Modifiers mods)
10196    {
10197       bool result = controller.OnMouseMove ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMouseMove)((Window)controller.controlled, controller, x, y, mods) : true;
10198       if(result)
10199       {
10200          bool(* onMouseMove)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove];
10201          if(onMouseMove)
10202             result = onMouseMove(controller.window, x, y, mods);
10203       }
10204       return result;
10205    }
10206
10207    bool OnLeftButtonDown(int x, int y, Modifiers mods)
10208    {
10209       bool result = controller.OnLeftButtonDown ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonDown)((Window)controller.controlled, controller, x, y, mods) : true;
10210       if(result)
10211       {
10212          bool(* onLeftButtonDown)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown];
10213          if(onLeftButtonDown)
10214             result = onLeftButtonDown(controller.window, x, y, mods);
10215       }
10216       return result;
10217    }
10218
10219    bool OnLeftButtonUp(int x, int y, Modifiers mods)
10220    {
10221       bool result = controller.OnLeftButtonUp ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonUp)((Window)controller.controlled, controller, x, y, mods) : true;
10222       if(result)
10223       {
10224          bool(* onLeftButtonUp)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp];
10225          if(onLeftButtonUp)
10226             result = onLeftButtonUp(controller.window, x, y, mods);
10227       }
10228       return result;
10229    }
10230
10231    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
10232    {
10233       bool result = controller.OnLeftDoubleClick ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftDoubleClick)((Window)controller.controlled, controller, x, y, mods) : true;
10234       if(result)
10235       {
10236          bool(* onLeftDoubleClick)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick];
10237          if(onLeftDoubleClick)
10238             result = onLeftDoubleClick(controller.window, x, y, mods);
10239       }
10240       return result;
10241    }
10242
10243    bool OnRightButtonDown(int x, int y, Modifiers mods)
10244    {
10245       bool result = controller.OnRightButtonDown ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonDown)((Window)controller.controlled, controller, x, y, mods) : true;
10246       if(result)
10247       {
10248          bool(* onRightButtonDown)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown];
10249          if(onRightButtonDown)
10250             result = onRightButtonDown(controller.window, x, y, mods);
10251       }
10252       return result;
10253    }
10254
10255    bool OnRightButtonUp(int x, int y, Modifiers mods)
10256    {
10257       bool result = controller.OnRightButtonUp ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonUp)((Window)controller.controlled, controller, x, y, mods) : true;
10258       if(result)
10259       {
10260          bool(* onRightButtonUp)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp];
10261          if(onRightButtonUp)
10262             result = onRightButtonUp(controller.window, x, y, mods);
10263       }
10264       return result;
10265    }
10266
10267    bool OnRightDoubleClick(int x, int y, Modifiers mods)
10268    {
10269       bool result = controller.OnRightDoubleClick ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightDoubleClick)((Window)controller.controlled, controller, x, y, mods) : true;
10270       if(result)
10271       {
10272          bool(* onRightDoubleClick)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick];
10273          if(onRightDoubleClick)
10274             result = onRightDoubleClick(controller.window, x, y, mods);
10275       }
10276       return result;
10277    }
10278
10279    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
10280    {
10281       bool result = controller.OnMiddleButtonDown ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonDown)((Window)controller.controlled, controller, x, y, mods) : true;
10282       if(result)
10283       {
10284          bool(* onMiddleButtonDown)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown];
10285          if(onMiddleButtonDown)
10286             result = onMiddleButtonDown(controller.window, x, y, mods);
10287       }
10288       return result;
10289    }
10290
10291    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
10292    {
10293       bool result = controller.OnMiddleButtonUp ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonUp)((Window)controller.controlled, controller, x, y, mods) : true;
10294       if(result)
10295       {
10296          bool(* onMiddleButtonUp)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp];
10297          if(onMiddleButtonUp)
10298             result = onMiddleButtonUp(controller.window, x, y, mods);
10299       }
10300       return result;
10301    }
10302
10303    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
10304    {
10305       bool result = controller.OnMiddleDoubleClick ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleDoubleClick)((Window)controller.controlled, controller, x, y, mods) : true;
10306       if(result)
10307       {
10308          bool(* onMiddleDoubleClick)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick];
10309          if(onMiddleDoubleClick)
10310             onMiddleDoubleClick(controller.window, x, y, mods);
10311       }
10312       return result;
10313    }
10314
10315    bool OnMultiTouch(TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers mods)
10316    {
10317       bool result = controller.OnMultiTouch ? ((bool(*)(Window, WindowController, TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers))(void *)controller.OnMultiTouch)((Window)controller.controlled, controller, event, infos, mods) : true;
10318       if(result)
10319       {
10320          bool(* onMultiTouch)(Window, TouchPointerEvent, Array<TouchPointerInfo>, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMultiTouch];
10321          if(onMultiTouch)
10322             onMultiTouch(controller.window, event, infos, mods);
10323       }
10324       return result;
10325    }
10326
10327    void OnResize(int width, int height)
10328    {
10329       if(controller.OnResize)
10330          ((void(*)(Window, WindowController, int, int))(void *)controller.OnResize)((Window)controller.controlled, controller, width, height);
10331       {
10332          void(* onResize)(Window, int, int) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize];
10333          if(onResize)
10334             onResize(controller.window, width, height);
10335       }
10336    }
10337
10338    void OnRedraw(Surface surface)
10339    {
10340       if(controller.OnRedraw)
10341          ((void(*)(Window, WindowController, Surface))(void *)controller.OnRedraw)((Window)controller.controlled, controller, surface);
10342       {
10343          void(* onRedraw)(Window, Surface) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw];
10344          if(onRedraw)
10345             onRedraw(controller.window, surface);
10346       }
10347    }
10348
10349    bool OnCreate()
10350    {
10351       bool result = controller.OnCreate ? ((bool(*)(Window, WindowController))(void *)controller.OnCreate)((Window)controller.controlled, controller) : true;
10352       if(result)
10353       {
10354          bool(* onCreate)(Window) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate];
10355          if(onCreate)
10356             result = onCreate(controller.window);
10357       }
10358       return result;
10359    }
10360
10361    bool OnLoadGraphics()
10362    {
10363       bool result = controller.OnLoadGraphics ? ((bool(*)(Window, WindowController))(void *)controller.OnLoadGraphics)((Window)controller.controlled, controller) : true;
10364       if(result)
10365       {
10366          bool(* onLoadGraphics)(Window) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics];
10367          if(onLoadGraphics)
10368             result = onLoadGraphics(controller.window);
10369       }
10370       return result;
10371    }
10372
10373    void OnUnloadGraphics()
10374    {
10375       if(controller.OnUnloadGraphics)
10376          ((void(*)(Window, WindowController))(void *)controller.OnUnloadGraphics)((Window)controller.controlled, controller);
10377       {
10378          void(* onUnloadGraphics)(Window) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics];
10379          if(onUnloadGraphics)
10380             onUnloadGraphics(controller.window);
10381       }
10382    }
10383 }
10384
10385 public class WindowController<class V>
10386 {
10387    void setWindow(Window value)
10388    {
10389       uint size = class(Window).vTblSize;
10390       if(value)
10391       {
10392          delete windowVTbl;
10393          windowVTbl = new void *[size];
10394          memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
10395          if(value._vTbl == value._class._vTbl)
10396          {
10397             value._vTbl = new void *[value._class.vTblSize];
10398             memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
10399          }
10400          {
10401             int c;
10402             for(c = 0; c < size; c++)
10403             {
10404                void * function = class(WindowControllerInterface)._vTbl[c];
10405                if(function && function != DefaultFunction)
10406                   value._vTbl[c] = function;
10407                else
10408                   value._vTbl[c] = windowVTbl[c];
10409             }
10410          }
10411       }
10412       else if(window)
10413       {
10414          memcpy(window._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
10415          delete windowVTbl;
10416       }
10417       window = value;
10418    }
10419 public:
10420    property Window window
10421    {
10422       get { return window; }
10423    }
10424    property V controlled
10425    {
10426       set { controlled = value; }
10427       get { return controlled; }
10428    }
10429    // TODO: Add OnStateChange so we can implement SavedConfigWindow as a WindowController instead
10430    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
10431    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
10432    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
10433    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
10434    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
10435    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
10436    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10437    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
10438    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
10439    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10440    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
10441    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
10442    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10443    virtual bool V::OnMultiTouch(WindowController controller, TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers mods);
10444    virtual void V::OnResize(WindowController controller, int width, int height);
10445    virtual void V::OnRedraw(WindowController controller, Surface surface);
10446    virtual bool V::OnCreate(WindowController controller);
10447    virtual bool V::OnLoadGraphics(WindowController controller);
10448    virtual void V::OnUnloadGraphics(WindowController controller);
10449
10450 private:
10451    public int (** windowVTbl)();
10452    V controlled;
10453    Window window;
10454
10455    ~WindowController()
10456    {
10457       delete windowVTbl;
10458    }
10459 }