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