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