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