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