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