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