home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / liblayer / src / cl_comp.c next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  83.7 KB  |  2,450 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /* 
  19.  *  cl_comp.c - The compositor API
  20.  */
  21.  
  22.  
  23. /* On UNIX, child and sibling windows are always clipped, so
  24.    cutout layers are unnecessary. */
  25. #ifdef XP_UNIX
  26. #    define TRIM_UPDATE_REGION_CUTOUTS PR_FALSE
  27. #else
  28. #    define TRIM_UPDATE_REGION_CUTOUTS PR_TRUE
  29. #endif
  30.  
  31. #include "prtypes.h"
  32. #ifdef XP_MAC
  33. #include "prpriv.h"
  34. #else
  35. #include "private/prpriv.h" /* For PR_NewNamedMonitor */
  36. #endif
  37.  
  38. #include "xp_core.h"
  39. #include "xpassert.h"
  40. #include "fe_proto.h"        /* For FE_SetTimeout(), et al */
  41. #include "layers.h"
  42. #include "cl_priv.h"
  43. #ifdef CL_ADAPT_FRAME_RATE
  44. #    include "prtime.h"
  45. #endif
  46.  
  47. #ifndef ABS
  48. #    define ABS(x)  (((x) < 0) ? -(x) : (x))
  49. #endif
  50.  
  51. static void
  52. cl_compute_update_region(CL_Compositor *compositor);
  53.  
  54. static PRBool
  55. cl_composite(CL_Compositor *compositor, PRBool cutoutp);
  56.  
  57. int cl_trace_level = 0;
  58.  
  59. #if !defined(XP_MAC) && defined(DEBUG) /* FE_HighlightRegion is not currently in the mac build */
  60. void
  61. CL_HighlightRegion(CL_Compositor *compositor, FE_Region region)
  62. {
  63.     extern MWContext *LO_CompositorToContext(CL_Compositor *compositor);
  64.  
  65.     int time;
  66.     MWContext *context = LO_CompositorToContext(compositor);
  67.  
  68.     time = 200;
  69. #if defined(XP_UNIX)
  70.     if (getenv("SHOWREGIONS"))
  71.         time = atoi(getenv("SHOWREGIONS"));
  72. #endif
  73.  
  74.     FE_HighlightRegion(context, region, time);
  75. }
  76. #endif
  77.  
  78. /* Allocate and initialize a new compositor */
  79. CL_Compositor *
  80. CL_NewCompositor(CL_Drawable *primary_drawable,
  81.                  CL_Drawable *backing_store,
  82.                  int32 x_offset, int32 y_offset,
  83.                  int32 width, int32 height,
  84.                  uint32 frame_rate)
  85. {
  86.     CL_Compositor *compositor;
  87.  
  88.     compositor = XP_NEW_ZAP(CL_Compositor);
  89.  
  90.     if (compositor == NULL)
  91.         return NULL;
  92.  
  93.     CL_TRACE(0, ("Creating new compositor: %x", compositor));
  94.  
  95. #ifdef CL_THREAD_SAFE
  96.     compositor->monitor = PR_NewNamedMonitor("compositor-monitor");
  97.     if (!compositor->monitor)
  98.         return NULL;
  99. #endif
  100.  
  101.     compositor->gen_id = 0;
  102.     compositor->primary_drawable = primary_drawable;
  103.     compositor->backing_store = backing_store;
  104.     compositor->x_offset = x_offset;
  105.     compositor->y_offset = y_offset;
  106.     compositor->window_size.left = compositor->window_size.top = 0;
  107.     compositor->window_size.right = width;
  108.     compositor->window_size.bottom = height;
  109.     if (frame_rate)
  110.         compositor->frame_period = 1000000.0F / frame_rate;
  111.     else
  112.         compositor->frame_period = 0.0F;
  113.  
  114.     compositor->window_region = FE_CreateRectRegion(&compositor->window_size);
  115.     compositor->update_region = FE_CreateRegion();
  116.  
  117.     compositor->event_containment_lists[0].layer_list = 
  118.         XP_ALLOC(CL_CONTAINMENT_LIST_SIZE * sizeof(CL_Layer *));
  119.     compositor->event_containment_lists[0].list_size = 
  120.         CL_CONTAINMENT_LIST_SIZE;
  121.     compositor->event_containment_lists[0].list_head = -1;
  122.     compositor->event_containment_lists[1].layer_list = 
  123.         XP_ALLOC(CL_CONTAINMENT_LIST_SIZE * sizeof(CL_Layer *));
  124.     compositor->event_containment_lists[1].list_size = 
  125.         CL_CONTAINMENT_LIST_SIZE;
  126.     compositor->event_containment_lists[1].list_head = -1;
  127.  
  128.     compositor->backing_store_region = FE_CreateRegion();
  129.     if ((compositor->window_region == NULL) ||
  130.         (compositor->update_region == NULL) ||
  131.         (compositor->backing_store_region == NULL) ||
  132.         (compositor->event_containment_lists[0].layer_list == NULL) ||
  133.         (compositor->event_containment_lists[1].layer_list == NULL)) {
  134.         CL_DestroyCompositor(compositor);
  135.         return NULL;
  136.     }
  137.     compositor->offscreen_enabled = PR_FALSE;
  138.     compositor->back_to_front_only = PR_FALSE;
  139.  
  140.     compositor->mouse_event_grabber = NULL;
  141.     compositor->key_event_grabber = NULL;
  142.     compositor->last_mouse_event_grabber = NULL;
  143.     compositor->focus_policy = CL_FOCUS_POLICY_CLICK;
  144.  
  145.     primary_drawable->compositor = compositor;
  146.     if (backing_store)
  147.         backing_store->compositor = compositor;
  148.  
  149.     cl_InitDrawable(compositor->primary_drawable);
  150.  
  151.     return compositor;
  152. }
  153.  
  154. static int
  155. cl_group_list_destroy(PRHashEntry *he,
  156.                       int i,
  157.                       void *arg)
  158. {
  159.     XP_List *list = (XP_List *)he->value;
  160.     
  161.     XP_ListDestroy(list);
  162.     
  163.     return HT_ENUMERATE_REMOVE;
  164. }
  165.  
  166.  
  167. /* Free an existing compositor */
  168. void 
  169. CL_DestroyCompositor(CL_Compositor *compositor)
  170. {
  171.     XP_ASSERT(compositor);
  172.  
  173.     if (!compositor)
  174.         return;
  175.  
  176.     CL_TRACE(0, ("Destroying compositor: %x", compositor));
  177.  
  178.     if (compositor->composite_timeout)
  179.         FE_ClearTimeout(compositor->composite_timeout);
  180.  
  181.     if (compositor->root)
  182.         CL_DestroyLayerTree(compositor->root);
  183.  
  184.     if (compositor->window_region)
  185.         FE_DestroyRegion(compositor->window_region);
  186.   
  187.     if (compositor->update_region)
  188.         FE_DestroyRegion(compositor->update_region);
  189.  
  190.     if (compositor->backing_store_region)
  191.         FE_DestroyRegion(compositor->backing_store_region);
  192.  
  193.     if (compositor->group_table) {
  194.         /* Delete all the group lists in the table */
  195.         PR_HashTableEnumerateEntries(compositor->group_table,
  196.                                      cl_group_list_destroy,
  197.                                      NULL);
  198.         PR_HashTableDestroy(compositor->group_table);
  199.     }
  200.  
  201.     if (compositor->primary_drawable) {
  202.         cl_RelinquishDrawable(compositor->primary_drawable);
  203.         CL_DestroyDrawable(compositor->primary_drawable);
  204.     }
  205.  
  206.     if (compositor->backing_store) {
  207.         if (compositor->offscreen_initialized)
  208.             cl_RelinquishDrawable(compositor->backing_store);
  209.         CL_DestroyDrawable(compositor->backing_store);
  210.     }
  211.  
  212.     if (compositor->event_containment_lists[0].layer_list)
  213.         XP_FREE(compositor->event_containment_lists[0].layer_list);
  214.  
  215.     if (compositor->event_containment_lists[1].layer_list)
  216.         XP_FREE(compositor->event_containment_lists[1].layer_list);
  217.     
  218. #ifdef CL_THREAD_SAFE
  219.     if (compositor->monitor)
  220.         PR_DestroyMonitor(compositor->monitor);
  221. #endif
  222.   
  223.     XP_FREE(compositor);
  224. }
  225.  
  226. void
  227. CL_IncrementCompositorGeneration(CL_Compositor *compositor)
  228. {
  229.     XP_ASSERT(compositor);
  230.     
  231.     if (!compositor)
  232.         return;
  233.     
  234.     compositor->gen_id++;
  235. }
  236.  
  237. /* Find layer by name. This carries out a breadth-first search */
  238. /* of the layer tree. Returns NULL if no such layer exists.    */
  239. CL_Layer *
  240. CL_FindLayer(CL_Compositor *compositor, char *name)
  241. {
  242.     XP_List *list;
  243.     CL_Layer *layer, *child;
  244.  
  245.     XP_ASSERT(compositor);
  246.     XP_ASSERT(name);
  247.  
  248.     if (!compositor || !name || !compositor->root)
  249.         return NULL;
  250.  
  251.     /* BUGBUG This is rather an expensive way to maintain a list */
  252.     /* since a little struct is allocated for each element added */
  253.     /* to the list.                                              */
  254.     list = XP_ListNew();
  255.  
  256.     if (list == NULL)
  257.         return NULL;
  258.  
  259.     LOCK_COMPOSITOR(compositor);
  260.   
  261.     XP_ListAddObject(list, compositor->root);
  262.  
  263.     /* While the list is not empty */
  264.     while ((layer = XP_ListRemoveTopObject(list))) {
  265.     
  266.         /* Check if the name of this layer matches */
  267.         if (layer->name && strcmp(layer->name, name) == 0) {
  268.             XP_ListDestroy(list);
  269.             UNLOCK_COMPOSITOR(compositor);
  270.             return layer;
  271.         }
  272.     
  273.         /* Add each of the children to the end of the list */
  274.         for (child = layer->top_child; child; child = child->sib_below)
  275.             XP_ListAddObjectToEnd(list, child);
  276.     }
  277.  
  278.     XP_ListDestroy(list);
  279.     UNLOCK_COMPOSITOR(compositor);
  280.     return NULL;
  281. }
  282.  
  283. static void
  284. cl_refresh_window_region_common(CL_Compositor *compositor, 
  285.                                 FE_Region refresh_region,
  286.                                 PRBool copy_region)
  287. {
  288.     FE_Region draw_region, save_update_region, copy_refresh_region;
  289.     CL_Drawable *backing_store;
  290.     PRBool save_offscreen_inhibited;
  291.     
  292.     XP_ASSERT(compositor);
  293.     XP_ASSERT(refresh_region);
  294.  
  295.     if (!compositor || !refresh_region)
  296.         return;
  297.     
  298.     CL_TRACE(0, ("Refreshing window region"));
  299.  
  300.     LOCK_COMPOSITOR(compositor);
  301.  
  302. #if 0
  303.     /* Subtract out the cutout layers, since they are out-of-bounds
  304.        for compositor drawing. */
  305.     if (compositor->enabled) {
  306.     cl_prepare_to_draw(compositor, refresh_region, PR_FALSE);
  307.     }
  308. #endif
  309.  
  310. /*    if (compositor->root)
  311.         CL_HighlightRegion(compositor, refresh_region);*/
  312.  
  313.     if (compositor->enabled)
  314.         cl_compute_update_region(compositor);
  315.  
  316.    /* Invalidate any parts of the backing store for which there are
  317.        update requests. */
  318.     FE_SubtractRegion(compositor->backing_store_region,
  319.                       compositor->update_region,
  320.                       compositor->backing_store_region);
  321.  
  322.     /* Figure out what part of the refresh region has already been
  323.        composited into the backing store and blit that onto the
  324.        primary drawable. */
  325.     if (compositor->backing_store) {
  326.         backing_store = cl_LockDrawableForRead(compositor->backing_store);
  327.         if (backing_store) {
  328.             draw_region = FE_CreateRegion();
  329.             if (! draw_region) {
  330.                 UNLOCK_COMPOSITOR(compositor);
  331.                 return;
  332.             }
  333.             
  334.             FE_IntersectRegion(compositor->backing_store_region, refresh_region, draw_region);
  335.             cl_CopyPixels(backing_store, compositor->primary_drawable,
  336.                           draw_region);
  337.             FE_SubtractRegion(refresh_region, draw_region, refresh_region);
  338.             FE_DestroyRegion(draw_region);
  339.             cl_UnlockDrawable(backing_store);
  340.         }
  341.     }
  342.  
  343.     if (compositor->enabled) {
  344.         /* Save out the current update region, since we only want to draw
  345.            the area that we got a refresh request for.  We can't simply
  346.            subtract out the refresh area from the update area because
  347.            of Windows' behavior: In between the BeginPaint() and EndPaint()
  348.            calls, the clip is constrained to be that of the OS's update
  349.            region intersected with the clip that we set.  But, we don't know
  350.            what the resulting cascaded clip. */
  351.         save_update_region = compositor->update_region;
  352.  
  353.         /* We might have to copy the refresh region, since compositing will
  354.            modify it. */
  355.         if (copy_region) {
  356.             copy_refresh_region = FE_CreateRegion();
  357.             FE_CopyRegion(refresh_region, copy_refresh_region);
  358.             compositor->update_region = copy_refresh_region;
  359.         }
  360.         else
  361.             compositor->update_region = refresh_region;
  362.  
  363.         /* Subtract out the area that isn't in the composited region */
  364.         FE_IntersectRegion(compositor->window_region, 
  365.                            compositor->update_region,
  366.                            compositor->update_region);
  367.  
  368.         /* For speedier scrolling and exposures, we always composite
  369.            on-screen for refresh. */
  370.         save_offscreen_inhibited = compositor->offscreen_inhibited;
  371.         compositor->offscreen_inhibited = PR_TRUE;
  372.  
  373.         /* 
  374.          * Note that we don't subtract out the cutout region when we're
  375.          * going through this entry point, since it can be a performance
  376.          * hog, especially if we're scrolling. This works for Windows and
  377.          * X, but I'm not sure it will work across platforms.
  378.          */
  379.         cl_composite(compositor, PR_FALSE);
  380.         compositor->offscreen_inhibited = save_offscreen_inhibited;
  381.  
  382.         /* 
  383.          * If a layer has changed during the compositing, the update
  384.          * region will reflect the changes and will need to be dealt
  385.          * with in the next compositing pass. Copy it back into the
  386.          * saved update region.
  387.          */
  388.         FE_UnionRegion(save_update_region, compositor->update_region,
  389.                        save_update_region);
  390.  
  391.         if (copy_region)
  392.             FE_DestroyRegion(copy_refresh_region);
  393.  
  394.         compositor->update_region = save_update_region;
  395.     }
  396.     else
  397.         FE_UnionRegion(compositor->update_region, refresh_region,
  398.                        compositor->update_region);
  399.  
  400.     UNLOCK_COMPOSITOR(compositor);
  401. }
  402.  
  403.  
  404. /*
  405.  * Inform the compositor that some part of the window needs to be
  406.  * refreshed, e.g. in response to a window expose event.  The region
  407.  * to be refreshed is expressed in window coordinates.
  408.  */
  409. void
  410. CL_RefreshWindowRegion(CL_Compositor *compositor, FE_Region refresh_region)
  411. {
  412.     cl_refresh_window_region_common(compositor, refresh_region, PR_TRUE);
  413. }
  414.  
  415. /*
  416.  * Inform the compositor that some part of the window needs to be
  417.  * refreshed, e.g. in response to a window expose event.  The region
  418.  * to be refreshed is expressed in window coordinates.
  419.  */
  420. void
  421. CL_RefreshWindowRect(CL_Compositor *compositor, XP_Rect *refresh_rect)
  422. {
  423.     FE_Region refresh_region = FE_CreateRectRegion(refresh_rect);
  424.  
  425.     if (! refresh_region)       /* OOM */
  426.         return;
  427.     
  428.     cl_refresh_window_region_common(compositor, refresh_region, PR_FALSE);
  429.     FE_DestroyRegion(refresh_region);
  430. }
  431.  
  432. /*
  433.  * Inform the compositor that some part of a layer has changed and
  434.  * needs to be redrawn. The region to be updated is expressed in the
  435.  * layer's coordinate system. For efficiency, only the part of the
  436.  * passed in region that is not clipped by ancestor layers is actually
  437.  * updated.  If update_now is PR_TRUE, the composite is done
  438.  * synchronously. Otherwise, it is done at the next timer callback.
  439.  */
  440. void 
  441. CL_UpdateLayerRegion(CL_Compositor *compositor, CL_Layer *layer,
  442.                      FE_Region layer_region, PRBool update_now)
  443. {
  444.     int32 x_offset, y_offset;
  445.     XP_Rect win_clipped_bbox;
  446.     FE_Region update_region, win_clipped_bbox_region;
  447.     
  448.     XP_ASSERT(compositor);
  449.     XP_ASSERT(layer);
  450.     XP_ASSERT(layer_region);
  451.  
  452.     if (!compositor || !layer || !layer_region)
  453.         return;
  454.  
  455.     /* Oddball predicate below is used to combat the case where the
  456.        layer was made invisible, updated and made visible again, all
  457.        between two composite cycles.  In that case, we still want
  458.        to repaint the composited area. */
  459.     if (!layer->prev_visible && !layer->visible)
  460.         return;
  461.  
  462.     CL_TRACE(0, ("Updating layer region"));
  463.  
  464.     LOCK_COMPOSITOR(compositor);
  465.  
  466.     /* Compute offsets to convert layer coordinates to window coordinates */
  467.     x_offset = layer->x_origin - compositor->x_offset;
  468.     y_offset = layer->y_origin - compositor->y_offset;
  469.     
  470.     /* 
  471.      * If the offsets are outside the coordinate range we can express
  472.      * for regions, we can assume that the region to be updated is
  473.      * outside the window rectangle.
  474.      */
  475.     if ((ABS(x_offset) > FE_MAX_REGION_COORDINATE) ||
  476.         (ABS(y_offset) > FE_MAX_REGION_COORDINATE)) {
  477.         UNLOCK_COMPOSITOR(compositor);
  478.         return;
  479.     }
  480.     
  481.     /* Convert input region from layer coordinates into window coordinates */
  482.     update_region = FE_CreateRegion();
  483.     
  484.     XP_ASSERT(update_region);
  485.     if (! update_region) {
  486.         UNLOCK_COMPOSITOR(compositor);
  487.         return;
  488.     }
  489.     
  490.     FE_CopyRegion(layer_region, update_region);
  491.     FE_OffsetRegion(update_region, x_offset, y_offset);
  492.  
  493.     /* Convert clipping bbox of layer from document coordinates to
  494.        window coordinates and clip to window bounds. */
  495.     XP_CopyRect(&layer->clipped_bbox, &win_clipped_bbox);
  496.     XP_OffsetRect(&win_clipped_bbox,
  497.                   -compositor->x_offset, -compositor->y_offset);
  498.     XP_IntersectRect(&compositor->window_size,
  499.                      &win_clipped_bbox, 
  500.                      &win_clipped_bbox);
  501.  
  502.     /* Make the clipping bbox into a region, so we can do intersection */
  503.     win_clipped_bbox_region = FE_CreateRectRegion(&win_clipped_bbox);
  504.     XP_ASSERT(win_clipped_bbox_region);
  505.     if (! win_clipped_bbox_region) {
  506.         FE_DestroyRegion(update_region);
  507.         UNLOCK_COMPOSITOR(compositor);
  508.         return;
  509.     }
  510.  
  511.     /* Subtract out the area that isn't visible in the layer */
  512.     FE_IntersectRegion(win_clipped_bbox_region, update_region, update_region);
  513.     FE_DestroyRegion(win_clipped_bbox_region);
  514.  
  515.     if (FE_IsEmptyRegion(update_region)) {
  516.         FE_DestroyRegion(update_region);
  517.         UNLOCK_COMPOSITOR(compositor);
  518.         return;
  519.     }
  520.     
  521.     /* Add the altered region to the region to update at the next composite */
  522.     FE_UnionRegion(compositor->update_region, update_region, 
  523.                    compositor->update_region);
  524.  
  525.     FE_DestroyRegion(update_region);
  526.  
  527.     if (compositor->enabled) {
  528.         if (update_now)
  529.             cl_composite(compositor, TRIM_UPDATE_REGION_CUTOUTS);
  530.         else
  531.             cl_start_compositor_timeouts(compositor);
  532.     }
  533.     UNLOCK_COMPOSITOR(compositor);
  534. }
  535.  
  536. /*
  537.  * Inform the compositor that some rectangular part of a layer has
  538.  * changed and needs to be redrawn. The region to be updated is
  539.  * expressed in the layer's coordinate system. For efficiency, only
  540.  * the part of the passed in region that is not clipped by ancestor
  541.  * layers is actually updated.  If update_now is PR_TRUE, the
  542.  * composite is done synchronously. Otherwise, it is done at the next
  543.  * timer callback.
  544.  */
  545. void
  546. CL_UpdateLayerRect(CL_Compositor *compositor, CL_Layer *layer,
  547.                    XP_Rect *layer_rect, PRBool composite_now)
  548. {
  549.     int32 x_offset, y_offset;
  550.     XP_Rect update_rect;
  551.  
  552.     XP_ASSERT(compositor);
  553.     XP_ASSERT(layer);
  554.     XP_ASSERT(layer_rect);
  555.  
  556.     if (!compositor || !layer || !layer_rect)
  557.         return;
  558.  
  559.     /* Oddball predicate below is used to combat the case where the
  560.        layer was made invisible, updated and made visible again, all
  561.        between two composite cycles.  In that case, we still want
  562.        to repaint the composited area. */
  563.     if (!layer->prev_visible && !layer->visible)
  564.         return;
  565.  
  566.     CL_TRACE(0, ("Updating layer rect"));
  567.  
  568.     XP_CopyRect(layer_rect, &update_rect);
  569.     
  570.     LOCK_COMPOSITOR(compositor);
  571.     
  572.     /* Compute offsets to convert layer coordinates to document coordinates */
  573.     x_offset = layer->x_origin;
  574.     y_offset = layer->y_origin;
  575.  
  576.     /* Convert the update_rect into document coordinates */
  577.     XP_OffsetRect(&update_rect, x_offset, y_offset);
  578.     
  579.     /* Don't update parts of the layer that are clipped by ancestor layers. */
  580.     XP_IntersectRect(&update_rect, &layer->clipped_bbox, &update_rect);
  581.  
  582.     CL_UpdateDocumentRect(compositor, &update_rect, composite_now);
  583.  
  584.     UNLOCK_COMPOSITOR(compositor);
  585. }
  586.  
  587. /*
  588.  * Inform the compositor that some rectangular part of a document has
  589.  * changed and needs to be redrawn. The region to be updated is
  590.  * expressed in the document's coordinate system.  If update_now is
  591.  * PR_TRUE, the composite is done synchronously. Otherwise, it is done
  592.  * at the next timer callback.
  593.  */
  594. void
  595. CL_UpdateDocumentRect(CL_Compositor *compositor,
  596.                       XP_Rect *doc_rect, PRBool update_now)
  597. {
  598.     int32 x_offset, y_offset;
  599.     XP_Rect update_rect;
  600.     FE_Region update_region;
  601.     
  602.     XP_ASSERT(compositor);
  603.     XP_ASSERT(doc_rect);
  604.  
  605.     if (!compositor || !doc_rect)
  606.         return;
  607.     
  608.     CL_TRACE(0, ("Updating document rect"));
  609.  
  610.     XP_CopyRect(doc_rect, &update_rect);
  611.  
  612.     LOCK_COMPOSITOR(compositor);
  613.  
  614.     /* Compute offsets to convert document coordinates to window coordinates */
  615.     x_offset = - compositor->x_offset;
  616.     y_offset = - compositor->y_offset;
  617.     
  618.     /* Convert the update_rect into window coordinates */
  619.     XP_OffsetRect(&update_rect, x_offset, y_offset);
  620.  
  621.     /* 
  622.      * If there's no overlap between the update_rect and the
  623.      * composited area, there's nothing to draw.
  624.      */
  625.     if (!XP_RectsOverlap(&compositor->window_size, &update_rect)) {
  626.         UNLOCK_COMPOSITOR(compositor);
  627.         return;
  628.     }
  629.     
  630.     /* Subtract out the area that isn't in the composited rect */
  631.     XP_IntersectRect(&compositor->window_size, &update_rect,
  632.                      &update_rect);
  633.  
  634.     update_region = FE_CreateRectRegion(&update_rect);
  635.  
  636.     XP_ASSERT(update_region);
  637.     if (!update_region) {
  638.         UNLOCK_COMPOSITOR(compositor);
  639.         return;
  640.     }
  641.     
  642.     /* 
  643.      * Add the altered region to the region to update at 
  644.      * the next composite 
  645.      */
  646.     FE_UnionRegion(compositor->update_region, update_region, 
  647.                    compositor->update_region);
  648.  
  649.     FE_DestroyRegion(update_region);
  650.  
  651.     if (compositor->enabled) {
  652.         if (update_now)
  653.             cl_composite(compositor, TRIM_UPDATE_REGION_CUTOUTS);
  654.         else
  655.             cl_start_compositor_timeouts(compositor);
  656.     }
  657.     UNLOCK_COMPOSITOR(compositor);
  658. }
  659.  
  660. /* Update the entire contents of a layer and its children. */
  661. void
  662. cl_UpdateLayer(CL_Layer *layer, PRBool update_now)
  663. {
  664.     if (! layer->compositor)
  665.         return;
  666.  
  667.     /* Update the layer */
  668.     CL_UpdateDocumentRect(layer->compositor, &layer->clipped_bbox, PR_FALSE);
  669.  
  670.     /* Update the layer's children, but only if there's a possibility
  671.        that some children are not clipped by this layer, otherwise
  672.        we've already updated with the statement above. */
  673.     if (!layer->clip_children) {
  674.         CL_Layer *child;
  675.         for (child = layer->top_child; child; child = child->sib_below) {
  676.             cl_UpdateLayer(child, PR_FALSE);
  677.         }
  678.     }
  679.  
  680.     if (layer->compositor->enabled) {
  681.         if (update_now)
  682.             cl_composite(layer->compositor, TRIM_UPDATE_REGION_CUTOUTS);
  683.         else
  684.             cl_start_compositor_timeouts(layer->compositor);
  685.     }
  686. }
  687.  
  688. /*
  689. The decision whether to draw onscreen or offscreen is made once for
  690. every composite cycle using these rules:
  691.  
  692.  1) If compositor->offscreen_inhibited is set, drawing is always
  693.     done onscreen.
  694.  2) If compositor->offscreen_enabled is set, drawing is always done
  695.     offscreen.
  696.  3) Otherwise, the offscreen mode depends on the drawing-mode flags
  697.     set for all the layers that fall within the update-region.
  698.  
  699.     A layer is either neutral or biased towards drawing onscreen or
  700.     drawing offscreen, as indicated by the CL_PREFER_DRAW_ONSCREEN and
  701.     CL_PREFER_DRAW_OFFSCREEN flags.
  702.  
  703.     For rule 3, the set of all layers that falls within the bounding box
  704.     of the update-region is examined to determine the drawing mode:
  705.  
  706.     3a) If no layer has the CL_PREFER_DRAW_OFFSCREEN flag set, all drawing
  707.     is performed onscreen.
  708.     3b) Otherwise, bottom-up drawing is performed offscreen until reaching
  709.     a layer that has CL_PREFER_DRAW_ONSCREEN set.  Then the offscreen
  710.     damaged area is BLTed onscreen and remaining layers are drawn onscreen.
  711.     
  712. Top-down drawing is handled differently: It always occurs onscreen unless
  713. CL_PREFER_DRAW_OFFSCREEN is set for an individual layer.
  714. */
  715.  
  716. static void
  717. cl_setup_offscreen(CL_Compositor *compositor)
  718. {
  719.     if (!compositor->backing_store)
  720.         return;
  721.     
  722.     if (compositor->offscreen_enabled && !compositor->offscreen_inhibited) {
  723.         if (!compositor->offscreen_initialized) {
  724.             int width = compositor->window_size.right-
  725.                 compositor->window_size.left;
  726.             int height = compositor->window_size.bottom-
  727.                 compositor->window_size.top;
  728.             cl_InitDrawable(compositor->backing_store);
  729.             cl_SetDrawableDimensions(compositor->backing_store, width, height);
  730.             compositor->offscreen_initialized = PR_TRUE;
  731.         }
  732.     } else if (compositor->offscreen_initialized) {
  733. #ifdef THRASH_OFFSCREEN
  734.         cl_RelinquishDrawable(compositor->backing_store);
  735.         compositor->offscreen_initialized = PR_FALSE;
  736. #endif
  737.     }
  738. }
  739.  
  740. static void
  741. cl_compute_update_region_recurse(CL_Compositor *compositor,
  742.                                  CL_Layer *layer,
  743.                                  FE_Region update_region)
  744. {
  745.     CL_Layer *child;
  746.     int32 x_offset, y_offset;
  747.     FE_Region layer_update_region;
  748.     XP_Rect *win_clipped_bbox;
  749.     XP_Rect prev_win_clipped_bbox;
  750.     
  751.     PRBool visibility_changed, bbox_changed, position_changed;
  752.  
  753.     /* Find out what properties of the layer have changed since the
  754.        last time compositing occurred. */
  755.     visibility_changed = layer->visible != layer->prev_visible;
  756.     bbox_changed = !XP_EqualRect(&layer->clipped_bbox,
  757.                                  &layer->prev_clipped_bbox);
  758.     x_offset = layer->x_origin - layer->prev_x_origin;
  759.     y_offset = layer->y_origin - layer->prev_y_origin;
  760.     position_changed = (x_offset || y_offset);
  761.  
  762.     /* If layer bbox changed, call client-defined callback. */
  763.     if (bbox_changed && layer->vtable.bbox_changed_func) {
  764.         XP_Rect bbox_copy;
  765.         XP_CopyRect(&layer->bbox, &bbox_copy);
  766.         (*layer->vtable.bbox_changed_func)(layer, &bbox_copy);
  767.     }
  768.  
  769.     /* If visibility changed, call client-defined callback. */
  770.     if (visibility_changed && layer->vtable.visibility_changed_func)
  771.         (*layer->vtable.visibility_changed_func)(layer, layer->visible);
  772.  
  773.     /* If layer origin changed, call client-defined callback. */
  774.     if (position_changed && layer->vtable.position_changed_func)
  775.         (*layer->vtable.position_changed_func)(layer, x_offset, y_offset);
  776.  
  777.     /* Compute the bounding box, in window coordinates, of the part of
  778.        the layer that isn't clipped by ancestors and which lies within
  779.        the bounding box of the window. */
  780.     win_clipped_bbox = &layer->win_clipped_bbox;
  781.     XP_CopyRect(&layer->clipped_bbox, win_clipped_bbox);
  782.     XP_OffsetRect(win_clipped_bbox,
  783.                   -compositor->x_offset, -compositor->y_offset);
  784.     XP_IntersectRect(win_clipped_bbox, &compositor->window_size,
  785.                      win_clipped_bbox);
  786.  
  787.     XP_CopyRect(&layer->prev_clipped_bbox, &prev_win_clipped_bbox);
  788.     XP_OffsetRect(&prev_win_clipped_bbox,
  789.                   -compositor->x_offset, -compositor->y_offset);
  790.     XP_IntersectRect(&prev_win_clipped_bbox, &compositor->window_size,
  791.                      &prev_win_clipped_bbox);
  792.  
  793.     layer_update_region = FE_NULL_REGION;
  794.     if (visibility_changed) {
  795.         if (layer->visible) {
  796.             if (!layer->cutout) {
  797.                 layer_update_region = FE_CreateRectRegion(win_clipped_bbox);
  798.                 XP_ASSERT(layer_update_region);
  799.             }
  800.         } else {
  801.             layer_update_region = FE_CreateRectRegion(&prev_win_clipped_bbox);
  802.             XP_ASSERT(layer_update_region);
  803.         }
  804.  
  805.     } else if (layer->visible && (bbox_changed || position_changed)) {
  806.         FE_Region win_clipped_region, prev_win_clipped_region;
  807.  
  808.         win_clipped_region = FE_CreateRectRegion(win_clipped_bbox);
  809.         prev_win_clipped_region = FE_CreateRectRegion(&prev_win_clipped_bbox);
  810.  
  811.         if (win_clipped_region && prev_win_clipped_region) {
  812.             layer_update_region = FE_CreateRegion();
  813.  
  814.             if (layer->cutout)
  815.                 FE_SubtractRegion(prev_win_clipped_region,
  816.                                   win_clipped_region,
  817.                                   layer_update_region);
  818.             else if (bbox_changed && !position_changed)
  819.                 cl_XorRegion(win_clipped_region,
  820.                              prev_win_clipped_region,
  821.                              layer_update_region);
  822.             else
  823.                 FE_UnionRegion(win_clipped_region,
  824.                                prev_win_clipped_region,
  825.                                layer_update_region);
  826.         }
  827.                                
  828.         if (win_clipped_region)
  829.             FE_DestroyRegion(win_clipped_region);
  830.         if (prev_win_clipped_region)
  831.             FE_DestroyRegion(prev_win_clipped_region);
  832.         XP_ASSERT(layer_update_region);
  833.     }
  834.         
  835.     if (layer_update_region != FE_NULL_REGION) {
  836.         FE_UnionRegion(update_region, layer_update_region, update_region);
  837.         FE_DestroyRegion(layer_update_region);
  838.     }
  839.     
  840.     /* Set layer properties for subsequent composite cycle */
  841.     layer->prev_visible = layer->visible;
  842.     XP_CopyRect(&layer->clipped_bbox, &layer->prev_clipped_bbox);
  843.     layer->prev_x_origin = layer->x_origin;
  844.     layer->prev_y_origin = layer->y_origin;
  845.  
  846.     for (child = layer->top_child; child; child = child->sib_below)
  847.         cl_compute_update_region_recurse(compositor, child, update_region);
  848. }
  849.  
  850. static void
  851. cl_compute_update_region(CL_Compositor *compositor)
  852. {
  853.     /* We may need to recompute the update region iteratively since
  854.        layer callbacks may result in changes to layer properties, such
  855.        as bbox, visibility and position. */
  856.     while (compositor->recompute_update_region) {
  857.         compositor->recompute_update_region = PR_FALSE;
  858.         cl_compute_update_region_recurse(compositor, compositor->root,
  859.                                          compositor->update_region);
  860.     }
  861. }
  862.  
  863. /* Pre-drawing layer initialization in front-to-back order.  (This
  864.    could be folded into cl_draw_front_to_back, but then we would need
  865.    to duplicate this functionality when in back_to_front_only mode. */
  866. static int
  867. cl_prepare_to_draw_recurse(CL_Compositor *compositor,
  868.                            CL_Layer *layer, PRBool cutoutp,
  869.                            XP_Rect *update_bbox,
  870.                            PRBool *prefer_draw_offscreen_p)
  871. {
  872.     CL_Layer *child;
  873.     XP_Rect *win_clipped_bbox;
  874.     int descendant_draw_needed = 0;
  875.  
  876.     /* Debugging assert to make sure that these regions are
  877.        destroyed at the end of the composite cycle */
  878.     XP_ASSERT(layer->draw_region == FE_NULL_REGION);
  879.     
  880.     /* Check if the layer is eligible for compositing.  A layer won't
  881.        be composited if it is hidden, or it is entirely clipped by
  882.        ancestors. */
  883.     if (! layer->visible) {
  884.         layer->draw_needed = FALSE;
  885.         if (!layer->descendant_visible || layer->cutout) {
  886.             layer->descendant_draw_needed = FALSE;
  887.             return FALSE;
  888.         }
  889.     } else {
  890.         layer->draw_needed = (layer->vtable.painter_func != NULL);
  891.     }
  892.  
  893.     /* Compute the bounding box, in window coordinates, of the part of
  894.        the layer that isn't clipped by ancestors and which lies within
  895.        the bounding box of the update region. */
  896.     win_clipped_bbox = &layer->win_clipped_bbox;
  897.     XP_CopyRect(&layer->clipped_bbox, win_clipped_bbox);
  898.     XP_OffsetRect(win_clipped_bbox,
  899.                   -compositor->x_offset, -compositor->y_offset);
  900.     XP_IntersectRect(win_clipped_bbox, update_bbox, win_clipped_bbox);
  901.  
  902.     if (XP_IsEmptyRect(win_clipped_bbox)) {
  903.         layer->draw_needed = PR_FALSE;
  904.         if (!layer->descendant_visible || layer->cutout) {
  905.             layer->descendant_draw_needed = PR_FALSE;
  906.             return FALSE;
  907.         }
  908.     }
  909.  
  910.     /* If this is a cutout layer, add the layer's area to the
  911.        off-limits drawing region for the compositor */
  912.     if (layer->cutout) {
  913.         if (cutoutp) {
  914.             FE_Region win_clipped_region = FE_CreateRectRegion(win_clipped_bbox);
  915.             
  916.             if (! win_clipped_region)    /* OOM check */
  917.                 return 0;
  918.             
  919.             FE_UnionRegion(compositor->cutout_region,
  920.                            win_clipped_region,
  921.                            compositor->cutout_region);
  922.             FE_DestroyRegion(win_clipped_region);
  923.         }
  924.  
  925.         /* Cutout-layers can't have children and don't draw themselves. */
  926.         layer->draw_needed = PR_FALSE;
  927.         layer->descendant_draw_needed = PR_FALSE;
  928.         return 0;
  929.     }
  930.  
  931.     /* Recurse for children.
  932.        First get the children to draw in front to back order. */
  933.     for (child = layer->top_child; child; child = child->sib_below) {
  934.         descendant_draw_needed |=
  935.             cl_prepare_to_draw_recurse(compositor, child, cutoutp, update_bbox,
  936.                                        prefer_draw_offscreen_p);
  937.     }
  938.     layer->descendant_draw_needed = (PRBool)descendant_draw_needed;
  939.  
  940.     /* If the layer must draw offscreen then do the entire composite
  941.        offscreen. */
  942.     if ((layer->draw_needed || descendant_draw_needed) && layer->prefer_draw_offscreen)
  943.         *prefer_draw_offscreen_p = PR_TRUE;
  944.  
  945.  
  946.     return (int)layer->draw_needed | descendant_draw_needed;
  947. }
  948.  
  949. static void
  950. cl_prepare_to_draw(CL_Compositor *compositor, FE_Region update_region, 
  951.                    PRBool cutoutp, PRBool *prefer_draw_offscreen_p)
  952. {
  953.     XP_Rect update_bbox;
  954.  
  955.     compositor->cutout_region = FE_CreateRegion();
  956.     if (!compositor->cutout_region) /* OOM */
  957.     return;
  958.  
  959.     FE_GetRegionBoundingBox(update_region, &update_bbox);
  960.  
  961.     cl_prepare_to_draw_recurse(compositor, compositor->root, cutoutp,
  962.                                &update_bbox, prefer_draw_offscreen_p);
  963.     
  964.     if (cutoutp)
  965.         FE_SubtractRegion(update_region, compositor->cutout_region,
  966.                           update_region);
  967.     FE_DestroyRegion(compositor->cutout_region);
  968. }
  969.  
  970. /* The front-to-back drawing phase
  971.    Yech!  Let's get rid of all these arguments. */
  972. static PRBool
  973. cl_draw_front_to_back_recurse(CL_Compositor *compositor,
  974.                               CL_Layer *layer,
  975.                               CL_Layer **top_undrawn_layerp,
  976.                               CL_Layer **bottom_undrawn_layerp,
  977.                               CL_Drawable *backing_store,
  978.                               PRBool *offscreen_layer_drawn_above,
  979.                               FE_Region update_region,
  980.                               FE_Region transparent_above,
  981.                               FE_Region unobscured_by_opaque,
  982.                               FE_Region offscreen_region)
  983. {
  984.     FE_Region overlap;
  985.     CL_Layer *child;
  986.     PRBool layer_is_unobscured_by_transparent_layers, done;
  987.     CL_Drawable *drawable;
  988.     int32 old_x_origin, old_y_origin;
  989.  
  990.     if (layer->descendant_draw_needed) {
  991.  
  992.         /* First get the children to draw in front to back order. */
  993.         done = PR_FALSE;
  994.         for (child = layer->top_child; child && !done; child = child->sib_below) {
  995.             done = cl_draw_front_to_back_recurse(compositor, child,
  996.                                                  top_undrawn_layerp,
  997.                                                  bottom_undrawn_layerp,
  998.                                                  backing_store,
  999.                                                  offscreen_layer_drawn_above,
  1000.                                                  update_region,
  1001.                                                  transparent_above,
  1002.                                                  unobscured_by_opaque,
  1003.                                                  offscreen_region);
  1004.         }
  1005.  
  1006.         /* Have we reached the last layer in the front-to-back pass ? */
  1007.         if (done)
  1008.             return PR_TRUE;
  1009.     }
  1010.  
  1011.     if (!layer->draw_needed)
  1012.         return PR_FALSE;
  1013.  
  1014.     /* Compute the layer's clipping region for drawing. */
  1015.     layer->draw_region = FE_CreateRectRegion(&layer->win_clipped_bbox);
  1016.     FE_IntersectRegion(unobscured_by_opaque, 
  1017.                        layer->draw_region, 
  1018.                        layer->draw_region);
  1019.  
  1020.     /* If the layer is wholly obscured by opaque layers in front of it,
  1021.        there's nothing to draw. */
  1022.     if (FE_IsEmptyRegion(layer->draw_region)) {
  1023.         layer->draw_needed = PR_FALSE;
  1024.         if (layer->clip_children) {
  1025.             layer->descendant_draw_needed = PR_FALSE;
  1026.         }
  1027.         FE_DestroyRegion(layer->draw_region);
  1028.         layer->draw_region = FE_NULL_REGION;
  1029.         return PR_FALSE;
  1030.     }
  1031.  
  1032.     if (layer->opaque) {
  1033.  
  1034.         overlap = FE_CreateRegion();
  1035.         FE_IntersectRegion(transparent_above, layer->draw_region, overlap);
  1036.         layer_is_unobscured_by_transparent_layers = FE_IsEmptyRegion(overlap);
  1037.         FE_DestroyRegion(overlap);
  1038.  
  1039.         /* Are there any non-opaque layers which must draw on top of this
  1040.            layer ? */
  1041.         if (layer_is_unobscured_by_transparent_layers) {
  1042.             
  1043.             /* Figure out if we're drawing to the backing store or not */
  1044.             if (layer->prefer_draw_onscreen || !backing_store) {
  1045.                 drawable = compositor->primary_drawable;
  1046.             } else {
  1047.                 drawable = backing_store;
  1048.                 FE_UnionRegion(layer->draw_region, 
  1049.                                offscreen_region, 
  1050.                                offscreen_region);
  1051.             }
  1052.  
  1053.             /* Set the drawing origin and clip for this layer. */
  1054.             cl_GetDrawableOrigin(drawable, &old_x_origin, &old_y_origin);
  1055.             cl_SetDrawableOrigin(drawable, layer->x_origin, layer->y_origin);
  1056.             cl_SetDrawableClip(drawable, layer->draw_region);
  1057.  
  1058.             /* Draw the layer's contents */
  1059.             (*layer->vtable.painter_func)(drawable,
  1060.                                           layer, layer->draw_region);
  1061.  
  1062.             cl_SetDrawableOrigin(drawable, old_x_origin, old_y_origin);
  1063.             
  1064.             /* No other layers either above or below this one need to
  1065.                update the screen area occupied by this layer.  Any
  1066.                layers are either opaque overlapping layers that have
  1067.                already been drawn in the front-to-back phase, or they
  1068.                are below this layer and will therefore be obscured by it. */
  1069.             FE_SubtractRegion(update_region,
  1070.                               layer->draw_region, update_region);
  1071.  
  1072.             /* We don't need to draw this layer in the back-to-front phase,
  1073.                since we've already drawn it. */
  1074.             layer->draw_needed = PR_FALSE;
  1075.         } else {
  1076.  
  1077.             /* This is the bottommost layer that needs drawing, and which
  1078.                has not yet been drawn */
  1079.             *bottom_undrawn_layerp = layer;
  1080.  
  1081.             if (! *top_undrawn_layerp)
  1082.                 *top_undrawn_layerp = layer;
  1083.  
  1084.             layer->offscreen_layer_drawn_above = *offscreen_layer_drawn_above;
  1085.             *offscreen_layer_drawn_above |= (int)layer->prefer_draw_offscreen;
  1086.         }
  1087.  
  1088.         FE_SubtractRegion(unobscured_by_opaque, layer->draw_region,
  1089.                           unobscured_by_opaque);
  1090.  
  1091.         /* If we've already drawn the layer, get rid of the draw region */
  1092.         if (layer_is_unobscured_by_transparent_layers) {
  1093.             FE_DestroyRegion(layer->draw_region);
  1094.             layer->draw_region = FE_NULL_REGION;
  1095.         }
  1096.         
  1097.         /* When the entire remaining update region is obscured by
  1098.            opaque layers above it, there's nothing left to do. */
  1099.         if (FE_IsEmptyRegion(unobscured_by_opaque)) {
  1100.             return PR_TRUE;
  1101.         }
  1102.     } else {
  1103.         FE_UnionRegion(transparent_above, layer->draw_region, 
  1104.                        transparent_above);
  1105.         *bottom_undrawn_layerp = layer;
  1106.         if (! *top_undrawn_layerp)
  1107.             *top_undrawn_layerp = layer;
  1108.         layer->offscreen_layer_drawn_above = *offscreen_layer_drawn_above;
  1109.         *offscreen_layer_drawn_above |= (int)layer->prefer_draw_offscreen;
  1110.     }
  1111.  
  1112.     return PR_FALSE;
  1113. }
  1114.  
  1115. /* The front-to-back drawing phase */
  1116. static void
  1117. cl_draw_front_to_back(CL_Compositor *compositor,
  1118.                       CL_Layer **top_undrawn_layerp,
  1119.                       CL_Layer **bottom_undrawn_layerp,
  1120.                       CL_Drawable *backing_store,
  1121.                       FE_Region update_region,
  1122.                       FE_Region offscreen_region)
  1123.     FE_Region transparent_above, unobscured_by_opaque;   
  1124.     PRBool offscreen_layer_drawn_above = PR_FALSE;
  1125.  
  1126.     transparent_above = FE_CreateRegion();
  1127.     if (! transparent_above) {
  1128.         XP_ASSERT(0);      /* OOM */
  1129.         return;
  1130.     }
  1131.          
  1132.     unobscured_by_opaque = FE_CopyRegion(update_region, NULL);
  1133.     if (! unobscured_by_opaque) {
  1134.         XP_ASSERT(0);      /* OOM */
  1135.         FE_DestroyRegion(transparent_above);
  1136.         return;
  1137.     }
  1138.     cl_draw_front_to_back_recurse(compositor, compositor->root,
  1139.                                   top_undrawn_layerp, bottom_undrawn_layerp,
  1140.                                   backing_store,
  1141.                                   &offscreen_layer_drawn_above,
  1142.                                   update_region,
  1143.                                   transparent_above,
  1144.                                   unobscured_by_opaque,
  1145.                                   offscreen_region);
  1146.     FE_DestroyRegion(transparent_above);
  1147.     FE_DestroyRegion(unobscured_by_opaque);
  1148. }
  1149.  
  1150. typedef struct cl_back_to_front_state 
  1151. {
  1152.     CL_Compositor *compositor;
  1153.     CL_Layer *top_undrawn_layer;
  1154.     CL_Layer *bottom_undrawn_layer;
  1155.     PRBool *onscreen_layer_drawn_below;
  1156.     FE_Region update_region;
  1157.     CL_Drawable *backing_store;
  1158.     FE_Region offscreen_region;
  1159. } cl_back_to_front_state;
  1160.  
  1161. /* The back-to-front drawing phase */
  1162. static CL_BackToFrontStatus
  1163. cl_draw_back_to_front_recurse(CL_Layer *layer,
  1164.                               cl_back_to_front_state *s,
  1165.                               CL_BackToFrontStatus status)
  1166. {
  1167.     CL_Layer *child;
  1168.     CL_Drawable *drawable;
  1169.     int32 old_x_origin, old_y_origin;
  1170.     PRBool *onscreen_layer_drawn_below = s->onscreen_layer_drawn_below;
  1171.     CL_Drawable *backing_store = s->backing_store;
  1172.     CL_Compositor *compositor = s->compositor;
  1173.  
  1174.     /* Only draw if a draw is necessary and we've already reached
  1175.      * the bottommost layer that needs to be drawn.
  1176.      */
  1177.     if (layer->draw_needed && ((status == CL_REACHED_BOTTOM_UNDRAWN) || 
  1178.                                (layer == s->bottom_undrawn_layer))) {
  1179.  
  1180.         /* Clip drawing to the bounds of itself and any ancestors */
  1181.         if (!layer->draw_region) {
  1182.             layer->draw_region = FE_CreateRectRegion(&layer->win_clipped_bbox);
  1183.             FE_IntersectRegion(s->update_region, layer->draw_region, 
  1184.                                layer->draw_region);
  1185.         }
  1186.  
  1187.         /* If any layers beneath this one were drawn onscreen, then this
  1188.            layer needs to be drawn there also. */
  1189.         if (!backing_store || *onscreen_layer_drawn_below) {
  1190.             drawable = compositor->primary_drawable;
  1191.             *onscreen_layer_drawn_below = PR_TRUE;
  1192.         } else {
  1193.             FE_Region offscreen_region = s->offscreen_region;
  1194.             
  1195.             /* If this layer and layers above this one are drawn
  1196.                onscreen, but all the layers beneath were drawn
  1197.                offscreen, we need to copy what we've painted so far
  1198.                from the backing store to the primary drawable. */
  1199.             if (layer->prefer_draw_onscreen &&
  1200.                 !layer->offscreen_layer_drawn_above &&
  1201.                 !*onscreen_layer_drawn_below) {
  1202.                 
  1203.                 /* The clip could have been modified during the
  1204.                    front-to-back phase, so clear it. */
  1205.                 cl_SetDrawableClip(compositor->primary_drawable, NULL);
  1206.                 cl_CopyPixels(backing_store, compositor->primary_drawable,
  1207.                               offscreen_region);
  1208.                 FE_CLEAR_REGION(offscreen_region);
  1209.                 drawable = compositor->primary_drawable;
  1210.                 *onscreen_layer_drawn_below = PR_TRUE;
  1211.             } else {
  1212.                 drawable = backing_store;
  1213.                 FE_UnionRegion(offscreen_region, layer->draw_region, 
  1214.                                offscreen_region);
  1215.             }
  1216.         }
  1217.  
  1218.         /* Set the drawing origin and clip for this layer. */
  1219.         cl_GetDrawableOrigin(drawable, &old_x_origin, &old_y_origin);
  1220.         cl_SetDrawableOrigin(drawable, layer->x_origin, layer->y_origin);
  1221.         cl_SetDrawableClip(drawable, layer->draw_region);
  1222.  
  1223.         /* Draw the layer */
  1224.         (*layer->vtable.painter_func)(drawable, layer, layer->draw_region);
  1225.  
  1226.         cl_SetDrawableOrigin(drawable, old_x_origin, old_y_origin);
  1227.  
  1228.         FE_DestroyRegion(layer->draw_region);
  1229.         layer->draw_region = FE_NULL_REGION;
  1230.  
  1231.         /* If this layer is uniformly-colored, push it on the
  1232.            front-to-back stack of uniformly-colored layers. */
  1233.         if (layer->uniform_color) {
  1234.             XP_ASSERT(layer->opaque);
  1235.             layer->uniformly_colored_layer_below = 
  1236.                 compositor->uniformly_colored_layer_stack;
  1237.             compositor->uniformly_colored_layer_stack = layer;
  1238.         }
  1239.         
  1240.         /* If we've reached the last layer that couldn't draw in the
  1241.            front to back phase, it's time to stop.              */
  1242.         if (layer == s->top_undrawn_layer)
  1243.             return CL_REACHED_TOP_UNDRAWN;
  1244.  
  1245.         /* If we've reached the bottommost (first) layer that needs to be
  1246.          * drawn, the rest of the layers can start drawing. */
  1247.         if (layer == s->bottom_undrawn_layer)
  1248.             status = CL_REACHED_BOTTOM_UNDRAWN;
  1249.     }
  1250.  
  1251.     if (layer->descendant_draw_needed) {
  1252.         
  1253.         /* Get the children to draw in back to front order. 
  1254.            Stop if we've reached the last layer to draw.      */
  1255.         for (child = layer->bottom_child; 
  1256.              child && (status != CL_REACHED_TOP_UNDRAWN) ; 
  1257.              child = child->sib_above) {
  1258.             status = cl_draw_back_to_front_recurse(child, s, status);
  1259.         }
  1260.         return status;
  1261.     }
  1262.     
  1263.     return status;
  1264. }
  1265.  
  1266. /* The back-to-front drawing phase */
  1267. static void
  1268. cl_draw_back_to_front(CL_Compositor *compositor, 
  1269.                       CL_Layer *top_undrawn_layer,
  1270.                       CL_Layer *bottom_undrawn_layer,
  1271.                       FE_Region update_region,
  1272.                       CL_Drawable *backing_store,
  1273.                       FE_Region offscreen_region)
  1274. {
  1275.     PRBool onscreen_layer_drawn_below = PR_FALSE;
  1276.     
  1277.     cl_back_to_front_state state;
  1278.     
  1279.     state.compositor = compositor;
  1280.     state.top_undrawn_layer = top_undrawn_layer;
  1281.     state.bottom_undrawn_layer = bottom_undrawn_layer;
  1282.     state.onscreen_layer_drawn_below = &onscreen_layer_drawn_below;
  1283.     state.update_region = update_region;
  1284.     state.backing_store = backing_store;
  1285.     state.offscreen_region = offscreen_region;
  1286.  
  1287.     if (compositor->back_to_front_only)
  1288.     cl_draw_back_to_front_recurse(compositor->root, &state, 
  1289.                                   CL_REACHED_BOTTOM_UNDRAWN);
  1290.     else
  1291.         cl_draw_back_to_front_recurse(compositor->root, &state, CL_REACHED_NOTHING);
  1292. }
  1293.     
  1294.  
  1295. /* Redraws all regions changed since last call to cl_composite().
  1296.  * This is called by the timer callback. It can be also be directly
  1297.  * called to force a synchronous composite.
  1298.  */
  1299. static PRBool
  1300. cl_composite(CL_Compositor *compositor, PRBool cutoutp)
  1301. {
  1302.     CL_Layer *top_undrawn_layer, *bottom_undrawn_layer;
  1303.     CL_Drawable *backing_store;
  1304.     FE_Region offscreen_region, update_region;
  1305.     PRBool save_offscreen_enabled, prefer_draw_offscreen = PR_FALSE;
  1306.     
  1307.     XP_ASSERT(compositor);
  1308.  
  1309.     if (!compositor || !compositor->root)
  1310.         return PR_FALSE;
  1311.  
  1312.     LOCK_COMPOSITOR(compositor);
  1313.  
  1314.     /* Check if there's a region to be drawn... */
  1315.     cl_compute_update_region(compositor);
  1316.     if (FE_IsEmptyRegion(compositor->update_region)) {
  1317.         UNLOCK_COMPOSITOR(compositor);
  1318.         return PR_FALSE;
  1319.     }
  1320.  
  1321.     {
  1322.         XP_Rect bbox;
  1323.         FE_GetRegionBoundingBox(compositor->update_region, &bbox);
  1324.         CL_TRACE(0, ("Compositing rectangle [%d, %d, %d, %d]",
  1325.                      bbox.left, bbox.top, bbox.right, bbox.bottom));
  1326.     }
  1327.  
  1328.     XP_ASSERT(!compositor->composite_in_progress);
  1329.     compositor->composite_in_progress = PR_TRUE;
  1330.  
  1331.      /* 
  1332.       * Copy the current update region and then clear it out. The layer
  1333.       * painter funcs might actually perform operations that add to the
  1334.       * update regions and we don't want to lose those updates.
  1335.       */
  1336.      update_region = FE_CopyRegion(compositor->update_region, NULL);
  1337.      FE_CLEAR_REGION(compositor->update_region);
  1338.  
  1339.      /* Initialize temporary per-layer drawing variables.  Also determine
  1340.         whether this composite must be done offscreen. */
  1341.      cl_prepare_to_draw(compositor, update_region, cutoutp,
  1342.                         &prefer_draw_offscreen);
  1343.  
  1344.      if (prefer_draw_offscreen) {
  1345.          save_offscreen_enabled = compositor->offscreen_enabled;
  1346.          compositor->offscreen_enabled = PR_TRUE;
  1347.      }
  1348.      cl_setup_offscreen(compositor);
  1349.  
  1350.      /* Determine whether or not we'll use a backing store */
  1351.      if (compositor->offscreen_inhibited || !compositor->offscreen_enabled ||
  1352.          !compositor->backing_store) {
  1353.          /* FIXME - what happens if we've disabled the backing store,
  1354.             but some layers have prefer_draw_offscreen set ? */
  1355.          backing_store = NULL;
  1356.          offscreen_region = FE_NULL_REGION;
  1357.          
  1358.          /* Invalidate the parts of the backing store for which there are
  1359.             update requests. */
  1360.          FE_SubtractRegion(compositor->backing_store_region,
  1361.                            compositor->update_region,
  1362.                            compositor->backing_store_region);
  1363.      } else {
  1364.          backing_store = cl_LockDrawableForReadWrite(compositor->backing_store);
  1365.          if (!backing_store) {
  1366.              /* Couldn't read the backing store.  Invalidate its contents. */
  1367.              FE_CLEAR_REGION(compositor->backing_store_region);
  1368.              backing_store = cl_LockDrawableForWrite(compositor->backing_store);
  1369.          }
  1370.  
  1371.          /* Assume that there is a painter for every area of the drawable to 
  1372.             be updated. */
  1373.          if (backing_store)
  1374.              offscreen_region = FE_CreateRegion();
  1375.          
  1376.      }
  1377.  
  1378.      compositor->uniformly_colored_layer_stack = NULL;
  1379.      top_undrawn_layer = bottom_undrawn_layer = NULL;
  1380.  
  1381.      /* Front-to-back phase */
  1382.      if (!compositor->back_to_front_only) {
  1383.          cl_draw_front_to_back(compositor,
  1384.                                &top_undrawn_layer, &bottom_undrawn_layer,
  1385.                                backing_store,
  1386.                                update_region,
  1387.                                offscreen_region);
  1388.      }
  1389.  
  1390.      /* Back-to-front phase */
  1391.      if (top_undrawn_layer || compositor->back_to_front_only) {
  1392.          cl_draw_back_to_front(compositor,
  1393.                                top_undrawn_layer,
  1394.                                bottom_undrawn_layer,
  1395.                                update_region,
  1396.                                backing_store,
  1397.                                offscreen_region);
  1398.      }
  1399.     
  1400.      /* Transfer the composited pixels from the backing store to
  1401.         the onscreen drawable. */
  1402.      cl_SetDrawableClip(compositor->primary_drawable, NULL);
  1403.      if (backing_store) {
  1404.          if (!FE_IsEmptyRegion(offscreen_region)) {
  1405.              /* The clip could have been modified during the
  1406.                 front-to-back phase, so clear it. */
  1407.              cl_CopyPixels(backing_store, compositor->primary_drawable,
  1408.                            offscreen_region);
  1409.          }
  1410.  
  1411.          cl_UnlockDrawable(backing_store);
  1412.  
  1413.          FE_DestroyRegion(offscreen_region);
  1414.      }
  1415.  
  1416.      /* If this composite was forced offscreen, restore the previous state */
  1417.      if (prefer_draw_offscreen)
  1418.          compositor->offscreen_enabled = save_offscreen_enabled;
  1419.  
  1420.      /* Get rid of the temporary copy */
  1421.      FE_DestroyRegion(update_region);
  1422.  
  1423.      /* Set the clip region back to its old value */
  1424.      cl_RestoreDrawableClip(compositor->primary_drawable);
  1425.      
  1426.      compositor->composite_in_progress = PR_FALSE;
  1427.      
  1428.      UNLOCK_COMPOSITOR(compositor);
  1429.  
  1430.      return PR_TRUE;
  1431. }
  1432.  
  1433. /* External API */
  1434. void
  1435. CL_CompositeNow(CL_Compositor *compositor)
  1436. {
  1437.     cl_composite(compositor, TRIM_UPDATE_REGION_CUTOUTS);
  1438. }
  1439.  
  1440. /* 
  1441.  * Indicates that the window the compositor is drawing to has been resized.
  1442.  * We make the assumption that any refreshing will be carried out by 
  1443.  * calling CL_RefreshWindowRect.
  1444.  */
  1445. void 
  1446. CL_ResizeCompositorWindow(CL_Compositor *compositor, int32 width, int32 height)
  1447. {
  1448.     XP_ASSERT(compositor);
  1449.   
  1450.     if (!compositor)
  1451.         return;
  1452.     
  1453.     LOCK_COMPOSITOR(compositor);
  1454.  
  1455.     compositor->window_size.right = compositor->window_size.left + width;
  1456.     compositor->window_size.bottom = compositor->window_size.top + height;
  1457.  
  1458.     if (compositor->window_region) 
  1459.         FE_DestroyRegion(compositor->window_region);
  1460.  
  1461.     compositor->window_region = FE_CreateRectRegion(&compositor->window_size);
  1462.  
  1463.     if (compositor->offscreen_initialized && compositor->backing_store)
  1464.         cl_SetDrawableDimensions(compositor->backing_store, width, height);
  1465.  
  1466.     UNLOCK_COMPOSITOR(compositor);
  1467. }
  1468.  
  1469. /* 
  1470.  * Called when the compositor's window scrolls. We make the assumption 
  1471.  * that any refreshing will be carried out by calling CL_RefreshWindowRect
  1472.  */
  1473. void 
  1474. CL_ScrollCompositorWindow(CL_Compositor *compositor, 
  1475.                           int32 x_origin, int32 y_origin)
  1476. {
  1477.     int32 delta_x, delta_y;
  1478.     
  1479.     XP_ASSERT(compositor);
  1480.     
  1481.     if (!compositor)
  1482.         return;
  1483.     
  1484.     LOCK_COMPOSITOR(compositor);
  1485.  
  1486.     if ((compositor->x_offset != x_origin) ||
  1487.         (compositor->y_offset != y_origin)) {
  1488.         
  1489.         /* Invalidate backing store.
  1490.            For better performance, perhaps we should be scrolling it, instead */
  1491.         FE_CLEAR_REGION(compositor->backing_store_region);
  1492.  
  1493.         delta_x = compositor->x_offset - x_origin;
  1494.         delta_y = compositor->y_offset - y_origin;
  1495.  
  1496.         /* Are we scrolling a small enough amount that some part of
  1497.            the current screen contents may remain onscreen ? */
  1498.         if ((ABS(delta_x) < FE_MAX_REGION_COORDINATE) &&
  1499.             (ABS(delta_y) < FE_MAX_REGION_COORDINATE)) {
  1500.             FE_Region update_region = compositor->update_region;
  1501.             FE_Region window_region = compositor->window_region;
  1502.             
  1503.             /* Scroll compositor update region */
  1504.             FE_OffsetRegion(update_region, delta_x, delta_y);
  1505.             
  1506.             FE_IntersectRegion(window_region, update_region, update_region);
  1507.         }
  1508.  
  1509.         compositor->x_offset = x_origin;
  1510.         compositor->y_offset = y_origin;
  1511.         
  1512.     }
  1513.     UNLOCK_COMPOSITOR(compositor);
  1514. }
  1515.  
  1516. /* Sets whether a compositor offscreen-drawing should occur or not */
  1517. /* If enabled is PR_TRUE, the compositor will use offscreen        */
  1518. /* drawing if applicable.                                          */
  1519. void
  1520. CL_SetCompositorOffscreenDrawing(CL_Compositor *compositor, 
  1521.                                  CL_OffscreenMode mode)
  1522. {
  1523.     XP_ASSERT(compositor);
  1524.     if (!compositor)
  1525.         return;
  1526.  
  1527.     switch (mode) {
  1528.     case CL_OFFSCREEN_ENABLED:
  1529.         compositor->offscreen_enabled = PR_TRUE;
  1530.         compositor->offscreen_inhibited = PR_FALSE;
  1531.         break;
  1532.     case CL_OFFSCREEN_DISABLED:
  1533.         compositor->offscreen_inhibited = PR_TRUE;
  1534.         break;
  1535.     case CL_OFFSCREEN_AUTO:
  1536.         compositor->offscreen_enabled = PR_FALSE;
  1537.         compositor->offscreen_inhibited = PR_FALSE;
  1538.         break;
  1539.     }
  1540. }
  1541.  
  1542. CL_OffscreenMode
  1543. CL_GetCompositorOffscreenDrawing(CL_Compositor *compositor)
  1544. {
  1545.     PRBool enabled;
  1546.     XP_ASSERT(compositor);
  1547.     if (! compositor)
  1548.         return PR_FALSE;
  1549.  
  1550.     if (compositor->offscreen_inhibited)
  1551.         return CL_OFFSCREEN_DISABLED;
  1552.  
  1553.     enabled = compositor->offscreen_enabled;
  1554.     return enabled ? CL_OFFSCREEN_ENABLED : CL_OFFSCREEN_AUTO;
  1555. }
  1556.  
  1557. /* Frame-rate excursion limits */
  1558. #define MAX_FRAME_PERIOD      (1000000.0F / CL_FRAME_RATE_MIN)
  1559. #define MIN_FRAME_PERIOD      (1000000.0F / CL_FRAME_RATE_MAX)
  1560. #define INITIAL_FRAME_PERIOD  (1000000.0F / CL_FRAME_RATE_INITIAL)
  1561.  
  1562. /* Timeout callback for time-based compositing.
  1563.  
  1564.    Adaptively adjust the frame-rate at which compositing is done based
  1565.    on the CPU load.  (CPU load is estimated by measuring the ability
  1566.    of recent composite timeouts to meet their deadlines.)
  1567.  */
  1568. static void
  1569. cl_compositor_callback(void *closure)
  1570. {
  1571. #ifdef CL_ADAPT_FRAME_RATE
  1572.     unsigned int i, index, filter_length, delay_line_index;
  1573.     int64 slack64, frame_period64, delay64, nominal_deadline64, now64;
  1574.     int32 slack, delay, slip, clamped_slack;
  1575.     double earliness, smoothed_slack, frame_period, adjust;
  1576.     
  1577.     CL_Compositor *compositor = (CL_Compositor *)closure;
  1578.     frame_period = compositor->frame_period;
  1579.  
  1580.     XP_ASSERT(compositor->frame_period != 0); /* should never be here in static case */
  1581.     if (compositor->frame_period == 0)
  1582.         return; /* to avoid divide by zero, since fundamentally should never be here */
  1583.  
  1584.     /* First, do the actual drawing work */
  1585.     if (cl_composite(compositor, TRIM_UPDATE_REGION_CUTOUTS) == PR_FALSE) {
  1586.  
  1587.         compositor->nothing_to_do_count++;
  1588.  
  1589.         if (compositor->nothing_to_do_count > 5) {
  1590.  
  1591.             /*
  1592.              *    Clear the timeout, because we are in the closure
  1593.              *    function, and we don't want another dangling timer.
  1594.              */
  1595.             compositor->composite_timeout = NULL; /* VERY IMPORTANT */
  1596.             compositor->nothing_to_do_count = 0;
  1597.             return;
  1598.         }
  1599.     } else {
  1600.         compositor->nothing_to_do_count = 0;
  1601.     }
  1602.  
  1603.     /* Compute the "slack", which indicates how late (or early) the
  1604.        compositor was meeting its deadline.  Positive slack numbers
  1605.        indicate earliness.  Negative numbers lateness. */
  1606.     now64 = PR_Now();
  1607.     nominal_deadline64 = compositor->nominal_deadline64;
  1608.     LL_SUB(slack64, nominal_deadline64, now64);
  1609.     LL_L2I(slack, slack64);
  1610.  
  1611.     slack -= (int32)((1.0 - CL_CPU_LOAD) * frame_period);
  1612.  
  1613.     /* Clamp slack to maximum permitted amount of frame-period adjustment. */
  1614.     slip = 0;
  1615.     if (frame_period - slack > MAX_FRAME_PERIOD) {
  1616.         clamped_slack = (int32)(frame_period - MAX_FRAME_PERIOD);
  1617.         slip = clamped_slack - slack;
  1618.     }
  1619.  
  1620.     /* Store latest slack value in the delay line, a circular array
  1621.        that keeps track of the most recent slack values. */
  1622.     delay_line_index = compositor->delay_line_index;
  1623.     if (delay_line_index == DELAY_LINE_LENGTH) {
  1624.         /* First time we're running the timeout.  Initialize the delay line */
  1625.         for (i = 0; i < DELAY_LINE_LENGTH; i++)
  1626.             compositor->delay_line[i] = slack;
  1627.     } else {
  1628.         /* Push most recent slack value into circular delay line */
  1629.         compositor->delay_line[delay_line_index] = slack;
  1630.     }
  1631.  
  1632.     /* Compute the number of filter taps corresponding to the
  1633.        requested duration of the filter, assuming that the
  1634.        compositor's frame-rate changes slowly. */
  1635.  
  1636.     /* This should never happen, since we check for this up top. But just in case */    
  1637.     /* something changes in the future in the above code, this is here */    
  1638.     /* just to make sure we find a potential divide by zero quickly, and don't do it.     
  1639.     XP_ASSERT(frame_period != 0); 
  1640.  
  1641.     if(frame_period == 0)
  1642.         filter_length = DELAY_LINE_LENGTH;
  1643.     else
  1644.     */
  1645.     
  1646.     filter_length = (unsigned int) ((SLOW_FILTER_DURATION * 1000) / frame_period);
  1647.  
  1648.     if (filter_length > DELAY_LINE_LENGTH)
  1649.         filter_length = DELAY_LINE_LENGTH;
  1650.     if (filter_length < 4)
  1651.         filter_length = 4;
  1652.  
  1653.     /* Average the last <filter_length> values in the circular delay
  1654.        line to create a smoothed slow-response filtering of the slack
  1655.        values.  Create a "fast-response" filter that uses half as many
  1656.        elements as the "slow" one. */
  1657.     smoothed_slack = 0;
  1658.     earliness = 0;
  1659.     for (i = 0; i < filter_length; i++) {
  1660.         int32 slack_val;
  1661.  
  1662.         index = delay_line_index - i;
  1663.         index &= (DELAY_LINE_LENGTH - 1);
  1664.         slack_val = compositor->delay_line[index];
  1665.         smoothed_slack += slack_val;
  1666.         if (slack_val > 0)
  1667.             earliness += slack_val;
  1668.     }
  1669.     smoothed_slack /= filter_length;
  1670.     earliness /= filter_length;
  1671.  
  1672.     /* Update next index in circular delay-line */
  1673.     delay_line_index++;
  1674.     delay_line_index &= (DELAY_LINE_LENGTH - 1);
  1675.     compositor->delay_line_index = delay_line_index;
  1676.  
  1677.     adjust = earliness + ((smoothed_slack > 0) ? 0 : smoothed_slack * 0.35);
  1678.  
  1679.     /* Adjust the frame rate, but don't allow the frame rate to excur
  1680.        outside its preset limits. */
  1681.     if (adjust < 0) {
  1682.         /* Slack is decreasing, Let's decrease the CPU load by
  1683.            decreasing the frame rate. */
  1684.         frame_period -= 0.10 * adjust;
  1685.         if (frame_period > MAX_FRAME_PERIOD)
  1686.             frame_period = MAX_FRAME_PERIOD;
  1687.     } else {
  1688.         /* Slack is negative and decreasing.  (Really, we're
  1689.            finishing earlier and getting more so) ; Increase
  1690.            frame-rate to make use of available CPU. */
  1691.         frame_period -= 0.20 * adjust;
  1692.         if (frame_period < MIN_FRAME_PERIOD)
  1693.             frame_period = MIN_FRAME_PERIOD;
  1694.     }
  1695.     compositor->frame_period = (float)frame_period;
  1696.  
  1697.     /* Compute delay from now until start of next composite timeout */
  1698.     LL_SUB(delay64, nominal_deadline64, now64);
  1699.     LL_L2I(delay, delay64);
  1700.     delay = (delay + 500) / 1000; /* Convert from microseconds to ms */
  1701.  
  1702.     /* Compute nominal completion time for next composite timeout */
  1703.     LL_I2L(frame_period64, (int32)frame_period + slip);
  1704.     LL_ADD(nominal_deadline64, nominal_deadline64, frame_period64);
  1705.     compositor->nominal_deadline64 = nominal_deadline64;
  1706.  
  1707.     /* Impose minimum delay to prevent timeouts from being scheduled
  1708.        back-to-back */
  1709.     if (delay < CL_MIN_TIMEOUT)
  1710.         delay = CL_MIN_TIMEOUT;
  1711.  
  1712.     /* Schedule the next compositor timeout. */
  1713.     compositor->composite_timeout = 
  1714.         FE_SetTimeout((TimeoutCallbackFunction)cl_compositor_callback,
  1715.                       (void *)compositor,
  1716.                       (uint32)delay);
  1717.  
  1718. #else  /* !CL_ADAPT_FRAME_RATE */
  1719.     CL_Compositor *compositor = (CL_Compositor *)closure;
  1720.     cl_composite(compositor, TRIM_UPDATE_REGION_CUTOUTS);
  1721.     compositor->composite_timeout = 
  1722.         FE_SetTimeout((TimeoutCallbackFunction)cl_compositor_callback,
  1723.                       (void *)compositor, 0);
  1724. #endif /* CL_ADAPT_FRAME_RATE */
  1725. }
  1726.  
  1727. PRBool 
  1728. CL_GetCompositorEnabled(CL_Compositor *compositor)
  1729. {
  1730.     XP_ASSERT(compositor);
  1731.     
  1732.     if (!compositor)
  1733.         return PR_FALSE;
  1734.     
  1735.     return compositor->enabled;
  1736. }
  1737.  
  1738.  
  1739. void
  1740. cl_start_compositor_timeouts(CL_Compositor *compositor)
  1741. {
  1742.     int64 frame_period64, now64;
  1743.  
  1744.     XP_ASSERT(compositor);
  1745.     if (compositor == NULL)
  1746.         return;
  1747.  
  1748.     if (compositor->frame_period == 0) /* indicates static case, no timeouts... */
  1749.         return;
  1750.  
  1751.     /* No need to start timeouts if already started */
  1752.     if (compositor->composite_timeout)
  1753.         return;
  1754.  
  1755.     if (!compositor->enabled)
  1756.         return;
  1757.  
  1758.     /* Compute nominal time for next composite timeout */
  1759.     now64 = PR_Now();
  1760.     LL_I2L(frame_period64, (int32)compositor->frame_period);
  1761.     LL_ADD(compositor->nominal_deadline64, now64, frame_period64);
  1762.  
  1763.     /* Special value indicates empty delay line */
  1764.     compositor->delay_line_index = DELAY_LINE_LENGTH;
  1765.     compositor->composite_timeout = 
  1766.         FE_SetTimeout((TimeoutCallbackFunction)cl_compositor_callback,
  1767.                       (void *)compositor, 0);
  1768. }
  1769.  
  1770.  
  1771. /* Sets a compositor's enabled state. Disabling a compositor will  */
  1772. /* stop timed composites (but will not prevent explicit composites */
  1773. /* from happening). Enabling a compositor restarts timed draws.    */
  1774. void 
  1775. CL_SetCompositorEnabled(CL_Compositor *compositor, PRBool enabled)
  1776. {
  1777.     XP_ASSERT(compositor);
  1778.  
  1779.     if (!compositor)
  1780.         return;
  1781.     
  1782.     CL_TRACE(0, ("Setting compositor enabled state to %d ", enabled));
  1783.  
  1784.     if (enabled && (compositor->enabled == PR_FALSE) && compositor->frame_period) {
  1785.         cl_composite(compositor, TRIM_UPDATE_REGION_CUTOUTS);
  1786.         
  1787.         CL_TRACE(0, ("Starting compositor timeout"));
  1788.         cl_start_compositor_timeouts(compositor);
  1789.     }
  1790.     else if (!enabled && (compositor->enabled == PR_TRUE)) {
  1791.         if (compositor->composite_timeout)
  1792.             FE_ClearTimeout(compositor->composite_timeout);
  1793.         compositor->composite_timeout = NULL;
  1794.         if (compositor->offscreen_initialized) {
  1795.             cl_RelinquishDrawable(compositor->backing_store);
  1796.             compositor->offscreen_initialized = PR_FALSE;
  1797.         }
  1798.     }
  1799.     
  1800.     compositor->enabled = enabled;
  1801. }
  1802.     
  1803. CL_Drawable *
  1804. CL_GetCompositorDrawable(CL_Compositor *compositor)
  1805. {
  1806.     XP_ASSERT(compositor);
  1807.     
  1808.     if (!compositor)
  1809.         return NULL;
  1810.     
  1811.     return compositor->primary_drawable;
  1812. }
  1813.  
  1814. void 
  1815. CL_SetCompositorDrawable(CL_Compositor *compositor, 
  1816.                          CL_Drawable *drawable)
  1817. {
  1818.     XP_ASSERT(compositor);
  1819.     
  1820.     if (!compositor)
  1821.         return;
  1822.     
  1823.     compositor->primary_drawable = drawable;
  1824.     drawable->compositor = compositor;
  1825. }
  1826.  
  1827. CL_Layer *
  1828. CL_GetCompositorRoot(CL_Compositor *compositor)
  1829. {
  1830.     XP_ASSERT(compositor);
  1831.     
  1832.     if (!compositor)
  1833.         return NULL;
  1834.  
  1835.     return compositor->root;
  1836. }
  1837.  
  1838. /* Set a layer as the root of the layer tree */
  1839. void 
  1840. CL_SetCompositorRoot(CL_Compositor *compositor, CL_Layer *root)
  1841. {
  1842.     XP_ASSERT(compositor);
  1843.  
  1844.     if (!compositor)
  1845.         return;
  1846.  
  1847.     CL_TRACE(0,("Setting root of compositor %x to layer %x", compositor, root));
  1848.  
  1849.     LOCK_COMPOSITOR(compositor);
  1850.     
  1851.     compositor->root = root;
  1852.  
  1853.     if (root) {
  1854.         cl_SetCompositorRecursive(root, compositor);
  1855.         
  1856.         cl_LayerAdded(compositor, root);
  1857.     }
  1858.     
  1859.     UNLOCK_COMPOSITOR(compositor);
  1860. }
  1861.  
  1862. uint32 
  1863. CL_GetCompositorFrameRate(CL_Compositor *compositor)
  1864. {
  1865.     XP_ASSERT(compositor);
  1866.     
  1867.     if (!compositor)
  1868.         return 0;
  1869.  
  1870.     if (compositor->frame_period == 0)
  1871.         return 0;
  1872.     else
  1873.         return (uint32)((1000000.0 / compositor->frame_period) + 0.5);
  1874. }
  1875.  
  1876. void 
  1877. CL_SetCompositorFrameRate(CL_Compositor *compositor, uint32 frame_rate)
  1878. {
  1879.     XP_ASSERT(compositor);
  1880.   
  1881.     if (!compositor)
  1882.         return;
  1883.  
  1884.     LOCK_COMPOSITOR(compositor);
  1885.  
  1886.     if (frame_rate)
  1887.         compositor->frame_period = 1000000.0F / frame_rate;
  1888.     else
  1889.         compositor->frame_period = 0.0F;
  1890.  
  1891.     /* BUGBUG This is probably the wrong behavior. If we had better */
  1892.     /* timing services, we could do better.                         */
  1893.     if (compositor->enabled && compositor->frame_period) {
  1894.         if (compositor->composite_timeout) {
  1895.             FE_ClearTimeout(compositor->composite_timeout);
  1896.             compositor->composite_timeout = NULL;
  1897.         }
  1898.     
  1899.         cl_start_compositor_timeouts(compositor);
  1900.     }
  1901.  
  1902.     UNLOCK_COMPOSITOR(compositor);
  1903. }
  1904.     
  1905. int32 
  1906. CL_GetCompositorXOffset(CL_Compositor *compositor)
  1907. {
  1908.     XP_ASSERT(compositor);
  1909.     
  1910.     if (!compositor)
  1911.         return 0;
  1912.  
  1913.     return compositor->x_offset;
  1914. }
  1915.  
  1916. int32 
  1917. CL_GetCompositorYOffset(CL_Compositor *compositor)
  1918. {
  1919.     XP_ASSERT(compositor);
  1920.     
  1921.     if (!compositor)
  1922.         return 0;
  1923.  
  1924.     return compositor->y_offset;
  1925. }
  1926.  
  1927. void CL_GetCompositorWindowSize(CL_Compositor *compositor,
  1928.                                 XP_Rect *window_size)
  1929. {
  1930.     XP_ASSERT(compositor);
  1931.     XP_ASSERT(window_size);
  1932.     
  1933.     if (!compositor || !window_size)
  1934.         return;
  1935.  
  1936.     LOCK_COMPOSITOR(compositor);
  1937.     *window_size = compositor->window_size;
  1938.     UNLOCK_COMPOSITOR(compositor);
  1939. }
  1940.  
  1941. static PRBool
  1942. cl_build_containment_list(CL_Compositor *compositor, CL_Layer *layer,
  1943.                           int32 which_list)
  1944. {
  1945.     int32 index = 0;
  1946.     CL_EventContainmentList *list = 
  1947.         &compositor->event_containment_lists[which_list];
  1948.  
  1949.     while (layer) {
  1950.         /* 
  1951.          * XXX We're assuming here that we don't have to do anything
  1952.          * special for Win16, since the depth of the layer tree will
  1953.          * hopefully not be > 8k (i.e. 32K segment boundary/4 bytes 
  1954.          * per pointer). Watch me eat my words one day.
  1955.          */
  1956.         if (index >= list->list_size) {
  1957.             list->list_size += CL_CONTAINMENT_LIST_INCREMENT;
  1958.             list->layer_list = XP_REALLOC(list->layer_list, list->list_size);
  1959.             if (list->layer_list == NULL)
  1960.                 return PR_FALSE;
  1961.         }
  1962.  
  1963.         list->layer_list[index++] = layer;
  1964.         layer = CL_GetLayerParent(layer);
  1965.     } 
  1966.  
  1967.     list->list_head = index-1;
  1968.  
  1969.     return PR_TRUE;
  1970. }
  1971.  
  1972. /*
  1973.  * This function checks for a change in either mouse or keyboard focus.
  1974.  * For mouse events, the focus has changed if the last layer to get
  1975.  * mouse events is different from the current one. In that case, we
  1976.  * build a containment list for the two layers. A containment list is
  1977.  * just a glorified name for a list consisting of the path from the
  1978.  * root of the layer tree down to the layer. Consider the following
  1979.  * example where layer C is the old mouse grabber and layer E the new
  1980.  * one.
  1981.  *                           root
  1982.  *                            /\
  1983.  *                           /  ...
  1984.  *                          A
  1985.  *                          |
  1986.  *                          B 
  1987.  *                         / \
  1988.  *                        C   D
  1989.  *                            |
  1990.  *                            E
  1991.  *            
  1992.  * In this case the containment list for layer C is root-A-B-C and the
  1993.  * containment list for layer E is root-A-B-D-E. We trace down both 
  1994.  * lists till we reach a point where there is a divergence. In this 
  1995.  * example, this point is below layer B. For the sub-tree rooted at B
  1996.  * that holds the old mouse grabber (layer C) we send MOUSE_LEAVE events
  1997.  * and for the sub-tree that holds the new mouse grabber (layer E) we
  1998.  * send MOUSE_ENTER events. This ensures that MOUSE_LEAVE and MOUSE_ENTER
  1999.  * events are sent for to all layers for which leaving and entering has
  2000.  * happened.
  2001.  */
  2002. static void
  2003. cl_check_focus_change(CL_Compositor *compositor, CL_Layer *new_grabber, 
  2004.                       CL_Event *mouse_event)
  2005. {    
  2006.     PRBool mouse_enter_occured = PR_FALSE;
  2007.  
  2008.     if (new_grabber != compositor->last_mouse_event_grabber) {
  2009.         CL_Event crossing_event;
  2010.         CL_Layer *last_grabber = compositor->last_mouse_event_grabber;
  2011.         int32 old_list_num = compositor->last_containment_list;
  2012.         int32 new_list_num = CL_NEXT_CONTAINMENT_LIST(old_list_num);
  2013.         int32 old_list_index, new_list_index;
  2014.         CL_EventContainmentList *old_list, *new_list;
  2015.  
  2016.         old_list = &compositor->event_containment_lists[old_list_num];
  2017.         new_list = &compositor->event_containment_lists[new_list_num];
  2018.         
  2019.         /* Build the containment list for the new mouse grabber */
  2020.         if (!cl_build_containment_list(compositor, 
  2021.                                        new_grabber, 
  2022.                                        new_list_num))
  2023.             return;
  2024.         
  2025.         old_list_index = old_list->list_head;
  2026.         new_list_index = new_list->list_head;
  2027.  
  2028.         /* 
  2029.          * Starting from the root, we trace downward in the tree, until
  2030.          * we find a divergence in the path.
  2031.          */
  2032.         while ((old_list_index >= 0) && (new_list_index >= 0) &&
  2033.                (old_list->layer_list[old_list_index] == 
  2034.                 new_list->layer_list[new_list_index])) {
  2035.             old_list_index--;
  2036.             new_list_index--;
  2037.         }
  2038.                
  2039.         crossing_event.x = crossing_event.y = 0;
  2040.         
  2041.         /* 
  2042.          * Send a mouse leave event to all layers that the mouse
  2043.          * has moved out of. 
  2044.          */
  2045.         while (old_list_index >= 0) {
  2046.             CL_Layer *layer = old_list->layer_list[old_list_index];
  2047.             
  2048.             if (layer && (layer->vtable.event_handler_func != NULL)) {
  2049.                 crossing_event.type = CL_EVENT_MOUSE_LEAVE;
  2050.                 crossing_event.which = (uint32)new_grabber;
  2051.                 crossing_event.fe_event = NULL;
  2052.                 crossing_event.x = mouse_event->x;
  2053.                 crossing_event.y = mouse_event->y;
  2054.                 crossing_event.modifiers = 0;
  2055.                 (*layer->vtable.event_handler_func)(layer, &crossing_event);
  2056.             }
  2057.             old_list_index--;
  2058.         }
  2059.         
  2060.         
  2061.         /* 
  2062.          * Send a mouse enter to all the new layers into which the mouse
  2063.          * has moved.
  2064.          */
  2065.         while (new_list_index >= 0) 
  2066.         {
  2067.             CL_Layer *layer = new_list->layer_list[new_list_index];
  2068.             
  2069.             if (layer && (layer->vtable.event_handler_func != NULL)) {
  2070.                 crossing_event.type = CL_EVENT_MOUSE_ENTER;
  2071.                 crossing_event.which = (uint32)last_grabber;
  2072.                 crossing_event.fe_event = NULL;
  2073.                 crossing_event.x = mouse_event->x;
  2074.                 crossing_event.y = mouse_event->y;
  2075.                 crossing_event.modifiers = 0;
  2076.                 (*layer->vtable.event_handler_func)(layer, &crossing_event);
  2077.                 mouse_enter_occured = PR_TRUE;
  2078.             }
  2079.             new_list_index--;
  2080.         }
  2081.  
  2082.         compositor->last_containment_list = new_list_num;
  2083.         compositor->last_mouse_event_grabber = new_grabber;
  2084.     }
  2085.   
  2086.     /* 
  2087.      * Check for a keyboard focus change, depending on the policy
  2088.      */
  2089.     if ((((compositor->focus_policy == CL_FOCUS_POLICY_CLICK) &&
  2090.           (mouse_event->type == CL_EVENT_MOUSE_BUTTON_DOWN) &&
  2091.           (mouse_event->which == 1)) ||
  2092.          ((compositor->focus_policy == CL_FOCUS_POLICY_MOUSE_ENTER) &&
  2093.           mouse_enter_occured))  &&
  2094.         (new_grabber != compositor->key_event_grabber)) {
  2095.         CL_Event keyboard_focus_event;
  2096.         CL_Layer *last_grabber = compositor->key_event_grabber;
  2097.         PRBool accepted = PR_TRUE;
  2098.        
  2099.         keyboard_focus_event.x = keyboard_focus_event.y
  2100.                 = keyboard_focus_event.modifiers = 0;
  2101.         
  2102.         /* Tell the new guy that he's gained focus */
  2103.         if (new_grabber &&
  2104.             (new_grabber->vtable.event_handler_func != NULL)){
  2105.             keyboard_focus_event.type = CL_EVENT_KEY_FOCUS_GAINED;
  2106.             keyboard_focus_event.which = (uint32)last_grabber;
  2107.             keyboard_focus_event.fe_event = NULL;
  2108.             accepted = (*new_grabber->vtable.event_handler_func)(new_grabber,
  2109.                                                       &keyboard_focus_event);
  2110.         }
  2111.  
  2112.         if (accepted) {
  2113.             /* Tell the old event focus holder that it's lost focus */
  2114.             if (last_grabber &&
  2115.                 (last_grabber->vtable.event_handler_func != NULL)){
  2116.                 keyboard_focus_event.type = CL_EVENT_KEY_FOCUS_LOST;
  2117.                 keyboard_focus_event.which = (uint32)new_grabber;
  2118.                 keyboard_focus_event.fe_event = NULL;
  2119.                 (*last_grabber->vtable.event_handler_func)(last_grabber, 
  2120.                                                         &keyboard_focus_event);
  2121.             }
  2122.  
  2123.             compositor->key_event_grabber = new_grabber;
  2124.         }
  2125.     }
  2126. }
  2127.  
  2128.  
  2129. static PRBool 
  2130. cl_front_to_back_event_dispatch(CL_Compositor *compositor, CL_Layer *layer,
  2131.                                 CL_Event *event)
  2132. {
  2133.     CL_Layer *child;
  2134.     PRBool event_grabbed = PR_FALSE;
  2135.     int32 old_gen_id;
  2136.  
  2137.     old_gen_id = compositor->gen_id;
  2138.     
  2139.     if (!layer->hidden) {
  2140.         /* 
  2141.          * First we ask the children if they're interested.
  2142.          * Stop if one of them grabs the event.
  2143.          */
  2144.         for (child = layer->top_child; 
  2145.              child && !event_grabbed; 
  2146.              child = child->sib_below) {
  2147.             event_grabbed = cl_front_to_back_event_dispatch(compositor, 
  2148.                                                             child, event);
  2149.         }
  2150.         
  2151.         /* 
  2152.          * Now check if the event occurred within this layer.
  2153.          * If so, call the event handler if one exists 
  2154.          */
  2155.         if (!event_grabbed &&
  2156.             XP_PointInRect(&layer->clipped_bbox, event->x, event->y) &&
  2157.             (layer->vtable.event_handler_func != NULL)) {
  2158.  
  2159.             event->x -= layer->x_origin;
  2160.             event->y -= layer->y_origin;
  2161.  
  2162.             event_grabbed = (*layer->vtable.event_handler_func)(layer, event);
  2163.  
  2164.             /*
  2165.              * If something in the event handler caused the gen_id to
  2166.              * fail, then we just bail out of here and hope that we
  2167.              * do nothing else that will access the old state of the
  2168.              * compositor.
  2169.              */
  2170.             if (compositor->gen_id != old_gen_id)
  2171.                 return PR_TRUE;
  2172.             
  2173.             /* 
  2174.              * Check for mouse entering/leaving for layers. If
  2175.              * the current event grabber (for mouse events) is not the 
  2176.              * same as the last one, we synthesize the appropriate event.
  2177.              */
  2178.             if (event_grabbed && CL_IS_MOUSE_EVENT(event))
  2179.                 cl_check_focus_change(compositor, layer, event);
  2180.  
  2181.             event->x += layer->x_origin;
  2182.             event->y += layer->y_origin;
  2183.         }
  2184.  
  2185.         return event_grabbed;
  2186.     }
  2187.     
  2188.     return PR_FALSE;
  2189. }
  2190.  
  2191. /* Dispatch an event to the correct layer */
  2192. PRBool
  2193. CL_DispatchEvent(CL_Compositor *compositor, CL_Event *event)
  2194. {
  2195.     CL_Layer *layer;
  2196.     int32 old_gen_id;
  2197.  
  2198.     XP_ASSERT(compositor);
  2199.     XP_ASSERT(event);
  2200.  
  2201.     if (!compositor || !event || !compositor->root)
  2202.         return PR_FALSE;
  2203.  
  2204.     if (event->type == CL_EVENT_MOUSE_MOVE) {
  2205.         compositor->last_mouse_x = event->x;
  2206.         compositor->last_mouse_y = event->y;
  2207.         compositor->last_mouse_button = event->which;
  2208.     }
  2209.     else if (event->type == CL_EVENT_MOUSE_BUTTON_DOWN) 
  2210.         compositor->last_mouse_button = event->which;
  2211.  
  2212.     old_gen_id = compositor->gen_id;
  2213.            
  2214.     if (compositor->mouse_event_grabber && CL_IS_MOUSE_EVENT(event)) {
  2215.         layer = compositor->mouse_event_grabber;
  2216.         if (layer->vtable.event_handler_func) {
  2217.             PRBool ret;
  2218.             
  2219.             event->x -= layer->x_origin;
  2220.             event->y -= layer->y_origin;
  2221.             ret = ((*layer->vtable.event_handler_func)(layer, event));
  2222.  
  2223.             if (compositor->gen_id != old_gen_id)
  2224.                 return ret;
  2225.  
  2226.             /* Check for a focus change */
  2227.             if (ret)
  2228.                 cl_check_focus_change(compositor, layer, event);
  2229.  
  2230.             return ret;
  2231.         }
  2232.     }
  2233.     else if (compositor->key_event_grabber && CL_IS_KEY_EVENT(event)) {
  2234.         layer = compositor->key_event_grabber;
  2235.         if (layer->vtable.event_handler_func) {
  2236.             event->x -= layer->x_origin;
  2237.             event->y -= layer->y_origin;
  2238.             return ((*layer->vtable.event_handler_func)(layer, event));
  2239.         }
  2240.     }
  2241.     else
  2242.         return cl_front_to_back_event_dispatch(compositor,
  2243.                                                compositor->root,
  2244.                                                event);
  2245.  
  2246.     return PR_FALSE;
  2247. }
  2248.  
  2249. /* All mouse events go to this layer. If layer is NULL, stop grabbing */
  2250. PRBool
  2251. CL_GrabMouseEvents(CL_Compositor *compositor, CL_Layer *layer)
  2252. {
  2253.     XP_ASSERT(compositor);
  2254.     
  2255.     if (!compositor)
  2256.         return PR_FALSE;
  2257.  
  2258.     compositor->mouse_event_grabber = layer;
  2259.     return PR_TRUE;
  2260. }
  2261.  
  2262. /* All key events go to this layer. If layer is NULL, stop grabbing */
  2263. PRBool
  2264. CL_GrabKeyEvents(CL_Compositor *compositor, CL_Layer *layer)
  2265. {
  2266.     CL_Event keyboard_focus_event;
  2267.     CL_Layer *last_grabber, *new_grabber;
  2268.     PRBool accepted = PR_TRUE;
  2269.  
  2270.     XP_ASSERT(compositor);
  2271.     
  2272.     if (!compositor)
  2273.         return PR_FALSE;
  2274.  
  2275.     keyboard_focus_event.x = keyboard_focus_event.y = 0;
  2276.     
  2277.     last_grabber = compositor->key_event_grabber;
  2278.     new_grabber = layer;
  2279.  
  2280.     if (new_grabber &&
  2281.         (new_grabber->vtable.event_handler_func != NULL)){
  2282.         keyboard_focus_event.type = CL_EVENT_KEY_FOCUS_GAINED;
  2283.         keyboard_focus_event.which = (uint32)last_grabber;
  2284.         keyboard_focus_event.fe_event = NULL;
  2285.         accepted = (*new_grabber->vtable.event_handler_func)(new_grabber,
  2286.                                                        &keyboard_focus_event);
  2287.     }
  2288.  
  2289.     if (accepted) {
  2290.         if (last_grabber &&
  2291.             (last_grabber->vtable.event_handler_func != NULL)){
  2292.             keyboard_focus_event.type = CL_EVENT_KEY_FOCUS_LOST;
  2293.             keyboard_focus_event.which = (uint32)new_grabber;
  2294.             keyboard_focus_event.fe_event = NULL;
  2295.             (*last_grabber->vtable.event_handler_func)(last_grabber, 
  2296.                                                        &keyboard_focus_event);
  2297.         }
  2298.  
  2299.         compositor->key_event_grabber = layer;
  2300.         return PR_TRUE;
  2301.     }
  2302.     else
  2303.         return PR_FALSE;
  2304. }
  2305.  
  2306. /* Returns PR_TRUE if layer is the mouse event grabber. */
  2307. PRBool
  2308. CL_IsMouseEventGrabber(CL_Compositor *compositor, CL_Layer *layer)
  2309. {
  2310.     XP_ASSERT(compositor);
  2311.     
  2312.     if (!compositor)
  2313.         return PR_FALSE;
  2314.     
  2315.     return (PRBool)(compositor->mouse_event_grabber == layer);
  2316. }
  2317.  
  2318. /* Returns PR_TRUE if layer is the key event grabber. */
  2319. PRBool
  2320. CL_IsKeyEventGrabber(CL_Compositor *compositor, CL_Layer *layer)
  2321. {
  2322.     XP_ASSERT(compositor);
  2323.     
  2324.     if (!compositor)
  2325.         return PR_FALSE;
  2326.     
  2327.     return (PRBool)(compositor->key_event_grabber == layer);
  2328. }
  2329.  
  2330. /* Returns PR_TRUE if layer is the key event grabber. */
  2331. CL_Layer *
  2332. CL_GetKeyEventGrabber(CL_Compositor *compositor)
  2333. {
  2334.     XP_ASSERT(compositor);
  2335.     
  2336.     if (!compositor)
  2337.         return NULL;
  2338.     
  2339.     return (compositor->key_event_grabber);
  2340. }
  2341.  
  2342. void
  2343. CL_SetKeyboardFocusPolicy(CL_Compositor *compositor, 
  2344.                           CL_KeyboardFocusPolicy focus_policy)
  2345. {
  2346.     XP_ASSERT(compositor);
  2347.     
  2348.     if (!compositor)
  2349.         return;
  2350.     
  2351.     compositor->focus_policy = focus_policy;
  2352. }
  2353.  
  2354. void 
  2355. CL_SetCompositorDrawingMethod(CL_Compositor *compositor,
  2356.                               CL_DrawingMethod method)
  2357. {
  2358.     XP_ASSERT(compositor);
  2359.     
  2360.     if (!compositor)
  2361.         return;
  2362.     
  2363.     compositor->back_to_front_only = 
  2364.         (method == CL_DRAWING_METHOD_BACK_TO_FRONT_ONLY);
  2365. }
  2366.  
  2367.  
  2368. /* Called when a layer is added to the layer tree */
  2369. void
  2370. cl_LayerAdded(CL_Compositor *compositor, CL_Layer *layer)
  2371. {
  2372.     XP_ASSERT(compositor);
  2373.     XP_ASSERT(layer);
  2374.  
  2375.     cl_ParentChanged(layer);
  2376.  
  2377.     /* If this child is visible, ask the compositor to update its area */
  2378.     if (layer->visible)
  2379.         cl_UpdateLayer(layer, PR_FALSE);
  2380. }
  2381.  
  2382. void
  2383. cl_LayerDestroyed(CL_Compositor *compositor, CL_Layer *layer)
  2384. {
  2385.     XP_ASSERT(compositor);
  2386.     XP_ASSERT(layer);
  2387.  
  2388.     if (!compositor || !layer)
  2389.         return;
  2390.     
  2391.     if (layer == compositor->mouse_event_grabber)
  2392.         compositor->mouse_event_grabber = NULL;
  2393.     if (layer == compositor->key_event_grabber)
  2394.         compositor->key_event_grabber = NULL;
  2395.     if (layer == compositor->last_mouse_event_grabber) {
  2396.         compositor->event_containment_lists[compositor->last_containment_list].list_head = -1;
  2397.         compositor->last_mouse_event_grabber = NULL;
  2398.     }
  2399.  
  2400.     compositor->gen_id++;
  2401. }
  2402.  
  2403. /* Called when a layer is removed from the layer tree */
  2404. void
  2405. cl_LayerRemoved(CL_Compositor *compositor, CL_Layer *layer)
  2406. {
  2407.     XP_ASSERT(compositor);
  2408.     XP_ASSERT(layer);
  2409.  
  2410.     if (!compositor || !layer)
  2411.         return;
  2412.  
  2413.     /* If this child was visible, ask the compositor
  2414.        to update the area it formerly occupied. */
  2415.     if (layer->visible)
  2416.         cl_UpdateLayer(layer, PR_FALSE);
  2417.  
  2418.     if (layer == compositor->last_mouse_event_grabber) {
  2419.         compositor->event_containment_lists[compositor->last_containment_list].list_head = -1;
  2420.         compositor->last_mouse_event_grabber = NULL;
  2421.     }
  2422. }
  2423.  
  2424. void
  2425. cl_LayerMoved(CL_Compositor *compositor, CL_Layer *layer)
  2426. {
  2427.  
  2428.     /* The auto-generation of mousemoves is playing havoc with the
  2429.      * REAL mouse moves.  Commented out until further notice. */
  2430.     if (0) {
  2431.     /*
  2432.      * If the layer that grabbed mouse events has moved, the
  2433.      * movement is equivalent to a mouse move.
  2434.      */
  2435.     if (compositor && compositor->mouse_event_grabber == layer) {
  2436.         CL_Event event;
  2437.         
  2438.         event.type = CL_EVENT_MOUSE_MOVE;
  2439.         event.fe_event = NULL;
  2440.         event.x = compositor->last_mouse_x - layer->x_offset;
  2441.         event.y = compositor->last_mouse_y - layer->y_offset;
  2442.         event.which = compositor->last_mouse_button;
  2443.  
  2444.         if (layer->vtable.event_handler_func)
  2445.         (*layer->vtable.event_handler_func)(layer, &event);
  2446.     }
  2447.     }
  2448. }
  2449.