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