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