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