ecere/gui/Window: Enabling OpenGL Shaders by default
[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          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4584             status = OnSysKeyHit(key, character);
4585          else if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4586             status = OnSysKeyUp(key, character);
4587          if(!status)
4588          {
4589             delete this;
4590             return true;
4591          }
4592
4593          // Process Key Message for Internal UI Keyboard actions
4594          if(status && !destroyed && menuBar && state != minimized)
4595          {
4596             // Disable the ALT
4597             if((SmartKey)key != alt)
4598                menuBar.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown, 0, 0);
4599             if(menuBar.focus)
4600             {
4601                SmartKey sk = (SmartKey) key;
4602                if((character && !key.alt && !key.ctrl) || sk == left || sk == right || sk == up || sk == down || sk == home || sk == end || sk == escape || sk == alt)
4603                {
4604                   status = menuBar.KeyMessage(method, key, character);
4605                   status = false;
4606                }
4607                else
4608                {
4609                   if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4610                      menuBar.OnKeyHit(escape, 0);
4611                }
4612                if(!menuBar.focus && guiApp.caretOwner)
4613                   guiApp.caretOwner.UpdateCaret(true, false);
4614             }
4615          }
4616          if(!destroyed && status)
4617          {
4618             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4619             {
4620                switch(key)
4621                {
4622                   case left: case up: case right: case down:
4623                      if(guiApp.windowMoving == this)
4624                      {
4625                         int step = 1; //8;
4626                         int w = guiApp.windowMoving.size.w;
4627                         int h = guiApp.windowMoving.size.h;
4628                         int x = guiApp.windowMoving.scrolledPos.x;
4629                         int y = guiApp.windowMoving.scrolledPos.y;
4630
4631                         if(guiApp.textMode)
4632                         {
4633                            if(key == down || key == up)
4634                               step = Max(step, textCellH);
4635                            else
4636                               step = Max(step, textCellW);
4637                         }
4638
4639                         if(guiApp.windowIsResizing)
4640                         {
4641                            switch(key)
4642                            {
4643                               case left: w-=step; break;
4644                               case right: w+=step; break;
4645                               case up: h-=step;   break;
4646                               case down: h+=step; break;
4647                            }
4648                         }
4649                         else
4650                         {
4651                            switch(key)
4652                            {
4653                               case left: x-=step; break;
4654                               case right: x+=step; break;
4655                               case up: y-=step;   break;
4656                               case down: y+=step; break;
4657                            }
4658                         }
4659
4660                         if(guiApp.resizeX) x += w - guiApp.windowMoving.size.w;
4661                         if(guiApp.resizeY) y += h - guiApp.windowMoving.size.h;
4662
4663                         if(!guiApp.windowIsResizing || guiApp.resizeX)
4664                            x = (x - guiApp.windowMovingBefore.x) + guiApp.windowMovingStart.x;
4665                         else
4666                            x = (w - guiApp.windowResizingBefore.w) + guiApp.windowMovingStart.x;
4667
4668                         if(!guiApp.windowIsResizing || guiApp.resizeY)
4669                            y = (y - guiApp.windowMovingBefore.y) + guiApp.windowMovingStart.y;
4670                         else
4671                            y = (h - guiApp.windowResizingBefore.h) + guiApp.windowMovingStart.y;
4672
4673                         guiApp.interfaceDriver.SetMousePosition(x, y);
4674                         ConsequentialMouseMove(true);
4675
4676                         status = false;
4677                      }
4678                      break;
4679                   case escape:
4680                   case enter:
4681                   case keyPadEnter:
4682                      if(guiApp.windowMoving && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4683                      {
4684                         guiApp.windowMoving.StopMoving();
4685                         ConsequentialMouseMove(false);
4686
4687                         status = false;
4688                      }
4689                      break;
4690                   case altSpace:
4691                      if(style.fixed)
4692                      {
4693                         ShowSysMenu(absPosition.x, absPosition.y);
4694                         status = false;
4695                      }
4696                      break;
4697                }
4698             }
4699          }
4700
4701          if(!destroyed && status && state != minimized)
4702          {
4703             // Process all the way down the children
4704             if(activeChild && !activeChild.disabled)
4705             {
4706                status = activeChild.KeyMessage(method, key, character);
4707             }
4708             if(status && activeClient && activeChild != activeClient && !activeClient.disabled && (key.alt || key.ctrl) &&
4709                key.code != left && key.code != right && key.code != up && key.code != down)
4710             {
4711                status = activeClient.KeyMessage(method, key, character);
4712             }
4713
4714             // Default Control
4715             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4716             {
4717                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && !defaultControl.disabled && state != minimized)
4718                   // && defaultControl != activeChild)
4719                {
4720                   delete previousActive;
4721                   previousActive = activeChild;
4722                   if(previousActive) incref previousActive;
4723
4724                   ConsequentialMouseMove(false);
4725                   if((defaultControl.active ||
4726                      defaultControl.ActivateEx(true, true, false, true, null, null)) && !defaultControl.disabled)
4727                      defaultControl.KeyMessage(method, defaultKey, character);
4728                   status = false;
4729                }
4730             }
4731          }
4732
4733          if(!destroyed && status && (!modalWindow || this == guiApp.desktop))
4734          {
4735             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4736             {
4737                switch(key)
4738                {
4739                   case altMinus:
4740                      if(style.fixed)
4741                      {
4742                         ShowSysMenu(absPosition.x, absPosition.y);
4743                         status = false;
4744                      }
4745                      break;
4746                   //case f5:
4747                   /*
4748                   case shiftF5:
4749                      if(this != guiApp.desktop)
4750                      {
4751                         if(!guiApp.windowMoving && !guiApp.windowCaptured)
4752                         {
4753                            if(state != maximized && (key.shift ? style.sizeable : style.fixed))
4754                            {
4755                               MenuMoveOrSize(key.shift, true);
4756                               status = false;
4757                            }
4758                         }
4759                         else if(guiApp.windowMoving)
4760                         {
4761                            guiApp.windowMoving.StopMoving();
4762                            ConsequentialMouseMove(false);
4763                            status = false;
4764                         }
4765                      }
4766                      break;
4767                   */
4768                }
4769             }
4770             if(!destroyed && status && state != minimized)
4771             {
4772                if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4773                {
4774                   switch(key)
4775                   {
4776                      case tab: case shiftTab:
4777                      {
4778                         Window cycleParent = this;
4779                         if(this == guiApp.interimWindow && master && !master.style.interim && !cycleParent.style.tabCycle && master.parent)
4780                            cycleParent = master.parent;
4781
4782                         if(!guiApp.windowCaptured && cycleParent.style.tabCycle)
4783                         {
4784                            if(cycleParent.CycleChildren(!key.shift, false, false, true))
4785                            {
4786                               /*
4787                               Window child = cycleParent.activeChild;
4788
4789                               // Scroll the window to include the active control
4790                               if(cycleParent.sbh && !child.style.dontScrollHorz)
4791                               {
4792                                  if(child.scrolledPos.x < 0)
4793                                     cycleParent.sbh.Action(Position,
4794                                        cycleParent.scroll.x + child.scrolledPos.x, 0);
4795                                  else if(child.scrolledPos.x + child.size.w > cycleParent.clientSize.w)
4796                                     cycleParent.sbh.Action(Position,
4797                                        cycleParent.scroll.x + child.scrolledPos.x + child.size.w - cycleParent.clientSize.w, 0);
4798                               }
4799                               if(cycleParent.sbv && !child.style.dontScrollVert)
4800                               {
4801                                  if(child.scrolledPos.y < 0)
4802                                     cycleParent.sbv.Action(Position,
4803                                        cycleParent.scroll.y + child.scrolledPos.y, 0);
4804                                  else if(child.scrolledPos.y + child.size.w > window.clientSize.h)
4805                                     cycleParent.sbv.Action(Position,
4806                                        cycleParent.scroll.y + child.scrolledPos.y+child.size.h - cycleParent.clientSize.h, 0);
4807                               }
4808                               */
4809                               cycleParent.ConsequentialMouseMove(false);
4810                               status = false;
4811                            }
4812                         }
4813                         break;
4814                      }
4815                      case f6: case shiftF6:
4816                         if(!guiApp.windowMoving /*!guiApp.windowCaptured*/)
4817                         {
4818                            // NOT NEEDED... guiApp.windowMoving.ReleaseCapture();
4819                            if(parent == guiApp.desktop)
4820                               if(guiApp.desktop.CycleChildren(key.shift, true, false, true))
4821                               {
4822                                  status = false;
4823                                  break;
4824                               }
4825                            if(style.tabCycle)
4826                            {
4827                               delete this;
4828                               return true;
4829                            }
4830                            if(CycleChildren(key.shift, true, false, true))
4831                            {
4832                               status = false;
4833                               break;
4834                            }
4835                         }
4836                         break;
4837                      /*
4838                      // mIRC Style Window Shortcuts
4839                      case alt1: case alt2: case alt3: case alt4: case alt5:
4840                      case alt6: case alt7: case alt8: case alt9: case alt0:
4841                      {
4842                         if(numPositions)
4843                         {
4844                            Window document;
4845                            for(document = children.first; document; document = document.next)
4846                            {
4847                               if(document.style.isDocument && document.documentID - 1 == key.code - k1)
4848                               {
4849                                  if(document == activeChild)
4850                                  {
4851                                     if(document.state == minimized)
4852                                        document.SetState(normal, false, key);
4853                                     else
4854                                     {
4855                                        document.SetState(minimized, false, key);
4856                                        CycleChildren(false, true, false);
4857                                     }
4858                                  }
4859                                  else
4860                                  {
4861                                     if(activeChild.state == maximized && document.style.hasMaximize)
4862                                        document.SetState(maximized, false, key);
4863                                     else if(document.state == minimized)
4864                                        document.SetState(normal, false, key);
4865                                     document.Activate();
4866                                  }
4867                                  status = false;
4868                                  break;
4869                               }
4870                            }
4871                         }
4872                         break;
4873                      }
4874                      */
4875                   }
4876                }
4877             }
4878          }
4879
4880          if(!destroyed && status)
4881          {
4882             if(state == minimized)
4883             {
4884                delete this;
4885                return true;
4886             }
4887             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4888             {
4889                if((SmartKey)key == enter && !key.alt && !key.ctrl && defaultControl && previousActive)
4890                {
4891                   if(defaultControl.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, key, character))
4892                      previousActive.ActivateEx(true, false, false, true, null, null);
4893                   delete previousActive;
4894                   status = false;
4895                }
4896             }
4897          }
4898
4899          if(!destroyed && status)
4900          {
4901             status = ProcessHotKeys(method, key, character);
4902          }
4903          if(!destroyed && status && !modalWindow && state != minimized)
4904          {
4905             if(KeyMethod)
4906                status = KeyMethod(this, key, character);
4907             if(!destroyed && status && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown)
4908                status = OnKeyHit(key, character);
4909             if(!destroyed && status && (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown || method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit))
4910             {
4911                bool result = false;
4912                switch(key)
4913                {
4914                   case ctrlUp: case ctrlDown:
4915                      if(sbv && !guiApp.windowScrolling)
4916                         result = sbv.Action((key == ctrlUp) ? up : down, 0, key);
4917                      break;
4918                   case wheelUp: case wheelDown:
4919                      if(sbv && !guiApp.windowScrolling)
4920                      {
4921                         result = sbv.Action((key == wheelUp) ? wheelUp : wheelDown, 0, key);
4922                         // Do we want to do a consequential move regardless of result in this case?
4923                         ConsequentialMouseMove(false);
4924                      }
4925                      break;
4926                   case ctrlPageUp: case ctrlPageDown:
4927                      if(sbh && !guiApp.windowScrolling)
4928                         result = sbh.Action((key == ctrlPageUp) ? up : down, 0, key);
4929                      break;
4930                }
4931                if(result)
4932                {
4933                   ConsequentialMouseMove(false);
4934                   status = false;
4935                }
4936             }
4937          }
4938          if(status && !destroyed && menuBar && state != minimized)
4939             status = menuBar.KeyMessage(method, key, character);
4940
4941          if(style.interim && /*destroyed && */status && interimMaster)
4942          {
4943             // Testing this... for Ctrl-O to open dialog when autocompletion listbox is popped...
4944             status = interimMaster.KeyMessage(method, key, character);
4945          }
4946          delete this;
4947       }
4948       return status;
4949    }
4950
4951    bool ProcessHotKeys(uint method, Key key, unichar character)
4952    {
4953       bool status = true;
4954       HotKeySlot hotKey;
4955
4956       for(hotKey = hotKeys.first; hotKey; hotKey = hotKey.next)
4957          if((hotKey.key == key || (method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp && hotKey.key.code == key.code)) &&
4958             !hotKey.window.disabled && (hotKey.window.style.nonClient || state != minimized))
4959          {
4960             Window hotKeyWindow = hotKey.window;
4961             Window parent = hotKeyWindow.parent;
4962             Window prevActiveWindow = activeChild;
4963             // For when sys buttons are placed inside the menu bar
4964             if(parent && parent._class == class(PopupMenu))
4965                parent = parent.parent;
4966
4967             // 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
4968             if(hotKeyWindow.style.hidden && (!hotKeyWindow.style.nonClient || !parent || !parent.nativeDecorations || (hotKeyWindow != parent.sysButtons[2] && hotKeyWindow != parent.sysButtons[1])))
4969                continue;
4970
4971             if(prevActiveWindow) incref prevActiveWindow;
4972             incref hotKeyWindow;
4973             if(method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown && !hotKeyWindow.style.nonClient && !hotKeyWindow.inactive)
4974                if(!hotKeyWindow.ActivateEx(true, true, false, true, null, null))
4975                {
4976                   status = false;
4977                   delete hotKeyWindow;
4978                   delete prevActiveWindow;
4979                   break;
4980                }
4981
4982             if(hotKeyWindow.style.nonClient && method == __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit)
4983                method = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown;
4984             if(!hotKeyWindow.KeyMessage(method, Key::hotKey, character))
4985             {
4986                // *********   WORKING ON THIS   ***********
4987                if(prevActiveWindow && !guiApp.interimWindow)
4988                   prevActiveWindow.ActivateEx(true, false, false, false, null, null);
4989                status = false;
4990             }
4991             else if(hotKeyWindow.style.inactive)
4992                status = hotKeyWindow.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp, Key::hotKey, character);
4993
4994             delete prevActiveWindow;
4995             delete hotKeyWindow;
4996             // For Key Ups, don't set status to false... (e.g.: Releasing Enter vs AltEnter hot key)
4997             if(method != __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp)
4998                status = false;
4999             break;
5000          }
5001       if(status && tabCycle)
5002       {
5003          Window child;
5004          for(child = children.first; child; child = child.next)
5005          {
5006             if(child.tabCycle && !child.ProcessHotKeys(method, key, character))
5007             {
5008                status = false;
5009                break;
5010             }
5011          }
5012       }
5013       return status;
5014    }
5015
5016
5017    // --- Windows and graphics initialization / termination ---
5018    bool SetupRoot(void)
5019    {
5020       Window child;
5021
5022       // Setup relationship with outside world (bb root || !bb)
5023 #if defined(__EMSCRIPTEN__)
5024       if(this == guiApp.desktop)
5025 #else
5026       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || this == guiApp.desktop ||
5027          (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver))
5028 #endif
5029       {
5030          rootWindow = this;
5031          if(!tempExtents)
5032             tempExtents = new0 Extent[4];
5033          against = null;
5034       }
5035       else
5036       {
5037          /*if(guiApp.fullScreenMode)
5038             rootWindow = guiApp.desktop;
5039          else*/
5040          //rootWindow = parent.created ? parent.rootWindow : null;
5041          rootWindow = parent.rootWindow;
5042
5043          if(style.nonClient)
5044             against = &parent.box;
5045          else
5046             against = &parent.clientArea;
5047       }
5048
5049       for(child = children.first; child; child = child.next)
5050          child.SetupRoot();
5051
5052       return (rootWindow && (rootWindow == this || rootWindow.created)) ? true : false;
5053    }
5054
5055    bool Setup(bool positionChildren)
5056    {
5057       bool result = false;
5058       Window child;
5059
5060 #if defined(__EMSCRIPTEN__)
5061       if(this == guiApp.desktop)
5062 #else
5063       if((!guiApp.fullScreenMode && parent == guiApp.desktop) || (guiApp.fullScreenMode && (this == guiApp.desktop || (_displayDriver && parent.dispDriver && dispDriver != parent.dispDriver))))
5064 #endif
5065       {
5066          subclass(DisplayDriver) dDriver = (dispDriver && !formDesigner) ? dispDriver : GetDisplayDriver(guiApp.defaultDisplayDriver);
5067          DisplaySystem displaySystem = dDriver ? dDriver.displaySystem : null;
5068
5069          if(!windowHandle)
5070             windowHandle = dDriver.printer ? null : guiApp.interfaceDriver.CreateRootWindow(this);
5071
5072          // This was here, is it really needed?
5073          //guiApp.interfaceDriver.ActivateRootWindow(this);
5074
5075          if(!displaySystem)
5076          {
5077             displaySystem = DisplaySystem { glCapabilities = glCapabilities };
5078             if(!displaySystem.Create(dDriver.name, guiApp.fullScreenMode ? windowHandle : windowHandle /*null*/, guiApp.fullScreenMode))
5079             {
5080                delete displaySystem;
5081             }
5082          }
5083          if(displaySystem)
5084          {
5085             display = Display { alphaBlend = alphaBlend, useSharedMemory = useSharedMemory, glCapabilities = glCapabilities, windowDriverData = windowData };
5086             if(display.Create(displaySystem, windowHandle))
5087                result = true;
5088             else
5089             {
5090                delete display;
5091             }
5092          }
5093          // Sometimes icon does not show up on Windows XP if we set here...
5094          // guiApp.interfaceDriver.SetIcon(this, icon);
5095       }
5096       else if(this != guiApp.desktop)
5097       {
5098          display = rootWindow ? rootWindow.display : null;
5099          result = true;
5100       }
5101       else
5102          result = true;
5103
5104       if(guiApp.acquiredWindow && rootWindow == guiApp.acquiredWindow.rootWindow)
5105          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, true);
5106
5107       for(child = children.first; child; child = child.next)
5108       {
5109          if(child.created && !child.Setup(false))
5110             result = false;
5111
5112          if(guiApp.modeSwitching && guiApp.fullScreen && child.rootWindow == child)
5113             child.UpdateCaption();
5114       }
5115       return result;
5116    }
5117
5118    bool SetupDisplay(void)
5119    {
5120 #if !defined(ECERE_NO3D) && !defined(ECERE_VANILLA)
5121       if(is3D) return Window3D_SetupDisplay(this); else
5122 #endif
5123       if(SetupRoot())
5124          return Setup(true);
5125       return false;
5126    }
5127
5128    class_data void ** pureVTbl;
5129
5130    bool LoadGraphics(bool creation, bool resetAnchors)
5131    {
5132       bool result = false;
5133       bool success = false;
5134       Window child;
5135       WindowState stateBackup = state;
5136
5137       if(((subclass(Window))_class).pureVTbl)
5138       {
5139          if(_vTbl == _class._vTbl)
5140          {
5141             _vTbl = ((subclass(Window))_class).pureVTbl;
5142          }
5143          else
5144          {
5145             int m;
5146             for(m = 0; m < _class.vTblSize; m++)
5147             {
5148                if(_vTbl[m] == _class._vTbl[m])
5149                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
5150             }
5151          }
5152       }
5153       if(guiApp.currentSkin && ((subclass(Window))_class).pureVTbl)
5154       {
5155          if(_vTbl == ((subclass(Window))_class).pureVTbl)
5156          {
5157             _vTbl = _class._vTbl;
5158          }
5159          else
5160          {
5161             int m;
5162             for(m = 0; m < _class.vTblSize; m++)
5163             {
5164                if(_vTbl[m] == ((subclass(Window))_class).pureVTbl[m])
5165                   _vTbl[m] = _class._vTbl[m];
5166             }
5167          }
5168       }
5169
5170       if(
5171 #if !defined(__EMSCRIPTEN__)
5172       guiApp.fullScreenMode ||
5173 #endif
5174          this != guiApp.desktop)
5175       {
5176          SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
5177          if(display)
5178          {
5179             ResPtr ptr;
5180             success = true;
5181
5182             display.Lock(false);
5183             if(rootWindow == this)
5184             {
5185                // Set Color Palette
5186                display.SetPalette(palette, true);
5187
5188                // Load Cursors
5189                /*
5190                if(guiApp.fullScreenMode && this == guiApp.desktop)
5191                {
5192                   int c;
5193                   Cursor cursor;
5194
5195                   for(c=0; c<SystemCursor::enumSize; c++)
5196                      if(!guiApp.systemCursors[c].bitmap)
5197                      {
5198                         guiApp.systemCursors[c].bitmapName = guiApp.currentSkin.CursorsBitmaps(c,
5199                            &guiApp.systemCursors[c].hotSpotX,&guiApp.systemCursors[c].hotSpotY, &guiApp.systemCursors[c].paletteShades);
5200                         if(guiApp.systemCursors[c].bitmapName)
5201                         {
5202                            guiApp.systemCursors[c].bitmap = eBitmap_LoadT(guiApp.systemCursors[c].bitmapName, null,
5203                               guiApp.systemCursors[c].paletteShades ? null : guiApp.desktop.display.displaySystem);
5204                            if(guiApp.systemCursors[c].bitmap)
5205                               guiApp.systemCursors[c].bitmap.paletteShades = guiApp.systemCursors[c].paletteShades;
5206                            else
5207                               success = false;
5208                         }
5209                      }
5210                   for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
5211                   {
5212                      cursor.bitmap = eBitmap_LoadT(cursor.bitmapName, null,
5213                         cursor.paletteShades ? null : guiApp.desktop.display.displaySystem);
5214                      if(cursor.bitmap)
5215                         cursor.bitmap.paletteShades = cursor.paletteShades;
5216                      else
5217                         success = false;
5218                   }
5219                   guiApp.cursorUpdate = true;
5220
5221                   display.Unlock();
5222                   ConsequentialMouseMove(false);
5223                   display.Lock(true);
5224                }
5225                */
5226             }
5227
5228             // Load Window Graphic Resources
5229
5230             /*
5231             if(usedFont == setFont || usedFont == window.systemFont)
5232                RemoveResource(usedFont);
5233             */
5234             if(setFont)
5235                RemoveResource(setFont); // TESTING setFont instead of usedFont);
5236
5237             if(systemFont)
5238                RemoveResource(systemFont);
5239
5240             if(captionFont)
5241                RemoveResource(captionFont);
5242
5243             for(ptr = resources.first; ptr; ptr = ptr.next)
5244             {
5245                if(!ptr.loaded)   // This check prevents a leak in case a watcher on 'font' calls AddResource (ListBox FontResource leak)
5246                   ptr.loaded = display.displaySystem.LoadResource(ptr.resource);
5247             }
5248             if(setFont)
5249                AddResource(setFont);
5250             if(systemFont)
5251                AddResource(systemFont);
5252
5253             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
5254
5255             firewatchers font;
5256
5257             /*
5258             if(!setFont)
5259             {
5260                //if(master && master.font)
5261                if(parent && parent.font)
5262                {
5263                   font = FontResource
5264                   {
5265                      faceName = parent.font.faceName,
5266                      size = parent.font.size,
5267                      bold = parent.font.bold,
5268                      italic = parent.font.italic,
5269                      underline = parent.font.underline
5270                   };
5271                   //font = parent.font;
5272                   watch(parent) { font { } };
5273                }
5274                else
5275                   font = guiApp.currentSkin.SystemFont();
5276                AddResource(font);
5277
5278                firewatchers font;
5279             }
5280             */
5281
5282             captionFont = guiApp.currentSkin ? guiApp.currentSkin.CaptionFont() : null;
5283             AddResource(captionFont);
5284
5285             if(OnLoadGraphics())
5286             {
5287                int x,y,w,h;
5288
5289                display.Unlock();
5290
5291                //SetScrollLineStep(sbStep.x, sbStep.y);
5292
5293                if(this != guiApp.desktop)
5294                {
5295                   if(resetAnchors)
5296                   {
5297                      normalAnchor = anchor;
5298                      normalSizeAnchor = sizeAnchor;
5299                   }
5300
5301                   // Break the anchors for moveable/resizable windows
5302                   /*
5303                   if(style.fixed && style.isDocument)
5304                   {
5305                      ComputeAnchors(ax, ay, aw, ah, &x, &y, &w, &h);
5306                      ax = x;
5307                      ay = y;
5308                      aw = w;
5309                      ah = h;
5310                      anchored = false;
5311                   }
5312                   */
5313                   switch(state)
5314                   {
5315                      case maximized:
5316
5317                         stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
5318                         stateSizeAnchor = SizeAnchor {};
5319                         break;
5320
5321                      case minimized:
5322                      {
5323                         int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
5324
5325                         stateAnchor =
5326                            Anchor
5327                            {
5328                               left = (iconID % maxIcons) * MINIMIZED_WIDTH,
5329                               bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24)
5330                            };
5331
5332                         stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
5333                         break;
5334                      }
5335                      case normal:
5336                         stateAnchor = normalAnchor;
5337                         stateSizeAnchor = normalSizeAnchor;
5338                         break;
5339                   }
5340                   position = Point { };
5341                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
5342
5343                }
5344                else
5345                {
5346                   x = scrolledPos.x;
5347                   y = scrolledPos.y;
5348                   w = size.w;
5349                   h = size.h;
5350                }
5351
5352                if(Position(x, y, w, h, true, false, true, true, true, true))
5353                {
5354                   if((this != guiApp.desktop || guiApp.fullScreenMode) && rootWindow == this)
5355                   {
5356                      if(!style.hidden)
5357                         guiApp.interfaceDriver.SetRootWindowState(this, normal, true);
5358                   }
5359
5360                   Update(null);
5361
5362                   result = true;
5363                }
5364             }
5365             else
5366             {
5367                result = false;
5368                display.Unlock();
5369             }
5370          }
5371       }
5372       else
5373       {
5374          success = result = true;
5375       }
5376
5377       if(!creation && result)
5378       {
5379          // Load menu bar first because sys buttons are on it...
5380          if(menuBar)
5381          {
5382             if(!menuBar.LoadGraphics(false, resetAnchors))
5383             {
5384                result = false;
5385                success = false;
5386             }
5387          }
5388          for(child = children.first; child; child = child.next)
5389          {
5390             if(child.created && child != menuBar && !child.LoadGraphics(false, resetAnchors))
5391             {
5392                result = false;
5393                success = false;
5394             }
5395          }
5396          if(!creation)
5397             CreateSystemChildren();
5398
5399          OnApplyGraphics();
5400       }
5401       if(this == guiApp.desktop && !guiApp.fullScreenMode)
5402       {
5403          if(activeChild)
5404             guiApp.interfaceDriver.ActivateRootWindow(activeChild);
5405       }
5406       if(!success)
5407          LogErrorCode(graphicsLoadingFailed, _class.name);
5408
5409       // Do this here to avoid problems on Windows
5410       if(rootWindow == this && parent && stateBackup == maximized)
5411          property::state = maximized;
5412       return result;
5413    }
5414
5415    void UnloadGraphics(bool destroyWindows)
5416    {
5417       Window child;
5418
5419       // Free children's graphics
5420       for(child = children.first; child; child = child.next)
5421          child.UnloadGraphics(destroyWindows);
5422
5423       if(display)
5424          display.Lock(false);
5425
5426       // Free cursors
5427       if(guiApp.fullScreenMode && this == guiApp.desktop)
5428       {
5429          Cursor cursor;
5430          SystemCursor c;
5431
5432          for(c=0; c<SystemCursor::enumSize; c++)
5433             if(guiApp.systemCursors[c].bitmap)
5434                delete guiApp.systemCursors[c].bitmap;
5435
5436          for(cursor = guiApp.customCursors.first; cursor; cursor = cursor.next)
5437             delete cursor.bitmap;
5438
5439          guiApp.cursorBackground.Free();
5440       }
5441
5442       if(display && display.displaySystem)
5443       {
5444          ResPtr ptr;
5445
5446          for(ptr = resources.first; ptr; ptr = ptr.next)
5447          {
5448             if(ptr.loaded)
5449             {
5450                display.displaySystem.UnloadResource(ptr.resource, ptr.loaded);
5451                ptr.loaded = null;
5452             }
5453          }
5454
5455          // Free window graphics
5456          OnUnloadGraphics();
5457
5458          // Free skin graphics
5459          if(rootWindow == this)
5460          {
5461             DisplaySystem displaySystem = display.displaySystem;
5462             if(is3D)
5463             {
5464                display.driverData = null;
5465                display.displaySystem = null;
5466             }
5467             display.Unlock();
5468             delete display;
5469             if(displaySystem && !displaySystem.numDisplays && !is3D)
5470                delete displaySystem;
5471          }
5472          else
5473          {
5474             display.Unlock();
5475             display = null;
5476          }
5477       }
5478
5479       if(guiApp.acquiredWindow && this == guiApp.acquiredWindow.rootWindow)
5480          guiApp.interfaceDriver.AcquireInput(guiApp.acquiredWindow.rootWindow, false);
5481
5482       if(this == guiApp.desktop || parent == guiApp.desktop)
5483       {
5484          if((guiApp.fullScreenMode || this != guiApp.desktop) && rootWindow == this && windowHandle && destroyWindows)
5485             guiApp.interfaceDriver.DestroyRootWindow(this);
5486       }
5487    }
5488
5489    // --- Window Hiding ---
5490
5491    void SetVisibility(bool state)
5492    {
5493       bool visible = (style.hidden || !created) ? false : state;
5494       if(visible != this.visible)
5495       {
5496          Window child;
5497
5498          this.visible = visible;
5499          for(child = children.first; child; child = child.next)
5500             child.SetVisibility(visible);
5501          Update(null);
5502          ConsequentialMouseMove(false);
5503          if(parent && !nonClient) parent.OnChildVisibilityToggled(this, visible);
5504       }
5505    }
5506
5507    // --- Windows and graphics initialization / termination ---
5508
5509    bool DisplayModeChanged(void)
5510    {
5511       bool result = false;
5512       if(!guiApp.fullScreenMode && !guiApp.modeSwitching/* && guiApp.desktop.active*/)
5513       {
5514          guiApp.modeSwitching = true;
5515          UnloadGraphics(false);
5516          if(SetupDisplay())
5517             if(LoadGraphics(false, false))
5518                result = true;
5519          guiApp.modeSwitching = false;
5520       }
5521       return result;
5522    }
5523
5524    // --- Window updates system ---
5525
5526    void UpdateDirty(Box updateBox)
5527    {
5528       if(!manageDisplay) { OnRedraw(null);return; }
5529       if(visible)
5530       {
5531          if(display && (!guiApp.fullScreenMode || guiApp.desktop.active) && !guiApp.modeSwitching)
5532          {
5533             display.Lock(true);
5534             if(display.flags.flipping)
5535             {
5536                Update(null);
5537                rootWindow.UpdateDisplay();
5538             }
5539             else
5540                UpdateBackDisplay(updateBox);
5541
5542             if(guiApp.fullScreenMode)
5543             {
5544                guiApp.cursorUpdate = true;
5545                guiApp.PreserveAndDrawCursor();
5546             }
5547             if(guiApp.fullScreenMode)
5548                guiApp.RestoreCursorBackground();
5549             display.Unlock();
5550          }
5551       }
5552    }
5553
5554    // This function is strictly called as a result of system window activation
5555    bool ExternalActivate(bool active, bool activateRoot, Window window, Window swap)
5556    {
5557       bool result = true;
5558       Window interimMaster = null;
5559       Window interimWindow = guiApp.interimWindow;
5560       if(interimWindow && interimWindow.master)
5561          interimMaster = interimWindow.master.rootWindow;
5562
5563       if(active && state == minimized && window.parent) // && (!window.nativeDecorations || window.rootWindow != window)
5564          // SetState(normal, false, 0);
5565          SetState(lastState, false, 0);
5566
5567       if(interimMaster && swap == interimMaster && interimMaster.IsSlaveOf(window))
5568          return false;
5569
5570       incref this;
5571       /* WTH is this doing here?
5572       while(swap && swap.activeChild)
5573       {
5574          swap = swap.activeChild;
5575       }
5576       */
5577       // TESTING THIS BEFORE...
5578       if(interimWindow && this == interimMaster)
5579       {
5580          if(active)
5581          {
5582             // Window interimSwap = this;
5583             Window menuBar = this.menuBar;
5584             if(menuBar && interimWindow.master == menuBar)
5585             {
5586                /*
5587                while(interimSwap && interimSwap.activeChild)
5588                   interimSwap = interimSwap.activeChild;
5589
5590                result = interimWindow.ActivateEx(false, false, false, activateRoot, null,
5591                (menuBar && interimWindow.master == menuBar) ? menuBar : interimSwap);
5592                */
5593                result = /*interimWindow.*/ActivateEx(false, false, false, activateRoot, null, menuBar);
5594                //result = ActivateEx(true, true, false, activateRoot, window, null);
5595             }
5596          }
5597       }
5598       else
5599          // Testing & FindModal() here: broke reactivating when a modal dialog is up (didn't root activate dialog)
5600          result = ActivateEx(active, active, false, activateRoot /*&& FindModal()*/, window, swap);
5601
5602       if(interimWindow == this && interimMaster && !active)
5603       {
5604          while(interimMaster && interimMaster.interim && interimMaster.master)
5605          {
5606             // printf("Going up one master %s\n", interimMaster._class.name);
5607             interimMaster = interimMaster.master.rootWindow;
5608          }
5609          // printf("Unactivating interim master %s (%x)\n", interimMaster._class.name, interimMaster);
5610          interimMaster.ActivateEx(active, active, false, activateRoot, window, swap);
5611       }
5612       delete this;
5613       return result;
5614    }
5615
5616    bool DestroyEx(int64 returnCode)
5617    {
5618       OldLink slave;
5619       Timer timer, nextTimer;
5620       Window child;
5621       OldLink prevOrder = null;
5622       Window client = null;
5623
5624       if(parent) stopwatching(parent, font);
5625
5626       // if(window.modalSlave) return false;
5627       if(destroyed || !created)
5628       {
5629          if(master)
5630          {
5631             /*
5632             if(destroyed)
5633             {
5634                OldLink slave = master.slaves.FindLink(this);
5635                master.slaves.Delete(slave);
5636             }
5637             */
5638             // TOFIX IMMEDIATELY: COMMENTED THIS OUT... causes problem second time creating file dialog
5639             //master = null;
5640          }
5641          return true;
5642       }
5643
5644       this.returnCode = (DialogResult)returnCode;
5645
5646       AcquireInput(false);
5647
5648       destroyed = true;
5649       if(hotKey)
5650       {
5651          master.hotKeys.Delete(hotKey);
5652          hotKey = null;
5653       }
5654
5655       if(guiApp.prevWindow == this)
5656       {
5657          guiApp.prevWindow = null;
5658          OnMouseLeave(0);
5659       }
5660       else
5661       {
5662          for(w : guiApp.overWindows; w == this)
5663          {
5664             OnMouseLeave(0);
5665             guiApp.overWindows.TakeOut(w);
5666             break;
5667          }
5668       }
5669       if(guiApp.caretOwner == this)
5670       {
5671          guiApp.interfaceDriver.SetCaret(0,0,0);
5672          UpdateCaret(false, true);
5673          guiApp.caretEnabled = false;
5674       }
5675
5676       /*
5677       if(cycle)
5678          parent.childrenCycle.Remove(cycle);
5679       */
5680       if(order)
5681       {
5682          OldLink tmpPrev = order.prev;
5683          if(tmpPrev && !(((Window)tmpPrev.data).style.hidden) && !(((Window)tmpPrev.data).destroyed) && (((Window)tmpPrev.data).created))
5684             prevOrder = tmpPrev;
5685          for(;;)
5686          {
5687             client = tmpPrev ? tmpPrev.data : null;
5688             if(client == this) { client = null; break; }
5689             if(client && (client.style.hidden || client.destroyed || !client.created))
5690                tmpPrev = client.order.prev;
5691             else
5692             {
5693                if(client)
5694                   prevOrder = tmpPrev;
5695                break;
5696             }
5697          }
5698
5699          // If this window can be an active client, make sure the next window we activate can also be one
5700          if(!style.nonClient && style.isActiveClient)
5701          {
5702             tmpPrev = prevOrder;
5703             for(;;)
5704             {
5705                client = tmpPrev ? tmpPrev.data : null;
5706                if(client == this) { client = null; break; }
5707                if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
5708                   tmpPrev = client.order.prev;
5709                else
5710                {
5711                   if(client)
5712                      prevOrder = tmpPrev;
5713                   break;
5714                }
5715             }
5716             if(client && client.style.hidden) client = null;
5717          }
5718          // parent.childrenOrder.Remove(order);
5719       }
5720
5721       if(parent && style.isActiveClient && visible)
5722       {
5723          if(state == minimized) parent.numIcons--;
5724          parent.numPositions--;
5725       }
5726
5727       // TESTING THIS HERE!
5728       created = false;
5729       visible = false;
5730
5731       // If no display, don't bother deactivating stuff (causes unneeded problems when trying
5732       // to create a window inside a rootwindow that's being destroyed)
5733       // DISABLED THIS BECAUSE OF CREATING WINDOW IN DESKTOP IN WINDOWED MODE
5734
5735       if(master && !master.destroyed /*&&
5736          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5737       {
5738          if(master.defaultControl == this)
5739             master.defaultControl = null;
5740       }
5741       if(parent)
5742          parent.OnChildAddedOrRemoved(this, true);
5743       if(parent && !parent.destroyed /*&&
5744          rootWindow && rootWindow.display && !rootWindow.destroyed*/)
5745       {
5746          if((parent.activeChild == this /*|| parent.activeClient == this */|| guiApp.interimWindow == this))
5747          {
5748             if(order && prevOrder && prevOrder.data != this && active)
5749             {
5750                //((Window)prevOrder.data).ActivateEx(true, false, false, false /*true*/, null);
5751
5752                ((Window)prevOrder.data).ActivateEx(true, false, false, (rootWindow == this) ? true : false, null, null);
5753                if(parent.activeClient == this)
5754                {
5755                   parent.activeClient = null;
5756                   parent.UpdateActiveDocument(null);
5757                }
5758             }
5759             else
5760             {
5761                if(guiApp.interimWindow == this)
5762                {
5763                   bool goOn = true;
5764                   PropagateActive(false, null, &goOn, true);
5765                }
5766                else
5767                {
5768                   //if(window.parent.activeChild == window)
5769                      parent.activeChild = null;
5770                   if(!style.nonClient /*&& style.isActiveClient*/)
5771                   {
5772                      Window previous = parent.activeClient;
5773                      if(style.isActiveClient)
5774                         parent.activeClient = null;
5775                      parent.UpdateActiveDocument(previous);
5776                   }
5777                }
5778             }
5779          }
5780          else if(parent.activeClient == this)
5781          {
5782             parent.activeClient = client;
5783             parent.UpdateActiveDocument(this);
5784
5785          }
5786       }
5787       if(guiApp.interimWindow == this)
5788       {
5789          guiApp.interimWindow = null;
5790          if(guiApp.caretOwner)
5791          {
5792             Window desktop = guiApp.desktop;
5793             if(desktop.activeChild && desktop.activeChild.menuBar && !desktop.activeChild.menuBar.focus)
5794                guiApp.caretOwner.UpdateCaret(false, false);
5795          }
5796       }
5797
5798       active = false;
5799       if(_isModal && master && master.modalSlave == this)
5800          master.modalSlave = null;
5801
5802       if(parent)
5803       {
5804          if(!guiApp.caretOwner && parent.caretSize)
5805          {
5806             guiApp.caretOwner = parent;
5807             parent.UpdateCaret(false, false);
5808             parent.Update(null);
5809          }
5810
5811          // Why was this commented out?
5812          GetRidOfVirtualArea();
5813       }
5814       /*
5815       delete cycle;
5816       delete order;
5817       */
5818       dirtyArea.Free(null);
5819       dirtyBack.Free(null);
5820       scrollExtent.Free(null);
5821
5822       /* ATTEMPTING TO MOVE THAT ABOVE
5823       created = false;
5824       visible = false;
5825       */
5826
5827       /*
5828       OnDestroy();
5829       {
5830          //Window next;
5831          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5832          for(;(child = window.children.first);)
5833          {
5834             for(; child && (child.destroyed || !child.created); child = child.next);
5835             if(child)
5836                child.DestroyEx(0);
5837             else
5838                break;
5839          }
5840       }
5841       */
5842
5843       UnloadGraphics(true);
5844
5845       if(previousActive)
5846          delete previousActive;
5847
5848       menuBar = null;
5849       // statusBar = null;
5850       sbv = sbh = null;
5851
5852       if(master && !master.destroyed)
5853       {
5854          //master.NotifyDestroyed(this, this.returnCode);
5855          NotifyDestroyed(master, this, this.returnCode);
5856       }
5857
5858       for(timer = guiApp.windowTimers.first; timer; timer = nextTimer)
5859       {
5860          nextTimer = timer.next;
5861          if(timer.window == this)
5862          {
5863             // WHY WERE WE SETTING THIS TO NULL? NO MORE WINDOW WHEN RECREATING...
5864             // timer.window = null;
5865             timer.Stop();
5866             //delete timer;
5867          }
5868       }
5869
5870       if(this == guiApp.windowMoving)
5871          StopMoving();
5872
5873       if(guiApp.windowCaptured == this)
5874          ReleaseCapture();
5875          //guiApp.windowCaptured = null;
5876
5877       if(rootWindow != this && rootWindow)
5878          rootWindow.ConsequentialMouseMove(false);
5879
5880       rootWindow = null;
5881
5882       OnDestroy();
5883
5884       {
5885          //Window next;
5886          //for(child = children.first; next = child ? child.next : null, child; child = next)
5887          for(;(child = children.first); )
5888          {
5889             for(; child && (child.destroyed || !child.created); child = child.next);
5890             if(child)
5891                child.DestroyEx(0);
5892             else
5893                break;
5894          }
5895       }
5896
5897       // master = null;
5898
5899       /* // MOVED THIS UP...
5900       {
5901          //Window next;
5902          //for(child = window.children.first; next = child ? child.next : null, child; child = next)
5903          for(;(child = window.children.first); )
5904          {
5905             for(; child && (child.destroyed || !child.created); child = child.next);
5906             if(child)
5907                child.DestroyEx(0);
5908             else
5909                break;
5910          }
5911       }
5912       */
5913
5914       while((slave = slaves.first))
5915       {
5916          for(; slave && (((Window)slave.data).destroyed || !((Window)slave.data).created); slave = slave.next);
5917          if(slave)
5918             ((Window)slave.data).DestroyEx(0);
5919          else
5920             break;
5921       }
5922
5923       if(guiApp.caretOwner == this)
5924          guiApp.caretOwner = null;
5925
5926       sysButtons[0] = null;
5927       sysButtons[1] = null;
5928       sysButtons[2] = null;
5929       activeChild = null;
5930
5931       if(rootWindow != this)
5932       {
5933          Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
5934          if(style.nonClient)
5935          {
5936             box.left   -= parent.clientStart.x;
5937             box.top    -= parent.clientStart.y;
5938             box.right  -= parent.clientStart.x;
5939             box.bottom -= parent.clientStart.y;
5940          }
5941          if(parent) parent.Update(box);
5942       }
5943       /*
5944       if(master)
5945       {
5946          OldLink slave = master.slaves.FindVoid(this);
5947          master.slaves.Delete(slave);
5948          master = null;
5949       }
5950
5951       if(parent)
5952       {
5953          parent.children.Remove(this);
5954          parent = null;
5955       }
5956       */
5957
5958       //autoCreate = false;
5959       //created = false;
5960
5961       // SHOULD THIS BE HERE? FIXED CRASH WITH GOTO DIALOG
5962       if(((subclass(Window))_class).pureVTbl)
5963       {
5964          if(_vTbl == _class._vTbl)
5965          {
5966             _vTbl = ((subclass(Window))_class).pureVTbl;
5967          }
5968          else
5969          {
5970             int m;
5971             for(m = 0; m < _class.vTblSize; m++)
5972             {
5973                if(_vTbl[m] == _class._vTbl[m])
5974                   _vTbl[m] = ((subclass(Window))_class).pureVTbl[m];
5975             }
5976          }
5977       }
5978
5979       delete this;
5980       return true;
5981    }
5982
5983    void SetStateEx(WindowState newState, bool activate)
5984    {
5985       int x,y,w,h;
5986       WindowState prevState = state;
5987
5988       state = newState;
5989
5990       if(prevState != newState)
5991          lastState = prevState;
5992
5993       if(rootWindow != this || !nativeDecorations || !windowHandle)
5994       {
5995          if(style.isActiveClient && !style.hidden && prevState == minimized)
5996             parent.numIcons--;
5997
5998          // This block used to be at the end of the function... moved it for flicker problem in X
5999          // ------------------------------------------------------
6000          switch(state)
6001          {
6002             case normal:
6003                stateAnchor = normalAnchor;
6004                stateSizeAnchor = normalSizeAnchor;
6005                break;
6006             case maximized:
6007                stateAnchor = Anchor { left = 0, top = 0, right = 0, bottom = 0 };
6008                stateSizeAnchor = SizeAnchor {};
6009                break;
6010             case minimized:
6011             {
6012                if(hasMinimize)
6013                {
6014                   int maxIcons = parent.clientSize.w / MINIMIZED_WIDTH;
6015                   Window child;
6016                   int size = 256;
6017                   byte * idBuffer = new0 byte[size];
6018                   int c;
6019                   for(child = parent.children.first; child; child = child.next)
6020                   {
6021                      if(child != this && child.state == minimized)
6022                      {
6023                         if(child.iconID > size - 2)
6024                         {
6025                            idBuffer = renew0 idBuffer byte[size*2];
6026                            memset(idBuffer + size, 0, size);
6027                            size *= 2;
6028                         }
6029                         idBuffer[child.iconID] = (byte)bool::true;
6030                      }
6031                   }
6032                   for(c = 0; c<size; c++)
6033                      if(!idBuffer[c])
6034                         break;
6035                   iconID = c;
6036                   delete idBuffer;
6037                   if(style.isActiveClient && !style.hidden)
6038                      parent.numIcons++;
6039
6040                   stateAnchor = Anchor { left = (iconID % maxIcons) * MINIMIZED_WIDTH, bottom = (iconID / maxIcons) * (guiApp.textMode ? 16 : 24) };
6041                   stateSizeAnchor = SizeAnchor { size.w = MINIMIZED_WIDTH };
6042                   break;
6043                }
6044             }
6045          }
6046          // TOCHECK: Why was this here?
6047          //position.x = (tx > 0) ? tx & 0xFFFFF : tx;
6048          //position.y = (ty > 0) ? ty & 0xFFFFF : ty;
6049          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6050
6051          if(state != minimized || hasMinimize)
6052             Position(x, y, w, h, true, true, true, true, false, true);
6053
6054          if(!style.inactive && !style.interim && parent && this == parent.activeClient)
6055             parent.UpdateActiveDocument(null);
6056       }
6057
6058       if(state != minimized || hasMinimize)
6059          CreateSystemChildren();
6060       // ------------------------------------------------------
6061    }
6062
6063    int GetPositionID(Window forChild)
6064    {
6065       Window child;
6066       int size = 256;
6067       byte * idBuffer = new0 byte[size];
6068       int c;
6069
6070       for(child = children.first; child; child = child.next)
6071       {
6072          if(child.style.isActiveClient && !child.style.hidden && child != forChild)
6073          {
6074             if(child.positionID > size - 2)
6075             {
6076                idBuffer = renew0 idBuffer byte[size*2];
6077                memset(idBuffer + size, 0, size);
6078                size *= 2;
6079             }
6080             idBuffer[child.positionID] = (byte)bool::true;
6081          }
6082       }
6083       for(c = 0; c<size; c++)
6084          if(!idBuffer[c])
6085             break;
6086       delete idBuffer;
6087       return c;
6088    }
6089
6090    // --- Window related graphics ---
6091
6092    void SetPalette(ColorAlpha * newPalette, bool colorMatch)
6093    {
6094       palette = newPalette;
6095       if(rootWindow.display)
6096          rootWindow.display.SetPalette(palette, colorMatch);
6097    }
6098
6099    public bool AcquireInput(bool acquired)
6100    {
6101       bool result = true;
6102       if((guiApp.acquiredWindow && acquiredInput) != acquired)
6103       {
6104          if(active || (!visible && creationActivation == activate))
6105             result = AcquireInputEx(acquired);
6106          /*if(!result)
6107          {
6108             Print("");
6109          }*/
6110          acquiredInput = acquired ? result : !result;
6111       }
6112       return result;
6113    }
6114
6115    void ListChildren(ListBox listBox)
6116    {
6117       Window child;
6118       char caption[2048];
6119       for(child = children.first; child; child = child.next)
6120       {
6121          if(child.cycle && !child.style.nonClient && child.style.isActiveClient && child.visible)
6122          {
6123             DataRow row = listBox.AddRow();
6124             row.tag = (int64)(intptr)child;
6125             child.FigureCaption(caption);
6126             row.SetData(null, caption);
6127          }
6128       }
6129    }
6130
6131    void UpdateVisual(Box extent)
6132    {
6133       if(guiApp.driver != null)
6134       {
6135 #if !defined(__EMSCRIPTEN__)
6136          if(guiApp.fullScreenMode && guiApp.desktop.display)
6137 #else
6138          if(true)
6139 #endif
6140          {
6141 #if !defined(__EMSCRIPTEN__)
6142             guiApp.desktop.mutex.Wait();
6143 #endif
6144             guiApp.desktop.display.Lock(true);
6145
6146             Update(extent);
6147             if(guiApp.desktop.active)
6148             {
6149                if(guiApp.desktop.dirty || guiApp.cursorUpdate)
6150                {
6151                   if(guiApp.desktop.display.flags.flipping)
6152                      guiApp.desktop.Update(null);
6153                   guiApp.desktop.UpdateDisplay();
6154                   guiApp.cursorUpdate = true;
6155                }
6156                if(guiApp.cursorUpdate || guiApp.desktop.dirty)
6157                {
6158                   guiApp.PreserveAndDrawCursor();
6159                   // guiApp.desktop.display.ShowScreen();
6160                   guiApp.cursorUpdate = false;
6161                   guiApp.desktop.dirty = false;
6162                   guiApp.RestoreCursorBackground();
6163                }
6164             }
6165
6166             guiApp.desktop.display.Unlock();
6167 #if !defined(__EMSCRIPTEN__)
6168             guiApp.desktop.mutex.Release();
6169 #endif
6170          }
6171          else
6172          {
6173             Window rootWindow = this.rootWindow;
6174 #if !defined(__EMSCRIPTEN__)
6175             rootWindow.mutex.Wait();
6176 #endif
6177             display.Lock(true);
6178
6179             Update(extent);
6180             if(guiApp.waiting)
6181                guiApp.SignalEvent();
6182             else
6183             {
6184 #if !defined(__EMSCRIPTEN__)
6185                guiApp.waitMutex.Wait();
6186 #endif
6187                guiApp.interfaceDriver.Lock(rootWindow);
6188                if(!rootWindow.style.hidden && rootWindow.dirty)
6189                {
6190                   if(rootWindow.display)
6191                   {
6192                      rootWindow.UpdateDisplay();
6193                      //rootWindow.display.ShowScreen(null);
6194                   }
6195                   rootWindow.dirty = false;
6196                }
6197                guiApp.interfaceDriver.Unlock(rootWindow);
6198 #if !defined(__EMSCRIPTEN__)
6199                guiApp.waitMutex.Release();
6200 #endif
6201             }
6202             display.Unlock();
6203 #if !defined(__EMSCRIPTEN__)
6204             rootWindow.mutex.Release();
6205 #endif
6206          }
6207       }
6208    }
6209
6210    void UnlockDisplay(void)
6211    {
6212       guiApp.interfaceDriver.Unlock(rootWindow);
6213    }
6214
6215    void LockDisplay(void)
6216    {
6217       guiApp.interfaceDriver.Lock(rootWindow);
6218    }
6219
6220    Surface GetSurface(Box box)
6221    {
6222       return Redraw((box == null) ? this.box : box);
6223    }
6224
6225    void SetMousePosition(int x, int y)
6226    {
6227       guiApp.interfaceDriver.SetMousePosition(x + absPosition.x + clientStart.x, y + absPosition.y + clientStart.y);
6228    }
6229
6230    /*
6231    void IntegrationActivate(bool active)
6232    {
6233       if(!guiApp.modeSwitching && !guiApp.fullScreenMode)
6234       {
6235          isForegroundWindow = true;
6236          ActivateEx(active, active, false, false, null, null);
6237          isForegroundWindow = false;
6238       }
6239    }
6240    */
6241
6242    Window QueryCapture(void)
6243    {
6244       return guiApp.windowCaptured;
6245    }
6246
6247    int GetDocumentID(void)
6248    {
6249       Window child;
6250       int size = 256;
6251       byte * idBuffer = new0 byte[size];
6252       int c;
6253
6254       for(child = children.first; child; child = child.next)
6255       {
6256          // TO CHECK: Do we want a documentID when we already have a file name?
6257          if(child.style.isDocument && !child.fileName)
6258          {
6259             if(child.documentID-1 > size - 2)
6260             {
6261                idBuffer = renew0 idBuffer byte[size*2];
6262                memset(idBuffer + size, 0, size);
6263                size *= 2;
6264             }
6265             idBuffer[child.documentID-1] = 1;
6266          }
6267       }
6268       for(c = 0; c<size; c++)
6269          if(!idBuffer[c])
6270             break;
6271       numDocuments++;
6272       delete idBuffer;
6273       return c + 1;
6274    }
6275
6276    void SetInitSize(Size size)
6277    {
6278       int x, y, w, h;
6279       sizeAnchor.size = size;
6280       normalSizeAnchor = sizeAnchor;
6281
6282       // Break the anchors for moveable/resizable windows
6283       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6284       {
6285          stateAnchor = normalAnchor;
6286          stateSizeAnchor = normalSizeAnchor;
6287
6288          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6289          Position(x,y, w, h, true, true, true, true, false, true);
6290       }
6291    }
6292
6293    void MenuMoveOrSize(bool resize, bool setCursorPosition)
6294    {
6295       if(this != guiApp.desktop && state != maximized && (resize ? (state != minimized && style.sizable) : (style.fixed || moveable)))
6296       {
6297          guiApp.windowIsResizing = resize;
6298          guiApp.windowMoving = this;
6299          guiApp.windowMovingStart = guiApp.movingLast = absPosition;
6300          if(guiApp.windowIsResizing)
6301          {
6302             guiApp.windowMovingStart.x += size.w - 1;
6303             guiApp.windowMovingStart.y += size.h - 1;
6304          }
6305          guiApp.windowMovingBefore = scrolledPos;
6306          guiApp.windowResizingBefore = size;
6307          guiApp.windowMoving.UpdateDecorations();
6308          if(guiApp.windowIsResizing)
6309             guiApp.resizeEndX = guiApp.resizeEndY = true;
6310
6311          if(setCursorPosition)
6312             guiApp.interfaceDriver.SetMousePosition(guiApp.windowMovingStart.x, guiApp.windowMovingStart.y);
6313          else
6314          {
6315             int x = 0, y = 0;
6316             guiApp.interfaceDriver.GetMousePosition(&x, &y);
6317             guiApp.windowMovingStart.x += x - absPosition.x;
6318             guiApp.windowMovingStart.y += y - absPosition.y;
6319          }
6320
6321          if(guiApp.windowMoving)
6322          {
6323             if(guiApp.windowMoving.style.nonClient)
6324                guiApp.windowMoving.parent.SetMouseRangeToWindow();
6325             else
6326                guiApp.windowMoving.parent.SetMouseRangeToClient();
6327          }
6328
6329          Capture();
6330
6331          if(this == rootWindow)
6332             guiApp.interfaceDriver.StartMoving(rootWindow, guiApp.windowMovingStart.x, guiApp.windowMovingStart.y, true);
6333       }
6334    }
6335
6336    void SetupFileMonitor()
6337    {
6338 #if !defined(__EMSCRIPTEN__)
6339       if(!fileMonitor)
6340       {
6341          fileMonitor = FileMonitor
6342          {
6343             this, FileChange { modified = true };
6344
6345             bool OnFileNotify(FileChange action, const char * param)
6346             {
6347                incref this;
6348                fileMonitor.StopMonitoring();
6349                if(OnFileModified(action, param))
6350                   fileMonitor.StartMonitoring();
6351                delete this;
6352                return true;
6353             }
6354          };
6355          incref fileMonitor;
6356       }
6357 #endif
6358    }
6359
6360 public:
6361    // normal Methods
6362    bool Create()
6363    {
6364       bool result = false;
6365
6366       if(created)
6367          result = true;
6368       else if(guiApp && guiApp.driver != null)
6369       {
6370          OldLink slaveHolder;
6371          Window last;
6372          bool visible = !style.hidden;
6373
6374          if(style.embedded)
6375          {
6376             systemParent = parent;
6377             parent = guiApp.desktop;
6378          }
6379          last = parent ? parent.children.last : null;
6380
6381          if((parent && parent != guiApp.desktop && !parent.created) ||
6382             (master && master != guiApp.desktop && !master.created))
6383             return false;
6384
6385          if(parent)
6386             stopwatching(parent, font);
6387
6388          if(!parent)
6389             property::parent = guiApp.desktop;
6390          if(!master) master = parent;
6391
6392          if(_isModal && master.modalSlave)
6393             property::master = master.modalSlave;
6394             //return false;
6395
6396          if(parent)
6397             parent.children.Remove(this);
6398          if(master)
6399          {
6400             for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
6401                if(slaveHolder.data == this)
6402                {
6403                   master.slaves.Delete(slaveHolder);
6404                   break;
6405                }
6406          }
6407
6408 #if !defined(__EMSCRIPTEN__)
6409          if(parent == guiApp.desktop && !mutex)
6410             mutex = Mutex {};
6411 #endif
6412
6413          if(style.isDocument)
6414          {
6415             if(parent)
6416                parent.numDocuments--;
6417             documentID = parent.GetDocumentID();
6418          }
6419
6420          if(!style.stayOnTop)
6421             for(; last && last.style.stayOnTop; last = last.prev);
6422
6423          parent.children.Insert((last == this) ? null : last, this);
6424          //parent.children.Add(this);
6425
6426          if(!dispDriver)
6427             dispDriver = parent.dispDriver;
6428          destroyed = false;
6429          if(_isModal)
6430             master.modalSlave = this;
6431
6432          box = Box { MAXINT, MAXINT, MININT, MININT }; //-MAXINT, -MAXINT };
6433
6434          incref this;
6435          incref this;
6436
6437          master.slaves.Add(slaveHolder = OldLink { data = this });
6438          if(slaveHolder)
6439          {
6440             if(setHotKey)
6441             {
6442                master.hotKeys.Add(hotKey = HotKeySlot { key = setHotKey, window = this });
6443             }
6444             if(style.isDefault && !master.defaultControl)
6445                master.defaultControl = this;
6446
6447             stateAnchor = normalAnchor = anchor;
6448             stateSizeAnchor = normalSizeAnchor = sizeAnchor;
6449
6450             // TOCHECK: Why is this here?
6451             //position.x = (ax > 0) ? ax & 0xFFFFF : ax;
6452             //position.y = (ay > 0) ? ay & 0xFFFFF : ay;
6453
6454             this.visible = false;
6455             style.hidden = true;
6456
6457             //created = true;
6458             // autoCreate = true;
6459             wasCreated = true;
6460             if(SetupDisplay())
6461             {
6462                created = true;
6463                if(OnCreate())
6464                {
6465                   /*
6466                   if(parent == guiApp.desktop)
6467                      Log("LoadGraphics %s\n", caption);
6468                   */
6469                   if(LoadGraphics(true, false))
6470                   {
6471                      if(!setFont)
6472                      {
6473                         watch(parent)
6474                         {
6475                            font
6476                            {
6477                               usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
6478                               firewatchers font;
6479                               Update(null);
6480                            }
6481                         };
6482                      }
6483
6484                      if(style.hasMenuBar /*&& menu*/)
6485                      {
6486                         menuBar =
6487                            PopupMenu
6488                            {
6489                               this,
6490                               menu = menu, isMenuBar = true, anchor = Anchor { top = 23, left = 1, right = 1 },
6491                               interim = false, inactive = true, nonClient = true, size.h = 24
6492                            };
6493                         menuBar.Create();
6494                      }
6495
6496                      if(statusBar)
6497                         statusBar.Create();
6498
6499                      // Create the system buttons
6500                      CreateSystemChildren();
6501
6502                      UpdateActiveDocument(null);
6503
6504                      if(style.isDocument)
6505                      {
6506                         if(menu)
6507                         {
6508                            MenuItem item = menu.FindItem(MenuFileSave, 0);
6509                            if(item) item.disabled = !modifiedDocument && fileName;
6510                         }
6511                      }
6512
6513                      /*
6514                      if(parent == guiApp.desktop)
6515                         Log("Preemptive SetState %s\n", caption);
6516                      */
6517
6518                      // Preemptive Set State to ensure proper anchoring
6519                      SetStateEx(state, false);
6520                      /*
6521                      style.hidden = true;
6522                      visible = false;
6523                      */
6524
6525                      {
6526                         Window child, next;
6527                         for(child = children.first; child; child = next)
6528                         {
6529                            next = child.next;
6530                            if(!child.created && (child.autoCreate || child.wasCreated))
6531                               child.Create();
6532                         }
6533                      }
6534
6535                      {
6536                         OldLink link, next;
6537                         for(link = slaves.first; link; link = next)
6538                         {
6539                            Window slave = link.data;
6540                            next = link.next;
6541                            if(!slave.created && (slave.autoCreate || slave.wasCreated))
6542                            {
6543                               if(slave.Create())
6544                                  // Things might have happened that invalidated 'next'...
6545                                  // Start over the search for slaves to create.
6546                                  // (Added this to fix crash with Stacker & Toolbar)
6547                                  next = slaves.first;
6548                            }
6549                         }
6550                      }
6551
6552                      if(OnPostCreate())
6553                         OnApplyGraphics();
6554
6555                      /*
6556                      if(parent == guiApp.desktop)
6557                         Log("Real SetState %s\n", caption);
6558                      */
6559
6560                      if(isActiveClient && visible)
6561                      {
6562                         parent.numPositions--;
6563                         if(state == minimized) parent.numIcons--;
6564                      }
6565
6566                      parent.OnChildAddedOrRemoved(this, false);
6567
6568                      if(rootWindow == this && visible)   // So that X11 windows don't show as 'unknown'
6569                         UpdateCaption();
6570                      // Real set state & activate for proper display & activation
6571                      property::visible = visible;
6572                      //  SetState(state & 0x00000003, true, 0);
6573                      guiApp.interfaceDriver.SetIcon(this, icon);
6574
6575                      if(visible)
6576                      {
6577                         UpdateCaption();
6578                         /*if(rootWindow == this)
6579                            guiApp.interfaceDriver.ActivateRootWindow(this);
6580                         else*/
6581                         if(creationActivation == activate && guiApp.desktop.active)
6582                            ActivateEx(true, false, true, true, null, null);
6583                         else if(creationActivation == activate || creationActivation == flash)
6584                         {
6585                            MakeActive();
6586                            if(this == rootWindow)
6587                               Flash();
6588                         }
6589                      }
6590
6591                      if(!destroyed && !noConsequential)
6592                         rootWindow.ConsequentialMouseMove(false);
6593
6594                      result = true;
6595                   }
6596                }
6597             }
6598          }
6599          /*
6600          if(!result)
6601          {
6602             Destroy(0);
6603             guiApp.LogErrorCode(IERR_WINDOW_CREATION_FAILED, caption);
6604          }
6605          */
6606
6607          if(!result)
6608          {
6609             // Testing this here... Otherwise a failed LoadGraphics stalls the application
6610             created = false;
6611             //style.hidden = true; // !visible;
6612             style.hidden = !visible;
6613             if(master.modalSlave == this)
6614                master.modalSlave = null;
6615          }
6616          delete this;
6617       }
6618       return result;
6619    }
6620
6621    void WriteCaption(Surface surface, int x, int y)
6622    {
6623       if(caption)
6624          Interface::WriteKeyedTextDisabled(surface, x,y, caption, hotKey ? hotKey.key : 0, !isEnabled);
6625    }
6626
6627    void Update(Box region)
6628    {
6629       if(this)
6630       {
6631          Window rootWindow;
6632
6633          rootWindow = this.rootWindow;
6634
6635          // rootWindow.mutex.Wait();
6636          if(!destroyed && visible && display)
6637          {
6638             Window child;
6639             Box realBox;
6640
6641             // Testing this to avoid repetitve full update to take time...
6642             if(rootWindow.fullRender)
6643             {
6644                rootWindow.dirty = true;
6645                return;
6646             }
6647             if(dirtyArea.count == 1)
6648             {
6649                BoxItem item = (BoxItem)ACCESS_ITEM(dirtyArea, dirtyArea.first);
6650                if(item.box.left <= box.left &&
6651                   item.box.top <= box.top &&
6652                   item.box.right >= box.right &&
6653                   item.box.bottom >= box.bottom)
6654                {
6655                   rootWindow.dirty = true;
6656                   return;
6657                }
6658             }
6659
6660             if(display.flags.flipping && !rootWindow.dirty)
6661             {
6662                if(this == rootWindow)
6663                   region = null;
6664                else
6665                {
6666                   rootWindow.Update(null);
6667                   return;
6668                }
6669             }
6670
6671             rootWindow.dirty = true;
6672
6673             if(region != null)
6674             {
6675                realBox = region;
6676                realBox.left += clientStart.x;
6677                realBox.top += clientStart.y;
6678                realBox.right += clientStart.x;
6679                realBox.bottom += clientStart.y;
6680                realBox.Clip(box);
6681             }
6682             else
6683                realBox = box;
6684
6685             if(realBox.right >= realBox.left &&
6686                realBox.bottom >= realBox.top)
6687             {
6688                // if(!rootWindow.fullRender)
6689                   dirtyArea.UnionBox(realBox, rootWindow.tempExtents[0]);
6690
6691                for(child = children.first; child; child = child.next)
6692                {
6693                   if(!child.is3D)
6694                   {
6695                      Box box = realBox;
6696                      box.left -= child.absPosition.x - absPosition.x;
6697                      box.top -= child.absPosition.y - absPosition.y;
6698                      box.right -= child.absPosition.x - absPosition.x;
6699                      box.bottom -= child.absPosition.y - absPosition.y;
6700                      if(box.right >= child.box.left && box.left <= child.box.right &&
6701                         box.bottom >= child.box.top && box.top <= child.box.bottom)
6702                      {
6703                         box.left -= child.clientStart.x;
6704                         box.top -= child.clientStart.y;
6705                         box.right -= child.clientStart.x;
6706                         box.bottom -= child.clientStart.y;
6707                         child.Update(box);
6708                      }
6709                   }
6710                }
6711
6712                realBox.left += absPosition.x - rootWindow.absPosition.x;
6713                realBox.top += absPosition.y - rootWindow.absPosition.y;
6714                realBox.right += absPosition.x - rootWindow.absPosition.x;
6715                realBox.bottom += absPosition.y - rootWindow.absPosition.y;
6716                rootWindow.dirtyBack.UnionBox(realBox, rootWindow.tempExtents[0]);
6717             }
6718          }
6719          else if(this == guiApp.desktop)
6720          {
6721             Window window;
6722             for(window = children.first; window; window = window.next)
6723             {
6724                if(!window.is3D)
6725                {
6726                   if(region != null)
6727                   {
6728                      Box childBox = region;
6729
6730                      childBox.left    -= window.absPosition.x - guiApp.desktop.absPosition.x;
6731                      childBox.top     -= window.absPosition.y - guiApp.desktop.absPosition.y;
6732                      childBox.right   -= window.absPosition.x - guiApp.desktop.absPosition.x;
6733                      childBox.bottom  -= window.absPosition.y - guiApp.desktop.absPosition.y;
6734
6735                      window.Update(childBox);
6736                   }
6737                   else
6738                      window.Update(null);
6739                }
6740             }
6741          }
6742
6743          // rootWindow.mutex.Release();
6744       }
6745    }
6746
6747    bool Capture(void)
6748    {
6749       bool result = true;
6750       if(guiApp.windowCaptured != this)
6751       {
6752          if(guiApp.windowCaptured)
6753             result = false;
6754          else
6755          {
6756             //Logf("Captured %s (%s)\n", caption, class.name);
6757             guiApp.interfaceDriver.SetMouseCapture(rootWindow);
6758             guiApp.windowCaptured = this;
6759          }
6760       }
6761       return result;
6762    }
6763
6764    bool Destroy(int64 code)
6765    {
6766       //if(created)
6767       if(this)
6768       {
6769          if(!destroyed && !CloseConfirmation(false)) return false;
6770          incref this;
6771          if(DestroyEx(code))
6772          {
6773             // TOCHECK: Should autoCreate be set to false here?
6774             autoCreate = false;
6775             wasCreated = false;
6776             delete this;
6777             return true;
6778          }
6779          delete this;
6780       }
6781       return false;
6782    }
6783
6784    void Move(int x, int y, int w, int h)
6785    {
6786       normalAnchor = Anchor { left = x, top = y };
6787       normalSizeAnchor = SizeAnchor { size = { w, h } };
6788
6789       if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
6790       {
6791          if(destroyed) return;
6792
6793          stateAnchor = normalAnchor;
6794          stateSizeAnchor = normalSizeAnchor;
6795
6796          ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
6797          Position(x,y, w, h, true, true, true, true, false, true);
6798       }
6799    }
6800
6801    DialogResult Modal(void)
6802    {
6803       isModal = true;
6804       if(Create())
6805          return DoModal();
6806
6807       // FIXES MEMORY LEAK IF Create() FAILED
6808       incref this;
6809       delete this;
6810       return 0;
6811    }
6812
6813    void SetScrollArea(int width, int height, bool snapToStep)
6814    {
6815       if(snapToStep)
6816       {
6817          int stepX = sbStep.x, stepY = sbStep.y;
6818          // Needed to make snapped down position match the skin's check of client area
6819          // against realvirtual
6820          if(guiApp.textMode)
6821          {
6822             SNAPDOWN(stepX, textCellW);
6823             SNAPDOWN(stepY, textCellH);
6824             stepX = Max(stepX, textCellW);
6825             stepY = Max(stepY, textCellH);
6826          }
6827          if(scrollFlags.snapX)
6828             SNAPUP(width, stepX);
6829          if(scrollFlags.snapY)
6830             SNAPUP(height, stepY);
6831       }
6832
6833       reqScrollArea.w = width;
6834       reqScrollArea.h = height;
6835       noAutoScrollArea = (width > 0 || height > 0);
6836
6837       UpdateScrollBars(true, true);
6838    }
6839
6840    void SetScrollPosition(int x, int y)
6841    {
6842       if(sbh)
6843          sbh.Action(setPosition, x, 0);
6844       else
6845       {
6846          int range;
6847          int seen = clientSize.w, total = reqScrollArea.w;
6848          seen = Max(1,seen);
6849          if(scrollFlags.snapX)
6850             SNAPDOWN(seen, sbStep.x);
6851
6852          if(!total) total = seen;
6853          range = total - seen + 1;
6854          range = Max(range, 1);
6855          if(x < 0) x = 0;
6856          if(x >= range) x = range - 1;
6857
6858          if(scrollFlags.snapX)
6859             SNAPUP(x, sbStep.x);
6860
6861          if(scroll.x != x)
6862             OnHScroll(setPosition, x, 0);
6863
6864          if(guiApp.textMode)
6865          {
6866             SNAPDOWN(x, textCellW);
6867          }
6868          scroll.x = x;
6869       }
6870
6871       if(sbv)
6872          sbv.Action(setPosition, y, 0);
6873       else
6874       {
6875          int range;
6876          int seen = clientSize.h, total = reqScrollArea.h;
6877          seen = Max(1,seen);
6878
6879          if(scrollFlags.snapY)
6880             SNAPDOWN(seen, sbStep.y);
6881
6882          if(!total) total = seen;
6883          range = total - seen + 1;
6884          range = Max(range, 1);
6885          if(y < 0) y = 0;
6886          if(y >= range) y = range - 1;
6887
6888          if(scrollFlags.snapY)
6889             SNAPUP(y, sbStep.y);
6890
6891          if(scroll.y != y)
6892             OnVScroll(setPosition, y, 0);
6893          if(guiApp.textMode)
6894          {
6895             SNAPDOWN(y, textCellH);
6896          }
6897          scroll.y = y;
6898       }
6899       if(!sbh || !sbv)
6900          UpdateCaret(false, false);
6901    }
6902
6903    void SetScrollLineStep(int stepX, int stepY)
6904    {
6905       sbStep.x = stepX;
6906       sbStep.y = stepY;
6907       if(guiApp.textMode)
6908       {
6909          SNAPDOWN(stepX, textCellW);
6910          SNAPDOWN(stepY, textCellH);
6911          stepX = Max(stepX, textCellW);
6912          stepY = Max(stepY, textCellH);
6913       }
6914       if(sbh)
6915          sbh.lineStep = stepX;
6916       if(sbv)
6917          sbv.lineStep = stepY;
6918    }
6919
6920    void SetState(WindowState newState, bool activate, Modifiers mods)
6921    {
6922       if(created)
6923       {
6924          if(state == newState || OnStateChange(newState, mods))
6925          {
6926             //WindowState prevState = state;
6927
6928             StopMoving();
6929
6930             // This used to be at the end of the brackets... moved for X, testing...
6931             // This has the effect of activating the window through the system...
6932             if(rootWindow == this)
6933                guiApp.interfaceDriver.SetRootWindowState(this, newState, !style.hidden);
6934
6935             SetStateEx(newState, activate);
6936
6937             if(rootWindow == this && !rootWindow.nativeDecorations)
6938             {
6939                int x = position.x, y = position.y;
6940                /*if(style.interim)
6941                {
6942                   x -= guiApp.desktop.absPosition.x;
6943                   y -= guiApp.desktop.absPosition.y;
6944                }*/
6945                guiApp.interfaceDriver.PositionRootWindow(this, x, y, size.w, size.h, true, true);
6946             }
6947
6948             //state = newState;
6949             //state = prevState;
6950
6951             if(state != maximized && style.hasMaximize)
6952             {
6953                Window child;
6954                for(child = parent.children.first; child; child = child.next)
6955                {
6956                   if(child != this && child.state == maximized)
6957                      child.SetStateEx(normal, false);
6958                }
6959             }
6960
6961             if(!style.nonClient && (sbv || sbh) && this != parent.sbv && this != parent.sbh)
6962                parent.UpdateScrollBars(true, true);
6963
6964             /*
6965             // Do we really need this stuff here?
6966             // Shouldn't the Activate stuff take care of it?
6967             if(parent.rootWindow == parent && style)
6968             {
6969                char caption[2048];
6970                parent.FigureCaption(caption);
6971                guiApp.interfaceDriver.SetRootWindowCaption(parent, caption);
6972                parent.UpdateDecorations();
6973             }
6974             */
6975
6976             rootWindow.ConsequentialMouseMove(false);
6977          }
6978       }
6979       else
6980          state = newState;
6981    }
6982
6983    BitmapResource GetIcon(SkinBitmap iconID)
6984    {
6985       return guiApp.currentSkin.GetBitmap(iconID);
6986    }
6987
6988    void SetMouseRange(Box range)
6989    {
6990       if(range || guiApp.fullScreenMode)
6991       {
6992          Box clip;
6993          if(range != null)
6994          {
6995             clip.left   = range.left + absPosition.x + clientStart.x;
6996             clip.top    = range.top + absPosition.y + clientStart.y;
6997             clip.right  = range.right + absPosition.x + clientStart.x;
6998             clip.bottom = range.bottom + absPosition.y + clientStart.y;
6999          }
7000          else
7001          {
7002             clip.left   = guiApp.desktop.box.left;
7003             clip.top    = guiApp.desktop.box.top;
7004             clip.right  = guiApp.desktop.box.right;
7005             clip.bottom = guiApp.desktop.box.bottom;
7006          }
7007          guiApp.interfaceDriver.SetMouseRange(rootWindow, clip);
7008       }
7009       else
7010          guiApp.interfaceDriver.SetMouseRange(rootWindow, null);
7011    }
7012
7013    void SetMouseRangeToClient(void)
7014    {
7015       if(guiApp.fullScreenMode || this != guiApp.desktop)
7016       {
7017          Box box {0, 0, clientSize.w - 1, clientSize.h - 1 };
7018          box.Clip(clientArea);
7019          SetMouseRange(box);
7020       }
7021       else
7022          SetMouseRange(null);
7023    }
7024
7025    void SetMouseRangeToWindow(void)
7026    {
7027       Box box { -clientStart.x, -clientStart.y, size.w-1, size.h-1 };
7028       if(this == guiApp.desktop)
7029          SetMouseRangeToClient();
7030       else
7031          SetMouseRange(box);
7032    }
7033
7034    // x, y: Desktop Coordinates
7035    void ShowSysMenu(int x, int y)
7036    {
7037       Menu menu { };
7038       PopupMenu windowMenu { master = this, interim = true, position = { x + 1 - guiApp.desktop.position.x, y + 1 - guiApp.desktop.position.y }, menu = menu };
7039       MenuItem
7040       {
7041          menu, $"Restore", r, NotifySelect = MenuWindowRestore,
7042          disabled = (!style.hasMaximize && !style.hasMinimize) || state == normal, bitmap = guiApp.currentSkin.GetBitmap(restore)
7043       };
7044       MenuItem
7045       {
7046          menu, $"Move", m, NotifySelect = MenuWindowMove,
7047          disabled = !style.fixed || state == maximized
7048       };
7049       MenuItem
7050       {
7051          menu, $"Size", s, NotifySelect = MenuWindowSize,
7052          disabled = !style.sizable || state != normal
7053       };
7054       MenuItem
7055       {
7056          menu, $"Minimize", n, NotifySelect = MenuWindowMinimize,
7057          disabled = !style.hasMinimize || state == minimized, bitmap = guiApp.currentSkin.GetBitmap(minimize)
7058       };
7059       MenuItem
7060       {
7061          menu, $"Maximize", KeyCode::x, NotifySelect = MenuWindowMaximize,
7062          disabled = !style.hasMaximize || state == maximized, bitmap = guiApp.currentSkin.GetBitmap(maximize)
7063       };
7064       MenuItem
7065       {
7066          menu, $"Stay On Top", t, NotifySelect = MenuWindowStayOnTop,
7067          disabled = !style.fixed, checkable = true, checked = style.stayOnTop
7068       };
7069       MenuDivider { menu };
7070       MenuItem
7071       {
7072          menu, $"Close", c, (parent == guiApp.desktop) ? altF4 : ( style.isActiveClient ? ctrlF4 : 0), NotifySelect = MenuWindowClose,
7073          bold = true, disabled = !style.hasClose, bitmap = guiApp.currentSkin.GetBitmap(close)
7074       };
7075       windowMenu.Create();
7076    }
7077
7078    void Activate(void)
7079    {
7080       ActivateEx(true, true, true, true, null, null);
7081    }
7082
7083    void MakeActive(void)
7084    {
7085       ActivateEx(true, false, true, false, null, null);
7086    }
7087
7088    void SoftActivate(void)
7089    {
7090       if(guiApp.desktop.active)
7091          Activate();
7092       else if(!active)
7093       {
7094          MakeActive();
7095          if(this == rootWindow)
7096             Flash();
7097       }
7098    }
7099
7100    void Deactivate(void)
7101    {
7102       ActivateEx(false, true, true, true, null, null);
7103    }
7104
7105    void Flash(void)
7106    {
7107       guiApp.interfaceDriver.FlashRootWindow(rootWindow);
7108    }
7109
7110    bool CycleChildren(bool backward, bool clientOnly, bool tabCycleOnly, bool cycleParents)
7111    {
7112       bool result = false;
7113       if(activeChild && activeChild.cycle)
7114       {
7115          Window modalWindow, child = activeChild;
7116          if(!clientOnly /*&& parent.tabCycle*/)
7117          {
7118             Window next = child;
7119             while(true)
7120             {
7121                if(next.cycle == (backward ? childrenCycle.first : childrenCycle.last))
7122                {
7123                   if(cycleParents)
7124                   {
7125                      if(parent && parent.CycleChildren(backward, false, true, true))
7126                         return true;
7127                      break;
7128                   }
7129                   else
7130                      return false;
7131                }
7132                if(backward)
7133                   next = next.cycle.prev.data;
7134                else
7135                   next = next.cycle.next.data;
7136                if(!next.disabled && !next.inactive /*isRemote*/ && next.created && !next.nonClient && (!clientOnly || next.style.isActiveClient) && !next.style.hidden && next.FindModal() != activeChild)
7137                   break;
7138             }
7139          }
7140          /*
7141          if(!clientOnly && child.cycle == (backward ? childrenCycle.first : childrenCycle.last) &&
7142             parent.tabCycle && parent.CycleChildren(backward, false, false))
7143             return true;
7144          */
7145
7146          if(tabCycleOnly && !tabCycle) return false;
7147
7148          while(child)
7149          {
7150             while(true)
7151             {
7152                if(backward)
7153                   child = child.cycle.prev.data;
7154                else
7155                   child = child.cycle.next.data;
7156                if(child == child.parent.activeChild)
7157                   return result;
7158                else if(!child.disabled && child.created && (!clientOnly || child.style.isActiveClient) && !child.style.hidden && child.FindModal() != activeChild)
7159                   break;
7160             }
7161             modalWindow = child.FindModal();
7162             if(!modalWindow)
7163             {
7164                // Scroll the window to include the active control
7165                if(sbh && !child.style.dontScrollHorz)
7166                {
7167                   if(child.scrolledPos.x < 0)
7168                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x, 0);
7169                   else if(child.scrolledPos.x + child.size.w > clientSize.w)
7170                      sbh.Action(setPosition, scroll.x + child.scrolledPos.x + child.size.w - clientSize.w, 0);
7171                }
7172                if(sbv && !child.style.dontScrollVert)
7173                {
7174                   if(child.scrolledPos.y < 0)
7175                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y, 0);
7176                   else if(child.scrolledPos.y + child.size.h > clientSize.h)
7177                      sbv.Action(setPosition, scroll.y + child.scrolledPos.y + child.size.h - clientSize.h, 0);
7178                }
7179             }
7180             result = true;
7181             child = modalWindow ? modalWindow : child;
7182             child.ActivateEx(true, true, true, true, null, null);
7183             if(child.tabCycle && child.childrenCycle.first)
7184                child = ((OldLink)(backward ? child.childrenCycle.first : child.childrenCycle.last)).data;
7185             else
7186                break;
7187          }
7188       }
7189       else
7190          return false;
7191
7192       ConsequentialMouseMove(false);
7193       return result;
7194    }
7195
7196    void AddResource(Resource resource)
7197    {
7198       if(resource)
7199       {
7200          ResPtr ptr { resource = resource };
7201          resources.Add(ptr);
7202          incref resource;
7203
7204          // Load Graphics here if window is created already
7205          if(/*created && */display)
7206          {
7207             display.Lock(false);
7208             if(!ptr.loaded)   // This check prevents a leak in case a watcher on 'font' calls AddResource (ListBox FontResource leak)
7209                ptr.loaded = display.displaySystem.LoadResource(resource);
7210             display.Unlock();
7211          }
7212          /*
7213          // Temporary hack to load font right away for listbox in dropbox ...
7214          else if(master && master.display)
7215          {
7216             master.display.Lock(false);
7217             master.display.displaySystem.LoadResource(resource);
7218             master.display.Unlock();
7219          }
7220          */
7221       }
7222    }
7223
7224    void RemoveResource(Resource resource)
7225    {
7226       if(resource)
7227       {
7228          ResPtr ptr;
7229          for(ptr = resources.first; ptr; ptr = ptr.next)
7230          {
7231             if(ptr.resource == resource)
7232                break;
7233          }
7234
7235          if(ptr)
7236          {
7237             // Unload Graphics here if window is created already
7238             if(/*created && */display)
7239             {
7240                if(ptr.loaded)
7241                {
7242                   display.Lock(false);
7243                   display.displaySystem.UnloadResource(resource, ptr.loaded);
7244                   display.Unlock();
7245                   ptr.loaded = null;
7246                }
7247             }
7248             delete resource;
7249             resources.Delete(ptr);
7250          }
7251       }
7252    }
7253
7254    void SetCaret(int x, int y, int size)
7255    {
7256       if(!destroyed)
7257       {
7258          caretPos.x = x;
7259          caretPos.y = y;
7260          caretSize = size;
7261          if(active && !style.interim && isEnabled)
7262          {
7263             if(visible || !guiApp.caretOwner)
7264                guiApp.caretOwner = size ? this : null;
7265             if(size)
7266                UpdateCaret(false, false);
7267             else
7268             {
7269                guiApp.interfaceDriver.SetCaret(0,0,0);
7270                UpdateCaret(false, true);
7271                guiApp.caretEnabled = false;
7272             }
7273          }
7274          else if(style.inactive && active)
7275          {
7276             guiApp.interfaceDriver.SetCaret(0,0,0);
7277             UpdateCaret(false, true);
7278             guiApp.caretEnabled = false;
7279          }
7280       }
7281    }
7282
7283    void Scroll(int x, int y)
7284    {
7285       bool opaque = !style.drawBehind || background.a;
7286       if(opaque && display && display.flags.scrolling)
7287       {
7288          Box box = clientArea;
7289          box.left += clientStart.x;
7290          box.top += clientStart.y;
7291          box.right += clientStart.x;
7292          box.bottom += clientStart.y;
7293
7294          //scrollExtent.Free(null);
7295          scrollExtent.AddBox(box);
7296          scrolledArea.x += x;
7297          scrolledArea.y += y;
7298
7299          //scrollExtent.Free();
7300          //scrollExtent.AddBox(clientArea);
7301          //scrollExtent.Offset(clientStart.x, clientStart.y);
7302          //scrolledArea.x = x;
7303          //scrolledArea.y = y;
7304       }
7305       else
7306          Update(clientArea);
7307
7308       if(rootWindow)
7309          rootWindow.dirty = true;
7310    }
7311
7312    void ReleaseCapture()
7313    {
7314       if(guiApp && guiApp.windowCaptured && guiApp.windowCaptured == this)
7315       {
7316          Window oldCaptured = guiApp.windowCaptured;
7317          guiApp.windowCaptured = null;
7318          guiApp.prevWindow = null;
7319          incref oldCaptured;
7320
7321          //guiApp.Log("Released Capture\n");
7322
7323          guiApp.interfaceDriver.SetMouseCapture(null);
7324
7325          //oldCaptured.OnMouseCaptureLost();
7326
7327          if(oldCaptured)
7328             oldCaptured.ConsequentialMouseMove(false);
7329          delete oldCaptured;
7330       }
7331    }
7332
7333    private void _SetCaption(const char * format, va_list args)
7334    {
7335       if(this)
7336       {
7337          delete caption;
7338          if(format)
7339          {
7340             char caption[MAX_F_STRING];
7341             vsnprintf(caption, sizeof(caption), format, args);
7342             caption[sizeof(caption)-1] = 0;
7343
7344             this.caption = CopyString(caption);
7345          }
7346          if(created)
7347             UpdateCaption();
7348
7349          firewatchers caption;
7350       }
7351    }
7352
7353    /*deprecated*/ void SetText(const char * format, ...)
7354    {
7355       va_list args;
7356       va_start(args, format);
7357       _SetCaption(format, args);
7358       va_end(args);
7359    }
7360
7361    void SetCaption(const char * format, ...)
7362    {
7363       va_list args;
7364       va_start(args, format);
7365       _SetCaption(format, args);
7366       va_end(args);
7367    }
7368
7369    bool Grab(Bitmap bitmap, Box box, bool decorations)
7370    {
7371       bool result = false;
7372       if(display || this == guiApp.desktop)
7373       {
7374          Box clip = {MININT, MININT, MAXINT, MAXINT};
7375
7376          if(box != null)
7377             clip = box;
7378
7379          if(!decorations)
7380             clip.Clip(clientArea);
7381          else
7382             clip.Clip(this.box);
7383
7384          if(rootWindow != this)
7385          {
7386             clip.left   += absPosition.y;
7387             clip.top    += absPosition.y;
7388             clip.right  += absPosition.x;
7389             clip.bottom += absPosition.y;
7390          }
7391
7392          if(!nativeDecorations)
7393          {
7394             clip.left += decorations ? 0 : clientStart.x;
7395             clip.top += decorations ? 0 : clientStart.y;
7396             clip.right += decorations ? 0 : clientStart.x;
7397             clip.bottom += decorations ? 0 : clientStart.y;
7398          }
7399
7400          if(decorations && this == guiApp.desktop)
7401             clip = { 0, 0, guiApp.virtualScreen.w, guiApp.virtualScreen.h };
7402
7403          if(display && display.flags.flipping)
7404          {
7405             rootWindow.Update(null);
7406             rootWindow.UpdateDisplay();
7407          }
7408
7409          if(!display)
7410          {
7411             Window window { };
7412             window.Create();
7413             result = window.display.displaySystem.driver.GrabScreen(null, bitmap, clip.left, clip.top,
7414                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7415             delete window;
7416          }
7417          else
7418             result = display.Grab(bitmap, clip.left, clip.top,
7419                clip.right - clip.left + 1, clip.bottom - clip.top + 1);
7420
7421          if(bitmap.pixelFormat != pixelFormat888 && bitmap.pixelFormat != pixelFormat8)
7422          {
7423             if(!bitmap.Convert(null, pixelFormat888, null))
7424                result = false;
7425          }
7426       }
7427       return result;
7428    }
7429
7430    void GetMousePosition(int * x, int * y)
7431    {
7432       int mouseX = 0, mouseY = 0;
7433       if(!guiApp.acquiredWindow && (guiApp.desktop.active || !guiApp.fullScreenMode))
7434       {
7435          if(guiApp.driver)
7436             guiApp.interfaceDriver.GetMousePosition(&mouseX, &mouseY);
7437          if(this != guiApp.desktop)
7438          {
7439             mouseX -= absPosition.x + clientStart.x;
7440             mouseY -= absPosition.y + clientStart.y;
7441          }
7442       }
7443       if(x) *x = mouseX;
7444       if(y) *y = mouseY;
7445    }
7446
7447    DialogResult DoModal()
7448    {
7449       DialogResult returnCode = 0;
7450       int terminated = terminateX;
7451       isModal = true;
7452       incref this;
7453       while(!destroyed && guiApp.driver != null)
7454       {
7455          if(terminateX != terminated)
7456          {
7457             terminated = terminateX;
7458             guiApp.desktop.Destroy(0);
7459             if(guiApp.desktop.created)
7460             {
7461                terminated = 0;
7462                //printf("Resetting terminate X to 0\n");
7463                terminateX = 0;
7464             }
7465             break;
7466          }
7467
7468          guiApp.UpdateDisplay();
7469          if(!guiApp.ProcessInput(false))
7470             guiApp.Wait();
7471       }
7472       returnCode = this.returnCode;
7473       delete this;
7474       return returnCode;
7475    }
7476
7477    void DoModalStart()
7478    {
7479       isModal = true;
7480       incref this;
7481    }
7482
7483    bool DoModalLoop()
7484    {
7485       return !destroyed && guiApp.driver != null && terminateX < 2;
7486    }
7487
7488    DialogResult DoModalEnd()
7489    {
7490       DialogResult returnCode = this.returnCode;
7491       delete this;
7492       return returnCode;
7493    }
7494
7495    // --- Window manipulation ---
7496    /*bool GetDisabled()
7497    {
7498       bool disabled = this.disabled;
7499       Window window;
7500       for(window = this; (window = window.master); )
7501       {
7502          if(window.disabled)
7503          {
7504             disabled = true;
7505             break;
7506          }
7507       }
7508       return disabled;
7509    }*/
7510
7511    // --- Mouse Manipulation ---
7512    void GetNCMousePosition(int * x, int * y)
7513    {
7514       GetMousePosition(x, y);
7515       if(x) *x += clientStart.x;
7516       if(y) *y += clientStart.y;
7517    }
7518
7519    // --- Carets manipulation ---
7520    void GetCaretPosition(Point caretPos)
7521    {
7522       caretPos = this.caretPos;
7523    }
7524
7525    int GetCaretSize(void)
7526    {
7527       return caretSize;
7528    }
7529
7530    bool ButtonCloseDialog(Button button, int x, int y, Modifiers mods)
7531    {
7532       Destroy(button.id);
7533       return true;
7534    }
7535
7536    bool CloseConfirmation(bool parentClosing)
7537    {
7538       bool result = true;
7539       OldLink slave;
7540       Window child;
7541
7542       if(closing)
7543          return false;
7544       if(terminateX > 1)
7545          return true;
7546
7547       closing = true;
7548
7549       if(!OnClose(parentClosing))
7550          result = false;
7551
7552       // If you want to skip this, simply set modifiedDocument to false in OnClose
7553       if(result && (/*fileName || */style.isDocument) && modifiedDocument)
7554       {
7555          DialogResult dialogRes;
7556          char message[1024];
7557          if(fileName)
7558             sprintf(message, $"Save changes to %s?", fileName);
7559          else
7560             sprintf(message, $"Save changes to Untitled %d?", documentID);
7561
7562          dialogRes = MessageBox { master = master, type = yesNoCancel, text = parent.caption ? parent.caption : rootWindow.caption, contents = message }.Modal();
7563
7564          if(dialogRes == yes)
7565          {
7566             // TOFIX: Precomp error if brackets are taken out
7567             result = (DialogResult)MenuFileSave(null, 0) != cancel;
7568          }
7569          else if(dialogRes == cancel)
7570             result = false;
7571       }
7572
7573       if(result)
7574       {
7575          for(slave = slaves.first; slave; slave = slave.next)
7576          {
7577             Window w = slave.data;
7578             if(w.parent != this && !w.IsDescendantOf(this) && !w.CloseConfirmation(true))
7579             {
7580                result = false;
7581                break;
7582             }
7583          }
7584       }
7585
7586       // Confirm closure of active clients first (We use OnClose() to hide instead of destroy in the IDE)
7587       if(result)
7588       {
7589          for(child = children.first; child; child = child.next)
7590             if(child.isActiveClient && !child.CloseConfirmation(true))
7591             {
7592                result = false;
7593                break;
7594             }
7595       }
7596       if(result)
7597       {
7598          for(child = children.first; child; child = child.next)
7599             if(!child.isActiveClient && !child.CloseConfirmation(true))
7600             {
7601                result = false;
7602                break;
7603             }
7604       }
7605       closing = false;
7606       return result;
7607    }
7608
7609    // Static methods... move them somewhere else?
7610    void ::RestoreCaret()
7611    {
7612       if(guiApp.caretOwner)
7613          guiApp.caretOwner.UpdateCaret(false, false);
7614    }
7615
7616    void ::FreeMouseRange()
7617    {
7618       guiApp.interfaceDriver.SetMouseRange(null, null);
7619    }
7620
7621    // Menu Methods
7622    bool MenuFileClose(MenuItem selection, Modifiers mods)
7623    {
7624       Window document = activeChild;
7625       if(document)
7626          document.Destroy(0);
7627       return true;
7628    }
7629
7630    bool MenuFileExit(MenuItem selection, Modifiers mods)
7631    {
7632       Destroy(0);
7633       return true;
7634    }
7635
7636    bool MenuFileSave(MenuItem selection, Modifiers mods)
7637    {
7638       SetupFileMonitor();
7639       if(fileName)
7640       {
7641 #if !defined(__EMSCRIPTEN__)
7642          fileMonitor.fileName = null;
7643 #endif
7644          saving = true;
7645
7646          if(OnSaveFile(fileName))
7647          {
7648             //if(OnFileModified != Window::OnFileModified)
7649             {
7650                saving = false;
7651 #if !defined(__EMSCRIPTEN__)
7652                fileMonitor.fileName = fileName;
7653 #endif
7654             }
7655             return true;
7656          }
7657          else
7658          {
7659             MessageBox dialog { master = master, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7660             DialogResult answer = dialog.Modal();
7661             saving = false;
7662             if(answer != yes) return (bool)answer;
7663          }
7664       }
7665       return MenuFileSaveAs(selection, mods);
7666    }
7667
7668    bool MenuFileSaveAs(MenuItem selection, Modifiers mods)
7669    {
7670       DialogResult result = (DialogResult)bool::true;
7671       FileDialog fileDialog = saveDialog;
7672
7673       SetupFileMonitor();
7674
7675       if(!fileDialog)
7676          fileDialog = FileDialog {};
7677       if(fileDialog)
7678       {
7679          incref fileDialog;
7680          if(fileName)
7681             fileDialog.filePath = fileName;
7682          else
7683          {
7684             char filePath[MAX_FILENAME];
7685             sprintf(filePath, "Untitled %d", documentID);
7686             fileDialog.filePath = filePath;
7687          }
7688 #if !defined(__EMSCRIPTEN__)
7689          fileMonitor.fileName = null;
7690 #endif
7691
7692          fileDialog.type = save;
7693          fileDialog.text = $"Save As";
7694
7695          while(true)
7696          {
7697             fileDialog.master = master.parent ? master : this;
7698             if(fileDialog.Modal() == ok)
7699             {
7700                const char * filePath = fileDialog.filePath;
7701                saving = true;
7702                if(OnSaveFile(filePath))
7703                {
7704                   saving = false;
7705                   property::fileName = filePath;
7706                   NotifySaved(master, this, filePath);
7707                   break;
7708                }
7709                else
7710                {
7711                   MessageBox dialog { master = master.parent ? master : this, type = yesNoCancel, text = $"Error writing file", contents = $"Save as a different file?" };
7712                   DialogResult answer = dialog.Modal();
7713                   saving = false;
7714                   if(answer != yes)
7715                   {
7716                      result = answer;
7717                      break;
7718                   }
7719                }
7720             }
7721             else
7722             {
7723                result = cancel;
7724                break;
7725             }
7726          }
7727 #if !defined(__EMSCRIPTEN__)
7728          //if(OnFileModified != Window::OnFileModified && fileName)
7729          {
7730             if(fileName)
7731                fileMonitor.fileName = fileName;
7732          }
7733 #endif
7734          delete fileDialog;
7735       }
7736       return (bool)result; // Actually returning result from Yes/NoCancel message box
7737    }
7738
7739    bool MenuFileSaveAll(MenuItem selection, Modifiers mods)
7740    {
7741       Window document = activeChild;
7742       Window next;
7743       for(document = children.first; document; document = next)
7744       {
7745          next = document.next;
7746          if(document.style.isDocument || document.fileName)
7747             document.MenuFileSave(selection, mods);
7748       }
7749       return true;
7750    }
7751
7752    bool MenuWindowArrangeIcons(MenuItem selection, Modifiers mods)
7753    {
7754       Window document;
7755
7756       for(document = children.first; document; document = document.next)
7757          //if(document.style.isDocument && document.state == minimized)
7758          if(document.style.isActiveClient && document.state == minimized)
7759             document.SetState(minimized, false, mods);
7760       return true;
7761    }
7762
7763    bool MenuWindowCascade(MenuItem selection, Modifiers mods)
7764    {
7765       Window document = activeChild;
7766       if(document)
7767       {
7768          Window firstDocument = null;
7769          Window child;
7770          OldLink cycle = document.cycle.prev;
7771          int id = 0;
7772          while(true)
7773          {
7774             child = cycle.data;
7775             if(child.style.isActiveClient && !child.style.hidden)
7776             {
7777                Window last;
7778
7779                firstDocument = child;
7780                if(child.state == minimized)
7781                   child.SetState(minimized, false, mods);
7782                else
7783                {
7784                   child.positionID = id++;
7785                   child.SetState(normal, false, mods);
7786                   child.anchor.left.type = cascade;
7787                   {
7788                      int x, y, w, h;
7789                      child.normalSizeAnchor = *&child.sizeAnchor;
7790                      child.normalAnchor = child.anchor;
7791
7792                      // Break the anchors for moveable/resizable windows
7793                      if(child.style.fixed)
7794                      {
7795                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7796
7797                         (*&child.normalAnchor).left = x;
7798                         (*&child.normalAnchor).top = y;
7799                         (*&child.normalAnchor).right.type = none;
7800                         (*&child.normalAnchor).bottom.type = none;
7801                         (*&child.normalSizeAnchor).isClientW = false;
7802                         (*&child.normalSizeAnchor).isClientH = false;
7803                         (*&child.normalSizeAnchor).size.w = w;
7804                         (*&child.normalSizeAnchor).size.h = h;
7805                         child.anchored = false;
7806                      }
7807
7808                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7809                      {
7810                         child.stateAnchor = child.normalAnchor;
7811                         child.stateSizeAnchor = child.normalSizeAnchor;
7812
7813                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7814                         child.Position(x, y, w, h, true, true, true, true, false, false);
7815                      }
7816                   }
7817                }
7818
7819                last = children.last;
7820                if(!child.style.stayOnTop)
7821                   for(; last && last.style.stayOnTop; last = last.prev);
7822                children.Move(child, last);
7823                childrenOrder.Move(child.order, childrenOrder.last);
7824             }
7825             if(cycle == document.cycle) break;
7826             cycle = cycle.prev;
7827          }
7828          if(firstDocument)
7829             firstDocument.Activate();
7830       }
7831       return true;
7832    }
7833
7834    bool MenuWindowClose(MenuItem selection, Modifiers mods)
7835    {
7836       if(style.hasClose)
7837          Destroy(0);
7838       return true;
7839    }
7840
7841    // Close all closes all active clients, not all documents
7842    bool MenuWindowCloseAll(MenuItem selection, Modifiers mods)
7843    {
7844       Window next, document;
7845
7846       for(document = children.first; document; document = next)
7847       {
7848          for(next = document.next; next && !next.style.isActiveClient; next = next.next);
7849          if(document.style.isActiveClient)
7850             if(!document.Destroy(0) && !document.style.hidden)
7851                return false;
7852       }
7853       return true;
7854    }
7855
7856    bool MenuWindowMaximize(MenuItem selection, Modifiers mods)
7857    {
7858       if(style.hasMaximize && state != maximized)
7859          SetState(maximized, 0, 0);
7860       return true;
7861    }
7862
7863    bool MenuWindowMinimize(MenuItem selection, Modifiers mods)
7864    {
7865       if(style.hasMinimize && state != minimized)
7866       {
7867          SetState(minimized, 0, 0);
7868          parent.CycleChildren(false, true, false, true);
7869       }
7870       return true;
7871    }
7872
7873    bool MenuWindowMove(MenuItem selection, Modifiers mods)
7874    {
7875       MenuMoveOrSize(false, selection ? true : false);
7876       return true;
7877    }
7878
7879    bool MenuWindowNext(MenuItem selection, Modifiers mods)
7880    {
7881       CycleChildren(false, true, false, true);
7882       return true;
7883    }
7884
7885    bool MenuWindowPrevious(MenuItem selection, Modifiers mods)
7886    {
7887       CycleChildren(true, true, false, true);
7888       return true;
7889    }
7890
7891    bool MenuWindowSize(MenuItem selection, Modifiers mods)
7892    {
7893       MenuMoveOrSize(true, true);
7894       return true;
7895    }
7896
7897    bool MenuWindowRestore(MenuItem selection, Modifiers mods)
7898    {
7899       if(state != normal)
7900          SetState(normal, 0, 0);
7901       return true;
7902    }
7903
7904    bool MenuWindowSelectWindow(MenuItem selection, Modifiers mods)
7905    {
7906       Window document;
7907       int64 id = selection.id;
7908       OldLink cycle = activeClient.cycle;
7909       int c = 0;
7910       //for(c = 0, cycle = activeChild.cycle; c<id; cycle = cycle.next, c++);
7911       while(true)
7912       {
7913          Window sibling = cycle.data;
7914          if(sibling.style.isActiveClient && sibling.visible && !sibling.style.nonClient)
7915          {
7916             if(c == id)
7917                break;
7918             c++;
7919          }
7920          cycle = cycle.next;
7921       }
7922       document = cycle.data;
7923       document.Activate();
7924
7925       //if(activeChild.state == maximized)
7926       //  document.SetState(maximized, false, mods);
7927       //else if(document.state == minimized)
7928       //   document.SetState(normal, false, mods);
7929       return true;
7930    }
7931
7932    bool MenuWindowStayOnTop(MenuItem selection, Modifiers mods)
7933    {
7934       stayOnTop = !style.stayOnTop;
7935       return true;
7936    }
7937
7938    bool MenuWindowTileHorz(MenuItem selection, Modifiers mods)
7939    {
7940       Window document = activeChild;
7941       if(document)
7942       {
7943          Window firstDocument = null;
7944          OldLink cycle = document.cycle;
7945          int id = 0;
7946          while(true)
7947          {
7948             Window child = cycle.data;
7949             if(child.style.isActiveClient && !child.style.hidden)
7950             {
7951                if(!firstDocument) firstDocument = child;
7952                if(child.state == minimized)
7953                   child.SetState(minimized, false, mods);
7954                else
7955                {
7956                   child.positionID = id++;
7957                   child.SetState(normal, false, mods);
7958                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
7959
7960                   child.anchor.left.type = hTiled;
7961                   {
7962                      int x, y, w, h;
7963                      child.normalSizeAnchor = *&child.sizeAnchor;
7964                      child.normalAnchor = child.anchor;
7965
7966                      // Break the anchors for moveable/resizable windows
7967                      if(child.style.fixed)
7968                      {
7969                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
7970
7971                         (*&child.normalAnchor).left = x;
7972                         (*&child.normalAnchor).top = y;
7973                         (*&child.normalAnchor).right.type = none;
7974                         (*&child.normalAnchor).bottom.type = none;
7975                         (*&child.normalSizeAnchor).isClientW = false;
7976                         (*&child.normalSizeAnchor).isClientH = false;
7977                         (*&child.normalSizeAnchor).size.w = w;
7978                         (*&child.normalSizeAnchor).size.h = h;
7979                         child.anchored = false;
7980                      }
7981
7982                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
7983                      {
7984                         child.stateAnchor = child.normalAnchor;
7985                         child.stateSizeAnchor = child.normalSizeAnchor;
7986
7987                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
7988                         child.Position(x,y, w, h, true, true, true, true, false, true);
7989                      }
7990                   }
7991                }
7992             }
7993             if((cycle = cycle.next) == document.cycle) break;
7994          }
7995          if(firstDocument)
7996             firstDocument.Activate();
7997       }
7998       return true;
7999    }
8000
8001    bool MenuWindowTileVert(MenuItem selection, Modifiers mods)
8002    {
8003       Window document = activeChild;
8004       if(document)
8005       {
8006          Window firstDocument = null;
8007          Window child;
8008          OldLink cycle = document.cycle;
8009          int id = 0;
8010          while(true)
8011          {
8012             child = cycle.data;
8013             //if(child.style.isDocument)
8014             if(child.style.isActiveClient && !child.style.hidden)
8015             {
8016                if(!firstDocument) firstDocument = child;
8017                if(child.state == minimized)
8018                   child.SetState(minimized, false, mods);
8019                else
8020                {
8021                   child.positionID = id++;
8022                   child.SetState(normal, false, mods);
8023                   child.ActivateEx(true, false, false, false, null, null);   // To move active clients on top of other windows
8024
8025                   child.anchor.left.type = vTiled;
8026                   {
8027                      int x, y, w, h;
8028                      child.normalSizeAnchor = *&child.sizeAnchor;
8029                      child.normalAnchor = child.anchor;
8030
8031                      // Break the anchors for moveable/resizable windows
8032                      if(child.style.fixed)
8033                      {
8034                         child.ComputeAnchors(child.anchor, *&child.sizeAnchor, &x, &y, &w, &h);
8035
8036                         (*&child.normalAnchor).left = x;
8037                         (*&child.normalAnchor).top = y;
8038                         (*&child.normalAnchor).right.type = none;
8039                         (*&child.normalAnchor).bottom.type = none;
8040                         (*&child.normalSizeAnchor).isClientW = false;
8041                         (*&child.normalSizeAnchor).isClientH = false;
8042                         (*&child.normalSizeAnchor).size.w = w;
8043                         (*&child.normalSizeAnchor).size.h = h;
8044                         child.anchored = false;
8045                      }
8046
8047                      if(child.state == normal /*|| child.state == Hidden */)   // Hidden is new here ...
8048                      {
8049                         child.stateAnchor = child.normalAnchor;
8050                         child.stateSizeAnchor = child.normalSizeAnchor;
8051
8052                         child.ComputeAnchors(child.stateAnchor, child.stateSizeAnchor, &x, &y, &w, &h);
8053                         child.Position(x,y, w, h, true, true, true, true, false, true);
8054                      }
8055                   }
8056                }
8057             }
8058             if((cycle = cycle.next) == document.cycle) break;
8059          }
8060          if(firstDocument)
8061             firstDocument.Activate();
8062       }
8063       return true;
8064    }
8065
8066    bool MenuWindowWindows(MenuItem selection, Modifiers mods)
8067    {
8068       WindowList
8069       {
8070          master = this; isModal = true;
8071
8072          void NotifyDestroyed(Window window, DialogResult result)
8073          {
8074             Window document = (Window)(intptr)result;
8075             if(document)
8076             {
8077                if(activeChild.state == maximized)
8078                   document.SetState(maximized, false, 0);
8079                else if(document.state == minimized)
8080                   document.SetState(normal, false, 0);
8081                document.Activate();
8082             }
8083          }
8084       }.Create();
8085       return true;
8086    }
8087
8088    // Virtual Methods
8089    virtual bool OnCreate(void);
8090    virtual void OnDestroy(void);
8091    virtual void OnDestroyed(void);
8092    virtual bool OnClose(bool parentClosing);
8093    virtual bool OnStateChange(WindowState state, Modifiers mods);
8094    virtual bool OnPostCreate(void);
8095    virtual bool OnMoving(int *x, int *y, int w, int h);
8096    virtual bool OnResizing(int *width, int *height);
8097    virtual void OnResize(int width, int height);
8098    virtual void OnPosition(int x, int y, int width, int height);
8099    virtual bool OnLoadGraphics(void);
8100    virtual void OnApplyGraphics(void);
8101    virtual void OnUnloadGraphics(void);
8102    virtual void OnRedraw(Surface surface);
8103    virtual bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct);
8104    virtual void OnActivateClient(Window client, Window previous);
8105    virtual bool OnKeyDown(Key key, unichar ch);
8106    virtual bool OnKeyUp(Key key, unichar ch);
8107    virtual bool OnKeyHit(Key key, unichar ch);
8108    virtual bool OnSysKeyDown(Key key, unichar ch);
8109    virtual bool OnSysKeyUp(Key key, unichar ch);
8110    virtual bool OnSysKeyHit(Key key, unichar ch);
8111    virtual bool OnMouseOver(int x, int y, Modifiers mods);
8112    virtual bool OnMouseLeave(Modifiers mods);
8113    virtual bool OnMouseMove(int x, int y, Modifiers mods);
8114    virtual bool OnLeftButtonDown(int x, int y, Modifiers mods);
8115    virtual bool OnLeftButtonUp(int x, int y, Modifiers mods);
8116    virtual bool OnLeftDoubleClick(int x, int y, Modifiers mods);
8117    virtual bool OnRightButtonDown(int x, int y, Modifiers mods);
8118    virtual bool OnRightButtonUp(int x, int y, Modifiers mods);
8119    virtual bool OnRightDoubleClick(int x, int y, Modifiers mods);
8120    virtual bool OnMiddleButtonDown(int x, int y, Modifiers mods);
8121    virtual bool OnMiddleButtonUp(int x, int y, Modifiers mods);
8122    virtual bool OnMiddleDoubleClick(int x, int y, Modifiers mods);
8123    virtual bool OnMultiTouch(TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers mods);
8124    virtual void OnMouseCaptureLost(void);
8125    virtual void OnHScroll(ScrollBarAction action, int position, Key key);
8126    virtual void OnVScroll(ScrollBarAction action, int position, Key key);
8127    virtual void OnDrawOverChildren(Surface surface);
8128    virtual bool OnFileModified(FileChange fileChange, const char * param);
8129    virtual bool OnSaveFile(const char * fileName);
8130
8131    // Virtual Methods -- Children management (To support Stacker, for lack of built-in auto-layout)
8132    // Note: A 'client' would refer to isActiveClient, rather than
8133    // being confined to the 'client area' (nonClient == false)
8134    virtual void OnChildAddedOrRemoved(Window child, bool removed);
8135    virtual void OnChildVisibilityToggled(Window child, bool visible);
8136    virtual void OnChildResized(Window child, int x, int y, int w, int h);
8137
8138    // Skins Virtual Functions
8139    virtual void GetDecorationsSize(MinMaxValue * w, MinMaxValue * h);
8140    virtual void SetWindowMinimum(MinMaxValue * mw, MinMaxValue * mh);
8141    virtual void SetWindowArea(int * x, int * y, MinMaxValue * w, MinMaxValue * h, MinMaxValue * cw, MinMaxValue * ch)
8142    {
8143       *cw = *w;
8144       *ch = *h;
8145    }
8146    virtual void ShowDecorations(Font captionFont, Surface surface, const char * name, bool active, bool moving);
8147    virtual void PreShowDecorations(Font captionFont, Surface surface, const char * name, bool active, bool moving);
8148    virtual bool IsMouseMoving(int x, int y, int w, int h)
8149    {
8150       return false;
8151    }
8152    virtual bool IsMouseResizing(int x, int y, int w, int h, bool *resizeX, bool *resizeY, bool *resizeEndX, bool *resizeEndY)
8153    {
8154       return false;
8155    }
8156    virtual void UpdateNonClient();
8157    virtual void SetBox(Box box);    // This is used in the MySkin skin
8158    virtual bool IsInside(int x, int y)
8159    {
8160       return box.IsPointInside({x, y});
8161    }
8162    virtual bool IsOpaque()
8163    {
8164       return (!style.drawBehind || background.a == 255);
8165    }
8166
8167    // Notifications
8168    virtual bool Window::NotifyActivate(Window window, bool active, Window previous);
8169    virtual void Window::NotifyDestroyed(Window window, DialogResult result);
8170    virtual void Window::NotifySaved(Window window, const char * filePath);
8171
8172    // Public Methods
8173
8174    // Properties
8175    property Window parent
8176    {
8177       property_category $"Layout"
8178       set
8179       {
8180          if(value || guiApp.desktop)
8181          {
8182             Window last;
8183             Window oldParent = parent;
8184             Anchor anchor = this.anchor;
8185
8186             if(value && value.IsDescendantOf(this)) return;
8187             if(value && value == this)
8188                return;
8189             if(!value) value = guiApp.desktop;
8190
8191             if(value == oldParent) return;
8192
8193             if(!master || (master == this.parent && master == guiApp.desktop))
8194                property::master = value;
8195
8196             if(parent)
8197             {
8198                parent.children.Remove(this);
8199
8200                parent.Update(
8201                {
8202                   box.left - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
8203                   box.top - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y,
8204                   box.right - absPosition.x + parent.absPosition.x + style.nonClient * parent.clientStart.x,
8205                   box.bottom - absPosition.y + parent.absPosition.y + style.nonClient * parent.clientStart.y
8206                });
8207             }
8208
8209             last = value.children.last;
8210
8211             if(style.isDocument)
8212             {
8213                if(parent)
8214                   parent.numDocuments--;
8215                documentID = value.GetDocumentID();
8216             }
8217
8218             if(style.isActiveClient && !style.hidden)
8219             {
8220                if(parent && parent != guiApp.desktop && !(style.hidden))
8221                {
8222                   if(state == minimized) parent.numIcons--;
8223                   parent.numPositions--;
8224                }
8225             }
8226
8227             if(!style.stayOnTop)
8228                for(; last && last.style.stayOnTop; last = last.prev);
8229
8230             value.children.Insert(last, this);
8231
8232             // *** NEW HERE: ***
8233             if(cycle)
8234                parent.childrenCycle.Delete(cycle);
8235             if(order)
8236                parent.childrenOrder.Delete(order);
8237             cycle = null;
8238             order = null;
8239             // *** TODO: Added this here to solve crash on setting parent to null before destroying/destructing ***
8240             //           Should something else be done?
8241             if(parent && parent.activeChild == this)
8242                parent.activeChild = null;
8243             if(parent && parent.activeClient == this)
8244                parent.activeClient = null;
8245
8246             //if(created)
8247             {
8248                if(created)
8249                {
8250                   int x = position.x, y = position.y, w = size.w, h = size.h;
8251
8252                   int vpw, vph;
8253
8254                   x += parent.absPosition.x - value.absPosition.x + parent.clientStart.x - value.clientStart.x;
8255                   y += parent.absPosition.y - value.absPosition.y + parent.clientStart.y - value.clientStart.y;
8256
8257                   vpw = value.clientSize.w;
8258                   vph = value.clientSize.h;
8259                   if(style.nonClient)
8260                   {
8261                      vpw = value.size.w;
8262                      vph = value.size.h;
8263                   }
8264                   else if(style.fixed)
8265                   {
8266                      if(!style.dontScrollHorz && value.scrollArea.w) vpw = value.scrollArea.w;
8267                      if(!style.dontScrollVert && value.scrollArea.h) vph = value.scrollArea.h;
8268                   }
8269
8270                   anchor = this.anchor;
8271
8272                   if(anchor.left.type == offset)            anchor.left.distance = x;
8273                   else if(anchor.left.type == relative)     anchor.left.percent = (float)x / vpw;
8274                   if(anchor.top.type == offset)             anchor.top.distance = y;
8275                   else if(anchor.top.type == relative)      anchor.top.percent = (float)y / vph;
8276                   if(anchor.right.type == offset)           anchor.right.distance = vpw - (x + w);
8277                   //else if(anchor.right.type == relative)  anchor.right.percent = 1.0-(float) (vpw - (x + w)) / vpw;
8278                   else if(anchor.right.type == relative)    anchor.right.percent = (float) (vpw - (x + w)) / vpw;
8279                   if(anchor.bottom.type == offset)          anchor.bottom.distance = vph - (y + h);
8280                   //else if(anchor.bottom.type == relative) anchor.bottom.percent = 1.0-(float) (vph - (y + h)) / vph;
8281                   else if(anchor.bottom.type == relative)   anchor.bottom.percent = (float) (vph - (y + h)) / vph;
8282
8283                   if(!anchor.left.type && !anchor.right.type)
8284                   {
8285                      anchor.horz.distance = (x + w / 2) - (vpw / 2);
8286                      //anchor.horz.type = anchor.horz.distance ? AnchorValueOffset : 0;
8287                   }
8288                   else if(anchor.horz.type == middleRelative) anchor.horz.percent = (float) ((x + w / 2) - (vpw / 2)) / vpw;
8289                   if(!anchor.top.type && !anchor.bottom.type)
8290                   {
8291                      anchor.vert.distance = (y + h / 2) - (vph / 2);
8292                      //anchor.vert.type = anchor.vert.distance ? AnchorValueOffset : 0;
8293                   }
8294                   else if(anchor.vert.type == middleRelative) anchor.vert.percent = (float)((y + h / 2) - (vph / 2)) / vph;
8295                }
8296                parent = value;
8297                parent.OnChildAddedOrRemoved(this, false);
8298
8299                // *** NEW HERE ***
8300                if(!style.inactive)
8301                {
8302                   if(!style.noCycle)
8303                      parent.childrenCycle.Insert(
8304                         // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8305                         //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
8306                         null,
8307                         cycle = OldLink { data = this });
8308                   parent.childrenOrder.Insert(
8309                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8310                      order = OldLink { data = this });
8311                }
8312
8313                if(!style.hidden && style.isActiveClient)
8314                {
8315                   positionID = parent.GetPositionID(this);
8316                   parent.numPositions++;
8317                   if(state == minimized) parent.numIcons--;
8318                }
8319
8320                // *** FONT INHERITANCE ***
8321                if(!setFont && oldParent)
8322                   stopwatching(oldParent, font);
8323
8324                if(systemFont)
8325                {
8326                   RemoveResource(systemFont);
8327                   delete systemFont;
8328                }
8329                // TESTING WITH WATCHERS:
8330                usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8331                // usedFont = setFont ? setFont : (systemFont);
8332
8333                if(!usedFont)
8334                {
8335                   if(guiApp.currentSkin)
8336                   {
8337                      systemFont = guiApp.currentSkin.SystemFont();
8338                      incref systemFont;
8339                   }
8340                   usedFont = systemFont;
8341                   AddResource(systemFont);
8342                }
8343
8344                if(!setFont)
8345                   watch(value)
8346                   {
8347                      font
8348                      {
8349                         usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8350                         firewatchers font;
8351                         Update(null);
8352                      }
8353                   };
8354
8355                firewatchers font;
8356
8357
8358                if(value.rootWindow && value.rootWindow.display && rootWindow && created)
8359                {
8360                   bool reloadGraphics = (oldParent.rootWindow == oldParent && value.rootWindow) || (!value.rootWindow && rootWindow == this) ||
8361                         (value.rootWindow.display && value.rootWindow.display.displaySystem != rootWindow.display.displaySystem);
8362
8363                   if(reloadGraphics)
8364                      UnloadGraphics(false);
8365                   SetupDisplay();
8366                   if(reloadGraphics)
8367                      LoadGraphics(false, false);
8368
8369                   /*
8370                   if(value.rootWindow != rootWindow)
8371                      DisplayModeChanged();
8372                   else
8373                   */
8374                }
8375                scrolledPos.x = MININT; // Prevent parent update
8376                {
8377                   bool anchored = this.anchored;
8378                   property::anchor = anchor;
8379                   this.anchored = anchored;
8380                }
8381                /*
8382                {
8383                   int x, y, w, h;
8384                   if(guiApp.currentSkin)
8385                      guiApp.currentSkin.SetWindowMinimum(this, &skinMinSize.w, &skinMinSize.h);
8386
8387                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8388                   Position(x, y, w, h, true, true, true, true, false, true);
8389                }
8390                */
8391
8392             }
8393             // else parent = value;
8394             if(oldParent)
8395                oldParent.OnChildAddedOrRemoved(this, true);
8396          }
8397       }
8398       get { return parent; }
8399    };
8400
8401    property Window master
8402    {
8403       property_category $"Behavior"
8404       set
8405       {
8406          //if(this == value) return;
8407          if(value && value.IsSlaveOf(this)) return;
8408
8409          if(master != value)
8410          {
8411             if(master)
8412             {
8413                OldLink slaveHolder;
8414                for(slaveHolder = master.slaves.first; slaveHolder; slaveHolder = slaveHolder.next)
8415                   if(slaveHolder.data == this)
8416                   {
8417                      master.slaves.Delete(slaveHolder);
8418                      break;
8419                   }
8420             }
8421
8422             if(value)
8423             {
8424                value.slaves.Add(OldLink { data = this });
8425
8426                if(hotKey)
8427                {
8428                   if(master)
8429                      master.hotKeys.Remove(hotKey);
8430                   value.hotKeys.Add(hotKey);
8431                   hotKey = null;
8432                }
8433                if(master && master.defaultControl == this)
8434                   master.defaultControl = null;
8435
8436                if(style.isDefault && !value.defaultControl)
8437                   value.defaultControl = this;
8438             }
8439          }
8440          master = value;
8441       }
8442       get { return master ? master : parent; }
8443    };
8444
8445    property const char * caption
8446    {
8447       property_category $"Appearance"
8448       watchable
8449       set
8450       {
8451          delete caption;
8452          if(value)
8453          {
8454             caption = new char[strlen(value)+1];
8455             if(caption)
8456                strcpy(caption, value);
8457          }
8458          if(created)
8459             UpdateCaption();
8460       }
8461       get { return caption; }
8462    };
8463
8464    property Key hotKey
8465    {
8466       property_category $"Behavior"
8467       set
8468       {
8469          setHotKey = value;
8470          if(created)
8471          {
8472             if(value)
8473             {
8474                if(!hotKey)
8475                   master.hotKeys.Add(hotKey = HotKeySlot { });
8476                if(hotKey)
8477                {
8478                   hotKey.key = value;
8479                   hotKey.window = this;
8480                }
8481             }
8482             else if(hotKey)
8483             {
8484                master.hotKeys.Delete(hotKey);
8485                hotKey = null;
8486             }
8487          }
8488       }
8489       get { return hotKey ? hotKey.key : 0; }
8490    };
8491
8492    property Color background
8493    {
8494       property_category $"Appearance"
8495       set
8496       {
8497          background.color = value;
8498          firewatchers;
8499          if(created)
8500          {
8501             Update(null);
8502             if(this == rootWindow)
8503                guiApp.interfaceDriver.SetRootWindowColor(this);
8504          }
8505       }
8506       get { return background.color; }
8507    };
8508
8509    property Percentage opacity
8510    {
8511       property_category $"Appearance"
8512       set
8513       {
8514          background.a = (byte)Min(Max((int)(value * 255), 0), 255);
8515          drawBehind = (background.a == 255) ? false : true;
8516       }
8517       get { return background.a / 255.0f; }
8518    };
8519
8520    property Color foreground
8521    {
8522       property_category $"Appearance"
8523       set
8524       {
8525          foreground = value;
8526          firewatchers;
8527          if(created)
8528             Update(null);
8529       }
8530       get { return foreground; }
8531    };
8532
8533    property BorderStyle borderStyle
8534    {
8535       property_category $"Appearance"
8536       set
8537       {
8538          if(!((BorderBits)value).fixed)
8539          {
8540             style.hasClose = false;
8541             style.hasMaximize = false;
8542             style.hasMinimize = false;
8543             nativeDecorations = false;
8544          }
8545          style.borderBits = value;
8546          if(created)
8547          {
8548             int x, y, w, h;
8549             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8550
8551             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8552             Position(x, y, w, h, true, true, true, true, false, true);
8553             CreateSystemChildren();
8554          }
8555       }
8556       get { return (BorderStyle)style.borderBits; }
8557    };
8558
8559    property Size minClientSize
8560    {
8561       property_category $"Layout"
8562       set { minSize = value; }
8563       get { value = minSize; }
8564    };
8565
8566    property Size maxClientSize
8567    {
8568       property_category $"Layout"
8569       set { maxSize = value; }
8570       get { value = maxSize; }
8571    };
8572
8573    property bool hasMaximize
8574    {
8575       property_category $"Window Style"
8576       set
8577       {
8578          style.hasMaximize = value;
8579          if(value) { style.fixed = true; style.contour = true; }
8580          if(created)
8581          {
8582             int x, y, w, h;
8583             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8584
8585             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8586             Position(x, y, w, h, true, true, true, true, false, true);
8587
8588             CreateSystemChildren();
8589          }
8590       }
8591       get { return style.hasMaximize; }
8592    };
8593
8594    property bool hasMinimize
8595    {
8596       property_category $"Window Style"
8597       set
8598       {
8599          style.hasMinimize = value;
8600          if(value) { style.fixed = true; style.contour = true; }
8601          if(created)
8602          {
8603             int x, y, w, h;
8604             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8605
8606             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8607             Position(x, y, w, h, true, true, true, true, false, true);
8608
8609             CreateSystemChildren();
8610          }
8611       }
8612       get { return style.hasMinimize;  }
8613    };
8614
8615    property bool hasClose
8616    {
8617       property_category $"Window Style"
8618       set
8619       {
8620          style.hasClose = value;
8621          if(value) { style.fixed = true; style.contour = true; }
8622          if(created)
8623          {
8624             int x, y, w, h;
8625             SetWindowMinimum(&skinMinSize.w, &skinMinSize.h);
8626             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8627             Position(x, y, w, h, true, true, true, true, false, true);
8628             CreateSystemChildren();
8629          }
8630       }
8631       get { return style.hasClose; }
8632    };
8633
8634    property bool nonClient
8635    {
8636       property_category $"Layout"
8637       set
8638       {
8639          style.nonClient = value;
8640          if(value)
8641             style.stayOnTop = true;
8642       }
8643       get { return style.nonClient; }
8644    };
8645
8646    property bool inactive
8647    {
8648       property_category $"Behavior"
8649       set
8650       {
8651          if(value)
8652          {
8653             // *** NEW HERE: ***
8654             if(!style.inactive)
8655             {
8656                if(cycle)
8657                   parent.childrenCycle.Delete(cycle);
8658                if(order)
8659                   parent.childrenOrder.Delete(order);
8660                cycle = null;
8661                order = null;
8662             }
8663
8664             if(created)
8665             {
8666                active = false; // true;
8667                if(parent.activeChild == this)
8668                   parent.activeChild = null;
8669                if(parent.activeClient == this)
8670                   parent.activeClient = null;
8671             }
8672          }
8673          else
8674          {
8675             if(style.inactive)
8676             {
8677                if(!style.noCycle)
8678                {
8679                   parent.childrenCycle.Insert(
8680                      // Note: changed to 'null' to fix broken tab cycling in WSMS custom reports
8681                      //(parent.activeChild && parent.activeChild.cycle) ? parent.activeChild.cycle.prev : null,
8682                      null,
8683                      cycle = OldLink { data = this });
8684                }
8685                parent.childrenOrder.Insert(
8686                   (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
8687                   order = OldLink { data = this });
8688             }
8689          }
8690          style.inactive = value;
8691       }
8692       get { return style.inactive; }
8693    };
8694
8695    property bool clickThrough
8696    {
8697       property_category $"Behavior"
8698       set { style.clickThrough = value; }
8699       get { return style.clickThrough; }
8700    };
8701
8702    property bool isRemote
8703    {
8704       property_category $"Behavior"
8705       set { style.isRemote = value; }
8706       get { return style.isRemote; }
8707    };
8708
8709    property bool noCycle
8710    {
8711       property_category $"Behavior"
8712       set { style.noCycle = value; }
8713       get { return style.noCycle; }
8714    };
8715
8716    property bool isModal
8717    {
8718       property_category $"Behavior"
8719       set { style.modal = value; }
8720       get { return style.modal; }
8721    };
8722
8723    property bool interim
8724    {
8725       property_category $"Behavior"
8726       set { style.interim = value; }
8727       get { return style.interim; }
8728    };
8729
8730    property bool tabCycle
8731    {
8732       property_category $"Behavior"
8733       set { style.tabCycle = value; }
8734       get { return style.tabCycle; }
8735    };
8736
8737    property bool isDefault
8738    {
8739       property_category $"Behavior"
8740       set
8741       {
8742          if(master)
8743          {
8744             if(value)
8745             {
8746                /*Window sibling;
8747                for(sibling = parent.children.first; sibling; sibling = sibling.next)
8748                   if(sibling != this && sibling.style.isDefault)
8749                      sibling.style.isDefault = false;*/
8750                if(master.defaultControl)
8751                   master.defaultControl.style.isDefault = false;
8752                master.defaultControl = this;
8753             }
8754             else if(master.defaultControl == this)
8755                master.defaultControl = null;
8756
8757             // Update(null);
8758          }
8759          style.isDefault = value;
8760          if(created)
8761             Position(position.x, position.y, size.w, size.h, true, true, true,true,true, true);
8762       }
8763       get { return style.isDefault; }
8764    };
8765
8766    property bool drawBehind
8767    {
8768       property_category $"Window Style"
8769       set { style.drawBehind = value; }
8770       get { return style.drawBehind; }
8771    };
8772
8773    property bool hasMenuBar
8774    {
8775       property_category $"Window Style"
8776       set
8777       {
8778          if(value)
8779          {
8780             if(!menu)
8781             {
8782                menu = Menu { };
8783                incref menu;
8784             }
8785             if(created && !menuBar)
8786             {
8787                menuBar =
8788                   PopupMenu
8789                   {
8790                      this, menu = menu,
8791                      isMenuBar = true,
8792                      anchor = Anchor { top = 23, left = 1, right = 1 },
8793                      size.h = 24,
8794                      inactive = true, nonClient = true
8795                   };
8796                menuBar.Create();
8797             }
8798          }
8799          else if(created && menuBar)
8800          {
8801             menuBar.Destroy(0);
8802             menuBar = null;
8803          }
8804          style.hasMenuBar = value;
8805       }
8806       get { return style.hasMenuBar; }
8807    };
8808
8809    property bool hasStatusBar
8810    {
8811       property_category $"Window Style"
8812       set
8813       {
8814          if(value)
8815          {
8816             if(!statusBar)
8817             {
8818                statusBar = StatusBar { this };
8819                incref statusBar;
8820                if(created)
8821                   statusBar.Create();
8822             }
8823          }
8824          else if(statusBar)
8825             delete statusBar;
8826          style.hasStatusBar = value;
8827       }
8828       get { return style.hasStatusBar; }
8829    };
8830    property bool stayOnTop
8831    {
8832       property_category $"Window Style"
8833       set
8834       {
8835          if(value)
8836          {
8837             if(created && !style.stayOnTop)
8838             {
8839                if(rootWindow == this)
8840                   guiApp.interfaceDriver.OrderRootWindow(this, true);
8841                else if(parent.children.last != this)
8842                {
8843                   parent.children.Move(this, parent.children.last);
8844                   Update(null);
8845                }
8846             }
8847             style.stayOnTop = true;
8848          }
8849          else
8850          {
8851             if(created && style.stayOnTop)
8852             {
8853                if(rootWindow == this)
8854                   guiApp.interfaceDriver.OrderRootWindow(this, false);
8855                else
8856                {
8857                   Window last;
8858                   if(order)
8859                   {
8860                      OldLink order;
8861                      for(order = (this.order == parent.childrenOrder.first) ? null : this.order.prev;
8862                          order && ((Window)order.data).style.stayOnTop;
8863                          order = (order == parent.childrenOrder.first) ? null : order.prev);
8864                       last = order ? order.data : null;
8865                   }
8866                   else
8867                   {
8868                      for(last = parent.children.last;
8869                          last && last.style.stayOnTop;
8870                          last = last.prev);
8871                   }
8872
8873                   parent.children.Move(this, last);
8874                   Update(null);
8875                }
8876             }
8877             style.stayOnTop = false;
8878          }
8879       }
8880       get { return style.stayOnTop; }
8881    };
8882
8883    property Menu menu
8884    {
8885       property_category $"Window Style"
8886       set
8887       {
8888          delete menu;
8889          if(value)
8890          {
8891             menu = value;
8892             incref menu;
8893          }
8894
8895          if(menuBar && !value)
8896          {
8897             menuBar.Destroy(0);
8898             menuBar = null;
8899          }
8900          if(created)
8901          {
8902             if(!menuBar && style.hasMenuBar && value)
8903             {
8904                menuBar = PopupMenu
8905                          {
8906                             this, menu = value, isMenuBar = true,
8907                             anchor = Anchor { left = 1, top = 23, right = 1 }, size.h = 24,
8908                             inactive = true, nonClient = true
8909                          };
8910                 menuBar.Create();
8911             }
8912             UpdateActiveDocument(null);
8913          }
8914       }
8915       get { return menu; }
8916    };
8917
8918    property FontResource font
8919    {
8920       property_category $"Appearance"
8921       watchable
8922       isset { return setFont ? true : false; }
8923       set
8924       {
8925          if(this)
8926          {
8927             if(value && !setFont) { stopwatching(parent, font); }
8928             else if(!value && setFont)
8929             {
8930                watch(parent)
8931                {
8932                   font
8933                   {
8934                      usedFont = setFont ? setFont : (parent.parent ? parent.usedFont : systemFont);
8935                      firewatchers font;
8936                      Update(null);
8937                   }
8938                };
8939             }
8940
8941             if(setFont)
8942             {
8943                RemoveResource(setFont);
8944                delete setFont;
8945             }
8946             if(systemFont)
8947             {
8948                RemoveResource(systemFont);
8949                delete systemFont;
8950             }
8951             setFont = value;
8952             if(setFont)
8953             {
8954                incref setFont;
8955                AddResource(setFont);
8956             }
8957
8958             usedFont = setFont ? setFont : ((parent && parent.parent) ? parent.usedFont : systemFont);
8959             if(!usedFont)
8960             {
8961                systemFont = guiApp.currentSkin.SystemFont();
8962                incref systemFont;
8963                usedFont = systemFont;
8964                AddResource(systemFont);
8965             }
8966
8967             firewatchers;
8968
8969             Update(null);
8970          }
8971       }
8972       get { return usedFont; }
8973    };
8974
8975    property SizeAnchor sizeAnchor
8976    {
8977       property_category $"Layout"
8978       isset
8979       {
8980          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
8981                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
8982             sizeAnchor.isClientW != sizeAnchor.isClientH;
8983       }
8984       set
8985       {
8986          int x, y, w, h;
8987          sizeAnchor = value;
8988
8989          normalSizeAnchor = sizeAnchor;
8990
8991          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
8992          {
8993             stateAnchor = normalAnchor;
8994             stateSizeAnchor = normalSizeAnchor;
8995
8996             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
8997             Position(x,y, w, h, true, true, true, true, false, true);
8998          }
8999       }
9000       get
9001       {
9002          value =
9003          {
9004             { sizeAnchor.isClientW ? clientSize.w : size.w, sizeAnchor.isClientH ? clientSize.h : size.h },
9005             sizeAnchor.isClientW,
9006             sizeAnchor.isClientH
9007          };
9008       }
9009    };
9010
9011    property Size size
9012    {
9013       property_category $"Layout"
9014       isset
9015       {
9016          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
9017                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
9018             !sizeAnchor.isClientW && !sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
9019       }
9020       set
9021       {
9022          int x, y, w, h;
9023
9024          sizeAnchor.isClientW = false;
9025          sizeAnchor.isClientH = false;
9026          sizeAnchor.size = value;
9027
9028          normalSizeAnchor = sizeAnchor;
9029
9030          if(state == normal /*|| state == Hidden*/)   // Hidden is new here ...
9031          {
9032             stateAnchor = normalAnchor;
9033             stateSizeAnchor = normalSizeAnchor;
9034
9035             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
9036             Position(x, y, w, h, true, true, true, true, false, true);
9037             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
9038          }
9039       }
9040       get { value = size; }
9041    };
9042
9043    property Size clientSize
9044    {
9045       property_category $"Layout"
9046       isset
9047       {
9048          return ((anchor.left.type == none || anchor.left.type == middleRelative || anchor.right.type == none) ||
9049                 (anchor.top.type == none || anchor.top.type == middleRelative || anchor.bottom.type == none)) &&
9050             sizeAnchor.isClientW && sizeAnchor.isClientH && sizeAnchor.size.w && sizeAnchor.size.h;
9051       }
9052       set
9053       {
9054          int x, y, w, h;
9055          sizeAnchor.isClientW = true;
9056          sizeAnchor.isClientH = true;
9057          sizeAnchor.size = value;
9058
9059          normalSizeAnchor = sizeAnchor;
9060
9061          if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
9062          {
9063             stateAnchor = normalAnchor;
9064             stateSizeAnchor = normalSizeAnchor;
9065
9066             ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
9067             Position(x,y, w, h, true, true, true, true, false, true);
9068             if(parent && parent.created && !nonClient) parent.OnChildResized(this, x, y, w, h);
9069          }
9070       }
9071       get { value = this ? clientSize : { 0, 0 }; }
9072    };
9073
9074    property Size initSize { get { value = sizeAnchor.size; } };
9075
9076    property Anchor anchor
9077    {
9078       property_category $"Layout"
9079       isset { return (anchor.left.type != offset || anchor.top.type != offset || anchor.right.type || anchor.bottom.type); }
9080
9081       set
9082       {
9083          if(value != null)
9084          {
9085             if(anchor.left.type && anchor.right.type && (!value.left.type || !value.right.type))
9086             {
9087                normalSizeAnchor.isClientW = sizeAnchor.isClientW = false;
9088                normalSizeAnchor.size.w = sizeAnchor.size.w = size.w;
9089             }
9090             if(anchor.top.type && anchor.bottom.type && (!value.top.type || !value.bottom.type))
9091             {
9092                normalSizeAnchor.isClientH = sizeAnchor.isClientH = false;
9093                normalSizeAnchor.size.h = sizeAnchor.size.h = size.h;
9094             }
9095             anchor = value;
9096
9097             if(anchor.right.type && (anchor.horz.type == middleRelative || !anchor.left.type))
9098             {
9099                anchor.left.distance = 0;
9100                anchor.horz.type = 0;
9101             }
9102             if(anchor.bottom.type && (anchor.vert.type == middleRelative || !anchor.top.type))
9103             {
9104                anchor.top.distance = 0;
9105                anchor.vert.type = 0;
9106             }
9107
9108             anchored = true;
9109
9110             //if(created)
9111             {
9112                int x, y, w, h;
9113
9114                normalAnchor = anchor;
9115
9116                // Break the anchors for moveable/resizable windows
9117                /*if(style.fixed ) //&& value.left.type == cascade)
9118                {
9119                   ComputeAnchors(anchor, sizeAnchor, &x, &y, &w, &h);
9120
9121                   this.anchor = normalAnchor = Anchor { left = x, top = y };
9122                   normalSizeAnchor = SizeAnchor { { w, h } };
9123                   anchored = false;
9124                }*/
9125                if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
9126                {
9127                   stateAnchor = normalAnchor;
9128                   stateSizeAnchor = normalSizeAnchor;
9129
9130                   ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
9131                   Position(x, y, w, h, true, true, true, true, false, true);
9132                }
9133             }
9134          }
9135          else
9136          {
9137             anchored = false;
9138          }
9139       }
9140       get { value = this ? anchor : Anchor { }; }
9141    };
9142
9143    property Point position
9144    {
9145       property_category $"Layout"
9146       set
9147       {
9148          if(value == null) return;
9149
9150          anchor.left = value.x;
9151          anchor.top  = value.y;
9152          anchor.right.type = none;
9153          anchor.bottom.type = none;
9154          //if(created)
9155          {
9156             int x, y, w, h;
9157
9158             normalAnchor = anchor;
9159
9160             // Break the anchors for moveable/resizable windows
9161             /*
9162             if(style.fixed)
9163             {
9164                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
9165
9166                normalAnchor.left = x;
9167                normalAnchor.top = y;
9168                normalAnchor.right.type = none;
9169                normalAnchor.bottom.type = none;
9170                normalSizeAnchor.size.width = w;
9171                normalSizeAnchor.size.height = h;
9172                anchored = false;
9173             }
9174             */
9175             if(state == normal /*|| state == Hidden */)   // Hidden is new here ...
9176             {
9177                stateAnchor = normalAnchor;
9178                stateSizeAnchor = normalSizeAnchor;
9179
9180                ComputeAnchors(stateAnchor, stateSizeAnchor, &x, &y, &w, &h);
9181                Position(x,y, w, h, true, true, true, true, false, true);
9182             }
9183          }
9184       }
9185       get { value = position; }
9186    };
9187
9188    property bool disabled
9189    {
9190       property_category $"Behavior"
9191       set
9192       {
9193          if(this && disabled != value)
9194          {
9195             disabled = value;
9196             if(created)
9197                Update(null);
9198          }
9199       }
9200       get { return (bool)disabled; }
9201    };
9202
9203    property bool isEnabled
9204    {
9205       get
9206       {
9207          Window parent;
9208          for(parent = this; parent; parent = parent.parent)
9209             if(parent.disabled)
9210                return false;
9211          return true;
9212       }
9213    };
9214
9215    property WindowState state
9216    {
9217       property_category $"Behavior"
9218       set { SetState(value, false, 0); }
9219       get { return this ? state : 0; }
9220    };
9221
9222    property bool visible
9223    {
9224       property_category $"Behavior"
9225       set
9226       {
9227          if(this && !value && !style.hidden && parent)
9228          {
9229             bool wasActiveChild = parent.activeChild == this;
9230             Window client = null;
9231
9232             style.hidden = true;
9233             if(style.isActiveClient)
9234             {
9235                parent.numPositions--;
9236                if(state == minimized) parent.numIcons--;
9237             }
9238
9239             if(created)
9240             {
9241                OldLink prevOrder = null;
9242
9243                if(rootWindow == this)
9244                   guiApp.interfaceDriver.SetRootWindowState(this, state, false);
9245                else
9246                {
9247                   Box box { scrolledPos.x, scrolledPos.y, scrolledPos.x + size.w - 1, scrolledPos.y + size.h - 1 };
9248                   if(style.nonClient)
9249                   {
9250                      box.left   -= parent.clientStart.x;
9251                      box.top    -= parent.clientStart.y;
9252                      box.right  -= parent.clientStart.x;
9253                      box.bottom -= parent.clientStart.y;
9254                   }
9255                   parent.Update(box);
9256                }
9257                if(_isModal && master && master.modalSlave == this)
9258                   master.modalSlave = null;
9259
9260                if(order)
9261                {
9262                   OldLink tmpPrev = order.prev;
9263                   client = tmpPrev ? tmpPrev.data : null;
9264                   if(client && !client.style.hidden && !client.destroyed && client.created)
9265                      prevOrder = tmpPrev;
9266                   for(;;)
9267                   {
9268                      client = tmpPrev ? tmpPrev.data : null;
9269                      if(client == this) { client = null; break; }
9270                      if(client && ((client.style.hidden) || client.destroyed || !client.created))
9271                      {
9272                         tmpPrev = client.order.prev;
9273                      }
9274                      else
9275                      {
9276                         if(client)
9277                            prevOrder = tmpPrev;
9278                         break;
9279                      }
9280                   }
9281
9282                   // If this window can be an active client, make sure the next window we activate can also be one
9283                   if(!style.nonClient && style.isActiveClient)
9284                   {
9285                      tmpPrev = prevOrder;
9286                      for(;;)
9287                      {
9288                         client = tmpPrev ? tmpPrev.data : null;
9289                         if(client == this) { client = null; break; }
9290                         if(client && (client.style.nonClient || !client.style.isActiveClient || client.style.hidden || client.destroyed || !client.created))
9291                         {
9292                            tmpPrev = client.order.prev;
9293                         }
9294                         else
9295                         {
9296                            if(client)
9297                               prevOrder = tmpPrev;
9298                            break;
9299                         }
9300                      }
9301                      if(client && client.style.hidden) client = null;
9302                   }
9303                }
9304
9305                if((wasActiveChild /*parent.activeChild == this*/ || guiApp.interimWindow == this) && true /*activate*/)
9306                {
9307                   if(order && prevOrder && prevOrder.data != this)
9308                      ((Window)prevOrder.data).ActivateEx(true, false, false, true, null, null);
9309                   else
9310                      ActivateEx(false, false, false, true, null, null);
9311
9312                   // TESTING THIS HERE FOR HIDING ACTIVE CLIENT
9313                   if(parent.activeClient == this)
9314                   {
9315                      parent.activeClient = null;
9316                      parent.UpdateActiveDocument(null);
9317                   }
9318                }
9319                else if(parent.activeClient == this)
9320                {
9321                   parent.activeClient = client;
9322                   parent.UpdateActiveDocument(this);
9323                }
9324
9325                // *** Not doing this anymore ***
9326               /*
9327                if(cycle)
9328                   parent.childrenCycle.Delete(cycle);
9329                if(order)
9330                   parent.childrenOrder.Delete(order);
9331                cycle = null;
9332                order = null;
9333                */
9334
9335                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9336             }
9337
9338             firewatchers;
9339          }
9340          else if(this && value && style.hidden)
9341          {
9342             style.hidden = false;
9343             if(created)
9344             {
9345                SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9346                if(rootWindow == this)
9347                   guiApp.interfaceDriver.SetRootWindowState(this, state, true);
9348
9349                if(_isModal && master)
9350                   master.modalSlave = this;
9351
9352                if(style.isActiveClient)
9353                {
9354                   positionID = parent.GetPositionID(this);
9355                   parent.numPositions++;
9356                   if(state == minimized) parent.numIcons++;
9357                }
9358
9359                // *** NOT DOING THIS ANYMORE ***
9360                /*
9361                if(!(style.inactive))
9362                {
9363                   if(!(style.noCycle))
9364                   {
9365                      cycle = parent.childrenCycle.AddAfter(
9366                         (parent.activeChild && parent.activeChild.cycle) ?
9367                            parent.activeChild.cycle.prev : null, sizeof(OldLink));
9368                      cycle.data = this;
9369                   }
9370                   order = parent.childrenOrder.AddAfter(
9371                      (parent.activeChild && parent.activeChild.order) ? parent.activeChild.order.prev : parent.childrenOrder.last,
9372                      sizeof(OldLink));
9373                   order.data = this;
9374                }
9375                */
9376
9377                /*
9378                if(true || !parent.activeChild)
9379                   ActivateEx(true, false, true, true, null, null);
9380                */
9381                if(creationActivation == activate && guiApp.desktop.active)
9382                   ActivateEx(true, false, true, true, null, null);
9383                else if((creationActivation == activate || creationActivation == flash) && !object)
9384                {
9385                   MakeActive();
9386                   if(this == rootWindow)
9387                      Flash();
9388                }
9389
9390                //SetVisibility(!parent.style.hidden && (style.hidden ? false : true));
9391                Update(null);
9392
9393                // rootWindow.
9394                ConsequentialMouseMove(false);
9395             }
9396
9397             firewatchers;
9398          }
9399          else if(this)
9400             style.hidden = !value;
9401       }
9402
9403       get { return (style.hidden || !setVisible) ? false : true; }
9404    };
9405
9406    property bool isDocument
9407    {
9408       property_category $"Document"
9409       set { style.isDocument = value; if(value) SetupFileMonitor(); }
9410       get { return style.isDocument; }
9411    };
9412
9413    property bool mergeMenus
9414    {
9415       property_category $"Window Style"
9416       set { mergeMenus = value; }
9417       get { return (bool)mergeMenus; }
9418    };
9419
9420    property bool hasHorzScroll
9421    {
9422       property_category $"Window Style"
9423       set
9424       {
9425          if(value)
9426          {
9427             if(!style.hasHorzScroll && created)
9428             {
9429                CreateSystemChildren();
9430                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9431             }
9432          }
9433          else if(style.hasHorzScroll)
9434          {
9435             sbh.Destroy(0);
9436             sbh = null;
9437             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9438          }
9439          style.hasHorzScroll = value;
9440       }
9441
9442       get { return style.hasHorzScroll; }
9443    };
9444
9445    property bool hasVertScroll
9446    {
9447       property_category $"Window Style"
9448       set
9449       {
9450          if(value)
9451          {
9452             if(!style.hasVertScroll && created)
9453             {
9454                style.hasVertScroll = true;
9455                CreateSystemChildren();
9456                Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9457             }
9458          }
9459          else if(style.hasVertScroll)
9460          {
9461             sbv.Destroy(0);
9462             sbv = null;
9463             Position(position.x, position.y, size.w, size.h, false, true, false, false, false, true);
9464          }
9465          style.hasVertScroll = value;
9466       }
9467       get { return style.hasVertScroll; }
9468    };
9469
9470    property bool dontHideScroll
9471    {
9472       property_category $"Behavior"
9473       set
9474       {
9475          scrollFlags.dontHide = value;
9476          if(value)
9477          {
9478             //UpdateScrollBars(true, true);
9479             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9480          }
9481          else
9482          {
9483             // UpdateScrollBars(true, true);
9484             Position(position.x, position.y, size.w, size.h, false, true, true, true, true, true);
9485          }
9486       }
9487       get { return scrollFlags.dontHide; }
9488    };
9489
9490    property bool dontScrollVert
9491    {
9492       property_category $"Behavior"
9493       set { style.dontScrollVert = value; }
9494       get { return style.dontScrollVert; }
9495    };
9496    property bool dontScrollHorz
9497    {
9498       property_category $"Behavior"
9499       set { style.dontScrollHorz = value; }
9500       get { return style.dontScrollHorz; }
9501    };
9502
9503    property bool snapVertScroll
9504    {
9505       property_category $"Behavior"
9506       set
9507       {
9508          scrollFlags.snapY = value;
9509          if(sbv) sbv.snap = value;
9510       }
9511       get { return scrollFlags.snapY; }
9512    };
9513    property bool snapHorzScroll
9514    {
9515        property_category $"Behavior"
9516       set
9517       {
9518          scrollFlags.snapX = value;
9519          if(sbh) sbh.snap = value;
9520       }
9521       get { return scrollFlags.snapX; }
9522    };
9523
9524    property Point scroll
9525    {
9526       property_category $"Behavior"
9527       set { if(this) SetScrollPosition(value.x, value.y); }
9528       get { value = scroll; }
9529    };
9530
9531    property bool modifyVirtualArea
9532    {
9533       property_category $"Behavior"
9534       set { modifyVirtArea = value; }
9535       get { return (bool)modifyVirtArea; }
9536    };
9537
9538    property bool dontAutoScrollArea
9539    {
9540       property_category $"Behavior"
9541       // Activating a child control out of view will automatically scroll to make it in view
9542       set { noAutoScrollArea = value; }
9543       get { return (bool)noAutoScrollArea; }
9544    };
9545
9546    property const char * fileName
9547    {
9548       property_category $"Document"
9549       set
9550       {
9551          SetupFileMonitor();
9552
9553          if(menu && ((!fileName && value) || (fileName && !value)))
9554          {
9555             MenuItem item = menu.FindItem(MenuFileSave, 0);
9556             if(item) item.disabled = !modifiedDocument && value;
9557          }
9558
9559          delete fileName;
9560
9561          if(value && value[0])
9562             fileName = CopyString(value);
9563
9564          if(parent && this == parent.activeClient)
9565             parent.UpdateActiveDocument(null);
9566          else
9567             UpdateCaption();
9568
9569          // if(style.isDocument)
9570 #if !defined(__EMSCRIPTEN__)
9571          if(!saving)
9572             fileMonitor.fileName = value;
9573 #endif
9574       }
9575       get { return fileName; }
9576    };
9577
9578    property int64 id
9579    {
9580       property_category $"Data"
9581       set { id = value; }
9582       get { return id; }
9583    };
9584
9585    property bool modifiedDocument
9586    {
9587       property_category $"Document"
9588       set
9589       {
9590          if(style.isDocument || fileName)
9591          {
9592             if(menu)
9593             {
9594                MenuItem item = menu.FindItem(MenuFileSave, 0);
9595                if(item) item.disabled = !value && fileName;
9596             }
9597          }
9598
9599          if(modifiedDocument != value)
9600          {
9601             modifiedDocument = value;
9602             if(style.isDocument || fileName)
9603                UpdateCaption();
9604          }
9605       }
9606       get { return (bool)modifiedDocument; }
9607    };
9608
9609    property bool showInTaskBar
9610    {
9611       property_category $"Window Style"
9612       set
9613       {
9614          style.showInTaskBar = value;
9615 #if defined(__WIN32__)
9616          Win32UpdateStyle(this);
9617 #endif
9618       }
9619       get { return style.showInTaskBar; }
9620    };
9621    property FileDialog saveDialog { set { saveDialog = value; } };
9622    property bool isActiveClient
9623    {
9624       property_category $"Behavior"
9625       set
9626       {
9627          if(parent && style.isActiveClient != value && !style.hidden)
9628          {
9629             if(value)
9630             {
9631                if(state == minimized) parent.numIcons++;
9632                parent.numPositions++;
9633             }
9634             else
9635             {
9636                if(state == minimized) parent.numIcons--;
9637                parent.numPositions--;
9638             }
9639          }
9640          style.isActiveClient = value;
9641       }
9642       get { return style.isActiveClient; }
9643    };
9644
9645    property Cursor cursor
9646    {
9647       property_category $"Appearance"
9648       set
9649       {
9650          cursor = value;
9651          SelectMouseCursor();
9652       }
9653       get { return cursor; }
9654    };
9655
9656 //#if !defined(ECERE_VANILLA)
9657    property const char * name
9658    {
9659       property_category $"Design"
9660       get
9661       {
9662          return (this && object) ? object.name : null;
9663       }
9664       set
9665       {
9666          if(activeDesigner)
9667             activeDesigner.RenameObject(object, value);
9668       }
9669    };
9670 //#endif
9671    property const char * displayDriver
9672    {
9673       property_category $"Behavior"
9674       set
9675       {
9676          dispDriver = GetDisplayDriver(value);
9677          //DisplayModeChanged();
9678       }
9679       get
9680       {
9681          return dispDriver ? dispDriver.name : null;
9682       }
9683    }
9684
9685    // RUNTIME PROPERTIES
9686    property bool autoCreate { set { autoCreate = value; } get { return (bool)autoCreate; } };
9687    property Size scrollArea
9688    {
9689       property_category $"Behavior"
9690       set
9691       {
9692          if(value != null)
9693             SetScrollArea(value.w, value.h, false);
9694          else
9695             SetScrollArea(0,0, true);
9696       }
9697       get { value = scrollArea; }
9698       isset
9699       {
9700          return scrollArea.w > clientSize.w || scrollArea.h > clientSize.h;
9701       }
9702    };
9703    property bool is3D
9704    {
9705       property_category $"Layout"
9706       set { if(this) is3D = value; }
9707       get { return (bool)is3D; }
9708    };
9709
9710    // Runtime Only Properties (No Set, can display the displayable ones depending on the type?)
9711
9712    // Will be merged with font later
9713    property Font fontObject { get { return usedFont ? usedFont.font : null; } };
9714    property Point clientStart { get { value = clientStart; } };
9715    property Point absPosition { get { value = absPosition; } };
9716    property Anchor normalAnchor { get { value = normalAnchor; } };
9717    property SizeAnchor normalSizeAnchor { get { value = normalSizeAnchor; } };
9718    property bool active { get { return (bool)active; } };
9719    property bool created { get { return (bool)created; } };
9720    property bool destroyed { get { return (bool)destroyed; } };
9721    property Window firstSlave { get { return slaves.first ? ((OldLink)slaves.first).data : null; } };
9722    property Window firstChild { get { return children.first; } };
9723    property Window lastChild { get { return children.last; } };
9724    property Window activeClient { get { return activeClient; } };
9725    property Window activeChild { get { return activeChild; } };
9726    property Display display  { get { return display ? display : ((parent && parent.rootWindow) ? parent.rootWindow.display : null); } };
9727    property DisplaySystem displaySystem { get { return display ? display.displaySystem : null; } };
9728    property ScrollBar horzScroll { get { return sbh; } };
9729    property ScrollBar vertScroll { get { return sbv; } };
9730    property StatusBar statusBar { get { return statusBar; } };
9731    property Window rootWindow { get { return rootWindow; } };
9732    property bool closing { get { return (bool)closing; } set { closing = value; } };
9733    property int documentID { get { return documentID; } };
9734    property Window previous { get { return prev; } }
9735    property Window next { get { return next; } }
9736    property Window nextSlave { get { OldLink link = master ? master.slaves.FindLink(this) : null; return (link && link.next) ? link.next.data : null; } }
9737    property PopupMenu menuBar { get { return menuBar; } }
9738    property ScrollBar sbv { get { return sbv; } }
9739    property ScrollBar sbh { get { return sbh; } }
9740    property bool fullRender { set { fullRender = value; } get { return (bool)fullRender; } }
9741    property void * systemHandle { get { return windowHandle; } }
9742    property Button minimizeButton { get { return sysButtons[0]; } };
9743    property Button maximizeButton { get { return sysButtons[1]; } };
9744    property Button closeButton { get { return sysButtons[2]; } };
9745    property BitmapResource icon
9746    {
9747       get { return icon; }
9748       set
9749       {
9750          icon = value;
9751          if(icon) incref icon;
9752          if(created)
9753             guiApp.interfaceDriver.SetIcon(this, value);
9754       }
9755    };
9756    property bool moveable { get { return (bool)moveable; } set { moveable = value; } };
9757    property bool alphaBlend { get { return (bool)alphaBlend; } set { alphaBlend = value; if(value) nativeDecorations = false; /* Native Decorations are not supported with alphaBlend */ } };
9758    property bool useSharedMemory { get { return (bool)useSharedMemory; } set { useSharedMemory = value; } };
9759    property GLCapabilities glCapabilities
9760    {
9761       get { return glCapabilities; }
9762       set
9763       {
9764          bool reload = display != null &&
9765             (glCapabilities.nonPow2Textures != value.nonPow2Textures ||
9766              glCapabilities.intAndDouble != value.intAndDouble ||
9767              glCapabilities.vertexBuffer != value.vertexBuffer ||
9768              glCapabilities.compatible != value.compatible ||
9769              glCapabilities.legacyFormats != value.legacyFormats ||
9770              glCapabilities.debug != value.debug ||
9771              glCapabilities.vertexPointer != value.vertexPointer ||
9772              glCapabilities.quads != value.quads);
9773          guiApp.modeSwitching = true;
9774          if(reload)
9775             UnloadGraphics(false);
9776
9777          glCapabilities = value;
9778
9779          if(reload)
9780          {
9781             if(SetupDisplay())
9782                LoadGraphics(false, false);
9783          }
9784          else if(display)
9785             display.glCapabilities = value;
9786          guiApp.modeSwitching = false;
9787       }
9788    };
9789    property CreationActivationOption creationActivation { get { return creationActivation; } set { creationActivation = value; } };
9790    property bool nativeDecorations
9791    {
9792       get { return (bool)nativeDecorations; }
9793       set { nativeDecorations = value; }
9794 #if !defined(ECERE_VANILLA) && !defined(ECERE_NOTRUETYPE)
9795       isset
9796       {
9797          //return (nativeDecorations && (rootWindow == this || (formDesigner && activeDesigner && ((FormDesigner)activeDesigner.classDesigner).form && parent == ((FormDesigner)activeDesigner.classDesigner).form.parent))) != style.fixed;
9798          bool result = false;
9799          if(nativeDecorations)
9800          {
9801             if(rootWindow == this)
9802                result = true;
9803             else
9804             {
9805                if(formDesigner && activeDesigner)
9806                {
9807                   FormDesigner cd = (FormDesigner)activeDesigner.classDesigner;
9808                   Window form = cd ? cd.form : null;
9809                   if(form && parent == form.parent)
9810                      result = true;
9811                }
9812             }
9813          }
9814          return result != style.fixed;
9815       }
9816 #endif
9817    };
9818    property bool manageDisplay { get { return (bool)manageDisplay; } set { manageDisplay = value; } };
9819
9820    property const char * text
9821    {
9822       property_category $"Deprecated"
9823       watchable
9824       set { property::caption = value; }
9825       get { return property::caption; }
9826    }
9827 private:
9828    // Data
9829    //char * yo;
9830    Window prev, next;
9831    WindowBits style;       // Window Style
9832    char * caption;            // Name / Caption
9833    Window parent;    // Parent window
9834    OldList children;          // List of children in Z order
9835    Window activeChild;     // Child window having focus
9836    Window activeClient;
9837    Window previousActive;  // Child active prior to activating the default child
9838    Window master;          // Window owning and receiving notifications concerning this window
9839    OldList slaves;            // List of windows belonging to this window
9840    Display display;        // Display this window is drawn into
9841
9842    Point position;         // Position in parent window client area
9843    Point absPosition;      // Absolute position
9844    Point clientStart;      // Client area position from (0,0) in this window
9845    Size size;              // Size
9846    Size clientSize;        // Client area size
9847    Size scrollArea;        // Virtual Scroll area size
9848    Size reqScrollArea;     // Requested virtual area size
9849    Point scroll;           // Virtual area scrolling position
9850    ScrollBar sbh, sbv;        // Scrollbar window handles
9851    Cursor cursor;        // Mouse cursor used for this window
9852    WindowState state;
9853    PopupMenu menuBar;
9854    StatusBar statusBar;
9855    Button sysButtons[3];
9856    char * fileName;
9857    Box clientArea;         // Client Area box clipped to parent
9858    Key setHotKey;
9859    HotKeySlot hotKey;        // HotKey for this window
9860    int numDocuments;
9861    int numPositions;
9862    Menu menu;
9863    ScrollFlags scrollFlags;// Window Scrollbar Flags
9864    int64 id;                 // Control ID
9865    int documentID;
9866    ColorAlpha background;  // Background color used to draw the window area
9867    Color foreground;
9868    subclass(DisplayDriver) dispDriver;   // Display driver name for this window
9869    OldList childrenCycle;     // Cycling order
9870    OldLink cycle;             // Element of parent's cycling order
9871    OldList childrenOrder;     // Circular Z-Order
9872    OldLink order;             // Element of parent's circular Z-Order
9873    Window modalSlave;      // Slave window blocking this window's interaction
9874
9875    Window rootWindow;      // Topmost system managed window
9876    void * windowHandle;    // System window handle
9877
9878    DialogResult returnCode;// Return code for modal windows
9879
9880    Point sbStep;           // Scrollbar line scrolling steps
9881
9882    Anchor stateAnchor;
9883    SizeAnchor stateSizeAnchor;
9884
9885    Anchor normalAnchor;
9886    SizeAnchor normalSizeAnchor;
9887
9888    Size skinMinSize;       // Minimal window size based on style
9889    Point scrolledPos;      // Scrolled position
9890    Box box;                // Window box clipped to parent
9891    Box * against;          // What to clip the box to
9892
9893    Extent dirtyArea { /*first = -1, last = -1, free = -1*/ };       // Area marked for update by Update
9894    Extent renderArea { /*first = -1, last = -1, free = -1*/ };      // Temporary extent: Area that is going to be rendered
9895    Extent overRenderArea { /*first = -1, last = -1, free = -1*/ };  // Temporary extent: Area that is going to be rendered over children
9896    Extent clipExtent { /*first = -1, last = -1, free = -1*/ };      // Temporary extent against which to clip render area
9897    Extent scrollExtent { /*first = -1, last = -1, free = -1*/ };    // Area to scroll
9898    Point scrolledArea;     // Distance to scroll area by
9899    Extent dirtyBack { /*first = -1, last = -1, free = -1*/ };       // Only used by root window
9900
9901    OldList hotKeys;           // List of the hotkeys of all children
9902    Window defaultControl;  // Default child control
9903    Size minSize;
9904    Size maxSize;
9905
9906    ColorAlpha * palette;   // Color palette used for this window
9907
9908    int caretSize;          // Size of caret, non zero if a caret is present
9909    Point caretPos;         // Caret position
9910
9911    void * systemParent;    // Parent System Window for embedded windows
9912
9913    int iconID;
9914    int numIcons;
9915    int positionID;
9916
9917 #if !defined(__EMSCRIPTEN__)
9918    Mutex mutex;
9919 #endif
9920    WindowState lastState;
9921
9922 #if !defined(__EMSCRIPTEN__)
9923    FileMonitor fileMonitor;
9924 #endif
9925
9926    FontResource setFont, systemFont;
9927    FontResource usedFont;
9928    FontResource captionFont;
9929    OldList resources;
9930    FileDialog saveDialog;
9931    Anchor anchor;
9932    SizeAnchor sizeAnchor;
9933
9934    // FormDesigner data
9935    ObjectInfo object;
9936    Window control;
9937    Extent * tempExtents; //[4];
9938    BitmapResource icon;
9939    void * windowData;
9940    CreationActivationOption creationActivation;
9941    GLCapabilities glCapabilities;
9942    glCapabilities = { true, true, true, true, true, true, true, true, true /*false*/, true, true, true, true, true, true, true };
9943    struct
9944    {
9945       bool active:1;            // true if window and ancestors are active
9946       bool acquiredInput:1;     // true if the window is processing state based input
9947       bool modifiedDocument:1;
9948       bool disabled:1;          // true if window cannot interact
9949       bool isForegroundWindow:1;// true while a root window is being activated
9950       bool visible:1;           // Visibility flag
9951       bool destroyed:1;         // true if window is being destroyed
9952       bool anchored:1;          // true if this window is repositioned when the parent resizes
9953       bool dirty:1;             // Flag set to true if any descendant must be redrawn
9954       bool mouseInside:1;
9955       bool positioned:1;
9956       bool created:1;
9957       bool is3D:1;
9958       bool mergeMenus:1;
9959       bool modifyVirtArea:1;
9960       bool noAutoScrollArea:1;
9961       bool closing:1;
9962       bool autoCreate:1;
9963       bool setVisible:1;      // FOR FORM DESIGNER
9964       bool wasCreated:1;
9965       bool fullRender:1;
9966       bool moveable:1;
9967       bool alphaBlend:1;
9968       bool composing:1;
9969       bool useSharedMemory:1;
9970       bool resized:1;
9971       bool saving:1;
9972       bool nativeDecorations:1;
9973       bool manageDisplay:1;
9974       bool formDesigner:1; // True if we this is running in the form editor
9975       bool requireRemaximize:1;
9976       bool noConsequential:1;
9977    };
9978
9979    // Checks used internally for them not to take effect in FormDesigner
9980    property bool _isModal        { get { return !formDesigner ? style.modal : false; } }
9981    property subclass(DisplayDriver) _displayDriver  { get { return !formDesigner ? dispDriver : null; } }
9982
9983    WindowController controller;
9984
9985    public property WindowController controller
9986    {
9987       get { return controller; }
9988       set
9989       {
9990          if(controller)
9991             controller.setWindow(null);
9992          delete controller;
9993          controller = value;
9994          if(controller)
9995          {
9996             incref controller;
9997             controller.setWindow(this);
9998          }
9999       }
10000    }
10001
10002    public property bool noConsequential
10003    {
10004       set { noConsequential = value; }
10005       get { return noConsequential; }
10006    }
10007 };
10008
10009 public class CommonControl : Window
10010 {
10011    // creationActivation = doNothing;
10012
10013    ToolTip toolTip;
10014    public property const String toolTip
10015    {
10016       property_category $"Appearance"
10017       set
10018       {
10019          if(created) CommonControl::OnDestroy();
10020          delete toolTip;
10021          toolTip = value ? ToolTip { tip = value; } : null;
10022          incref toolTip;
10023          if(created) CommonControl::OnCreate();
10024       }
10025       get { return toolTip ? toolTip.tip : null; }
10026    }
10027
10028    void OnDestroy()
10029    {
10030       if(toolTip)
10031          // (Very) Ugly work around for the fact that the parent watcher
10032          // won't fire when it's already been disconnected...
10033          eInstance_FireSelfWatchers(toolTip,
10034             __ecereProp___ecereNameSpace__ecere__gui__Window_parent);
10035    }
10036
10037    bool OnCreate()
10038    {
10039       if(toolTip)
10040          toolTip.parent = this;
10041       return true;
10042    }
10043    ~CommonControl()
10044    {
10045       delete toolTip;
10046    }
10047 };
10048
10049 public class Percentage : float
10050 {
10051    const char * OnGetString(char * string, float * fieldData, bool * needClass)
10052    {
10053       int c;
10054       int last = 0;
10055       sprintf(string, "%.2f", this);
10056       c = strlen(string)-1;
10057       for( ; c >= 0; c--)
10058       {
10059          if(string[c] != '0')
10060             last = Max(last, c);
10061          if(string[c] == '.')
10062          {
10063             if(last == c)
10064                string[c] = 0;
10065             else
10066                string[last+1] = 0;
10067             break;
10068          }
10069       }
10070       return string;
10071    }
10072 };
10073
10074 public void ApplySkin(Class c, const char * name, void ** vTbl)
10075 {
10076    char className[1024];
10077    Class sc;
10078    OldLink d;
10079    int m;
10080
10081    subclass(Window) wc = (subclass(Window))c;
10082    subclass(Window) base = (subclass(Window))c.base;
10083
10084    sprintf(className, "%sSkin_%s", name, c.name);
10085    wc.pureVTbl = c._vTbl;
10086    c._vTbl = new void *[c.vTblSize];
10087    memcpy(c._vTbl, wc.pureVTbl, c.vTblSize * sizeof(void *));
10088    sc = eSystem_FindClass(c.module.application, className);
10089
10090    if(vTbl)
10091    {
10092       for(m = 0; m < c.base.vTblSize; m++)
10093       {
10094          if(c._vTbl[m] == base.pureVTbl[m])
10095             c._vTbl[m] = vTbl[m];
10096       }
10097    }
10098    if(sc)
10099    {
10100       for(m = 0; m < c.vTblSize; m++)
10101       {
10102          if(sc._vTbl[m] != wc.pureVTbl[m])
10103             c._vTbl[m] = sc._vTbl[m];
10104       }
10105    }
10106
10107    for(d = c.derivatives.first; d; d = d.next)
10108    {
10109       ApplySkin(d.data, name, c._vTbl);
10110    }
10111 }
10112
10113 public void UnapplySkin(Class c)
10114 {
10115    subclass(Window) wc = (subclass(Window))c;
10116    OldLink d;
10117
10118    if(wc.pureVTbl && c._vTbl != wc.pureVTbl)
10119    {
10120       delete c._vTbl;
10121       c._vTbl = wc.pureVTbl;
10122       wc.pureVTbl = null;
10123    }
10124
10125    for(d = c.derivatives.first; d; d = d.next)
10126    {
10127       UnapplySkin(d.data);
10128    }
10129 }
10130 /*
10131 void CheckFontIntegrity(Window window)
10132 {
10133    Window c;
10134    if(window)
10135    {
10136       if(window.usedFont && window.usedFont.font == 0xecececec)
10137       {
10138          FontResource uf = window.usedFont;
10139          char * className = window._class.name;
10140          char * text = window.text;
10141          Print("");
10142       }
10143       for(c = window.firstChild; c; c = c.next)
10144          CheckFontIntegrity(c);
10145    }
10146 }*/
10147
10148 public class ControllableWindow : Window
10149 {
10150    /*WindowController controller;
10151    public property WindowController controller { get { return controller; } set { delete controller; controller = value; incref controller; } }
10152    ~ControllableWindow() { delete controller; }*/
10153 }
10154
10155 class WindowControllerInterface : ControllableWindow
10156 {
10157    bool OnKeyDown(Key key, unichar ch)
10158    {
10159       bool result = controller.OnKeyDown ? ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyDown)((Window)controller.controlled, controller, key, ch) : true;
10160       if(result)
10161       {
10162          bool (* onKeyDown)(Window, Key, unichar) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown];
10163          if(onKeyDown)
10164             result = onKeyDown(controller.window, key, ch);
10165       }
10166       return result;
10167    }
10168
10169    bool OnKeyUp(Key key, unichar ch)
10170    {
10171       bool result = controller.OnKeyUp ? ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyUp)((Window)controller.controlled, controller, key, ch) : true;
10172       if(result)
10173       {
10174          bool (* onKeyUp)(Window, Key, unichar) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyUp];
10175          if(onKeyUp)
10176             result = onKeyUp(controller.window, key, ch);
10177       }
10178       return result;
10179    }
10180
10181    bool OnKeyHit(Key key, unichar ch)
10182    {
10183       bool result = controller.OnKeyHit ? ((bool(*)(Window, WindowController, Key, unichar))(void *)controller.OnKeyHit)((Window)controller.controlled, controller, key, ch) : true;
10184       if(result)
10185       {
10186          bool (* onKeyHit)(Window, Key, unichar) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit];
10187          if(onKeyHit)
10188             result = onKeyHit(controller.window, key, ch);
10189       }
10190       return result;
10191    }
10192
10193    bool OnMouseMove(int x, int y, Modifiers mods)
10194    {
10195       bool result = controller.OnMouseMove ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMouseMove)((Window)controller.controlled, controller, x, y, mods) : true;
10196       if(result)
10197       {
10198          bool(* onMouseMove)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove];
10199          if(onMouseMove)
10200             result = onMouseMove(controller.window, x, y, mods);
10201       }
10202       return result;
10203    }
10204
10205    bool OnLeftButtonDown(int x, int y, Modifiers mods)
10206    {
10207       bool result = controller.OnLeftButtonDown ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonDown)((Window)controller.controlled, controller, x, y, mods) : true;
10208       if(result)
10209       {
10210          bool(* onLeftButtonDown)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown];
10211          if(onLeftButtonDown)
10212             result = onLeftButtonDown(controller.window, x, y, mods);
10213       }
10214       return result;
10215    }
10216
10217    bool OnLeftButtonUp(int x, int y, Modifiers mods)
10218    {
10219       bool result = controller.OnLeftButtonUp ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftButtonUp)((Window)controller.controlled, controller, x, y, mods) : true;
10220       if(result)
10221       {
10222          bool(* onLeftButtonUp)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp];
10223          if(onLeftButtonUp)
10224             result = onLeftButtonUp(controller.window, x, y, mods);
10225       }
10226       return result;
10227    }
10228
10229    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
10230    {
10231       bool result = controller.OnLeftDoubleClick ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnLeftDoubleClick)((Window)controller.controlled, controller, x, y, mods) : true;
10232       if(result)
10233       {
10234          bool(* onLeftDoubleClick)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick];
10235          if(onLeftDoubleClick)
10236             result = onLeftDoubleClick(controller.window, x, y, mods);
10237       }
10238       return result;
10239    }
10240
10241    bool OnRightButtonDown(int x, int y, Modifiers mods)
10242    {
10243       bool result = controller.OnRightButtonDown ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonDown)((Window)controller.controlled, controller, x, y, mods) : true;
10244       if(result)
10245       {
10246          bool(* onRightButtonDown)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonDown];
10247          if(onRightButtonDown)
10248             result = onRightButtonDown(controller.window, x, y, mods);
10249       }
10250       return result;
10251    }
10252
10253    bool OnRightButtonUp(int x, int y, Modifiers mods)
10254    {
10255       bool result = controller.OnRightButtonUp ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightButtonUp)((Window)controller.controlled, controller, x, y, mods) : true;
10256       if(result)
10257       {
10258          bool(* onRightButtonUp)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp];
10259          if(onRightButtonUp)
10260             result = onRightButtonUp(controller.window, x, y, mods);
10261       }
10262       return result;
10263    }
10264
10265    bool OnRightDoubleClick(int x, int y, Modifiers mods)
10266    {
10267       bool result = controller.OnRightDoubleClick ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnRightDoubleClick)((Window)controller.controlled, controller, x, y, mods) : true;
10268       if(result)
10269       {
10270          bool(* onRightDoubleClick)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightDoubleClick];
10271          if(onRightDoubleClick)
10272             result = onRightDoubleClick(controller.window, x, y, mods);
10273       }
10274       return result;
10275    }
10276
10277    bool OnMiddleButtonDown(int x, int y, Modifiers mods)
10278    {
10279       bool result = controller.OnMiddleButtonDown ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonDown)((Window)controller.controlled, controller, x, y, mods) : true;
10280       if(result)
10281       {
10282          bool(* onMiddleButtonDown)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown];
10283          if(onMiddleButtonDown)
10284             result = onMiddleButtonDown(controller.window, x, y, mods);
10285       }
10286       return result;
10287    }
10288
10289    bool OnMiddleButtonUp(int x, int y, Modifiers mods)
10290    {
10291       bool result = controller.OnMiddleButtonUp ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleButtonUp)((Window)controller.controlled, controller, x, y, mods) : true;
10292       if(result)
10293       {
10294          bool(* onMiddleButtonUp)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp];
10295          if(onMiddleButtonUp)
10296             result = onMiddleButtonUp(controller.window, x, y, mods);
10297       }
10298       return result;
10299    }
10300
10301    bool OnMiddleDoubleClick(int x, int y, Modifiers mods)
10302    {
10303       bool result = controller.OnMiddleDoubleClick ? ((bool(*)(Window, WindowController, int, int, Modifiers))(void *)controller.OnMiddleDoubleClick)((Window)controller.controlled, controller, x, y, mods) : true;
10304       if(result)
10305       {
10306          bool(* onMiddleDoubleClick)(Window, int, int, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick];
10307          if(onMiddleDoubleClick)
10308             onMiddleDoubleClick(controller.window, x, y, mods);
10309       }
10310       return result;
10311    }
10312
10313    bool OnMultiTouch(TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers mods)
10314    {
10315       bool result = controller.OnMultiTouch ? ((bool(*)(Window, WindowController, TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers))(void *)controller.OnMultiTouch)((Window)controller.controlled, controller, event, infos, mods) : true;
10316       if(result)
10317       {
10318          bool(* onMultiTouch)(Window, TouchPointerEvent, Array<TouchPointerInfo>, Modifiers) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMultiTouch];
10319          if(onMultiTouch)
10320             onMultiTouch(controller.window, event, infos, mods);
10321       }
10322       return result;
10323    }
10324
10325    void OnResize(int width, int height)
10326    {
10327       if(controller.OnResize)
10328          ((void(*)(Window, WindowController, int, int))(void *)controller.OnResize)((Window)controller.controlled, controller, width, height);
10329       {
10330          void(* onResize)(Window, int, int) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnResize];
10331          if(onResize)
10332             onResize(controller.window, width, height);
10333       }
10334    }
10335
10336    void OnRedraw(Surface surface)
10337    {
10338       if(controller.OnRedraw)
10339          ((void(*)(Window, WindowController, Surface))(void *)controller.OnRedraw)((Window)controller.controlled, controller, surface);
10340       {
10341          void(* onRedraw)(Window, Surface) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRedraw];
10342          if(onRedraw)
10343             onRedraw(controller.window, surface);
10344       }
10345    }
10346
10347    bool OnCreate()
10348    {
10349       bool result = controller.OnCreate ? ((bool(*)(Window, WindowController))(void *)controller.OnCreate)((Window)controller.controlled, controller) : true;
10350       if(result)
10351       {
10352          bool(* onCreate)(Window) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnCreate];
10353          if(onCreate)
10354             result = onCreate(controller.window);
10355       }
10356       return result;
10357    }
10358
10359    bool OnLoadGraphics()
10360    {
10361       bool result = controller.OnLoadGraphics ? ((bool(*)(Window, WindowController))(void *)controller.OnLoadGraphics)((Window)controller.controlled, controller) : true;
10362       if(result)
10363       {
10364          bool(* onLoadGraphics)(Window) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLoadGraphics];
10365          if(onLoadGraphics)
10366             result = onLoadGraphics(controller.window);
10367       }
10368       return result;
10369    }
10370
10371    void OnUnloadGraphics()
10372    {
10373       if(controller.OnUnloadGraphics)
10374          ((void(*)(Window, WindowController))(void *)controller.OnUnloadGraphics)((Window)controller.controlled, controller);
10375       {
10376          void(* onUnloadGraphics)(Window) = (void *)controller.windowVTbl[__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnUnloadGraphics];
10377          if(onUnloadGraphics)
10378             onUnloadGraphics(controller.window);
10379       }
10380    }
10381 }
10382
10383 public class WindowController<class V>
10384 {
10385    void setWindow(Window value)
10386    {
10387       uint size = class(Window).vTblSize;
10388       if(value)
10389       {
10390          delete windowVTbl;
10391          windowVTbl = new void *[size];
10392          memcpy(windowVTbl, value._vTbl, size * sizeof(void *));
10393          if(value._vTbl == value._class._vTbl)
10394          {
10395             value._vTbl = new void *[value._class.vTblSize];
10396             memcpy(value._vTbl + size, value._class._vTbl + size, (value._class.vTblSize - size) * sizeof(void *));
10397          }
10398          {
10399             int c;
10400             for(c = 0; c < size; c++)
10401             {
10402                void * function = class(WindowControllerInterface)._vTbl[c];
10403                if(function && function != DefaultFunction)
10404                   value._vTbl[c] = function;
10405                else
10406                   value._vTbl[c] = windowVTbl[c];
10407             }
10408          }
10409       }
10410       else if(window)
10411       {
10412          memcpy(window._vTbl, windowVTbl, class(Window).vTblSize * sizeof(void *));
10413          delete windowVTbl;
10414       }
10415       window = value;
10416    }
10417 public:
10418    property Window window
10419    {
10420       get { return window; }
10421    }
10422    property V controlled
10423    {
10424       set { controlled = value; }
10425       get { return controlled; }
10426    }
10427    // TODO: Add OnStateChange so we can implement SavedConfigWindow as a WindowController instead
10428    virtual bool V::OnKeyDown(WindowController controller, Key key, unichar ch);
10429    virtual bool V::OnKeyUp(WindowController controller, Key key, unichar ch);
10430    virtual bool V::OnKeyHit(WindowController controller, Key key, unichar ch);
10431    virtual bool V::OnMouseMove(WindowController controller, int x, int y, Modifiers mods);
10432    virtual bool V::OnLeftButtonDown(WindowController controller, int x, int y, Modifiers mods);
10433    virtual bool V::OnLeftButtonUp(WindowController controller, int x, int y, Modifiers mods);
10434    virtual bool V::OnLeftDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10435    virtual bool V::OnRightButtonDown(WindowController controller, int x, int y, Modifiers mods);
10436    virtual bool V::OnRightButtonUp(WindowController controller, int x, int y, Modifiers mods);
10437    virtual bool V::OnRightDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10438    virtual bool V::OnMiddleButtonDown(WindowController controller, int x, int y, Modifiers mods);
10439    virtual bool V::OnMiddleButtonUp(WindowController controller, int x, int y, Modifiers mods);
10440    virtual bool V::OnMiddleDoubleClick(WindowController controller, int x, int y, Modifiers mods);
10441    virtual bool V::OnMultiTouch(WindowController controller, TouchPointerEvent event, Array<TouchPointerInfo> infos, Modifiers mods);
10442    virtual void V::OnResize(WindowController controller, int width, int height);
10443    virtual void V::OnRedraw(WindowController controller, Surface surface);
10444    virtual bool V::OnCreate(WindowController controller);
10445    virtual bool V::OnLoadGraphics(WindowController controller);
10446    virtual void V::OnUnloadGraphics(WindowController controller);
10447
10448 private:
10449    public int (** windowVTbl)();
10450    V controlled;
10451    Window window;
10452
10453    ~WindowController()
10454    {
10455       delete windowVTbl;
10456    }
10457 }