update copyrights
[aros:aros.git] / AROS / workbench / devs / monitors / Compositor / compositorclass.c
1 /*
2     Copyright © 2010-2013, The AROS Development Team. All rights reserved.
3     $Id$
4 */
5
6 #define DEBUG 0
7 #if (DEBUG)
8 #define DTOGGLE(x) x
9 #define DMODE(x) x
10 #define DMOVE(x) x
11 #define DRECALC(x) x
12 #define DREDRAWBM(x) x
13 #define DREDRAWSCR(x) x
14 #define DSTACK(x) x
15 #define DUPDATE(x) x
16 #else
17 #define DTOGGLE(x)
18 #define DMODE(x)
19 #define DMOVE(x)
20 #define DRECALC(x)
21 #define DREDRAWBM(x)
22 #define DREDRAWSCR(x)
23 #define DSTACK(x)
24 #define DUPDATE(x)
25 #endif
26
27 #include <aros/debug.h>
28
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <proto/graphics.h>
32 #include <proto/oop.h>
33 #include <proto/utility.h>
34
35 #include <graphics/view.h>
36 #include <hidd/graphics.h>
37
38 #include "compositor_intern.h"
39
40 #define COMPOSITE_PREFS "SYS/compositor.prefs"
41 #define COMPOSITE_PEFSTEMPLATE  "ABOVE/S,BELOW/S,LEFT/S,RIGHT/S,ALPHA/S"
42
43 enum
44 {
45     ARG_ABOVE = 0,
46     ARG_BELOW,
47     ARG_LEFT,
48     ARG_RIGHT,
49     ARG_ALPHA,
50     NOOFARGS
51 };
52
53
54 #ifdef GfxBase
55 #undef GfxBase
56 #endif
57 #define GfxBase compdata->GraphicsBase
58
59 #define _RECT(x) x.MinX, x.MinY, x.MaxX, x.MaxY
60
61 #define MAX(a,b) a > b ? a : b
62 #define MIN(a,b) a < b ? a : b
63
64 static BOOL AndRectRect(struct Rectangle * rect1, struct Rectangle * rect2,
65     struct Rectangle * intersect)
66 {
67     intersect->MinX = MAX(rect1->MinX, rect2->MinX);
68     intersect->MinY = MAX(rect1->MinY, rect2->MinY);
69     intersect->MaxX = MIN(rect1->MaxX, rect2->MaxX);
70     intersect->MaxY = MIN(rect1->MaxY, rect2->MaxY);
71     
72     if ((intersect->MinX > intersect->MaxX) ||
73         (intersect->MinY > intersect->MaxY))
74         return FALSE;
75     else
76         return TRUE;
77 }
78
79 static struct StackBitMapNode * HIDDCompositorIsBitMapOnStack(struct HIDDCompositorData * compdata, OOP_Object * bm)
80 {
81     struct StackBitMapNode * n = NULL;
82     
83     ForeachNode(&compdata->bitmapstack, n)
84     {
85         if (n->bm == bm)
86             return n;
87     }
88
89     return NULL;
90 }
91
92 static VOID HIDDCompositorValidateBitMapPositionChange(OOP_Object * bm, SIPTR *newxoffset, SIPTR *newyoffset, LONG displayedwidth, LONG displayedheight)
93 {
94     IPTR width, height;
95     LONG neglimit, poslimit;
96
97     OOP_GetAttr(bm, aHidd_BitMap_Width, &width);
98     OOP_GetAttr(bm, aHidd_BitMap_Height, &height);
99
100     /* Check x position */
101     if (width > displayedwidth)
102     {
103         neglimit = displayedwidth - width;
104         poslimit = 0;
105     }
106     else
107     {
108         neglimit = 0;
109         poslimit = displayedwidth - width;
110     }
111
112     if (*(newxoffset) > poslimit)
113         *(newxoffset) = poslimit;
114     if (*(newxoffset) < neglimit)
115         *(newxoffset) = neglimit;
116
117     /* Check y position */
118     if (height > displayedheight)
119         neglimit = displayedheight - height; /* Limit for scroll */
120     else
121         neglimit = 0;
122     poslimit = displayedheight - 15; /* Limit for drag */
123
124     if (*(newyoffset) > poslimit)
125         *(newyoffset) = poslimit;
126     if (*(newyoffset) < neglimit)
127         *(newyoffset) = neglimit;
128 }
129
130 static VOID HIDDCompositorRecalculateVisibleRegions(struct HIDDCompositorData *compdata)
131 {
132     struct StackBitMapNode      *n = NULL, *tmpn;
133     struct Region               *dispvisregion = NULL;
134     OOP_Object                  *bmpxfmt;
135
136     DRECALC(bug("[Compositor:%s] Display rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(compdata->screenrect)));
137
138     /*
139      * This function assumes bitmapstack is in correct Z order: 
140      * from topmost to bottom most
141      */
142     if ((dispvisregion = NewRegion()) != NULL)
143     {
144         OrRectRegion(dispvisregion, &compdata->screenrect);
145         
146         DRECALC(bug("[Compositor:%s] DisplayRegion @ 0x%p\n", __PRETTY_FUNCTION__, dispvisregion));
147
148         ForeachNodeSafe(&compdata->bitmapstack, n, tmpn)
149         {
150             /* Get bitmap bounding box in screen coordinates */
151             struct Rectangle tmprect;
152
153             n->sbmflags &= ~STACKNODE_VISIBLE;
154
155             if (n->screenregion)
156                 DisposeRegion(n->screenregion);
157
158             if ((n->screenregion = NewRegion()) != NULL)
159             {
160                 tmprect.MinX = n->leftedge;
161                 tmprect.MaxX = n->leftedge + OOP_GET(n->bm, aHidd_BitMap_Width) - 1;
162                 tmprect.MinY = n->topedge;
163                 tmprect.MaxY = n->topedge  + OOP_GET(n->bm, aHidd_BitMap_Height) - 1;
164
165                 DRECALC(bug("[Compositor:%s] Screen Rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(&tmprect)));
166
167                 OrRectRegion(n->screenregion, &tmprect); // Start with the Screen's dimensions ..
168                 AndRegionRegion(dispvisregion, n->screenregion); // And adjust for the "Display"
169
170                 if (n->screenregion->RegionRectangle)
171                 {
172                     int bmpstdfmt;
173                     bmpxfmt = (OOP_Object *)OOP_GET(n->bm, aHidd_BitMap_PixFmt);
174                     bmpstdfmt = (int)OOP_GET(bmpxfmt, aHidd_PixFmt_StdPixFmt);
175                     DRECALC(bug("[Compositor:%s] Screen BitMap PixFmt %lx @ 0x%p\n", __PRETTY_FUNCTION__, bmpstdfmt, bmpxfmt));
176
177                     switch (bmpstdfmt)
178                     {
179                         case vHidd_StdPixFmt_ARGB32:
180                         case vHidd_StdPixFmt_BGRA32:
181                         case vHidd_StdPixFmt_RGBA32:
182                         case vHidd_StdPixFmt_ABGR32:
183                         {
184                             DRECALC(bug("[Compositor:%s] BitMap has ALPHA\n", __PRETTY_FUNCTION__));
185
186                             n->sbmflags |= STACKNODE_ALPHA;
187
188                             if (!(compdata->alpharegion))
189                             {
190                                 compdata->alpharegion = NewRegion();
191                                 DRECALC(bug("[Compositor:%s] AlphaRegion Allocated @ 0x%p\n", __PRETTY_FUNCTION__, compdata->alpharegion));
192                             }
193
194                             OrRegionRegion(compdata->alpharegion, n->screenregion);
195                             break;
196                         }
197                         default:
198                         {
199                             n->sbmflags &= ~STACKNODE_ALPHA;
200
201                             AndRectRect(&n->screenregion->bounds, &compdata->screenrect, &n->screenvisiblerect);
202                             ClearRegionRegion(n->screenregion, dispvisregion);
203
204                             if (!(compdata->capabilities & COMPF_ABOVE))
205                             {
206                                 tmprect.MinX = compdata->screenrect.MinX;
207                                 tmprect.MaxX = compdata->screenrect.MaxX;
208                                 tmprect.MinY = compdata->screenrect.MinY;
209                                 tmprect.MaxY = n->topedge - 1;
210                                 ClearRectRegion(dispvisregion, &tmprect);
211                             }
212                             if (!(compdata->capabilities & COMPF_BELOW))
213                             {
214                                 tmprect.MinX = compdata->screenrect.MinX;
215                                 tmprect.MaxX = compdata->screenrect.MaxX;
216                                 tmprect.MinY = n->topedge  + OOP_GET(n->bm, aHidd_BitMap_Height);
217                                 tmprect.MaxY = compdata->screenrect.MaxY;
218                                 ClearRectRegion(dispvisregion, &tmprect);
219                             }
220                             if (!(compdata->capabilities & COMPF_LEFT))
221                             {
222                                 tmprect.MinX = compdata->screenrect.MinX;
223                                 tmprect.MaxX = n->leftedge - 1;
224                                 tmprect.MinY = n->topedge;
225                                 tmprect.MaxY = n->topedge  + OOP_GET(n->bm, aHidd_BitMap_Height) - 1;
226                                 ClearRectRegion(dispvisregion, &tmprect);
227                             }
228                             if (!(compdata->capabilities & COMPF_RIGHT))
229                             {
230                                 tmprect.MinX = n->leftedge + OOP_GET(n->bm, aHidd_BitMap_Width);
231                                 tmprect.MaxX = compdata->screenrect.MaxX;
232                                 tmprect.MinY = n->topedge;
233                                 tmprect.MaxY = n->topedge  + OOP_GET(n->bm, aHidd_BitMap_Height) - 1;
234                                 ClearRectRegion(dispvisregion, &tmprect);
235                             }
236                         }
237                     }
238                     n->sbmflags |= STACKNODE_VISIBLE;
239                 }
240
241                 DRECALC(bug("[Compositor:%s] Bitmap 0x%x, topedge %d, visible %d, [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, 
242                             n->bm, n->topedge, (n->sbmflags & STACKNODE_VISIBLE), _RECT(n->screenvisiblerect)));
243             }
244             else
245             {
246                 DRECALC(bug("[Compositor:%s] Failed to create Screen Region\n", __PRETTY_FUNCTION__));
247             }
248         }
249         DisposeRegion(dispvisregion);
250     }
251     else
252     {
253         DRECALC(bug("[Compositor:%s] Failed to create Display Region\n", __PRETTY_FUNCTION__));
254     }
255 }
256
257 static HIDDT_ModeID FindBestHiddMode(struct HIDDCompositorData *compdata, ULONG width, ULONG height, ULONG depth, ULONG *res_depth)
258 {
259     HIDDT_ModeID mode = vHidd_ModeID_Invalid;
260     OOP_Object *sync, *pf;
261     IPTR w, h, d;
262     ULONG dw, dh, delta;
263     ULONG found_delta  = -1;
264     ULONG found_width  = 0;
265     ULONG found_height = 0;
266     ULONG found_depth  = 0;
267     HIDDT_ModeID found_mode = vHidd_ModeID_Invalid;
268
269     DMODE(bug("[%s] Finding best match for mode %ux%ux%u\n", __PRETTY_FUNCTION__, width, height, depth));
270
271     while ((mode = HIDD_Gfx_NextModeID(compdata->gfx, mode, &sync, &pf)) != vHidd_ModeID_Invalid)
272     {
273         BOOL match;
274
275         DMODE(bug("[%s] Checking mode 0x%08X... ", __PRETTY_FUNCTION__, mode));
276         if (OOP_GET(pf, aHidd_PixFmt_ColorModel) != vHidd_ColorModel_TrueColor)
277         {
278             DMODE(bug("Skipped (not truecolor)\n"));
279             continue;
280         }
281
282         OOP_GetAttr(sync, aHidd_Sync_HDisp, &w);
283         OOP_GetAttr(sync, aHidd_Sync_VDisp, &h);
284         OOP_GetAttr(pf, aHidd_PixFmt_Depth, &d);
285
286         dw = w > width  ? w - width  : w < width  ? width  - w : 1;
287         dh = h > height ? h - height : h < height ? height - h : 1;
288         delta = dw * dh;
289
290         match = FALSE;
291         if (delta < found_delta)
292         {
293             /* If mode resolution is closer to the needed one, we've got a better match */
294             found_delta  = delta;
295             found_width  = w;
296             found_height = h;
297
298             match = TRUE;
299         }
300         else if (delta == found_delta)
301         {
302             /* If resolution is the same as that of current candidate mode, we can look at depth. */
303             if (found_depth > depth)
304             {
305                 /*
306                  * Candidate mode if deeper than requested. We can supersede it with another mode
307                  * of smaller depth, but which still matches our request.
308                  */
309                 if ((d < found_depth) && (d >= depth))
310                     match = TRUE;
311             }
312             else if (found_depth < depth)
313             {
314                 /*
315                  * We want better depth than current candidate.
316                  * In this case anything deeper will do.
317                  */
318                 if (d > found_depth)
319                     match = TRUE;
320             }
321         }
322
323         if (match)
324         {
325             /*
326              * Mode with the same delta, but larger depth, may supersede
327              * previous mode, if we prefer deeper ones.
328              */
329             DMODE(bug("Selected (%ldx%ldx%ld, delta = %u)", w, h, d, delta));
330             found_depth = d;
331             found_mode  = mode;
332         }
333         DMODE(bug("\n"));
334     }
335
336     /* Store mode information */ 
337     compdata->screenrect.MinX = 0;
338     compdata->screenrect.MinY = 0;
339     compdata->screenrect.MaxX = found_width  - 1;
340     compdata->screenrect.MaxY = found_height - 1;
341     *res_depth = found_depth;
342
343     return found_mode;
344 }
345
346 static void UpdateDisplayMode(struct HIDDCompositorData *compdata)
347 {
348     struct StackBitMapNode *n;
349     IPTR modeid, width, height, depth;
350     OOP_Object *sync, *pf;
351     UBYTE comp_depth = 16;
352     ULONG found_depth;
353
354     /*
355      * Examine all bitmaps in the stack to figure out the needed depth.
356      * We need a maximum depth of all depths in order to keep correct colors.
357      * But not less than 16 bits, because we can't compose on a LUT screen.
358      *
359      * If a LUT bitmap is present in the stack (depth < 9), we request truecolor
360      * screen for better color presentation.
361      *
362      * We examine bitmaps in reverse order, in this case 'sync' will hold
363      * information about the top bitmap when we exit the loop.
364      * Size of our composited mode needs to be as close as possible to that one.
365      */
366     for (n = (struct StackBitMapNode *)compdata->bitmapstack.mlh_TailPred;
367          n->n.mln_Pred; n = (struct StackBitMapNode *)n->n.mln_Pred)
368     {
369         OOP_GetAttr(n->bm, aHidd_BitMap_ModeID, &modeid);
370         HIDD_Gfx_GetMode(compdata->gfx, modeid, &sync, &pf);
371
372         if (OOP_GET(pf, aHidd_PixFmt_ColorModel) == vHidd_ColorModel_TrueColor)
373         {
374             OOP_GetAttr(pf, aHidd_PixFmt_Depth, &depth);
375             if (depth > comp_depth)
376                 comp_depth = depth;
377         }
378         else
379         {
380             /*
381              * If we have a LUT bitmap on stack, we request 24-bit screen
382              * for better color transfer.
383              */
384             comp_depth = 24;
385         }
386     }
387
388     /* Get the needed size */
389     OOP_GetAttr(sync, aHidd_Sync_HDisp, &width);
390     OOP_GetAttr(sync, aHidd_Sync_VDisp, &height);
391
392     DSTACK(bug("[%s] Requested mode %ldx%ldx%d\n", __PRETTY_FUNCTION__, width, height, comp_depth));
393
394     modeid = FindBestHiddMode(compdata, width, height, depth, &found_depth);
395     DSTACK(bug("[%s] Composition Display Mode 0x%08X [current 0x%08X]\n", __PRETTY_FUNCTION__, modeid, compdata->screenmodeid));
396
397     if (modeid != compdata->screenmodeid)
398     {
399         /* The mode is different. Need to prepare information needed for compositing */
400         struct TagItem gctags[] =
401         {
402             { aHidd_GC_Foreground, 0x99999999 }, 
403             { TAG_DONE           , 0          }
404         };
405
406         /* Signal mode change */ 
407         compdata->screenmodeid = modeid;
408         compdata->modeschanged = TRUE;
409
410         /* Get gray foregound */
411         if (found_depth < 24)
412             gctags[0].ti_Data = 0x9492;
413
414         OOP_SetAttrs(compdata->gc, gctags);
415     }
416 }
417
418 static inline void HIDDCompositorRedrawBitmap(struct HIDDCompositorData *compdata, struct StackBitMapNode *n, struct Rectangle *rect)
419 {
420     /* The given rectangle is already in screen coordinate system here */
421     ULONG blitwidth  = rect->MaxX - rect->MinX + 1;
422     ULONG blitheight = rect->MaxY - rect->MinY + 1;
423
424     DREDRAWBM(bug("[Compositor:%s] Redraw BitMap 0x%p, Rect[%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, n->bm,
425                   rect->MinX, rect->MinY, rect->MaxX, rect->MaxY));
426     DREDRAWBM(bug("[Compositor:%s] Blitting %dx%d [from %d, %d]\n", __PRETTY_FUNCTION__, blitwidth, blitheight, 
427                   rect->MinX - n->leftedge, rect->MinY - n->topedge));
428
429     HIDD_Gfx_CopyBox(compdata->gfx, n->bm,
430                     /* Transform to source bitmap coord system */
431                     rect->MinX - n->leftedge, rect->MinY - n->topedge,
432                     compdata->compositedbitmap,
433                     rect->MinX, rect->MinY, blitwidth, blitheight,
434                     compdata->gc);
435 }
436
437 static inline void ClearRect(struct HIDDCompositorData *compdata, ULONG MinX, ULONG MinY, ULONG MaxX, ULONG MaxY)
438 {
439     DREDRAWSCR(bug("[Compositor:%s] Clearing [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__,
440                    MinX, MinY, MaxX, MaxY));
441
442     HIDD_BM_FillRect(compdata->compositedbitmap, compdata->gc,
443                      MinX, MinY, MaxX, MaxY);
444 }
445
446 static VOID HIDDCompositorRedrawVisibleDisplay(struct HIDDCompositorData *compdata)
447 {
448     struct Region       *dispvisregion = NULL;
449     struct Rectangle    tmprect;
450
451     struct StackBitMapNode *n;
452
453     DREDRAWSCR(bug("[Compositor:%s] Redrawing screen (GfxBase @ 0x%p)\n", __PRETTY_FUNCTION__, GfxBase));
454
455     /* Recalculate visible regions */
456     HIDDCompositorRecalculateVisibleRegions(compdata);
457
458     if ((dispvisregion = NewRegion()) != NULL)
459     {
460         OrRectRegion(dispvisregion, &compdata->screenrect);
461         DRECALC(bug("[Compositor:%s] Display rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(compdata->screenrect)));
462
463         ForeachNode(&compdata->bitmapstack, n)
464         {
465             if ((n->sbmflags & STACKNODE_VISIBLE) &&
466                 (!(n->sbmflags & STACKNODE_ALPHA)) &&
467                 (n->screenregion))
468             {
469                 DREDRAWSCR(bug("[Compositor:%s] ScreenRegion @ 0x%p ScreenBitMap @ 0x%p [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__,
470                                n->screenregion, n->bm, _RECT(n->screenvisiblerect)));
471
472                 DREDRAWSCR(bug("[Compositor:%s] Redrawing Visible Screen Regions..\n", __PRETTY_FUNCTION__));
473                 // Render the visable regions ..
474                 struct RegionRectangle * srrect = n->screenregion->RegionRectangle;
475                 while (srrect)
476                 {
477                     tmprect.MinX = srrect->bounds.MinX + n->screenregion->bounds.MinX;
478                     tmprect.MinY = srrect->bounds.MinY + n->screenregion->bounds.MinY;
479                     tmprect.MaxX = srrect->bounds.MaxX + n->screenregion->bounds.MinX;
480                     tmprect.MaxY = srrect->bounds.MaxY + n->screenregion->bounds.MinY;
481
482                     DREDRAWSCR(bug("[Compositor:%s] Region [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(&tmprect)));
483
484                     HIDDCompositorRedrawBitmap(compdata, n, &tmprect);
485                     HIDD_BM_UpdateRect(compdata->compositedbitmap,
486                        tmprect.MinX, tmprect.MinY,
487                        tmprect.MaxX - tmprect.MinX + 1,
488                        tmprect.MaxY - tmprect.MinY + 1);
489
490                     srrect = srrect->Next;
491                 }
492                 ClearRegionRegion(n->screenregion, dispvisregion);
493             }
494         }
495         struct RegionRectangle * dispclrrect = dispvisregion->RegionRectangle;
496         while (dispclrrect)
497         {
498             struct HIDD_BackFillHookMsg clearmsg;
499
500             tmprect.MinX = dispclrrect->bounds.MinX + dispvisregion->bounds.MinX;
501             tmprect.MinY = dispclrrect->bounds.MinY + dispvisregion->bounds.MinY;
502             tmprect.MaxX = dispclrrect->bounds.MaxX + dispvisregion->bounds.MinX;
503             tmprect.MaxY = dispclrrect->bounds.MaxY + dispvisregion->bounds.MinY;
504
505             DREDRAWSCR(bug("[Compositor:%s] Render Display Void Region [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(&tmprect)));
506
507             clearmsg.bounds = &tmprect;
508             clearmsg.offsetx = 0;
509             clearmsg.offsety = 0;
510             CallHookPkt(compdata->backfillhook, compdata->compositedbitmap, &clearmsg);
511             HIDD_BM_UpdateRect(compdata->compositedbitmap,
512                tmprect.MinX, tmprect.MinY,
513                tmprect.MaxX - tmprect.MinX + 1,
514                tmprect.MaxY - tmprect.MinY + 1);
515
516             dispclrrect = dispclrrect->Next;
517         }
518         ForeachNode(&compdata->bitmapstack, n)
519         {
520             if ((n->sbmflags & STACKNODE_VISIBLE) &&
521                 (n->sbmflags & STACKNODE_ALPHA) &&
522                 (n->screenregion))
523             {
524                 DREDRAWSCR(bug("[Compositor:%s] ALPHAScreenRegion @ 0x%p ScreenBitMap @ 0x%p [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__,
525                                    n->screenregion, n->bm, _RECT(n->screenvisiblerect)));
526             }
527         }
528         DisposeRegion(dispvisregion);
529     }
530 }
531
532 /*  
533
534 There are several cases that needs to be handled in this code. They are documented
535 below. Please read it before making changes.
536 etb     = existing topbitmap
537 ntb     = new top bitmap
538 sb      = screen bitmap
539 cb      = composited bitmap
540 fs      = covers full screen
541 nfs     = not covers full screen
542 mA      = mode "A"
543 mB      = mode "B"
544 disp()  = dispose
545 new()   = new
546
547 The resulting mode is always that of screen bitmap as set in "effect" column.
548 The composited bitmap always matches the resulting screen mode or is NULL.
549
550 | exiting screen situation          | change         | effect                               |
551 | USE CASE: SWITCHING BETWEEN FULL SCREEN SCREENS - SAME MODE                               |
552 | etb->fs, mA, sb==etb, cb==NULL    | ntb->fs, mA    | sb==ntb, cb==NULL                    |
553 | etb->fs, mA, sb==etb, cb!=NULL    | ntb->fs, mA    | sb==ntb, cb!=NULL                    |
554 | USE CASE: SWITCHING BETWEEN FULL SCREEN AND NOT FULL SCREEN SCREENS - SAME MODE           |
555 | etb->fs, mA, sb==etb, cb==NULL    | ntb->nfs, mA   | new(cb), sb==cb, cb!=NULL            |
556 | etb->fs, mA, sb==etb, cb!=NULL    | ntb->nfs, mA   | sb==cb, cb!=NULL                     |
557 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND FULL SCREEN SCREENS - SAME MODE           |
558 | etb->nfs, mA, sb==cb, cb==NULL    | NOT POSSIBLE                                          |
559 | etb->nfs, mA, sb==cb, cb!=NULL    | ntb->fs, mA    | sb==ntb, cb!=NULL                    |
560 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND NOT FULL SCREEN SCREENS - SAME MODE       |
561 | etb->nfs, mA, sb==cb, cb==NULL    | NOT POSSIBLE                                          |
562 | etb->nfs, mA, sb==cb, cb!=NULL    | ntb->nfs, mA   | sb==cb, cb!=NULL                     |
563
564
565 | USE CASE: SWITCHING BETWEEN FULL SCREEN SCREENS - DIFFERENT MODES                         |
566 | etb->fs, mA, sb==etb, cb==NULL    | ntb->fs, mB    | sb==ntb, cb==NULL                    |
567 | etb->fs, mA, sb==etb, cb!=NULL    | ntb->fs, mB    | disp(cb), sb==ntb, cb==NULL          |
568 | USE CASE: SWITCHING BETWEEN FULL SCREEN AND NOT FULL SCREEN SCREENS - DIFFERENT MODES     |
569 | etb->fs, mA, sb==etb, cb==NULL    | ntb->nfs, mB   | new(cb), sb==cb, cb!=NULL            |
570 | etb->fs, mA, sb==etb, cb!=NULL    | ntb->nfs, mB   | disp(cb), new(cb), sb==cb, cb!=NULL  |
571 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND FULL SCREEN SCREENS - DIFFERENT MODES     |
572 | etb->nfs, mA, sb==cb, cb==NULL    | NOT POSSIBLE                                          |
573 | etb->nfs, mA, sb==cb, cb!=NULL    | ntb->fs, mB    | disp(cb), sb==ntb, cb==NULL          |
574 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND NOT FULL SCREEN SCREENS - DIFFERENT MODES |
575 | etb->nfs, mA, sb==cb, cb==NULL    | NOT POSSIBLE                                          |
576 | etb->nfs, mA, sb==cb, cb!=NULL    | ntb->nfs, mB   | disp(cb), new(cb), sb==cb, cb!=NULL  |
577
578
579 | USE CASE: DRAGGING SCREEN DOWN                                                            |
580 | etb->fs, mA, sb==etb, cb==NULL    | ntb->nfs, mA   | new(cb), sb==cb                      |
581 | etb->fs, mA, sb==etb, cb!=NULL    | ntb->nfs, mA   | sb==cb                               |
582 | USE CASE: DRAGGING SCREEN UP                                                              |
583 | etb->nfs, mA, sb==cb, cb!=NULL    | ntb->fs, mA    | sb==etb                              |
584 | etb->nfs, mA, sb==cb, cb==NULL    | NOT POSSIBLE                                          |
585
586 Resulting rules (order matters):
587
588 (a) if ((cb!=NULL) && (etb->mode!=ntb->mode)) {dispose(cb), cb=NULL}
589 (b) if ((ntb->nfs) && (cb==NULL)) new(cb)
590 (c) if (ntb->nfs) sb=cb
591 (d) if (ntb->fs) sb=ntb
592
593 Additional rule:
594 (e) if (oldsb!=sb) modeswitch(sb)
595
596 02.09.2011: we don't remember sb any more because we don't handle it in any way. Instead
597             we either have or don't have compositedbitmap. If we have it, composition
598             is on (sb = cb). If we don't have it, composition is off (sb = ntb).
599 */
600 static BOOL HIDDCompositorToggleCompositing(struct HIDDCompositorData *compdata, BOOL newtop)
601 {
602     /* 
603      * If the topbitmap covers the complete screen, show it instead of 
604      * compositedbitmap. Remember that screen bitmap -> composited bitmap
605      * mirroring has a negative impact on performance.
606      */
607     OOP_Object *oldcompositedbitmap = compdata->compositedbitmap;
608     OOP_Object *newscreenbitmap = NULL;
609     BOOL ok = TRUE;
610
611     /* (a) If mode change is needed, enforce opening a new screen */
612     if (compdata->modeschanged)
613     {
614         D(bug("[Compositor:%s] Display Mode changed\n", __PRETTY_FUNCTION__));
615         compdata->compositedbitmap = NULL;
616     }
617
618 #if (0)
619     /*
620      * This condition is enough as compositing allows only dragging screen down
621      * and not up/left/right at the moment.
622      */
623     if (topedge > 0)
624     {
625 #endif
626         /* (b) */
627         if (compdata->compositedbitmap == NULL)
628         {
629             /*
630              * compositedbitmap == NULL means we were in passthrough mode before,
631              * or have just changed display mode - set up screen for composition.
632              */
633             D(bug("[Compositor:%s] Initialising Display-Compositor..\n", __PRETTY_FUNCTION__));
634
635             if (compdata->fb)
636             {
637                 /*
638                  * If our display driver uses a framebuffer, we can reuse it.
639                  * Copy its original contents back into the bitmap which it replaced,
640                  * then change framebuffer's video mode.
641                  * Framebuffer is the only bitmap which can change its ModeID on the fly.
642                  */
643                 D(bug("[Compositor:%s] Using Display Famebuffer BitMap @ 0x%p\n", __PRETTY_FUNCTION__, compdata->fb));
644
645                  /* Do this comparison in order not to show the framebuffer twice */
646                 if (oldcompositedbitmap != compdata->fb)
647                 {
648                     /*
649                      * 1. It's legal to show the framebuffer itself. This causes copying
650                      *    back old bitmap contents and detaching from it.
651                      * 2. The result of this will always match compdata->fb.
652                      * 3. Internally this is a simple blit operation, it can't fail.
653                      */
654                     D(bug("[Compositor:%s] Copying old Famebuffer BitMap\n", __PRETTY_FUNCTION__));
655                     compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, compdata->fb, fHidd_Gfx_Show_CopyBack);
656                 }
657
658                 /* Switch display mode on the framebuffer. */
659                 OOP_SetAttrsTags(compdata->fb, aHidd_BitMap_ModeID, compdata->screenmodeid, TAG_DONE);
660                 /* We are now compositing on the framebuffer */
661                 compdata->compositedbitmap = compdata->fb;
662             }
663             else
664             {
665                 /*
666                  * There's no framebuffer.
667                  * Create a new bitmap that will be used for compositing.
668                  */
669                 struct TagItem bmtags[5];
670
671                 bmtags[0].ti_Tag = aHidd_BitMap_Width;          bmtags[0].ti_Data = compdata->screenrect.MaxX + 1;
672                 bmtags[1].ti_Tag = aHidd_BitMap_Height;         bmtags[1].ti_Data = compdata->screenrect.MaxY + 1;
673                 bmtags[2].ti_Tag = aHidd_BitMap_Displayable;    bmtags[2].ti_Data = TRUE;
674                 bmtags[3].ti_Tag = aHidd_BitMap_ModeID;         bmtags[3].ti_Data = compdata->screenmodeid;
675                 bmtags[4].ti_Tag = TAG_DONE;                    bmtags[4].ti_Data = TAG_DONE;
676
677                 compdata->compositedbitmap = HIDD_Gfx_NewBitMap(compdata->gfx, bmtags);
678                 D(bug("[Compositor:%s] Created Compositor Display BitMap @ 0x%p\n", __PRETTY_FUNCTION__, compdata->compositedbitmap));
679
680                 /* Mode changed, this bitmap will be shown later */
681                 newscreenbitmap = compdata->compositedbitmap;
682
683                 /* NewBitMap can fail, handle this */
684                 if (!newscreenbitmap)
685                     ok = FALSE;
686             }
687         }
688         else /* if (compdata->compositedbitmap == NULL) */
689         {
690             /*
691              * We are already in compositing mode and will stay in it.
692              * Do not destroy our working bitmap.
693              */
694             oldcompositedbitmap = NULL;
695         }
696
697         /*
698          * (c) Here composition is turned on (compositedbitmap != NULL).
699          * Redraw bitmap stack - compensate possible changes
700          */
701         if (ok)
702             HIDDCompositorRedrawVisibleDisplay(compdata);
703 #if(0)
704     }
705     else if (oldcompositedbitmap || newtop)
706     {
707         /*
708          * (d) Set passthrough mode and display the frontmost bitmap.
709          * This is also triggered by 'newtop' parameter, which tells us
710          * that frontmost bitmap has been changed, and we need to display a new one.
711          * Old compositedbitmap has been remembered in the beginning. If it's not
712          * NULL, it will be destroyed in the end.
713          */
714         newscreenbitmap = compdata->topbitmap;
715         compdata->compositedbitmap = NULL;
716     }
717 #endif
718
719     DTOGGLE(bug("[Compositor:%s] oldcompbmp 0x%p, topbmp 0x%p, compbmp 0x%p, newscreenbmp 0x%p\n", __PRETTY_FUNCTION__,
720             oldcompositedbitmap, compdata->topbitmap, compdata->compositedbitmap, newscreenbitmap));
721
722     /*
723      * (e) If the screenbitmap changed, show the new screenbitmap.
724      * We do it after refreshing, for better visual appearance.
725      */
726     if (newscreenbitmap)
727     {
728         IPTR w, h;
729
730         compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, newscreenbitmap, fHidd_Gfx_Show_CopyBack);
731         D(bug("[Compositor:%s] Displayed bitmap 0x%p, Show returned 0x%p\n", __PRETTY_FUNCTION__, newscreenbitmap, compdata->screenbitmap));
732
733         /* After Show we need Update for mirroring drivers */
734         if (compdata->screenbitmap)
735         {
736             OOP_GetAttr(compdata->screenbitmap, aHidd_BitMap_Width, &w);
737             OOP_GetAttr(compdata->screenbitmap, aHidd_BitMap_Height, &h);
738             HIDD_BM_UpdateRect(compdata->screenbitmap, 0, 0, w, h);
739         }
740     }
741
742     /*
743      * (a) - disposing of oldcompositingbitmap needs to happen after mode switch 
744      * since it could have been the current screenbitmap
745      */
746     if (oldcompositedbitmap && (oldcompositedbitmap != compdata->fb))
747     {
748         D(bug("[Compositor:%s] Disposing old working bitmap 0x%p\n", __PRETTY_FUNCTION__, oldcompositedbitmap));
749         HIDD_Gfx_DisposeBitMap(compdata->gfx, oldcompositedbitmap);
750     }
751
752     /* Handled */
753     compdata->modeschanged = FALSE;
754
755     return ok;
756 }
757
758 static VOID HIDDCompositorPurgeBitMapStack(struct HIDDCompositorData * compdata)
759 {
760     struct StackBitMapNode * curr, * next;
761
762     ForeachNodeSafe(&compdata->bitmapstack, curr, next)
763     {
764         if (curr->screenregion)
765             DisposeRegion(curr->screenregion);
766
767         FreeMem(curr, sizeof(struct StackBitMapNode));
768     }
769
770     NEWLIST(&compdata->bitmapstack);
771 }
772
773 static void HIDDCompositorShowSingle(struct HIDDCompositorData *compdata, OOP_Object *bm)
774 {
775     /* Show the single top bitmap */
776     compdata->topbitmap = bm;
777     compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, bm, fHidd_Gfx_Show_CopyBack);
778
779     /* Dispose working bitmap (if any) */
780     if (compdata->compositedbitmap)
781     {
782         /* Be careful with the framebuffer */
783         if (compdata->compositedbitmap != compdata->fb)
784             HIDD_Gfx_DisposeBitMap(compdata->gfx, compdata->compositedbitmap);
785
786         /* This will deactivate us */
787         compdata->compositedbitmap = NULL;
788     }
789 }
790
791 /* Emergency error recovery function */
792 static void HIDDCompositorReset(struct HIDDCompositorData *compdata)
793 {
794     /* Purge bitmap stack */
795     HIDDCompositorPurgeBitMapStack(compdata);
796
797     /*
798      * Reset our internal state so that next BitMapStackChanged
799      * causes complete reinitialization.
800      */
801     compdata->screenmodeid = vHidd_ModeID_Invalid;
802     compdata->screenbitmap = NULL;
803 }
804
805 VOID CompositorParseConfig(struct HIDDCompositorData *compdata)
806 {
807     struct RDArgs *rdargs;
808     IPTR CompArgs[NOOFARGS] = { 0 };
809     TEXT CompConfig[1024];
810
811     /* use default amiga-like capabailities */
812     compdata->capabilities = COMPF_ABOVE;
813
814     rdargs = AllocDosObjectTags(DOS_RDARGS, TAG_END);
815     if (rdargs != NULL)
816     {
817         if (GetVar(COMPOSITE_PREFS, CompConfig, 1024, GVF_GLOBAL_ONLY) != -1)
818         {
819             rdargs->RDA_Source.CS_Buffer = CompConfig;
820             rdargs->RDA_Source.CS_Length = strlen(rdargs->RDA_Source.CS_Buffer);
821             rdargs->RDA_DAList = NULL;
822             rdargs->RDA_Buffer = NULL;
823             rdargs->RDA_BufSiz = 0;
824             rdargs->RDA_ExtHelp = NULL;
825             rdargs->RDA_Flags = 0;
826
827             if (ReadArgs(COMPOSITE_PEFSTEMPLATE, CompArgs, rdargs) != NULL)
828             {
829                 if (CompArgs[ARG_ABOVE])
830                     compdata->capabilities |= COMPF_ABOVE;
831                 else
832                     compdata->capabilities &= ~COMPF_ABOVE;
833                 
834                 if (CompArgs[ARG_BELOW])
835                     compdata->capabilities |= COMPF_BELOW;
836                 else
837                     compdata->capabilities &= ~COMPF_BELOW;
838                 
839                 if (CompArgs[ARG_LEFT])
840                     compdata->capabilities |= COMPF_LEFT;
841                 else
842                     compdata->capabilities &= ~COMPF_LEFT;
843                 
844                 if (CompArgs[ARG_RIGHT])
845                     compdata->capabilities |= COMPF_RIGHT;
846                 else
847                     compdata->capabilities &= ~COMPF_RIGHT;
848     /*
849                 if (CompArgs[ARG_ALPHA])
850                     compdata->capabilities |= COMPF_ALPHA;
851                 else
852                     compdata->capabilities &= ~COMPF_ALPHA;
853     */
854                 FreeArgs(rdargs);
855             }
856         }
857         FreeDosObject(DOS_RDARGS, rdargs);
858     }
859 }
860
861 AROS_UFH3(void, CompositorDefaultBackFillFunc,
862     AROS_UFHA(struct Hook *             , h,      A0),
863     AROS_UFHA(OOP_Object *              , bm,     A2),
864     AROS_UFHA(struct HIDD_BackFillHookMsg *  , msg,    A1))
865 {
866     AROS_USERFUNC_INIT
867
868     struct HIDDCompositorData *compdata = h->h_Data;
869
870     D(bug("[%s] HIDDCompositorData @ 0x%p\n", __PRETTY_FUNCTION__, compdata));
871
872     ClearRect(compdata, msg->bounds->MinX, msg->bounds->MinY, msg->bounds->MaxX, msg->bounds->MaxY);
873
874     AROS_USERFUNC_EXIT
875 }
876
877 /* PUBLIC METHODS */
878 OOP_Object *METHOD(Compositor, Root, New)
879 {
880     o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
881
882     if (o)
883     {
884         OOP_MethodID disposemid;
885         struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
886
887         D(bug("[%s] Compositor @ 0x%p, data @ 0x%p\n", __PRETTY_FUNCTION__, o, compdata));
888
889         CompositorParseConfig(compdata);
890
891         D(bug("[%s] Composite Capabilities: %08lx\n", __PRETTY_FUNCTION__, compdata->capabilities));
892
893         compdata->screenmodeid = vHidd_ModeID_Invalid;
894
895         NEWLIST(&compdata->bitmapstack);
896
897         compdata->defaultbackfill.h_Entry = (HOOKFUNC)AROS_ASMSYMNAME(CompositorDefaultBackFillFunc);
898         compdata->defaultbackfill.h_Data = compdata;
899         compdata->backfillhook = &compdata->defaultbackfill;
900
901         InitSemaphore(&compdata->semaphore);
902
903         compdata->gfx = (OOP_Object *)GetTagData(aHidd_Compositor_GfxHidd, 0, msg->attrList);
904         compdata->fb  = (OOP_Object *)GetTagData(aHidd_Compositor_FrameBuffer, 0, msg->attrList);
905
906         compdata->GraphicsBase = OpenLibrary("graphics.library", 41);
907
908         /* GfxHidd is mandatory */
909         if ((compdata->GraphicsBase) && (compdata->gfx != NULL))
910         {
911             /* Create GC object that will be used for drawing operations */
912             compdata->gc = HIDD_Gfx_NewGC(compdata->gfx, NULL);
913
914             D(bug("[%s] Compositor GC @ %p\n", __PRETTY_FUNCTION__, compdata->gc));
915
916             if ((compdata->gfx) && (compdata->gc))
917                 return o;
918         }
919
920         /* Creation failed */
921         disposemid = OOP_GetMethodID(IID_Root, moRoot_Dispose);
922         OOP_CoerceMethod(cl, o, &disposemid);
923     }
924
925     return NULL;
926 }
927
928 void METHOD(Compositor, Root, Dispose)
929 {
930
931     D(
932         struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
933         bug("[%s] HIDDCompositorData @ 0x%p\n", __PRETTY_FUNCTION__, compdata);
934       )
935
936     OOP_DoSuperMethod(cl, o, &msg->mID);
937 }
938
939 VOID METHOD(Compositor, Root, Get)
940 {
941     ULONG idx;
942
943     struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
944
945     if (IS_COMPOSITOR_ATTR(msg->attrID, idx))
946     {
947         switch (idx)
948         {
949             case aoHidd_Compositor_Capabilities:
950             {
951                 D(bug("[%s] Composite Capabilities: %lx\n", __PRETTY_FUNCTION__, compdata->capabilities));
952                 *msg->storage = (IPTR)COMPF_ABOVE|COMPF_BELOW|COMPF_LEFT|COMPF_RIGHT;
953                 return;
954             }
955             case aoHidd_Compositor_BackFillHook:
956             {
957                 D(bug("[%s] BackFillHook: 0x%p\n", __PRETTY_FUNCTION__, compdata->backfillhook));
958                 *msg->storage = (IPTR)compdata->backfillhook;
959                 return;
960             }
961         }
962     }
963     OOP_DoSuperMethod(cl, o, &msg->mID);
964 }
965
966 VOID METHOD(Compositor, Root, Set)
967 {
968     ULONG idx;
969
970     struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
971     struct TagItem *tag, *tstate = msg->attrList;
972
973     while ((tag = NextTagItem(&tstate)))
974     {
975         if (IS_COMPOSITOR_ATTR(tag->ti_Tag, idx))
976         {
977             switch (idx)
978             {
979                 case aoHidd_Compositor_Capabilities:
980                 {
981                     D(bug("[%s] Composite Capabilities: %lx -> %lx\n", __PRETTY_FUNCTION__, compdata->capabilities, tag->ti_Data));
982                     compdata->capabilities = (ULONG)tag->ti_Data;
983                     break;
984                 }
985                 case aoHidd_Compositor_BackFillHook:
986                 {
987                     if (tag->ti_Data)
988                     {
989                         D(bug("[%s] BackFillHook: 0x%p -> 0x%p\n", __PRETTY_FUNCTION__, compdata->backfillhook, tag->ti_Data));
990                         compdata->backfillhook = (struct Hook *)tag->ti_Data;
991                     }
992                     else
993                     {
994                         D(bug("[%s] Default BackFillHook\n", __PRETTY_FUNCTION__));
995                         compdata->backfillhook = &compdata->defaultbackfill;
996                     }
997                     break;
998                 }
999             }
1000         }
1001     }
1002
1003     OOP_DoSuperMethod(cl, o, &msg->mID);
1004 }
1005
1006 OOP_Object *METHOD(Compositor, Hidd_Compositor, BitMapStackChanged)
1007 {
1008     struct HIDD_ViewPortData *vpdata;
1009     struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
1010     struct StackBitMapNode *n;
1011     BOOL newtop = FALSE;
1012     BOOL ok = TRUE;
1013
1014     DSTACK(bug("[%s] Top bitmap: 0x%lx\n", __PRETTY_FUNCTION__, msg->data->Bitmap));
1015
1016     LOCK_COMPOSITOR_WRITE
1017
1018     /* Free all items which are already on the list */
1019     HIDDCompositorPurgeBitMapStack(compdata);
1020
1021     if (!msg->data)
1022     {
1023         UNLOCK_COMPOSITOR
1024
1025         /* Blank screen */
1026         HIDDCompositorShowSingle(compdata, NULL);
1027
1028         /* We know we are inactive after this */
1029         *msg->active = FALSE;
1030         /* This can return NULL, it's okay */
1031         return compdata->screenbitmap;
1032     }
1033
1034     /* Copy bitmaps pointers to our stack */
1035     for (vpdata = msg->data; vpdata; vpdata = vpdata->Next)
1036     {
1037         n = AllocMem(sizeof(struct StackBitMapNode), MEMF_ANY | MEMF_CLEAR);
1038         if (!n)
1039         {
1040             /*
1041              * Error happened.
1042              * We need to reset own state and return NULL. graphics.library
1043              * falls back to no composition in this case.
1044              */
1045             DSTACK(bug("[%s] Error allocating StackBitMapNode!!!\n", __PRETTY_FUNCTION__));
1046
1047             ok = FALSE;
1048             break;
1049         }
1050
1051         DSTACK(bug("[%s] ViewPort 0x%p, offset (%d, %d)\n", __PRETTY_FUNCTION__, vpdata->vpe->ViewPort, vpdata->vpe->ViewPort->DxOffset, vpdata->vpe->ViewPort->DyOffset));
1052
1053         n->bm                   = vpdata->Bitmap;
1054         n->sbmflags             = 0;
1055         n->leftedge             = vpdata->vpe->ViewPort->DxOffset;
1056         n->topedge              = vpdata->vpe->ViewPort->DyOffset;
1057
1058         AddTail((struct List *)&compdata->bitmapstack, (struct Node *)n);
1059     }
1060
1061     /* Switch mode if needed */
1062     UpdateDisplayMode(compdata);
1063
1064     if (msg->data->Bitmap != compdata->topbitmap)
1065     {
1066         /* Set the new pointer to top bitmap */
1067         compdata->topbitmap = msg->data->Bitmap;
1068         newtop = TRUE;
1069     }
1070
1071     if (ok)
1072     {
1073         /*
1074          * Validate bitmap offsets - they might not match the compositing rules taking
1075          * new displayedwidth/displayedheight values
1076          */
1077         ForeachNode(&compdata->bitmapstack, n)
1078         {
1079             HIDDCompositorValidateBitMapPositionChange(n->bm, &n->leftedge, &n->topedge, 
1080                                                         compdata->screenrect.MaxX + 1, compdata->screenrect.MaxY + 1);
1081             DSTACK(bug("[%s] Bitmap 0x%p, display size %d x %d, validated position (%ld, %ld)\n", __PRETTY_FUNCTION__,
1082                        n->bm, compdata->screenrect.MaxX + 1, compdata->screenrect.MaxY + 1,
1083                        n->leftedge, n->topedge));
1084         }
1085
1086         /* Toogle compositing based on screen positions */
1087         ok = HIDDCompositorToggleCompositing(compdata, newtop);
1088     }
1089
1090     /* Handle error */
1091     if (!ok)
1092     {
1093         HIDDCompositorReset(compdata);
1094         HIDDCompositorShowSingle(compdata, msg->data->Bitmap);
1095     }
1096
1097     UNLOCK_COMPOSITOR
1098
1099     DSTACK(bug("[%s] Done, composited bitmap 0x%p\n", __PRETTY_FUNCTION__, compdata->compositedbitmap));
1100
1101     /* Tell if the composition is active */
1102     *msg->active = compdata->compositedbitmap ? TRUE : FALSE;
1103     /* Return actually displayed bitmap */
1104     return compdata->screenbitmap;
1105 }
1106
1107 VOID METHOD(Compositor, Hidd_Compositor, BitMapRectChanged)
1108 {
1109     struct HIDDCompositorData * compdata = OOP_INST_DATA(cl, o);
1110
1111     if (compdata->compositedbitmap)
1112     {
1113         /* Composition is active, handle redraw if the bitmap is on screen */
1114         struct StackBitMapNode *n;
1115
1116         DUPDATE(bug("[%s] Bitmap 0x%p\n", __PRETTY_FUNCTION__, msg->bm));
1117
1118         LOCK_COMPOSITOR_READ
1119
1120         n = HIDDCompositorIsBitMapOnStack(compdata, msg->bm);
1121         if (n && (n->sbmflags & STACKNODE_VISIBLE))
1122         {
1123             struct Rectangle srcrect, dstandvisrect;
1124
1125             srcrect.MinX = n->leftedge + msg->x;
1126             srcrect.MinY = n->topedge + msg->y;
1127             srcrect.MaxX = n->leftedge + msg->x + msg->width - 1; 
1128             srcrect.MaxY = n->topedge + msg->y + msg->height - 1;
1129             DUPDATE(bug("[%s] Bitmap rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, msg->x, msg->y, msg->x + msg->width - 1, msg->y + msg->height - 1));
1130
1131             DUPDATE(bug("[%s] Screen-relative rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(srcrect)));
1132
1133             struct RegionRectangle * srrect = n->screenregion->RegionRectangle;
1134             while (srrect)
1135             {
1136                 dstandvisrect.MinX = srrect->bounds.MinX + n->screenregion->bounds.MinX;
1137                 dstandvisrect.MinY = srrect->bounds.MinY + n->screenregion->bounds.MinY;
1138                 dstandvisrect.MaxX = srrect->bounds.MaxX + n->screenregion->bounds.MinX;
1139                 dstandvisrect.MaxY = srrect->bounds.MaxY + n->screenregion->bounds.MinY;
1140
1141                 if (AndRectRect(&srcrect, &dstandvisrect, &dstandvisrect))
1142                 {
1143                     /* Intersection is valid. Blit. */
1144                     DUPDATE(bug("[%s] Clipped rect (%d, %d) - (%d, %d)\n", __PRETTY_FUNCTION__, _RECT(dstandvisrect)));
1145
1146                     HIDDCompositorRedrawBitmap(compdata, n, &dstandvisrect);
1147
1148                     HIDD_BM_UpdateRect(compdata->compositedbitmap,
1149                                        dstandvisrect.MinX, dstandvisrect.MinY,
1150                                        dstandvisrect.MaxX - dstandvisrect.MinX + 1,
1151                                        dstandvisrect.MaxY - dstandvisrect.MinY + 1);
1152                 }
1153                 srrect = srrect->Next;
1154             }
1155         }
1156
1157         UNLOCK_COMPOSITOR
1158         
1159         DUPDATE(bug("[%s] Done\n", __PRETTY_FUNCTION__));
1160     }
1161     else
1162     {
1163         /*
1164          * In order to speed things up, we handle passthrough ourselves here.
1165          * It's not difficult.
1166          */
1167         HIDD_BM_UpdateRect(msg->bm, msg->x, msg->y, msg->width, msg->height);
1168     }
1169 }
1170
1171 IPTR METHOD(Compositor, Hidd_Compositor, BitMapPositionChange)
1172 {
1173     struct HIDDCompositorData *compdata = OOP_INST_DATA(cl, o);
1174     struct StackBitMapNode *n;
1175     IPTR disp_width, disp_height;
1176
1177     LOCK_COMPOSITOR_READ
1178
1179     n = HIDDCompositorIsBitMapOnStack(compdata, msg->bm);
1180     if (n)
1181     {
1182         /* The bitmap is on display. Validate against screen size */
1183         disp_width  = compdata->screenrect.MaxX + 1;
1184         disp_height = compdata->screenrect.MaxY + 1;
1185     }
1186     else
1187     {
1188         /* The bitmap is not displayed yet. Validate against its own ModeID size. */
1189         HIDDT_ModeID modeid = vHidd_ModeID_Invalid;
1190         OOP_Object *sync, *pf;
1191
1192         OOP_GetAttr(msg->bm, aHidd_BitMap_ModeID, &modeid);
1193
1194         if (modeid == vHidd_ModeID_Invalid)
1195         {
1196             /*
1197              * Nondisplayable bitmaps don't scroll.
1198              * In fact they simply can't get in here because MakeVPort() performs the validation.
1199              * But who knows what bug can slip into someone's software...
1200              */
1201             UNLOCK_COMPOSITOR
1202             return FALSE;
1203         }
1204
1205         HIDD_Gfx_GetMode(compdata->gfx, modeid, &sync, &pf);
1206         OOP_GetAttr(sync, aHidd_Sync_HDisp, &disp_width);
1207         OOP_GetAttr(sync, aHidd_Sync_VDisp, &disp_height);
1208     }
1209
1210     DMOVE(bug("[%s] Validating bitmap 0x%p, position (%ld, %ld), limits %ld x %ld\n", __PRETTY_FUNCTION__,
1211           msg->bm, *msg->newxoffset, *msg->newyoffset, disp_width, disp_height));
1212
1213     HIDDCompositorValidateBitMapPositionChange(msg->bm, msg->newxoffset, msg->newyoffset,
1214                                                 disp_width, disp_height);
1215
1216     DMOVE(bug("[%s] Validated position (%ld, %ld)\n", __PRETTY_FUNCTION__, *msg->newxoffset, *msg->newyoffset));
1217
1218     if (n && ((*msg->newxoffset != n->leftedge) || (*msg->newyoffset != n->topedge)))
1219     {
1220         DMOVE(bug("[%s] Old position (%ld, %ld)\n", __PRETTY_FUNCTION__, n->leftedge, n->topedge));
1221
1222         /* Reflect the change if it happened */
1223         n->leftedge = *msg->newxoffset;
1224         n->topedge  = *msg->newyoffset;
1225
1226         if (compdata->topbitmap == msg->bm)
1227         {
1228             /*
1229              * If this is the frontmost bitmap, we may want to toggle compositing,
1230              * if it starts/stops covering the whole screen at one point.
1231              * We don't need to call HIDDCompositorRedrawVisibleDisplay() here because
1232              * HIDDCompositorToggleCompositing() does this itself, for improved
1233              * visual appearance.
1234              */
1235             HIDDCompositorToggleCompositing(compdata, FALSE);    
1236         }
1237         else
1238             HIDDCompositorRedrawVisibleDisplay(compdata);
1239     }
1240
1241     UNLOCK_COMPOSITOR
1242
1243     /* Return active state */
1244     return compdata->compositedbitmap ? TRUE : FALSE;
1245 }
1246
1247 #define NUM_Compositor_Root_METHODS 4
1248
1249 static const struct OOP_MethodDescr Compositor_Root_descr[] =
1250 {
1251     {(OOP_MethodFunc)Compositor__Root__New, moRoot_New},
1252     {(OOP_MethodFunc)Compositor__Root__Dispose, moRoot_Dispose},
1253     {(OOP_MethodFunc)Compositor__Root__Get, moRoot_Get},
1254     {(OOP_MethodFunc)Compositor__Root__Set, moRoot_Set},
1255     {NULL, 0}
1256 };
1257
1258 #define NUM_Compositor_Hidd_Compositor_METHODS 3
1259
1260 static const struct OOP_MethodDescr Compositor_Hidd_Compositor_descr[] =
1261 {
1262     {(OOP_MethodFunc)Compositor__Hidd_Compositor__BitMapStackChanged, moHidd_Compositor_BitMapStackChanged},
1263     {(OOP_MethodFunc)Compositor__Hidd_Compositor__BitMapRectChanged, moHidd_Compositor_BitMapRectChanged},
1264     {(OOP_MethodFunc)Compositor__Hidd_Compositor__BitMapPositionChange, moHidd_Compositor_BitMapPositionChange},
1265     {NULL, 0}
1266 };
1267
1268 const struct OOP_InterfaceDescr Compositor_ifdescr[] =
1269 {
1270     {Compositor_Root_descr, IID_Root, NUM_Compositor_Root_METHODS},
1271     {Compositor_Hidd_Compositor_descr, IID_Hidd_Compositor, NUM_Compositor_Hidd_Compositor_METHODS},
1272     {NULL, NULL}
1273 };