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