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