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