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