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