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