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