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