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