#define EXECUTIVE_MODE_ENABLED
#define E_COMP_X
#include "e.h"

#define RANDR_VERSION_1_3 ((1 << 16) | 3)
#define RANDR_VERSION_1_4 ((1 << 16) | 4)

#define GRAV_SET(ec, grav)                                                         \
  ecore_x_window_gravity_set(e_client_util_pwin_get(ec), grav);                          \
  if (_e_comp_x_client_data_get(ec)->lock_win) ecore_x_window_gravity_set(_e_comp_x_client_data_get(ec)->lock_win, grav);

#ifdef HAVE_WAYLAND
# define E_COMP_X_PIXMAP_CHECK if ((e_pixmap_type_get(ec->pixmap) != E_PIXMAP_TYPE_X) && (!e_client_has_xwindow(ec))) return
#else
# define E_COMP_X_PIXMAP_CHECK if (!e_pixmap_is_x(ec->pixmap)) return
#endif
/* maybe make configurable?
 * not sure why anyone would want to change it...
 */
#define MOVE_COUNTER_LIMIT 50

#define PARENT_ACTIVATE_TIME 200
#define PARENT_ACTIVATE_LIMIT 2

EINTERN void _e_main_cb_x_fatal(void *data EINA_UNUSED);

typedef struct _Frame_Extents Frame_Extents;

struct _Frame_Extents
{
   int l, r, t, b;
};

struct _E_Comp_X_Data
{
   Ecore_X_Window lock_grab_break_wnd;

   Eina_List *retry_clients;
   Ecore_Timer *retry_timer;
   Eina_Bool restack E_BITFIELD;
};

typedef struct Pending_Configure
{
   Evas_Point point;
   Ecore_X_Window win;
   Ecore_Timer *timer;
} Pending_Configure;

static Eina_Hash *pending_configures;

static unsigned int focus_time = 0;
static unsigned int focus_canvas_time = 0;
static Ecore_Timer *focus_timer;
static E_Client *mouse_client;
static Eina_List *handlers = NULL;
static Eina_Hash *clients_win_hash = NULL;
static Eina_Hash *damages_hash = NULL;
static Eina_Hash *frame_extents = NULL;
static Eina_Hash *alarm_hash = NULL;

static Evas_Point mouse_in_coords = {-1, -1};
static Ecore_Job *mouse_in_job;
static E_Client *focus_job_client;
static Ecore_Job *focus_job;
static E_Client *unfocus_job_client;
static Ecore_Job *unfocus_job;
static Ecore_Idle_Enterer *_e_comp_x_post_client_idler = NULL;
static Ecore_Idle_Enterer *_x_idle_flush = NULL;
static Eina_List *post_clients = NULL;

static int _e_comp_x_mapping_change_disabled = 0;

static Ecore_X_Randr_Screen_Size screen_size = { -1, -1 };
static int screen_size_index = -1;

static Ecore_X_Atom backlight_atom = 0;

static Ecore_Timer *mouse_in_fix_check_timer = NULL;

static Eina_Hash *dead_wins;

static Ecore_Window _e_comp_x_suspend_grabbed; // window grabber for suspending pointer

static void _e_comp_x_hook_client_pre_frame_assign(void *d EINA_UNUSED, E_Client *ec);

static inline E_Comp_X_Client_Data *
_e_comp_x_client_data_get(const E_Client *ec)
{
#ifdef HAVE_WAYLAND
   if (!e_pixmap_is_x(ec->pixmap))
     return e_comp_wl_client_xwayland_data(ec);
#endif
   return ec->comp_data;
}

static Eina_Bool
_e_comp_x_flusher(void *data EINA_UNUSED)
{
   ecore_x_flush();
   return ECORE_CALLBACK_RENEW;
}

static inline Ecore_X_Window
_e_comp_x_client_window_get(const E_Client *ec)
{
   E_Comp_X_Client_Data *cd = _e_comp_x_client_data_get(ec);
   if (cd && cd->reparented)
     return e_client_util_pwin_get(ec);
   return e_client_util_win_get(ec);
}

static void
_e_comp_x_client_damage_add(E_Client *ec)
{
   Ecore_X_Window win;

   if (_e_comp_x_client_data_get(ec)->damage) return;
   win = _e_comp_x_client_window_get(ec);
   _e_comp_x_client_data_get(ec)->damage = ecore_x_damage_new(win, ECORE_X_DAMAGE_REPORT_DELTA_RECTANGLES);
   eina_hash_add(damages_hash, &_e_comp_x_client_data_get(ec)->damage, ec);
}

static void
_e_comp_x_focus_check(void)
{
   E_Client *focused;

   if (stopping || e_comp->nocomp) return;
   focused = e_client_focused_get();
   /* if there is no new focused or it is a non-X client,
    * focus comp canvas on focus-out */
   if ((!focused) || (!e_client_has_xwindow(focused)))
     {
        focus_canvas_time = ecore_x_current_time_get();
        focus_time = 0;
        if (e_comp->comp_type != E_PIXMAP_TYPE_X)
          e_grabinput_focus(e_comp->root, E_FOCUS_METHOD_PASSIVE);
// this breaks Qt because it seems to create override-redirect popup windows
// that it FOCUSES instead of grabbking the kbd like most other menu windows
// so this causes the parent window to lose focus in a way that then causes
// the popups to dismiss instantly
//             e_grabinput_focus(e_comp->ee_win, E_FOCUS_METHOD_PASSIVE);
// This might be more specific a workaround bit might miss other cases, so keep
// here as an idea and for future reference
        else
          {
             Ecore_X_Window focus_win = ecore_x_window_focus_get();
             if (focus_win)
               {
                  if ((ecore_x_window_root_get(focus_win) == focus_win) ||
                      (!ecore_x_icccm_transient_for_get(focus_win)))
                    e_grabinput_focus(e_comp->ee_win, E_FOCUS_METHOD_PASSIVE);
               }
             else
               e_grabinput_focus(e_comp->ee_win, E_FOCUS_METHOD_PASSIVE);
          }
     }
}

static void
_e_comp_x_client_modal_setup(E_Client *ec)
{
   E_Comp_X_Client_Data *pcd;

   ec->parent->modal = ec;
   ec->parent->lock_close = 1;
   pcd = _e_comp_x_client_data_get(ec->parent);
   if (!pcd->lock_win)
     {
        eina_hash_add(clients_win_hash, &pcd->lock_win, ec->parent);
        pcd->lock_win = ecore_x_window_input_new(e_client_util_pwin_get(ec->parent), 0, 0, ec->parent->w, ec->parent->h);
        e_comp_ignore_win_add(E_PIXMAP_TYPE_X, pcd->lock_win);
        ecore_x_window_show(pcd->lock_win);
        ecore_x_icccm_name_class_set(pcd->lock_win, "comp_data->lock_win", "comp_data->lock_win");
     }
}

static void
_e_comp_x_client_frame_update(E_Client *ec, int l, int r, int t, int b)
{
   ecore_x_netwm_frame_size_set(e_client_util_win_get(ec), l, r, t, b);
   ecore_x_e_frame_size_set(e_client_util_win_get(ec), l, r, t, b);
   _e_comp_x_client_data_get(ec)->frame_update = 0;
}

static Eina_List *iconshare = NULL;

typedef struct _E_Client_Icon_Entry E_Client_Icon_Entry;

struct _E_Client_Icon_Entry
{
   Ecore_X_Icon *icons;
   int num_icons;
   int ref;
};

static Ecore_X_Icon *
_e_comp_x_client_icon_deduplicate(Ecore_X_Icon *icons, int num_icons)
{
   int i;
   Eina_List *l;
   E_Client_Icon_Entry *ie;

   // unless the rest of e uses border icons OTHER than icon #0
   // then free the rest that we don't need anymore.
   for (i = 1; i < num_icons; i++)
     {
        E_FREE(icons[i].data);
     }
   // lookup icon data in icons cache/share
   EINA_LIST_FOREACH(iconshare, l, ie)
     {
        if ((ie->num_icons == num_icons) &&
            (num_icons  > 0) &&
            (ie->icons[0].width == icons[0].width) &&
            (ie->icons[0].height == icons[0].height) &&
            (!memcmp(ie->icons[0].data, icons[0].data,
                     icons[0].width * icons[0].height * 4)))
          {
             // found so free the input icons
             for (i = 0; i < num_icons; i++)
               free(icons[i].data);
             free(icons);
             // ref the shared/cached one
             ie->ref++;
             iconshare = eina_list_promote_list(iconshare, l);
             // and return that
             return ie->icons;
          }
     }
   // no hit - new entry to cache. add it
   ie = calloc(1, sizeof(E_Client_Icon_Entry));
   if (ie)
     {
        ie->icons = icons;
        ie->num_icons = num_icons;
        ie->ref = 1;
        iconshare = eina_list_prepend(iconshare, ie);
     }
   return icons;
}

static void
_e_comp_x_client_icon_free(Ecore_X_Icon *icons, int num_icons)
{
   int i;
   Eina_List *l;
   E_Client_Icon_Entry *ie;

   // lookup in icon share cache
   EINA_LIST_FOREACH(iconshare, l, ie)
     {
        if ((ie->num_icons == num_icons) &&
            (num_icons  > 0) &&
            (ie->icons[0].width == icons[0].width) &&
            (ie->icons[0].height == icons[0].height) &&
            (!memcmp(ie->icons[0].data, icons[0].data,
                     icons[0].width * icons[0].height * 4)))
          {
             // found so deref
             ie->ref--;
             if (ie->ref <= 0)
               {
                  // no refs left - free the icon from the share/cache
                  iconshare = eina_list_remove_list(iconshare, l);
                  for (i = 0; i < ie->num_icons; i++)
                    free(ie->icons[i].data);
                  free(ie->icons);
                  free(ie);
               }
             return;
          }
     }
   // not found - so just free it ... odd - we should never be here
   for (i = 0; i < num_icons; i++)
     free(icons[i].data);
   free(icons);
}

static void
_e_comp_x_client_event_free(void *d EINA_UNUSED, void *e)
{
   E_Event_Client *ev = e;

   UNREFD(ev->ec, 1);
   e_object_unref(E_OBJECT(ev->ec));
   free(ev);
}

static void
_e_comp_x_print_win(Ecore_X_Window win)
{
   int x, y, w, h;
   Eina_Bool vis;

   ecore_x_window_geometry_get(win, &x, &y, &w, &h);
   vis = ecore_x_window_visible_get(win);
   fprintf(stderr, "%s 0x%x: %d,%d @ %dx%d\n", vis ? "VIS" : "HID", win, x, y, w, h);
}

static void
_e_comp_x_focus_grab(E_Client *ec)
{
   if (ec->internal_elm_win) return;
   ecore_x_window_button_grab(e_client_util_win_get(ec), 1,
                              ECORE_X_EVENT_MASK_MOUSE_DOWN |
                              ECORE_X_EVENT_MASK_MOUSE_UP |
                              ECORE_X_EVENT_MASK_MOUSE_MOVE, 0, 1);
   ecore_x_window_button_grab(e_client_util_win_get(ec), 2,
                              ECORE_X_EVENT_MASK_MOUSE_DOWN |
                              ECORE_X_EVENT_MASK_MOUSE_UP |
                              ECORE_X_EVENT_MASK_MOUSE_MOVE, 0, 1);
   ecore_x_window_button_grab(e_client_util_win_get(ec), 3,
                              ECORE_X_EVENT_MASK_MOUSE_DOWN |
                              ECORE_X_EVENT_MASK_MOUSE_UP |
                              ECORE_X_EVENT_MASK_MOUSE_MOVE, 0, 1);
   _e_comp_x_client_data_get(ec)->button_grabbed = 1;
}

static void
_e_comp_x_focus_init(E_Client *ec)
{
   if (_e_comp_x_client_data_get(ec)->button_grabbed) return;
   if (!((e_client_focus_policy_click(ec)) ||
       (e_config->always_click_to_raise) ||
       (e_config->always_click_to_focus))) return;
   _e_comp_x_focus_grab(ec);
}

static void
_e_comp_x_focus_setup(E_Client *ec)
{
   if (_e_comp_x_client_data_get(ec)->button_grabbed) return;
   if ((!e_client_focus_policy_click(ec)) ||
       (e_config->always_click_to_raise) ||
       (e_config->always_click_to_focus)) return;
   _e_comp_x_focus_grab(ec);
}


static void
_e_comp_x_focus_setdown(E_Client *ec)
{
   Ecore_X_Window win, pwin;

   if (!_e_comp_x_client_data_get(ec)->button_grabbed) return;
   if ((!e_client_focus_policy_click(ec)) ||
       (e_config->always_click_to_raise) ||
       (e_config->always_click_to_focus)) return;
   win = e_client_util_win_get(ec);
   pwin = e_client_util_pwin_get(ec);
   e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, pwin);
   e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, pwin);
   ecore_x_window_button_ungrab(win, 1, 0, 1);
   ecore_x_window_button_ungrab(win, 2, 0, 1);
   ecore_x_window_button_ungrab(win, 3, 0, 1);
   e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, pwin);
   e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, pwin);
   _e_comp_x_client_data_get(ec)->button_grabbed = 0;
}

static Eina_Bool
_e_comp_x_client_new_helper(E_Client *ec)
{
   Ecore_X_Window win = e_client_util_win_get(ec);
   int at_num = 0, i;
   Ecore_X_Atom *atoms;

   if (!ecore_x_window_attributes_get(win, &ec->comp_data->initial_attributes))
     {
        //CRI("OUCH! FIX THIS!");
        DELD(ec, 1);
        e_object_del(E_OBJECT(ec));
        return EINA_FALSE;
     }
   if (ec->re_manage && (!ec->comp_data->initial_attributes.visible))
     {
        /* ain't gonna be no hidden clients on my watch! */
        DELD(ec, 1);
        e_object_del(E_OBJECT(ec));
        return EINA_FALSE;
     }
   ec->depth = ec->comp_data->initial_attributes.depth;
   ec->override = ec->comp_data->initial_attributes.override;
   ec->placed |= ec->override;
   ec->input_only = ec->comp_data->initial_attributes.input_only;
   ec->border_size = ec->comp_data->initial_attributes.border;
   ec->icccm.accepts_focus = (!ec->override) && (!ec->input_only);
   //INF("NEW CLIENT: %d,%d -> %d,%d", ec->x, ec->y, ec->comp_data->initial_attributes.x, ec->comp_data->initial_attributes.y);
   ec->x = ec->client.x = ec->comp_data->initial_attributes.x;
   ec->y = ec->client.y = ec->comp_data->initial_attributes.y;
   if (ec->override && ((ec->x == -77) && (ec->y == -777)))
     {
        /* this is the ecore-x private window :/ */
        e_comp_ignore_win_add(E_PIXMAP_TYPE_X, win);
        DELD(ec, 1);
        e_object_del(E_OBJECT(ec));
        return EINA_FALSE;
     }
   if ((!e_client_util_ignored_get(ec)) && (!ec->internal) && (!ec->internal_elm_win))
     {
        ec->comp_data->need_reparent = 1;
        EC_CHANGED(ec);
        ec->take_focus = !starting;
     }
   ec->new_client ^= ec->override;
   if (!ec->new_client)
     e_comp->new_clients--;

   ec->w = ec->client.w = ec->comp_data->initial_attributes.w;
   ec->h = ec->client.h = ec->comp_data->initial_attributes.h;
   if (!ec->internal)
     {
        ec->comp_data->pw = ec->w;
        ec->comp_data->ph = ec->h;
     }
   ec->changes.size = 1;


   e_pixmap_visual_cmap_set(ec->pixmap, ec->comp_data->initial_attributes.visual, ec->comp_data->initial_attributes.colormap);
   if (ec->override && (!ec->internal))
     ecore_x_window_shape_events_select(win, 1);
   if (ec->override && (!(ec->comp_data->initial_attributes.event_mask.mine & ECORE_X_EVENT_MASK_WINDOW_PROPERTY)))
     ecore_x_event_mask_set(win, ECORE_X_EVENT_MASK_WINDOW_PROPERTY);

   atoms = ecore_x_window_prop_list(win, &at_num);
   ec->icccm.fetch.command = 1;

   if (atoms)
     {
        Eina_Bool video_parent = EINA_FALSE;
        Eina_Bool video_position = EINA_FALSE;
        Eina_Bool found_desk = EINA_FALSE;
        Eina_Bool found_zone = EINA_FALSE;

        /* icccm */
        for (i = 0; i < at_num; i++)
          {
             if (atoms[i] == ECORE_X_ATOM_WM_NAME)
               ec->icccm.fetch.title = 1;
             else if (atoms[i] == ECORE_X_ATOM_WM_CLASS)
               ec->icccm.fetch.name_class = 1;
             else if (atoms[i] == ECORE_X_ATOM_WM_ICON_NAME)
               ec->icccm.fetch.icon_name = 1;
             else if (atoms[i] == ECORE_X_ATOM_WM_CLIENT_MACHINE)
               ec->icccm.fetch.machine = 1;
             else if (atoms[i] == ECORE_X_ATOM_WM_HINTS)
               ec->icccm.fetch.hints = 1;
             else if (atoms[i] == ECORE_X_ATOM_WM_NORMAL_HINTS)
               ec->icccm.fetch.size_pos_hints = 1;
             else if (atoms[i] == ECORE_X_ATOM_WM_PROTOCOLS)
               ec->icccm.fetch.protocol = 1;
             else if (atoms[i] == ECORE_X_ATOM_MOTIF_WM_HINTS)
               ec->mwm.fetch.hints = 1;
             else if (atoms[i] == ECORE_X_ATOM_WM_TRANSIENT_FOR)
               {
                  ec->icccm.fetch.transient_for = 1;
                  ec->netwm.fetch.type = 1;
               }
             else if (atoms[i] == ECORE_X_ATOM_WM_CLIENT_LEADER)
               ec->icccm.fetch.client_leader = 1;
             else if (atoms[i] == ECORE_X_ATOM_WM_WINDOW_ROLE)
               ec->icccm.fetch.window_role = 1;
          }
        /* netwm, loop again, netwm will ignore some icccm, so we
         * have to be sure that netwm is checked after */
        for (i = 0; i < at_num; i++)
          {
             if (atoms[i] == ECORE_X_ATOM_NET_WM_NAME)
               {
                  /* Ignore icccm */
                  ec->icccm.fetch.title = 0;
                  ec->netwm.fetch.name = 1;
               }
             else if (atoms[i] == ECORE_X_ATOM_NET_WM_ICON_NAME)
               {
                  /* Ignore icccm */
                  ec->icccm.fetch.icon_name = 0;
                  ec->netwm.fetch.icon_name = 1;
               }
             else if (atoms[i] == ECORE_X_ATOM_NET_WM_ICON)
               {
                  ec->netwm.fetch.icon = 1;
               }
             else if (atoms[i] == ECORE_X_ATOM_NET_WM_USER_TIME)
               {
                  ec->netwm.fetch.user_time = 1;
               }
             else if (atoms[i] == ECORE_X_ATOM_NET_WM_STRUT)
               {
                  DBG("ECORE_X_ATOM_NET_WM_STRUT");
                  ec->netwm.fetch.strut = 1;
               }
             else if (atoms[i] == ECORE_X_ATOM_NET_WM_STRUT_PARTIAL)
               {
                  DBG("ECORE_X_ATOM_NET_WM_STRUT_PARTIAL");
                  ec->netwm.fetch.strut = 1;
               }
             else if (atoms[i] == ECORE_X_ATOM_NET_WM_WINDOW_TYPE)
               {
                  /* Ignore mwm
                     ec->mwm.fetch.hints = 0;
                   */
                  ec->netwm.fetch.type = 1;
               }
             else if (atoms[i] == ECORE_X_ATOM_NET_WM_STATE)
               {
                  ec->netwm.fetch.state = 1;
               }
             else if (atoms[i] == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY)
               ec->netwm.fetch.opacity = 1;
          }
        /* other misc atoms */
        for (i = 0; i < at_num; i++)
          {
             /* loop to check for own atoms */
             if (atoms[i] == E_ATOM_WINDOW_STATE)
               {
                  ec->e.fetch.state = 1;
               }
             /* loop to check for qtopia atoms */
             if (atoms[i] == ATM__QTOPIA_SOFT_MENU)
               ec->qtopia.fetch.soft_menu = 1;
             else if (atoms[i] == ATM__QTOPIA_SOFT_MENUS)
               ec->qtopia.fetch.soft_menus = 1;
             /* loop to check for vkbd atoms */
             else if (atoms[i] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE)
               ec->vkbd.fetch.state = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD)
               ec->vkbd.fetch.vkbd = 1;
             /* loop to check for illume atoms */
             else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_CONFORMANT)
               ec->comp_data->illume.conformant.fetch.conformant = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE)
               ec->comp_data->illume.quickpanel.fetch.state = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL)
               ec->comp_data->illume.quickpanel.fetch.quickpanel = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR)
               ec->comp_data->illume.quickpanel.fetch.priority.major = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR)
               ec->comp_data->illume.quickpanel.fetch.priority.minor = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE)
               ec->comp_data->illume.quickpanel.fetch.zone = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED)
               ec->comp_data->illume.drag.fetch.locked = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_DRAG)
               ec->comp_data->illume.drag.fetch.drag = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE)
               ec->comp_data->illume.win_state.fetch.state = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_VIDEO_PARENT)
               video_parent = EINA_TRUE;
             else if (atoms[i] == ECORE_X_ATOM_E_VIDEO_POSITION)
               video_position = EINA_TRUE;
             /* loop to check for window profile list atom */
             else if (atoms[i] == ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED)
               ec->e.fetch.profile = 1;
             else if (atoms[i] == ECORE_X_ATOM_E_STACK_TYPE)
               ec->e.fetch.stack = 1;
             else if (atoms[i] == ATM_GTK_FRAME_EXTENTS)
               ec->comp_data->fetch_gtk_frame_extents = 1;
             else if (atoms[i] == ATM_STEAM_GAME)
               e_hints_window_steam_game_get(ec);
             else if (ec->re_manage)
               {
                  if (atoms[i] == E_ATOM_DESKTOP_FILE)
                    {
                       char *path = ecore_x_window_prop_string_get(win,
                                                             E_ATOM_DESKTOP_FILE);
                       if (path)
                         {
                            ec->desktop = efreet_desktop_get(path);
                            free(path);
                         }
                    }
                  else if (atoms[i] == E_ATOM_DESK)
                    found_desk = 1;
                  else if (atoms[i] == E_ATOM_ZONE)
                    found_zone = 1;
               }
          }
        if (video_position && video_parent)
          {
             ec->e.state.video = 1;
             ec->e.fetch.video_parent = 1;
             ec->e.fetch.video_position = 1;
             fprintf(stderr, "We found a video window \\o/ %x\n", win);
          }
        free(atoms);

        if (ec->re_manage && found_desk && found_zone)
          {
             E_Zone *zone = NULL;
             E_Desk *desk = NULL;
             unsigned int id, deskxy[2];
             int ret;

             /* get all information from window before it is
              * reset by e_client_new */
             ret = ecore_x_window_prop_card32_get(win,
                                                  E_ATOM_ZONE,
                                                  &id, 1);
             if (ret == 1)
               zone = e_comp_zone_number_get(id);
             if (!zone)
               zone = e_zone_current_get();
             ret = ecore_x_window_prop_card32_get(win,
                                                  E_ATOM_DESK,
                                                  deskxy, 2);
             if (ret == 2)
               desk = e_desk_at_xy_get(zone,
                                       deskxy[0],
                                       deskxy[1]);

             if (desk) e_client_desk_set(ec, desk);

          }
     }

   return EINA_TRUE;
}

static E_Client *
_e_comp_x_client_find_by_damage(Ecore_X_Damage damage)
{
   return eina_hash_find(damages_hash, &damage);
}

static E_Client *
_e_comp_x_client_find_by_window(Ecore_X_Window win)
{
   E_Client *ec;

   ec = eina_hash_find(clients_win_hash, &win);
   if (ec && e_object_is_del(E_OBJECT(ec))) ec = NULL;
   return ec;
}

/*
static E_Client *
_e_comp_x_client_find_all_by_window(Ecore_X_Window win)
{
   return eina_hash_find(clients_win_hash, &win);
}
*/

static void
_e_comp_x_add_fail_job(void *d EINA_UNUSED)
{
   e_util_dialog_internal
     (_("Compositor Warning"),
      _("Your display driver does not support OpenGL, GLSL<ps/>"
        "shaders or no OpenGL engines were compiled or installed<ps/>"
        "for Evas or Ecore-Evas. Falling back to software engine.<ps/>"
        "<ps/>"
        "You will need an OpenGL 2.0 (or OpenGL ES 2.0) capable<ps/>"
        "GPU to use OpenGL with compositing."));
}

static void
_pri_adj(int pid, int set, int adj, Eina_Bool use_adj, Eina_Bool adj_children, Eina_Bool do_children)
{
   int newpri = set;

   if (use_adj) newpri = getpriority(PRIO_PROCESS, pid) + adj;
   setpriority(PRIO_PROCESS, pid, newpri);
// shouldn't need to do this as default ionice class is "none" (0), and
// this inherits io priority FROM nice level
//        ioprio_set(IOPRIO_WHO_PROCESS, pid,
//                   IOPRIO_PRIO_VALUE(2, 5));
   if (do_children)
     {
        Eina_List *files;
        char *file, buf[PATH_MAX];
        FILE *f;
        int pid2, ppid;

        // yes - this is /proc specific... so this may not work on some
        // os's - works on linux. too bad for others.
        files = ecore_file_ls("/proc");
        EINA_LIST_FREE(files, file)
          {
             if (isdigit(file[0]))
               {
                  snprintf(buf, sizeof(buf), "/proc/%s/stat", file);
                  f = fopen(buf, "r");
                  if (f)
                    {
                       pid2 = -1;
                       ppid = -1;
                       if (fscanf(f, "%i %*s %*s %i %*s", &pid2, &ppid) == 2)
                         {
                            fclose(f);
                            if (ppid == pid)
                              {
                                 if (adj_children)
                                   _pri_adj(pid2, set, adj, EINA_TRUE,
                                            adj_children, do_children);
                                 else
                                   _pri_adj(pid2, set, adj, use_adj,
                                            adj_children, do_children);
                              }
                         }
                       else fclose(f);
                    }
               }
             free(file);
          }
     }
}

static E_Client *
_e_comp_x_client_find_by_alarm(Ecore_X_Sync_Alarm al)
{
   return eina_hash_find(alarm_hash, &al);
}

static void
_e_comp_x_client_move_resize_send(E_Client *ec)
{
   if (ec->internal_elm_win)
     ecore_evas_managed_move(e_win_ee_get(ec->internal_elm_win), ec->client.x - ec->x, ec->client.y - ec->y);

   ecore_x_icccm_move_resize_send(e_client_util_win_get(ec), ec->client.x, ec->client.y, ec->client.w, ec->client.h);
}

static Eina_Bool
_e_comp_x_post_client_idler_cb(void *d EINA_UNUSED)
{
   E_Client *ec;

   //INF("POST IDLER");
   EINA_LIST_FREE(post_clients, ec)
     {
        Ecore_X_Window win, twin;

        if (e_object_is_del(E_OBJECT(ec)) || (!_e_comp_x_client_data_get(ec))) continue;
        win = _e_comp_x_client_window_get(ec);
        if (ec->post_move)
          {
             E_Client *tmp;
             Eina_List *l;

             EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
               {
                  twin = _e_comp_x_client_window_get(tmp);
                  ecore_x_window_move(twin,
                                      ec->client.x +
                                      tmp->e.state.video_position.x,
                                      ec->client.y +
                                      tmp->e.state.video_position.y);
               }
          }
        if (ec->e.state.video)
          {
             E_Client *parent;

             parent = ec->e.state.video_parent_client;
             twin = _e_comp_x_client_window_get(parent);
             ecore_x_window_move(twin,
                                 parent->client.x +
                                 ec->e.state.video_position.x,
                                 parent->client.y +
                                 ec->e.state.video_position.y);
          }
        else if (ec->shading)
          {
             // do nothing
          }
        else if ((ec->post_move) && (ec->post_resize))
          {
             //INF("X MVRSZ");
             ecore_x_window_move_resize(win,
                                        ec->client.x,
                                        ec->client.y,
                                        ec->client.w,
                                        ec->client.h);
             if (_e_comp_x_client_data_get(ec)->reparented)
               ecore_x_window_move_resize(e_client_util_win_get(ec), 0, 0,
                                          ec->client.w,
                                          ec->client.h);
          }
        else if (ec->post_move)
          {
             //INF("X MV");
             ecore_x_window_move(win, ec->client.x, ec->client.y);
          }
        else if (ec->post_resize)
          {
             //INF("X RSZ: %dx%d (REAL: %dx%d)", ec->client.w, ec->client.h, ec->w, ec->h);
             ecore_x_window_resize(win,
                                   ec->client.w, ec->client.h);
             if (_e_comp_x_client_data_get(ec)->reparented)
               ecore_x_window_move_resize(e_client_util_win_get(ec), 0, 0,
                                          ec->client.w, ec->client.h);
          }
        if ((!ec->shading) && (!ec->shaded))
          {
             if (ec->post_resize)
               {
                  if (ec->netwm.sync.request && (e_comp->comp_type == E_PIXMAP_TYPE_X))
                    {
                       //INF("NETWM SYNC: %p", ec);
                       ec->netwm.sync.wait++;
                       ecore_x_netwm_sync_request_send(e_client_util_win_get(ec),
                                                       ec->netwm.sync.serial++);
                    }
               }

             if (ec->post_move || ec->post_resize)
               _e_comp_x_client_move_resize_send(ec);
          }

        if (ec->e.state.video)
          {
             fprintf(stderr, "VIDEO %p: [%i, %i] [%i, %i]\n",
                     ec,
                     ec->e.state.video_parent_client->client.x +
                     ec->e.state.video_position.x,
                     ec->e.state.video_parent_client->client.y +
                     ec->e.state.video_position.y,
                     ec->w, ec->h);
          }
        if (ec->netwm.opacity_changed)
          {
             unsigned int opacity;
             int op;

             evas_object_color_get(ec->frame, NULL, NULL, NULL, &op);
             ec->netwm.opacity = op;
             opacity = (op << 24) | (op << 16) | (op << 8) | op;
             ecore_x_window_prop_card32_set(e_client_util_win_get(ec), ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, &opacity, 1);
             /* flag gets unset in property cb to avoid fetching opacity after we just set it */
          }
        if (e_pixmap_is_x(ec->pixmap) && ec->post_resize)
          {
             e_pixmap_dirty(ec->pixmap);
             e_comp_object_render_update_del(ec->frame);
             if (!ec->internal)
               {
                  _e_comp_x_client_data_get(ec)->pw = ec->client.w;
                  _e_comp_x_client_data_get(ec)->ph = ec->client.h;
               }
          }
        ec->post_move = 0;
        ec->post_resize = 0;
     }
   if (e_comp_x->restack && (!e_comp->new_clients))
     {
        e_hints_client_stacking_set();
        e_comp_x->restack = 0;
     }
   _e_comp_x_post_client_idler = NULL;
   return EINA_FALSE;
}

static void
_e_comp_x_post_client_idler_add(E_Client *ec)
{
   if (!_e_comp_x_post_client_idler)
     _e_comp_x_post_client_idler = ecore_idle_enterer_add(_e_comp_x_post_client_idler_cb, NULL);
   if (!ec) CRI("ACK!");
   //INF("POST IDLE: %p", ec);
   if (!eina_list_data_find(post_clients, ec))
     post_clients = eina_list_append(post_clients, ec);
}

static void
_e_comp_x_client_stack(E_Client *ec)
{
   E_Client *ec2;
   Ecore_X_Window_Stack_Mode mode = ECORE_X_WINDOW_STACK_BELOW;
   Ecore_X_Window cwin, win = 0;
   Eina_List *l;

   if (ec->override && (!ec->internal)) return; //can't restack these
   if (e_client_is_stacking(ec)) return;
   if (!_e_comp_x_client_data_get(ec)) return;
   if (_e_comp_x_client_data_get(ec)->unredirected_single) return;

   cwin = _e_comp_x_client_window_get(ec);

   ecore_x_window_shadow_tree_flush();

   /* try stacking below */
   if (e_comp->nocomp_ec && e_comp->nocomp_ec->comp_data && (ec != e_comp->nocomp_ec))
     win = _e_comp_x_client_window_get(e_comp->nocomp_ec);
   else
     {
        ec2 = ec;
        do
          {
             ec2 = e_client_above_get(ec2);
             if (ec2 && e_client_has_xwindow(ec2) && ec2->comp_data && (!ec2->new_client) &&
                 (e_client_is_stacking(ec2) || ((!ec2->override) || ec2->internal)))
               {
                  if (ec2->layer != ec->layer) break;
                  if (_e_comp_x_client_data_get(ec2)->need_reparent && (!_e_comp_x_client_data_get(ec2)->reparented)) continue;
                  win = _e_comp_x_client_window_get(ec2);
               }
          } while (ec2 && (!win));
     }

   /* try stacking above */
   if (!win)
     {
        ec2 = ec;
        do
          {
             ec2 = e_client_below_get(ec2);
             if (ec2 && e_client_has_xwindow(ec2) && ec2->comp_data && (!ec2->new_client) &&
                 (e_client_is_stacking(ec2) || ((!ec2->override) || ec2->internal)))
               {
                  if (ec2->layer != ec->layer) break;
                  if (_e_comp_x_client_data_get(ec2)->need_reparent && (!_e_comp_x_client_data_get(ec2)->reparented)) continue;
                  win = _e_comp_x_client_window_get(ec2);
                  mode = ECORE_X_WINDOW_STACK_ABOVE;
               }
          } while (ec2 && (!win));
     }

   /* just layer stack */
   if (!win)
     {
        win = e_comp->layers[e_comp_canvas_layer_map(ec->layer)].win;
        mode = ECORE_X_WINDOW_STACK_BELOW;
     }
   ecore_x_window_configure(cwin,
                            ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
                            ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
                            0, 0, 0, 0, 0, win, mode);
   _e_comp_x_post_client_idler_add(ec);
   e_comp_x->restack = 1;
   EINA_LIST_FOREACH(ec->e.state.video_child, l, ec2)
     evas_object_stack_below(ec2->frame, ec->frame);
}

static E_Client *
_e_comp_x_client_new(Ecore_X_Window win, Eina_Bool first)
{
   E_Pixmap *cp;
   E_Client *ec;

   cp = e_pixmap_new(E_PIXMAP_TYPE_X, win);
   EINA_SAFETY_ON_NULL_RETURN_VAL(cp, NULL);

   ec = e_client_new(cp, first, 0);
   return ec;
}

static void
_e_comp_x_client_pri_raise(E_Client *ec)
{
   if (ec->netwm.pid <= 0) return;
   if (ec->netwm.pid == getpid()) return;
   _pri_adj(ec->netwm.pid,
            e_config->priority - 1, -1, EINA_FALSE,
//            EINA_TRUE, EINA_TRUE);
            EINA_TRUE, EINA_FALSE);
//   printf("WIN: pid %i, title %s (HI!!!!!!!!!!!!!!!!!!)\n",
//          ec->netwm.pid, e_client_util_name_get(ec));
}

static void
_e_comp_x_client_pri_norm(E_Client *ec)
{
   if (ec->netwm.pid <= 0) return;
   if (ec->netwm.pid == getpid()) return;
   _pri_adj(ec->netwm.pid,
            e_config->priority, 1, EINA_FALSE,
//            EINA_TRUE, EINA_TRUE);
            EINA_TRUE, EINA_FALSE);
//   printf("WIN: pid %i, title %s (NORMAL)\n",
//          ec->netwm.pid, e_client_util_name_get(ec));
}

static void
_e_comp_x_client_shape_input_rectangle_set(E_Client *ec)
{
   Ecore_X_Window win = e_client_util_pwin_get(ec);

   if (ec->override || (!_e_comp_x_client_data_get(ec)->reparented)) return;

   if (ec->visible && (!ec->comp_hidden))
     ecore_x_composite_window_events_enable(win);
   else
     ecore_x_composite_window_events_disable(win);
}

static void
_e_comp_x_evas_color_set_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
   E_Client *ec = data;
   int a;

   if (!_e_comp_x_client_data_get(ec)) return;
   evas_object_color_get(obj, NULL, NULL, NULL, &a);
   if (a == ec->netwm.opacity) return;
   ec->netwm.opacity_changed = 1;
   _e_comp_x_post_client_idler_add(ec);
}

static void
_e_comp_x_evas_ping_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data;

   if (!_e_comp_x_client_data_get(ec)) return;
   ecore_x_netwm_ping_send(e_client_util_win_get(ec));
}

static void
_e_comp_x_evas_kill_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data;

   if (!_e_comp_x_client_data_get(ec)) return;
   ecore_x_kill(e_client_util_win_get(ec));
}

static void
_e_comp_x_evas_delete_request_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data;

   if (!_e_comp_x_client_data_get(ec)) return;
   if (ec->netwm.ping)
     e_client_ping(ec);
   ecore_x_window_delete_request_send(e_client_util_win_get(ec));
}

static void
_e_comp_x_evas_comp_hidden_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *tmp, *ec = data;
   Eina_List *l;
   Ecore_X_Window win;

   if (!_e_comp_x_client_data_get(ec)) return;
   if (_e_comp_x_client_data_get(ec)->need_reparent) return;
   win = _e_comp_x_client_window_get(ec);

   EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
     {
        Ecore_X_Window cwin;

        cwin = _e_comp_x_client_window_get(tmp);
        if (ec->comp_hidden)
          ecore_x_window_hide(cwin);
        else
          ecore_x_window_show(cwin);
     }

   if ((ec->internal) && (win == e_client_util_win_get(ec))) return;
   if (ec->comp_hidden)
     ecore_x_composite_window_events_disable(win);
   else
     ecore_x_composite_window_events_enable(win);
    ecore_x_window_ignore_set(win, ec->comp_hidden);
}

static void
_e_comp_x_evas_shade_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data;
   Eina_List *l;
   E_Client *tmp;

   if (!_e_comp_x_client_data_get(ec)) return;
   EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
     ecore_x_window_hide(e_client_util_pwin_get(tmp));

   ecore_x_window_shadow_tree_flush();
}

static void
_e_comp_x_evas_frame_recalc_cb(void *data, Evas_Object *obj, void *event_info)
{
   E_Client *ec = data;
   E_Comp_Object_Frame *fr = event_info;

   if (!_e_comp_x_client_data_get(ec)) return;
   if (evas_object_visible_get(obj))
     _e_comp_x_client_frame_update(ec, fr->l, fr->r, fr->t, fr->b);
   else
     _e_comp_x_client_data_get(ec)->frame_update = 1;
   ec->post_move = ec->post_resize = 1;
   _e_comp_x_post_client_idler_add(ec);
}

static void
_e_comp_x_evas_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data;

   if (!_e_comp_x_client_data_get(ec)) return;
   if (_e_comp_x_client_data_get(ec)->moving && (!_e_comp_x_client_data_get(ec)->unredirected_single))
     {
        if (_e_comp_x_client_data_get(ec)->move_counter++ < MOVE_COUNTER_LIMIT) return;
        _e_comp_x_client_data_get(ec)->move_counter = 0;
     }

   ecore_x_window_shadow_tree_flush();
   ec->post_move = 1;
   _e_comp_x_post_client_idler_add(ec);
}

static void
_e_comp_x_evas_resize_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data;

   if (!_e_comp_x_client_data_get(ec)) return;
   if (ec->shading || ec->shaded) return;
   if (!e_pixmap_size_changed(ec->pixmap, ec->client.w, ec->client.h)) return;

   ecore_x_window_shadow_tree_flush();

   if (ec->e.state.video)
     {
        if (ec->e.state.video_position.updated)
          {
             ecore_x_window_move(e_client_util_pwin_get(ec),
                                 ec->e.state.video_parent_client->client.x +
                                 ec->e.state.video_position.x,
                                 ec->e.state.video_parent_client->client.y +
                                 ec->e.state.video_position.y);
             ec->e.state.video_position.updated = 0;
          }
     }
   else if (ec->changes.pos)
     {
        E_Client *tmp;
        Eina_List *l;

        EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
          ecore_x_window_move(e_client_util_pwin_get(tmp),
                              ec->client.x + tmp->e.state.video_position.x,
                              ec->client.y + tmp->e.state.video_position.y);
     }

   ec->post_resize = 1;
   if (e_pixmap_is_x(ec->pixmap))
     e_comp_object_render_update_del(ec->frame);
   _e_comp_x_post_client_idler_add(ec);
}

static void
_e_comp_x_client_hide(E_Client *ec)
{
   unsigned int visible = 0;

   ecore_x_window_shadow_tree_flush();
   if ((!ec->iconic) && (!ec->override))
     ecore_x_window_prop_card32_set(e_client_util_win_get(ec), E_ATOM_MAPPED, &visible, 1);

   _e_comp_x_client_data_get(ec)->iconic = ec->iconic && (!e_comp_object_mirror_visibility_check(ec->frame));
   if (ec->unredirected_single || _e_comp_x_client_data_get(ec)->iconic)
     ecore_x_window_hide(_e_comp_x_client_window_get(ec));
   if (_e_comp_x_client_data_get(ec)->iconic)
     e_hints_window_iconic_set(ec);
}

static void
_e_comp_x_evas_hide_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data, *tmp;
   Eina_List *l;

   if (ec == mouse_client)
     {
        mouse_client = NULL;
        E_FREE_FUNC(mouse_in_job, ecore_job_del);
     }

   if (!_e_comp_x_client_data_get(ec)) return; // already deleted, happens with internal wins
   _e_comp_x_client_hide(ec);

   EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
     evas_object_hide(tmp->frame);

   if (e_comp_config_get()->send_flush)
     ecore_x_e_comp_flush_send(e_client_util_win_get(ec));
   if (e_comp_config_get()->send_dump)
     ecore_x_e_comp_dump_send(e_client_util_win_get(ec));
}

static void
_e_comp_x_client_show(E_Client *ec)
{
   unsigned int visible = 1;
   Ecore_X_Window win;

   win = e_client_util_win_get(ec);
   ecore_x_window_shadow_tree_flush();
   if ((!_e_comp_x_client_data_get(ec)->need_reparent) && (!ec->override))
     ecore_x_window_show(win);
   if (ec->unredirected_single || _e_comp_x_client_data_get(ec)->iconic)
     {
        e_pixmap_clear(ec->pixmap);
        ecore_x_window_show(_e_comp_x_client_window_get(ec));
        _e_comp_x_client_data_get(ec)->iconic = 0;
     }
   if (!ec->override)
     e_hints_window_visible_set(ec);

   ecore_x_window_prop_card32_set(win, E_ATOM_MAPPED, &visible, 1);
   ecore_x_window_prop_card32_set(win, E_ATOM_MANAGED, &visible, 1);
}

static void
_e_comp_x_evas_show_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data, *tmp;
   Eina_List *l;

   if (!_e_comp_x_client_data_get(ec)) return;
   _e_comp_x_client_show(ec);

   if (_e_comp_x_client_data_get(ec)->frame_update)
     {
        int ll, r, t, b;

        e_comp_object_frame_geometry_get(obj, &ll, &r, &t, &b);
        _e_comp_x_client_frame_update(ec, ll, r, t, b);
     }

   EINA_LIST_FOREACH(ec->e.state.video_child, l, tmp)
     {
        evas_object_show(tmp->frame);
        ecore_x_window_show(e_client_util_pwin_get(tmp));
     }
}

static void
_e_comp_x_evas_stack_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
   if (evas_object_data_get(obj, "client_restack"))
     _e_comp_x_client_stack(data);
}

static void
_e_comp_x_evas_unfullscreen_zoom_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   if ((screen_size.width != -1) && (screen_size.height != -1))
     {
        ecore_x_randr_screen_primary_output_size_set(e_comp->root,
                                                     screen_size_index);
        screen_size.width = -1;
        screen_size.height = -1;
     }
}

static void
_e_comp_x_evas_fullscreen_zoom_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data;
   Ecore_X_Randr_Screen_Size_MM *sizes;
   int num_sizes, i, best_size_index = 0;

   ecore_x_randr_screen_primary_output_current_size_get(e_comp->root,
                                                        &screen_size.width,
                                                        &screen_size.height,
                                                        NULL, NULL, NULL);
   sizes = ecore_x_randr_screen_primary_output_sizes_get(e_comp->root,
                                                         &num_sizes);
   if (sizes)
     {
        Ecore_X_Randr_Screen_Size best_size = { -1, -1 };
        int best_dist = INT_MAX, dist;

        for (i = 0; i < num_sizes; i++)
          {
             if ((sizes[i].width > ec->w) && (sizes[i].height > ec->h))
               {
                  dist = (sizes[i].width * sizes[i].height) - (ec->w * ec->h);
                  if (dist < best_dist)
                    {
                       best_size.width = sizes[i].width;
                       best_size.height = sizes[i].height;
                       best_dist = dist;
                       best_size_index = i;
                    }
               }
          }
        if (((best_size.width != -1) && (best_size.height != -1)) &&
            ((best_size.width != screen_size.width) ||
             (best_size.height != screen_size.height)))
          {
             if (ecore_x_randr_screen_primary_output_size_set(e_comp->root,
                                                              best_size_index))
               screen_size_index = best_size_index;
             evas_object_geometry_set(ec->frame, 0, 0, best_size.width, best_size.height);
          }
        else
          {
             screen_size.width = -1;
             screen_size.height = -1;
             evas_object_geometry_set(ec->frame, 0, 0, ec->zone->w, ec->zone->h);
          }
        free(sizes);
     }
   else
     {
        evas_object_geometry_set(ec->frame, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h);
     }
}

static Eina_Bool
_e_comp_x_destroy(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Destroy *ev)
{
   E_Client *ec;

   //INF("X DESTROY: %u", ev->win);
   e_comp_ignore_win_del(E_PIXMAP_TYPE_X, ev->win);
   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec)
     {
        if (!e_comp_x->retry_clients) return ECORE_CALLBACK_RENEW;
        e_comp_x->retry_clients = eina_list_remove(e_comp_x->retry_clients, (uintptr_t*)(unsigned long)ev->win);
        if (!e_comp_x->retry_clients)
          E_FREE_FUNC(e_comp_x->retry_timer, ecore_timer_del);
        return ECORE_CALLBACK_PASS_ON;
     }
   if (_e_comp_x_client_data_get(ec))
     {
        if (_e_comp_x_client_data_get(ec)->reparented)
          e_client_comp_hidden_set(ec, 1);
        evas_object_pass_events_set(ec->frame, 1);
        evas_object_hide(ec->frame);
        _e_comp_x_client_data_get(ec)->deleted = 1;
        DELD(ec, 2);
        e_object_del(E_OBJECT(ec));
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_resize_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Resize_Request *ev)
{
   E_Client *ec;
   int w, h;

   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec)
     {
        if (!e_comp_find_by_window(ev->win)) ecore_x_window_resize(ev->win, ev->w, ev->h);
        return ECORE_CALLBACK_PASS_ON;
     }
   w = ev->w, h = ev->h;
   if (ec->zone && (e_config->geometry_auto_resize_limit == 1))
     {
        int zx, zy, zw, zh;

        e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
        if (w > zw)
          w = zw;

        if (h > zh)
          h = zh;
     }
   if ((w != ec->w) || (h != ec->h))
     {
        evas_object_resize(ec->frame, w, h);
     }
   return ECORE_CALLBACK_RENEW;
}

static void
_e_comp_x_evas_mirror_hidden(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data;

   if (!_e_comp_x_client_data_get(ec)) return;
   if ((!ec->iconic) || (!_e_comp_x_client_data_get(ec)->iconic)) return;
   _e_comp_x_client_hide(ec);
}

static void
_e_comp_x_evas_mirror_visible(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec = data;

   if (!_e_comp_x_client_data_get(ec)) return;
   if ((!ec->iconic) || _e_comp_x_client_data_get(ec)->iconic) return;
   _e_comp_x_client_show(ec);
}

static void
_e_comp_x_client_evas_init(E_Client *ec)
{
   if (_e_comp_x_client_data_get(ec)->evas_init) return;
   _e_comp_x_client_data_get(ec)->evas_init = 1;
   evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_RESTACK, _e_comp_x_evas_stack_cb, ec);
   evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_SHOW, _e_comp_x_evas_show_cb, ec);
   evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_HIDE, _e_comp_x_evas_hide_cb, ec);
   if (!ec->override)
     {
        evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_MOVE, _e_comp_x_evas_move_cb, ec);
        evas_object_smart_callback_add(ec->frame, "client_resize", _e_comp_x_evas_resize_cb, ec);
     }
   evas_object_smart_callback_add(ec->frame, "frame_recalc_done", _e_comp_x_evas_frame_recalc_cb, ec);
   evas_object_smart_callback_add(ec->frame, "shade_done", _e_comp_x_evas_shade_cb, ec);
   evas_object_smart_callback_add(ec->frame, "comp_hidden", _e_comp_x_evas_comp_hidden_cb, ec);
   evas_object_smart_callback_add(ec->frame, "delete_request", _e_comp_x_evas_delete_request_cb, ec);
   evas_object_smart_callback_add(ec->frame, "kill_request", _e_comp_x_evas_kill_cb, ec);
   evas_object_smart_callback_add(ec->frame, "ping", _e_comp_x_evas_ping_cb, ec);
   evas_object_smart_callback_add(ec->frame, "color_set", _e_comp_x_evas_color_set_cb, ec);
   evas_object_smart_callback_add(ec->frame, "fullscreen_zoom", _e_comp_x_evas_fullscreen_zoom_cb, ec);
   evas_object_smart_callback_add(ec->frame, "unfullscreen_zoom", _e_comp_x_evas_unfullscreen_zoom_cb, ec);
   evas_object_smart_callback_add(ec->frame, "visibility_force", _e_comp_x_evas_mirror_visible, ec);
   evas_object_smart_callback_add(ec->frame, "visibility_normal", _e_comp_x_evas_mirror_hidden, ec);
   /* force apply this since we haven't set up our smart cb previously */
   _e_comp_x_evas_comp_hidden_cb(ec, NULL, NULL);
}

static Eina_Bool
_e_comp_x_object_add(void *d EINA_UNUSED, int t EINA_UNUSED, E_Event_Comp_Object *ev)
{
   E_Client *ec;

   ec = e_comp_object_client_get(ev->comp_object);
   if ((!ec) || e_object_is_del(E_OBJECT(ec)) || ec->re_manage) return ECORE_CALLBACK_RENEW;
   E_COMP_X_PIXMAP_CHECK ECORE_CALLBACK_RENEW;
   _e_comp_x_client_evas_init(ec);
   _e_comp_x_client_stack(ec);
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_show_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Show_Request *ev)
{
   E_Client *ec;

   //INF("X SHOW REQ: %u", ev->win);
   ec = _e_comp_x_client_find_by_window(ev->win);
   if (e_comp_ignore_win_find(ev->win) ||
     (ec && (ec->ignored || ec->override)) ||
     (!e_comp_find_by_window(ev->parent)) ||
     (ev->parent != e_comp->root))
     {
        if ((!ec) && (!eina_hash_find(dead_wins, &ev->parent)))
          {
             ecore_x_window_show(ev->win);
             return ECORE_CALLBACK_RENEW;
          }
     }
   if (!ec)
     ec = _e_comp_x_client_new(ev->win, 0);
   if (!ec)
     {
        ecore_x_window_show(ev->win);
        return ECORE_CALLBACK_RENEW;
     }
   if ((e_comp->comp_type != E_PIXMAP_TYPE_X) && ec->ignored)
     {
        ec->visible = 1;
        if (ec->comp_data->need_reparent)
          _e_comp_x_hook_client_pre_frame_assign(NULL, ec);
        else
          ecore_x_window_show(ev->win);
        return ECORE_CALLBACK_RENEW;
     }

   if ((!_e_comp_x_client_data_get(ec)->reparented) && (!e_client_util_ignored_get(ec)))
     {
        if (!ec->override)
          _e_comp_x_client_data_get(ec)->need_reparent = 1;
        ec->visible = 1;
        EC_CHANGED(ec);
        return ECORE_CALLBACK_RENEW;
     }
   if (ec->iconic)
     {
        if (!ec->lock_client_iconify)
          e_client_uniconify(ec);
     }
   else
     {
        /* FIXME: make client "urgent" for a bit - it wants attention */
        /*	e_client_show(ec); */
        if (!ec->lock_client_stacking)
          evas_object_raise(ec->frame);
     }
   return ECORE_CALLBACK_RENEW;
}

static void
_e_comp_x_show_helper(E_Client *ec)
{
   if ((!ec->override) && (!ec->re_manage) && (!_e_comp_x_client_data_get(ec)->first_map) &&
       (!_e_comp_x_client_data_get(ec)->reparented) && (!_e_comp_x_client_data_get(ec)->need_reparent))
     {
        /* this is most likely an internal window */
        _e_comp_x_client_data_get(ec)->need_reparent = 1;
        ec->visible = 1;
        if (ec->internal_elm_win)
          ec->take_focus = 1;
        EC_CHANGED(ec);
     }
   else if (ec->override)
     {
        if (e_comp->comp_type == E_PIXMAP_TYPE_WL)
          {
             ec->visible = 1;
             return;
          }
        ec->redirected = !ec->input_only;
        ec->changes.visible = ec->visible = 1;
        EC_CHANGED(ec);
        if (!_e_comp_x_client_data_get(ec)->first_map)
          _e_comp_x_client_evas_init(ec);
     }
   if (!ec->input_only)
     _e_comp_x_client_damage_add(ec);
   if (!_e_comp_x_client_data_get(ec)->need_reparent)
     {
        e_pixmap_usable_set(ec->pixmap, 1);
        if (ec->hidden || ec->iconic)
          {
             evas_object_hide(ec->frame);
             e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
          }
        else if (ec->override || (ec->icccm.state == ECORE_X_WINDOW_STATE_HINT_NORMAL))
          evas_object_show(ec->frame);
        _e_comp_x_client_data_get(ec)->first_map = 1;
        if (ec->internal_elm_win)
          {
             _e_comp_x_post_client_idler_add(ec);
             ec->post_move = 1;
             ec->post_resize = 1;
             e_comp_x->restack = 1;
          }
     }
}

static Eina_Bool
_e_comp_x_show_retry(void *data EINA_UNUSED)
{
   uintptr_t *win;

   EINA_LIST_FREE(e_comp_x->retry_clients, win)
     {
        E_Client *ec;

        ec = _e_comp_x_client_new((Ecore_X_Window)(uintptr_t)win, 0);
        if (ec) _e_comp_x_show_helper(ec);
     }

   e_comp_x->retry_timer = NULL;
   return EINA_FALSE;
}

static Eina_Bool
_e_comp_x_show(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Show *ev)
{
   E_Client *ec;

   //INF("X SHOW: %u", ev->win);
   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec)
     {
        E_Comp *c;

        if (e_comp_ignore_win_find(ev->win)) return ECORE_CALLBACK_RENEW;
        c = e_comp_find_by_window(ev->event_win);
        if (!c) return ECORE_CALLBACK_RENEW;
        if (ev->event_win != e_comp->root) return ECORE_CALLBACK_RENEW;
        if ((c->win == ev->win) || (c->ee_win == ev->win) ||
            (c->root == ev->win) || (c->cm_selection == ev->win)) return ECORE_CALLBACK_RENEW;
        /* some window which we haven't made a client for yet but need to */
        ec = _e_comp_x_client_new(ev->win, 0);
        if (!ec)
          {
             if (c->x_comp_data->retry_timer)
               ecore_timer_loop_reset(c->x_comp_data->retry_timer);
             else
               c->x_comp_data->retry_timer = ecore_timer_loop_add(0.02, _e_comp_x_show_retry, c);
             c->x_comp_data->retry_clients = eina_list_append(c->x_comp_data->retry_clients, (uintptr_t*)(unsigned long)ev->win);
             return ECORE_CALLBACK_RENEW;
          }
     }
   else if (e_object_is_del(E_OBJECT(ec)) || ec->already_unparented)
     return ECORE_CALLBACK_RENEW;
   _e_comp_x_show_helper(ec);
   if (ec->internal || (!ec->override))
     _e_comp_x_client_stack(ec);
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_hide(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Hide *ev)
{
   E_Client *ec;
   Eina_Bool hid = EINA_FALSE;

   //INF("X HIDE: %u", ev->win);
   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec)
     {
        if (!e_comp_x->retry_clients) return ECORE_CALLBACK_RENEW;
        e_comp_x->retry_clients = eina_list_remove(e_comp_x->retry_clients, (uintptr_t*)(unsigned long)ev->win);
        if (!e_comp_x->retry_clients)
          E_FREE_FUNC(e_comp_x->retry_timer, ecore_timer_del);
        return ECORE_CALLBACK_PASS_ON;
     }
   if ((!ec->visible) || (ec->hidden && ec->unredirected_single))
     {
        //INF("IGNORED");
        return ECORE_CALLBACK_PASS_ON;
     }

   if (ev->win != ev->event_win)
     {
        if ((!ec->override) && (!ev->send_event)) return ECORE_CALLBACK_PASS_ON;
     }
   if (ec->ignore_first_unmap > 0)
     {
        ec->ignore_first_unmap--;
        return ECORE_CALLBACK_PASS_ON;
     }
   /* Don't delete hidden or iconified windows */
   if (ec->iconic)
     {
        /* Only hide the border if it is visible */
        hid = EINA_TRUE;
        evas_object_hide(ec->frame);
     }
   else
     {
        hid = EINA_TRUE;
        evas_object_hide(ec->frame);
        if (ec->internal)
          e_hints_window_hidden_set(ec);
        else
          {
             if (ec->exe_inst && ec->exe_inst->exe)
               ec->exe_inst->phony = 0;
             DELD(ec, 3);
             e_object_del(E_OBJECT(ec));
          }
     }
   if (hid)
     _e_comp_x_focus_check();
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_reparent(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Reparent *ev)
{
   E_Client *ec;

   ec = _e_comp_x_client_find_by_window(ev->win);
   if ((!ec) || (ev->win == e_client_util_pwin_get(ec))) return ECORE_CALLBACK_PASS_ON;
   DBG("== repar [%u] to [%u]", ev->win, ev->parent);
   /* FIXME: this is almost definitely wrong */
   if (ev->parent != e_client_util_pwin_get(ec))
     {
        e_pixmap_parent_window_set(ec->pixmap, ev->parent);
        if (!e_object_is_del(E_OBJECT(ec)))
          e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_configure(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Configure *ev)
{
   E_Client *ec;
   Eina_Bool move, resize;

   if (e_comp_find_by_window(ev->win))
     {
        // do not handle this here - use randr events
        //e_comp_canvas_resize(ev->w, ev->h);
        return ECORE_CALLBACK_RENEW;
     }
   ec = _e_comp_x_client_find_by_window(ev->win);
   if ((!ec) || (!ec->override) || (!ev->override) || e_client_is_stacking(ec)) return ECORE_CALLBACK_PASS_ON;

   //INF("configure %p: %d,%d %dx%d", ec, ev->x, ev->y, ev->w, ev->h);
   if (ev->abovewin == 0)
     {
        if (e_client_below_get(ec))
          evas_object_lower(ec->frame);
     }
   else
     {
        E_Client *ec2 = _e_comp_x_client_find_by_window(ev->abovewin);

        if (ec2)
          {
             /* client(ec) wants to be above a layer client(ec2) */
             if (e_client_is_stacking(ec2)) //is it a stacking placeholder window?
               {
                  E_Client *ec3;

                  ec3 = e_client_above_get(ec2);
                  /* stack under next client(ec3) */
                  if (ec3)
                    {
                       evas_object_layer_set(ec->frame, ec3->layer);
                       if (!e_client_is_stacking(ec3))
                         evas_object_stack_below(ec->frame, ec3->frame);
                    }
                  else //force override to obey our stacking
                    evas_object_layer_set(ec->frame, ec2->layer);
               }
             else
               {
                  evas_object_layer_set(ec->frame, ec2->layer);
                  evas_object_stack_above(ec->frame, ec2->frame);
               }
          }
        else
          evas_object_layer_set(ec->frame, E_LAYER_CLIENT_PRIO);
     }
   move = (ec->client.x != ev->x) || (ec->client.y != ev->y);
   resize = (ec->client.w != ev->w) || (ec->client.h != ev->h);
   if (!ec->internal)
     _e_comp_x_client_data_get(ec)->pw = ev->w, _e_comp_x_client_data_get(ec)->ph = ev->h;
   EINA_RECTANGLE_SET(&ec->client, ev->x, ev->y, ev->w, ev->h);
   if (move)
     evas_object_move(ec->frame, ev->x, ev->y);
   if (resize && e_pixmap_is_x(ec->pixmap))
     {
        e_pixmap_dirty(ec->pixmap);
        evas_object_resize(ec->frame, ev->w, ev->h);
     }
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_configure_request_timer(void *d)
{
   Pending_Configure *pc = d;
   eina_hash_list_remove(pending_configures, &pc->win, pc);
   free(pc);
   return EINA_FALSE;
}

static Eina_Bool
_e_comp_x_configure_request(void *data  EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Configure_Request *ev)
{
   E_Client *ec;
   Eina_Bool move = EINA_FALSE, resize = EINA_FALSE;
   int ox, oy, ow, oh;
   int x, y, w, h;

//   printf("configure request {0x%08x}  %4i,%4i %4ix%4i b=%i [%c%c%c%c]\n",
//          ev->win, ev->x, ev->y, ev->w, ev->h, ev->border,
//          ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X ? 'x' : ' ',
//          ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y ? 'y' : ' ',
//          ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W ? 'w' : ' ',
//          ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H ? 'h' : ' ');
   if (e_comp_find_by_window(ev->win)) return ECORE_CALLBACK_RENEW;
   ec = _e_comp_x_client_find_by_window(ev->win);

   /* pass through requests for windows we haven't/won't reparent yet */
   if (ec && (!_e_comp_x_client_data_get(ec)->need_reparent) && (!_e_comp_x_client_data_get(ec)->reparented))
     {
        if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X)
          _e_comp_x_client_data_get(ec)->initial_attributes.x = ev->x;
        if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y)
          _e_comp_x_client_data_get(ec)->initial_attributes.y = ev->y;
        if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W)
          ec->w = ec->client.w = _e_comp_x_client_data_get(ec)->initial_attributes.w = ev->w;
        if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H)
          ec->h = ec->client.h = _e_comp_x_client_data_get(ec)->initial_attributes.h = ev->h;
        ec->border_size = ev->border;
        ec->changes.size = 1;
        ec = NULL;
     }
   if (!ec)
     {
        if ((ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X) ||
            (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y))
          {
             Pending_Configure *pc = E_NEW(Pending_Configure, 1);
             pc->point.x = ev->x;
             pc->point.y = ev->y;
             pc->timer = ecore_timer_loop_add(5.0, _e_comp_x_configure_request_timer, pc);
             pc->win = ev->win;
             eina_hash_list_append(pending_configures, &ev->win, pc);
          }
        ecore_x_window_configure(ev->win, ev->value_mask,
                                 ev->x, ev->y, ev->w, ev->h, ev->border,
                                 ev->abovewin, ev->detail);
        return ECORE_CALLBACK_PASS_ON;
     }

   x = ox = ec->client.x;
   y = oy = ec->client.y;
   w = ow = ec->client.w;
   h = oh = ec->client.h;

   if ((ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X) ||
       (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y))
     {
        int zx, zy, zw, zh;

        e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
        if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X)
          {
             _e_comp_x_client_data_get(ec)->initial_attributes.x = ev->x;
             if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
               x = E_CLAMP(ev->x, zx, zx + zw - ec->w);
             else
               x = ev->x;
          }
        if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y)
          {
             _e_comp_x_client_data_get(ec)->initial_attributes.y = ev->y;
             if (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE)
               y = E_CLAMP(ev->y, zy, zy + zh - ec->h);
             else
               y = ev->y;
          }
     }

   if ((ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W) ||
       (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H))
     {
        if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W)
          w = ev->w, _e_comp_x_client_data_get(ec)->initial_attributes.w = ev->w;
        if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H)
          h = ev->h, _e_comp_x_client_data_get(ec)->initial_attributes.h = ev->h;
     }

   e_comp_object_frame_xy_adjust(ec->frame, x, y, &x, &y);
   e_comp_object_frame_wh_adjust(ec->frame, w, h, &w, &h);

   if ((ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X) ||
       (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y))
     move = (x != ec->x) || (y != ec->y);
   if ((ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W) ||
       (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H))
     resize = (w != ec->w) || (h != ec->h);

   if (move && (!ec->lock_client_location))
     {
        if ((ec->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE)
          {
             E_Zone *zone;

             e_comp_object_frame_xy_unadjust(ec->frame, x, y, &ec->saved.x, &ec->saved.y);

             zone = e_comp_zone_xy_get(x, y);
             if (zone && (zone->x || zone->y))
               {
                  ec->saved.x -= zone->x;
                  ec->saved.y -= zone->y;
               }
          }
        else if (!ec->maximize_override)
          {
             /* client is completely outside the screen, policy does not allow */
             if (((!E_INTERSECTS(x, y, ec->w, ec->h, 0, 0, e_comp->w - 5, e_comp->h - 5)) &&
                 (e_config->screen_limits != E_CLIENT_OFFSCREEN_LIMIT_ALLOW_FULL)) ||
                 /* client is partly outside the zone, policy does not allow */
                 (((!E_INSIDE(x, y, 0, 0, e_comp->w - 5, e_comp->h - 5)) &&
                  (!E_INSIDE(x + ec->w, y, 0, 0, e_comp->w - 5, e_comp->h - 5)) &&
                  (!E_INSIDE(x, y + ec->h, 0, 0, e_comp->w - 5, e_comp->h - 5)) &&
                  (!E_INSIDE(x + ec->w, y + ec->h, 0, 0, e_comp->w - 5, e_comp->h - 5))) &&
                  (e_config->screen_limits == E_CLIENT_OFFSCREEN_LIMIT_ALLOW_NONE))
                )
               e_comp_object_util_center(ec->frame);
             else
               {
                  evas_object_move(ec->frame, x, y);
               }
          }
     }

   if (resize && (!ec->lock_client_size) && (move || ((!ec->maximized) && (!ec->fullscreen))))
     {
        if (ec->shaded || ((ec->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE))
          e_comp_object_frame_wh_unadjust(ec->frame, w, h, &ec->saved.w, &ec->saved.h);
        else if (!ec->maximize_override)
          {
             evas_object_resize(ec->frame, w, h);
          }
     }
   if (!ec->lock_client_stacking)
     {
        if ((ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE) &&
            (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING))
          {
             E_Client *oec;

             if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE)
               {
                  oec = _e_comp_x_client_find_by_window(ev->abovewin);
                  if (oec)
                    {
                       evas_object_stack_above(ec->frame, oec->frame);
                    }
                  else
                    {
                       ecore_x_window_configure(e_client_util_pwin_get(ec),
                                                ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
                                                ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
                                                0, 0, 0, 0, 0,
                                                ev->abovewin, ECORE_X_WINDOW_STACK_ABOVE);
                    }
               }
             else if (ev->detail == ECORE_X_WINDOW_STACK_BELOW)
               {
                  oec = _e_comp_x_client_find_by_window(ev->abovewin);
                  if (oec)
                    {
                       evas_object_stack_below(ec->frame, oec->frame);
                    }
                  else
                    {
                       ecore_x_window_configure(e_client_util_pwin_get(ec),
                                                ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
                                                ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
                                                0, 0, 0, 0, 0,
                                                ev->abovewin, ECORE_X_WINDOW_STACK_BELOW);
                    }
               }
             else if (ev->detail == ECORE_X_WINDOW_STACK_TOP_IF)
               {
                  /* FIXME: do */
               }
             else if (ev->detail == ECORE_X_WINDOW_STACK_BOTTOM_IF)
               {
                  /* FIXME: do */
               }
             else if (ev->detail == ECORE_X_WINDOW_STACK_OPPOSITE)
               {
                  /* FIXME: do */
               }
          }
        else if (ev->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE)
          {
             if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE)
               {
                  evas_object_raise(ec->frame);
               }
             else if (ev->detail == ECORE_X_WINDOW_STACK_BELOW)
               {
                  evas_object_lower(ec->frame);
               }
             else if (ev->detail == ECORE_X_WINDOW_STACK_TOP_IF)
               {
                  /* FIXME: do */
               }
             else if (ev->detail == ECORE_X_WINDOW_STACK_BOTTOM_IF)
               {
                  /* FIXME: do */
               }
             else if (ev->detail == ECORE_X_WINDOW_STACK_OPPOSITE)
               {
                  /* FIXME: do */
               }
          }
     }

   /* FIXME: need to send synthetic stacking event to, as well as move/resize */
   if ((((ec->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE) && (move || resize)) ||
       ((!move) && (!resize)))
     {
        _e_comp_x_client_move_resize_send(ec);
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_stack_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Stack_Request *ev)
{
   E_Client *ec;

   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec) return ECORE_CALLBACK_RENEW;
   if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE)
     evas_object_raise(ec->frame);
   else if (ev->detail == ECORE_X_WINDOW_STACK_BELOW)
     evas_object_lower(ec->frame);
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_stack(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Stack *ev)
{
   E_Client *ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec) return ECORE_CALLBACK_PASS_ON;
   if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE) evas_object_raise(ec->frame);
   else evas_object_lower(ec->frame);
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_property(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Property *ev)
{
   E_Client *ec;

   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec) return ECORE_CALLBACK_RENEW;

   if (ev->atom == ECORE_X_ATOM_WM_NAME)
     {
        if ((!ec->netwm.name) &&
            (!ec->netwm.fetch.name))
          {
             ec->icccm.fetch.title = 1;
             EC_CHANGED(ec);
          }
     }
   else if (ev->atom == ECORE_X_ATOM_NET_WM_NAME)
     {
        ec->netwm.fetch.name = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_WM_CLASS)
     {
        ec->icccm.fetch.name_class = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_WM_ICON_NAME)
     {
        if ((!ec->netwm.icon_name) &&
            (!ec->netwm.fetch.icon_name))
          {
             ec->icccm.fetch.icon_name = 1;
             EC_CHANGED(ec);
          }
     }
   else if (ev->atom == ECORE_X_ATOM_NET_WM_ICON_NAME)
     {
        ec->netwm.fetch.icon_name = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_WM_CLIENT_MACHINE)
     {
        ec->icccm.fetch.machine = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_WM_PROTOCOLS)
     {
        ec->icccm.fetch.protocol = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_WM_HINTS)
     {
        ec->icccm.fetch.hints = 1;
        EC_CHANGED(ec);
        if (ec->icccm.state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
          ec->ignored = 0;
     }
   else if (ev->atom == ECORE_X_ATOM_WM_NORMAL_HINTS)
     {
        if (_e_comp_x_client_data_get(ec)->internal_props_set)
          _e_comp_x_client_data_get(ec)->internal_props_set--;
        else
          {
             ec->icccm.fetch.size_pos_hints = 1;
             EC_CHANGED(ec);
          }
     }
   else if (ev->atom == ECORE_X_ATOM_MOTIF_WM_HINTS)
     {
        /*
           if ((ec->netwm.type == E_WINDOW_TYPE_UNKNOWN) &&
            (!ec->netwm.fetch.type))
           {
         */
        ec->mwm.fetch.hints = 1;
        EC_CHANGED(ec);
        /*
           }
         */
     }
   else if (ev->atom == ECORE_X_ATOM_WM_TRANSIENT_FOR)
     {
        ec->icccm.fetch.transient_for = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_WM_CLIENT_LEADER)
     {
        ec->icccm.fetch.client_leader = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_WM_WINDOW_ROLE)
     {
        ec->icccm.fetch.window_role = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_NET_WM_ICON)
     {
        ec->netwm.fetch.icon = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ATM__QTOPIA_SOFT_MENU)
     {
        ec->qtopia.fetch.soft_menu = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ATM__QTOPIA_SOFT_MENUS)
     {
        ec->qtopia.fetch.soft_menus = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE)
     {
        ec->vkbd.fetch.state = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD)
     {
        ec->vkbd.fetch.vkbd = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_ILLUME_CONFORMANT)
     {
        _e_comp_x_client_data_get(ec)->illume.conformant.fetch.conformant = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE)
     {
        _e_comp_x_client_data_get(ec)->illume.quickpanel.fetch.state = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL)
     {
        _e_comp_x_client_data_get(ec)->illume.quickpanel.fetch.quickpanel = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR)
     {
        _e_comp_x_client_data_get(ec)->illume.quickpanel.fetch.priority.major = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR)
     {
        _e_comp_x_client_data_get(ec)->illume.quickpanel.fetch.priority.minor = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE)
     {
        _e_comp_x_client_data_get(ec)->illume.quickpanel.fetch.zone = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED)
     {
        _e_comp_x_client_data_get(ec)->illume.drag.fetch.locked = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_ILLUME_DRAG)
     {
        _e_comp_x_client_data_get(ec)->illume.drag.fetch.drag = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE)
     {
        _e_comp_x_client_data_get(ec)->illume.win_state.fetch.state = 1;
        EC_CHANGED(ec);
     }
   /*
      else if (ev->atom == ECORE_X_ATOM_NET_WM_USER_TIME)
      {
        ec->netwm.fetch.user_time = 1;
        EC_CHANGED(ec);
      }
      else if (ev->atom == ECORE_X_ATOM_NET_WM_STRUT)
      {
        ec->netwm.fetch.strut = 1;
        EC_CHANGED(ec);
      }
      else if (ev->atom == ECORE_X_ATOM_NET_WM_STRUT_PARTIAL)
      {
        ec->netwm.fetch.strut = 1;
        EC_CHANGED(ec);
      }
    */
   else if (ev->atom == ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER)
     {
        //printf("ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER\n");
     }
   else if (ev->atom == ECORE_X_ATOM_E_VIDEO_POSITION)
     {
        ec->e.fetch.video_position = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_VIDEO_PARENT)
     {
        ec->e.fetch.video_parent = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_NET_WM_STATE)
     {
        ec->netwm.fetch.state = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY)
     {
        if (ec->netwm.opacity_changed)
          ec->netwm.opacity_changed = 0;
        else
          {
             ec->netwm.fetch.opacity = 1;
             EC_CHANGED(ec);
          }
     }
   else if (ev->atom == ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED)
     {
        ec->e.fetch.profile = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ECORE_X_ATOM_E_WINDOW_PROFILE_AVAILABLE_LIST)
     {
        ec->e.fetch.profile = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ATM_GTK_FRAME_EXTENTS)
     {
        _e_comp_x_client_data_get(ec)->fetch_gtk_frame_extents = 1;
        EC_CHANGED(ec);
     }
   else if (ev->atom == ATM_STEAM_GAME)
     {
        e_hints_window_steam_game_get(ec);
        ec->changes.icon = 1;
        EC_CHANGED(ec);
     }

   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_message(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Client_Message *ev)
{
   E_Client *ec;

   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec)
     {
        char *name;

        if (!eina_log_domain_level_check(e_log_dom, EINA_LOG_LEVEL_DBG)) return ECORE_CALLBACK_RENEW;
        name = ecore_x_atom_name_get(ev->message_type);
        DBG("missed client message '%s' for %u", name, ev->win);
        free(name);
        return ECORE_CALLBACK_RENEW;
     }
   if (ev->message_type == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY)
     {
        ec->netwm.fetch.opacity = 1;
        EC_CHANGED(ec);
     }
   else if (ev->message_type == ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE)
     {
        if (ec->e.state.profile.use)
          {
             char *p = ecore_x_atom_name_get(ev->data.l[1]);
             if (e_client_desk_window_profile_available_check(ec, p))
               {
                  if (e_util_strcmp(p, ec->desk->window_profile))
                    {
                       E_Desk *old_desk = ec->desk;
                       E_Desk *desk = e_comp_desk_window_profile_get(p);
                       Eina_Bool was_focused = e_client_stack_focused_get(ec);

                       if ((desk) && (desk != old_desk))
                         {
                            e_client_desk_set(ec, desk);
                            if (was_focused)
                              e_desk_last_focused_focus(old_desk);
                         }
                    }
               }
             free(p);
          }
     }
   else if (ev->message_type == ECORE_X_ATOM_NET_ACTIVE_WINDOW)
     {
#if 0 /* notes */
        if (e->data.l[0] == 0 /* 0 == old, 1 == client, 2 == pager */)
          {
          }
        timestamp = e->data.l[1];
        requestor_id e->data.l[2];
#endif
        switch (e_config->window_activehint_policy)
          {
           case 0: break;

           case 1:
             e_client_urgent_set(ec, 1);
             break;

           default:
             if (e_client_action_get() || e_comp->nocomp)
               {
                  /* be helpful and ignore activates during window actions, but still set urgent */
                  e_client_urgent_set(ec, 1);
                  break;
               }
             if ((!starting) && (!ec->focused))
               {
                  if ((e_config->window_activehint_policy == E_ACTIVEHINT_POLICY_ACTIVATE_EXCLUDE) &&
                      (!ec->desk->visible))
                    e_client_urgent_set(ec, 1);
                  else
                    {
                       /* some apps, eg. libreoffice, create "modal" windows which
                        * do not have the netwm modal state set. instead, attempting to
                        * focus the parent window results in the app immediately trying to
                        * activate the "modal" window, triggering an infinite loop.
                        *
                        * by treating this "modal" window as a genuine modal window,
                        * we (eventually) can ignore this type of bad behavior and
                        * give the application/user the expected behavior
                        */
                       if (ec->parent && (!ec->parent->modal) && (e_client_focused_get() == ec->parent) &&
                           (ev->time - focus_time < PARENT_ACTIVATE_TIME))
                         {
                            E_Comp_X_Client_Data *cd;

                            cd = _e_comp_x_client_data_get(ec);
                            if (cd)
                              {
                                 cd->parent_activate_count++;
                                 if (cd->parent_activate_count >= PARENT_ACTIVATE_LIMIT)
                                   _e_comp_x_client_modal_setup(ec);
                              }
                         }
                       e_client_activate(ec, EINA_TRUE);
                    }
               }
             else
               evas_object_raise(ec->frame);
          }
     }
   else if (ev->message_type == ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE_DONE)
     {
        if ((ec->e.state.profile.use) &&
            (ec->e.state.profile.wait_for_done))
          {
             char *p = ecore_x_atom_name_get(ev->data.l[1]);
             if (!e_util_strcmp(ec->e.state.profile.wait, p))
               {
                  E_Desk *old_desk = ec->desk;
                  E_Desk *desk = ec->e.state.profile.wait_desk;
                  Eina_Bool was_focused = e_client_stack_focused_get(ec);

                  eina_stringshare_replace(&ec->e.state.profile.wait, NULL);
                  ec->e.state.profile.wait_for_done = 0;
                  if ((desk) && (desk != old_desk))
                    {
                       eina_stringshare_replace(&ec->e.state.profile.name,
                                                desk->window_profile);
                       e_client_desk_set(ec, desk);
                       if (was_focused)
                         e_desk_last_focused_focus(old_desk);
                    }
                  e_client_desk_window_profile_wait_desk_set(ec, NULL);
               }
             free(p);
          }
     }
   else if (ev->message_type == ATM_NETWM_SHOW_WINDOW_MENU)
     {
       /*
         message_type = _NET_WM_SHOW_WINDOW_MENU
         window = window for which the menu should be shown
         format = 32
         data.l[0] = xinput2_device_id
         data.l[1] = root_x
         data.l[2] = root_y
         other data.l[] elements = 0
        */

        int x, y;

        x = ev->data.l[1];
        y = ev->data.l[2];
        e_int_client_menu_show(ec,
          e_comp_canvas_x_root_adjust(x),
          e_comp_canvas_y_root_adjust(y),
          0, 0);
     }
   else if (ev->message_type == ATM_NETWM_PERFORM_BUTTON_ACTION)
     {
        char emission[128];
       /*
         message_type = _NET_WM_PERFORM_BUTTON_ACTION
         window = window for which the action should be performed
         format = 32
         data.l[0] = xinput2_device_id
         data.l[1] = root_x
         data.l[2] = root_y
         data.l[3] = button
         data.l[4] = timestamp
        */
        if (e_dnd_active() || ec->iconic) return ECORE_CALLBACK_RENEW;
        switch (ev->data.l[3])
          {
           case 1:
           case 2:
           case 3:
             snprintf(emission, sizeof(emission), "mouse,down,%d", (int)ev->data.l[3]);
             e_bindings_signal_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(ec), emission, "e.event.titlebar");
             break;
           case 4:
             e_bindings_signal_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(ec), "mouse,wheel,?,-1", "e.event.titlebar");
             break;
           case 5:
             e_bindings_signal_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(ec), "mouse,wheel,?,1", "e.event.titlebar");
             break;
          }
     }
#ifdef HAVE_WAYLAND
   else if (ev->message_type == WL_SURFACE_ID)
     {
        void *res;
        E_Client *wc = NULL;

        if (e_comp->comp_type != E_PIXMAP_TYPE_WL) return ECORE_CALLBACK_RENEW;
        res = wl_client_get_object(e_comp_wl->xwl_client, ev->data.l[0]);
        if (res)
          wc = wl_resource_get_user_data(res);
        if (wc)
          {
             if (wc->internal)
               {
                  e_object_del(E_OBJECT(wc));
                  e_object_del(E_OBJECT(ec));
                  /* this is an xwayland bug. somehow the wrong surface is being passed
                   * and it's an internal surface--internal surfaces are NEVER
                   * xwayland clients.
                   *
                   * ever.
                   */
                  return ECORE_CALLBACK_RENEW;
               }
             e_comp_x_xwayland_client_setup(ec, wc);
          }
        else
          {
             ec->comp_data->surface_id = ev->data.l[0];
             e_comp_wl_xwayland_client_queue(ec);
          }
     }
#endif
   else
     {
        char *name;

        if (!eina_log_domain_level_check(e_log_dom, EINA_LOG_LEVEL_DBG)) return ECORE_CALLBACK_RENEW;
        name = ecore_x_atom_name_get(ev->message_type);
        DBG("missed client message '%s' for %u", name, ev->win);
        free(name);
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_state_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_State_Request *ev)
{
   int i;
   E_Client *ec;
   int max;

   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec) return ECORE_CALLBACK_RENEW;

   max = (1 << ev->state[0]) | (1 << ev->state[1]);
   if ((max & (1 << ECORE_X_WINDOW_STATE_MAXIMIZED_VERT)) &&
       (max & (1 << ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ)))
     e_hints_window_state_update(ec, INT_MAX, ev->action);
   else
     {
        for (i = 0; i < 2; i++)
          e_hints_window_state_update(ec, ev->state[i], ev->action);
     }

   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_mapping_change(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Mapping_Change *ev EINA_UNUSED)
{
   const Eina_List *l;
   E_Client *ec;

   if (_e_comp_x_mapping_change_disabled) return ECORE_CALLBACK_RENEW;
   e_comp_canvas_keys_ungrab();
   EINA_LIST_FOREACH(e_comp->clients, l, ec)
     {
        if (e_pixmap_type_get(ec->pixmap) != E_PIXMAP_TYPE_X) continue;
        if ((!_e_comp_x_client_data_get(ec)->first_map) || (!_e_comp_x_client_data_get(ec)->reparented)) continue;
        if (ec->focused)
          {
             _e_comp_x_focus_setup(ec);
             _e_comp_x_focus_setdown(ec);
          }
        else
          {
             _e_comp_x_focus_setdown(ec);
             _e_comp_x_focus_setup(ec);
             e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
             e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
          }
     }
   e_comp_canvas_keys_grab();
   return ECORE_CALLBACK_PASS_ON;
}

static void
_e_comp_x_mouse_in_job(void *d EINA_UNUSED)
{
   if (mouse_client)
     e_client_mouse_in(mouse_client, e_comp_canvas_x_root_adjust(mouse_in_coords.x), e_comp_canvas_y_root_adjust(mouse_in_coords.y));
   mouse_in_job = NULL;
}

static Eina_Bool
_e_comp_x_mouse_in_fix_check_timer_cb(void *data EINA_UNUSED)
{
   E_Client *ec = NULL, *cec;
   int x, y;

   mouse_in_fix_check_timer = NULL;
   if (e_grabinput_key_win_get() || e_grabinput_mouse_win_get())
     return EINA_FALSE;
   ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
   E_CLIENT_REVERSE_FOREACH(cec)
     {
        /* If a border was specified which should be excluded from the list
         * (because it will be closed shortly for example), skip */
        if ((!e_client_util_desk_visible(cec, e_desk_current_get(e_zone_current_get())))) continue;
        if (!evas_object_visible_get(cec->frame)) continue;
        if (!E_INSIDE(x, y, cec->x, cec->y, cec->w, cec->h))
          continue;
        /* If the layer is higher, the position of the window is higher
         * (always on top vs always below) */
        if (!ec || (cec->layer > ec->layer))
          ec = cec;
     }
   if (ec)
     {
        mouse_client = ec;
        if (mouse_in_job) ecore_job_del(mouse_in_job);
        mouse_in_job = ecore_job_add(_e_comp_x_mouse_in_job, NULL);
     }
   return EINA_FALSE;
}

static Eina_Bool
_e_comp_x_mouse_in(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Mouse_In *ev)
{
   E_Client *ec;

   if (e_comp->comp_type != E_PIXMAP_TYPE_X) return ECORE_CALLBACK_RENEW;
   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec) goto done;
   if (ev->mode == ECORE_X_EVENT_MODE_NORMAL)
     {
        if (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
          {
             if (ev->win != e_client_util_pwin_get(ec)) goto done;
             if (ev->event_win != e_client_util_win_get(ec)) goto done;
          }
        if (ev->detail == ECORE_X_EVENT_DETAIL_VIRTUAL)
          {
             if (ev->win != e_client_util_win_get(ec)) goto done;
             if (ev->event_win != e_client_util_pwin_get(ec)) goto done;
          }
        if (!evas_object_visible_get(ec->frame)) goto done;
     }
   if (_e_comp_x_client_data_get(ec)->deleted) goto done;
   mouse_client = ec;
   if (mouse_in_job) ecore_job_del(mouse_in_job);
   mouse_in_job = ecore_job_add(_e_comp_x_mouse_in_job, NULL);
   mouse_in_coords.x = ev->root.x;
   mouse_in_coords.y = ev->root.y;
done:
   E_FREE_FUNC(mouse_in_fix_check_timer, ecore_timer_del);
   if ((!e_grabinput_mouse_win_get()) && (!e_grabinput_key_win_get()))
     mouse_in_fix_check_timer =
       ecore_timer_add(0.1, _e_comp_x_mouse_in_fix_check_timer_cb, NULL);
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_mouse_out(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Mouse_In *ev)
{
   E_Client *ec;

   if (e_comp->comp_type != E_PIXMAP_TYPE_X) return ECORE_CALLBACK_RENEW;
   if ((ev->mode == ECORE_X_EVENT_MODE_UNGRAB) &&
       (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR))
     return ECORE_CALLBACK_PASS_ON;
   if (ev->mode == ECORE_X_EVENT_MODE_GRAB)
     return ECORE_CALLBACK_PASS_ON;
   if ((ev->mode == ECORE_X_EVENT_MODE_NORMAL) &&
       (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR))
     return ECORE_CALLBACK_PASS_ON;
   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec) return ECORE_CALLBACK_RENEW;
   if (_e_comp_x_client_data_get(ec)->deleted) return ECORE_CALLBACK_RENEW;
   if (mouse_client == ec)
     {
        mouse_client = NULL;
        E_FREE_FUNC(mouse_in_job, ecore_job_del);
     }
   if (ec->mouse.in)
     e_client_mouse_out(ec, e_comp_canvas_x_root_adjust(ev->root.x), e_comp_canvas_y_root_adjust(ev->root.y));
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_mouse_wheel(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Wheel *ev)
{
   E_Client *ec;
   E_Binding_Event_Wheel ev2;

   if (e_comp->comp_type != E_PIXMAP_TYPE_X) return ECORE_CALLBACK_RENEW;
   //if (action_input_win)
     //ec = action_border;
   //else
     {
        ec = _e_comp_x_client_find_by_window(ev->window);
        if ((!ec) && (ev->window != ev->event_window))
          ec = _e_comp_x_client_find_by_window(ev->event_window);
        if (!ec) return ECORE_CALLBACK_RENEW;
     }
   if (_e_comp_x_client_data_get(ec)->deleted) return ECORE_CALLBACK_RENEW;
   e_bindings_ecore_event_mouse_wheel_convert(ev, &ev2);
   e_client_mouse_wheel(ec, (Evas_Point*)&ev->root, &ev2);
   return ECORE_CALLBACK_RENEW;
}


static Eina_Bool
_e_comp_x_mouse_up(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev)
{
   E_Client *ec;
   E_Binding_Event_Mouse_Button ev2;

   if (e_comp->comp_type != E_PIXMAP_TYPE_X) return ECORE_CALLBACK_RENEW;
   //if (action_input_win)
     //ec = action_border;
   //else
     {
        ec = _e_comp_x_client_find_by_window(ev->window);
        if ((!ec) && (ev->window != ev->event_window))
          ec = _e_comp_x_client_find_by_window(ev->event_window);
        if (!ec)
          {
             if (e_client_comp_grabbed_get())
               ec = e_client_action_get();
             if (!ec) return ECORE_CALLBACK_RENEW;
          }
        if ((!ec) || e_client_util_ignored_get(ec)) return ECORE_CALLBACK_RENEW;
     }
   if (_e_comp_x_client_data_get(ec)->deleted) return ECORE_CALLBACK_RENEW;
   e_bindings_ecore_event_mouse_button_convert(ev, &ev2);
   e_client_mouse_up(ec, ev->buttons, (Evas_Point*)&ev->root, &ev2);
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_mouse_down(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev)
{
   E_Client *ec;
   E_Binding_Event_Mouse_Button ev2;

   if (e_comp->comp_type != E_PIXMAP_TYPE_X) return ECORE_CALLBACK_RENEW;
   if (e_client_action_get()) return ECORE_CALLBACK_RENEW; //block extra mouse buttons during action
   //if (action_input_win)
     //ec = action_border;
   //else
     {
        ec = _e_comp_x_client_find_by_window(ev->window);
        if ((!ec) && (ev->window != ev->event_window))
          ec = _e_comp_x_client_find_by_window(ev->event_window);
        if ((!ec) || e_client_util_ignored_get(ec)) return ECORE_CALLBACK_RENEW;
     }
   if (_e_comp_x_client_data_get(ec)->deleted) return ECORE_CALLBACK_RENEW;
   e_bindings_ecore_event_mouse_button_convert(ev, &ev2);
   e_client_mouse_down(ec, ev->buttons, (Evas_Point*)&ev->root, &ev2);
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_mouse_move(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev)
{
   E_Client *ec;

   if (e_comp->comp_type != E_PIXMAP_TYPE_X) return ECORE_CALLBACK_RENEW;
   ec = e_client_action_get();
   if (!ec)
     {
        ec = _e_comp_x_client_find_by_window(ev->window);
        if ((!ec) && (ev->window != ev->event_window))
          ec = _e_comp_x_client_find_by_window(ev->event_window);
        if ((!ec) || e_client_util_ignored_get(ec)) return ECORE_CALLBACK_RENEW;
        if ((!ec->mouse.in) && evas_object_visible_get(ec->frame) && (!ec->desk->animate_count))
          {
             E_Client *tec;
             Ecore_Window top = e_comp_top_window_at_xy_get(ev->root.x, ev->root.y);
             int x, y;
             if (top == e_comp->ee_win) return ECORE_CALLBACK_RENEW;

             x = e_comp_canvas_x_root_adjust(ev->root.x);
             y = e_comp_canvas_y_root_adjust(ev->root.y);
             for (tec = e_client_above_get(ec); tec; tec = e_client_above_get(tec))
               {
                  if (!evas_object_visible_get(tec->frame)) continue;
                  if (E_INSIDE(x, y, tec->x, tec->y, tec->w, tec->h)) return ECORE_CALLBACK_RENEW;
               }
             if (!mouse_in_job)
               e_client_mouse_in(ec, x, y);
          }
        return ECORE_CALLBACK_RENEW;
     }
   E_COMP_X_PIXMAP_CHECK ECORE_CALLBACK_RENEW;
   if (_e_comp_x_client_data_get(ec)->deleted || e_client_util_ignored_get(ec)) return ECORE_CALLBACK_RENEW;
   if (e_client_util_resizing_get(ec) && (e_comp->comp_type == E_PIXMAP_TYPE_X) &&
       ec->netwm.sync.request &&
       _e_comp_x_client_data_get(ec)->alarm
      )
     {
        if ((ecore_loop_time_get() - ec->netwm.sync.send_time) > 0.5)
          {
             if (ec->pending_resize)
               {
                  ec->changes.pos = 1;
                  ec->changes.size = 1;
                  EC_CHANGED(ec);
                  _e_comp_x_client_move_resize_send(ec);
               }
             E_FREE_LIST(ec->pending_resize, free);

             ec->netwm.sync.wait = 0;
             /* sync.wait is incremented when resize_handle sends
              * sync-request and decremented by sync-alarm cb. so
              * we resize here either on initial resize, timeout or
              * when no new resize-request was added by sync-alarm cb.
              */
          }
     }
   e_client_mouse_move(ec, (Evas_Point*)&ev->root);
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_focus_out(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Focus_Out *ev)
{
   E_Client *ec;

   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec) return ECORE_CALLBACK_RENEW;

   _e_comp_x_client_pri_norm(ec);
   if (ev->mode == ECORE_X_EVENT_MODE_NORMAL)
     {
        if (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
          return ECORE_CALLBACK_PASS_ON;
        else if (ev->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR)
          return ECORE_CALLBACK_PASS_ON;
        else if (ev->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL)
          return ECORE_CALLBACK_PASS_ON;
     }
   else if (ev->mode == ECORE_X_EVENT_MODE_GRAB)
     {
        if (ev->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR)
          return ECORE_CALLBACK_PASS_ON;
        else if (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
          return ECORE_CALLBACK_PASS_ON;
        else if (ev->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL)
          return ECORE_CALLBACK_PASS_ON;
        else if (ev->detail == ECORE_X_EVENT_DETAIL_ANCESTOR)
          return ECORE_CALLBACK_PASS_ON;
        else if (ev->detail == ECORE_X_EVENT_DETAIL_VIRTUAL)
          return ECORE_CALLBACK_PASS_ON;
     }
   else if (ev->mode == ECORE_X_EVENT_MODE_UNGRAB)
     {
        /* for firefox/thunderbird (xul) menu walking */
        /* NB: why did i disable this before? */
        if (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
          return ECORE_CALLBACK_PASS_ON;
        else if (ev->detail == ECORE_X_EVENT_DETAIL_POINTER)
          return ECORE_CALLBACK_PASS_ON;
     }
   else if (ev->mode == ECORE_X_EVENT_MODE_WHILE_GRABBED)
     {
        if (ev->detail == ECORE_X_EVENT_DETAIL_ANCESTOR)
          return ECORE_CALLBACK_PASS_ON;
        else if (ev->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
          return ECORE_CALLBACK_PASS_ON;
     }
   evas_object_focus_set(ec->frame, 0);
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_client_property(void *d EINA_UNUSED, int t EINA_UNUSED, E_Event_Client_Property *ev)
{
   if ((ev->property & E_CLIENT_PROPERTY_ICON) && ev->ec->desktop)
     ecore_x_window_prop_string_set(e_client_util_win_get(ev->ec), E_ATOM_DESKTOP_FILE,
                                    ev->ec->desktop->orig_path);
   return ECORE_CALLBACK_RENEW;
}

static void
_e_comp_x_client_zone_geometry_set(E_Client *ec)
{
   unsigned int zgeom[4];

   E_COMP_X_PIXMAP_CHECK;
   zgeom[0] = ec->zone->x;
   zgeom[1] = ec->zone->y;
   zgeom[2] = ec->zone->w;
   zgeom[3] = ec->zone->h;
   ecore_x_window_prop_card32_set(e_client_util_win_get(ec), E_ATOM_ZONE_GEOMETRY, zgeom, 4);
}

static Eina_Bool
_e_comp_x_client_zone_set(void *data EINA_UNUSED, int type EINA_UNUSED, E_Event_Client *ev)
{
   E_Client *ec = ev->ec;

   if (e_object_is_del(E_OBJECT(ec))) return ECORE_CALLBACK_RENEW;
   E_COMP_X_PIXMAP_CHECK ECORE_CALLBACK_RENEW;
   ecore_x_window_prop_card32_set(e_client_util_win_get(ev->ec), E_ATOM_ZONE, &ev->ec->zone->num, 1);
   _e_comp_x_client_zone_geometry_set(ev->ec);
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_sync_alarm(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Sync_Alarm *ev)
{
   unsigned int serial;
   E_Client *ec;
//   Eina_Bool resize = EINA_FALSE;

   ec = _e_comp_x_client_find_by_alarm(ev->alarm);
   if ((!ec) || e_object_is_del(E_OBJECT(ec))) return ECORE_CALLBACK_RENEW;

   if (ec->netwm.sync.wait)
     ec->netwm.sync.wait--;

   if (ecore_x_sync_counter_query(_e_comp_x_client_data_get(ec)->sync_counter, &serial))
     {
        E_Client_Pending_Resize *pnd = NULL;

        /* skip pending for which we didn't get a reply */
        while (ec->pending_resize)
          {
             pnd = ec->pending_resize->data;
             ec->pending_resize = eina_list_remove(ec->pending_resize, pnd);

             if (serial == pnd->serial)
               break;

             E_FREE(pnd);
          }

        if (pnd)
          {
// disable this as it just seems to cause mis-sizing and issues...
//             resize = ((ec->w != pnd->w) || (ec->h != pnd->h));
//             e_comp_object_frame_wh_adjust(ec->frame, pnd->w, pnd->h, &ec->w, &ec->h);
             E_FREE(pnd);
          }
     }

// this too... as above
//   if (resize)
//     {
//        evas_object_resize(ec->frame, ec->w, ec->h);
//        if (ec->internal_elm_win)
//          evas_object_resize(ec->internal_elm_win, ec->client.w, ec->client.h);
//     }

   ec->netwm.sync.send_time = ecore_loop_time_get();
// this too - as above
//   if (resize)
//     {
//        ecore_x_pointer_xy_get(e_comp->root,
//                               &ec->mouse.current.mx,
//                               &ec->mouse.current.my);
//        e_client_mouse_move(ec, &(Evas_Point){ec->mouse.current.mx, ec->mouse.current.my});
//     }
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_desktop_change(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Desktop_Change *ev)
{
   E_Client *ec;

   ec = _e_comp_x_client_find_by_window(ev->win);
   if (ec)
     {
        if (ev->desk == 0xffffffff)
          e_client_stick(ec);
        else if ((int)ev->desk < (ec->zone->desk_x_count * ec->zone->desk_y_count))
          {
             E_Desk *desk;

             desk = e_desk_at_pos_get(ec->zone, ev->desk);
             if (desk)
               e_client_desk_set(ec, desk);
          }
     }
   else
     ecore_x_netwm_desktop_set(ev->win, ev->desk);
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_move_resize_request(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Move_Resize_Request *ev)
{
   E_Client *ec;

   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec) return ECORE_CALLBACK_RENEW;

   if ((ec->shaded) || (ec->shading) ||
       (ec->fullscreen) || (ec->moving) ||
       (ec->resize_mode != E_POINTER_RESIZE_NONE))
     return ECORE_CALLBACK_PASS_ON;

   if ((ev->button >= 1) && (ev->button <= 3))
     {
        ec->mouse.last_down[ev->button - 1].mx = ev->x;
        ec->mouse.last_down[ev->button - 1].my = ev->y;
        ec->mouse.last_down[ev->button - 1].x = ec->x;
        ec->mouse.last_down[ev->button - 1].y = ec->y;
        ec->mouse.last_down[ev->button - 1].w = ec->w;
        ec->mouse.last_down[ev->button - 1].h = ec->h;
     }
   else
     {
        ec->moveinfo.down.x = ec->x;
        ec->moveinfo.down.y = ec->y;
        ec->moveinfo.down.w = ec->w;
        ec->moveinfo.down.h = ec->h;
     }
   ec->mouse.current.mx = ev->x;
   ec->mouse.current.my = ev->y;
   ec->moveinfo.down.button = ev->button;
   ec->moveinfo.down.mx = ev->x;
   ec->moveinfo.down.my = ev->y;

   if (!ec->lock_user_stacking)
     evas_object_raise(ec->frame);

   if (ev->direction == E_POINTER_MOVE)
     {
        ec->cur_mouse_action = e_action_find("window_move");
        if (ec->cur_mouse_action)
          {
             if ((!ec->cur_mouse_action->func.end_mouse) &&
                 (!ec->cur_mouse_action->func.end))
               ec->cur_mouse_action = NULL;
             if (ec->cur_mouse_action)
               {
                  e_object_ref(E_OBJECT(ec->cur_mouse_action));
                  ec->cur_mouse_action->func.go(E_OBJECT(ec), NULL);
               }
          }
        return ECORE_CALLBACK_PASS_ON;
     }

   ec->cur_mouse_action = e_action_find("window_resize");
   if (ec->cur_mouse_action)
     {
        if ((!ec->cur_mouse_action->func.end_mouse) &&
            (!ec->cur_mouse_action->func.end))
          ec->cur_mouse_action = NULL;
     }
   if (!ec->cur_mouse_action) return ECORE_CALLBACK_RENEW;
   e_object_ref(E_OBJECT(ec->cur_mouse_action));
   ec->cur_mouse_action->func.go(E_OBJECT(ec), NULL);

   if (ev->direction != E_POINTER_RESIZE_NONE)
     {
        e_pointer_mode_pop(ec, ec->resize_mode);
        ec->resize_mode = ev->direction;
        e_pointer_mode_push(ec, ec->resize_mode);
     }
   switch (ev->direction)
     {
      case E_POINTER_RESIZE_TL:
        GRAV_SET(ec, ECORE_X_GRAVITY_SE);
        break;

      case E_POINTER_RESIZE_T:
        GRAV_SET(ec, ECORE_X_GRAVITY_S);
        break;

      case E_POINTER_RESIZE_TR:
        GRAV_SET(ec, ECORE_X_GRAVITY_SW);
        break;

      case E_POINTER_RESIZE_R:
        GRAV_SET(ec, ECORE_X_GRAVITY_W);
        break;

      case E_POINTER_RESIZE_BR:
        GRAV_SET(ec, ECORE_X_GRAVITY_NW);
        break;

      case E_POINTER_RESIZE_B:
        GRAV_SET(ec, ECORE_X_GRAVITY_N);
        break;

      case E_POINTER_RESIZE_BL:
        GRAV_SET(ec, ECORE_X_GRAVITY_NE);
        break;

      case E_POINTER_RESIZE_L:
        GRAV_SET(ec, ECORE_X_GRAVITY_E);
        break;

      default:
        return ECORE_CALLBACK_PASS_ON;
     }

   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_focus_timer_cb(void *d EINA_UNUSED)
{
   E_Client *focused;

   /* if mouse-based focus policy clients exist for [focused] and [mouse_client],
    * [mouse_client] should have focus here.
    * race conditions in x11 focus setting can result in a scenario such that:
    * -> set focus on A
    * -> set focus on B
    * -> receive focus event on A
    * -> re-set focus on A
    * -> receive focus event on B
    * -> receive focus event on A
    * ...
    * where the end state is that the cursor is over a client which does not have focus.
    * this timer is triggered only when such eventing occurs in order to adjust the focused
    * client as necessary
    */
   focused = e_client_focused_get();
   if (mouse_client && focused && (!e_client_focus_policy_click(focused)) && (mouse_client != focused))
     {
        int x, y;

        ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
        if (E_INSIDE(x, y, mouse_client->x, mouse_client->y, mouse_client->w, mouse_client->h))
          {
             if (!_e_comp_x_client_data_get(mouse_client)->deleted)
               e_client_mouse_in(mouse_client, x, y);
          }
     }
   focus_timer = NULL;
   return EINA_FALSE;
}

static void
_e_comp_x_focus_timer(void)
{
   if (focus_timer)
     ecore_timer_loop_reset(focus_timer);
   else /* focus has changed twice in .002 seconds; .01 seconds should be more than enough delay */
     focus_timer = ecore_timer_loop_add(0.01, _e_comp_x_focus_timer_cb, NULL);
}

static Eina_Bool
_e_comp_x_focus_in(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Focus_In *ev)
{
   E_Client *ec, *focused;

   ec = _e_comp_x_client_find_by_window(ev->win);

   if (e_comp->comp_type == E_PIXMAP_TYPE_WL)
     {
        focused = e_client_focused_get();
        if (ec && focused)
          {
             if ((!ec->override) && (ec != focused))
               {
                  ecore_x_window_focus(e_client_util_win_get(focused));
                  ecore_x_icccm_take_focus_send(e_client_util_win_get(focused), ecore_x_current_time_get());
               }
          }
        else
          ecore_x_window_focus(e_comp->root);
        return ECORE_CALLBACK_RENEW;
     }
   if (!ec)
     {
        if ((ev->win == e_comp->ee_win) && (ev->time >= focus_canvas_time) && (!focus_time))
          {
             focused = e_client_focused_get();
             if (focused)
               evas_object_focus_set(focused->frame, 0);
             focus_canvas_time = 0;
          }
        return ECORE_CALLBACK_RENEW;
     }

   /* block refocus attempts on iconic clients
    * these result from iconifying a client during a grab */
   if (ec->iconic) return ECORE_CALLBACK_RENEW;

   focused = e_client_focused_get();

   _e_comp_x_client_pri_raise(ec);
   if (ev->mode == ECORE_X_EVENT_MODE_GRAB)
     {
        if (ev->detail == ECORE_X_EVENT_DETAIL_POINTER) return ECORE_CALLBACK_PASS_ON;
     }
   else if (ev->mode == ECORE_X_EVENT_MODE_UNGRAB)
     {
        /* this seems to break winlist...
        if (ev->detail == ECORE_X_EVENT_DETAIL_POINTER)
        */

        /* we're getting a non-linear focus re-set on a visible
         * window on current desk when no other client is focused;
         * this is probably when we're trying to reapply focus after
         * unfocusing some comp canvas widget
         */
        if ((ev->detail != ECORE_X_EVENT_DETAIL_NON_LINEAR) ||
            focused ||
            (!e_client_util_desk_visible(ec, e_desk_current_get(ec->zone))))
        return ECORE_CALLBACK_PASS_ON;
     }

   /* ignore focus in from !take_focus windows, we just gave it em */
   /* if (!ec->icccm.take_focus)
    *   return ECORE_CALLBACK_PASS_ON; */

   /* should be equal, maybe some clients don't reply with the proper timestamp ? */
   if (ev->time >= focus_time)
     evas_object_focus_set(ec->frame, 1);
   /* handle case of someone trying to benchmark focus handling */
   if ((!e_client_focus_policy_click(ec)) && (focused && (!e_client_focus_policy_click(focused))) &&
       (ev->time - focus_time <= 2))
     _e_comp_x_focus_timer();
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_shape(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Shape *ev)
{
   E_Client *ec;
   Eina_Bool pshaped;
   //const char *txt[] =
   //{
      //[ECORE_X_SHAPE_BOUNDING] = "BOUNDING",
      //[ECORE_X_SHAPE_INPUT] = "INPUT",
      //[ECORE_X_SHAPE_CLIP] = "CLIP",
   //};

   ec = _e_comp_x_client_find_by_window(ev->win);
   if (!ec) return ECORE_CALLBACK_RENEW;
   pshaped = ec->shaped;
   //INF("%p(%s): %d,%d %dx%d || %d", ec, txt[ev->type], ev->x, ev->y, ev->w, ev->h, ev->shaped);
   if (ev->win == e_client_util_win_get(ec))
     {
        if (ev->type == ECORE_X_SHAPE_INPUT)
          {
             ec->changes.shape_input = 1;
             ec->need_shape_merge = 1;
          }
        else
          {
             if ((_e_comp_x_client_data_get(ec)->shape.x != ev->x) ||
                 (_e_comp_x_client_data_get(ec)->shape.y != ev->y) ||
                 (_e_comp_x_client_data_get(ec)->shape.w != ev->w) ||
                 (_e_comp_x_client_data_get(ec)->shape.h != ev->h))
               {
                  /* bounding box changed, need export for rendering */
                  EINA_RECTANGLE_SET(&_e_comp_x_client_data_get(ec)->shape, ev->x, ev->y, ev->w, ev->h);
                  ec->need_shape_export = !ec->override;
               }
             ec->changes.shape = 1;
          }
     }
   else if (ec->shaped) //shape change on parent window only valid if window is known to be shaped
     ec->need_shape_export = 1;
   if (ec->changes.shape)
     {
        if ((ev->type == ECORE_X_SHAPE_BOUNDING) && (ec->shaped || (pshaped != ec->shaped)))
          {
             if (ec->shape_rects || (!ec->shaped))
               e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
          }
     }
   EC_CHANGED(ec);
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_damage(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Damage *ev)
{
   E_Client *ec;
   Ecore_X_Rectangle *rects = NULL;
   int n = 0;
   Eina_Bool skip;

   ec = _e_comp_x_client_find_by_damage(ev->damage);
   if ((!ec) || e_object_is_del(E_OBJECT(ec))) return ECORE_CALLBACK_PASS_ON;
   skip = ec->shape_rects_num > 50;
   if (_e_comp_x_client_data_get(ec)->damage)
     {
        Ecore_X_Region parts;
        Ecore_X_Rectangle bounds;

        parts = ecore_x_region_new(NULL, 0);
        ecore_x_damage_subtract(_e_comp_x_client_data_get(ec)->damage, 0, parts);
        if (!skip)
          rects = ecore_x_region_fetch(parts, &n, &bounds);
        ecore_x_region_free(parts);
     }
   //WRN("DAMAGE %p: %dx%d", ec, ev->area.width, ev->area.height);

   if (e_comp->nocomp)
     e_pixmap_dirty(ec->pixmap);
   else if (skip)
     e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
   else
     {
        int i;

        for (i = 0; i < n; i++)
          e_comp_object_damage(ec->frame, rects[i].x, rects[i].y, rects[i].width, rects[i].height);
     }
   free(rects);
   if ((!ec->re_manage) && (!ec->override) && (!_e_comp_x_client_data_get(ec)->first_damage))
     e_comp_object_render_update_del(ec->frame);
   else
     E_FREE_FUNC(_e_comp_x_client_data_get(ec)->first_draw_delay, ecore_timer_del);
   _e_comp_x_client_data_get(ec)->first_damage = 1;
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_damage_win(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Window_Damage *ev)
{
   if (e_comp_find_by_window(ev->win)) e_comp_render_queue();
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_grab_replay(void *data EINA_UNUSED, int type, void *event)
{
   Ecore_Event_Mouse_Button *ev = event;
   E_Binding_Event_Mouse_Button ev2;
   E_Client *ec;

   if (type != ECORE_EVENT_MOUSE_BUTTON_DOWN) return ECORE_CALLBACK_DONE;
   if ((!e_config->pass_click_on) &&
       (!e_config->always_click_to_raise) && // this works even if not on click-to-focus
       (!e_config->always_click_to_focus) // this works even if not on click-to-focus
       )
     return ECORE_CALLBACK_DONE;
   ec = _e_comp_x_client_find_by_window(ev->event_window);
   if (!ec) return ECORE_CALLBACK_DONE;
   if (ec->cur_mouse_action) return ECORE_CALLBACK_DONE;
   if (ev->event_window != e_client_util_win_get(ec)) return ECORE_CALLBACK_DONE;
   e_bindings_ecore_event_mouse_button_convert(ev, &ev2);
   return !e_bindings_mouse_button_find(E_BINDING_CONTEXT_WINDOW,
                                        &ev2, NULL);
}

static void
_e_comp_x_hook_client_eval_end(void *d EINA_UNUSED, E_Client *ec)
{
   E_COMP_X_PIXMAP_CHECK;
   if (e_comp_x->restack && (!e_comp->new_clients))
     {
        e_hints_client_stacking_set();
        e_comp_x->restack = 0;
     }
}

static Eina_Bool
_e_comp_x_client_shape_rects_check(E_Client *ec, Ecore_X_Rectangle *rects, int num)
{
   Eina_Bool changed = 1;
   Ecore_X_Rectangle *orects;

   if (((unsigned int)num == ec->shape_rects_num) && (ec->shape_rects))
     {
        int i;

        orects = (Ecore_X_Rectangle*)ec->shape_rects;
        changed = 0;
        for (i = 0; i < num; i++)
          {
             E_RECTS_CLIP_TO_RECT(rects[i].x, rects[i].y,
               rects[i].width, rects[i].height, 0, 0, ec->client.w, ec->client.h);

             if ((orects[i].x != rects[i].x) ||
                 (orects[i].y != rects[i].y) ||
                 (orects[i].width != rects[i].width) ||
                 (orects[i].height != rects[i].height))
               {
                  changed = 1;
                  break;
               }
          }
     }
   if ((changed) && (rects))
     {
        E_FREE(ec->shape_rects);
        ec->shape_rects = (Eina_Rectangle*)rects;
        ec->shape_rects_num = num;
        ec->shape_changed = 1;
        e_comp_shape_queue();
     }
   else
     free(rects);
   return changed;
}

static void
_e_comp_x_hook_client_post_new_client(void *d EINA_UNUSED, E_Client *ec)
{
   E_COMP_X_PIXMAP_CHECK;
   if (ec->changes.reset_gravity)
     {
        GRAV_SET(ec, ECORE_X_GRAVITY_NW);
     }

   if (ec->need_shape_merge)
     {
        _e_comp_x_client_shape_input_rectangle_set(ec);
        if ((!ec->shaped) && _e_comp_x_client_data_get(ec)->reparented)
          ecore_x_window_shape_mask_set(e_client_util_pwin_get(ec), 0);
        ec->need_shape_merge = 0;
     }

   if (ec->changes.internal_state)
     {
        Ecore_X_Atom state[1];
        int num = 0;

        if (e_win_centered_get(ec->internal_elm_win))
          state[num++] = E_ATOM_WINDOW_STATE_CENTERED;

        if (num)
          ecore_x_window_prop_card32_set(elm_win_window_id_get(ec->internal_elm_win), E_ATOM_WINDOW_STATE, state, num);
        else
          ecore_x_window_prop_property_del(elm_win_window_id_get(ec->internal_elm_win), E_ATOM_WINDOW_STATE);
        ec->changes.internal_state = 0;
     }

   if (ec->need_shape_export)
     {
        Ecore_X_Rectangle *rects;
        int num;

        rects = ecore_x_window_shape_rectangles_get(e_client_util_win_get(ec), &num);
        if (rects)
          _e_comp_x_client_shape_rects_check(ec, rects, num);
        else
          {
             E_FREE(ec->shape_rects);
             ec->shape_rects_num = 0;
          }
        ec->need_shape_export = 0;
     }
}

static void
_e_comp_x_hook_client_pre_frame_assign(void *d EINA_UNUSED, E_Client *ec)
{
   Ecore_X_Window win, pwin;
   int w, h;
   E_Pixmap *ep;
   E_Comp_X_Client_Data *cd;

   E_COMP_X_PIXMAP_CHECK;
   ep = e_comp_x_client_pixmap_get(ec);
   win = e_client_util_win_get(ec);
   cd = _e_comp_x_client_data_get(ec);
   if (!cd->need_reparent) return;
   w = MAX(ec->client.w, 1);
   h = MAX(ec->client.h, 1);
   /* match ec parent argbness */
   if (ec->argb)
     pwin = ecore_x_window_manager_argb_new(e_comp->root, ec->client.x, ec->client.y, w, h);
   else
     {
        pwin = ecore_x_window_override_new(e_comp->root, ec->client.x, ec->client.y, w, h);
        ecore_x_window_shape_events_select(pwin, !ec->internal); //let's just agree never to do this with our own windows...
     }

   if (ec->client.w && ec->client.h)
     /* force a resize here (no-op most of the time)
      * prevents mismatch between remembered window size and current size
      */
     ecore_x_window_resize(win, ec->client.w, ec->client.h);
   ecore_x_window_container_manage(pwin);
   if (!ec->internal) ecore_x_window_client_manage(win);
   ecore_x_window_configure(pwin,
                            ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
                            ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
                            0, 0, 0, 0, 0,
                            win, ECORE_X_WINDOW_STACK_ABOVE);
   ecore_x_event_mask_set(pwin, ECORE_X_EVENT_MASK_KEY_DOWN | ECORE_X_EVENT_MASK_KEY_UP |
                                ECORE_X_EVENT_MASK_MOUSE_MOVE | ECORE_X_EVENT_MASK_MOUSE_DOWN |
                                ECORE_X_EVENT_MASK_MOUSE_UP |
                                ECORE_X_EVENT_MASK_MOUSE_IN | ECORE_X_EVENT_MASK_MOUSE_OUT);
   ecore_x_window_border_width_set(win, 0);
   ec->border_size = 0;

   if (ec->e.state.video)
     {
        ecore_x_window_lower(pwin);
        ecore_x_composite_window_events_disable(pwin);
        ecore_x_window_ignore_set(pwin, EINA_TRUE);
     }
   if (!ec->internal)
     ecore_x_window_save_set_add(win);
   ecore_x_window_reparent(win, pwin, 0, 0);
   e_pixmap_alias(ep, E_PIXMAP_TYPE_X, pwin);

   {
      unsigned int managed = 1;
      ecore_x_window_prop_card32_set(win, E_ATOM_MANAGED, &managed, 1);
   }
   e_pixmap_parent_window_set(ep, pwin);
   ec->border.changed = 1;
   if (!ec->shaped)
     ecore_x_window_shape_mask_set(pwin, 0);
   if (ec->shaped_input)
     ecore_x_window_shape_input_rectangles_set(pwin, (Ecore_X_Rectangle*)ec->shape_input_rects, ec->shape_input_rects_num);
   ec->changes.shape = 1;
   ec->changes.shape_input = 1;
   if (ec->internal_elm_win)
     {
        ecore_x_window_gravity_set(win, ECORE_X_GRAVITY_NW);
        ec->changes.reset_gravity = 1;
     }
   EC_CHANGED(ec);

   eina_hash_add(clients_win_hash, &pwin, ec);

   if (ec->visible)
     {
        if (cd->set_win_type && ec->internal_elm_win)
          {
             if (ec->dialog)
               ecore_x_netwm_window_type_set(win, ECORE_X_WINDOW_TYPE_DIALOG);
             else
               ecore_x_netwm_window_type_set(win, ECORE_X_WINDOW_TYPE_NORMAL);
             cd->set_win_type = 0;
          }
     }
   ecore_x_window_show(win);
   if (ec->icccm.state != ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
     ecore_x_window_show(pwin);

   _e_comp_x_focus_init(ec);
   e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, pwin);
   e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, pwin);
   _e_comp_x_client_evas_init(ec);
   if (ec->netwm.ping && (!ec->ping_poller))
     e_client_ping(ec);
   if (ec->visible && (ec->icccm.state != ECORE_X_WINDOW_STATE_HINT_WITHDRAWN))
     evas_object_show(ec->frame);
   cd->need_reparent = 0;
   ec->redirected = 1;
   if (cd->change_icon)
     {
        ec->changes.icon = 1;
        EC_CHANGED(ec);
     }
   cd->change_icon = 0;
   cd->reparented = 1;
   _e_comp_x_evas_comp_hidden_cb(ec, NULL, NULL);
}

static void
_e_comp_x_hook_client_fetch(void *d EINA_UNUSED, E_Client *ec)
{
   Ecore_X_Window win, pwin;
   int rem_change = 0;
   Eina_Bool need_desk_set = EINA_FALSE;
   E_Comp_X_Client_Data *cd;

   E_COMP_X_PIXMAP_CHECK;
   win = e_client_util_win_get(ec);
   pwin = e_client_util_pwin_get(ec);
   cd = _e_comp_x_client_data_get(ec);
   if (ec->changes.visible)
     _e_comp_x_client_shape_input_rectangle_set(ec);
   /* fetch any info queued to be fetched */
   if (ec->changes.prop || ec->netwm.fetch.state)
     {
        e_hints_window_state_get(ec);
        ec->netwm.fetch.state = 0;
        rem_change = 1;
     }
   if (ec->icccm.fetch.client_leader)
     {
        /* TODO: What do to if the client leader isn't mapped yet? */
        E_Client *ec_leader = NULL;

        ec->icccm.client_leader = ecore_x_icccm_client_leader_get(win);
        if (ec->icccm.client_leader)
          ec_leader = _e_comp_x_client_find_by_window(ec->icccm.client_leader);
        if (ec->leader)
          {
             if (ec->leader != ec_leader)
               {
                  ec->leader->group = eina_list_remove(ec->leader->group, ec);
                  if (ec->leader->modal == ec) ec->leader->modal = NULL;
                  ec->leader = NULL;
               }
             else
               ec_leader = NULL;
          }
        /* If this client is the leader of the group, don't register itself */
        if ((ec_leader) && (ec_leader != ec))
          {
             ec_leader->group = eina_list_append(ec_leader->group, ec);
             ec->leader = ec_leader;
             /* Only set the window modal to the leader it there is no parent */
             if ((ec->netwm.state.modal) &&
                 ((!ec->parent) || (ec->parent->modal != ec)))
               {
                  ec->leader->modal = ec;
                  if (ec->leader->focused)
                    evas_object_focus_set(ec->frame, 1);
                  else
                    {
                       Eina_List *l;
                       E_Client *child;

                       EINA_LIST_FOREACH(ec->leader->group, l, child)
                         {
                            if ((child != ec) && (child->focused))
                              evas_object_focus_set(ec->frame, 1);
                         }
                    }
               }
          }
        ec->icccm.fetch.client_leader = 0;
        rem_change = 1;
     }
   if (ec->icccm.fetch.title)
     {
        char *title = ecore_x_icccm_title_get(win);
        eina_stringshare_replace(&ec->icccm.title, title);
        free(title);

        e_comp_object_frame_title_set(ec->frame, ec->icccm.title);

        ec->icccm.fetch.title = 0;
        rem_change = 1;
     }
   if (ec->netwm.fetch.name)
     {
        char *name;
        ecore_x_netwm_name_get(win, &name);
        eina_stringshare_replace(&ec->netwm.name, name);
        free(name);

        ec->hacks.iconic_shading =
          ((ec->netwm.icon_name == ec->netwm.name) &&
           (!e_util_strcmp(ec->netwm.name, "QEMU")));

        e_comp_object_frame_title_set(ec->frame, ec->netwm.name);

        ec->netwm.fetch.name = 0;
        rem_change = 1;
     }

   if (ec->icccm.fetch.name_class)
     {
        const char *pname, *pclass;
        char *nname, *nclass;

        ecore_x_icccm_name_class_get(win, &nname, &nclass);
        pname = ec->icccm.name;
        pclass = ec->icccm.class;
        ec->icccm.name = eina_stringshare_add(nname);
        ec->icccm.class = eina_stringshare_add(nclass);
        ec->hacks.mapping_change =
          ((!e_util_strcasecmp(ec->icccm.class, "vmplayer")) ||
           (!e_util_strcasecmp(ec->icccm.class, "vmware")));
        if (ec->hacks.mapping_change)
          _e_comp_x_mapping_change_disabled++;
        _e_comp_x_mapping_change_disabled = MIN(_e_comp_x_mapping_change_disabled, 0);
        free(nname);
        free(nclass);

        if (!((ec->icccm.name == pname) &&
              (ec->icccm.class == pclass)))
          {
             ec->changes.icon = 1;
             rem_change = 1;
          }

        eina_stringshare_del(pname);
        eina_stringshare_del(pclass);
        ec->icccm.fetch.name_class = 0;
     }
   if (ec->changes.prop || ec->e.fetch.state)
     {
        e_hints_window_e_state_get(ec);
        ec->e.fetch.state = 0;
        rem_change = 1;
     }
   if (ec->e.fetch.stack)
     {
        cd->stack = ecore_x_e_stack_type_get(win);
        ec->e.state.stack = !!cd->stack;
        ec->e.fetch.stack = 0;
     }
   if (ec->e.fetch.profile)
     {
        const char **list = NULL;
        int n, i, res;
        unsigned int use;

        ec->e.state.profile.use = 0;

        if (ec->e.state.profile.name)
          {
             eina_stringshare_del(ec->e.state.profile.name);
             ec->e.state.profile.name = NULL;
          }

        if (ec->e.state.profile.available_list)
          {
             for (i = 0; i < ec->e.state.profile.num; i++)
               {
                  if (ec->e.state.profile.available_list[i])
                    {
                       eina_stringshare_del(ec->e.state.profile.available_list[i]);
                       ec->e.state.profile.available_list[i] = NULL;
                    }
               }
             E_FREE(ec->e.state.profile.available_list);
             ec->e.state.profile.available_list = NULL;
          }
        ec->e.state.profile.num = 0;

        res = ecore_x_window_prop_card32_get(win,
                                             ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED,
                                             &use,
                                             1);
        if ((res == 1) && (use == 1))
          {
             Ecore_X_Atom val;
             res = ecore_x_window_prop_atom_get(win,
                                                ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE,
                                                &val, 1);
             if (res == 1)
               {
                  char *name = ecore_x_atom_name_get(val);
                  if (name)
                    {
                       ec->e.state.profile.set = eina_stringshare_add(name);
                       free(name);
                    }
               }

             if (ecore_x_e_window_available_profiles_get(win, &list, &n))
               {
                  ec->e.state.profile.available_list = E_NEW(const char *, n);
                  for (i = 0; i < n; i++)
                    ec->e.state.profile.available_list[i] = eina_stringshare_add(list[i]);
                  ec->e.state.profile.num = n;
               }
             need_desk_set = EINA_TRUE;
             ec->e.state.profile.use = 1;
             free(list);
          }

        ec->e.fetch.profile = 0;
     }
   if (ec->changes.prop || ec->netwm.fetch.type)
     {
        unsigned int type = ec->netwm.type;
        e_hints_window_type_get(ec);
        if (((!ec->lock_border) || (!ec->border.name) || (type != ec->netwm.type)) && (cd->reparented || ec->internal))
          {
             ec->border.changed = 1;
             EC_CHANGED(ec);
          }

        if ((ec->netwm.type == E_WINDOW_TYPE_DOCK) || ec->tooltip)
          {
             if (!ec->netwm.state.skip_pager)
               {
                  ec->netwm.state.skip_pager = 1;
                  ec->netwm.update.state = 1;
               }
             if (!ec->netwm.state.skip_taskbar)
               {
                  ec->netwm.state.skip_taskbar = 1;
                  ec->netwm.update.state = 1;
               }
          }
        else if (ec->netwm.type == E_WINDOW_TYPE_DESKTOP)
          {
             ec->focus_policy_override = E_FOCUS_CLICK;
             _e_comp_x_focus_setdown(ec);
             _e_comp_x_focus_setup(ec);
             e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, pwin);
             e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, pwin);
             if (!ec->netwm.state.skip_pager)
               {
                  ec->netwm.state.skip_pager = 1;
                  ec->netwm.update.state = 1;
               }
             if (!ec->netwm.state.skip_taskbar)
               {
                  ec->netwm.state.skip_taskbar = 1;
                  ec->netwm.update.state = 1;
               }
             if (!e_client_util_ignored_get(ec))
               ec->border.changed = ec->borderless = 1;
          }
        if (ec->tooltip)
          {
             ec->icccm.accepts_focus = 0;
             eina_stringshare_replace(&ec->bordername, "borderless");
          }
        {
           E_Event_Client_Property *ev;

           ev = E_NEW(E_Event_Client_Property, 1);
           ev->ec = ec;
           REFD(ec, 1);
           e_object_ref(E_OBJECT(ec));
           ev->property = E_CLIENT_PROPERTY_NETWM_STATE;
           ecore_event_add(E_EVENT_CLIENT_PROPERTY, ev, _e_comp_x_client_event_free, NULL);
        }
        ec->netwm.fetch.type = 0;
     }
   if (ec->icccm.fetch.machine)
     {
        char *machine = ecore_x_icccm_client_machine_get(win);

        if ((!machine) && (ec->icccm.client_leader))
          machine = ecore_x_icccm_client_machine_get(ec->icccm.client_leader);

        eina_stringshare_replace(&ec->icccm.machine, machine);
        free(machine);

        ec->icccm.fetch.machine = 0;
        rem_change = 1;
     }
   if (ec->icccm.fetch.command)
     {
        if ((ec->icccm.command.argc > 0) && (ec->icccm.command.argv))
          {
             int i;

             for (i = 0; i < ec->icccm.command.argc; i++)
               free(ec->icccm.command.argv[i]);
             free(ec->icccm.command.argv);
          }
        ec->icccm.command.argc = 0;
        ec->icccm.command.argv = NULL;
        ecore_x_icccm_command_get(win,
                                  &(ec->icccm.command.argc),
                                  &(ec->icccm.command.argv));
        if ((ec->icccm.client_leader) &&
            (!ec->icccm.command.argv))
          ecore_x_icccm_command_get(ec->icccm.client_leader,
                                    &(ec->icccm.command.argc),
                                    &(ec->icccm.command.argv));
        ec->icccm.fetch.command = 0;
        rem_change = 1;
     }
   if (ec->changes.prop || ec->icccm.fetch.hints)
     {
        Eina_Bool accepts_focus, is_urgent;
        Ecore_X_Window_State_Hint state = ec->icccm.state;

        accepts_focus = EINA_TRUE;
        is_urgent = EINA_FALSE;
        ec->icccm.state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
        if (ecore_x_icccm_hints_get(win,
                                    &accepts_focus,
                                    &ec->icccm.state,
                                    &ec->icccm.icon_pixmap,
                                    &ec->icccm.icon_mask,
                                    (Ecore_X_Window*)&ec->icccm.icon_window,
                                    (Ecore_X_Window*)&ec->icccm.window_group,
                                    &is_urgent))
          {
             if (ec->new_client)
               {
                  /* clients may unset iconic state when no wm is present */
                  if (ec->netwm.state.hidden && (ec->icccm.state == ECORE_X_WINDOW_STATE_HINT_NORMAL))
                    ec->icccm.initial_state = ECORE_X_WINDOW_STATE_HINT_ICONIC;
                  else
                    ec->icccm.initial_state = ec->icccm.state;
               }
             if (state != ec->icccm.state)
               {
                  if (ec->icccm.state == ECORE_X_WINDOW_STATE_HINT_WITHDRAWN)
                    ec->ignored = 1, ec->visible = 0;
                  else
                    {
                       ec->visible = 1;
                       ec->changes.visible = ec->new_client;
                       if ((!ec->new_client) &&
                         (ec->icccm.state == ECORE_X_WINDOW_STATE_HINT_NORMAL))
                         evas_object_show(ec->frame);
                    }
               }
             ec->icccm.accepts_focus = accepts_focus;
             ec->icccm.urgent = is_urgent;
             e_client_urgent_set(ec, is_urgent);

             /* If this is a new window, set the state as requested. */
             if ((ec->new_client) &&
                 (ec->icccm.initial_state == ECORE_X_WINDOW_STATE_HINT_ICONIC))
               e_client_iconify(ec);
          }
        ec->icccm.fetch.hints = 0;
        rem_change = 1;
     }
   if (ec->override) ec->placed = EINA_TRUE;
   if (ec->changes.prop || ec->icccm.fetch.size_pos_hints)
     {
        Eina_Bool request_pos;

        request_pos = EINA_FALSE;
        if (ecore_x_icccm_size_pos_hints_get(win,
                                             &request_pos,
                                             &ec->icccm.gravity,
                                             &ec->icccm.min_w,
                                             &ec->icccm.min_h,
                                             &ec->icccm.max_w,
                                             &ec->icccm.max_h,
                                             &ec->icccm.base_w,
                                             &ec->icccm.base_h,
                                             &ec->icccm.step_w,
                                             &ec->icccm.step_h,
                                             &ec->icccm.min_aspect,
                                             &ec->icccm.max_aspect))
          {
             ec->icccm.request_pos = request_pos;
             if (request_pos && (!ec->placed) && (!ec->re_manage))
               {
                  Ecore_X_Window_Attributes *att;
                  int bw;
                  int l, r, t, b;
                  int zx = 0, zy = 0, zw = 0, zh = 0;

                  if (ec->zone)
                    e_zone_useful_geometry_get(ec->zone, &zx, &zy, &zw, &zh);
                  e_comp_object_frame_geometry_get(ec->frame, &l, &r, &t, &b);
                  att = &cd->initial_attributes;
                  bw = att->border * 2;
                  switch (ec->icccm.gravity)
                    {
                     case ECORE_X_GRAVITY_N:
                       ec->x = (att->x - (bw / 2)) - (l / 2);
                       ec->y = att->y;
                       break;

                     case ECORE_X_GRAVITY_NE:
                       ec->x = (att->x - (bw)) - (l);
                       ec->y = att->y;
                       break;

                     case ECORE_X_GRAVITY_E:
                       ec->x = (att->x - (bw)) - (l);
                       ec->y = (att->y - (bw / 2)) - (t / 2);
                       break;

                     case ECORE_X_GRAVITY_SE:
                       ec->x = (att->x - (bw)) - (l);
                       ec->y = (att->y - (bw)) - (t);
                       break;

                     case ECORE_X_GRAVITY_S:
                       ec->x = (att->x - (bw / 2)) - (l / 2);
                       ec->y = (att->y - (bw)) - (t);
                       break;

                     case ECORE_X_GRAVITY_SW:
                       ec->x = att->x;
                       ec->y = (att->y - (bw)) - (t);
                       break;

                     case ECORE_X_GRAVITY_W:
                       ec->x = att->x;
                       ec->y = (att->y - (bw)) - (t);
                       break;

                     case ECORE_X_GRAVITY_CENTER:
                       ec->x = (att->x - (bw / 2)) - (l / 2);
                       ec->y = (att->y - (bw / 2)) - (t / 2);
                       break;

                     case ECORE_X_GRAVITY_NW:
                     default:
                       ec->x = att->x;
                       ec->y = att->y;
                    }

                  /*
                   * This ensures that windows that like to open with a x/y
                   * position smaller than returned by e_zone_useful_geometry_get()
                   * are moved to useful positions.
                   */
                  // ->
                  if (e_config->geometry_auto_move)
                    {
                       if (ec->x < zx)
                         ec->x = zx;

                       if (ec->y < zy)
                         ec->y = zy;

                       /* ensure we account for windows which already have client_inset;
                        * fixes lots of wine placement issues
                        */
                       if (ec->x - l >= zx)
                         ec->x -= l;
                       if (ec->y - t >= zy)
                         ec->y -= t;

                       if (ec->x + ec->w > zx + zw)
                         ec->x = zx + zw - ec->w;

                       if (ec->y + ec->h > zy + zh)
                         ec->y = zy + zh - ec->h;

                       // <--
                       if (e_comp_zone_xy_get(ec->x, ec->y))
                         {
                            if (!E_INSIDE(ec->x, ec->y, ec->zone->x, ec->zone->y, ec->zone->w, ec->zone->h))
                              {
                                 ec->x = E_CLAMP(ec->x, ec->zone->x, ec->zone->x + ec->zone->w);
                                 ec->y = E_CLAMP(ec->y, ec->zone->y, ec->zone->y + ec->zone->h);
                              }
                            /* some application failing to correctly center a window */
                            if (eina_list_count(e_comp->zones) > 1)
                              {
                                 if (abs((e_comp->w / 2) - ec->x - (ec->w / 2)) < 3)
                                   ec->x = ((ec->zone->x + ec->zone->w) / 2) - (ec->w / 2);
                                 if (abs((e_comp->h / 2) - ec->y - (ec->h / 2)) < 3)
                                   ec->y = ((ec->zone->y + ec->zone->h) / 2) - (ec->h / 2);
                              }
                            ec->changes.pos = 1;
                            ec->placed = 1;
                         }
                    }
                  else
                    {
                       ec->changes.pos = 1;
                       ec->placed = 1;
                    }
               }
             if (ec->placed && (!e_client_util_resizing_get(ec)) && (!ec->override))
               {
                  if (ec->fullscreen || ec->maximized)
                    e_client_rescale(ec);
                  else
                    {
                       int rw = ec->w, rh = ec->h;

                       e_client_resize_limit(ec, &rw, &rh);
                       evas_object_resize(ec->frame, rw, rh);
                    }
               }
          }
        if (ec->icccm.min_w > 32767) ec->icccm.min_w = 32767;
        if (ec->icccm.min_h > 32767) ec->icccm.min_h = 32767;
        if (ec->icccm.max_w > 32767) ec->icccm.max_w = 32767;
        if (ec->icccm.max_h > 32767) ec->icccm.max_h = 32767;
        if (ec->icccm.base_w > 32767) ec->icccm.base_w = 32767;
        if (ec->icccm.base_h > 32767) ec->icccm.base_h = 32767;
        //	if (ec->icccm.step_w < 1) ec->icccm.step_w = 1;
        //	if (ec->icccm.step_h < 1) ec->icccm.step_h = 1;
        // if doing a resize, fix it up
        if (e_client_util_resizing_get(ec))
          {
             int x, y, w, h, new_w, new_h;

             x = ec->x;
             y = ec->y;
             w = ec->w;
             h = ec->h;
             new_w = w;
             new_h = h;
             e_client_resize_limit(ec, &new_w, &new_h);
             if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
                 (ec->resize_mode == E_POINTER_RESIZE_L) ||
                 (ec->resize_mode == E_POINTER_RESIZE_BL))
               x += (w - new_w);
             if ((ec->resize_mode == E_POINTER_RESIZE_TL) ||
                 (ec->resize_mode == E_POINTER_RESIZE_T) ||
                 (ec->resize_mode == E_POINTER_RESIZE_TR))
               y += (h - new_h);
             evas_object_geometry_set(ec->frame, x, y, new_w, new_h);
          }
        ec->icccm.fetch.size_pos_hints = 0;
        rem_change = 1;
     }
   if (ec->icccm.fetch.protocol)
     {
        int i, num;
        Ecore_X_WM_Protocol *proto;

        proto = ecore_x_window_prop_protocol_list_get(win, &num);
        if (proto)
          {
             for (i = 0; i < num; i++)
               {
                  if (proto[i] == ECORE_X_WM_PROTOCOL_DELETE_REQUEST)
                    ec->icccm.delete_request = 1;
                  else if (proto[i] == ECORE_X_WM_PROTOCOL_TAKE_FOCUS)
                    ec->icccm.take_focus = 1;
                  else if (proto[i] == ECORE_X_NET_WM_PROTOCOL_PING)
                    ec->netwm.ping = 1;
                  else if (proto[i] == ECORE_X_NET_WM_PROTOCOL_SYNC_REQUEST)
                    {
                       ec->netwm.sync.request = 1;
                       if (!ecore_x_netwm_sync_counter_get(win,
                                                           &cd->sync_counter))
                         ec->netwm.sync.request = 0;
                    }
               }
             free(proto);
          }
        if (ec->netwm.ping && cd->evas_init)
          e_client_ping(ec);
        else
          E_FREE_FUNC(ec->ping_poller, ecore_poller_del);
        ec->icccm.fetch.protocol = 0;
     }
   if (ec->icccm.fetch.transient_for)
     {
        /* TODO: What do to if the transient for isn't mapped yet? */
        E_Client *ec_parent = NULL;

        ec->icccm.transient_for = ecore_x_icccm_transient_for_get(win);
        if (ec->icccm.transient_for)
          ec_parent = _e_comp_x_client_find_by_window(ec->icccm.transient_for);

        e_client_parent_set(ec, ec_parent);
        if (ec->parent && (!e_client_util_ignored_get(ec)) && ec->netwm.state.modal)
          _e_comp_x_client_modal_setup(ec);
        if ((ec_parent) && (cd->stack != ECORE_X_STACK_NONE))
          {
             E_Client *ec2;

             // find last one
             for (ec2 = ec_parent; ec2->stack.next; ec2 = ec2->stack.next);
             ec->stack.prev = ec2;
             ec->stack.next = NULL;
             ec->stack.prev->stack.next = ec;
          }
        ec->icccm.fetch.transient_for = 0;
        rem_change = 1;
     }
   if (ec->icccm.fetch.window_role)
     {
        char *role = ecore_x_icccm_window_role_get(win);
        eina_stringshare_replace(&ec->icccm.window_role, role);
        free(role);

        ec->icccm.fetch.window_role = 0;
        rem_change = 1;
     }
   if (ec->icccm.fetch.icon_name)
     {
        char *icon_name = ecore_x_icccm_icon_name_get(win);
        eina_stringshare_replace(&ec->icccm.icon_name, icon_name);
        free(icon_name);

        ec->hacks.iconic_shading =
          ((ec->netwm.icon_name == ec->netwm.name) &&
           (!e_util_strcmp(ec->netwm.icon_name, "QEMU")));

        ec->icccm.fetch.icon_name = 0;
        rem_change = 1;
     }
   if (ec->netwm.fetch.icon_name)
     {
        char *icon_name;
        ecore_x_netwm_icon_name_get(win, &icon_name);
        eina_stringshare_replace(&ec->netwm.icon_name, icon_name);
        free(icon_name);

        ec->netwm.fetch.icon_name = 0;
        rem_change = 1;
     }
   if (ec->netwm.fetch.opacity)
     {
        unsigned int val;

        if (ecore_x_netwm_opacity_get(win, &val))
          {
             val >>= 24;
             if (ec->netwm.opacity != val)
               {
                  ec->netwm.opacity = val;
                  evas_object_color_set(ec->frame, val, val, val, val);
                  rem_change = 1;
               }
             ec->netwm.fetch.opacity = !ec->netwm.opacity;
          }
        else
          ec->netwm.fetch.opacity = 0;
     }
   if (ec->netwm.fetch.icon)
     {
        _e_comp_x_client_icon_free(ec->netwm.icons, ec->netwm.num_icons);
        ec->netwm.icons = NULL;
        ec->netwm.num_icons = 0;
        if (ecore_x_netwm_icons_get(win,
                                    &ec->netwm.icons,
                                    &ec->netwm.num_icons))
          {
             if (ec->netwm.icons)
               ec->netwm.icons = _e_comp_x_client_icon_deduplicate
                 (ec->netwm.icons, ec->netwm.num_icons);
             ec->changes.icon = 1;
          }
        ec->netwm.fetch.icon = 0;
     }
   if (ec->netwm.fetch.user_time)
     {
        ecore_x_netwm_user_time_get(win, &ec->netwm.user_time);
        ec->netwm.fetch.user_time = 0;
     }
   if (ec->netwm.fetch.strut)
     {
        if (!ecore_x_netwm_strut_partial_get(win,
                                             &ec->netwm.strut.left,
                                             &ec->netwm.strut.right,
                                             &ec->netwm.strut.top,
                                             &ec->netwm.strut.bottom,
                                             &ec->netwm.strut.left_start_y,
                                             &ec->netwm.strut.left_end_y,
                                             &ec->netwm.strut.right_start_y,
                                             &ec->netwm.strut.right_end_y,
                                             &ec->netwm.strut.top_start_x,
                                             &ec->netwm.strut.top_end_x,
                                             &ec->netwm.strut.bottom_start_x,
                                             &ec->netwm.strut.bottom_end_x))
          {
             ecore_x_netwm_strut_get(win,
                                     &ec->netwm.strut.left, &ec->netwm.strut.right,
                                     &ec->netwm.strut.top, &ec->netwm.strut.bottom);

             ec->netwm.strut.left_start_y = 0;
             ec->netwm.strut.left_end_y = 0;
             ec->netwm.strut.right_start_y = 0;
             ec->netwm.strut.right_end_y = 0;
             ec->netwm.strut.top_start_x = 0;
             ec->netwm.strut.top_end_x = 0;
             ec->netwm.strut.bottom_start_x = 0;
             ec->netwm.strut.bottom_end_x = 0;
          }
        ec->netwm.fetch.strut = 0;
     }
   if (ec->qtopia.fetch.soft_menu)
     {
        e_hints_window_qtopia_soft_menu_get(ec);
        ec->qtopia.fetch.soft_menu = 0;
        rem_change = 1;
     }
   if (ec->qtopia.fetch.soft_menus)
     {
        e_hints_window_qtopia_soft_menus_get(ec);
        ec->qtopia.fetch.soft_menus = 0;
        rem_change = 1;
     }
   if (ec->vkbd.fetch.state)
     {
        e_hints_window_virtual_keyboard_state_get(ec);
        ec->vkbd.fetch.state = 0;
        rem_change = 1;
     }
   if (ec->vkbd.fetch.vkbd)
     {
        e_hints_window_virtual_keyboard_get(ec);
        ec->vkbd.fetch.vkbd = 0;
        rem_change = 1;
     }
   if (cd->illume.conformant.fetch.conformant)
     {
        cd->illume.conformant.conformant =
          ecore_x_e_illume_conformant_get(win);
        cd->illume.conformant.fetch.conformant = 0;
     }
   if (cd->illume.quickpanel.fetch.state)
     {
        cd->illume.quickpanel.state =
          ecore_x_e_illume_quickpanel_state_get(win);
        cd->illume.quickpanel.fetch.state = 0;
     }
   if (cd->illume.quickpanel.fetch.quickpanel)
     {
        cd->illume.quickpanel.quickpanel =
          ecore_x_e_illume_quickpanel_get(win);
        cd->illume.quickpanel.fetch.quickpanel = 0;
     }
   if (cd->illume.quickpanel.fetch.priority.major)
     {
        cd->illume.quickpanel.priority.major =
          ecore_x_e_illume_quickpanel_priority_major_get(win);
        cd->illume.quickpanel.fetch.priority.major = 0;
     }
   if (cd->illume.quickpanel.fetch.priority.minor)
     {
        cd->illume.quickpanel.priority.minor =
          ecore_x_e_illume_quickpanel_priority_minor_get(win);
        cd->illume.quickpanel.fetch.priority.minor = 0;
     }
   if (cd->illume.quickpanel.fetch.zone)
     {
        cd->illume.quickpanel.zone =
          ecore_x_e_illume_quickpanel_zone_get(win);
        cd->illume.quickpanel.fetch.zone = 0;
     }
   if (cd->illume.drag.fetch.drag)
     {
        cd->illume.drag.drag =
          ecore_x_e_illume_drag_get(win);
        cd->illume.drag.fetch.drag = 0;
     }
   if (cd->illume.drag.fetch.locked)
     {
        cd->illume.drag.locked =
          ecore_x_e_illume_drag_locked_get(win);
        cd->illume.drag.fetch.locked = 0;
     }
   if (cd->illume.win_state.fetch.state)
     {
        cd->illume.win_state.state =
          ecore_x_e_illume_window_state_get(win);
        cd->illume.win_state.fetch.state = 0;
     }
   if (ec->changes.shape)
     {
        Ecore_X_Rectangle *rects;
        int num;
        Eina_Bool pshaped = ec->shaped;

        ec->changes.shape = 0;
        rects = ecore_x_window_shape_rectangles_get(win, &num);
        if (rects && num)
          {
             int cw = 0, ch = 0;

             /* This doesn't fix the race, but makes it smaller. we detect
              * this and if cw and ch != client w/h then mark this as needing
              * a shape change again to fixup next event loop.
              */
             ecore_x_window_size_get(win, &cw, &ch);
             /* normalize for client window dead zone */
             if (ec->border_size && (num == 1))
               {
                  rects[0].x += ec->border_size;
                  rects[0].y += ec->border_size;
                  rects[0].width -= ec->border_size;
                  rects[0].height -= ec->border_size;
               }
             if ((cw != ec->client.w) || (ch != ec->client.h))
               {
                  ec->changes.shape = 1;
                  EC_CHANGED(ec);
               }
             if ((num == 1) &&
                 (rects[0].x == 0) &&
                 (rects[0].y == 0) &&
                 ((int)rects[0].width == cw) &&
                 ((int)rects[0].height == ch))
               {
                  if (ec->shaped)
                    {
                       ec->shaped = 0;
                       if (cd->reparented && (!ec->bordername))
                         {
                            ec->border.changed = 1;
                            EC_CHANGED(ec);
                         }
                    }
               }
             else
               {
                  if (cd->reparented)
                    {
                       ecore_x_window_shape_rectangles_set(pwin, rects, num);
                       if ((!ec->shaped) && (!ec->bordername))
                         {
                            ec->border.changed = 1;
                            EC_CHANGED(ec);
                         }
                    }
                  else
                    {
                       if (_e_comp_x_client_shape_rects_check(ec, rects, num))
                         e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
                    }
                  ec->shaped = 1;
                  ec->changes.shape_input = 0;
                  E_FREE(ec->shape_input_rects);
                  ec->shape_input_rects_num = 0;
               }
             if (cd->reparented || (!ec->shaped))
               free(rects);
             if (ec->shape_changed)
               e_comp_object_frame_theme_set(ec->frame, E_COMP_OBJECT_FRAME_RESHADOW);
             evas_object_pass_events_set(ec->frame, ec->netwm.type == E_WINDOW_TYPE_DND);
          }
        else
          {
             ec->shaped = 1;
             E_FREE(ec->shape_rects);
             ec->shape_rects_num = 0;
             E_FREE(ec->shape_input_rects);
             ec->shape_input_rects_num = 0;
             e_comp_object_frame_theme_set(ec->frame, E_COMP_OBJECT_FRAME_RESHADOW);
             if (ec->shaped && cd->reparented && (!ec->bordername))
               {
                  ec->border.changed = 1;
                  EC_CHANGED(ec);
               }
             evas_object_pass_events_set(ec->frame, 1);
          }
        if (ec->shaped != pshaped)
          {
             _e_comp_x_client_shape_input_rectangle_set(ec);
             if ((!ec->shaped) && cd->reparented)
               ecore_x_window_shape_mask_set(pwin, 0);
          }
        ec->need_shape_merge = 1;
     }
   if (ec->changes.shape_input)
     {
        Ecore_X_Rectangle *rects;
        Eina_Bool pshaped = ec->shaped_input, changed = EINA_FALSE;
        int num;

        ec->changes.shape_input = 0;
        rects = ecore_x_window_shape_input_rectangles_get(win, &num);
        if (rects && num)
          {
             int cw = 0, ch = 0;

             /* This doesn't fix the race, but makes it smaller. we detect
              * this and if cw and ch != client w/h then mark this as needing
              * a shape change again to fixup next event loop.
              */
             ecore_x_window_size_get(win, &cw, &ch);
             /* normalize for client window dead zone */
             if (ec->border_size && (num == 1))
               {
                  rects[0].x += ec->border_size;
                  rects[0].y += ec->border_size;
                  rects[0].width -= ec->border_size;
                  rects[0].height -= ec->border_size;
               }
             if ((cw != ec->client.w) || (ch != ec->client.h))
               ec->changes.shape_input = 1;
             if (num == 1)
               E_RECTS_CLIP_TO_RECT(rects[0].x, rects[0].y, rects[0].width, rects[0].height, 0, 0, cw, ch);
             if ((num == 1) &&
                 (rects[0].x == 0) &&
                 (rects[0].y == 0) &&
                 ((int)rects[0].width == cw) &&
                 ((int)rects[0].height == ch))
               {
                  ec->shaped_input = 0;
                  free(rects);
               }
             else
               {
                  ec->shaped_input = 1;
                  if (cd->reparented)
                    ecore_x_window_shape_input_rectangles_set(pwin, rects, num);
                  changed = EINA_TRUE;
                  free(ec->shape_input_rects);
                  ec->shape_input_rects = (Eina_Rectangle*)rects;
                  ec->shape_input_rects_num = num;
               }
             evas_object_pass_events_set(ec->frame, ec->netwm.type == E_WINDOW_TYPE_DND);
          }
        else
          {
             ec->shaped_input = 1;
             if (cd->reparented)
               ecore_x_window_shape_input_rectangles_set(pwin, rects, num);
             changed = EINA_TRUE;
             evas_object_pass_events_set(ec->frame, 1);
             free(ec->shape_input_rects);
             ec->shape_input_rects = NULL;
             ec->shape_input_rects_num = 0;
          }
        if (changed || (pshaped != ec->shaped_input))
          {
             ec->need_shape_merge = 1;
             e_comp_shape_queue();
          }
     }
   if (ec->changes.prop || ec->mwm.fetch.hints)
     {
        int pb;

        ec->mwm.exists =
          ecore_x_mwm_hints_get(win,
                                &ec->mwm.func,
                                &ec->mwm.decor,
                                &ec->mwm.input);
        pb = ec->mwm.borderless;
        ec->mwm.borderless = 0;
        if (ec->mwm.exists)
          {
             if ((!(ec->mwm.decor & ECORE_X_MWM_HINT_DECOR_ALL)) &&
                 (!(ec->mwm.decor & ECORE_X_MWM_HINT_DECOR_TITLE)) &&
                 (!(ec->mwm.decor & ECORE_X_MWM_HINT_DECOR_BORDER)))
               ec->mwm.borderless = 1;
          }
        if (ec->mwm.borderless != pb)
          {
             if ((ec->internal || cd->reparented) && ((!ec->lock_border) || (!ec->border.name)))
               {
                  ec->border.changed = 1;
                  EC_CHANGED(ec);
               }
          }
        ec->mwm.fetch.hints = 0;
        rem_change = 1;
     }
   if (ec->e.fetch.video_parent)
     {
        /* unlinking child/parent */
        if (ec->e.state.video_parent_client != NULL)
          {
             ec->e.state.video_parent_client->e.state.video_child =
               eina_list_remove(ec->e.state.video_parent_client->e.state.video_child, ec);
          }

        ecore_x_window_prop_card32_get(win,
                                       ECORE_X_ATOM_E_VIDEO_PARENT,
                                       (Ecore_X_Window*)&ec->e.state.video_parent, 1);

        /* linking child/parent */
        if (ec->e.state.video_parent != 0)
          {
             E_Client *tmp;

             tmp = _e_comp_x_client_find_by_window(ec->e.state.video_parent);
             if (tmp)
               {
                  /* fprintf(stderr, "child added to parent \\o/\n"); */
                  ec->e.state.video_parent_client = tmp;
                  tmp->e.state.video_child = eina_list_append(tmp->e.state.video_child, ec);
                  if (ec->desk != tmp->desk)
                    e_client_desk_set(ec, tmp->desk);
               }
          }

        /* fprintf(stderr, "new parent %x => %p\n", ec->e.state.video_parent, ec->e.state.video_parent_client); */

        if (ec->e.state.video_parent_client) ec->e.fetch.video_parent = 0;
        rem_change = 1;
     }
   if (ec->e.fetch.video_position && ec->e.fetch.video_parent == 0)
     {
        unsigned int xy[2];

        ecore_x_window_prop_card32_get(win,
                                       ECORE_X_ATOM_E_VIDEO_POSITION,
                                       xy, 2);
        ec->e.state.video_position.x = xy[0];
        ec->e.state.video_position.y = xy[1];
        ec->e.state.video_position.updated = 1;
        ec->e.fetch.video_position = 0;
        ec->x = ec->e.state.video_position.x;
        ec->y = ec->e.state.video_position.y;

        fprintf(stderr, "internal position has been updated [%i, %i]\n", ec->e.state.video_position.x, ec->e.state.video_position.y);
     }
   if (ec->changes.prop || ec->netwm.update.state)
     {
        e_hints_window_state_set(ec);
        /* Some stats might change the border, like modal */
        if (((!ec->lock_border) || (!ec->border.name)) &&
            (!(((ec->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN))) &&
            (ec->internal || cd->reparented))
          {
             ec->border.changed = 1;
             EC_CHANGED(ec);
          }
        if (ec->parent)
          {
             if (ec->netwm.state.modal)
               {
                  ec->parent->modal = ec;
                  if (ec->parent->focused)
                    evas_object_focus_set(ec->frame, 1);
               }
          }
        else if (ec->leader)
          {
             if (ec->netwm.state.modal)
               {
                  ec->leader->modal = ec;
                  if (ec->leader->focused)
                    evas_object_focus_set(ec->frame, 1);
                  else
                    {
                       Eina_List *l;
                       E_Client *child;

                       EINA_LIST_FOREACH(ec->leader->group, l, child)
                         {
                            if ((child != ec) && (child->focused))
                              evas_object_focus_set(ec->frame, 1);
                         }
                    }
               }
          }
        ec->netwm.update.state = 0;
     }

   if (cd->fetch_exe)
     {
        E_Exec_Instance *inst;

        if (((!ec->lock_border) || (!ec->border.name)) &&
            (ec->internal || cd->reparented))
          {
             ec->border.changed = 1;
             EC_CHANGED(ec);
          }

        {
           char *str = NULL;

           if ((!ec->internal) &&
               ((ecore_x_netwm_startup_id_get(win, &str) && (str)) ||
               ((ec->icccm.client_leader > 0) &&
                ecore_x_netwm_startup_id_get(ec->icccm.client_leader, &str) && (str)))
               )
             {
                if (!strncmp(str, "E_START|", 8))
                  {
                     int id;

                     id = atoi(str + 8);
                     if (id > 0) ec->netwm.startup_id = id;
                  }
                free(str);
             }
        }
        /* It's ok not to have fetch flag, should only be set on startup
         * and not changed. */
        if (!ecore_x_netwm_pid_get(win, &ec->netwm.pid))
          {
             if (ec->icccm.client_leader)
               {
                  if (!ecore_x_netwm_pid_get(ec->icccm.client_leader, &ec->netwm.pid))
                    ec->netwm.pid = -1;
               }
             else
               ec->netwm.pid = -1;
          }

        if (!e_client_util_ignored_get(ec))
          {
             inst = e_exec_startup_id_pid_instance_find(ec->netwm.startup_id,
                                                        ec->netwm.pid);
             if (inst)
               {
                  Eina_Bool found;

                  if (inst->used == 0)
                    {
                       inst->used++;
                       if ((!ec->remember) || !(ec->remember->apply & E_REMEMBER_APPLY_DESKTOP))
                         {
                            E_Zone *zone;
                            E_Desk *desk;

                            zone = e_comp_zone_number_get(inst->screen);
                            if (zone) e_client_zone_set(ec, zone);
                            desk = e_desk_at_xy_get(ec->zone, inst->desk_x,
                                                    inst->desk_y);
                            if (desk) e_client_desk_set(ec, desk);
                         }
                       if (ec->netwm.pid != ecore_exe_pid_get(inst->exe))
                         {
                            /* most likely what has happened here is that the .desktop launcher
                             * has spawned a process which then created this border, meaning the
                             * E_Exec instance will be deleted in a moment, and we will be unable to track it.
                             * to prevent this, we convert our instance to a phony
                             */
                             inst->phony = 1;
                         }
                    }
                  found = !!inst->clients;
                  e_exec_instance_client_add(inst, ec);
                  if (!found)
                    e_exec_instance_found(inst);
               }

             if (e_config->window_grouping) // FIXME: We may want to make the border "urgent" so that the user knows it appeared.
               {
                  E_Client *ecl = NULL;

                  ecl = ec->parent;
                  if (!ecl)
                    ecl = ec->leader;
                  if (!ecl)
                    {
                       E_Client *child;

                       E_CLIENT_FOREACH(child)
                         {
                            if (child == ec) continue;
                            if (e_object_is_del(E_OBJECT(child))) continue;
                            if ((ec->icccm.client_leader) &&
                                (child->icccm.client_leader ==
                                 ec->icccm.client_leader))
                              {
                                 ecl = child;
                                 break;
                              }
                         }
                    }
                  if (ecl)
                    {
                       if (ecl->zone)
                         e_client_zone_set(ec, ecl->zone);
                       if (ecl->desk)
                         e_client_desk_set(ec, ecl->desk);
                       else
                         e_client_stick(ec);
                    }
               }
          }
        cd->fetch_exe = 0;
     }

   if (need_desk_set)
     {
        E_Desk *desk = NULL;
        const char *p, *p2;
        Eina_Bool set = EINA_FALSE;
        int i;

        /* set desktop using given initial profile */
        p = ec->e.state.profile.set;
        if (p)
          {
             if (!e_util_strcmp(p, ec->desk->window_profile))
               {
                  e_client_desk_window_profile_wait_desk_set(ec, ec->desk);
                  set = EINA_TRUE;
               }
             else
               {
                  desk = e_comp_desk_window_profile_get(p);
                  if (desk)
                    {
                       e_client_desk_set(ec, desk);
                       set = EINA_TRUE;
                    }
               }
          }

        if (!set)
          {
             /* try to find desktop using available profile list */
             for (i = 0; i < ec->e.state.profile.num; i++)
               {
                  p2 = ec->e.state.profile.available_list[i];
                  if (!e_util_strcmp(p2, ec->desk->window_profile))
                    {
                       eina_stringshare_replace(&ec->e.state.profile.set, p2);
                       e_client_desk_window_profile_wait_desk_set(ec, ec->desk);
                       set = EINA_TRUE;
                       break;
                    }
               }
             if (!set)
               {
                  for (i = 0; i < ec->e.state.profile.num; i++)
                    {
                       p2 = ec->e.state.profile.available_list[i];
                       desk = e_comp_desk_window_profile_get(p2);
                       if (desk)
                         {
                            e_client_desk_set(ec, desk);
                            set = EINA_TRUE;
                            break;
                         }
                    }
               }
          }

        if ((!set) && ec->desk)
          {
             eina_stringshare_replace(&ec->e.state.profile.set, ec->desk->window_profile);
             e_client_desk_window_profile_wait_desk_set(ec, ec->desk);
          }
     }

   if (ec->e.state.profile.set)
     {
        printf("E: sent profile set req to 0x%x [%s]\n", win, ec->e.state.profile.set);
        ecore_x_e_window_profile_change_request_send(win,
                                                     ec->e.state.profile.set);
        eina_stringshare_replace(&ec->e.state.profile.wait, ec->e.state.profile.set);
        ec->e.state.profile.wait_for_done = 1;
        eina_stringshare_replace(&ec->e.state.profile.set, NULL);
     }
   if (cd->fetch_gtk_frame_extents)
     {
        unsigned int *extents;
        int count;

        if (ecore_x_window_prop_property_get(win,
                                             ATM_GTK_FRAME_EXTENTS,
                                             ECORE_X_ATOM_CARDINAL, 32,
                                             (void *)(&extents), &count))
          {
             /* _GTK_FRAME_EXTENTS describes a region l/r/t/b pixels
              * from the "window" object in which shadows will be drawn.
              * this area should not be accounted for in sizing or
              * placement calculations.
              */
             e_comp_object_frame_geometry_set(ec->frame,
               -extents[0], -extents[1], -extents[2], -extents[3]);
             if (ec->override &&
                (ec->x == ec->comp_data->initial_attributes.x) &&
                (ec->y == ec->comp_data->initial_attributes.y))
               e_comp_object_frame_xy_adjust(ec->frame, ec->x, ec->y, &ec->x, &ec->y);
             free(extents);
          }
        cd->fetch_gtk_frame_extents = 0;
     }
   ec->changes.prop = 0;
   if (rem_change) e_remember_update(ec);
   if ((!cd->reparented) && (!ec->internal)) ec->changes.border = 0;
   if (ec->changes.icon)
     {
        /* don't create an icon until we need it */
        if (cd->reparented) return;
        cd->change_icon = 1;
        ec->changes.icon = 0;
     }
}

static Eina_Bool
_e_comp_x_first_draw_delay_cb(void *data)
{
   E_Client *ec = data;

   _e_comp_x_client_data_get(ec)->first_draw_delay = NULL;
   if (ec->shape_rects || (!ec->shaped))
     e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
   return EINA_FALSE;
}

static void
_e_comp_x_hook_client_new(void *d EINA_UNUSED, E_Client *ec)
{
   Ecore_X_Window win;
   Eina_List *pending;
   Pending_Configure *pc;

   E_COMP_X_PIXMAP_CHECK;
   win = e_pixmap_window_get(ec->pixmap);
   ec->ignored = e_comp_ignore_win_find(win);

   ec->comp_data = E_NEW(E_Comp_Client_Data, 1);
   ec->comp_data->set_win_type = ec->comp_data->fetch_exe = 1;

   /* FIXME: ewww - round trip */
   ec->argb = ecore_x_window_argb_get(win);
   ec->changes.shape = 1;
   ec->changes.shape_input = 1;

   ec->netwm.type = E_WINDOW_TYPE_UNKNOWN;
   ec->icccm.state = ec->icccm.initial_state = ECORE_X_WINDOW_STATE_HINT_NONE;

   if (!_e_comp_x_client_new_helper(ec)) return;
   ec->ignored |= e_comp->comp_type == E_PIXMAP_TYPE_WL;
   pending = eina_hash_set(pending_configures, &win, NULL);
   if (pending)
     {
        Eina_Bool request_pos = EINA_FALSE;

        /* UGLY: round trip, but necessary to work around bad clients
         * positioning windows anyway AND libreoffice trying to hack
         * getting its windows across multiple screens this way
         * which isn't really right either... */
        ecore_x_icccm_size_pos_hints_get(win,
                                         &request_pos,
                                         &ec->icccm.gravity,
                                         &ec->icccm.min_w,
                                         &ec->icccm.min_h,
                                         &ec->icccm.max_w,
                                         &ec->icccm.max_h,
                                         &ec->icccm.base_w,
                                         &ec->icccm.base_h,
                                         &ec->icccm.step_w,
                                         &ec->icccm.step_h,
                                         &ec->icccm.min_aspect,
                                         &ec->icccm.max_aspect);
        if (request_pos)
          {
             Eina_List *l;
             E_Zone *zone;
             pc = eina_list_last_data_get(pending);
             EINA_LIST_FOREACH(e_comp->zones, l, zone)
               {
                  if (E_INTERSECTS(pc->point.x, pc->point.y, ec->w, ec->h,
                                   zone->x, zone->y, zone->w, zone->h))
                    {
                       e_client_zone_set(ec, zone);
                       break;
                    }
               }
          }
     }
   EINA_LIST_FREE(pending, pc)
     {
        ecore_timer_del(pc->timer);
        free(pc);
     }

   ec->comp_data->first_damage = ec->internal;

   eina_hash_add(clients_win_hash, &win, ec);
   if (!ec->input_only)
     ec->comp_data->first_draw_delay = ecore_timer_loop_add(e_comp_config_get()->first_draw_delay, _e_comp_x_first_draw_delay_cb, ec);
}

static void
_e_comp_x_hook_client_focus_unset_job(void *d EINA_UNUSED)
{
   E_Client *ec = unfocus_job_client;
   unfocus_job = NULL;
   if (!unfocus_job_client) return;
   unfocus_job_client = NULL;
   E_COMP_X_PIXMAP_CHECK;
   _e_comp_x_focus_setup(ec);
   _e_comp_x_focus_check();
}

static void
_e_comp_x_hook_client_focus_unset(void *d EINA_UNUSED, E_Client *ec)
{
   if (focus_job_client == ec)
     {
        focus_job_client = NULL;
        E_FREE_FUNC(focus_job, ecore_job_del);
     }
   if (ec->override) return;
   unfocus_job_client = ec;
   if (!unfocus_job)
     unfocus_job = ecore_job_add(_e_comp_x_hook_client_focus_unset_job, NULL);
}

static void
_e_comp_x_hook_client_focus_set_job(void *d EINA_UNUSED)
{
   E_Client *ec = focus_job_client;
   focus_job = NULL;
   if (!focus_job_client) return;
   focus_job_client = NULL;
   focus_time = ecore_x_current_time_get();
   focus_canvas_time = 0;
   if (!e_client_has_xwindow(ec))
     {
        e_grabinput_focus(e_comp->root, E_FOCUS_METHOD_PASSIVE);
        return;
     }
   _e_comp_x_focus_setdown(ec);

   if ((ec->icccm.take_focus) && (ec->icccm.accepts_focus))
     {
        e_grabinput_focus(e_client_util_win_get(ec), E_FOCUS_METHOD_LOCALLY_ACTIVE);
        /* TODO what if the client didn't take focus ? */
     }
   else if (!ec->icccm.accepts_focus)
     {
        e_grabinput_focus(e_client_util_win_get(ec), E_FOCUS_METHOD_GLOBALLY_ACTIVE);
     }
   else if (!ec->icccm.take_focus)
     {
        e_grabinput_focus(e_client_util_win_get(ec), E_FOCUS_METHOD_PASSIVE);
     }
}

static void
_e_comp_x_hook_client_focus_set(void *d EINA_UNUSED, E_Client *ec)
{
   if (unfocus_job_client == ec)
     {
        unfocus_job_client = NULL;
        E_FREE_FUNC(unfocus_job, ecore_job_del);
     }
   if (ec->override) return;
   focus_job_client = ec;
   if (!focus_job)
     focus_job = ecore_job_add(_e_comp_x_hook_client_focus_set_job, NULL);
}

static void
_e_comp_x_hook_client_redirect(void *d EINA_UNUSED, E_Client *ec)
{
   E_COMP_X_PIXMAP_CHECK;
   if (_e_comp_x_client_data_get(ec)->unredirected_single)
     {
        ecore_x_composite_redirect_window(_e_comp_x_client_window_get(ec), ECORE_X_COMPOSITE_UPDATE_MANUAL);
        _e_comp_x_client_data_get(ec)->unredirected_single = 0;
     }
   else if (e_comp->nocomp)
     {
        /* first window */
        e_comp_x_nocomp_end();
        ecore_x_window_reparent(_e_comp_x_client_window_get(ec), e_comp->root, ec->client.x, ec->client.y);
        _e_comp_x_client_stack(ec);
     }
   if (!_e_comp_x_client_data_get(ec)->damage)
     _e_comp_x_client_damage_add(ec);
}

static void
_e_comp_x_hook_client_unredirect(void *d EINA_UNUSED, E_Client *ec)
{
   Ecore_X_Region parts;

   E_COMP_X_PIXMAP_CHECK;
   eina_hash_del(damages_hash, &_e_comp_x_client_data_get(ec)->damage, ec);
   parts = ecore_x_region_new(NULL, 0);
   ecore_x_damage_subtract(_e_comp_x_client_data_get(ec)->damage, 0, parts);
   ecore_x_region_free(parts);
   ecore_x_damage_free(_e_comp_x_client_data_get(ec)->damage);
   _e_comp_x_client_data_get(ec)->damage = 0;

   if (ec->unredirected_single && (!_e_comp_x_client_data_get(ec)->unredirected_single))
     {
        ecore_x_composite_unredirect_window(_e_comp_x_client_window_get(ec), ECORE_X_COMPOSITE_UPDATE_MANUAL);
        ecore_x_window_reparent(_e_comp_x_client_window_get(ec), e_comp->win, ec->client.x, ec->client.y);
        ecore_x_window_raise(_e_comp_x_client_window_get(ec));
        _e_comp_x_client_data_get(ec)->unredirected_single = 1;
     }
   if (!e_comp->nocomp) return; //wait for it...
   ecore_x_composite_unredirect_subwindows(e_comp->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);
   ecore_x_window_hide(e_comp->win);
}

static Eina_Bool
_e_comp_x_dead_win_timer(void *d)
{
   uint32_t pwin = (uintptr_t)(uintptr_t*)d;

   eina_hash_del_by_key(dead_wins, &pwin);
   return EINA_FALSE;
}

static void
_e_comp_x_hook_client_del(void *d EINA_UNUSED, E_Client *ec)
{
   Ecore_X_Window win, pwin;
   unsigned int visible = 0;
   E_Comp_X_Client_Data *cd;

   E_COMP_X_PIXMAP_CHECK;
   win = e_client_util_win_get(ec);
   pwin = e_client_util_pwin_get(ec);
   cd = _e_comp_x_client_data_get(ec);

   if (mouse_client == ec) mouse_client = NULL;
   if (focus_job_client == ec) focus_job_client = NULL;
   if (unfocus_job_client == ec) unfocus_job_client = NULL;
   if ((!stopping) && cd && (!cd->deleted))
     ecore_x_window_prop_card32_set(win, E_ATOM_MANAGED, &visible, 1);
   if (stopping && ec->iconic)
     {
        e_hints_window_iconic_set(ec);
        e_hints_window_state_set(ec);
     }
   if ((!ec->already_unparented) && cd && cd->reparented)
     {
        _e_comp_x_focus_setdown(ec);
        e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, pwin);
        e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, pwin);
        if (!cd->deleted)
          {
             if (stopping)
               {
                  ecore_x_window_reparent(win, e_comp->root,
                                          ec->client.x, ec->client.y);
                  ecore_x_window_configure(win,
                                           ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
                                           ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
                                           0, 0, 0, 0, 0, pwin,
                                           ECORE_X_WINDOW_STACK_BELOW);
               }

             else
               /* put the window back where we found it to prevent annoying dancing windows */
               ecore_x_window_reparent(win, e_comp->root,
                                       cd->initial_attributes.x,
                                       cd->initial_attributes.y);
             if (!ec->internal)
               ecore_x_window_save_set_del(win);
          }
        e_pixmap_alias(NULL, E_PIXMAP_TYPE_X, pwin);
     }
   ec->already_unparented = 1;
   if (cd)
     eina_hash_del_by_key(clients_win_hash, &win);
   if (cd && cd->damage)
     {
        eina_hash_del(damages_hash, &cd->damage, ec);
        ecore_x_damage_free(cd->damage);
        cd->damage = 0;
     }
   if (cd && cd->reparented)
     {
        eina_hash_del_by_key(clients_win_hash, &pwin);
        e_pixmap_parent_window_set(e_comp_x_client_pixmap_get(ec), 0);
        ecore_x_window_free(pwin);
        eina_hash_add(dead_wins, &pwin, (void*)1);
        ecore_timer_add(0.5, _e_comp_x_dead_win_timer, (uintptr_t*)(uintptr_t)pwin);
     }

   if (ec->hacks.mapping_change)
     _e_comp_x_mapping_change_disabled--;
   if (ec->parent && (ec->parent->modal == ec))
     {
        E_Comp_X_Client_Data *pcd;

        pcd = _e_comp_x_client_data_get(ec->parent);
        if (pcd->lock_win)
          {
             eina_hash_del_by_key(clients_win_hash, &pcd->lock_win);
             ecore_x_window_hide(pcd->lock_win);
             ecore_x_window_free(pcd->lock_win);
             pcd->lock_win = 0;
          }
        ec->parent->lock_close = 0;
        ec->parent->modal = NULL;
     }
   if (cd)
     E_FREE_FUNC(cd->first_draw_delay, ecore_timer_del);
#ifdef HAVE_WAYLAND
   if (e_comp->comp_type == E_PIXMAP_TYPE_WL)
     {
        if (e_pixmap_is_x(ec->pixmap))
          e_comp_wl_client_xwayland_setup(ec, NULL, NULL);
        else
          {
             e_pixmap_alias(NULL, E_PIXMAP_TYPE_X, win);
             free(cd);
             e_pixmap_free(e_comp_x_client_pixmap_get(ec));
          }
     }
   else
#endif
     {
        if (e_pixmap_free(ec->pixmap))
          e_pixmap_client_set(ec->pixmap, NULL);
        ec->pixmap = NULL;
     }
   if (ec->netwm.icons)
     {
        _e_comp_x_client_icon_free(ec->netwm.icons, ec->netwm.num_icons);
        ec->netwm.icons = NULL;
        ec->netwm.num_icons = 0;
     }

   if (post_clients)
     post_clients = eina_list_remove(post_clients, ec);

   _e_comp_x_focus_check();
}

static void
_e_comp_x_hook_client_move_end(void *d EINA_UNUSED, E_Client *ec)
{
   E_COMP_X_PIXMAP_CHECK;
   _e_comp_x_client_data_get(ec)->moving = 0;
   if (!_e_comp_x_client_data_get(ec)->move_counter) return;
   _e_comp_x_client_data_get(ec)->move_counter = 0;
   ec->post_move = 1;
   _e_comp_x_post_client_idler_add(ec);
}

static void
_e_comp_x_hook_client_move_begin(void *d EINA_UNUSED, E_Client *ec)
{
   E_COMP_X_PIXMAP_CHECK;
   _e_comp_x_client_data_get(ec)->moving = 1;
}

static void
_e_comp_x_hook_client_resize_end(void *d EINA_UNUSED, E_Client *ec)
{
   E_COMP_X_PIXMAP_CHECK;
   if (_e_comp_x_client_data_get(ec)->alarm)
     {
        eina_hash_del_by_key(alarm_hash, &_e_comp_x_client_data_get(ec)->alarm);
        ecore_x_sync_alarm_free(_e_comp_x_client_data_get(ec)->alarm);
        _e_comp_x_client_data_get(ec)->alarm = 0;
     }
   ec->netwm.sync.alarm = 0;
   /* resize to last geometry if sync alarm for it was not yet handled */
   if (ec->pending_resize)
     {
        EC_CHANGED(ec);
        ec->changes.pos = 1;
        ec->changes.size = 1;
     }

   E_FREE_LIST(ec->pending_resize, free);
}

static void
_e_comp_x_hook_client_resize_begin(void *d EINA_UNUSED, E_Client *ec)
{
   E_COMP_X_PIXMAP_CHECK;
   if (!ec->netwm.sync.request) return;
   if (e_comp->comp_type == E_PIXMAP_TYPE_X)
     {
        _e_comp_x_client_data_get(ec)->alarm = ecore_x_sync_alarm_new(_e_comp_x_client_data_get(ec)->sync_counter);
        eina_hash_add(alarm_hash, &_e_comp_x_client_data_get(ec)->alarm, ec);
     }
   ec->netwm.sync.alarm = ec->netwm.sync.serial = 1;
   ec->netwm.sync.wait = 0;
   ec->netwm.sync.send_time = ecore_loop_time_get();
}

static void
_e_comp_x_hook_client_desk_set(void *d EINA_UNUSED, E_Client *ec)
{
   unsigned int num[2];
   int x, y;

   E_COMP_X_PIXMAP_CHECK;
   e_desk_xy_get(ec->desk, &x, &y);
   num[0] = x, num[1] = y;
   ecore_x_window_prop_card32_set(e_client_util_win_get(ec), E_ATOM_DESK, num, 2);
}

static Eina_Bool
_e_comp_x_cb_ping(void *data EINA_UNUSED, int ev_type EINA_UNUSED, Ecore_X_Event_Ping *ev)
{
   E_Client *ec;

   ec = _e_comp_x_client_find_by_window(ev->event_win);
   if (ec) ec->ping_ok = 1;
   return ECORE_CALLBACK_PASS_ON;
}

static void
_e_comp_pointer_grab(void)
{
   if (_e_comp_x_suspend_grabbed) ecore_x_window_free(_e_comp_x_suspend_grabbed);
   _e_comp_x_suspend_grabbed = ecore_x_window_input_new(e_comp->root, 0, 0, 1, 1);
   ecore_x_window_show(_e_comp_x_suspend_grabbed);
   if (!e_grabinput_get(_e_comp_x_suspend_grabbed, 0, 0))
     {
        ecore_x_window_free(_e_comp_x_suspend_grabbed);
        _e_comp_x_suspend_grabbed = 0;
     }
}

static void
_e_comp_pointer_ungrab(void)
{
   if (!_e_comp_x_suspend_grabbed) return;
   e_grabinput_release(_e_comp_x_suspend_grabbed, 0);
   ecore_x_window_free(_e_comp_x_suspend_grabbed);
   _e_comp_x_suspend_grabbed = 0;
}

static void
_e_comp_cb_pointer_suspend_resume_done(void *data, Evas_Object *obj, const char *emission, const char *source)
{
   edje_object_signal_callback_del(obj, emission, source,
                                   _e_comp_cb_pointer_suspend_resume_done);
   if (!data)
     {
        _e_comp_pointer_ungrab();
        e_pointer_grab_set(e_comp->pointer, EINA_FALSE);
     }
}

EINTERN Eina_Bool
_e_comp_x_screensaver_on()
{
   const char *s;

   if ((!e_comp->pointer) || (!e_comp->pointer->o_ptr)) return ECORE_CALLBACK_RENEW;
   s = edje_object_data_get(e_comp->pointer->o_ptr, "can_suspend");

   if ((s) && (atoi(s) == 1))
     {
        if (!e_desklock_state_get())
          {
             _e_comp_pointer_ungrab();
             e_pointer_grab_set(e_comp->pointer, EINA_FALSE);
             e_pointer_grab_set(e_comp->pointer, EINA_TRUE);
             _e_comp_pointer_grab();
             if (!_e_comp_x_suspend_grabbed) return ECORE_CALLBACK_RENEW;
          }
        edje_object_signal_callback_del(e_comp->pointer->o_ptr,
                                        "e,state,mouse,suspend,done", "e",
                                        _e_comp_cb_pointer_suspend_resume_done);
        edje_object_signal_callback_del(e_comp->pointer->o_ptr,
                                        "e,state,mouse,resume,done", "e",
                                        _e_comp_cb_pointer_suspend_resume_done);
        edje_object_signal_callback_add(e_comp->pointer->o_ptr,
                                        "e,state,mouse,suspend,done",
                                        "e",
                                        _e_comp_cb_pointer_suspend_resume_done,
                                        e_comp);
        edje_object_signal_emit(e_comp->pointer->o_ptr,
                                "e,state,mouse,suspend", "e");
     }
   return ECORE_CALLBACK_RENEW;
}

EINTERN Eina_Bool
_e_comp_x_screensaver_off()
{
   const char *s;

   _e_comp_pointer_ungrab();
   e_pointer_grab_set(e_comp->pointer, EINA_FALSE);
   if ((!e_comp->pointer) || (!e_comp->pointer->o_ptr)) return ECORE_CALLBACK_RENEW;
   s = edje_object_data_get(e_comp->pointer->o_ptr, "can_suspend");

   if ((s) && (atoi(s) == 1))
     {
        if (!e_desklock_state_get())
          {
             e_pointer_grab_set(e_comp->pointer, EINA_TRUE);
             _e_comp_pointer_grab();
             if (!_e_comp_x_suspend_grabbed) return ECORE_CALLBACK_RENEW;
          }
        edje_object_signal_callback_del(e_comp->pointer->o_ptr,
                                        "e,state,mouse,suspend,done", "e",
                                        _e_comp_cb_pointer_suspend_resume_done);
        edje_object_signal_callback_del(e_comp->pointer->o_ptr,
                                        "e,state,mouse,resume,done", "e",
                                        _e_comp_cb_pointer_suspend_resume_done);
        edje_object_signal_callback_add(e_comp->pointer->o_ptr,
                                        "e,state,mouse,resume,done",
                                        "e",
                                        _e_comp_cb_pointer_suspend_resume_done,
                                        NULL);
        edje_object_signal_emit(e_comp->pointer->o_ptr,
                                "e,state,mouse,resume", "e");
     }
   return ECORE_CALLBACK_RENEW;
}

static Ecore_Timer *screensaver_eval_timer = NULL;
static Eina_Bool saver_on = EINA_FALSE;

static Eina_Bool
_e_comp_x_screensaver_eval_cb(void *d EINA_UNUSED)
{
   e_screensaver_eval(saver_on);
   screensaver_eval_timer = NULL;
   return EINA_FALSE;
}

static Eina_Bool
_e_comp_x_screensaver_notify_cb(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_X_Event_Screensaver_Notify *ev)
{
   if (e_screensaver_ignore_get()) return ECORE_CALLBACK_PASS_ON;
   if ((ev->on) && (!saver_on))
     {
        saver_on = EINA_TRUE;
        E_FREE_FUNC(screensaver_eval_timer, ecore_timer_del);
        screensaver_eval_timer = ecore_timer_loop_add(0.3, _e_comp_x_screensaver_eval_cb, NULL);
     }
   else if ((!ev->on) && (saver_on))
     {
        saver_on = EINA_FALSE;
        E_FREE_FUNC(screensaver_eval_timer, ecore_timer_del);
        screensaver_eval_timer = ecore_timer_loop_add(0.3, _e_comp_x_screensaver_eval_cb, NULL);
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_comp_x_backlight_notify_cb(void *data EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Randr_Output_Property_Notify *ev)
{
   if (ev->property != backlight_atom) return ECORE_CALLBACK_RENEW;
   e_backlight_update();
   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_cb_frame_extents_request(void *data EINA_UNUSED, int ev_type EINA_UNUSED, Ecore_X_Event_Frame_Extents_Request *ev)
{
   Ecore_X_Window_Type type;
   Ecore_X_MWM_Hint_Decor decor;
   Ecore_X_Window_State *state;
   Ecore_X_Window win;
   Frame_Extents *extents;
   const char *border, *sig, *key;
   int ok;
   unsigned int i, num;

   win = ecore_x_window_parent_get(ev->win);
   if (win != e_comp->root) return ECORE_CALLBACK_PASS_ON;

   /* TODO:
    * * We need to check if we remember this window, and border locking is set
    */
   border = "default";
   key = border;
   ok = ecore_x_mwm_hints_get(ev->win, NULL, &decor, NULL);
   if ((ok) &&
       (!(decor & ECORE_X_MWM_HINT_DECOR_ALL)) &&
       (!(decor & ECORE_X_MWM_HINT_DECOR_TITLE)) &&
       (!(decor & ECORE_X_MWM_HINT_DECOR_BORDER)))
     {
        border = "borderless";
        key = border;
     }

   ok = ecore_x_netwm_window_type_get(ev->win, &type);
   if ((ok) &&
       ((type == ECORE_X_WINDOW_TYPE_DESKTOP) ||
        (type == ECORE_X_WINDOW_TYPE_DOCK)))
     {
        border = "borderless";
        key = border;
     }

   sig = NULL;
   ecore_x_netwm_window_state_get(ev->win, &state, &num);
   if (state)
     {
        int maximized = 0;

        for (i = 0; i < num; i++)
          {
             switch (state[i])
               {
                case ECORE_X_WINDOW_STATE_MAXIMIZED_VERT:
                  maximized++;
                  break;

                case ECORE_X_WINDOW_STATE_MAXIMIZED_HORZ:
                  maximized++;
                  break;

                case ECORE_X_WINDOW_STATE_FULLSCREEN:
                  border = "borderless";
                  key = border;
                  break;

                case ECORE_X_WINDOW_STATE_SHADED:
                case ECORE_X_WINDOW_STATE_SKIP_TASKBAR:
                case ECORE_X_WINDOW_STATE_SKIP_PAGER:
                case ECORE_X_WINDOW_STATE_HIDDEN:
                case ECORE_X_WINDOW_STATE_ICONIFIED:
                case ECORE_X_WINDOW_STATE_MODAL:
                case ECORE_X_WINDOW_STATE_STICKY:
                case ECORE_X_WINDOW_STATE_ABOVE:
                case ECORE_X_WINDOW_STATE_BELOW:
                case ECORE_X_WINDOW_STATE_DEMANDS_ATTENTION:
                case ECORE_X_WINDOW_STATE_UNKNOWN:
                  break;
               }
          }
        if ((maximized == 2) &&
            (e_config->maximize_policy == E_MAXIMIZE_FULLSCREEN))
          {
             sig = "ev,action,maximize,fullscreen";
             key = "maximize,fullscreen";
          }
        free(state);
     }

   extents = eina_hash_find(frame_extents, key);
   if (!extents)
     {
        Evas_Object *o;
        char buf[1024];

        extents = E_NEW(Frame_Extents, 1);
        if (!extents) return ECORE_CALLBACK_RENEW;

        o = edje_object_add(e_comp->evas);
        snprintf(buf, sizeof(buf), "ev/widgets/border/%s/border", border);
        ok = e_theme_edje_object_set(o, "base/theme/borders", buf);
        if (ok)
          {
             Evas_Coord x, y, w, h;

             if (sig)
               {
                  edje_object_signal_emit(o, sig, "ev");
                  edje_object_message_signal_process(o);
               }

             evas_object_resize(o, 1000, 1000);
             edje_object_calc_force(o);
             edje_object_part_geometry_get(o, "ev.swallow.client",
                                           &x, &y, &w, &h);
             extents->l = x;
             extents->r = 1000 - (x + w);
             extents->t = y;
             extents->b = 1000 - (y + h);
          }
        else
          {
             extents->l = 0;
             extents->r = 0;
             extents->t = 0;
             extents->b = 0;
          }
        evas_object_del(o);
        eina_hash_add(frame_extents, key, extents);
     }

   if (extents)
     ecore_x_netwm_frame_size_set(ev->win, extents->l, extents->r, extents->t, extents->b);

   return ECORE_CALLBACK_RENEW;
}

static Eina_Bool
_e_comp_x_randr_change(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event_info EINA_UNUSED)
{
   E_Client *ec;

   ecore_x_netwm_desk_size_set(e_comp->root, e_comp->w, e_comp->h);
   E_CLIENT_FOREACH(ec)
     {
        if (!e_client_util_ignored_get(ec))
          _e_comp_x_client_zone_geometry_set(ec);
     }
   return ECORE_CALLBACK_RENEW;
}

static void
_e_comp_x_del(E_Comp *c)
{
   unsigned int i;

   if (!e_comp_wl)
     ecore_x_window_key_ungrab(c->root, "F", ECORE_EVENT_MODIFIER_SHIFT |
                               ECORE_EVENT_MODIFIER_CTRL |
                               ECORE_EVENT_MODIFIER_ALT, 0);
   if (ecore_x_display_get())
     {
        if (c->grabbed)
          {
             c->grabbed = 0;
             ecore_x_ungrab();
             ecore_x_sync();
          }

        if (restart)
          {
             Ecore_X_Atom a;
             Ecore_X_Window blackwin;

             a = ecore_x_atom_get("E_COMP_BLACK_WIN");
             blackwin = ecore_x_window_permanent_new(c->root, a);
             ecore_x_window_ignore_set(blackwin, 1);
             ecore_x_window_override_set(blackwin, EINA_TRUE);
             ecore_x_window_move_resize(blackwin, 0, 0, e_comp->w, e_comp->h);
             ecore_x_window_background_color_set(blackwin, 0, 0, 0);
             ecore_x_window_show(blackwin);
             ecore_x_window_prop_window_set(c->root, a, &blackwin, 1);
             ecore_x_sync();
          }

        for (i = e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); i <= e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); i++)
          ecore_x_window_free(c->layers[i].win);

        ecore_x_composite_unredirect_subwindows
          (c->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);
        if (c->block_win) ecore_x_window_free(c->block_win);
        ecore_x_composite_render_window_disable(c->win);
        e_alert_composite_win(c->root, 0);

        ecore_x_window_free(c->cm_selection);
        ecore_x_screen_is_composited_set(0, 0);
     }

   eina_list_free(c->x_comp_data->retry_clients);
   ecore_timer_del(c->x_comp_data->retry_timer);
   E_FREE_FUNC(mouse_in_job, ecore_job_del);
   E_FREE_FUNC(focus_job, ecore_job_del);
   E_FREE_FUNC(unfocus_job, ecore_job_del);
   free(c->x_comp_data);
   c->x_comp_data = e_comp_x = NULL;
   c->root = 0;
}

static void
_e_comp_x_manage_windows(void)
{
   Ecore_X_Window *windows;
   int wnum;
   int i;
   const char *atom_names[] =
   {
      "_XEMBED_INFO",
      "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
      "KWM_DOCKWINDOW"
   };
   Ecore_X_Atom atoms[3];
   Ecore_X_Atom atom_xmbed, atom_kde_netwm_systray, atom_kwm_dockwindow;
   int count;

   /* a manager is designated for each root. lets get all the windows in
      the managers root */
   windows = ecore_x_window_children_get(e_comp->root, &wnum);
   if (!windows) return;

   ecore_x_atoms_get(atom_names, 3, atoms);
   atom_xmbed = atoms[0];
   atom_kde_netwm_systray = atoms[1];
   atom_kwm_dockwindow = atoms[2];
   for (i = 0; i < wnum; i++)
     {
        unsigned int ret_val;
        unsigned char *data = NULL;
        int ret;
        E_Client *ec = NULL;

        if ((e_comp->win == windows[i]) || (e_comp->ee_win == windows[i]) ||
            (e_comp->root == windows[i]) || (e_comp->cm_selection == windows[i]))
          continue;
        if (_e_comp_x_client_find_by_window(windows[i]))
          continue;
        if (!ecore_x_window_prop_property_get(windows[i],
                                              atom_kde_netwm_systray,
                                              atom_xmbed, 32,
                                              &data, &count))
          data = NULL;

        if (!data)
          {
             if (!ecore_x_window_prop_property_get(windows[i],
                                                   atom_kwm_dockwindow,
                                                   atom_kwm_dockwindow, 32,
                                                   &data, &count))
               data = NULL;
          }
        if (data)
          {
             E_FREE(data);
             continue;
          }
        ret = ecore_x_window_prop_card32_get(windows[i],
                                             E_ATOM_MANAGED,
                                             &ret_val, 1);

        ec = _e_comp_x_client_new(windows[i], (ret > -1) && (ret_val == 1));
        if (ec && (!_e_comp_x_client_data_get(ec)->initial_attributes.visible))
          {
             DELD(ec, 3);
             E_FREE_FUNC(ec, e_object_del);
          }
        if (ec)
          {
             if (ec->override || (!ec->icccm.fetch.hints))
               {
                  _e_comp_x_client_evas_init(ec);
                  if (!ec->input_only)
                    _e_comp_x_client_damage_add(ec);
                  e_pixmap_usable_set(ec->pixmap, 1);
                  _e_comp_x_client_data_get(ec)->first_map = 1;
                  evas_object_geometry_set(ec->frame, ec->client.x, ec->client.y, ec->client.w, ec->client.h);
               }
             ec->ignore_first_unmap = 1;
             if (ec->override || (!ec->icccm.fetch.hints))
               evas_object_show(ec->frame);
             _e_comp_x_client_stack(ec);
          }
     }
   free(windows);
}

static void
_e_comp_x_bindings_grab_cb(void)
{
   Eina_List *l;
   E_Client *ec;

   EINA_LIST_FOREACH(e_comp->clients, l, ec)
     {
        if (e_client_util_ignored_get(ec)) continue;
        _e_comp_x_focus_init(ec);
        if (ec->focused)
          _e_comp_x_focus_setdown(ec);
        else
          {
             _e_comp_x_focus_setup(ec);
             e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
             e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
          }
     }
}

static void
_e_comp_x_bindings_ungrab_cb(void)
{
   Eina_List *l;
   E_Client *ec;

   EINA_LIST_FOREACH(e_comp->clients, l, ec)
     {
        Ecore_X_Window win;

        if (e_client_util_ignored_get(ec)) continue;
        win = e_client_util_win_get(ec);
        ecore_x_window_button_ungrab(win, 1, 0, 1);
        ecore_x_window_button_ungrab(win, 2, 0, 1);
        ecore_x_window_button_ungrab(win, 3, 0, 1);
        e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
        e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, e_client_util_pwin_get(ec));
        _e_comp_x_client_data_get(ec)->button_grabbed = 0;
     }
}

static void
_e_comp_x_desklock_hide(void)
{
   e_comp_ungrab_input(1, 1);

   if (e_comp_x->lock_grab_break_wnd)
     ecore_x_window_show(e_comp_x->lock_grab_break_wnd);
   e_comp_x->lock_grab_break_wnd = 0;
   e_comp_override_del();
}

static Eina_Bool
_e_comp_x_desklock_show(void)
{
   if (!e_comp_grab_input(1, 1))
     {
        Ecore_X_Window *windows;
        int wnum, i;

        windows = ecore_x_window_children_get(e_comp->root, &wnum);
        if (!windows) goto fail;
        for (i = 0; i < wnum; i++)
          {
             Ecore_X_Window_Attributes att;

             memset(&att, 0, sizeof(Ecore_X_Window_Attributes));
             ecore_x_window_attributes_get(windows[i], &att);
             if (att.visible)
               {
                  ecore_x_window_hide(windows[i]);
                  if (e_comp_grab_input(1, 1))
                    {
                       e_comp_x->lock_grab_break_wnd = windows[i];
                       free(windows);
                       goto works;
                    }
                  ecore_x_window_show(windows[i]);
               }
          }
        free(windows);
     }
works:
   e_comp_override_add();

   return EINA_TRUE;
fail:
   /* everything failed - can't lock */
   e_util_dialog_show(_("Lock Failed"),
                      _("Locking the desktop failed because some application<ps/>"
                        "has grabbed either the keyboard or the mouse or both<ps/>"
                        "and their grab is unable to be broken."));
   return EINA_FALSE;
}

static Eina_Bool
_e_comp_x_setup(Ecore_X_Window root, int w, int h)
{
   Ecore_X_Window_Attributes att;
   Ecore_X_Atom a;
   Ecore_X_Window blackwin = 0;
   Eina_Bool res;
   unsigned int i;

   res = ecore_x_screen_is_composited(0);
   if (res)
     {
        ERR(_("Another compositor is already running on your display server."));
        return EINA_FALSE;
     }
   if (!ecore_x_window_manage(root)) return EINA_FALSE;

   a = ecore_x_atom_get("E_COMP_BLACK_WIN");
   if (ecore_x_window_prop_window_get(root, a, &blackwin, 1) == 1)
     {
        ecore_x_window_ignore_set(blackwin, 1);
     }

   e_comp_x = e_comp->x_comp_data = E_NEW(E_Comp_X_Data, 1);
   ecore_x_e_window_profile_supported_set(root, EINA_TRUE);
   e_comp->cm_selection = ecore_x_window_input_new(root, 0, 0, 1, 1);
   if (!e_comp->cm_selection) return EINA_FALSE;
   ecore_x_icccm_name_class_set(e_comp->cm_selection, "comp", "cm_selection");
   e_comp_ignore_win_add(E_PIXMAP_TYPE_X, e_comp->cm_selection);
   e_hints_init(root, e_comp->cm_selection);
   ecore_x_window_background_color_set(root, 0, 0, 0);
   ecore_x_screen_is_composited_set(0, e_comp->cm_selection);
   ecore_x_selection_owner_set(e_comp->cm_selection, ecore_x_atom_get("WM_S0"), ecore_x_current_time_get());

   e_comp->win = ecore_x_composite_render_window_enable(root);
   if (!e_comp->win)
     {
        ERR(_("Your display server does not support the compositor overlay window.\n"
              "This is needed for Enlightenment to function."));
        return EINA_FALSE;
     }
   e_comp->root = root;

   memset((&att), 0, sizeof(Ecore_X_Window_Attributes));
   ecore_x_window_attributes_get(e_comp->win, &att);

   if ((att.depth != 24) && (att.depth != 32))
     {
        /*
                  e_util_dialog_internal
                  (_("Compositor Error"), _("Your screen is not in 24/32bit display mode.<ps/>"
                  "This is required to be your default depth<ps/>"
                  "setting for the compositor to work properly."));
                  ecore_x_composite_render_window_disable(e_comp->win);
                  free(e_comp);
                  return NULL;
         */
     }
   e_alert_composite_win(root, e_comp->win);

   if (!e_comp->ee)
     {
        if (!e_comp_x_randr_canvas_new(e_comp->win, w, h))
          ecore_job_add(_e_comp_x_add_fail_job, NULL);
     }

   ecore_x_composite_redirect_subwindows(root, ECORE_X_COMPOSITE_UPDATE_MANUAL);

   ecore_evas_data_set(e_comp->ee, "comp", e_comp);
   e_comp->bindings_grab_cb = _e_comp_x_bindings_grab_cb;
   e_comp->bindings_ungrab_cb = _e_comp_x_bindings_ungrab_cb;

   if (e_comp->comp_type == E_PIXMAP_TYPE_NONE)
     {
        if (!e_comp_canvas_init(w, h)) return EINA_FALSE;
        ecore_x_window_key_grab(root, "F", ECORE_EVENT_MODIFIER_SHIFT |
                        ECORE_EVENT_MODIFIER_CTRL |
                        ECORE_EVENT_MODIFIER_ALT, 0);
     }

   if (e_comp->comp_type == E_PIXMAP_TYPE_X)
     e_grabinput_focus(e_comp->ee_win, E_FOCUS_METHOD_PASSIVE);
   else
     e_grabinput_focus(e_comp->root, E_FOCUS_METHOD_PASSIVE);

   /* init layers */
   for (i = e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); i <= e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO); i++)
     {
        char buf[64];
        E_Client *ec;

        e_comp->layers[i].win = ecore_x_window_input_new(root, 0, 0, 1, 1);
        ecore_x_window_show(e_comp->layers[i].win);
        snprintf(buf, sizeof(buf), "%d", e_comp_canvas_layer_map_to(i));
        ecore_x_icccm_name_class_set(e_comp->layers[i].win, buf, "e_layer_win");

        if (i >= e_comp_canvas_layer_map(E_LAYER_CLIENT_ABOVE))
          ecore_x_window_raise(e_comp->layers[i].win);
        ec = _e_comp_x_client_new(e_comp->layers[i].win, 0);
        if (!ec) continue;
        evas_object_name_set(ec->frame, "layer_obj");
        ec->lock_client_stacking = 1;
        ec->internal = 1;
        ec->visible = 1;
        evas_object_del(e_comp->layers[i].obj);
        e_comp->layers[i].obj = ec->frame;
        evas_object_layer_set(ec->frame, e_comp_canvas_layer_map_to(i));
        evas_object_pass_events_set(ec->frame, 1);
        evas_object_show(ec->frame);
     }
   for (i = e_comp_canvas_layer_map(E_LAYER_CLIENT_NORMAL); i >= e_comp_canvas_layer_map(E_LAYER_CLIENT_DESKTOP); i--)
     ecore_x_window_lower(e_comp->layers[i].win);

   ecore_evas_lower(e_comp->ee);
   if (e_comp->comp_type == E_PIXMAP_TYPE_NONE)
     {
        e_comp->pointer = e_pointer_window_new(e_comp->root, 0);
        e_comp->pointer->color = ecore_x_cursor_color_supported_get();
        e_pointer_type_push(e_comp->pointer, e_comp->pointer, "default");
        ecore_x_icccm_state_set(ecore_evas_window_get(e_comp->ee), ECORE_X_WINDOW_STATE_HINT_NORMAL);
        e_startup();
     }
   else
     e_pointer_window_add(e_comp->pointer, e_comp->root);
   _e_comp_x_manage_windows();

   if (blackwin)
     {
        ecore_x_window_free(blackwin);
        ecore_x_window_prop_property_del(root, a);
        ecore_x_window_ignore_set(blackwin, 0);
     }

   return !!e_comp->canvas->resize_object;
}

static Eina_Bool
_e_comp_x_screens_setup(void)
{
   Ecore_X_Window root;
   int rw, rh;
   Eina_Bool ret;

   if (e_comp->comp_type == E_PIXMAP_TYPE_NONE)
     {
        e_comp_x_randr_screen_iface_set();
        if (!e_randr2_init()) return 0;
     }
   root = ecore_x_window_root_first_get();
   if (!root)
     {
        e_error_message_show("X reports there are no root windows!\n");
        return 0;
     }
   ecore_x_window_size_get(root, &rw, &rh);
   if (e_comp->comp_type == E_PIXMAP_TYPE_NONE)
     e_randr2_screens_setup(rw, rh);
   ret = _e_comp_x_setup(root, rw, rh);
   if (ret) return EINA_TRUE;
   e_randr2_shutdown();
   e_xinerama_screens_set(NULL);
   e_comp->screen = NULL;
   return EINA_FALSE;
}

E_API Eina_Bool
e_comp_x_init(void)
{
   Eina_List *h = NULL;
   if (!ecore_x_init(NULL))
     {
        fprintf(stderr, _("Enlightenment cannot initialize X Connection...\n"));
        return EINA_FALSE;
     }

   if (e_comp->comp_type == E_PIXMAP_TYPE_X)
     ecore_x_io_error_handler_set(_e_main_cb_x_fatal, NULL);

   if (!ecore_x_composite_query())
     {
        _e_comp_x_print_win(0);
        ecore_x_shutdown();
        e_error_message_show
          (_("Your display server does not support XComposite, "
             "or Ecore-X was built without XComposite support. "
             "Note that for composite support you will also need "
             "XRender and XFixes support in X11 and Ecore."));
        return EINA_FALSE;
     }
   if (!ecore_x_damage_query())
     {
        e_error_message_show
          (_("Your display server does not support XDamage "
             "or Ecore was built without XDamage support."));
        return EINA_FALSE;
     }
   if (!e_atoms_init()) return 0;

   clients_win_hash = eina_hash_int32_new(NULL);
   damages_hash = eina_hash_int32_new(NULL);
   alarm_hash = eina_hash_int32_new(NULL);
   dead_wins = eina_hash_int32_new(NULL);
   pending_configures = eina_hash_int32_new(NULL);
   frame_extents = eina_hash_string_superfast_new(free);

   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_DESK_SET, _e_comp_x_hook_client_desk_set, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_RESIZE_BEGIN, _e_comp_x_hook_client_resize_begin, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_RESIZE_END, _e_comp_x_hook_client_resize_end, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_MOVE_BEGIN, _e_comp_x_hook_client_move_begin, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_MOVE_END, _e_comp_x_hook_client_move_end, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_DEL, _e_comp_x_hook_client_del, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_NEW_CLIENT, _e_comp_x_hook_client_new, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_EVAL_FETCH, _e_comp_x_hook_client_fetch, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_EVAL_PRE_FRAME_ASSIGN, _e_comp_x_hook_client_pre_frame_assign, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_UNREDIRECT, _e_comp_x_hook_client_unredirect, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_REDIRECT, _e_comp_x_hook_client_redirect, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_EVAL_POST_NEW_CLIENT, _e_comp_x_hook_client_post_new_client, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_FOCUS_SET, _e_comp_x_hook_client_focus_set, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_FOCUS_UNSET, _e_comp_x_hook_client_focus_unset, NULL));
   h = eina_list_append(h, e_client_hook_add(E_CLIENT_HOOK_EVAL_END, _e_comp_x_hook_client_eval_end, NULL));

   if (!_e_comp_x_screens_setup())
     {
        e_atoms_shutdown();
        E_FREE_LIST(h, e_client_hook_del);
        E_FREE_FUNC(clients_win_hash, eina_hash_free);
        E_FREE_FUNC(damages_hash, eina_hash_free);
        E_FREE_FUNC(alarm_hash, eina_hash_free);
        E_FREE_FUNC(frame_extents, eina_hash_free);
        return 0;
     }

   E_LIST_HANDLER_APPEND(handlers, E_EVENT_COMP_OBJECT_ADD, _e_comp_x_object_add, NULL);

   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_DESTROY, _e_comp_x_destroy, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_SHOW, _e_comp_x_show, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_SHOW_REQUEST, _e_comp_x_show_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_RESIZE_REQUEST, _e_comp_x_resize_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_HIDE, _e_comp_x_hide, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_REPARENT, _e_comp_x_reparent, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_CONFIGURE, _e_comp_x_configure, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST, _e_comp_x_configure_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STATE_REQUEST, _e_comp_x_state_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STACK, _e_comp_x_stack, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STACK_REQUEST, _e_comp_x_stack_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_CLIENT_MESSAGE, _e_comp_x_message, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_PROPERTY, _e_comp_x_property, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_SHAPE, _e_comp_x_shape, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_DAMAGE_NOTIFY, _e_comp_x_damage, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_DAMAGE, _e_comp_x_damage_win, NULL);

   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_MAPPING_CHANGE, _e_comp_x_mapping_change, NULL);

   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_FOCUS_IN, _e_comp_x_focus_in, NULL);
   if (e_comp->comp_type != E_PIXMAP_TYPE_WL)
     E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_FOCUS_OUT, _e_comp_x_focus_out, NULL);

   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST,
                         _e_comp_x_move_resize_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_DESKTOP_CHANGE,
                         _e_comp_x_desktop_change, NULL);
   if (e_comp->comp_type != E_PIXMAP_TYPE_WL)
     E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_SYNC_ALARM,
                           _e_comp_x_sync_alarm, NULL);

   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_DOWN,
                         _e_comp_x_mouse_down, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_UP,
                         _e_comp_x_mouse_up, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_WHEEL,
                         _e_comp_x_mouse_wheel, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_MOVE,
                         _e_comp_x_mouse_move, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_MOUSE_IN,
                         _e_comp_x_mouse_in, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_MOUSE_OUT,
                         _e_comp_x_mouse_out, NULL);

   E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_ZONE_SET,
                         _e_comp_x_client_zone_set, NULL);
   E_LIST_HANDLER_APPEND(handlers, E_EVENT_CLIENT_PROPERTY,
                         _e_comp_x_client_property, NULL);

   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_FRAME_EXTENTS_REQUEST,
                         _e_comp_x_cb_frame_extents_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_PING,
                         _e_comp_x_cb_ping, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_RANDR_OUTPUT_PROPERTY_NOTIFY, _e_comp_x_backlight_notify_cb, NULL);
   if (ecore_x_randr_version_get() >= RANDR_VERSION_1_3)
     backlight_atom = ecore_x_atom_get("Backlight");

   if (!backlight_atom)
     backlight_atom = ecore_x_atom_get("BACKLIGHT");

   ecore_x_passive_grab_replay_func_set(_e_comp_x_grab_replay, NULL);

   if (!e_xsettings_init())
     e_error_message_show(_("Enlightenment cannot initialize the XSettings system.\n"));
   E_LIST_HANDLER_APPEND(handlers, E_EVENT_RANDR_CHANGE, _e_comp_x_randr_change, NULL);

   ecore_x_sync();
   _x_idle_flush = ecore_idle_enterer_add(_e_comp_x_flusher, NULL);

   if (e_comp->comp_type != E_PIXMAP_TYPE_WL)
     {
        ecore_x_screensaver_event_listen_set(1);
        E_LIST_HANDLER_APPEND(handlers, E_EVENT_SCREENSAVER_ON, _e_comp_x_screensaver_on, NULL);
        E_LIST_HANDLER_APPEND(handlers, E_EVENT_SCREENSAVER_OFF, _e_comp_x_screensaver_off, NULL);
        E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_SCREENSAVER_NOTIFY, _e_comp_x_screensaver_notify_cb, NULL);
        ecore_x_screensaver_custom_blanking_enable();

        e_screensaver_attrs_set(ecore_x_screensaver_timeout_get(),
                                ecore_x_screensaver_blank_get(),
                                ecore_x_screensaver_expose_get());
        e_desklock_show_hook_add(_e_comp_x_desklock_show);
        e_desklock_hide_hook_add(_e_comp_x_desklock_hide);
        int timeout = e_screensaver_timeout_get(EINA_TRUE);
        ecore_x_screensaver_set(timeout + 10,
                                0,
                                !e_config->screensaver_blanking,
                                !e_config->screensaver_expose);
        ecore_x_screensaver_set(timeout,
                                0,
                                e_config->screensaver_blanking,
                                e_config->screensaver_expose);
     }
   else
     e_dnd_init();
   eina_list_free(h);
   return EINA_TRUE;
}

E_API void
e_comp_x_shutdown(void)
{
   _e_comp_x_del(e_comp);
   E_FREE_LIST(handlers, ecore_event_handler_del);
   E_FREE_FUNC(clients_win_hash, eina_hash_free);
   E_FREE_FUNC(damages_hash, eina_hash_free);
   E_FREE_FUNC(alarm_hash, eina_hash_free);
   E_FREE_FUNC(pending_configures, eina_hash_free);
   E_FREE_FUNC(frame_extents, eina_hash_free);
   E_FREE_FUNC(mouse_in_fix_check_timer, ecore_timer_del);
   e_xsettings_shutdown();
   if (x_fatal) return;
   if (e_comp->comp_type == E_PIXMAP_TYPE_X)
     ecore_x_screensaver_custom_blanking_disable();
   e_atoms_shutdown();
   /* ecore_x_ungrab(); */
   ecore_x_focus_reset();
   ecore_x_events_allow_all();
   ecore_x_shutdown();
}

EINTERN void
e_comp_x_nocomp_end(void)
{
   e_comp->nocomp = 0;
   ecore_x_window_show(e_comp->win);
   ecore_x_composite_redirect_subwindows(e_comp->root, ECORE_X_COMPOSITE_UPDATE_MANUAL);
   _e_comp_x_focus_check();
}

#ifdef HAVE_WAYLAND
EINTERN void
e_comp_x_xwayland_client_setup(E_Client *ec, E_Client *wc)
{
   Ecore_X_Window win, pwin;
   E_Comp_X_Client_Data *cd;
   Eina_Bool placed;

   win = e_client_util_win_get(ec);
   pwin = e_client_util_pwin_get(ec);
   cd = ec->comp_data;
   e_comp_wl_client_xwayland_setup(wc, cd, e_pixmap_ref(ec->pixmap));
   eina_hash_del(damages_hash, &cd->damage, ec);
   ecore_x_damage_free(cd->damage);
   E_FREE_FUNC(cd->first_draw_delay, ecore_timer_del);
   cd->damage = 0;
   ec->comp_data = NULL;
   cd->evas_init = 0;
   _e_comp_x_client_evas_init(wc);
   if (!e_comp_object_frame_exists(ec->frame))
     {
        int l, r, t, b;

        e_comp_object_frame_geometry_get(ec->frame, &l, &r, &t, &b);
        e_comp_object_frame_geometry_set(wc->frame, l, r, t, b);
     }
   wc->borderless = ec->borderless;
   wc->border.changed = 1;
   EC_CHANGED(wc);
   wc->depth = ec->depth;
   wc->override = ec->override;
   placed = ec->placed;
   wc->input_only = ec->input_only;
   wc->border_size = ec->border_size;
   wc->no_shape_cut = 0;
   memcpy(&wc->icccm, &ec->icccm, sizeof(ec->icccm));
   memcpy(&wc->netwm, &ec->netwm, sizeof(ec->netwm));
   memcpy(&wc->e, &ec->e, sizeof(ec->e));
   wc->new_client = !wc->override;
   if (wc->new_client)
     e_comp->new_clients++;

   eina_hash_set(clients_win_hash, &win, wc);
   if (pwin)
     eina_hash_set(clients_win_hash, &pwin, wc);
   wc->visible = 1;
   if (wc->ignored)
     e_client_unignore(wc);
   if (ec->override)
     e_client_focus_stack_set(eina_list_remove(e_client_focus_stack_get(), wc));
   evas_object_name_set(wc->frame, evas_object_name_get(ec->frame));
   wc->x = ec->x, wc->y = ec->y;
   wc->client.x = ec->client.x, wc->client.y = ec->client.y;
   wc->w = ec->w, wc->h = ec->h;
   wc->client.w = ec->client.w, wc->client.h = ec->client.h;
   wc->layer = ec->layer;
   wc->netwm.sync.request = 1;
   evas_object_layer_set(wc->frame, evas_object_layer_get(ec->frame));
   evas_object_geometry_set(wc->frame, ec->x, ec->y, ec->w, ec->h);
   evas_object_show(wc->frame);
   e_pixmap_alias(wc->pixmap, E_PIXMAP_TYPE_X, e_pixmap_window_get(ec->pixmap));
   e_object_del(E_OBJECT(ec));
   e_hints_window_visible_set(wc);
   _e_comp_x_client_stack(wc);
   wc->placed = placed;
   if (!placed) wc->changes.pos = 0;
}
#endif

E_API inline E_Pixmap *
e_comp_x_client_pixmap_get(const E_Client *ec)
{
#ifdef HAVE_WAYLAND
   if ((!e_pixmap_is_x(ec->pixmap)) && e_client_has_xwindow(ec))
     return e_comp_wl_client_xwayland_pixmap(ec);
#endif
   return ec->pixmap;
}
