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