<commit_before>#include "e.h"
#include "e_mod_main.h"
#include "e_mod_comp.h"
#include "e_mod_comp_update.h"
#include "config.h"

//////////////////////////////////////////////////////////////////////////
//
// TODO (no specific order):
//   1. abstract evas object and compwin so we can duplicate the object N times
//      in N canvases - for winlist, everything, pager etc. too
//   2. implement "unmapped composite cache" -> N pixels worth of unmapped
//      windows to be fully composited. only the most active/recent.
//   3. for unmapped windows - when window goes out of unmapped comp cache
//      make a miniature copy (1/4 width+height?) and set property on window
//      with pixmap id
//   6. other engine fast-paths (gl specifically)!
//   8. transparenty property
//   9. shortcut lots of stuff to draw inside the compositor - shelf,
//      wallpaper, efm - hell even menus and anything else in e (this is what
//      e18 was mostly about)
//  10. fullscreen windows need to be able to bypass compositing
//  11. handle root window resize!
//  
//////////////////////////////////////////////////////////////////////////

struct _E_Comp
{
   Ecore_X_Window  win;
   Ecore_Evas     *ee;
   Ecore_X_Window  ee_win;
   Evas           *evas;
   E_Manager      *man;
   Eina_Inlist    *wins;
   Eina_List      *updates;
   Ecore_Animator *render_animator;
   Ecore_Job      *update_job;
   int             render_overflow;

   Eina_Bool       gl : 1;
   Eina_Bool       grabbed : 1;
};

struct _E_Comp_Win
{
   EINA_INLIST;
   
   E_Comp         *c; // parent compositor
   Ecore_X_Window  win; // raw window - for menus etc.
   E_Border       *bd; // if its a border - later
   E_Popup        *pop; // if its a popup - later
   E_Menu         *menu; // if it is a menu - later
   int             x, y, w, h; // geometry
   int             pw, ph; // pixmap w/h
   int             border; // border width
   Ecore_X_Pixmap  pixmap; // the compositing pixmap
   Ecore_X_Damage  damage; // damage region
   Ecore_X_Visual  vis; // window visual
   int             depth; // window depth
   Evas_Object    *obj; // composite object
   Evas_Object    *shobj; // shadow object
   Ecore_X_Image  *xim; // x image - software fallback
   E_Update       *up; // update handler
   E_Object_Delfn *dfn; // delete function handle for objects being tracked
   Ecore_X_Sync_Counter counter; // sync counter for syncronised drawing
   Ecore_Timer    *update_timeout; // max time between damage and "done" event
   
   Eina_List      *effects;

   Ecore_X_Pixmap  cache_pixmap; // the cached pixmap (1/nth the dimensions)
   int             cache_w, cache_h; // cached pixmap size
   int             update_count; // how many updates have happend to this win
   double          last_visible_time; // last time window was visible
   double          last_draw_time; // last time window was damaged
   
   Eina_Bool       visible : 1; // is visible
   Eina_Bool       input_only : 1; // is input_only
   Eina_Bool       override : 1; // is override-redirect
   Eina_Bool       argb : 1; // is argb
   Eina_Bool       shaped : 1; // is shaped
   Eina_Bool       update : 1; // has updates to fetch
   Eina_Bool       redirected : 1; // has updates to fetch
   Eina_Bool       shape_changed : 1; // shape changed
   Eina_Bool       native : 1; // native
   Eina_Bool       drawme : 1; // drawme flag fo syncing rendering
   Eina_Bool       invalid : 1; // invalid depth used - just use as marker
   Eina_Bool       defer_hide : 1; // flag to get hide to work on deferred hide
   Eina_Bool       delete_me : 1;
};

static Eina_List *handlers = NULL;
static Eina_List *compositors = NULL;
static Eina_Hash *windows = NULL;
static Eina_Hash *borders = NULL;
static Eina_Hash *damages = NULL;

//////////////////////////////////////////////////////////////////////////
// not working yet.
typedef struct _Effect Effect;

struct _Effect
{
   E_Comp_Win *cw;
   Ecore_Animator *animator;
   double start, len;
   double src, dst;
   int type;
};

#define EFFECT_SHOW 1
#define EFFECT_HIDE 2
#define EFFECT_MOVE 3

static Effect *
_e_mod_comp_effect_add(E_Comp_Win *cw, int (*func) (void *data), double len, int type)
{
   Effect *ef;
   
   ef = calloc(1, sizeof(Effect));
   ef->animator = ecore_animator_add(func, ef);
   ef->start = ecore_loop_time_get();
   ef->len = len;
   ef->cw = cw;
   ef->type = type;
   cw->effects = eina_list_append(cw->effects, ef);
   return ef;
}

static void
_e_mod_comp_effect_del(Effect *ef)
{
   ef->cw->effects = eina_list_remove(ef->cw->effects, ef);
   ecore_animator_del(ef->animator);
   free(ef);
}

static Effect *
_e_mod_comp_win_effect_find(E_Comp_Win *cw, int type)
{
   Eina_List *l;
   Effect *ef;
   
   // fixme: use hash if compositors list > 4
   EINA_LIST_FOREACH(cw->effects, l, ef)
     {
        if (ef->type == type) return ef;
     }
   return NULL;
}

static void _e_mod_comp_win_hide(E_Comp_Win *cw); // quick and dirty
static void _e_mod_comp_win_del(E_Comp_Win *cw); // quick and dirty
static void _e_mod_comp_win_render_queue(E_Comp_Win *cw); // quick and dirty

static int
_e_mod_comp_ef_cb_fade_to(void *data)
{
   Effect *ef = data;
   double t = (ecore_loop_time_get() - ef->start) / ef->len;
   E_Comp_Win *cw = ef->cw;
   double v;
   int col;
   if (t > 1.0) t = 1.0;
   
   v = ef->src + ((ef->dst - ef->src) * t);
   col = 255.0 * v;
   evas_object_color_set(cw->obj, col, col, col, col);
   if (ef->cw->shobj)
     evas_object_color_set(cw->shobj, col, col, col, col);
   if (t >= 1.0)
     {
        evas_object_color_set(cw->obj, 255, 255, 255, 255);
        _e_mod_comp_effect_del(ef);
        _e_mod_comp_win_render_queue(cw);
        if (!cw->effects)
          {
             if (cw->defer_hide)
               {
                  cw->defer_hide = 0;
                  _e_mod_comp_win_hide(cw);
               }
             if (cw->delete_me)
               _e_mod_comp_win_del(cw);
          }
        return 0;
     }
   return 1;
}

static void
_e_mod_comp_win_show_effects_add(E_Comp_Win *cw)
{
   Effect *ef;
   
   do
     {
        ef = _e_mod_comp_win_effect_find(cw, EFFECT_SHOW);
        if (ef) _e_mod_comp_effect_del(ef);
     }
   while (ef);
   
   do
     {
        ef = _e_mod_comp_win_effect_find(cw, EFFECT_HIDE);
        if (ef) _e_mod_comp_effect_del(ef);
     }
   while (ef);
   
   if (_comp_mod->conf->effect_fade)
     {
        ef = _e_mod_comp_effect_add(cw, _e_mod_comp_ef_cb_fade_to, 0.2, EFFECT_SHOW);
        ef->src = 0.0;
        ef->dst = 1.0;
        cw->defer_hide = 0;
        _e_mod_comp_ef_cb_fade_to(ef);
     }
}

static void
_e_mod_comp_win_hide_effects_add(E_Comp_Win *cw)
{
   Effect *ef;
   
   do
     {
        ef = _e_mod_comp_win_effect_find(cw, EFFECT_SHOW);
        if (ef) _e_mod_comp_effect_del(ef);
     }
   while (ef);
   
   do
     {
        ef = _e_mod_comp_win_effect_find(cw, EFFECT_HIDE);
        if (ef) _e_mod_comp_effect_del(ef);
     }
   while (ef);
   
   if (_comp_mod->conf->effect_fade)
     {
        int a;
        
        ef = _e_mod_comp_effect_add(cw, _e_mod_comp_ef_cb_fade_to, 0.2, EFFECT_HIDE);
        evas_object_color_get(cw->obj, NULL, NULL, NULL, &a);
        ef->src = (double)a / 255.0;
        ef->dst = 0.0;
        cw->defer_hide = 1;
        _e_mod_comp_ef_cb_fade_to(ef);
     }
}

static void
_e_mod_comp_win_move_effects_add(E_Comp_Win *cw)
{
}

//////////////////////////////////////////////////////////////////////////

#if 0
#define DBG(f, x...) printf(f, ##x)
#else
#define DBG(f, x...)
#endif

static void _e_mod_comp_render_queue(E_Comp *c);
static void _e_mod_comp_win_damage(E_Comp_Win *cw, int x, int y, int w, int h, Eina_Bool dmg);

static void
_e_mod_comp_win_shape_rectangles_apply(E_Comp_Win *cw)
{
   Ecore_X_Rectangle *rects;
   int num, i;
   
   DBG("SHAPE [0x%x] change\n", cw->win);
   rects = ecore_x_window_shape_rectangles_get(cw->win, &num);
   if ((rects) && (num == 1))
     {
        DBG("SHAPE [0x%x] rect 1\n", cw->win);
        if ((rects[0].x == 0) &&
            (rects[0].y == 0) &&
            (rects[0].width == cw->w) &&
            (rects[0].height == cw->h))
          {
             DBG("SHAPE [0x%x] rect solid\n", cw->win);
             free(rects);
             rects = NULL;
          }
     }
   if (rects)
     {
        unsigned int *pix, *p;
        unsigned char *spix, *sp;
        int w, h, px, py;
        
        cw->shaped = 1;
        evas_object_image_size_get(cw->obj, &w, &h);
        if ((w > 0) && (h > 0))
          {
             pix = evas_object_image_data_get(cw->obj, 1);
             spix = calloc(w * h, sizeof(unsigned char));
             if (spix)
               {
                  DBG("SHAPE [0x%x] rects %i\n", cw->win, num);
                  for (i = 0; i < num; i++)
                    {
                       int rx, ry, rw, rh;
                       
                       rx = rects[i].x; ry = rects[i].y;
                       rw = rects[i].width; rh = rects[i].height;
                       E_RECTS_CLIP_TO_RECT(rx, ry, rw, rh, 0, 0, w, h);
                       sp = spix + (w * ry) + rx;
                       for (py = 0; py < rh; py++)
                         {
                            for (px = 0; px < rw; px++)
                              {
                                 *sp = 1; sp++;
                              }
                            sp += w - rw;
                         }
                    }
                  sp = spix;
                  p = pix;
                  for (py = 0; py < h; py++)
                    {
                       for (px = 0; px < w; px++)
                         {
                            if (*sp) *p |= 0xff000000;
                            else *p = 0x00000000;
                            sp++;
                            p++;
                         }
                    }
                  free(spix);
               }
             evas_object_image_data_set(cw->obj, pix);
             evas_object_image_alpha_set(cw->obj, 1);
             evas_object_image_data_update_add(cw->obj, 0, 0, w, h);
          }
        free(rects);
     }
   else
     {
        cw->shaped = 0;
        evas_object_image_alpha_set(cw->obj, 0);
        // dont need to fix alpha chanel as blending 
        // should be totally off here regardless of
        // alpha channe; content
     }
}

static void
_e_mod_comp_win_update(E_Comp_Win *cw)
{
   E_Update_Rect *r;
   int i/*, new_pixmap = 0*/;
   
   ecore_x_grab();
   cw->update = 0;
   if (!cw->pixmap)
     {
        cw->pixmap = ecore_x_composite_name_window_pixmap_get(cw->win);
        if (cw->pixmap)
          ecore_x_pixmap_geometry_get(cw->pixmap, NULL, NULL, &(cw->pw), &(cw->ph));
        else
          {
             cw->pw = 0;
             cw->ph = 0;
          }
        DBG("REND [0x%x] pixmap = [0x%x], %ix%i\n", cw->win, cw->pixmap, cw->pw, cw->ph);
        if ((cw->pw <= 0) || (cw->ph <= 0))
          {
             if (cw->native)
               {
                  DBG("  [0x%x] free native\n", cw->win);
                  evas_object_image_native_surface_set(cw->obj, NULL);
                  cw->native = 0;
               }
             if (cw->pixmap)
               {
                  DBG("  [0x%x] free pixmap\n", cw->win);
                  ecore_x_pixmap_free(cw->pixmap);
                  cw->pixmap = 0;
               }
             cw->pw = 0;
             cw->ph = 0;
          }
//        else
//          new_pixmap = 1;
        cw->native = 0;
     }
   if (!((cw->pw > 0) && (cw->ph > 0)))
     {
        ecore_x_ungrab();
        return;
     }

   if ((cw->pw != cw->w) || (cw->ph != cw->h))
     {
        ecore_x_window_geometry_get(cw->win, 
                                    &(cw->x), &(cw->y), 
                                    &(cw->w), &(cw->h));
        evas_object_move(cw->obj, cw->x, cw->y);
        if (cw->shobj)
          {
             evas_object_move(cw->shobj, cw->x, cw->y);
          }
        evas_object_resize(cw->obj, 
                           cw->w + (cw->border * 2), 
                           cw->h + (cw->border * 2));
        if (cw->shobj)
          {
             evas_object_resize(cw->shobj, 
                                cw->w + (cw->border * 2),
                                cw->h + (cw->border * 2));
          }
     }
   ecore_x_ungrab();
   
   if ((cw->c->gl) && (_comp_mod->conf->texture_from_pixmap) &&
       (!cw->shaped) && (!cw->shape_changed))
     {
//y        if (new_pixmap)
//y          e_mod_comp_update_add(cw->up, 0, 0, cw->pw, cw->ph);
        
//        DBG("DEBUG - pm now %x\n", ecore_x_composite_name_window_pixmap_get(cw->win));
        evas_object_image_size_set(cw->obj, cw->pw, cw->ph);
        if (!cw->native)
          {
             Evas_Native_Surface ns;
             
             ns.data.x11.visual = cw->vis;
             ns.data.x11.pixmap = cw->pixmap;
             evas_object_image_native_surface_set(cw->obj, &ns);
             DBG("NATIVE [0x%x] %x %ix%i\n", cw->win, cw->pixmap, cw->pw, cw->ph);
             cw->native = 1;
          }
        r = e_mod_comp_update_rects_get(cw->up);
        if (r) 
          {
             e_mod_comp_update_clear(cw->up);
             for (i = 0; r[i].w > 0; i++)
               {
                  int x, y, w, h;
                       
                  x = r[i].x; y = r[i].y;
                  w = r[i].w; h = r[i].h;
                  DBG("UPDATE [0x%x] pm [0x%x] %i %i %ix%i\n", cw->win, cw->pixmap, x, y, w, h);
                  evas_object_image_data_update_add(cw->obj, x, y, w, h);
               }
             free(r);
          }
        else
          cw->update = 1;
     }
   else
     {
        if (!cw->xim)
          {
             if (cw->xim = ecore_x_image_new(cw->pw, cw->ph, cw->vis, cw->depth))
               {
//y                  e_mod_comp_update_add(cw->up, 0, 0, cw->pw, cw->ph);
               }
          }
        r = e_mod_comp_update_rects_get(cw->up);
        if (r) 
          {
             if (cw->xim)
               {
                  unsigned int *pix;
                  
                  pix = ecore_x_image_data_get(cw->xim, NULL, NULL, NULL);
                  evas_object_image_data_set(cw->obj, pix);
                  evas_object_image_size_set(cw->obj, cw->pw, cw->ph);
                  
                  e_mod_comp_update_clear(cw->up);
                  for (i = 0; r[i].w > 0; i++)
                    {
                       unsigned int *pix;
                       int x, y, w, h;
                       
                       x = r[i].x; y = r[i].y;
                       w = r[i].w; h = r[i].h;
                       ecore_x_image_get(cw->xim, cw->pixmap, x, y, x, y, w, h);
                       DBG("UPDATE [0x%x] %i %i %ix%i\n", cw->win, x, y, w, h);
// why do we neeed these 2? this smells wrong
                       pix = ecore_x_image_data_get(cw->xim, NULL, NULL, NULL);
                       evas_object_image_data_set(cw->obj, pix);
                       
                       evas_object_image_data_update_add(cw->obj, x, y, w, h);
                       if (cw->shaped) cw->shape_changed = 1;
                    }
                  if ((cw->shape_changed) && (!cw->argb))
                    {
                       _e_mod_comp_win_shape_rectangles_apply(cw);
                       cw->shape_changed = 0;
                    }
               }
             free(r);
          }
        else
          cw->update = 1;
     }
   if (cw->shobj)
     {
        if (cw->shaped) evas_object_hide(cw->shobj);
     }
}

static void
_e_mod_comp_pre_swap(void *data, Evas *e)
{
   E_Comp *c = data;
   
   if (_comp_mod->conf->grab)
     {
        if (c->grabbed)
          {
             ecore_x_ungrab();
             c->grabbed = 0;
          }
     }
}

static int
_e_mod_comp_cb_update(E_Comp *c)
{
   E_Comp_Win *cw;
   Eina_List *new_updates = NULL; // for failed pixmap fetches - get them next frame
   Eina_List *update_done = NULL;

   if (_comp_mod->conf->grab)
     {
        ecore_x_grab();
        ecore_x_sync();
        c->grabbed = 1;
     }
   EINA_LIST_FREE(c->updates, cw)
     {
        if (_comp_mod->conf->efl_sync)
          {
             if (((cw->counter) && (cw->drawme)) || (!cw->counter))
               {
                  _e_mod_comp_win_update(cw);
                  if (cw->drawme)
                    update_done = eina_list_append(update_done, cw);
                  cw->drawme = 0;
               }
             else
               cw->update = 0;
          }
        else
          _e_mod_comp_win_update(cw);
        if (cw->update)
          new_updates = eina_list_append(new_updates, cw);
     }
   if (_comp_mod->conf->lock_fps)
     ecore_evas_manual_render(c->ee);
   if (_comp_mod->conf->efl_sync)
     {  
        EINA_LIST_FREE(update_done, cw)
          {
             ecore_x_sync_counter_inc(cw->counter, 1);
          }
     }
   if (_comp_mod->conf->grab)
     {
        if (c->grabbed)
          {
             c->grabbed = 0;
             ecore_x_ungrab();
          }
     }
   if (new_updates) _e_mod_comp_render_queue(c);
   c->updates = new_updates;
   c->render_overflow--;
   c->update_job = NULL;
   if (c->render_overflow == 0)
     {
        if (c->render_animator) c->render_animator = NULL;
        return 0;
     }
   return 1;
}

static void
_e_mod_comp_cb_job(void *data)
{
   _e_mod_comp_cb_update(data);
}

static int
_e_mod_comp_cb_animator(void *data)
{
   return _e_mod_comp_cb_update(data);
}

static void
_e_mod_comp_render_queue(E_Comp *c)
{
   if (_comp_mod->conf->lock_fps)
     {
        if (c->render_animator)
          {
             c->render_overflow = 10;
             return;
          }
        c->render_animator = ecore_animator_add(_e_mod_comp_cb_animator, c);
     }
   else
     {
        if (c->update_job)
          {
             ecore_job_del(c->update_job);
             c->render_overflow = 0;
          }
        c->update_job = ecore_job_add(_e_mod_comp_cb_job, c);
     }
}

static void
_e_mod_comp_win_render_queue(E_Comp_Win *cw)
{
   _e_mod_comp_render_queue(cw->c);
}

static E_Comp *
_e_mod_comp_find(Ecore_X_Window root)
{
   Eina_List *l;
   E_Comp *c;
   
   // fixme: use hash if compositors list > 4
   EINA_LIST_FOREACH(compositors, l, c)
     {
        if (c->man->root == root) return c;
     }
   return NULL;
}

static E_Comp_Win *
_e_mod_comp_win_find(Ecore_X_Window win)
{
   return eina_hash_find(windows, e_util_winid_str_get(win));
}

static E_Comp_Win *
_e_mod_comp_border_client_find(Ecore_X_Window win)
{
   return eina_hash_find(borders, e_util_winid_str_get(win));
}

static E_Comp_Win *
_e_mod_comp_win_damage_find(Ecore_X_Damage damage)
{
   return eina_hash_find(damages, e_util_winid_str_get(damage));
}

static Eina_Bool
_e_mod_comp_win_is_borderless(E_Comp_Win *cw)
{
   if (!cw->bd) return 1;
   if ((cw->bd->client.border.name) &&
       (!strcmp(cw->bd->client.border.name, "borderless")))
     return 1;
   return 0;
}

static Eina_Bool
_e_mod_comp_win_do_shadow(E_Comp_Win *cw)
{
   if (cw->shaped) return 0;
   if (cw->argb)
     {
        if (_e_mod_comp_win_is_borderless(cw)) return 0;
     }
   return 1;
}

static int
_e_mod_comp_win_damage_timeout(void *data)
{
   E_Comp_Win *cw = data;
   
   if (!cw->update)
     {
        if (cw->update_timeout)
          {
             ecore_timer_del(cw->update_timeout);
             cw->update_timeout = NULL;
          }
        cw->update = 1;
        cw->c->updates = eina_list_append(cw->c->updates, cw);
     }
   cw->drawme = 1;
   _e_mod_comp_win_render_queue(cw);
   cw->update_timeout = NULL;
   return 0;
}

static E_Comp_Win *
_e_mod_comp_win_add(E_Comp *c, Ecore_X_Window win)
{
   Ecore_X_Window_Attributes att;
   E_Comp_Win *cw;
   
   cw = calloc(1, sizeof(E_Comp_Win));
   if (!cw) return NULL;
   cw->win = win;
   // FIXME: check if bd or pop - track
   cw->c = c;
   memset((&att), 0, sizeof(Ecore_X_Window_Attributes));
   if (!ecore_x_window_attributes_get(cw->win, &att))
     {
        free(cw);
        return NULL;
     }
   if ((!att.input_only) && 
       ((att.depth != 24) && (att.depth != 32)))
     {
        printf("WARNING: window 0x%x not 24/32bpp -> %ibpp\n", cw->win, att.depth);
        cw->invalid = 1;
     }
   cw->input_only = att.input_only;
   cw->override = att.override;
   cw->vis = att.visual;
   cw->depth = att.depth;
   cw->argb = ecore_x_window_argb_get(cw->win);
   eina_hash_add(windows, e_util_winid_str_get(cw->win), cw);
   if ((!cw->input_only) && (!cw->invalid))
     {
        Ecore_X_Rectangle *rects;
        int num;
        
        cw->damage = ecore_x_damage_new(cw->win, ECORE_X_DAMAGE_REPORT_DELTA_RECTANGLES);
        eina_hash_add(damages, e_util_winid_str_get(cw->damage), cw);
        cw->shobj = edje_object_add(c->evas);
        cw->obj = evas_object_image_filled_add(c->evas);
        evas_object_image_colorspace_set(cw->obj, EVAS_COLORSPACE_ARGB8888);
        if (cw->argb) evas_object_image_alpha_set(cw->obj, 1);
        else evas_object_image_alpha_set(cw->obj, 0);
        ecore_x_window_shape_events_select(cw->win, 1);
        rects = ecore_x_window_shape_rectangles_get(cw->win, &num);
        if (rects)
          {
             if ((rects) && (num == 1)  &&
                 (rects[0].x == 0) && (rects[0].y == 0) &&
                 (rects[0].width == att.w) && (rects[0].height == att.h))
               {
                  free(rects);
                  rects = NULL;
               }
             if (rects)
               {
                  cw->shaped = 1;
                  cw->shape_changed = 1;
                  free(rects);
               }
          }
     }
   else
     {
        cw->obj = evas_object_rectangle_add(c->evas);
        evas_object_color_set(cw->obj, 0, 0, 0, 64);
     }
   c->wins = eina_inlist_append(c->wins, EINA_INLIST_GET(cw));
   cw->up = e_mod_comp_update_new();
   e_mod_comp_update_tile_size_set(cw->up, 32, 32);
   // for software:
   e_mod_comp_update_policy_set
     (cw->up, E_UPDATE_POLICY_HALF_WIDTH_OR_MORE_ROUND_UP_TO_FULL_WIDTH);
   if (((!cw->input_only) && (!cw->invalid)) && (cw->override))
     {
        cw->redirected = 1;
        ecore_x_composite_redirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
//z        _e_mod_comp_win_damage(cw, 0, 0, cw->w, cw->h, 0);
     }
   DBG("  [0x%x] add\n", cw->win);
   return cw;
}

static void
_e_mod_comp_win_del(E_Comp_Win *cw)
{
   e_mod_comp_update_free(cw->up);
   DBG("  [0x%x] del\n", cw->win);
   while (cw->effects) _e_mod_comp_effect_del(cw->effects->data);
   if (cw->update_timeout)
     {
        ecore_timer_del(cw->update_timeout);
        cw->update_timeout = NULL;
     }
   if (cw->dfn)
     {
        if (cw->bd)
          {
             eina_hash_del(borders, e_util_winid_str_get(cw->bd->client.win), cw);
             e_object_delfn_del(E_OBJECT(cw->bd), cw->dfn);
          }
        else if (cw->pop) e_object_delfn_del(E_OBJECT(cw->pop), cw->dfn);
        else if (cw->menu) e_object_delfn_del(E_OBJECT(cw->menu), cw->dfn);
        cw->dfn = NULL;
     }
   if (cw->native)
     {
        evas_object_image_native_surface_set(cw->obj, NULL);
        cw->native = 0;
     }
   if (cw->pixmap)
     {
        ecore_x_pixmap_free(cw->pixmap);
        cw->pixmap = 0;
        cw->pw = 0;
        cw->ph = 0;
     }
   if (cw->update)
     {
        cw->update = 0;
        cw->c->updates = eina_list_remove(cw->c->updates, cw);
     }
   if (cw->xim)
     {
        evas_object_image_data_set(cw->obj, NULL);
        ecore_x_image_free(cw->xim);
        cw->xim = NULL;
     }
   if (cw->obj)
     {
        evas_object_del(cw->obj);
        cw->obj = NULL;
     }
   if (cw->shobj)
     {
        evas_object_del(cw->shobj);
        cw->shobj = NULL;
     }
   eina_hash_del(windows, e_util_winid_str_get(cw->win), cw);
   if (cw->damage)
     {
        Ecore_X_Region parts;
   
        eina_hash_del(damages, e_util_winid_str_get(cw->damage), cw);
        parts = ecore_x_region_new(NULL, 0);
        ecore_x_damage_subtract(cw->damage, 0, parts);
        ecore_x_region_free(parts);
        ecore_x_damage_free(cw->damage);
        cw->damage = 0;
     }
   cw->c->wins = eina_inlist_remove(cw->c->wins, EINA_INLIST_GET(cw));
   free(cw);
}

static void
_e_mod_comp_object_del(void *data, void *obj)
{
   E_Comp_Win *cw = data;

   _e_mod_comp_win_render_queue(cw);
   if (obj == cw->bd)
     {
        eina_hash_del(borders, e_util_winid_str_get(cw->bd->client.win), cw);
        cw->bd = NULL;
        cw->counter = 0;
     }
   else if (obj == cw->pop) cw->pop = NULL;
   else if (obj == cw->menu) cw->menu = NULL;
   if (cw->dfn)
     {
        e_object_delfn_del(obj, cw->dfn);
        cw->dfn = NULL;
     }
}

static void
_e_mod_comp_win_show(E_Comp_Win *cw)
{
   if (cw->visible) return;
   cw->visible = 1;
   DBG("  [0x%x] sho ++++++++++\n", cw->win);
   if ((cw->input_only) || (cw->invalid)) return;
   if (!cw->redirected)
     {
        cw->redirected = 1;
        ecore_x_composite_redirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
//z        _e_mod_comp_win_damage(cw, 0, 0, cw->w, cw->h, 0);
     }

   // FIXME: only do this if no bd set
   // FIXME: listen for bd del events
   
   if (cw->dfn)
     {
        if (cw->bd)
          {
             eina_hash_del(borders, e_util_winid_str_get(cw->bd->client.win), cw);
             e_object_delfn_del(E_OBJECT(cw->bd), cw->dfn);
             cw->counter = 0;
          }
        else if (cw->pop) e_object_delfn_del(E_OBJECT(cw->pop), cw->dfn);
        else if (cw->menu) e_object_delfn_del(E_OBJECT(cw->menu), cw->dfn);
        cw->dfn = NULL;
     }
   
   cw->bd = NULL;
   cw->pop = NULL;
   cw->menu = NULL;
   
   cw->bd = e_border_find_by_window(cw->win);
   if (cw->bd)
     {
        Ecore_X_Sync_Counter counter;
        
        eina_hash_add(borders, e_util_winid_str_get(cw->bd->client.win), cw);
        cw->dfn = e_object_delfn_add(E_OBJECT(cw->bd), 
                                     _e_mod_comp_object_del, cw);
        if (_comp_mod->conf->efl_sync)
          {
             if (_e_mod_comp_win_is_borderless(cw) ||
                 (_comp_mod->conf->loose_sync))
               {
                  counter = ecore_x_e_comp_sync_counter_get(cw->bd->client.win);
                  if (counter)
                    {
                       cw->counter = counter;
                       ecore_x_sync_counter_inc(cw->counter, 1);
                       ecore_x_e_comp_sync_begin_send(cw->bd->client.win);
                    }
               }
             else
               {
                  ecore_x_e_comp_sync_cancel_send(cw->bd->client.win);
               }
          }
        // ref bd
     }
   else
     {
        cw->pop = e_popup_find_by_window(cw->win);
        if (cw->pop)
          {
             cw->dfn = e_object_delfn_add(E_OBJECT(cw->pop), 
                                          _e_mod_comp_object_del, cw);
             // ref pop
          }
        else
          {
             cw->menu = e_menu_find_by_window(cw->win);
             if (cw->menu)
               {
                  cw->dfn = e_object_delfn_add(E_OBJECT(cw->menu), 
                                               _e_mod_comp_object_del, cw);
                  // ref menu
               }
          }
     }
   evas_object_show(cw->obj);
   if (cw->shobj)
     {
        if (_comp_mod->conf->use_shadow)
          {
             if (_e_mod_comp_win_do_shadow(cw))
               {
                  int ok = 0;
                  char buf[PATH_MAX];
                  
                 // fimxe: maker shadow object configurable - use theme first
                  if (_comp_mod->conf->shadow_file)
                    {
                       ok = 1;
                       if (!edje_object_file_set(cw->shobj, 
                                                 _comp_mod->conf->shadow_file,
                                                 "shadow"))
                         ok = 0;
                    }
                  if (!ok)
                    {
                       ok = 1;
                       if (!e_theme_edje_object_set(cw->shobj,
                                                    "base/theme/borders",
                                                    "e/shadow/box"))
                         ok = 0;
                    }
                  if (!ok)
                    {
                       snprintf(buf, sizeof(buf), "%s/shadow.edj", 
                                e_module_dir_get(_comp_mod->module)
                                );
                       edje_object_file_set(cw->shobj, buf, "shadow");
                    }
                  evas_object_show(cw->shobj);
               }
          }
     }
   _e_mod_comp_win_render_queue(cw);
   _e_mod_comp_win_show_effects_add(cw);
}

static void
_e_mod_comp_win_hide(E_Comp_Win *cw)
{
   if (!cw->defer_hide)
     {
        if (!cw->visible) return;
     }
   cw->defer_hide = 0;
   cw->visible = 0;
   if ((cw->input_only) || (cw->invalid)) return;
   DBG("  [0x%x] hid --\n", cw->win);
   _e_mod_comp_win_hide_effects_add(cw);
   if (cw->effects)
     {
        cw->defer_hide = 1;
        return; // defer rest of hide
     }
   if (cw->update_timeout)
     {
        ecore_timer_del(cw->update_timeout);
        cw->update_timeout = NULL;
     }
   if (_comp_mod->conf->efl_sync)
     {
        if ((cw->bd) && (cw->counter))
          ecore_x_e_comp_sync_end_send(cw->bd->client.win);
     }
   evas_object_hide(cw->obj);
   if (cw->shobj) evas_object_hide(cw->shobj);

   if (_comp_mod->conf->keep_unmapped)
     {
        // fixme: ask the x homies. why does this need to be done?
        // why free pixmap (+texture bound), undriect, then redirect again
        // getting pixmap againand well - getting texture too again. why?
        if (cw->redirected)
          {
             if (cw->native) evas_object_image_native_surface_set(cw->obj, NULL);
             if (cw->pixmap) ecore_x_pixmap_free(cw->pixmap);
             evas_object_image_size_set(cw->obj, 1, 1);
             cw->pixmap = 0;
             cw->pw = 0;
             cw->ph = 0;
             cw->native = 0;
             ecore_x_composite_unredirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
             ecore_x_composite_redirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
             cw->pixmap = ecore_x_composite_name_window_pixmap_get(cw->win);
             if (cw->pixmap)
               ecore_x_pixmap_geometry_get(cw->pixmap, NULL, NULL, &(cw->pw), &(cw->ph));
             else
               {
                  cw->pw = 0;
                  cw->ph = 0;
               }
             if ((cw->pw <= 0) || (cw->ph <= 0))
               {
                  ecore_x_pixmap_free(cw->pixmap);
                  cw->pixmap = 0;
               }
          }
        return;
     }
   
   if (cw->redirected)
     {
        ecore_x_composite_unredirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
        cw->redirected = 0;
        cw->pw = 0;
        cw->ph = 0;
     }
   if (cw->native)
     {
        evas_object_image_native_surface_set(cw->obj, NULL);
        cw->native = 0;
     }
   evas_object_image_size_set(cw->obj, 1, 1);
   if (cw->pixmap)
     {
        ecore_x_pixmap_free(cw->pixmap);
        cw->pixmap = 0;
        cw->pw = 0;
        cw->ph = 0;
     }
   if (cw->xim)
     {
        evas_object_image_data_set(cw->obj, NULL);
        ecore_x_image_free(cw->xim);
        cw->xim = NULL;
     }
   _e_mod_comp_win_render_queue(cw);
}

static void
_e_mod_comp_win_raise_above(E_Comp_Win *cw, E_Comp_Win *cw2)
{
   DBG("  [0x%x] abv [0x%x]\n", cw->win, cw2->win);
   cw->c->wins = eina_inlist_remove(cw->c->wins, EINA_INLIST_GET(cw));
   cw->c->wins = eina_inlist_append_relative(cw->c->wins, 
                                             EINA_INLIST_GET(cw), 
                                             EINA_INLIST_GET(cw2));
   evas_object_stack_above(cw->obj, cw2->obj);
   if (cw->shobj)
     {
        evas_object_stack_below(cw->shobj, cw->obj);
     }
   _e_mod_comp_win_render_queue(cw);
}

static void
_e_mod_comp_win_raise(E_Comp_Win *cw)
{
   DBG("  [0x%x] rai\n", cw->win);
   cw->c->wins = eina_inlist_remove(cw->c->wins, EINA_INLIST_GET(cw));
   cw->c->wins = eina_inlist_append(cw->c->wins, EINA_INLIST_GET(cw));
   evas_object_raise(cw->obj);
   if (cw->shobj)
     {
        evas_object_stack_below(cw->shobj, cw->obj);
     }
   _e_mod_comp_win_render_queue(cw);
}

static void
_e_mod_comp_win_lower(E_Comp_Win *cw)
{
   DBG("  [0x%x] low\n", cw->win);
   cw->c->wins = eina_inlist_remove(cw->c->wins, EINA_INLIST_GET(cw));
   cw->c->wins = eina_inlist_prepend(cw->c->wins, EINA_INLIST_GET(cw));
   evas_object_lower(cw->obj);
   if (cw->shobj)
     {
        evas_object_stack_below(cw->shobj, cw->obj);
     }
   _e_mod_comp_win_render_queue(cw);
}

static void
_e_mod_comp_win_configure(E_Comp_Win *cw, int x, int y, int w, int h, int border)
{
   Eina_Bool moved = 0;
   
   if (!((x == cw->x) && (y == cw->y)))
     {
        DBG("  [0x%x] mov %4i %4i\n", cw->win, x, y);
        cw->x = x;
        cw->y = y;
        evas_object_move(cw->obj, cw->x, cw->y);
        if (cw->shobj)
          {
             evas_object_move(cw->shobj, cw->x, cw->y);
          }
        moved = 1;
     }
   if (!((w == cw->w) && (h == cw->h)))
     {
        DBG("  [0x%x] rsz %4ix%4i\n", cw->win, w, h);
        if (cw->pixmap)
          {
             DBG("  [0x%x] free pm %x\n", cw->win, cw->pixmap);
             ecore_x_pixmap_free(cw->pixmap);
             cw->pixmap = 0;
             cw->native = 0;
             cw->pw = 0;
             cw->ph = 0;
          }
        cw->w = w;
        cw->h = h;
        evas_object_resize(cw->obj, 
                           cw->w + (cw->border * 2), 
                           cw->h + (cw->border * 2));
        if (cw->shobj)
          {
             evas_object_resize(cw->shobj, 
                                cw->w + (cw->border * 2),
                                cw->h + (cw->border * 2));
          }
        if (cw->xim)
          {
             evas_object_image_data_set(cw->obj, NULL);
             ecore_x_image_free(cw->xim);
             cw->xim = NULL;
          }
     }
   if (cw->border != border)
     {
        cw->border = border;
        evas_object_resize(cw->obj, 
                           cw->w + (cw->border * 2), 
                           cw->h + (cw->border * 2));
        if (cw->shobj)
          {
             evas_object_resize(cw->shobj, 
                                cw->w + (cw->border * 2),
                                cw->h + (cw->border * 2));
          }
     }
   if ((cw->input_only) || (cw->invalid)) return;
   e_mod_comp_update_resize(cw->up, cw->w, cw->h);
   _e_mod_comp_win_render_queue(cw);
   if (moved) _e_mod_comp_win_move_effects_add(cw);
}

static void
_e_mod_comp_win_damage(E_Comp_Win *cw, int x, int y, int w, int h, Eina_Bool dmg)
{
   if ((cw->input_only) || (cw->invalid)) return;
   DBG("  [0x%x] dmg [%x] %4i %4i %4ix%4i\n", cw->win, cw->damage, x, y, w, h);
   if ((dmg) && (cw->damage))
     {
        Ecore_X_Region parts;
   
        parts = ecore_x_region_new(NULL, 0);
        ecore_x_damage_subtract(cw->damage, 0, parts);
        ecore_x_region_free(parts);
     }
   e_mod_comp_update_add(cw->up, x, y, w, h);
   if (dmg)
     {
        if (cw->counter)
          {
             if (!cw->update_timeout)
               cw->update_timeout = ecore_timer_add
               (ecore_animator_frametime_get() * 2, 
                _e_mod_comp_win_damage_timeout, cw);
             return;
          }
     }
   if (!cw->update)
     {
        cw->update = 1;
        cw->c->updates = eina_list_append(cw->c->updates, cw);
     }
   _e_mod_comp_win_render_queue(cw);
}

static void
_e_mod_comp_win_reshape(E_Comp_Win *cw)
{
   if (cw->shape_changed) return;
   cw->shape_changed = 1;
   if (!cw->update)
     {
        cw->update = 1;
        cw->c->updates = eina_list_append(cw->c->updates, cw);
     }
   e_mod_comp_update_add(cw->up, 0, 0, cw->w, cw->h);
   _e_mod_comp_win_render_queue(cw);
}

//////////////////////////////////////////////////////////////////////////

static int
_e_mod_comp_create(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Create *ev = event;
   E_Comp_Win *cw;
   E_Comp *c = _e_mod_comp_find(ev->parent);
   if (!c) return 1;
   if (_e_mod_comp_win_find(ev->win)) return 1;
   if (c->win == ev->win) return 1;
   if (c->ee_win == ev->win) return 1;
   cw = _e_mod_comp_win_add(c, ev->win);
   if (cw) _e_mod_comp_win_configure(cw, ev->x, ev->y, ev->w, ev->h, ev->border);
   return 1;
}

static int
_e_mod_comp_destroy(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Destroy *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   if (cw->effects) cw->delete_me = 1;
   else _e_mod_comp_win_del(cw);
   return 1;
}

static int
_e_mod_comp_show(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Show *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   if (cw->visible) return 1;
   _e_mod_comp_win_show(cw);
   return 1;
}

static int
_e_mod_comp_hide(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Hide *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   if (!cw->visible) return 1;
   _e_mod_comp_win_hide(cw);
   return 1;
}

static int
_e_mod_comp_reparent(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Reparent *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   DBG("== repar [0x%x] to [0x%x]\n", ev->win, ev->parent);
   if (ev->parent != cw->c->man->root)
     _e_mod_comp_win_del(cw);
   return 1;
}

static int
_e_mod_comp_configure(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Configure *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;

   if (ev->abovewin == 0)
     {
        if (EINA_INLIST_GET(cw)->prev) _e_mod_comp_win_lower(cw);
     }
   else
     {
        E_Comp_Win *cw2 = _e_mod_comp_win_find(ev->abovewin);

        if (cw2)
          {
             E_Comp_Win *cw3 = (E_Comp_Win *)(EINA_INLIST_GET(cw)->prev);

             if (cw3 != cw2)
               _e_mod_comp_win_raise_above(cw, cw2);
          }
     }
   
   if (!((cw->x == ev->x) && (cw->y == ev->y) &&
         (cw->w == ev->h) && (cw->h == ev->h) &&
         (cw->border == ev->border)))
     {
        _e_mod_comp_win_configure(cw, ev->x, ev->y, ev->w, ev->h, ev->border);
     }
   return 1;
}

static int
_e_mod_comp_stack(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Stack *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE) _e_mod_comp_win_raise(cw);
   else _e_mod_comp_win_lower(cw);
   return 1;
}

static int
_e_mod_comp_property(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Property *ev = event;
   return 1;
}

static int
_e_mod_comp_message(void *data, int type, void *event)
{
   Ecore_X_Event_Client_Message *ev = event;
   E_Comp_Win *cw = NULL;
   if ((ev->message_type != ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE) ||
       (ev->format != 32)) return 1;
   cw = _e_mod_comp_border_client_find(ev->data.l[0]);
   if (!cw) return 1;
   if (!cw->bd) return 1;
   if (ev->data.l[0] != cw->bd->client.win) return 1;
   if (cw->bd)
     {
        if (cw->counter)
          {
             if (!cw->update)
               {
                  if (cw->update_timeout)
                    {
                       ecore_timer_del(cw->update_timeout);
                       cw->update_timeout = NULL;
                    }
                  cw->update = 1;
                  cw->c->updates = eina_list_append(cw->c->updates, cw);
               }
             cw->drawme = 1;
             _e_mod_comp_win_render_queue(cw);
          }
     }
   return 1;
}

static int
_e_mod_comp_shape(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Shape *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   _e_mod_comp_win_reshape(cw);
   return 1;
}

static int
_e_mod_comp_damage(void *data, int type, void *event)
{
   Ecore_X_Event_Damage *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_damage_find(ev->damage);
   if (!cw) return 1;
   _e_mod_comp_win_damage(cw, 
                          ev->area.x, ev->area.y, 
                          ev->area.width, ev->area.height, 1); 
   return 1;
}

static int
_e_mod_comp_randr(void *data, int type, void *event)
{
   Eina_List *l;
   E_Comp *c;

   EINA_LIST_FOREACH(compositors, l, c)
     {
        ecore_evas_resize(c->ee, c->man->w, c->man->h);
     }
   return 1;
}

static int
_e_mod_comp_bd_add(void *data, int type, void *event)
{
   E_Event_Border_Add *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: add/enable compositing here not in show event for borders
   return 1;
}

static int
_e_mod_comp_bd_del(void *data, int type, void *event)
{
   E_Event_Border_Remove *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   if (cw->bd == ev->border) _e_mod_comp_object_del(cw, ev->border);
   return 1;
}

static int
_e_mod_comp_bd_show(void *data, int type, void *event)
{
   E_Event_Border_Show *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: show compwin here
   return 1;
}

static int
_e_mod_comp_bd_hide(void *data, int type, void *event)
{
   E_Event_Border_Hide *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: hide compwin here
   return 1;
}

static int
_e_mod_comp_bd_move(void *data, int type, void *event)
{
   E_Event_Border_Move *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: do move here for composited bd
   return 1;
}

static int
_e_mod_comp_bd_resize(void *data, int type, void *event)
{
   E_Event_Border_Resize *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: do resize here instead of conf notify
   return 1;
}

static int
_e_mod_comp_bd_iconify(void *data, int type, void *event)
{
   E_Event_Border_Iconify *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: special iconfiy anim
   return 1;
}

static int
_e_mod_comp_bd_uniconify(void *data, int type, void *event)
{
   E_Event_Border_Uniconify *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: special uniconfiy anim
   return 1;
}

static int
_e_mod_comp_bd_urgent_change(void *data, int type, void *event)
{
   E_Event_Border_Urgent_Change *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: do special anim to show urgency
   return 1;
}

static int
_e_mod_comp_bd_focus_in(void *data, int type, void *event)
{
   E_Event_Border_Focus_In *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: can do anim on focus in
   return 1;
}

static int
_e_mod_comp_bd_focus_out(void *data, int type, void *event)
{
   E_Event_Border_Focus_Out *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: can do anim on focus out
   return 1;
}

static int
_e_mod_comp_bd_property(void *data, int type, void *event)
{
   E_Event_Border_Property *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: check properties and adjust things if needed...
   return 1;
}

//////////////////////////////////////////////////////////////////////////

static E_Comp *
_e_mod_comp_add(E_Manager *man)
{
   E_Comp *c;
   Ecore_X_Window *wins;
   Ecore_X_Window_Attributes att;
   int i, num;
   
   c = calloc(1, sizeof(E_Comp));
   if (!c) return NULL;

   ecore_x_e_comp_sync_supported_set(man->root, _comp_mod->conf->efl_sync);
   
   c->man = man;
   c->win = ecore_x_composite_render_window_enable(man->root);
   if (!c->win)
     {
        e_util_dialog_internal
          (_("Compositor Error"),
           _("Your screen does not support the compositor<br>"
             "overlay window. This is needed for it to<br>"
             "function."));
        free(c);
        return NULL;
     }
   
   memset((&att), 0, sizeof(Ecore_X_Window_Attributes));
   ecore_x_window_attributes_get(c->win, &att);   
   
   if ((att.depth != 24) && (att.depth != 32))
     {
        e_util_dialog_internal
          (_("Compositor Error"),
           _("Your screen is not in 24/32bit display mode.<br>"
             "This is required to be your default depth<br>"
             "setting for the compositor to work properly."));
        ecore_x_composite_render_window_disable(c->win);
        free(c);
        return NULL;
     }
   
   if (c->man->num == 0) e_alert_composite_win = c->win;
   
   if (_comp_mod->conf->engine == E_EVAS_ENGINE_GL_X11)
     {
        c->ee = ecore_evas_gl_x11_new(NULL, c->win, 0, 0, man->w, man->h);
        if (c->ee)
          {
             c->gl = 1;
             ecore_evas_gl_x11_pre_post_swap_callback_set
               (c->ee, c, _e_mod_comp_pre_swap, NULL);
          }
     }
   if (!c->ee)
     c->ee = ecore_evas_software_x11_new(NULL, c->win, 0, 0, man->w, man->h);
   
   ecore_evas_comp_sync_set(c->ee, 0);
   ecore_evas_manual_render_set(c->ee, _comp_mod->conf->lock_fps);
   c->evas = ecore_evas_get(c->ee);
   ecore_evas_show(c->ee);
   
   c->ee_win = ecore_evas_software_x11_window_get(c->ee);
   ecore_x_screen_is_composited_set(c->man->num, c->ee_win);
//   ecore_x_composite_unredirect_subwindows
//     (c->man->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);

   wins = ecore_x_window_children_get(c->man->root, &num);
   if (wins)
     {
        for (i = 0; i < num; i++)
          {
             E_Comp_Win *cw;
             int x, y, w, h, border;
             
             cw = _e_mod_comp_win_add(c, wins[i]);
             if (!cw) continue;
             ecore_x_window_geometry_get(cw->win, &x, &y, &w, &h);
             border = ecore_x_window_border_width_get(cw->win);
             if (wins[i] == c->win) continue;
             _e_mod_comp_win_configure(cw, x, y, w, h, border);
             if (ecore_x_window_visible_get(wins[i]))
               {
                  _e_mod_comp_win_show(cw);
               }
          }
        free(wins);
     }
   
   return c;
}

static void
_e_mod_comp_del(E_Comp *c)
{
   E_Comp_Win *cw;
   
   if (c->grabbed)
     {
        c->grabbed = 0;
        ecore_x_ungrab();
     }
   ecore_x_screen_is_composited_set(c->man->num, 0);
   while (c->wins)
     {
        cw = (E_Comp_Win *)(c->wins);
        if (cw->counter)
          {
             ecore_x_sync_counter_free(cw->counter);
             cw->counter = 0;
          }
        _e_mod_comp_win_hide(cw);
        _e_mod_comp_win_del(cw);
     }
   ecore_evas_free(c->ee);
//   ecore_x_composite_unredirect_subwindows
//     (c->man->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);
   ecore_x_composite_render_window_disable(c->win);
   if (c->man->num == 0) e_alert_composite_win = 0;
   if (c->render_animator) ecore_animator_del(c->render_animator);
   if (c->update_job) ecore_job_del(c->update_job);
   
   ecore_x_e_comp_sync_supported_set(c->man->root, 0);
   
   free(c);
}

//////////////////////////////////////////////////////////////////////////

Eina_Bool
e_mod_comp_init(void)
{
   Eina_List *l;
   E_Manager *man;
<commit_msg>fix some bugs i added to compositing in making gl more solid - software compositing that is.<commit_after>#include "e.h"
#include "e_mod_main.h"
#include "e_mod_comp.h"
#include "e_mod_comp_update.h"
#include "config.h"

//////////////////////////////////////////////////////////////////////////
//
// TODO (no specific order):
//   1. abstract evas object and compwin so we can duplicate the object N times
//      in N canvases - for winlist, everything, pager etc. too
//   2. implement "unmapped composite cache" -> N pixels worth of unmapped
//      windows to be fully composited. only the most active/recent.
//   3. for unmapped windows - when window goes out of unmapped comp cache
//      make a miniature copy (1/4 width+height?) and set property on window
//      with pixmap id
//   6. other engine fast-paths (gl specifically)!
//   8. transparenty property
//   9. shortcut lots of stuff to draw inside the compositor - shelf,
//      wallpaper, efm - hell even menus and anything else in e (this is what
//      e18 was mostly about)
//  10. fullscreen windows need to be able to bypass compositing
//  11. handle root window resize!
//  
//////////////////////////////////////////////////////////////////////////

struct _E_Comp
{
   Ecore_X_Window  win;
   Ecore_Evas     *ee;
   Ecore_X_Window  ee_win;
   Evas           *evas;
   E_Manager      *man;
   Eina_Inlist    *wins;
   Eina_List      *updates;
   Ecore_Animator *render_animator;
   Ecore_Job      *update_job;
   int             render_overflow;

   Eina_Bool       gl : 1;
   Eina_Bool       grabbed : 1;
};

struct _E_Comp_Win
{
   EINA_INLIST;
   
   E_Comp         *c; // parent compositor
   Ecore_X_Window  win; // raw window - for menus etc.
   E_Border       *bd; // if its a border - later
   E_Popup        *pop; // if its a popup - later
   E_Menu         *menu; // if it is a menu - later
   int             x, y, w, h; // geometry
   int             pw, ph; // pixmap w/h
   int             border; // border width
   Ecore_X_Pixmap  pixmap; // the compositing pixmap
   Ecore_X_Damage  damage; // damage region
   Ecore_X_Visual  vis; // window visual
   int             depth; // window depth
   Evas_Object    *obj; // composite object
   Evas_Object    *shobj; // shadow object
   Ecore_X_Image  *xim; // x image - software fallback
   E_Update       *up; // update handler
   E_Object_Delfn *dfn; // delete function handle for objects being tracked
   Ecore_X_Sync_Counter counter; // sync counter for syncronised drawing
   Ecore_Timer    *update_timeout; // max time between damage and "done" event
   
   Eina_List      *effects; // list of effects attached to this window currently

   Ecore_X_Pixmap  cache_pixmap; // the cached pixmap (1/nth the dimensions)
   int             cache_w, cache_h; // cached pixmap size
   int             update_count; // how many updates have happend to this win
   double          last_visible_time; // last time window was visible
   double          last_draw_time; // last time window was damaged
   
   Eina_Bool       visible : 1; // is visible
   Eina_Bool       input_only : 1; // is input_only
   Eina_Bool       override : 1; // is override-redirect
   Eina_Bool       argb : 1; // is argb
   Eina_Bool       shaped : 1; // is shaped
   Eina_Bool       update : 1; // has updates to fetch
   Eina_Bool       redirected : 1; // has updates to fetch
   Eina_Bool       shape_changed : 1; // shape changed
   Eina_Bool       native : 1; // native
   Eina_Bool       drawme : 1; // drawme flag fo syncing rendering
   Eina_Bool       invalid : 1; // invalid depth used - just use as marker
   Eina_Bool       defer_hide : 1; // flag to get hide to work on deferred hide
   Eina_Bool       delete_me : 1;
};

static Eina_List *handlers = NULL;
static Eina_List *compositors = NULL;
static Eina_Hash *windows = NULL;
static Eina_Hash *borders = NULL;
static Eina_Hash *damages = NULL;

//////////////////////////////////////////////////////////////////////////
// not working yet.
typedef struct _Effect Effect;

struct _Effect
{
   E_Comp_Win *cw;
   Ecore_Animator *animator;
   double start, len;
   double src, dst;
   int type;
};

#define EFFECT_SHOW 1
#define EFFECT_HIDE 2
#define EFFECT_MOVE 3

static Effect *
_e_mod_comp_effect_add(E_Comp_Win *cw, int (*func) (void *data), double len, int type)
{
   Effect *ef;
   
   ef = calloc(1, sizeof(Effect));
   ef->animator = ecore_animator_add(func, ef);
   ef->start = ecore_loop_time_get();
   ef->len = len;
   ef->cw = cw;
   ef->type = type;
   cw->effects = eina_list_append(cw->effects, ef);
   return ef;
}

static void
_e_mod_comp_effect_del(Effect *ef)
{
   ef->cw->effects = eina_list_remove(ef->cw->effects, ef);
   ecore_animator_del(ef->animator);
   free(ef);
}

static Effect *
_e_mod_comp_win_effect_find(E_Comp_Win *cw, int type)
{
   Eina_List *l;
   Effect *ef;
   
   // fixme: use hash if compositors list > 4
   EINA_LIST_FOREACH(cw->effects, l, ef)
     {
        if (ef->type == type) return ef;
     }
   return NULL;
}

static void _e_mod_comp_win_hide(E_Comp_Win *cw); // quick and dirty
static void _e_mod_comp_win_del(E_Comp_Win *cw); // quick and dirty
static void _e_mod_comp_win_render_queue(E_Comp_Win *cw); // quick and dirty

static int
_e_mod_comp_ef_cb_fade_to(void *data)
{
   Effect *ef = data;
   double t = (ecore_loop_time_get() - ef->start) / ef->len;
   E_Comp_Win *cw = ef->cw;
   double v;
   int col;
   if (t > 1.0) t = 1.0;
   
   v = ef->src + ((ef->dst - ef->src) * t);
   col = 255.0 * v;
   evas_object_color_set(cw->obj, col, col, col, col);
   if (ef->cw->shobj)
     evas_object_color_set(cw->shobj, col, col, col, col);
   if (t >= 1.0)
     {
        evas_object_color_set(cw->obj, 255, 255, 255, 255);
        _e_mod_comp_effect_del(ef);
        _e_mod_comp_win_render_queue(cw);
        if (!cw->effects)
          {
             if (cw->defer_hide)
               {
                  cw->defer_hide = 0;
                  _e_mod_comp_win_hide(cw);
               }
             if (cw->delete_me)
               _e_mod_comp_win_del(cw);
          }
        return 0;
     }
   return 1;
}

static void
_e_mod_comp_win_show_effects_add(E_Comp_Win *cw)
{
   Effect *ef;
   
   do
     {
        ef = _e_mod_comp_win_effect_find(cw, EFFECT_SHOW);
        if (ef) _e_mod_comp_effect_del(ef);
     }
   while (ef);
   
   do
     {
        ef = _e_mod_comp_win_effect_find(cw, EFFECT_HIDE);
        if (ef) _e_mod_comp_effect_del(ef);
     }
   while (ef);
   
   if (_comp_mod->conf->effect_fade)
     {
        ef = _e_mod_comp_effect_add(cw, _e_mod_comp_ef_cb_fade_to, 0.2, EFFECT_SHOW);
        ef->src = 0.0;
        ef->dst = 1.0;
        cw->defer_hide = 0;
        _e_mod_comp_ef_cb_fade_to(ef);
     }
}

static void
_e_mod_comp_win_hide_effects_add(E_Comp_Win *cw)
{
   Effect *ef;
   
   do
     {
        ef = _e_mod_comp_win_effect_find(cw, EFFECT_SHOW);
        if (ef) _e_mod_comp_effect_del(ef);
     }
   while (ef);
   
   do
     {
        ef = _e_mod_comp_win_effect_find(cw, EFFECT_HIDE);
        if (ef) _e_mod_comp_effect_del(ef);
     }
   while (ef);
   
   if (_comp_mod->conf->effect_fade)
     {
        int a;
        
        ef = _e_mod_comp_effect_add(cw, _e_mod_comp_ef_cb_fade_to, 0.2, EFFECT_HIDE);
        evas_object_color_get(cw->obj, NULL, NULL, NULL, &a);
        ef->src = (double)a / 255.0;
        ef->dst = 0.0;
        cw->defer_hide = 1;
        _e_mod_comp_ef_cb_fade_to(ef);
     }
}

static void
_e_mod_comp_win_move_effects_add(E_Comp_Win *cw)
{
}

//////////////////////////////////////////////////////////////////////////

#if 0
#define DBG(f, x...) printf(f, ##x)
#else
#define DBG(f, x...)
#endif

static void _e_mod_comp_render_queue(E_Comp *c);
static void _e_mod_comp_win_damage(E_Comp_Win *cw, int x, int y, int w, int h, Eina_Bool dmg);

static void
_e_mod_comp_win_shape_rectangles_apply(E_Comp_Win *cw)
{
   Ecore_X_Rectangle *rects;
   int num, i;
   
   DBG("SHAPE [0x%x] change\n", cw->win);
   rects = ecore_x_window_shape_rectangles_get(cw->win, &num);
   if ((rects) && (num == 1))
     {
        DBG("SHAPE [0x%x] rect 1\n", cw->win);
        if ((rects[0].x == 0) &&
            (rects[0].y == 0) &&
            (rects[0].width == cw->w) &&
            (rects[0].height == cw->h))
          {
             DBG("SHAPE [0x%x] rect solid\n", cw->win);
             free(rects);
             rects = NULL;
          }
     }
   if (rects)
     {
        unsigned int *pix, *p;
        unsigned char *spix, *sp;
        int w, h, px, py;
        
        cw->shaped = 1;
        evas_object_image_size_get(cw->obj, &w, &h);
        if ((w > 0) && (h > 0))
          {
             pix = evas_object_image_data_get(cw->obj, 1);
             spix = calloc(w * h, sizeof(unsigned char));
             if (spix)
               {
                  DBG("SHAPE [0x%x] rects %i\n", cw->win, num);
                  for (i = 0; i < num; i++)
                    {
                       int rx, ry, rw, rh;
                       
                       rx = rects[i].x; ry = rects[i].y;
                       rw = rects[i].width; rh = rects[i].height;
                       E_RECTS_CLIP_TO_RECT(rx, ry, rw, rh, 0, 0, w, h);
                       sp = spix + (w * ry) + rx;
                       for (py = 0; py < rh; py++)
                         {
                            for (px = 0; px < rw; px++)
                              {
                                 *sp = 1; sp++;
                              }
                            sp += w - rw;
                         }
                    }
                  sp = spix;
                  p = pix;
                  for (py = 0; py < h; py++)
                    {
                       for (px = 0; px < w; px++)
                         {
                            if (*sp) *p |= 0xff000000;
                            else *p = 0x00000000;
                            sp++;
                            p++;
                         }
                    }
                  free(spix);
               }
             evas_object_image_data_set(cw->obj, pix);
             evas_object_image_alpha_set(cw->obj, 1);
             evas_object_image_data_update_add(cw->obj, 0, 0, w, h);
          }
        free(rects);
     }
   else
     {
        cw->shaped = 0;
        evas_object_image_alpha_set(cw->obj, 0);
        // dont need to fix alpha chanel as blending 
        // should be totally off here regardless of
        // alpha channe; content
     }
}

static void
_e_mod_comp_win_update(E_Comp_Win *cw)
{
   E_Update_Rect *r;
   int i;
   
   ecore_x_grab();
   cw->update = 0;
   if (!cw->pixmap)
     {
        cw->pixmap = ecore_x_composite_name_window_pixmap_get(cw->win);
        if (cw->pixmap)
          ecore_x_pixmap_geometry_get(cw->pixmap, NULL, NULL, &(cw->pw), &(cw->ph));
        else
          {
             cw->pw = 0;
             cw->ph = 0;
          }
        DBG("REND [0x%x] pixmap = [0x%x], %ix%i\n", cw->win, cw->pixmap, cw->pw, cw->ph);
        if ((cw->pw <= 0) || (cw->ph <= 0))
          {
             if (cw->native)
               {
                  DBG("  [0x%x] free native\n", cw->win);
                  evas_object_image_native_surface_set(cw->obj, NULL);
                  cw->native = 0;
               }
             if (cw->pixmap)
               {
                  DBG("  [0x%x] free pixmap\n", cw->win);
                  ecore_x_pixmap_free(cw->pixmap);
                  cw->pixmap = 0;
               }
             cw->pw = 0;
             cw->ph = 0;
          }
        cw->native = 0;
        e_mod_comp_update_resize(cw->up, cw->pw, cw->ph);
        e_mod_comp_update_add(cw->up, 0, 0, cw->pw, cw->ph);
     }
   if (!((cw->pw > 0) && (cw->ph > 0)))
     {
        ecore_x_ungrab();
        return;
     }

   if ((cw->pw != cw->w) || (cw->ph != cw->h))
     {
        ecore_x_window_geometry_get(cw->win, 
                                    &(cw->x), &(cw->y), 
                                    &(cw->w), &(cw->h));
        evas_object_move(cw->obj, cw->x, cw->y);
        if (cw->shobj)
          {
             evas_object_move(cw->shobj, cw->x, cw->y);
          }
        evas_object_resize(cw->obj, 
                           cw->w + (cw->border * 2), 
                           cw->h + (cw->border * 2));
        if (cw->shobj)
          {
             evas_object_resize(cw->shobj, 
                                cw->w + (cw->border * 2),
                                cw->h + (cw->border * 2));
          }
     }
   ecore_x_ungrab();
   
   if ((cw->c->gl) && (_comp_mod->conf->texture_from_pixmap) &&
       (!cw->shaped) && (!cw->shape_changed))
     {
//        DBG("DEBUG - pm now %x\n", ecore_x_composite_name_window_pixmap_get(cw->win));
        evas_object_image_size_set(cw->obj, cw->pw, cw->ph);
        if (!cw->native)
          {
             Evas_Native_Surface ns;
             
             ns.data.x11.visual = cw->vis;
             ns.data.x11.pixmap = cw->pixmap;
             evas_object_image_native_surface_set(cw->obj, &ns);
             DBG("NATIVE [0x%x] %x %ix%i\n", cw->win, cw->pixmap, cw->pw, cw->ph);
             cw->native = 1;
          }
        r = e_mod_comp_update_rects_get(cw->up);
        if (r) 
          {
             e_mod_comp_update_clear(cw->up);
             for (i = 0; r[i].w > 0; i++)
               {
                  int x, y, w, h;
                       
                  x = r[i].x; y = r[i].y;
                  w = r[i].w; h = r[i].h;
                  DBG("UPDATE [0x%x] pm [0x%x] %i %i %ix%i\n", cw->win, cw->pixmap, x, y, w, h);
                  evas_object_image_data_update_add(cw->obj, x, y, w, h);
               }
             free(r);
          }
        else
          cw->update = 1;
     }
   else
     {
        if (!cw->xim)
          {
             if (cw->xim = ecore_x_image_new(cw->pw, cw->ph, cw->vis, cw->depth))
               e_mod_comp_update_add(cw->up, 0, 0, cw->pw, cw->ph);
          }
        r = e_mod_comp_update_rects_get(cw->up);
        if (r) 
          {
             if (cw->xim)
               {
                  unsigned int *pix;
                  
                  pix = ecore_x_image_data_get(cw->xim, NULL, NULL, NULL);
                  evas_object_image_data_set(cw->obj, pix);
                  evas_object_image_size_set(cw->obj, cw->pw, cw->ph);
                  
                  e_mod_comp_update_clear(cw->up);
                  for (i = 0; r[i].w > 0; i++)
                    {
                       unsigned int *pix;
                       int x, y, w, h;
                       
                       x = r[i].x; y = r[i].y;
                       w = r[i].w; h = r[i].h;
                       if (!ecore_x_image_get(cw->xim, cw->pixmap, x, y, x, y, w, h))
                         {
                            printf("EEEEK! get failed\n");
                         }
// why do we neeed these 2? this smells wrong
                       pix = ecore_x_image_data_get(cw->xim, NULL, NULL, NULL);
                       DBG("UPDATE [0x%x] %i %i %ix%i -- pix = %p\n", cw->win, x, y, w, h, pix);
                       evas_object_image_data_set(cw->obj, pix);
                       
                       evas_object_image_data_update_add(cw->obj, x, y, w, h);
                       if (cw->shaped) cw->shape_changed = 1;
                    }
                  if ((cw->shape_changed) && (!cw->argb))
                    {
                       _e_mod_comp_win_shape_rectangles_apply(cw);
                       cw->shape_changed = 0;
                    }
               }
             free(r);
          }
        else
          cw->update = 1;
     }
   if (cw->shobj)
     {
        if (cw->shaped) evas_object_hide(cw->shobj);
     }
}

static void
_e_mod_comp_pre_swap(void *data, Evas *e)
{
   E_Comp *c = data;
   
   if (_comp_mod->conf->grab)
     {
        if (c->grabbed)
          {
             ecore_x_ungrab();
             c->grabbed = 0;
          }
     }
}

static int
_e_mod_comp_cb_update(E_Comp *c)
{
   E_Comp_Win *cw;
   Eina_List *new_updates = NULL; // for failed pixmap fetches - get them next frame
   Eina_List *update_done = NULL;

   if (_comp_mod->conf->grab)
     {
        ecore_x_grab();
        ecore_x_sync();
        c->grabbed = 1;
     }
   EINA_LIST_FREE(c->updates, cw)
     {
        if (_comp_mod->conf->efl_sync)
          {
             if (((cw->counter) && (cw->drawme)) || (!cw->counter))
               {
                  _e_mod_comp_win_update(cw);
                  if (cw->drawme)
                    update_done = eina_list_append(update_done, cw);
                  cw->drawme = 0;
               }
             else
               cw->update = 0;
          }
        else
          _e_mod_comp_win_update(cw);
        if (cw->update)
          new_updates = eina_list_append(new_updates, cw);
     }
   if (_comp_mod->conf->lock_fps)
     ecore_evas_manual_render(c->ee);
   if (_comp_mod->conf->efl_sync)
     {  
        EINA_LIST_FREE(update_done, cw)
          {
             ecore_x_sync_counter_inc(cw->counter, 1);
          }
     }
   if (_comp_mod->conf->grab)
     {
        if (c->grabbed)
          {
             c->grabbed = 0;
             ecore_x_ungrab();
          }
     }
   if (new_updates) _e_mod_comp_render_queue(c);
   c->updates = new_updates;
   c->render_overflow--;
   c->update_job = NULL;
   if (c->render_overflow == 0)
     {
        if (c->render_animator) c->render_animator = NULL;
        return 0;
     }
   return 1;
}

static void
_e_mod_comp_cb_job(void *data)
{
   _e_mod_comp_cb_update(data);
}

static int
_e_mod_comp_cb_animator(void *data)
{
   return _e_mod_comp_cb_update(data);
}

static void
_e_mod_comp_render_queue(E_Comp *c)
{
   if (_comp_mod->conf->lock_fps)
     {
        if (c->render_animator)
          {
             c->render_overflow = 10;
             return;
          }
        c->render_animator = ecore_animator_add(_e_mod_comp_cb_animator, c);
     }
   else
     {
        if (c->update_job)
          {
             ecore_job_del(c->update_job);
             c->render_overflow = 0;
          }
        c->update_job = ecore_job_add(_e_mod_comp_cb_job, c);
     }
}

static void
_e_mod_comp_win_render_queue(E_Comp_Win *cw)
{
   _e_mod_comp_render_queue(cw->c);
}

static E_Comp *
_e_mod_comp_find(Ecore_X_Window root)
{
   Eina_List *l;
   E_Comp *c;
   
   // fixme: use hash if compositors list > 4
   EINA_LIST_FOREACH(compositors, l, c)
     {
        if (c->man->root == root) return c;
     }
   return NULL;
}

static E_Comp_Win *
_e_mod_comp_win_find(Ecore_X_Window win)
{
   return eina_hash_find(windows, e_util_winid_str_get(win));
}

static E_Comp_Win *
_e_mod_comp_border_client_find(Ecore_X_Window win)
{
   return eina_hash_find(borders, e_util_winid_str_get(win));
}

static E_Comp_Win *
_e_mod_comp_win_damage_find(Ecore_X_Damage damage)
{
   return eina_hash_find(damages, e_util_winid_str_get(damage));
}

static Eina_Bool
_e_mod_comp_win_is_borderless(E_Comp_Win *cw)
{
   if (!cw->bd) return 1;
   if ((cw->bd->client.border.name) &&
       (!strcmp(cw->bd->client.border.name, "borderless")))
     return 1;
   return 0;
}

static Eina_Bool
_e_mod_comp_win_do_shadow(E_Comp_Win *cw)
{
   if (cw->shaped) return 0;
   if (cw->argb)
     {
        if (_e_mod_comp_win_is_borderless(cw)) return 0;
     }
   return 1;
}

static int
_e_mod_comp_win_damage_timeout(void *data)
{
   E_Comp_Win *cw = data;
   
   if (!cw->update)
     {
        if (cw->update_timeout)
          {
             ecore_timer_del(cw->update_timeout);
             cw->update_timeout = NULL;
          }
        cw->update = 1;
        cw->c->updates = eina_list_append(cw->c->updates, cw);
     }
   cw->drawme = 1;
   _e_mod_comp_win_render_queue(cw);
   cw->update_timeout = NULL;
   return 0;
}

static void
_e_mod_comp_object_del(void *data, void *obj)
{
   E_Comp_Win *cw = data;

   _e_mod_comp_win_render_queue(cw);
   if (obj == cw->bd)
     {
        eina_hash_del(borders, e_util_winid_str_get(cw->bd->client.win), cw);
        cw->bd = NULL;
        cw->counter = 0;
     }
   else if (obj == cw->pop) cw->pop = NULL;
   else if (obj == cw->menu) cw->menu = NULL;
   if (cw->dfn)
     {
        e_object_delfn_del(obj, cw->dfn);
        cw->dfn = NULL;
     }
}

static E_Comp_Win *
_e_mod_comp_win_add(E_Comp *c, Ecore_X_Window win)
{
   Ecore_X_Window_Attributes att;
   E_Comp_Win *cw;
   
   cw = calloc(1, sizeof(E_Comp_Win));
   if (!cw) return NULL;
   cw->win = win;
   cw->c = c;
   cw->bd = e_border_find_by_window(cw->win);
   if (cw->bd)
     {
        eina_hash_add(borders, e_util_winid_str_get(cw->bd->client.win), cw);
        cw->dfn = e_object_delfn_add(E_OBJECT(cw->bd), 
                                     _e_mod_comp_object_del, cw);
        if (_comp_mod->conf->efl_sync)
          {
             if (_e_mod_comp_win_is_borderless(cw) ||
                 (_comp_mod->conf->loose_sync))
               {
                  cw->counter = 
                    ecore_x_e_comp_sync_counter_get(cw->bd->client.win);
                  if (cw->counter)
                    {
                       ecore_x_sync_counter_inc(cw->counter, 1);
                       ecore_x_e_comp_sync_begin_send(cw->bd->client.win);
                    }
               }
             else
               ecore_x_e_comp_sync_cancel_send(cw->bd->client.win);
          }
     }
   else
     {
        cw->pop = e_popup_find_by_window(cw->win);
        if (cw->pop)
          cw->dfn = e_object_delfn_add(E_OBJECT(cw->pop), 
                                       _e_mod_comp_object_del, cw);
        else
          {
             cw->menu = e_menu_find_by_window(cw->win);
             if (cw->menu)
               cw->dfn = e_object_delfn_add(E_OBJECT(cw->menu), 
                                            _e_mod_comp_object_del, cw);
          }
     }
   // fixme: could use bd/pop/menu for this too
   memset((&att), 0, sizeof(Ecore_X_Window_Attributes));
   if (!ecore_x_window_attributes_get(cw->win, &att))
     {
        free(cw);
        return NULL;
     }
   if ((!att.input_only) && 
       ((att.depth != 24) && (att.depth != 32)))
     {
        printf("WARNING: window 0x%x not 24/32bpp -> %ibpp\n", cw->win, att.depth);
        cw->invalid = 1;
     }
   cw->input_only = att.input_only;
   cw->override = att.override;
   cw->vis = att.visual;
   cw->depth = att.depth;
   cw->argb = ecore_x_window_argb_get(cw->win);
   eina_hash_add(windows, e_util_winid_str_get(cw->win), cw);
   if ((!cw->input_only) && (!cw->invalid))
     {
        Ecore_X_Rectangle *rects;
        int num;
        
        cw->damage = ecore_x_damage_new
          (cw->win, ECORE_X_DAMAGE_REPORT_DELTA_RECTANGLES);
        eina_hash_add(damages, e_util_winid_str_get(cw->damage), cw);
        cw->shobj = edje_object_add(c->evas);
        cw->obj = evas_object_image_filled_add(c->evas);
        evas_object_image_colorspace_set(cw->obj, EVAS_COLORSPACE_ARGB8888);
        if (cw->argb) evas_object_image_alpha_set(cw->obj, 1);
        else evas_object_image_alpha_set(cw->obj, 0);
        ecore_x_window_shape_events_select(cw->win, 1);
        rects = ecore_x_window_shape_rectangles_get(cw->win, &num);
        if (rects)
          {
             if ((rects) && (num == 1)  &&
                 (rects[0].x == 0) && (rects[0].y == 0) &&
                 (rects[0].width == att.w) && (rects[0].height == att.h))
               {
                  free(rects);
                  rects = NULL;
               }
             if (rects)
               {
                  cw->shaped = 1;
                  cw->shape_changed = 1;
                  free(rects);
               }
          }
     }
   else
     {
        cw->obj = evas_object_rectangle_add(c->evas);
        evas_object_color_set(cw->obj, 0, 0, 0, 64);
     }
   c->wins = eina_inlist_append(c->wins, EINA_INLIST_GET(cw));
   cw->up = e_mod_comp_update_new();
   e_mod_comp_update_tile_size_set(cw->up, 32, 32);
   // for software:
   e_mod_comp_update_policy_set
     (cw->up, E_UPDATE_POLICY_HALF_WIDTH_OR_MORE_ROUND_UP_TO_FULL_WIDTH);
   if (((!cw->input_only) && (!cw->invalid)) && (cw->override))
     {
        cw->redirected = 1;
        ecore_x_composite_redirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
     }
   DBG("  [0x%x] add\n", cw->win);
   return cw;
}

static void
_e_mod_comp_win_del(E_Comp_Win *cw)
{
   e_mod_comp_update_free(cw->up);
   DBG("  [0x%x] del\n", cw->win);
   while (cw->effects) _e_mod_comp_effect_del(cw->effects->data);
   if (cw->update_timeout)
     {
        ecore_timer_del(cw->update_timeout);
        cw->update_timeout = NULL;
     }
   if (cw->dfn)
     {
        if (cw->bd)
          {
             eina_hash_del(borders, e_util_winid_str_get(cw->bd->client.win), cw);
             e_object_delfn_del(E_OBJECT(cw->bd), cw->dfn);
          }
        else if (cw->pop) e_object_delfn_del(E_OBJECT(cw->pop), cw->dfn);
        else if (cw->menu) e_object_delfn_del(E_OBJECT(cw->menu), cw->dfn);
        cw->dfn = NULL;
     }
   if (cw->native)
     {
        evas_object_image_native_surface_set(cw->obj, NULL);
        cw->native = 0;
     }
   if (cw->pixmap)
     {
        ecore_x_pixmap_free(cw->pixmap);
        cw->pixmap = 0;
        cw->pw = 0;
        cw->ph = 0;
     }
   if (cw->update)
     {
        cw->update = 0;
        cw->c->updates = eina_list_remove(cw->c->updates, cw);
     }
   if (cw->xim)
     {
        evas_object_image_data_set(cw->obj, NULL);
        ecore_x_image_free(cw->xim);
        cw->xim = NULL;
     }
   if (cw->obj)
     {
        evas_object_del(cw->obj);
        cw->obj = NULL;
     }
   if (cw->shobj)
     {
        evas_object_del(cw->shobj);
        cw->shobj = NULL;
     }
   eina_hash_del(windows, e_util_winid_str_get(cw->win), cw);
   if (cw->damage)
     {
        Ecore_X_Region parts;
   
        eina_hash_del(damages, e_util_winid_str_get(cw->damage), cw);
        parts = ecore_x_region_new(NULL, 0);
        ecore_x_damage_subtract(cw->damage, 0, parts);
        ecore_x_region_free(parts);
        ecore_x_damage_free(cw->damage);
        cw->damage = 0;
     }
   cw->c->wins = eina_inlist_remove(cw->c->wins, EINA_INLIST_GET(cw));
   free(cw);
}

static void
_e_mod_comp_win_show(E_Comp_Win *cw)
{
   if (cw->visible) return;
   cw->visible = 1;
   DBG("  [0x%x] sho ++++++++++\n", cw->win);
   if ((cw->input_only) || (cw->invalid)) return;
   /*
   if (cw->redirected)
     {
        if (cw->native) evas_object_image_native_surface_set(cw->obj, NULL);
        if (cw->pixmap) ecore_x_pixmap_free(cw->pixmap);
        evas_object_image_size_set(cw->obj, 1, 1);
        cw->pixmap = 0;
        cw->pw = 0;
        cw->ph = 0;
        cw->native = 0;
        ecore_x_composite_unredirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
        cw->redirected = 0;
     }
   */
   if (!cw->redirected)
     {
        ecore_x_composite_redirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
        cw->pixmap = ecore_x_composite_name_window_pixmap_get(cw->win);
        if (cw->pixmap)
          ecore_x_pixmap_geometry_get(cw->pixmap, NULL, NULL, &(cw->pw), &(cw->ph));
        else
          {
             cw->pw = 0;
             cw->ph = 0;
          }
        if ((cw->pw <= 0) || (cw->ph <= 0))
          {
             ecore_x_pixmap_free(cw->pixmap);
             cw->pixmap = 0;
          }
        cw->redirected = 1;
     }
   evas_object_show(cw->obj);
   if (cw->shobj)
     {
        if (_comp_mod->conf->use_shadow)
          {
             if (_e_mod_comp_win_do_shadow(cw))
               {
                  int ok = 0;
                  char buf[PATH_MAX];
                  
                 // fimxe: make shadow object configurable - use theme first
                  if (_comp_mod->conf->shadow_file)
                    {
                       ok = 1;
                       if (!edje_object_file_set(cw->shobj, 
                                                 _comp_mod->conf->shadow_file,
                                                 "shadow"))
                         ok = 0;
                    }
                  if (!ok)
                    {
                       ok = 1;
                       if (!e_theme_edje_object_set(cw->shobj,
                                                    "base/theme/borders",
                                                    "e/shadow/box"))
                         ok = 0;
                    }
                  if (!ok)
                    {
                       snprintf(buf, sizeof(buf), "%s/shadow.edj", 
                                e_module_dir_get(_comp_mod->module)
                                );
                       edje_object_file_set(cw->shobj, buf, "shadow");
                    }
                  evas_object_show(cw->shobj);
               }
          }
     }
   _e_mod_comp_win_render_queue(cw);
   _e_mod_comp_win_show_effects_add(cw);
}

static void
_e_mod_comp_win_hide(E_Comp_Win *cw)
{
   if (!cw->defer_hide)
     {
        if (!cw->visible) return;
     }
   cw->defer_hide = 0;
   cw->visible = 0;
   if ((cw->input_only) || (cw->invalid)) return;
   DBG("  [0x%x] hid --\n", cw->win);
   _e_mod_comp_win_hide_effects_add(cw);
   if (cw->effects)
     {
        cw->defer_hide = 1;
        return; // defer rest of hide
     }
   if (cw->update_timeout)
     {
        ecore_timer_del(cw->update_timeout);
        cw->update_timeout = NULL;
     }
   if (_comp_mod->conf->efl_sync)
     {
        if ((cw->bd) && (cw->counter))
          ecore_x_e_comp_sync_end_send(cw->bd->client.win);
     }
   evas_object_hide(cw->obj);
   if (cw->shobj) evas_object_hide(cw->shobj);

   if (_comp_mod->conf->keep_unmapped)
     {
        // fixme: ask the x homies. why does this need to be done?
        // why free pixmap (+texture bound), undriect, then redirect again
        // getting pixmap againand well - getting texture too again. why?
        if (cw->redirected)
          {
             if (cw->native) evas_object_image_native_surface_set(cw->obj, NULL);
             if (cw->pixmap) ecore_x_pixmap_free(cw->pixmap);
             evas_object_image_size_set(cw->obj, 1, 1);
             cw->pixmap = 0;
             cw->pw = 0;
             cw->ph = 0;
             cw->native = 0;
             ecore_x_composite_unredirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
             ecore_x_composite_redirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
             cw->pixmap = ecore_x_composite_name_window_pixmap_get(cw->win);
             if (cw->pixmap)
               ecore_x_pixmap_geometry_get(cw->pixmap, NULL, NULL, &(cw->pw), &(cw->ph));
             else
               {
                  cw->pw = 0;
                  cw->ph = 0;
               }
             if ((cw->pw <= 0) || (cw->ph <= 0))
               {
                  ecore_x_pixmap_free(cw->pixmap);
                  cw->pixmap = 0;
               }
          }
        return;
     }
   
   if (cw->native)
     {
        evas_object_image_native_surface_set(cw->obj, NULL);
        cw->native = 0;
     }
   if (cw->pixmap)
     {
        ecore_x_pixmap_free(cw->pixmap);
        cw->pixmap = 0;
        cw->pw = 0;
        cw->ph = 0;
     }
   if (cw->xim)
     {
        evas_object_image_size_set(cw->obj, 1, 1);
        evas_object_image_data_set(cw->obj, NULL);
        ecore_x_image_free(cw->xim);
        cw->xim = NULL;
     }
   if (cw->redirected)
     {
        ecore_x_composite_unredirect_window(cw->win, ECORE_X_COMPOSITE_UPDATE_MANUAL);
        cw->redirected = 0;
        cw->pw = 0;
        cw->ph = 0;
     }
   _e_mod_comp_win_render_queue(cw);
}

static void
_e_mod_comp_win_raise_above(E_Comp_Win *cw, E_Comp_Win *cw2)
{
   DBG("  [0x%x] abv [0x%x]\n", cw->win, cw2->win);
   cw->c->wins = eina_inlist_remove(cw->c->wins, EINA_INLIST_GET(cw));
   cw->c->wins = eina_inlist_append_relative(cw->c->wins, 
                                             EINA_INLIST_GET(cw), 
                                             EINA_INLIST_GET(cw2));
   evas_object_stack_above(cw->obj, cw2->obj);
   if (cw->shobj)
     {
        evas_object_stack_below(cw->shobj, cw->obj);
     }
   _e_mod_comp_win_render_queue(cw);
}

static void
_e_mod_comp_win_raise(E_Comp_Win *cw)
{
   DBG("  [0x%x] rai\n", cw->win);
   cw->c->wins = eina_inlist_remove(cw->c->wins, EINA_INLIST_GET(cw));
   cw->c->wins = eina_inlist_append(cw->c->wins, EINA_INLIST_GET(cw));
   evas_object_raise(cw->obj);
   if (cw->shobj)
     {
        evas_object_stack_below(cw->shobj, cw->obj);
     }
   _e_mod_comp_win_render_queue(cw);
}

static void
_e_mod_comp_win_lower(E_Comp_Win *cw)
{
   DBG("  [0x%x] low\n", cw->win);
   cw->c->wins = eina_inlist_remove(cw->c->wins, EINA_INLIST_GET(cw));
   cw->c->wins = eina_inlist_prepend(cw->c->wins, EINA_INLIST_GET(cw));
   evas_object_lower(cw->obj);
   if (cw->shobj)
     {
        evas_object_stack_below(cw->shobj, cw->obj);
     }
   _e_mod_comp_win_render_queue(cw);
}

static void
_e_mod_comp_win_configure(E_Comp_Win *cw, int x, int y, int w, int h, int border)
{
   Eina_Bool moved = 0;
   
   if (!((x == cw->x) && (y == cw->y)))
     {
        DBG("  [0x%x] mov %4i %4i\n", cw->win, x, y);
        cw->x = x;
        cw->y = y;
        evas_object_move(cw->obj, cw->x, cw->y);
        if (cw->shobj)
          {
             evas_object_move(cw->shobj, cw->x, cw->y);
          }
        moved = 1;
     }
   if (!((w == cw->w) && (h == cw->h)))
     {
        DBG("  [0x%x] rsz %4ix%4i\n", cw->win, w, h);
        if (cw->pixmap)
          {
             DBG("  [0x%x] free pm %x\n", cw->win, cw->pixmap);
             ecore_x_pixmap_free(cw->pixmap);
             cw->pixmap = 0;
             cw->native = 0;
             cw->pw = 0;
             cw->ph = 0;
          }
        cw->w = w;
        cw->h = h;
        evas_object_resize(cw->obj, 
                           cw->w + (cw->border * 2), 
                           cw->h + (cw->border * 2));
        if (cw->shobj)
          {
             evas_object_resize(cw->shobj, 
                                cw->w + (cw->border * 2),
                                cw->h + (cw->border * 2));
          }
        if (cw->xim)
          {
             evas_object_image_data_set(cw->obj, NULL);
             ecore_x_image_free(cw->xim);
             cw->xim = NULL;
          }
        _e_mod_comp_win_damage(cw, 0, 0, cw->w, cw->h, 0);
     }
   if (cw->border != border)
     {
        cw->border = border;
        evas_object_resize(cw->obj, 
                           cw->w + (cw->border * 2), 
                           cw->h + (cw->border * 2));
        if (cw->shobj)
          {
             evas_object_resize(cw->shobj, 
                                cw->w + (cw->border * 2),
                                cw->h + (cw->border * 2));
          }
     }
   if ((cw->input_only) || (cw->invalid)) return;
   _e_mod_comp_win_render_queue(cw);
   if (moved) _e_mod_comp_win_move_effects_add(cw);
}

static void
_e_mod_comp_win_damage(E_Comp_Win *cw, int x, int y, int w, int h, Eina_Bool dmg)
{
   if ((cw->input_only) || (cw->invalid)) return;
   DBG("  [0x%x] dmg [%x] %4i %4i %4ix%4i\n", cw->win, cw->damage, x, y, w, h);
   if ((dmg) && (cw->damage))
     {
        Ecore_X_Region parts;
   
        parts = ecore_x_region_new(NULL, 0);
        ecore_x_damage_subtract(cw->damage, 0, parts);
        ecore_x_region_free(parts);
     }
   e_mod_comp_update_add(cw->up, x, y, w, h);
   if (dmg)
     {
        if (cw->counter)
          {
             if (!cw->update_timeout)
               cw->update_timeout = ecore_timer_add
               (ecore_animator_frametime_get() * 2, 
                _e_mod_comp_win_damage_timeout, cw);
             return;
          }
     }
   if (!cw->update)
     {
        cw->update = 1;
        cw->c->updates = eina_list_append(cw->c->updates, cw);
     }
   _e_mod_comp_win_render_queue(cw);
}

static void
_e_mod_comp_win_reshape(E_Comp_Win *cw)
{
   if (cw->shape_changed) return;
   cw->shape_changed = 1;
   if (!cw->update)
     {
        cw->update = 1;
        cw->c->updates = eina_list_append(cw->c->updates, cw);
     }
   e_mod_comp_update_add(cw->up, 0, 0, cw->w, cw->h);
   _e_mod_comp_win_render_queue(cw);
}

//////////////////////////////////////////////////////////////////////////

static int
_e_mod_comp_create(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Create *ev = event;
   E_Comp_Win *cw;
   E_Comp *c = _e_mod_comp_find(ev->parent);
   if (!c) return 1;
   if (_e_mod_comp_win_find(ev->win)) return 1;
   if (c->win == ev->win) return 1;
   if (c->ee_win == ev->win) return 1;
   cw = _e_mod_comp_win_add(c, ev->win);
   if (cw) _e_mod_comp_win_configure(cw, ev->x, ev->y, ev->w, ev->h, ev->border);
   return 1;
}

static int
_e_mod_comp_destroy(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Destroy *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   if (cw->effects) cw->delete_me = 1;
   else _e_mod_comp_win_del(cw);
   return 1;
}

static int
_e_mod_comp_show(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Show *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   if (cw->visible) return 1;
   _e_mod_comp_win_show(cw);
   return 1;
}

static int
_e_mod_comp_hide(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Hide *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   if (!cw->visible) return 1;
   _e_mod_comp_win_hide(cw);
   return 1;
}

static int
_e_mod_comp_reparent(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Reparent *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   DBG("== repar [0x%x] to [0x%x]\n", ev->win, ev->parent);
   if (ev->parent != cw->c->man->root)
     _e_mod_comp_win_del(cw);
   return 1;
}

static int
_e_mod_comp_configure(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Configure *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;

   if (ev->abovewin == 0)
     {
        if (EINA_INLIST_GET(cw)->prev) _e_mod_comp_win_lower(cw);
     }
   else
     {
        E_Comp_Win *cw2 = _e_mod_comp_win_find(ev->abovewin);

        if (cw2)
          {
             E_Comp_Win *cw3 = (E_Comp_Win *)(EINA_INLIST_GET(cw)->prev);

             if (cw3 != cw2)
               _e_mod_comp_win_raise_above(cw, cw2);
          }
     }
   
   if (!((cw->x == ev->x) && (cw->y == ev->y) &&
         (cw->w == ev->h) && (cw->h == ev->h) &&
         (cw->border == ev->border)))
     {
        _e_mod_comp_win_configure(cw, ev->x, ev->y, ev->w, ev->h, ev->border);
     }
   return 1;
}

static int
_e_mod_comp_stack(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Stack *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE) _e_mod_comp_win_raise(cw);
   else _e_mod_comp_win_lower(cw);
   return 1;
}

static int
_e_mod_comp_property(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Property *ev = event;
   return 1;
}

static int
_e_mod_comp_message(void *data, int type, void *event)
{
   Ecore_X_Event_Client_Message *ev = event;
   E_Comp_Win *cw = NULL;
   if ((ev->message_type != ECORE_X_ATOM_E_COMP_SYNC_DRAW_DONE) ||
       (ev->format != 32)) return 1;
   cw = _e_mod_comp_border_client_find(ev->data.l[0]);
   if (!cw) return 1;
   if (!cw->bd) return 1;
   if (ev->data.l[0] != cw->bd->client.win) return 1;
   if (cw->bd)
     {
        if (cw->counter)
          {
             if (!cw->update)
               {
                  if (cw->update_timeout)
                    {
                       ecore_timer_del(cw->update_timeout);
                       cw->update_timeout = NULL;
                    }
                  cw->update = 1;
                  cw->c->updates = eina_list_append(cw->c->updates, cw);
               }
             cw->drawme = 1;
             _e_mod_comp_win_render_queue(cw);
          }
     }
   return 1;
}

static int
_e_mod_comp_shape(void *data, int type, void *event)
{
   Ecore_X_Event_Window_Shape *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->win);
   if (!cw) return 1;
   _e_mod_comp_win_reshape(cw);
   return 1;
}

static int
_e_mod_comp_damage(void *data, int type, void *event)
{
   Ecore_X_Event_Damage *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_damage_find(ev->damage);
   if (!cw) return 1;
   _e_mod_comp_win_damage(cw, 
                          ev->area.x, ev->area.y, 
                          ev->area.width, ev->area.height, 1); 
   return 1;
}

static int
_e_mod_comp_randr(void *data, int type, void *event)
{
   Eina_List *l;
   E_Comp *c;

   EINA_LIST_FOREACH(compositors, l, c)
     {
        ecore_evas_resize(c->ee, c->man->w, c->man->h);
     }
   return 1;
}

static int
_e_mod_comp_bd_add(void *data, int type, void *event)
{
   E_Event_Border_Add *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: add/enable compositing here not in show event for borders
   return 1;
}

static int
_e_mod_comp_bd_del(void *data, int type, void *event)
{
   E_Event_Border_Remove *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   if (cw->bd == ev->border) _e_mod_comp_object_del(cw, ev->border);
   return 1;
}

static int
_e_mod_comp_bd_show(void *data, int type, void *event)
{
   E_Event_Border_Show *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: show compwin here
   return 1;
}

static int
_e_mod_comp_bd_hide(void *data, int type, void *event)
{
   E_Event_Border_Hide *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: hide compwin here
   return 1;
}

static int
_e_mod_comp_bd_move(void *data, int type, void *event)
{
   E_Event_Border_Move *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: do move here for composited bd
   return 1;
}

static int
_e_mod_comp_bd_resize(void *data, int type, void *event)
{
   E_Event_Border_Resize *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: do resize here instead of conf notify
   return 1;
}

static int
_e_mod_comp_bd_iconify(void *data, int type, void *event)
{
   E_Event_Border_Iconify *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: special iconfiy anim
   return 1;
}

static int
_e_mod_comp_bd_uniconify(void *data, int type, void *event)
{
   E_Event_Border_Uniconify *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: special uniconfiy anim
   return 1;
}

static int
_e_mod_comp_bd_urgent_change(void *data, int type, void *event)
{
   E_Event_Border_Urgent_Change *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: do special anim to show urgency
   return 1;
}

static int
_e_mod_comp_bd_focus_in(void *data, int type, void *event)
{
   E_Event_Border_Focus_In *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: can do anim on focus in
   return 1;
}

static int
_e_mod_comp_bd_focus_out(void *data, int type, void *event)
{
   E_Event_Border_Focus_Out *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: can do anim on focus out
   return 1;
}

static int
_e_mod_comp_bd_property(void *data, int type, void *event)
{
   E_Event_Border_Property *ev = event;
   E_Comp_Win *cw = _e_mod_comp_win_find(ev->border->win);
   if (!cw) return 1;
   // fimxe: check properties and adjust things if needed...
   return 1;
}

//////////////////////////////////////////////////////////////////////////

static E_Comp *
_e_mod_comp_add(E_Manager *man)
{
   E_Comp *c;
   Ecore_X_Window *wins;
   Ecore_X_Window_Attributes att;
   int i, num;
   
   c = calloc(1, sizeof(E_Comp));
   if (!c) return NULL;

   ecore_x_e_comp_sync_supported_set(man->root, _comp_mod->conf->efl_sync);
   
   c->man = man;
   c->win = ecore_x_composite_render_window_enable(man->root);
   if (!c->win)
     {
        e_util_dialog_internal
          (_("Compositor Error"),
           _("Your screen does not support the compositor<br>"
             "overlay window. This is needed for it to<br>"
             "function."));
        free(c);
        return NULL;
     }
   
   memset((&att), 0, sizeof(Ecore_X_Window_Attributes));
   ecore_x_window_attributes_get(c->win, &att);   
   
   if ((att.depth != 24) && (att.depth != 32))
     {
        e_util_dialog_internal
          (_("Compositor Error"),
           _("Your screen is not in 24/32bit display mode.<br>"
             "This is required to be your default depth<br>"
             "setting for the compositor to work properly."));
        ecore_x_composite_render_window_disable(c->win);
        free(c);
        return NULL;
     }
   
   if (c->man->num == 0) e_alert_composite_win = c->win;
   
   if (_comp_mod->conf->engine == E_EVAS_ENGINE_GL_X11)
     {
        c->ee = ecore_evas_gl_x11_new(NULL, c->win, 0, 0, man->w, man->h);
        if (c->ee)
          {
             c->gl = 1;
             ecore_evas_gl_x11_pre_post_swap_callback_set
               (c->ee, c, _e_mod_comp_pre_swap, NULL);
          }
     }
   if (!c->ee)
     c->ee = ecore_evas_software_x11_new(NULL, c->win, 0, 0, man->w, man->h);
   
   ecore_evas_comp_sync_set(c->ee, 0);
   ecore_evas_manual_render_set(c->ee, _comp_mod->conf->lock_fps);
   c->evas = ecore_evas_get(c->ee);
   ecore_evas_show(c->ee);
   
   c->ee_win = ecore_evas_software_x11_window_get(c->ee);
   ecore_x_screen_is_composited_set(c->man->num, c->ee_win);
   ecore_x_composite_unredirect_subwindows
     (c->man->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);

   wins = ecore_x_window_children_get(c->man->root, &num);
   if (wins)
     {
        for (i = 0; i < num; i++)
          {
             E_Comp_Win *cw;
             int x, y, w, h, border;
             
             cw = _e_mod_comp_win_add(c, wins[i]);
             if (!cw) continue;
             ecore_x_window_geometry_get(cw->win, &x, &y, &w, &h);
             border = ecore_x_window_border_width_get(cw->win);
             if (wins[i] == c->win) continue;
             _e_mod_comp_win_configure(cw, x, y, w, h, border);
             if (ecore_x_window_visible_get(wins[i]))
               {
                  _e_mod_comp_win_show(cw);
               }
          }
        free(wins);
     }
   
   return c;
}

static void
_e_mod_comp_del(E_Comp *c)
{
   E_Comp_Win *cw;
   
   if (c->grabbed)
     {
        c->grabbed = 0;
        ecore_x_ungrab();
     }
   ecore_x_screen_is_composited_set(c->man->num, 0);
   while (c->wins)
     {
        cw = (E_Comp_Win *)(c->wins);
        if (cw->counter)
          {
             ecore_x_sync_counter_free(cw->counter);
             cw->counter = 0;
          }
        _e_mod_comp_win_hide(cw);
        _e_mod_comp_win_del(cw);
     }
   ecore_evas_free(c->ee);
   ecore_x_composite_unredirect_subwindows
     (c->man->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);
   ecore_x_composite_render_window_disable(c->win);
   if (c->man->num == 0) e_alert_composite_win = 0;
   if (c->render_animator) ecore_animator_del(c->render_animator);
   if (c->update_job) ecore_job_del(c->update_job);
   
   ecore_x_e_comp_sync_supported_set(c->man->root, 0);
   
   free(c);
}

//////////////////////////////////////////////////////////////////////////

Eina_Bool
e_mod_comp_init(void)
{
   Eina_List *l;
   E_Manager *man;

{'fraction_non_alphanumeric': 0.14265883163377135, 'fraction_numerical': 0.008913567618908453, 'mean_word_length': 1.7701159395148467, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 1595, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 45, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6693401', 'n_tokens_mistral': 37852, 'n_tokens_neox': 36600, 'n_words': 6674}