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