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