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