#include "e.h"
#ifdef HAVE_WAYLAND_CLIENTS
#include "e_comp_wl.h"
#endif

//#define INOUTDEBUG_MOUSE 1
//#define INOUTDEBUG_FOCUS 1

/* local subsystem functions */
static void _e_border_pri_raise(E_Border *bd);
static void _e_border_pri_norm(E_Border *bd);
static void _e_border_free(E_Border *bd);
static void _e_border_del(E_Border *bd);

#ifdef PRINT_LOTS_OF_DEBUG
#define E_PRINT_BORDER_INFO(X) \
  _e_border_print(X, __PRETTY_FUNC__)

static void _e_border_print(E_Border *bd,
                            const char *func);
#endif

static void _e_border_shadow(E_Border *bd);

/* FIXME: these likely belong in a separate icccm/client handler */
/* and the border needs to become a dumb object that just does what its */
/* told to do */
static Eina_Bool _e_border_cb_window_show_request(void *data,
                                                  int ev_type,
                                                  void *ev);
static Eina_Bool _e_border_cb_window_destroy(void *data,
                                             int ev_type,
                                             void *ev);
static Eina_Bool _e_border_cb_window_hide(void *data,
                                          int ev_type,
                                          void *ev);
static Eina_Bool _e_border_cb_window_reparent(void *data,
                                              int ev_type,
                                              void *ev);
static Eina_Bool _e_border_cb_window_configure_request(void *data,
                                                       int ev_type,
                                                       void *ev);
static Eina_Bool _e_border_cb_window_resize_request(void *data,
                                                    int ev_type,
                                                    void *ev);
static Eina_Bool _e_border_cb_window_gravity(void *data,
                                             int ev_type,
                                             void *ev);
static Eina_Bool _e_border_cb_window_stack_request(void *data,
                                                   int ev_type,
                                                   void *ev);
static Eina_Bool _e_border_cb_window_property(void *data,
                                              int ev_type,
                                              void *ev);
static Eina_Bool _e_border_cb_window_colormap(void *data,
                                              int ev_type,
                                              void *ev);
static Eina_Bool _e_border_cb_window_shape(void *data,
                                           int ev_type,
                                           void *ev);
static Eina_Bool _e_border_cb_window_focus_in(void *data,
                                              int ev_type,
                                              void *ev);
static Eina_Bool _e_border_cb_window_focus_out(void *data,
                                               int ev_type,
                                               void *ev);
static Eina_Bool _e_border_cb_client_message(void *data, int ev_type, void *ev);
static Eina_Bool _e_border_cb_window_state_request(void *data,
                                                   int ev_type,
                                                   void *ev);
static Eina_Bool _e_border_cb_window_move_resize_request(void *data,
                                                         int ev_type,
                                                         void *ev);
static Eina_Bool _e_border_cb_desktop_change(void *data,
                                             int ev_type,
                                             void *ev);
static Eina_Bool _e_border_cb_sync_alarm(void *data,
                                         int ev_type,
                                         void *ev);
static Eina_Bool _e_border_cb_efreet_cache_update(void *data,
                                                  int ev_type,
                                                  void *ev);
static Eina_Bool _e_border_cb_config_icon_theme(void *data,
                                                int ev_type,
                                                void *ev);
static Eina_Bool _e_border_cb_config_mode(void *data,
                                          int ev_type,
                                          void *ev);
static Eina_Bool _e_border_cb_pointer_warp(void *data,
                                           int ev_type,
                                           void *ev);
static void      _e_border_cb_signal_bind(void *data,
                                          Evas_Object *obj,
                                          const char *emission,
                                          const char *source);
static Eina_Bool _e_border_cb_grab_replay(void *data,
                                          int type,
                                          void *event);
static void      _e_border_cb_drag_finished(E_Drag *drag,
                                            int dropped);
#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
static Eina_Bool _e_border_cb_desk_window_profile_change(void *data,
                                                         int ev_type,
                                                         void *ev);
#endif
static void      _e_border_eval(E_Border *bd);
static void      _e_border_eval0(E_Border *bd);
static void      _e_border_container_layout_hook(E_Container *con);

static void      _e_border_moveinfo_gather(E_Border *bd,
                                           const char *source);
static void      _e_border_resize_handle(E_Border *bd);

static Eina_Bool _e_border_shade_animator(void *data);

static void      _e_border_event_border_add_free(void *data,
                                                 void *ev);
static void      _e_border_event_border_remove_free(void *data,
                                                    void *ev);
static void      _e_border_event_border_zone_set_free(void *data,
                                                      void *ev);
static void      _e_border_event_border_desk_set_free(void *data,
                                                      void *ev);
static void      _e_border_event_border_stack_free(void *data,
                                                   void *ev);
static void      _e_border_event_border_icon_change_free(void *data,
                                                         void *ev);
static void      _e_border_event_border_title_change_free(void *data,
                                                         void *ev);
static void      _e_border_event_border_urgent_change_free(void *data,
                                                           void *ev);
static void      _e_border_event_border_focus_in_free(void *data,
                                                      void *ev);
static void      _e_border_event_border_focus_out_free(void *data,
                                                       void *ev);
static void      _e_border_event_border_resize_free(void *data,
                                                    void *ev);
static void      _e_border_event_border_move_free(void *data,
                                                  void *ev);
static void      _e_border_event_border_show_free(void *data,
                                                  void *ev);
static void      _e_border_event_border_hide_free(void *data,
                                                  void *ev);
static void      _e_border_event_border_iconify_free(void *data,
                                                     void *ev);
static void      _e_border_event_border_uniconify_free(void *data,
                                                       void *ev);
static void      _e_border_event_border_stick_free(void *data,
                                                   void *ev);
static void      _e_border_event_border_unstick_free(void *data,
                                                     void *ev);
static void      _e_border_event_border_property_free(void *data,
                                                      void *ev);
static void      _e_border_event_border_fullscreen_free(void *data,
                                                        void *ev);
static void      _e_border_event_border_unfullscreen_free(void *data,
                                                          void *ev);

static void      _e_border_zone_update(E_Border *bd);

static int       _e_border_resize_begin(E_Border *bd);
static int       _e_border_resize_end(E_Border *bd);
static void      _e_border_resize_update(E_Border *bd);

static int       _e_border_move_begin(E_Border *bd);
static int       _e_border_move_end(E_Border *bd);
static void      _e_border_move_update(E_Border *bd);

static Eina_Bool _e_border_cb_ping_poller(void *data);
static Eina_Bool _e_border_cb_kill_timer(void *data);

static void      _e_border_hook_call(E_Border_Hook_Point hookpoint,
                                     void *bd);

static void      _e_border_client_move_resize_send(E_Border *bd);

static void      _e_border_shape_input_rectangle_set(E_Border *bd);
static void      _e_border_show(E_Border *bd);
static void      _e_border_hide(E_Border *bd);

static void _e_border_cb_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static void _e_border_cb_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static void _e_border_cb_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static void _e_border_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static void _e_border_cb_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);
static void _e_border_cb_mouse_wheel(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info);

static Eina_Bool _e_border_cb_mouse_x_wheel(void *d EINA_UNUSED, int t, Ecore_Event_Mouse_Wheel *ev);
static Eina_Bool _e_border_cb_mouse_x_up(void *d EINA_UNUSED, int t, Ecore_Event_Mouse_Button *ev);
static Eina_Bool _e_border_cb_mouse_x_down(void *d EINA_UNUSED, int t, Ecore_Event_Mouse_Button *ev);
static Eina_Bool _e_border_cb_mouse_x_move(void *d, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev);
static Eina_Bool _e_border_cb_mouse_x_in(void *d, int t EINA_UNUSED, Ecore_X_Event_Mouse_In *ev);
static Eina_Bool _e_border_cb_mouse_x_out(void *d, int t EINA_UNUSED, Ecore_X_Event_Mouse_Out *ev);

static void _e_border_action_finish(void);

static void      _e_border_move_lost_window_to_center(E_Border *bd);
static void      _e_border_reset_lost_window(E_Border *bd);
static Eina_Bool _e_border_pointer_warp_to_center_timer(void *data);

/* local subsystem globals */
static Eina_List *handlers = NULL;
static Eina_List *borders = NULL;
static Eina_Hash *borders_hash = NULL;
static E_Border *focused = NULL;
static E_Border *focusing = NULL;
static Eina_List *focus_next = NULL;
static Ecore_X_Time focus_time = 0;

static E_Border *bdresize = NULL;
static E_Border *bdmove = NULL;
static E_Drag *drag_border = NULL;

static int grabbed = 0;

static Eina_List *focus_stack = NULL;
static Eina_List *raise_stack = NULL;

static E_Border *warp_timer_border = NULL;
static Eina_Bool focus_locked = EINA_FALSE;

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

static int focus_track_frozen = 0;

static int warp_to = 0;
static int warp_to_x = 0;
static int warp_to_y = 0;
static int warp_x[2] = {0}; //{cur,prev}
static int warp_y[2] = {0}; //{cur,prev}
static Ecore_X_Window warp_to_win;
static Ecore_Timer *warp_timer = NULL;

static Ecore_X_Window action_input_win = 0;
static E_Border *action_border = NULL;
static Ecore_Event_Handler *action_handler_key = NULL;
static Ecore_Event_Handler *action_handler_mouse = NULL;
static Ecore_Timer *action_timer = NULL;
static Ecore_X_Rectangle action_orig;

EAPI int E_EVENT_BORDER_ADD = 0;
EAPI int E_EVENT_BORDER_REMOVE = 0;
EAPI int E_EVENT_BORDER_ZONE_SET = 0;
EAPI int E_EVENT_BORDER_DESK_SET = 0;
EAPI int E_EVENT_BORDER_RESIZE = 0;
EAPI int E_EVENT_BORDER_MOVE = 0;
EAPI int E_EVENT_BORDER_SHOW = 0;
EAPI int E_EVENT_BORDER_HIDE = 0;
EAPI int E_EVENT_BORDER_ICONIFY = 0;
EAPI int E_EVENT_BORDER_UNICONIFY = 0;
EAPI int E_EVENT_BORDER_STICK = 0;
EAPI int E_EVENT_BORDER_UNSTICK = 0;
EAPI int E_EVENT_BORDER_STACK = 0;
EAPI int E_EVENT_BORDER_ICON_CHANGE = 0;
EAPI int E_EVENT_BORDER_TITLE_CHANGE = 0;
EAPI int E_EVENT_BORDER_URGENT_CHANGE = 0;
EAPI int E_EVENT_BORDER_FOCUS_IN = 0;
EAPI int E_EVENT_BORDER_FOCUS_OUT = 0;
EAPI int E_EVENT_BORDER_PROPERTY = 0;
EAPI int E_EVENT_BORDER_FULLSCREEN = 0;
EAPI int E_EVENT_BORDER_UNFULLSCREEN = 0;

#define GRAV_SET(bd, grav)                                                         \
  ecore_x_window_gravity_set(bd->win, grav);                          \
  if (bd->client.lock_win) ecore_x_window_gravity_set(bd->client.lock_win, grav);  \
  ecore_x_window_gravity_set(bd->client.win, grav);

static Eina_List *
_e_border_sub_borders_new(E_Border *bd)
{
   Eina_List *list = NULL, *l;
   E_Border *child;

   EINA_LIST_FOREACH(bd->transients, l, child)
     {
        if (!eina_list_data_find(list, child))
          list = eina_list_append(list, child);
     }
   return list;
}

/* externally accessible functions */
EINTERN int
e_border_init(void)
{
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_SHOW_REQUEST,
                         _e_border_cb_window_show_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_DESTROY,
                         _e_border_cb_window_destroy, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_HIDE,
                         _e_border_cb_window_hide, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_REPARENT,
                         _e_border_cb_window_reparent, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_CONFIGURE_REQUEST,
                         _e_border_cb_window_configure_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_RESIZE_REQUEST,
                         _e_border_cb_window_resize_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_GRAVITY,
                         _e_border_cb_window_gravity, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STACK_REQUEST,
                         _e_border_cb_window_stack_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_PROPERTY,
                         _e_border_cb_window_property, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_COLORMAP,
                         _e_border_cb_window_colormap, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_SHAPE,
                         _e_border_cb_window_shape, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_FOCUS_IN,
                         _e_border_cb_window_focus_in, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_FOCUS_OUT,
                         _e_border_cb_window_focus_out, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_CLIENT_MESSAGE,
                         _e_border_cb_client_message, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STATE_REQUEST,
                         _e_border_cb_window_state_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_MOVE_RESIZE_REQUEST,
                         _e_border_cb_window_move_resize_request, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_DESKTOP_CHANGE,
                         _e_border_cb_desktop_change, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_SYNC_ALARM,
                         _e_border_cb_sync_alarm, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_DOWN,
                         _e_border_cb_mouse_x_down, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_BUTTON_UP,
                         _e_border_cb_mouse_x_up, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_MOUSE_IN,
                         _e_border_cb_mouse_x_in, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_MOUSE_OUT,
                         _e_border_cb_mouse_x_out, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_WHEEL,
                         _e_border_cb_mouse_x_wheel, NULL);
   E_LIST_HANDLER_APPEND(handlers, ECORE_EVENT_MOUSE_MOVE,
                         _e_border_cb_mouse_x_move, NULL);

   ecore_x_passive_grab_replay_func_set(_e_border_cb_grab_replay, NULL);

   E_LIST_HANDLER_APPEND(handlers, E_EVENT_POINTER_WARP,
                         _e_border_cb_pointer_warp, NULL);
   E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_DESKTOP_CACHE_UPDATE,
                         _e_border_cb_efreet_cache_update, NULL);
   E_LIST_HANDLER_APPEND(handlers, EFREET_EVENT_ICON_CACHE_UPDATE,
                         _e_border_cb_efreet_cache_update, NULL);
   E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_ICON_THEME,
                         _e_border_cb_config_icon_theme, NULL);
   E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONFIG_MODE_CHANGED,
                         _e_border_cb_config_mode, NULL);
#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
   E_LIST_HANDLER_APPEND(handlers, E_EVENT_DESK_WINDOW_PROFILE_CHANGE,
                         _e_border_cb_desk_window_profile_change, NULL);
#endif
   if (!borders_hash) borders_hash = eina_hash_string_superfast_new(NULL);

   E_EVENT_BORDER_ADD = ecore_event_type_new();
   E_EVENT_BORDER_REMOVE = ecore_event_type_new();
   E_EVENT_BORDER_DESK_SET = ecore_event_type_new();
   E_EVENT_BORDER_ZONE_SET = ecore_event_type_new();
   E_EVENT_BORDER_RESIZE = ecore_event_type_new();
   E_EVENT_BORDER_MOVE = ecore_event_type_new();
   E_EVENT_BORDER_SHOW = ecore_event_type_new();
   E_EVENT_BORDER_HIDE = ecore_event_type_new();
   E_EVENT_BORDER_ICONIFY = ecore_event_type_new();
   E_EVENT_BORDER_UNICONIFY = ecore_event_type_new();
   E_EVENT_BORDER_STICK = ecore_event_type_new();
   E_EVENT_BORDER_UNSTICK = ecore_event_type_new();
   E_EVENT_BORDER_STACK = ecore_event_type_new();
   E_EVENT_BORDER_ICON_CHANGE = ecore_event_type_new();
   E_EVENT_BORDER_TITLE_CHANGE = ecore_event_type_new();
   E_EVENT_BORDER_URGENT_CHANGE = ecore_event_type_new();
   E_EVENT_BORDER_FOCUS_IN = ecore_event_type_new();
   E_EVENT_BORDER_FOCUS_OUT = ecore_event_type_new();
   E_EVENT_BORDER_PROPERTY = ecore_event_type_new();
   E_EVENT_BORDER_FULLSCREEN = ecore_event_type_new();
   E_EVENT_BORDER_UNFULLSCREEN = ecore_event_type_new();

//   e_init_undone();

   return 1;
}

EINTERN int
e_border_shutdown(void)
{
   E_FREE_LIST(handlers, ecore_event_handler_del);

   if (borders_hash) eina_hash_free(borders_hash);
   borders_hash = NULL;
   e_int_border_menu_hooks_clear();
   focus_locked = EINA_FALSE;
   if (warp_timer) ecore_timer_del(warp_timer);
   warp_timer = NULL;
   warp_timer_border = NULL;

   return 1;
}

EAPI void
e_border_focus_lock_set(Eina_Bool lock)
{
   focus_locked = !!lock;
}

EAPI Eina_Bool
e_border_focus_lock_get(void)
{
   return focus_locked;
}

EAPI E_Border *
e_border_new(E_Container *con, Ecore_X_Window win, int first_map, int internal)
{
   E_Border *bd;
   Ecore_X_Window_Attributes *att;
   unsigned int managed, desk[2];
   int deskx, desky;

   if (eina_hash_find(borders_hash, e_util_winid_str_get(win))) return NULL;
   bd = E_OBJECT_ALLOC(E_Border, E_BORDER_TYPE, _e_border_free);
   if (!bd) return NULL;
   ecore_x_window_shadow_tree_flush();
   e_object_del_func_set(E_OBJECT(bd), E_OBJECT_CLEANUP_FUNC(_e_border_del));

   bd->focus_policy_override = E_FOCUS_LAST;
   bd->w = 1;
   bd->h = 1;
   /* FIXME: ewww - round trip */
   bd->client.argb = ecore_x_window_argb_get(win);
   /* match bd parent argbness */
   if (bd->client.argb)
     bd->win = ecore_x_window_manager_argb_new(con->win, 0, 0, bd->w, bd->h);
   else
     {
        bd->win = ecore_x_window_override_new(con->win, 0, 0, bd->w, bd->h);
        ecore_x_window_shape_events_select(bd->win, 1);
     }
   e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, bd->win);
   e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, bd->win);
   e_focus_setup(bd);
   /* FIXME: Round trip. XCB */
   /* fetch needed to avoid grabbing the server as window may vanish */
   att = &bd->client.initial_attributes;
   if ((!ecore_x_window_attributes_get(win, att)) || (att->input_only))
     {
        //	printf("##- ATTR FETCH FAILED/INPUT ONLY FOR 0x%x - ABORT MANAGE\n", win);
        ecore_x_window_free(bd->win);
        e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win);
        e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win);
        ecore_x_window_free(bd->win);
        free(bd);
        return NULL;
     }
   ecore_x_window_container_manage(bd->win);
   if (!internal) ecore_x_window_client_manage(win);
   ecore_x_window_configure(bd->win,
                            ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
                            ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
                            0, 0, 0, 0, 0,
                            win, ECORE_X_WINDOW_STACK_BELOW);
   ecore_x_event_mask_set(bd->win, ECORE_X_EVENT_MASK_MOUSE_IN | ECORE_X_EVENT_MASK_MOUSE_OUT);

   /* printf("##- ON MAP CLIENT 0x%x SIZE %ix%i %i:%i\n",
    *     bd->client.win, bd->client.w, bd->client.h, att->x, att->y); */

   /* FIXME: if first_map is 1 then we should ignore the first hide event
    * or ensure the window is already hidden and events flushed before we
    * create a border for it */
   if (first_map)
     {
        // printf("##- FIRST MAP\n");
        bd->x = att->x;
        bd->y = att->y;
        bd->changes.pos = 1;
        bd->re_manage = 1;
        // needed to be 1 for internal windw and on restart.
        // bd->ignore_first_unmap = 2;
     }

   bd->client.win = win;
   bd->zone = e_zone_current_get(con);

   _e_border_hook_call(E_BORDER_HOOK_NEW_BORDER, bd);

   bd->client.icccm.title = NULL;
   bd->client.icccm.name = NULL;
   bd->client.icccm.class = NULL;
   bd->client.icccm.icon_name = NULL;
   bd->client.icccm.machine = NULL;
   bd->client.icccm.min_w = 1;
   bd->client.icccm.min_h = 1;
   bd->client.icccm.max_w = 32767;
   bd->client.icccm.max_h = 32767;
   bd->client.icccm.base_w = 0;
   bd->client.icccm.base_h = 0;
   bd->client.icccm.step_w = -1;
   bd->client.icccm.step_h = -1;
   bd->client.icccm.min_aspect = 0.0;
   bd->client.icccm.max_aspect = 0.0;
   bd->client.icccm.accepts_focus = 1;

   bd->client.netwm.pid = 0;
   bd->client.netwm.name = NULL;
   bd->client.netwm.icon_name = NULL;
   bd->client.netwm.desktop = 0;
   bd->client.netwm.state.modal = 0;
   bd->client.netwm.state.sticky = 0;
   bd->client.netwm.state.shaded = 0;
   bd->client.netwm.state.hidden = 0;
   bd->client.netwm.state.maximized_v = 0;
   bd->client.netwm.state.maximized_h = 0;
   bd->client.netwm.state.skip_taskbar = 0;
   bd->client.netwm.state.skip_pager = 0;
   bd->client.netwm.state.fullscreen = 0;
   bd->client.netwm.state.stacking = E_STACKING_NONE;
   bd->client.netwm.action.move = 0;
   bd->client.netwm.action.resize = 0;
   bd->client.netwm.action.minimize = 0;
   bd->client.netwm.action.shade = 0;
   bd->client.netwm.action.stick = 0;
   bd->client.netwm.action.maximized_h = 0;
   bd->client.netwm.action.maximized_v = 0;
   bd->client.netwm.action.fullscreen = 0;
   bd->client.netwm.action.change_desktop = 0;
   bd->client.netwm.action.close = 0;
   bd->client.netwm.opacity = 255;
   bd->client.netwm.type = ECORE_X_WINDOW_TYPE_UNKNOWN;

   {
      int at_num = 0, i;
      Ecore_X_Atom *atoms;

      atoms = ecore_x_window_prop_list(bd->client.win, &at_num);
      bd->client.icccm.fetch.command = 1;
      if (atoms)
        {
           Eina_Bool video_parent = EINA_FALSE;
           Eina_Bool video_position = EINA_FALSE;

           /* icccm */
           for (i = 0; i < at_num; i++)
             {
                if (atoms[i] == ECORE_X_ATOM_WM_NAME)
                  bd->client.icccm.fetch.title = 1;
                else if (atoms[i] == ECORE_X_ATOM_WM_CLASS)
                  bd->client.icccm.fetch.name_class = 1;
                else if (atoms[i] == ECORE_X_ATOM_WM_ICON_NAME)
                  bd->client.icccm.fetch.icon_name = 1;
                else if (atoms[i] == ECORE_X_ATOM_WM_CLIENT_MACHINE)
                  bd->client.icccm.fetch.machine = 1;
                else if (atoms[i] == ECORE_X_ATOM_WM_HINTS)
                  bd->client.icccm.fetch.hints = 1;
                else if (atoms[i] == ECORE_X_ATOM_WM_NORMAL_HINTS)
                  bd->client.icccm.fetch.size_pos_hints = 1;
                else if (atoms[i] == ECORE_X_ATOM_WM_PROTOCOLS)
                  bd->client.icccm.fetch.protocol = 1;
                else if (atoms[i] == ECORE_X_ATOM_MOTIF_WM_HINTS)
                  bd->client.mwm.fetch.hints = 1;
                else if (atoms[i] == ECORE_X_ATOM_WM_TRANSIENT_FOR)
                  {
                     bd->client.icccm.fetch.transient_for = 1;
                     bd->client.netwm.fetch.type = 1;
                  }
                else if (atoms[i] == ECORE_X_ATOM_WM_CLIENT_LEADER)
                  bd->client.icccm.fetch.client_leader = 1;
                else if (atoms[i] == ECORE_X_ATOM_WM_WINDOW_ROLE)
                  bd->client.icccm.fetch.window_role = 1;
                else if (atoms[i] == ECORE_X_ATOM_WM_STATE)
                  bd->client.icccm.fetch.state = 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 */
                     bd->client.icccm.fetch.title = 0;
                     bd->client.netwm.fetch.name = 1;
                  }
                else if (atoms[i] == ECORE_X_ATOM_NET_WM_ICON_NAME)
                  {
                     /* Ignore icccm */
                     bd->client.icccm.fetch.icon_name = 0;
                     bd->client.netwm.fetch.icon_name = 1;
                  }
                else if (atoms[i] == ECORE_X_ATOM_NET_WM_ICON)
                  {
                     bd->client.netwm.fetch.icon = 1;
                  }
                else if (atoms[i] == ECORE_X_ATOM_NET_WM_USER_TIME)
                  {
                     bd->client.netwm.fetch.user_time = 1;
                  }
                else if (atoms[i] == ECORE_X_ATOM_NET_WM_STRUT)
                  {
                     DBG("ECORE_X_ATOM_NET_WM_STRUT");
                     bd->client.netwm.fetch.strut = 1;
                  }
                else if (atoms[i] == ECORE_X_ATOM_NET_WM_STRUT_PARTIAL)
                  {
                     DBG("ECORE_X_ATOM_NET_WM_STRUT_PARTIAL");
                     bd->client.netwm.fetch.strut = 1;
                  }
                else if (atoms[i] == ECORE_X_ATOM_NET_WM_WINDOW_TYPE)
                  {
                     /* Ignore mwm
                        bd->client.mwm.fetch.hints = 0;
                      */
                     bd->client.netwm.fetch.type = 1;
                  }
                else if (atoms[i] == ECORE_X_ATOM_NET_WM_STATE)
                  {
                     bd->client.netwm.fetch.state = 1;
                  }
                else if (atoms[i] == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY)
                  bd->client.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)
                  {
                     bd->client.e.fetch.state = 1;
                  }
                /* loop to check for qtopia atoms */
                if (atoms[i] == ATM__QTOPIA_SOFT_MENU)
                  bd->client.qtopia.fetch.soft_menu = 1;
                else if (atoms[i] == ATM__QTOPIA_SOFT_MENUS)
                  bd->client.qtopia.fetch.soft_menus = 1;
                /* loop to check for vkbd atoms */
                else if (atoms[i] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE)
                  bd->client.vkbd.fetch.state = 1;
                else if (atoms[i] == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD)
                  bd->client.vkbd.fetch.vkbd = 1;
                /* loop to check for illume atoms */
                else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_CONFORMANT)
                  bd->client.illume.conformant.fetch.conformant = 1;
                else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE)
                  bd->client.illume.quickpanel.fetch.state = 1;
                else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL)
                  bd->client.illume.quickpanel.fetch.quickpanel = 1;
                else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR)
                  bd->client.illume.quickpanel.fetch.priority.major = 1;
                else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR)
                  bd->client.illume.quickpanel.fetch.priority.minor = 1;
                else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE)
                  bd->client.illume.quickpanel.fetch.zone = 1;
                else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED)
                  bd->client.illume.drag.fetch.locked = 1;
                else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_DRAG)
                  bd->client.illume.drag.fetch.drag = 1;
                else if (atoms[i] == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE)
                  bd->client.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;
#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
                /* loop to check for window profile list atom */
                else if (atoms[i] == ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED)
                  bd->client.e.fetch.profile = 1;
#endif
             }
           if (video_position && video_parent)
             {
                bd->client.e.state.video = 1;
                bd->client.e.fetch.video_parent = 1;
                bd->client.e.fetch.video_position = 1;
                ecore_x_window_lower(bd->win);
                ecore_x_composite_window_events_disable(bd->win);
                ecore_x_window_ignore_set(bd->win, EINA_TRUE);
                fprintf(stderr, "We found a video window \\o/ %x\n", win);
             }
           free(atoms);
        }
   }
   bd->client.border.changed = 1;

   bd->client.w = att->w;
   bd->client.h = att->h;

   bd->w = bd->client.w;
   bd->h = bd->client.h;

   bd->resize_mode = E_POINTER_RESIZE_NONE;
   bd->layer = 100;
   bd->saved.layer = bd->layer;
   bd->changes.icon = 1;
   bd->changes.size = 1;
   bd->changes.shape = 1;
   bd->changes.shape_input = 1;

   bd->offer_resistance = 1;

   /* just to friggin make java happy - we're DELAYING the reparent until
    * eval time...
    */
/*   ecore_x_window_reparent(win, bd->win, 0, 0); */
   bd->need_reparent = 1;

   ecore_x_window_border_width_set(win, 0);
   bd->shape = e_container_shape_add(con);

   bd->take_focus = 1;
   bd->new_client = 1;
   BD_CHANGED(bd);

//   bd->zone = e_zone_current_get(con);
   bd->desk = e_desk_current_get(bd->zone);
   e_container_border_add(bd);
   borders = eina_list_append(borders, bd);
   eina_hash_add(borders_hash, e_util_winid_str_get(bd->client.win), bd);
   eina_hash_add(borders_hash, e_util_winid_str_get(bd->win), bd);
   managed = 1;
   ecore_x_window_prop_card32_set(win, E_ATOM_MANAGED, &managed, 1);
   ecore_x_window_prop_card32_set(win, E_ATOM_CONTAINER, &bd->zone->container->num, 1);
   ecore_x_window_prop_card32_set(win, E_ATOM_ZONE, &bd->zone->num, 1);
   {
      unsigned int zgeom[4];

      zgeom[0] = bd->zone->x;
      zgeom[1] = bd->zone->y;
      zgeom[2] = bd->zone->w;
      zgeom[3] = bd->zone->h;
      ecore_x_window_prop_card32_set(win, E_ATOM_ZONE_GEOMETRY, zgeom, 4);
   }
   e_desk_xy_get(bd->desk, &deskx, &desky);
   desk[0] = deskx;
   desk[1] = desky;
   ecore_x_window_prop_card32_set(win, E_ATOM_DESK, desk, 2);

   if (starting)
     focus_stack = eina_list_prepend(focus_stack, bd);
   else
     focus_stack = eina_list_append(focus_stack, bd);

   return bd;
}

EAPI void
e_border_res_change_geometry_save(E_Border *bd)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   if (bd->pre_res_change.valid) return;
   bd->pre_res_change.valid = 1;
   bd->pre_res_change.x = bd->x;
   bd->pre_res_change.y = bd->y;
   bd->pre_res_change.w = bd->w;
   bd->pre_res_change.h = bd->h;
   bd->pre_res_change.saved.x = bd->saved.x;
   bd->pre_res_change.saved.y = bd->saved.y;
   bd->pre_res_change.saved.w = bd->saved.w;
   bd->pre_res_change.saved.h = bd->saved.h;
}

EAPI void
e_border_res_change_geometry_restore(E_Border *bd)
{
   struct
   {
      unsigned char valid : 1;
      int           x, y, w, h;
      struct
      {
         int x, y, w, h;
      } saved;
   } pre_res_change;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (!bd->pre_res_change.valid) return;
   if (bd->new_client) return;

   ecore_x_window_shadow_tree_flush();
   memcpy(&pre_res_change, &bd->pre_res_change, sizeof(pre_res_change));

   if (bd->fullscreen)
     {
        e_border_unfullscreen(bd);
        e_border_fullscreen(bd, e_config->fullscreen_policy);
     }
   else if (bd->maximized != E_MAXIMIZE_NONE)
     {
        E_Maximize max;

        max = bd->maximized;
        e_border_unmaximize(bd, E_MAXIMIZE_BOTH);
        e_border_maximize(bd, max);
     }
   else
     {
        int x, y, w, h, zx, zy, zw, zh;

        bd->saved.x = bd->pre_res_change.saved.x;
        bd->saved.y = bd->pre_res_change.saved.y;
        bd->saved.w = bd->pre_res_change.saved.w;
        bd->saved.h = bd->pre_res_change.saved.h;

        e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh);

        if (bd->saved.w > zw)
          bd->saved.w = zw;
        if ((bd->saved.x + bd->saved.w) > (zx + zw))
          bd->saved.x = zx + zw - bd->saved.w;

        if (bd->saved.h > zh)
          bd->saved.h = zh;
        if ((bd->saved.y + bd->saved.h) > (zy + zh))
          bd->saved.y = zy + zh - bd->saved.h;

        x = bd->pre_res_change.x;
        y = bd->pre_res_change.y;
        w = bd->pre_res_change.w;
        h = bd->pre_res_change.h;
        if (w > zw)
          w = zw;
        if (h > zh)
          h = zh;
        if ((x + w) > (zx + zw))
          x = zx + zw - w;
        if ((y + h) > (zy + zh))
          y = zy + zh - h;
        e_border_move_resize(bd, x, y, w, h);
     }
   memcpy(&bd->pre_res_change, &pre_res_change, sizeof(pre_res_change));
}

EAPI void
e_border_zone_set(E_Border *bd,
                  E_Zone *zone)
{
   E_Event_Border_Zone_Set *ev;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   E_OBJECT_CHECK(zone);
   E_OBJECT_TYPE_CHECK(zone, E_ZONE_TYPE);
   if (!zone) return;
   if (bd->zone == zone) return;

   /* if the window does not lie in the new zone, move it so that it does */
   if (!E_INTERSECTS(bd->x, bd->y, bd->w, bd->h, zone->x, zone->y, zone->w, zone->h))
     {
        int x, y;
        /* first guess -- get offset from old zone, and apply to new zone */
        x = zone->x + (bd->x - bd->zone->x);
        y = zone->y + (bd->y - bd->zone->y);

        /* keep window from hanging off bottom and left */
        if (x + bd->w > zone->x + zone->w) x += (zone->x + zone->w) - (x + bd->w);
        if (y + bd->h > zone->y + zone->h) y += (zone->y + zone->h) - (y + bd->h);

        /* make sure to and left are on screen (if the window is larger than the zone, it will hang off the bottom / right) */
        if (x < zone->x) x = zone->x;
        if (y < zone->y) y = zone->y;

        if (!E_INTERSECTS(x, y, bd->w, bd->h, zone->x, zone->y, zone->w, zone->h))
          {
             /* still not in zone at all, so just move it to closest edge */
             if (x < zone->x) x = zone->x;
             if (x >= zone->x + zone->w) x = zone->x + zone->w - bd->w;
             if (y < zone->y) y = zone->y;
             if (y >= zone->y + zone->h) y = zone->y + zone->h - bd->h;
          }
        e_border_move(bd, x, y);
     }

   bd->zone = zone;

   if (bd->desk->zone != bd->zone)
     e_border_desk_set(bd, e_desk_current_get(bd->zone));

   ev = E_NEW(E_Event_Border_Zone_Set, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
//   e_object_breadcrumb_add(E_OBJECT(bd), "border_zone_set_event");
   ev->zone = zone;
   e_object_ref(E_OBJECT(zone));

   ecore_event_add(E_EVENT_BORDER_ZONE_SET, ev, _e_border_event_border_zone_set_free, NULL);

   ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_ZONE, &bd->zone->num, 1);
   // XXXXXXXXXXXXXXXXXXXXXXXXX
   // XXX ZZZZZZZZZZZZZZZZZZZzz
   // need to adjust this if zone pos/size changes
   {
      unsigned int zgeom[4];

      zgeom[0] = bd->zone->x;
      zgeom[1] = bd->zone->y;
      zgeom[2] = bd->zone->w;
      zgeom[3] = bd->zone->h;
      ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_ZONE_GEOMETRY, zgeom, 4);
   }
   e_remember_update(bd);
   e_border_res_change_geometry_save(bd);
   e_border_res_change_geometry_restore(bd);
   bd->pre_res_change.valid = 0;
}

EAPI void
e_border_desk_set(E_Border *bd,
                  E_Desk *desk)
{
   E_Event_Border_Desk_Set *ev;
   E_Desk *old_desk;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   E_OBJECT_CHECK(desk);
   E_OBJECT_TYPE_CHECK(desk, E_DESK_TYPE);
   if (bd->desk == desk) return;
#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
   if ((e_config->use_desktop_window_profile) &&
       (bd->client.e.state.profile.use))
     {
        if (bd->client.e.state.profile.wait_for_done) return;
        if (e_util_strcmp(bd->client.e.state.profile.name, desk->window_profile))
          {
             ecore_x_e_window_profile_change_request_send(bd->client.win,
                                                          desk->window_profile);
             bd->client.e.state.profile.wait_for_done = 1;
             return;
          }
     }
#endif
   if (desk == e_desk_current_get(desk->zone))
     {
        e_comp_win_effect_unclip(bd->cw);
        e_comp_win_effect_set(bd->cw, NULL);
        e_border_show(bd);
     }
   else
     e_border_hide(bd, 2);
   ecore_x_window_shadow_tree_flush();
   if (bd->fullscreen)
     {
        bd->desk->fullscreen_borders--;
        desk->fullscreen_borders++;
     }
   old_desk = bd->desk;
   bd->desk = desk;
   e_border_zone_set(bd, desk->zone);

   _e_border_hook_call(E_BORDER_HOOK_SET_DESK, bd);
   e_hints_window_desktop_set(bd);

   ev = E_NEW(E_Event_Border_Desk_Set, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
//   e_object_breadcrumb_add(E_OBJECT(bd), "border_desk_set_event");
   ev->desk = old_desk;
   e_object_ref(E_OBJECT(old_desk));
   ecore_event_add(E_EVENT_BORDER_DESK_SET, ev, _e_border_event_border_desk_set_free, NULL);

   if (bd->ignore_first_unmap != 1)
     {
        if ((bd->desk->visible) || (bd->sticky))
          e_border_show(bd);
        else
          e_border_hide(bd, 1);
     }

   if (e_config->transient.desktop)
     {
        E_Border *child;
        Eina_List *list = _e_border_sub_borders_new(bd);

        EINA_LIST_FREE(list, child)
          e_border_desk_set(child, bd->desk);
     }
   e_remember_update(bd);
}

EAPI void
e_border_show(E_Border *bd)
{
   E_Event_Border_Show *ev;
   unsigned int visible;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (bd->visible) return;
   ecore_x_window_shadow_tree_flush();
   e_container_shape_show(bd->shape);
   if (!bd->need_reparent)
     ecore_x_window_show(bd->client.win);
   e_hints_window_visible_set(bd);
   bd->hidden = 0;
   bd->visible = 1;
   bd->changes.visible = 1;

   visible = 1;
   ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MAPPED, &visible, 1);
   ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MANAGED, &visible, 1);

   if (bd->new_client) return;

   ev = E_NEW(E_Event_Border_Show, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
//   e_object_breadcrumb_add(E_OBJECT(bd), "border_show_event");
   ecore_event_add(E_EVENT_BORDER_SHOW, ev, _e_border_event_border_show_free, NULL);
}

EAPI void
e_border_hide(E_Border *bd,
              int manage)
{
   unsigned int visible;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (!bd->visible) goto send_event;
   ecore_x_window_shadow_tree_flush();
   if (bd->moving)
     _e_border_move_end(bd);
   if (bd->resize_mode != E_POINTER_RESIZE_NONE)
     _e_border_resize_end(bd);
   if (action_border == bd)
     _e_border_action_finish();

   e_container_shape_hide(bd->shape);
   if ((!bd->iconic) && (!bd->delete_requested))
     e_hints_window_hidden_set(bd);

   bd->visible = 0;
   bd->changes.visible = 1;

   if (!bd->need_reparent)
     {
        if (bd->focused)
          {
             e_border_focus_set(bd, 0, 1);
             if (manage != 2)
               {
                  E_Border *pbd;
                  E_Zone *zone;
                  E_Desk *desk;

                  zone = e_util_zone_current_get(e_manager_current_get());
                  desk = e_desk_current_get(zone);

                  if ((bd->parent) &&
                      (bd->parent->desk == desk) && (bd->parent->modal == bd))
                    e_border_focus_set(bd->parent, 1, 1);
                  else if (e_config->focus_revert_on_hide_or_close)
                    {
                       Eina_Bool unlock = bd->lock_focus_out;
                       bd->lock_focus_out = 1;
                       e_desk_last_focused_focus(desk);
                       bd->lock_focus_out = unlock;
                    }
                  else if (e_config->focus_policy == E_FOCUS_MOUSE)
                    {
                       pbd = e_border_under_pointer_get(desk, bd);
                       if (pbd)
                         e_border_focus_set(pbd, 1, 1);
                    }
               }
          }
        switch (manage)
          {
           case 2: break;

           case 3:
             bd->hidden = 1;
             /* fallthrough */
           case 1:
           default:
             if (!e_comp_evas_exists(bd))
               {
                  /* Make sure that this border isn't deleted */
                  bd->await_hide_event++;
                  ecore_x_window_hide(bd->client.win);
               }
          }
     }

   if (!bd->delete_requested)
     {
        visible = 0;
        ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MAPPED, &visible, 1);
        if (!manage)
          ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MANAGED, &visible, 1);
     }

   bd->post_show = 0;

send_event:
   if (bd->new_client) return;
   if (!stopping)
     {
        E_Event_Border_Hide *ev;

        ev = E_NEW(E_Event_Border_Hide, 1);
        ev->border = bd;
        ev->manage = manage;
        e_object_ref(E_OBJECT(bd));
//	e_object_breadcrumb_add(E_OBJECT(bd), "border_hide_event");
        ecore_event_add(E_EVENT_BORDER_HIDE, ev, _e_border_event_border_hide_free, NULL);
     }
}

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);
// shouldnt 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 void
_e_border_pri_raise(E_Border *bd)
{
   if (bd->client.netwm.pid <= 0) return;
   if (bd->client.netwm.pid == getpid()) return;
   _pri_adj(bd->client.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",
//          bd->client.netwm.pid, e_border_name_get(bd));
}

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

static void
_e_border_client_move_resize_send(E_Border *bd)
{
   if (bd->internal_ecore_evas)
     ecore_evas_managed_move(bd->internal_ecore_evas,
                             bd->client_inset.l,
                             bd->client_inset.t);

   ecore_x_icccm_move_resize_send(bd->client.win,
                                  bd->x + bd->client_inset.l,
                                  bd->y + bd->client_inset.t,
                                  bd->client.w,
                                  bd->client.h);
}

static void
_e_border_pending_move_resize_add(E_Border *bd,
                                  int move,
                                  int resize,
                                  int x,
                                  int y,
                                  int w,
                                  int h,
                                  Eina_Bool without_border,
                                  unsigned int serial)
{
   E_Border_Pending_Move_Resize *pnd;

   pnd = E_NEW(E_Border_Pending_Move_Resize, 1);
   if (!pnd) return;
   pnd->resize = resize;
   pnd->move = move;
   pnd->without_border = without_border;
   pnd->x = x;
   pnd->y = y;
   pnd->w = w;
   pnd->h = h;
   pnd->serial = serial;
   bd->pending_move_resize = eina_list_append(bd->pending_move_resize, pnd);
}

static void
_e_border_move_internal(E_Border *bd,
                        int x,
                        int y,
                        Eina_Bool without_border)
{
   E_Event_Border_Move *ev;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   ecore_x_window_shadow_tree_flush();
   if (bd->new_client)
     {
        _e_border_pending_move_resize_add(bd, 1, 0, x, y, 0, 0, without_border, 0);
        return;
     }

   if (bd->maximized)
     {
        if ((bd->maximized & E_MAXIMIZE_DIRECTION) != E_MAXIMIZE_BOTH)
          {
             if (e_config->allow_manip)
               bd->maximized = 0;

             if ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_HORIZONTAL)
               {
                  x = bd->x;
               }
             else
             if ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_VERTICAL)
               {
                  y = bd->y;
               }
          }
        else if (e_config->allow_manip)
          bd->maximized = 0;
        else
          return;
     }

   if (without_border)
     {
        x -= bd->client_inset.l;
        y -= bd->client_inset.t;
     }
   if (bd->move_intercept_cb)
     {
        int px, py;
        px = bd->x, py = bd->y;
        bd->move_intercept_cb(bd, x, y);
        if ((bd->x == px) && (bd->y == py)) return;
     }
   else if ((x == bd->x) && (y == bd->y))
     return;
   bd->pre_res_change.valid = 0;
   bd->x = x;
   bd->y = y;
   BD_CHANGED(bd);
   bd->changes.pos = 1;
#if 0
   if (bd->client.netwm.sync.request)
     {
        bd->client.netwm.sync.wait++;
        ecore_x_netwm_sync_request_send(bd->client.win, bd->client.netwm.sync.serial++);
     }
#endif
   _e_border_client_move_resize_send(bd);
   _e_border_move_update(bd);
   ev = E_NEW(E_Event_Border_Move, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
//  e_object_breadcrumb_add(E_OBJECT(bd), "border_move_event");
   ecore_event_add(E_EVENT_BORDER_MOVE, ev, _e_border_event_border_move_free, NULL);
   _e_border_zone_update(bd);
}

/**
 * Move window to coordinates that already account border decorations.
 *
 * This call will consider given position already accounts border
 * decorations, so it will not be considered later. This will just
 * work properly with borders that have being evaluated and border
 * decorations are known (border->client_inset).
 *
 * @parm x horizontal position to place window.
 * @parm y vertical position to place window.
 *
 * @see e_border_move_without_border()
 */
EAPI void
e_border_move(E_Border *bd,
              int x,
              int y)
{
   if (bd->fullscreen)
     return;

   _e_border_move_internal(bd, x, y, 0);
}

/**
 * Set a callback which will be called just prior to updating the
 * move coordinates for a border
 */
EAPI void
e_border_move_intercept_cb_set(E_Border *bd, E_Border_Move_Intercept_Cb cb)
{
   bd->move_intercept_cb = cb;
}

/**
 * Move window to coordinates that do not account border decorations yet.
 *
 * This call will consider given position does not account border
 * decoration, so these values (border->client_inset) will be
 * accounted automatically. This is specially useful when it is a new
 * client and has not be evaluated yet, in this case
 * border->client_inset will be zeroed and no information is known. It
 * will mark pending requests so border will be accounted on
 * evalutation phase.
 *
 * @parm x horizontal position to place window.
 * @parm y vertical position to place window.
 *
 * @see e_border_move()
 */
EAPI void
e_border_move_without_border(E_Border *bd,
                             int x,
                             int y)
{
   if (bd->fullscreen)
     return;

   _e_border_move_internal(bd, x, y, 1);
}

EAPI void
e_border_center(E_Border *bd)
{
   int x, y, w, h;
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   e_zone_useful_geometry_get(bd->zone, &x, &y, &w, &h);
   e_border_move(bd, x + (w - bd->w) / 2, y + (h - bd->h) / 2);
}

EAPI void
e_border_center_pos_get(E_Border *bd,
                        int *x,
                        int *y)
{
   int zx, zy, zw, zh;
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh);
   if (x) *x = zx + (zw - bd->w) / 2;
   if (y) *y = zy + (zh - bd->h) / 2;
}

static void
_e_border_move_resize_internal(E_Border *bd,
                               int x,
                               int y,
                               int w,
                               int h,
                               Eina_Bool without_border,
                               Eina_Bool move)
{
   E_Event_Border_Move *mev;
   E_Event_Border_Resize *rev;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   ecore_x_window_shadow_tree_flush();

   if (bd->new_client)
     {
        _e_border_pending_move_resize_add(bd, move, 1, x, y, w, h, without_border, 0);
        return;
     }

   if (bd->maximized)
     {
        if ((bd->maximized & E_MAXIMIZE_DIRECTION) != E_MAXIMIZE_BOTH)
          {
             if (e_config->allow_manip)
               bd->maximized = 0;

             if ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_HORIZONTAL)
               {
                  x = bd->x;
                  w = bd->w;
               }
             else
             if ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_VERTICAL)
               {
                  y = bd->y;
                  h = bd->h;
               }
          }
        else
        if (e_config->allow_manip)
          bd->maximized = 0;
        else
          return;
     }

   if (without_border)
     {
        x -= bd->client_inset.l;
        y -= bd->client_inset.t;
        w += e_border_inset_width_get(bd);
        h += e_border_inset_height_get(bd);
     }

   if ((!move || ((x == bd->x) && (y == bd->y))) &&
       (w == bd->w) && (h == bd->h))
     return;

   bd->pre_res_change.valid = 0;
   if (move)
     {
        bd->changes.pos = 1;
        bd->x = x;
        bd->y = y;
     }
   bd->w = w;
   bd->h = h;
   bd->client.w = bd->w - e_border_inset_width_get(bd);
   bd->client.h = bd->h - e_border_inset_height_get(bd);

   if (bd->client.shaped)
     {
        bd->need_shape_merge = 1;
        bd->need_shape_export = 1;
     }
   if (bd->shaped_input)
     {
        bd->need_shape_merge = 1;
     }

   if (bd->internal_ecore_evas)
     {
        BD_CHANGED(bd);
        bd->changes.size = 1;
     }
   else
     {
        if (bdresize && bd->client.netwm.sync.request)
          {
             bd->client.netwm.sync.wait++;
             /* Don't use x and y as supplied to this function, as it is called with 0, 0
              * when no move is intended.  The border geometry is set above anyways.
              */
             _e_border_pending_move_resize_add(bd, move, 1, bd->x, bd->y, bd->w, bd->h, without_border,
                                               bd->client.netwm.sync.serial);
             ecore_x_netwm_sync_request_send(bd->client.win,
                                             bd->client.netwm.sync.serial++);
          }
        else
          {
             BD_CHANGED(bd);
             bd->changes.size = 1;
          }
     }

   _e_border_client_move_resize_send(bd);

   _e_border_resize_update(bd);
   if (move)
     {
        mev = E_NEW(E_Event_Border_Move, 1);
        mev->border = bd;
        e_object_ref(E_OBJECT(bd));
        //   e_object_breadcrumb_add(E_OBJECT(bd), "border_move_event");
        ecore_event_add(E_EVENT_BORDER_MOVE, mev, _e_border_event_border_move_free, NULL);
     }

   rev = E_NEW(E_Event_Border_Resize, 1);
   rev->border = bd;
   e_object_ref(E_OBJECT(bd));
//   e_object_breadcrumb_add(E_OBJECT(bd), "border_resize_event");
   ecore_event_add(E_EVENT_BORDER_RESIZE, rev, _e_border_event_border_resize_free, NULL);
   _e_border_zone_update(bd);
}

/**
 * Move and resize window to values that already account border decorations.
 *
 * This call will consider given values already accounts border
 * decorations, so it will not be considered later. This will just
 * work properly with borders that have being evaluated and border
 * decorations are known (border->client_inset).
 *
 * @parm x horizontal position to place window.
 * @parm y vertical position to place window.
 * @parm w horizontal window size.
 * @parm h vertical window size.
 *
 * @see e_border_move_resize_without_border()
 */
EAPI void
e_border_move_resize(E_Border *bd,
                     int x,
                     int y,
                     int w,
                     int h)
{
   if (bd->fullscreen)
     return;

   _e_border_move_resize_internal(bd, x, y, w, h, 0, 1);
}

/**
 * Move and resize window to values that do not account border decorations yet.
 *
 * This call will consider given values already accounts border
 * decorations, so it will not be considered later. This will just
 * work properly with borders that have being evaluated and border
 * decorations are known (border->client_inset).
 *
 * @parm x horizontal position to place window.
 * @parm y vertical position to place window.
 * @parm w horizontal window size.
 * @parm h vertical window size.
 *
 * @see e_border_move_resize()
 */
EAPI void
e_border_move_resize_without_border(E_Border *bd,
                                    int x,
                                    int y,
                                    int w,
                                    int h)
{
   if (bd->fullscreen)
     return;

   _e_border_move_resize_internal(bd, x, y, w, h, 1, 1);
}

/**
 * Resize window to values that already account border decorations.
 *
 * This call will consider given size already accounts border
 * decorations, so it will not be considered later. This will just
 * work properly with borders that have being evaluated and border
 * decorations are known (border->client_inset).
 *
 * @parm w horizontal window size.
 * @parm h vertical window size.
 *
 * @see e_border_resize_without_border()
 */
EAPI void
e_border_resize(E_Border *bd,
                int w,
                int h)
{
   if (bd->fullscreen)
     return;

   _e_border_move_resize_internal(bd, 0, 0, w, h, 0, 0);
}

/**
 * Resize window to values that do not account border decorations yet.
 *
 * This call will consider given size does not account border
 * decoration, so these values (border->client_inset) will be
 * accounted automatically. This is specially useful when it is a new
 * client and has not be evaluated yet, in this case
 * border->client_inset will be zeroed and no information is known. It
 * will mark pending requests so border will be accounted on
 * evalutation phase.
 *
 * @parm w horizontal window size.
 * @parm h vertical window size.
 *
 * @see e_border_resize()
 */
EAPI void
e_border_resize_without_border(E_Border *bd,
                               int w,
                               int h)
{
   if (bd->fullscreen)
     return;

   _e_border_move_resize_internal(bd, 0, 0, w, h, 1, 0);
}

EAPI void
e_border_layer_set(E_Border *bd,
                   E_Layer layer)
{
   int oldraise;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   ecore_x_window_shadow_tree_flush();

   oldraise = e_config->transient.raise;

   if (bd->fullscreen)
     {
        bd->saved.layer = layer;
        return;
     }
   bd->layer = layer;
   if (e_config->transient.layer)
     {
        E_Border *child;
        Eina_List *list = _e_border_sub_borders_new(bd);

        /* We need to set raise to one, else the child wont
         * follow to the new layer. It should be like this,
         * even if the user usually doesn't want to raise
         * the transients.
         */
        e_config->transient.raise = 1;
        EINA_LIST_FREE(list, child)
          e_border_layer_set(child, layer);
     }
   if ((!bd->modal) || (bd->modal->layer > bd->layer))
     e_border_raise(bd);
   else
     e_border_stack_below(bd, bd->modal);
   if (layer == E_LAYER_BELOW)
     e_hints_window_stacking_set(bd, E_STACKING_BELOW);
   else if (layer == E_LAYER_ABOVE)
     e_hints_window_stacking_set(bd, E_STACKING_ABOVE);
   else
     e_hints_window_stacking_set(bd, E_STACKING_NONE);
   e_config->transient.raise = oldraise;
}

EAPI void
e_border_raise(E_Border *bd)
{
   E_Event_Border_Stack *ev;
   E_Border *last = NULL, *child;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   ecore_x_window_shadow_tree_flush();

   if (e_config->transient.raise)
     {
        Eina_List *l, *l_prev;
        Eina_List *list = _e_border_sub_borders_new(bd);

        EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, child)
        {
           /* Don't stack iconic transients. If the user wants these shown,
            * thats another option.
            */
           if (!child->iconic)
             {
                if (last)
                  e_border_stack_below(child, last);
                else
                  {
                     E_Border *above;

                     /* First raise the border to find out which border we will end up above */
                     above = e_container_border_raise(child);

                     if (above)
                       {
                          /* We ended up above a border, now we must stack this border to
                           * generate the stacking event, and to check if this transient
                           * has other transients etc.
                           */
                          e_border_stack_above(child, above);
                       }
                     else
                       {
                          /* If we didn't end up above any border, we are on the bottom! */
                          e_border_lower(child);
                       }
                  }
                last = child;
             }
           list = eina_list_remove_list(list, l);
        }
     }

   ev = E_NEW(E_Event_Border_Stack, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));

   if (last)
     {
        e_container_border_stack_below(bd, last);
        ev->stack = last;
        e_object_ref(E_OBJECT(last));
        ev->type = E_STACKING_BELOW;
     }
   else
     {
        E_Border *above;

        /* If we don't have any children, raise this border */
        above = e_container_border_raise(bd);
        e_border_raise_latest_set(bd);
        if (above)
          {
             /* We ended up above a border */
             ev->stack = above;
             e_object_ref(E_OBJECT(above));
             ev->type = E_STACKING_ABOVE;
          }
        else
          {
             /* No border to raise above, same as a lower! */
             ev->stack = NULL;
             ev->type = E_STACKING_ABOVE;
          }
     }

   ecore_event_add(E_EVENT_BORDER_STACK, ev, _e_border_event_border_stack_free, NULL);
   e_remember_update(bd);
}

EAPI void
e_border_lower(E_Border *bd)
{
   E_Event_Border_Stack *ev;
   E_Border *last = NULL, *child;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   ecore_x_window_shadow_tree_flush();

   if (e_config->transient.lower)
     {
        Eina_List *l, *l_prev;
        Eina_List *list = _e_border_sub_borders_new(bd);

        EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, child)
        {
           /* Don't stack iconic transients. If the user wants these shown,
            * thats another option.
            */
           if (!child->iconic)
             {
                if (last)
                  e_border_stack_below(child, last);
                else
                  {
                     E_Border *below;

                     /* First lower the border to find out which border we will end up below */
                     below = e_container_border_lower(child);

                     if (below)
                       {
                          /* We ended up below a border, now we must stack this border to
                           * generate the stacking event, and to check if this transient
                           * has other transients etc.
                           */
                          e_border_stack_below(child, below);
                       }
                     else
                       {
                          /* If we didn't end up below any border, we are on top! */
                          e_border_raise(child);
                       }
                  }
                last = child;
             }
           list = eina_list_remove_list(list, l);
        }
     }

   ev = E_NEW(E_Event_Border_Stack, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));

   if (last)
     {
        e_container_border_stack_below(bd, last);
        ev->stack = last;
        e_object_ref(E_OBJECT(last));
        ev->type = E_STACKING_BELOW;
     }
   else
     {
        E_Border *below;

        /* If we don't have any children, lower this border */
        below = e_container_border_lower(bd);
        if (below)
          {
             /* We ended up below a border */
             ev->stack = below;
             e_object_ref(E_OBJECT(below));
             ev->type = E_STACKING_BELOW;
          }
        else
          {
             /* No border to hide under, same as a raise! */
             ev->stack = NULL;
             ev->type = E_STACKING_BELOW;
          }
     }

   ecore_event_add(E_EVENT_BORDER_STACK, ev, _e_border_event_border_stack_free, NULL);
   e_remember_update(bd);
}

EAPI void
e_border_stack_above(E_Border *bd,
                     E_Border *above)
{
   /* TODO: Should stack above allow the border to change level */
   E_Event_Border_Stack *ev;
   E_Border *last = NULL, *child;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   ecore_x_window_shadow_tree_flush();

   if (e_config->transient.raise)
     {
        Eina_List *l, *l_prev;
        Eina_List *list = _e_border_sub_borders_new(bd);

        EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, child)
        {
           /* Don't stack iconic transients. If the user wants these shown,
            * thats another option.
            */
           if (!child->iconic)
             {
                if (last)
                  e_border_stack_below(child, last);
                else
                  e_border_stack_above(child, above);
                last = child;
             }
           list = eina_list_remove_list(list, l);
        }
     }

   ev = E_NEW(E_Event_Border_Stack, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));

   if (last)
     {
        e_container_border_stack_below(bd, last);
        ev->stack = last;
        e_object_ref(E_OBJECT(last));
        ev->type = E_STACKING_BELOW;
     }
   else
     {
        e_container_border_stack_above(bd, above);
        ev->stack = above;
        e_object_ref(E_OBJECT(above));
        ev->type = E_STACKING_ABOVE;
     }

   ecore_event_add(E_EVENT_BORDER_STACK, ev, _e_border_event_border_stack_free, NULL);
   e_remember_update(bd);
}

EAPI void
e_border_stack_below(E_Border *bd,
                     E_Border *below)
{
   /* TODO: Should stack below allow the border to change level */
   E_Event_Border_Stack *ev;
   E_Border *last = NULL, *child;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   ecore_x_window_shadow_tree_flush();

   if (e_config->transient.lower)
     {
        Eina_List *l, *l_prev;
        Eina_List *list = _e_border_sub_borders_new(bd);

        EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, child)
        {
           /* Don't stack iconic transients. If the user wants these shown,
            * thats another option.
            */
           if (!child->iconic)
             {
                if (last)
                  e_border_stack_below(child, last);
                else
                  e_border_stack_below(child, below);
                last = child;
             }
           list = eina_list_remove_list(list, l);
        }
     }

   ev = E_NEW(E_Event_Border_Stack, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));

   if (last)
     {
        e_container_border_stack_below(bd, last);
        ev->stack = last;
        e_object_ref(E_OBJECT(last));
        ev->type = E_STACKING_BELOW;
     }
   else
     {
        e_container_border_stack_below(bd, below);
        ev->stack = below;
        e_object_ref(E_OBJECT(below));
        ev->type = E_STACKING_BELOW;
     }

   ecore_event_add(E_EVENT_BORDER_STACK, ev, _e_border_event_border_stack_free, NULL);
   e_remember_update(bd);
}

EAPI void
e_border_focus_latest_set(E_Border *bd)
{
   focus_stack = eina_list_remove(focus_stack, bd);
   focus_stack = eina_list_prepend(focus_stack, bd);
}

EAPI void
e_border_raise_latest_set(E_Border *bd)
{
   raise_stack = eina_list_remove(raise_stack, bd);
   raise_stack = eina_list_prepend(raise_stack, bd);
}

/*
 * Sets the focus to the given border if necessary
 * There are 3 cases of different focus_policy-configurations:
 *
 * - E_FOCUS_CLICK: just set the focus, the most simple one
 *
 * - E_FOCUS_MOUSE: focus is where the mouse is, so try to
 *   warp the pointer to the window. If this fails (because
 *   the pointer is already in the window), just set the focus.
 *
 * - E_FOCUS_SLOPPY: focus is where the mouse is or on the
 *   last window which was focused, if the mouse is on the
 *   desktop. So, we need to look if there is another window
 *   under the pointer and warp to pointer to the right
 *   one if so (also, we set the focus afterwards). In case
 *   there is no window under pointer, the pointer is on the
 *   desktop and so we just set the focus.
 *
 *
 * This function is to be called when setting the focus was not
 * explicitly triggered by the user (by moving the mouse or
 * clicking for example), but implicitly (by closing a window,
 * the last focused window should get focus).
 *
 */
EAPI void
e_border_focus_set_with_pointer(E_Border *bd)
{
#ifdef PRINT_LOTS_OF_DEBUG
   E_PRINT_BORDER_INFO(bd);
#endif
   /* note: this is here as it seems there are enough apps that do not even
    * expect us to emulate a look of focus but not actually set x input
    * focus as we do - so simply abort any focuse set on such windows */
   /* be strict about accepting focus hint */
   if ((!bd->client.icccm.accepts_focus) &&
       (!bd->client.icccm.take_focus)) return;
   if (bd->lock_focus_out) return;
   if (bd == focused) return;
   e_border_focus_set(bd, 1, 1);

   if (e_config->focus_policy == E_FOCUS_CLICK) return;
   if (!bd->visible) return;

   if (e_config->focus_policy == E_FOCUS_SLOPPY)
     {
        E_Border *pbd;
        int ret = 0;
        pbd = e_border_under_pointer_get(bd->desk, bd);
        /* Do not slide pointer when disabled (probably breaks focus
         * on sloppy/mouse focus but requested by users). */
        if (e_config->pointer_slide && pbd && (pbd != bd))
          ret = e_border_pointer_warp_to_center(bd);
        if (!ret) e_border_focus_set(bd, 1, 0);
     }
   else
     {
        if (e_config->pointer_slide && (!e_border_pointer_warp_to_center(bd)))
          e_border_focus_set(bd, 1, 0);
     }
}

EAPI void
e_border_focus_set(E_Border *bd,
                   int focus,
                   int set)
{
   E_Border *bd_unfocus = NULL;
   Eina_Bool focus_changed = EINA_FALSE;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   /* note: this is here as it seems there are enough apps that do not even
    * expect us to emulate a look of focus but not actually set x input
    * focus as we do - so simply abort any focuse set on such windows */
   /* be strict about accepting focus hint */
   if ((!bd->client.icccm.accepts_focus) &&
       (!bd->client.icccm.take_focus))
     return;
   if ((set) && (focus) && (bd->lock_focus_out)) return;

   /* dont focus an iconified window. that's silly! */
   if (focus)
     {
        if ((bd->iconic) && (!bd->deskshow))
          {
             e_border_uniconify(bd);
             if (!focus_track_frozen)
               e_border_focus_latest_set(bd);
             return;
          }
        else if (!bd->visible)
          {
             return;
          }
        /* FIXME: hack for deskflip animation:
         * dont update focus when sliding previous desk */
        else if ((!bd->sticky) &&
                 (bd->desk != e_desk_current_get(bd->desk->zone)))
          {
             return;
          }
     }

   if ((bd->modal) && (bd->modal != bd) && (bd->modal->visible))
     {
        e_border_focus_set(bd->modal, focus, set);
        return;
     }
   else if ((bd->leader) && (bd->leader->modal) && (bd->leader->modal != bd))
     {
        e_border_focus_set(bd->leader->modal, focus, set);
        return;
     }

   if (focus)
     {
        if (set)
          {
             if (bd->visible && bd->changes.visible)
               {
                  bd->want_focus = 1;
                  BD_CHANGED(bd);
               }
             else if ((!bd->focused) ||
                      (focus_next && (bd != eina_list_data_get(focus_next))))
               {
                  Eina_List *l;

                  if ((l = eina_list_data_find_list(focus_next, bd)))
                    focus_next = eina_list_promote_list(focus_next, l);
                  else
                    focus_next = eina_list_prepend(focus_next, bd);
               }
             if ((bd->client.icccm.take_focus) &&
                 (bd->client.icccm.accepts_focus))
               {
                  e_grabinput_focus(bd->client.win, E_FOCUS_METHOD_LOCALLY_ACTIVE);
                  /* TODO what if the client didn't take focus ? */
               }
             else if (!bd->client.icccm.accepts_focus)
               {
                  e_grabinput_focus(bd->client.win, E_FOCUS_METHOD_GLOBALLY_ACTIVE);
               }
             else if (!bd->client.icccm.take_focus)
               {
                  e_grabinput_focus(bd->client.win, E_FOCUS_METHOD_PASSIVE);
                  /* e_border_focus_set(bd, 1, 0); */
               }
             return;
          }

        if (!bd->focused)
          {
             if (focused) bd_unfocus = focused;
             if (focusing == bd) focusing = NULL;
             bd->focused = 1;
             focused = bd;
             if ((!e_config->allow_above_fullscreen) && (!bd_unfocus))
               {
                  Eina_List *l;
                  E_Border *bd2;

                  EINA_LIST_FOREACH(e_border_client_list(), l, bd2)
                    {
                       if ((bd2->fullscreen) &&
                           (bd2 != bd) &&
                           (bd2->zone == bd->zone) &&
                           ((bd2->desk == bd->desk) ||
                            (bd2->sticky) || (bd->sticky)))
                         {
                            Eina_Bool unfocus_is_parent = EINA_FALSE;
                            E_Border *bd_parent;

                            bd_parent = bd->parent;
                            while (bd_parent)
                              {
                                 if (bd_parent == bd2)
                                   {
                                      unfocus_is_parent = EINA_TRUE;
                                      break;
                                   }
                                 bd_parent = bd->parent;
                              }
                            if (!unfocus_is_parent)
                              e_border_unfullscreen(bd2);
                         }
                    }
               }
             focus_changed = EINA_TRUE;
          }
     }
   else
     {
        bd->want_focus = 0;
        focus_next = eina_list_remove(focus_next, bd);
        if (bd == focusing) focusing = NULL;

        if (bd->focused)
          {
             Eina_Bool wasfocused = EINA_FALSE;
             bd_unfocus = bd;

             /* should always be the case. anyway */
             if (bd == focused)
               {
                  focused = NULL;
                  wasfocused = EINA_TRUE;
               }

             if ((set) && (!focus_next) && (!focusing))
               {
                  e_grabinput_focus(bd->zone->container->bg_win,
                                    E_FOCUS_METHOD_PASSIVE);
               }
             if ((!e_config->allow_above_fullscreen) &&
                 (bd->fullscreen) && (wasfocused) &&
                 ((bd->desk == e_desk_current_get(bd->zone)) || (bd->sticky)))
               {
                  Eina_Bool have_vis_child = EINA_FALSE;
                  Eina_List *l;
                  E_Border *bd2;

                  EINA_LIST_FOREACH(e_border_client_list(), l, bd2)
                    {
                       if ((bd2 != bd) &&
                           (bd2->zone == bd->zone) &&
                           ((bd2->desk == bd->desk) ||
                            (bd2->sticky) || (bd->sticky)))
                         {
                            if (bd2->parent == bd)
                              {
                                 have_vis_child = EINA_TRUE;
                                 break;
                              }
                         }
                    }
                  if (!have_vis_child)
                    e_border_unfullscreen(bd);
               }
          }
     }

   if ((bd_unfocus) &&
       (!e_object_is_del(E_OBJECT(bd_unfocus)) &&
        (e_object_ref_get(E_OBJECT(bd_unfocus)) > 0)))
     {
        E_Event_Border_Focus_Out *ev;

        bd_unfocus->focused = 0;
        e_focus_event_focus_out(bd_unfocus);

        if (bd_unfocus->raise_timer)
          ecore_timer_del(bd_unfocus->raise_timer);
        bd_unfocus->raise_timer = NULL;

        edje_object_signal_emit(bd_unfocus->bg_object, "e,state,unfocused", "e");
        if (bd_unfocus->icon_object)
          edje_object_signal_emit(bd_unfocus->icon_object, "e,state,unfocused", "e");

        ev = E_NEW(E_Event_Border_Focus_Out, 1);
        ev->border = bd_unfocus;
        e_object_ref(E_OBJECT(bd_unfocus));

        ecore_event_add(E_EVENT_BORDER_FOCUS_OUT, ev,
                        _e_border_event_border_focus_out_free, NULL);
        if ((!e_config->allow_above_fullscreen) &&
            (bd_unfocus->fullscreen) &&
            (bd != bd_unfocus) &&
            (bd->zone == bd_unfocus->zone) &&
            ((bd->desk == bd_unfocus->desk) ||
             (bd->sticky) || (bd_unfocus->sticky)))
          {
             Eina_Bool unfocus_is_parent = EINA_FALSE;
             E_Border *bd_parent;

             bd_parent = bd->parent;
             while (bd_parent)
               {
                  if (bd_parent == bd_unfocus)
                    {
                       unfocus_is_parent = EINA_TRUE;
                       break;
                    }
                  bd_parent = bd_parent->parent;
               }
             if (!unfocus_is_parent)
               e_border_unfullscreen(bd_unfocus);
          }
     }

   if (focus_changed)
     {
        E_Event_Border_Focus_In *ev;

        e_focus_event_focus_in(bd);

        if (!focus_track_frozen)
          e_border_focus_latest_set(bd);

        e_hints_active_window_set(bd->zone->container->manager, bd);

        edje_object_signal_emit(bd->bg_object, "e,state,focused", "e");
        if (bd->icon_object)
          edje_object_signal_emit(bd->icon_object, "e,state,focused", "e");

        ev = E_NEW(E_Event_Border_Focus_In, 1);
        ev->border = bd;
        e_object_ref(E_OBJECT(bd));

        ecore_event_add(E_EVENT_BORDER_FOCUS_IN, ev,
                        _e_border_event_border_focus_in_free, NULL);
     }
}

EAPI void
e_border_shade(E_Border *bd,
               E_Direction dir)
{
   E_Event_Border_Simple *ev;
   Eina_List *l;
   E_Border *tmp;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if ((bd->shaded) || (bd->shading) || (bd->fullscreen) ||
       ((bd->maximized) && (!e_config->allow_manip))) return;
   if ((bd->client.border.name) &&
       (!strcmp("borderless", bd->client.border.name))) return;

   EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp)
     ecore_x_window_hide(tmp->win);

   ecore_x_window_shadow_tree_flush();

   bd->take_focus = 0;
   bd->shade.x = bd->x;
   bd->shade.y = bd->y;
   bd->shade.dir = dir;

   e_hints_window_shaded_set(bd, 1);
   e_hints_window_shade_direction_set(bd, dir);

   if (e_config->border_shade_animate && (!bd->new_client))
     {
        bd->shade.start = ecore_loop_time_get();
        bd->shading = 1;
        bd->changes.shading = 1;
        BD_CHANGED(bd);

        bd->shade.anim = ecore_animator_add(_e_border_shade_animator, bd);
        edje_object_signal_emit(bd->bg_object, "e,state,shading", "e");
     }
   else
     {
        Eina_Bool move = EINA_FALSE;

        if (bd->shade.dir == E_DIRECTION_UP)
          {
             bd->h = bd->client_inset.t;
          }
        else if (bd->shade.dir == E_DIRECTION_DOWN)
          {
             bd->h = bd->client_inset.t;
             bd->y = bd->y + bd->client.h;
             move = EINA_TRUE;
          }
        else if (bd->shade.dir == E_DIRECTION_LEFT)
          {
             bd->w = bd->client_inset.t;
          }
        else if (bd->shade.dir == E_DIRECTION_RIGHT)
          {
             bd->w = bd->client_inset.t;
             bd->x = bd->x + bd->client.w;
             move = EINA_TRUE;
          }

        if (bd->client.shaped)
          {
             bd->need_shape_merge = 1;
             bd->need_shape_export = 1;
          }
        if (bd->shaped_input)
          {
             bd->need_shape_merge = 1;
          }

        bd->shaded = 1;
        bd->changes.shaded = 1;
        BD_CHANGED(bd);
        edje_object_signal_emit(bd->bg_object, "e,state,shaded", "e");
        e_border_frame_recalc(bd);
        if (move)
          {
             ev = E_NEW(E_Event_Border_Simple, 1);
             ev->border = bd;
             e_object_ref(E_OBJECT(bd));
             ecore_event_add(E_EVENT_BORDER_MOVE, ev, _e_border_event_border_move_free, NULL);
             e_container_shape_move(bd->shape, bd->x, bd->y);
          }
        e_container_shape_resize(bd->shape, bd->w, bd->h);
        e_border_comp_hidden_set(bd, EINA_TRUE);
        ev = E_NEW(E_Event_Border_Simple, 1);
        ev->border = bd;
        /* The resize is added in the animator when animation complete */
        /* For non-animated, we add it immediately with the new size */
        e_object_ref(E_OBJECT(bd));
        //	     e_object_breadcrumb_add(E_OBJECT(bd), "border_resize_event");
        ecore_event_add(E_EVENT_BORDER_RESIZE, ev, _e_border_event_border_resize_free, NULL);
     }

   e_remember_update(bd);
}

EAPI void
e_border_unshade(E_Border *bd,
                 E_Direction dir)
{
   E_Event_Border_Simple *ev;
   Eina_List *l;
   E_Border *tmp;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if ((!bd->shaded) || (bd->shading))
     return;

   EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp)
     ecore_x_window_show(tmp->win);

   ecore_x_window_shadow_tree_flush();

   bd->shade.dir = dir;

   e_hints_window_shaded_set(bd, 0);
   e_hints_window_shade_direction_set(bd, dir);

   if (bd->shade.dir == E_DIRECTION_UP ||
       bd->shade.dir == E_DIRECTION_LEFT)
     {
        bd->shade.x = bd->x;
        bd->shade.y = bd->y;
     }
   else
     {
        bd->shade.x = bd->x - bd->client.w;
        bd->shade.y = bd->y - bd->client.h;
     }
   if (e_config->border_shade_animate)
     {
        bd->shade.start = ecore_loop_time_get();
        bd->shading = 1;
        bd->changes.shading = 1;
        BD_CHANGED(bd);

        bd->shade.anim = ecore_animator_add(_e_border_shade_animator, bd);
        edje_object_signal_emit(bd->bg_object, "e,state,unshading", "e");
     }
   else
     {
        Eina_Bool move = EINA_FALSE;

        if (bd->shade.dir == E_DIRECTION_UP)
          {
             bd->h = bd->client_inset.t + bd->client.h + bd->client_inset.b;
          }
        else if (bd->shade.dir == E_DIRECTION_DOWN)
          {
             bd->h = bd->client_inset.t + bd->client.h + bd->client_inset.b;
             bd->y = bd->y - bd->client.h;
             move = EINA_TRUE;
          }
        else if (bd->shade.dir == E_DIRECTION_LEFT)
          {
             bd->w = bd->client_inset.l + bd->client.w + bd->client_inset.r;
          }
        else if (bd->shade.dir == E_DIRECTION_RIGHT)
          {
             bd->w = bd->client_inset.l + bd->client.w + bd->client_inset.r;
             bd->x = bd->x - bd->client.w;
             move = EINA_TRUE;
          }
        if (bd->client.shaped)
          {
             bd->need_shape_merge = 1;
             bd->need_shape_export = 1;
          }
        if (bd->shaped_input)
          {
             bd->need_shape_merge = 1;
          }

        bd->shaded = 0;
        bd->changes.shaded = 1;
        BD_CHANGED(bd);
        edje_object_signal_emit(bd->bg_object, "e,state,unshaded", "e");
        e_border_frame_recalc(bd);
        if (move)
          {
             ev = E_NEW(E_Event_Border_Simple, 1);
             ev->border = bd;
             e_object_ref(E_OBJECT(bd));
             ecore_event_add(E_EVENT_BORDER_MOVE, ev, _e_border_event_border_move_free, NULL);
             e_container_shape_move(bd->shape, bd->x, bd->y);
          }
        e_container_shape_resize(bd->shape, bd->w, bd->h);
        e_border_comp_hidden_set(bd, EINA_FALSE);
        ev = E_NEW(E_Event_Border_Simple, 1);
        ev->border = bd;
        /* The resize is added in the animator when animation complete */
        /* For non-animated, we add it immediately with the new size */
        e_object_ref(E_OBJECT(bd));
        //	     e_object_breadcrumb_add(E_OBJECT(bd), "border_resize_event");
        ecore_event_add(E_EVENT_BORDER_RESIZE, ev, _e_border_event_border_resize_free, NULL);
     }

   e_remember_update(bd);
}

static void
_e_border_client_inset_calc(E_Border *bd)
{
   int w, h, cx, cy, cw, ch;

   if (bd->bg_object)
     {
        Evas_Object *layout;

        layout = e_comp_get(bd)->layout;
        if (layout) e_layout_freeze(layout);
        evas_object_geometry_get(bd->bg_object, NULL, NULL, &w, &h);
        evas_object_resize(bd->bg_object, MAX(w, 50), MAX(h, 50));
        edje_object_message_signal_process(bd->bg_object);
        edje_object_calc_force(bd->bg_object);
        edje_object_part_geometry_get(bd->bg_object, "e.swallow.client", &cx, &cy, &cw, &ch);
        bd->client_inset.l = cx;
        bd->client_inset.r = MAX(w, 50) - (cx + cw);
        bd->client_inset.t = cy;
        bd->client_inset.b = MAX(h, 50) - (cy + ch);
        evas_object_resize(bd->bg_object, w, h);
        if (layout) e_layout_thaw(layout);
     }
   else
     {
        bd->client_inset.l = 0;
        bd->client_inset.r = 0;
        bd->client_inset.t = 0;
        bd->client_inset.b = 0;
     }

   ecore_x_netwm_frame_size_set(bd->client.win,
                                bd->client_inset.l, bd->client_inset.r,
                                bd->client_inset.t, bd->client_inset.b);
   ecore_x_e_frame_size_set(bd->client.win,
                            bd->client_inset.l, bd->client_inset.r,
                            bd->client_inset.t, bd->client_inset.b);
   bd->client_inset.calc = 1;
}

static void
_e_border_maximize(E_Border *bd, E_Maximize max)
{
   int x1, yy1, x2, y2;
   int w, h, pw, ph;
   int zx, zy, zw, zh;

   zx = zy = zw = zh = 0;

   switch (max & E_MAXIMIZE_TYPE)
     {
      case E_MAXIMIZE_NONE:
        /* Ignore */
        break;

      case E_MAXIMIZE_FULLSCREEN:
        w = bd->zone->w;
        h = bd->zone->h;

        if (bd->bg_object)
          {
             edje_object_signal_emit(bd->bg_object, "e,action,maximize,fullscreen", "e");
             _e_border_client_inset_calc(bd);
          }
        e_border_resize_limit(bd, &w, &h);
        /* center x-direction */
        x1 = bd->zone->x + (bd->zone->w - w) / 2;
        /* center y-direction */
        yy1 = bd->zone->y + (bd->zone->h - h) / 2;

        switch (max & E_MAXIMIZE_DIRECTION)
          {
           case E_MAXIMIZE_BOTH:
             e_border_move_resize(bd, x1, yy1, w, h);
             break;

           case E_MAXIMIZE_VERTICAL:
             e_border_move_resize(bd, bd->x, yy1, bd->w, h);
             break;

           case E_MAXIMIZE_HORIZONTAL:
             e_border_move_resize(bd, x1, bd->y, w, bd->h);
             break;

           case E_MAXIMIZE_LEFT:
             e_border_move_resize(bd, bd->zone->x, bd->zone->y, w / 2, h);
             break;

           case E_MAXIMIZE_RIGHT:
             e_border_move_resize(bd, x1, bd->zone->y, w / 2, h);
             break;
          }
        break;

      case E_MAXIMIZE_SMART:
      case E_MAXIMIZE_EXPAND:
        e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh);
        w = zw, h = zh;

        if (bd->bg_object)
          {
             edje_object_signal_emit(bd->bg_object, "e,action,maximize", "e");
             _e_border_client_inset_calc(bd);
          }
        e_border_resize_limit(bd, &w, &h);

        if (bd->w < zw)
          w = bd->w;
        else
          w = zw;

        if (bd->h < zh)
          h = bd->h;
        else
          h = zh;

        if (bd->x < zx) // window left not useful coordinates
          x1 = zx;
        else if (bd->x + bd->w > zx + zw) // window right not useful coordinates
          x1 = zx + zw - bd->w;
        else // window normal position
          x1 = bd->x;

        if (bd->y < zy) // window top not useful coordinates
          yy1 = zy;
        else if (bd->y + bd->h > zy + zh) // window bottom not useful coordinates
          yy1 = zy + zh - bd->h;
        else // window normal position
          yy1 = bd->y;

        switch (max & E_MAXIMIZE_DIRECTION)
          {
           case E_MAXIMIZE_BOTH:
             e_border_move_resize(bd, zx, zy, zw, zh);
             break;

           case E_MAXIMIZE_VERTICAL:
             e_border_move_resize(bd, x1, zy, w, zh);
             break;

           case E_MAXIMIZE_HORIZONTAL:
             e_border_move_resize(bd, zx, yy1, zw, h);
             break;

           case E_MAXIMIZE_LEFT:
             e_border_move_resize(bd, zx, zy, zw / 2, zh);
             break;

           case E_MAXIMIZE_RIGHT:
             e_border_move_resize(bd, zx + zw / 2, zy, zw / 2, zh);
             break;
          }

        break;

      case E_MAXIMIZE_FILL:
        x1 = bd->zone->x;
        yy1 = bd->zone->y;
        x2 = bd->zone->x + bd->zone->w;
        y2 = bd->zone->y + bd->zone->h;

        /* walk through all shelves */
        e_maximize_border_shelf_fill(bd, &x1, &yy1, &x2, &y2, max);

        /* walk through all windows */
        e_maximize_border_border_fill(bd, &x1, &yy1, &x2, &y2, max);

        w = x2 - x1;
        h = y2 - yy1;
        pw = w;
        ph = h;
        e_border_resize_limit(bd, &w, &h);
        /* center x-direction */
        x1 = x1 + (pw - w) / 2;
        /* center y-direction */
        yy1 = yy1 + (ph - h) / 2;

        switch (max & E_MAXIMIZE_DIRECTION)
          {
           case E_MAXIMIZE_BOTH:
             e_border_move_resize(bd, x1, yy1, w, h);
             break;

           case E_MAXIMIZE_VERTICAL:
             e_border_move_resize(bd, bd->x, yy1, bd->w, h);
             break;

           case E_MAXIMIZE_HORIZONTAL:
             e_border_move_resize(bd, x1, bd->y, w, bd->h);
             break;

           case E_MAXIMIZE_LEFT:
             e_border_move_resize(bd, bd->zone->x, bd->zone->y, w / 2, h);
             break;

           case E_MAXIMIZE_RIGHT:
             e_border_move_resize(bd, x1, bd->zone->y, w / 2, h);
             break;
          }
        break;
     }
}

EAPI void
e_border_maximize(E_Border *bd,
                  E_Maximize max)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   if (!(max & E_MAXIMIZE_DIRECTION)) max |= E_MAXIMIZE_BOTH;

   if ((bd->shaded) || (bd->shading)) return;
   ecore_x_window_shadow_tree_flush();
   if (bd->fullscreen)
     e_border_unfullscreen(bd);
   /* Only allow changes in vertical/ horizontal maximization */
   if (((bd->maximized & E_MAXIMIZE_DIRECTION) == (max & E_MAXIMIZE_DIRECTION)) ||
       ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_BOTH)) return;
   if (bd->new_client)
     {
        bd->need_maximize = 1;
        bd->maximized &= ~E_MAXIMIZE_TYPE;
        bd->maximized |= max;
        return;
     }

   bd->pre_res_change.valid = 0;
   if (!(bd->maximized & E_MAXIMIZE_HORIZONTAL))
     {
        /* Horizontal hasn't been set */
        bd->saved.x = bd->x - bd->zone->x;
        bd->saved.w = bd->w;
     }
   if (!(bd->maximized & E_MAXIMIZE_VERTICAL))
     {
        /* Vertical hasn't been set */
        bd->saved.y = bd->y - bd->zone->y;
        bd->saved.h = bd->h;
     }

   bd->saved.zone = bd->zone->num;
   e_hints_window_size_set(bd);

   e_border_raise(bd);

   _e_border_maximize(bd, max);

   /* Remove previous type */
   bd->maximized &= ~E_MAXIMIZE_TYPE;
   /* Add new maximization. It must be added, so that VERTICAL + HORIZONTAL == BOTH */
   bd->maximized |= max;

   if ((bd->maximized & E_MAXIMIZE_DIRECTION) > E_MAXIMIZE_BOTH)
     /* left/right maximize */
     e_hints_window_maximized_set(bd, 0,
                                  ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_LEFT) ||
                                  ((bd->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_RIGHT));
   else
     e_hints_window_maximized_set(bd, bd->maximized & E_MAXIMIZE_HORIZONTAL,
                                  bd->maximized & E_MAXIMIZE_VERTICAL);
   e_remember_update(bd);
}

EAPI void
e_border_unmaximize(E_Border *bd,
                    E_Maximize max)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (!(max & E_MAXIMIZE_DIRECTION))
     {
        CRI("BUG: Unmaximize call without direction!");
        return;
     }

   if ((bd->shaded) || (bd->shading)) return;
   ecore_x_window_shadow_tree_flush();
   /* Remove directions not used */
   max &= (bd->maximized & E_MAXIMIZE_DIRECTION);
   /* Can only remove existing maximization directions */
   if (!max) return;
   if (bd->maximized & E_MAXIMIZE_TYPE)
     {
        bd->pre_res_change.valid = 0;
        bd->need_maximize = 0;

        if ((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN)
          {
             if (bd->bg_object)
               {
                  edje_object_signal_emit(bd->bg_object, "e,action,unmaximize,fullscreen", "e");
                  _e_border_client_inset_calc(bd);
               }

             bd->maximized = E_MAXIMIZE_NONE;
             _e_border_move_resize_internal(bd,
                                            bd->zone->x + bd->saved.x,
                                            bd->zone->y + bd->saved.y,
                                            bd->saved.w, bd->saved.h, 0, 1);
             bd->saved.x = bd->saved.y = bd->saved.w = bd->saved.h = 0;
             e_hints_window_size_unset(bd);
          }
        else
          {
             int w, h, x, y;

             w = bd->w;
             h = bd->h;
             x = bd->x;
             y = bd->y;

             if (((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_SMART) ||
                 ((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_EXPAND))
               {
                  if (bd->bg_object)
                    {
                       edje_object_signal_emit(bd->bg_object, "e,action,unmaximize,fullscreen", "e");
                       _e_border_client_inset_calc(bd);
                    }
               }
             if (max & E_MAXIMIZE_VERTICAL)
               {
                  /* Remove vertical */
                  h = bd->saved.h;
                  y = bd->saved.y + bd->zone->y;
                  bd->saved.h = bd->saved.y = 0;
                  bd->maximized &= ~E_MAXIMIZE_VERTICAL;
                  bd->maximized &= ~E_MAXIMIZE_LEFT;
                  bd->maximized &= ~E_MAXIMIZE_RIGHT;
               }
             if (max & E_MAXIMIZE_HORIZONTAL)
               {
                  /* Remove horizontal */
                  w = bd->saved.w;
                  x = bd->saved.x + bd->zone->x;
                  bd->saved.w = bd->saved.x = 0;
                  bd->maximized &= ~E_MAXIMIZE_HORIZONTAL;
               }

             e_border_resize_limit(bd, &w, &h);

             if (!(bd->maximized & E_MAXIMIZE_DIRECTION))
               {
                  bd->maximized = E_MAXIMIZE_NONE;
                  _e_border_move_resize_internal(bd, x, y, w, h, 0, 1);
                  e_hints_window_size_unset(bd);
                  edje_object_signal_emit(bd->bg_object, "e,action,unmaximize", "e");
               }
             else
               {
                  _e_border_move_resize_internal(bd, x, y, w, h, 0, 1);
                  e_hints_window_size_set(bd);
               }
          }
        e_hints_window_maximized_set(bd, bd->maximized & E_MAXIMIZE_HORIZONTAL,
                                     bd->maximized & E_MAXIMIZE_VERTICAL);
     }
   e_remember_update(bd);
}

EAPI void
e_border_fullscreen(E_Border *bd,
                    E_Fullscreen policy)
{
   E_Event_Border_Fullscreen *ev;
   int x, y, w, h;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   if ((bd->shaded) || (bd->shading)) return;
   ecore_x_window_shadow_tree_flush();
   if (bd->new_client)
     {
        bd->need_fullscreen = 1;
        return;
     }
   if (!bd->fullscreen)
     {
        bd->pre_res_change.valid = 0;

        if (bd->maximized)
          {
             x = bd->saved.x;
             y = bd->saved.y;
             w = bd->saved.w;
             h = bd->saved.h;
          }
        else
          {
             bd->saved.x = bd->x - bd->zone->x;
             bd->saved.y = bd->y - bd->zone->y;
             bd->saved.w = bd->client.w;
             bd->saved.h = bd->client.h;
          }
        bd->saved.maximized = bd->maximized;
        bd->saved.zone = bd->zone->num;

        if (bd->maximized)
          {
             e_border_unmaximize(bd, E_MAXIMIZE_BOTH);
             bd->saved.x = x;
             bd->saved.y = y;
             bd->saved.w = w;
             bd->saved.h = h;
          }
        e_hints_window_size_set(bd);

        bd->client_inset.l = 0;
        bd->client_inset.r = 0;
        bd->client_inset.t = 0;
        bd->client_inset.b = 0;

        bd->desk->fullscreen_borders++;

        /* e_zone_fullscreen_set(bd->zone, 1); */
        bd->saved.layer = bd->layer;
        if (!e_config->allow_above_fullscreen)
          e_border_layer_set(bd, E_LAYER_FULLSCREEN);
        else if (e_config->mode.presentation)
          e_border_layer_set(bd, E_LAYER_TOP);

        if ((eina_list_count(bd->zone->container->zones) > 1) ||
            (policy == E_FULLSCREEN_RESIZE) || (!ecore_x_randr_query()))
          {
             e_border_move_resize(bd, bd->zone->x, bd->zone->y, bd->zone->w, bd->zone->h);
          }
        else if (policy == E_FULLSCREEN_ZOOM)
          {
             Ecore_X_Randr_Screen_Size_MM *sizes;
             int num_sizes, i, best_size_index = 0;

             ecore_x_randr_screen_primary_output_current_size_get(bd->zone->container->manager->root,
                                                                  &screen_size.width,
                                                                  &screen_size.height,
                                                                  NULL, NULL, NULL);
             sizes = ecore_x_randr_screen_primary_output_sizes_get(bd->zone->container->manager->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 > bd->w) && (sizes[i].height > bd->h))
                         {
                            dist = (sizes[i].width * sizes[i].height) - (bd->w * bd->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(bd->zone->container->manager->root,
                                                                        best_size_index))
                         screen_size_index = best_size_index;
                       e_border_move_resize(bd, 0, 0, best_size.width, best_size.height);
                    }
                  else
                    {
                       screen_size.width = -1;
                       screen_size.height = -1;
                       e_border_move_resize(bd, 0, 0, bd->zone->w, bd->zone->h);
                    }
                  free(sizes);
               }
             else
               e_border_move_resize(bd, bd->zone->x, bd->zone->y, bd->zone->w, bd->zone->h);
          }
        bd->fullscreen = 1;

        e_hints_window_fullscreen_set(bd, 1);
        e_hints_window_size_unset(bd);
        bd->client.border.changed = 1;
        BD_CHANGED(bd);
     }
   bd->fullscreen_policy = policy;
   _e_border_shadow(bd);

   ev = E_NEW(E_Event_Border_Fullscreen, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
   //   e_object_breadcrumb_add(E_OBJECT(bd), "border_fullscreen_event");
   ecore_event_add(E_EVENT_BORDER_FULLSCREEN, ev, _e_border_event_border_fullscreen_free, NULL);

   e_remember_update(bd);
}

EAPI void
e_border_unfullscreen(E_Border *bd)
{
   E_Event_Border_Unfullscreen *ev;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if ((bd->shaded) || (bd->shading)) return;
   ecore_x_window_shadow_tree_flush();
   if (bd->fullscreen)
     {
        bd->pre_res_change.valid = 0;
        bd->fullscreen = 0;
        bd->need_fullscreen = 0;
        bd->desk->fullscreen_borders--;

        if ((screen_size.width != -1) && (screen_size.height != -1))
          {
             ecore_x_randr_screen_primary_output_size_set(bd->zone->container->manager->root,
                                                          screen_size_index);
             screen_size.width = -1;
             screen_size.height = -1;
          }
        _e_border_move_resize_internal(bd,
                                       bd->zone->x + bd->saved.x,
                                       bd->zone->y + bd->saved.y,
                                       bd->saved.w, bd->saved.h, 0, 1);

        if (bd->saved.maximized)
          e_border_maximize(bd, (e_config->maximize_policy & E_MAXIMIZE_TYPE) |
                            bd->saved.maximized);

        e_border_layer_set(bd, bd->saved.layer);

        e_hints_window_fullscreen_set(bd, 0);
        bd->client.border.changed = 1;
        BD_CHANGED(bd);
     }
   bd->fullscreen_policy = 0;
   _e_border_shadow(bd);

   ev = E_NEW(E_Event_Border_Unfullscreen, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
   //   e_object_breadcrumb_add(E_OBJECT(bd), "border_unfullscreen_event");
   ecore_event_add(E_EVENT_BORDER_UNFULLSCREEN, ev, _e_border_event_border_unfullscreen_free, NULL);

   e_remember_update(bd);
}

EAPI void
e_border_iconify(E_Border *bd)
{
   E_Event_Border_Iconify *ev;
   unsigned int iconic;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (bd->shading) return;
   ecore_x_window_shadow_tree_flush();
   if (!bd->iconic)
     {
        bd->iconic = 1;
        bd->take_focus = 0;
        e_border_hide(bd, 1);
        if (bd->fullscreen) bd->desk->fullscreen_borders--;
        edje_object_signal_emit(bd->bg_object, "e,action,iconify", "e");
     }
   iconic = 1;
   e_hints_window_iconic_set(bd);
   ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MAPPED, &iconic, 1);

   ev = E_NEW(E_Event_Border_Iconify, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
//   e_object_breadcrumb_add(E_OBJECT(bd), "border_iconify_event");
   ecore_event_add(E_EVENT_BORDER_ICONIFY, ev, _e_border_event_border_iconify_free, NULL);

   if (e_config->transient.iconify)
     {
        E_Border *child;
        Eina_List *list = _e_border_sub_borders_new(bd);

        EINA_LIST_FREE(list, child)
          e_border_iconify(child);
     }
   e_remember_update(bd);
}

EAPI void
e_border_uniconify(E_Border *bd)
{
   E_Desk *desk;
   E_Event_Border_Uniconify *ev;
   unsigned int iconic;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (bd->shading) return;
   ecore_x_window_shadow_tree_flush();
   e_border_show(bd);
   if (bd->iconic)
     {
        bd->iconic = 0;
        if (bd->fullscreen) bd->desk->fullscreen_borders++;
        desk = e_desk_current_get(bd->desk->zone);
        e_border_desk_set(bd, desk);
        e_border_raise(bd);
        edje_object_signal_emit(bd->bg_object, "e,action,uniconify", "e");
     }
   iconic = 0;
   ecore_x_window_prop_card32_set(bd->client.win, E_ATOM_MAPPED, &iconic, 1);

   ev = E_NEW(E_Event_Border_Uniconify, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
//   e_object_breadcrumb_add(E_OBJECT(bd), "border_uniconify_event");
   ecore_event_add(E_EVENT_BORDER_UNICONIFY, ev, _e_border_event_border_uniconify_free, NULL);

   if (e_config->transient.iconify)
     {
        E_Border *child;
        Eina_List *list = _e_border_sub_borders_new(bd);

        EINA_LIST_FREE(list, child)
          e_border_uniconify(child);
     }
   e_remember_update(bd);
}

EAPI void
e_border_stick(E_Border *bd)
{
   E_Event_Border_Stick *ev;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (bd->sticky) return;
   bd->sticky = 1;
   e_hints_window_sticky_set(bd, 1);
   e_border_show(bd);

   if (e_config->transient.desktop)
     {
        E_Border *child;
        Eina_List *list = _e_border_sub_borders_new(bd);

        EINA_LIST_FREE(list, child)
          {
             child->sticky = 1;
             e_hints_window_sticky_set(child, 1);
             e_border_show(child);
          }
     }

   edje_object_signal_emit(bd->bg_object, "e,state,sticky", "e");
   ev = E_NEW(E_Event_Border_Stick, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
//   e_object_breadcrumb_add(E_OBJECT(bd), "border_stick_event");
   ecore_event_add(E_EVENT_BORDER_STICK, ev, _e_border_event_border_stick_free, NULL);
   e_remember_update(bd);
}

EAPI void
e_border_unstick(E_Border *bd)
{
   E_Event_Border_Unstick *ev;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   /* Set the desk before we unstick the border */
   if (!bd->sticky) return;
   bd->sticky = 0;
   e_hints_window_sticky_set(bd, 0);

   if (e_config->transient.desktop)
     {
        E_Border *child;
        Eina_List *list = _e_border_sub_borders_new(bd);

        EINA_LIST_FREE(list, child)
          {
             child->sticky = 0;
             e_hints_window_sticky_set(child, 0);
          }
     }

   edje_object_signal_emit(bd->bg_object, "e,state,unsticky", "e");
   ev = E_NEW(E_Event_Border_Unstick, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
//   e_object_breadcrumb_add(E_OBJECT(bd), "border_unstick_event");
   ecore_event_add(E_EVENT_BORDER_UNSTICK, ev, _e_border_event_border_unstick_free, NULL);

   e_border_desk_set(bd, e_desk_current_get(bd->zone));
   e_remember_update(bd);
}

EAPI void
e_border_pinned_set(E_Border *bd,
                    int set)
{
   E_Layer layer;

   if (bd)
     {
        bd->borderless = set;
        bd->user_skip_winlist = set;
        if (set)
          layer = E_LAYER_BELOW;
        else
          layer = E_LAYER_NORMAL;

        e_border_layer_set(bd, layer);

        bd->client.border.changed = 1;
        BD_CHANGED(bd);
     }
}

EAPI E_Border *
e_border_find_by_client_window(Ecore_X_Window win)
{
   E_Border *bd;

   bd = eina_hash_find(borders_hash, e_util_winid_str_get(win));
   if ((bd) && (!e_object_is_del(E_OBJECT(bd))) &&
       (bd->client.win == win))
     return bd;
#ifdef HAVE_WAYLAND_CLIENTS
   bd = e_comp_wl_border_surface_find(win);
   if (bd && (!e_object_is_del(E_OBJECT(bd)))) return bd;
#endif
   return NULL;
}

EAPI E_Border *
e_border_find_all_by_client_window(Ecore_X_Window win)
{
   E_Border *bd;

   bd = eina_hash_find(borders_hash, e_util_winid_str_get(win));
   if ((bd) && (bd->client.win == win))
     return bd;
#ifdef HAVE_WAYLAND_CLIENTS
   return e_comp_wl_border_surface_find(win);
#endif
   return NULL;
}

EAPI E_Border *
e_border_find_by_window(Ecore_X_Window win)
{
   E_Border *bd;

   bd = eina_hash_find(borders_hash, e_util_winid_str_get(win));
   if ((bd) && (!e_object_is_del(E_OBJECT(bd))) &&
       ((bd->win == win) || (bd->client.lock_win == win)))
     return bd;
   return NULL;
}

EAPI E_Border *
e_border_find_by_alarm(Ecore_X_Sync_Alarm al)
{
   Eina_List *l;
   E_Border *bd;

   EINA_LIST_FOREACH(borders, l, bd)
     {
        if ((bd) && (!e_object_is_del(E_OBJECT(bd))) &&
            (bd->client.netwm.sync.alarm == al))
          return bd;
     }
   return NULL;
}

EAPI E_Border *
e_border_focused_get(void)
{
   return focused;
}

static void
_e_border_shape_input_rectangle_set(E_Border *bd)
{
   if (!bd) return;

   if ((!bd->visible) || (!bd->shaped_input))
     {
        if (bd->visible) // not shaped input
          {
             if (!((bd->comp_hidden) || (bd->tmp_input_hidden > 0)))
               ecore_x_composite_window_events_enable(bd->win);
             else
               ecore_x_composite_window_events_disable(bd->win);
          }
        else
          {
             if (!e_comp_evas_exists(bd))
               ecore_x_composite_window_events_enable(bd->win);
             else
               ecore_x_composite_window_events_disable(bd->win);
          }
     }
}

EAPI void
e_border_idler_before(void)
{
   Eina_List *ml, *cl;
   E_Manager *man;
   E_Container *con;

   if (!borders)
     return;

   EINA_LIST_FOREACH(e_manager_list(), ml, man)
     {
        EINA_LIST_FOREACH(man->containers, cl, con)
          {
             E_Border_List *bl;
             E_Border *bd;

             // pass 1 - eval0. fetch properties on new or on change and
             // call hooks to decide what to do - maybe move/resize
             bl = e_container_border_list_first(con);
             while ((bd = e_container_border_list_next(bl)))
               {
                  if (bd->changed) _e_border_eval0(bd);
               }
             e_container_border_list_free(bl);

             // layout hook - this is where a hook gets to figure out what to
             // do if anything.
             _e_border_container_layout_hook(con);

             // pass 2 - show windows needing show
             bl = e_container_border_list_first(con);
             while ((bd = e_container_border_list_next(bl)))
               {
                  if ((bd->changes.visible) && (bd->visible) &&
                      (!bd->new_client) && (!bd->changes.pos) &&
                      (!bd->changes.size))
                    {
                       _e_border_show(bd);
                       bd->changes.visible = 0;
                    }

                  if (bd->zone && (!bd->new_client) &&
                      (!E_INSIDE(bd->x, bd->y, 0, 0, bd->zone->w - 5, bd->zone->h - 5)) &&
                      (!E_INSIDE(bd->x, bd->y, 0 - bd->w + 5, 0 - bd->h + 5, bd->zone->w - 5, bd->zone->h - 5))
                      )
                    {
                       if (e_config->screen_limits != E_SCREEN_LIMITS_COMPLETELY)
                         _e_border_move_lost_window_to_center(bd);
                    }
               }
             e_container_border_list_free(bl);

             // pass 3 - hide windows needing hide and eval (main eval)
             bl = e_container_border_list_first(con);
             while ((bd = e_container_border_list_next(bl)))
               {
                  if (e_object_is_del(E_OBJECT(bd))) continue;

                  if ((bd->changes.visible) && (!bd->visible))
                    {
                       _e_border_hide(bd);
                       bd->changes.visible = 0;
                    }

                  if (bd->changed) _e_border_eval(bd);

                  if ((bd->changes.visible) && (bd->visible))
                    {
                       _e_border_show(bd);
                       bd->changes.visible = 0;
                    }
               }
             e_container_border_list_free(bl);
          }
     }

   if (focus_next)
     {
        E_Border *bd = NULL, *bd2;

        EINA_LIST_FREE(focus_next, bd2)
          if ((!bd) && (bd2->visible)) bd = bd2;

        if (!bd)
          {
             /* TODO revert focus when lost here ? */
             return;
          }
#if 0
        if (bd == focused)
          {
             /* already focused. but anyway dont be so strict, this
                fcks up illume setting focus on internal windows */
             return;
          }
#endif

        focus_time = ecore_x_current_time_get();

        focusing = bd;

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

EAPI Eina_List *
e_border_client_list(void)
{
   /* FIXME: This should be a somewhat ordered list */
   return borders;
}

static void
_e_border_show(E_Border *bd)
{
   Eina_List *l;
   E_Border *tmp;

   if (bd->post_job)
     {
        bd->post_show = 1;
        return;
     }

   if (!((bd->comp_hidden) || (bd->tmp_input_hidden > 0)))
     {
        _e_border_shape_input_rectangle_set(bd);
        // not anymore
        //	ecore_x_composite_window_events_enable(bd->win);
        ecore_x_window_ignore_set(bd->win, EINA_FALSE);
     }

   ecore_x_window_show(bd->win);

   EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp)
     ecore_x_window_show(tmp->win);
}

static void
_e_border_hide(E_Border *bd)
{
   E_Border *tmp;
   Eina_List *l;

   if (!e_comp_evas_exists(bd))
     {
        ecore_x_window_hide(bd->win);

        EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp)
          ecore_x_window_hide(tmp->win);
     }
   else
     {
        ecore_x_composite_window_events_disable(bd->win);
        ecore_x_window_ignore_set(bd->win, EINA_TRUE);
     }
}

static int
_e_border_action_input_win_del(void)
{
   if (!action_input_win)
     return 0;

   e_grabinput_release(action_input_win, action_input_win);
   action_input_win = 0;
   return 1;
}

static int
_e_border_action_input_win_new(E_Border *bd)
{
   if (!action_input_win)
     action_input_win = e_comp_get(bd)->ee_win;

   if (e_grabinput_get(action_input_win, 0, action_input_win))
     return 1;

   _e_border_action_input_win_del();
   return 0;
}

static void
_e_border_action_finish(void)
{
   _e_border_action_input_win_del();

   if (action_timer)
     {
        ecore_timer_del(action_timer);
        action_timer = NULL;
     }

   if (action_handler_key)
     {
        ecore_event_handler_del(action_handler_key);
        action_handler_key = NULL;
     }

   if (action_handler_mouse)
     {
        ecore_event_handler_del(action_handler_mouse);
        action_handler_mouse = NULL;
     }

   action_border = NULL;
}

static void
_e_border_action_init(E_Border *bd)
{
   action_orig.x = bd->x;
   action_orig.y = bd->y;
   action_orig.width = bd->w;
   action_orig.height = bd->h;

   action_border = bd;
}

static void
_e_border_action_restore_orig(E_Border *bd)
{
   if (action_border != bd)
     return;

   e_border_move_resize(bd, action_orig.x, action_orig.y, action_orig.width, action_orig.height);
}

static int
_e_border_key_down_modifier_apply(int modifier,
                                  int value)
{
   if (modifier & ECORE_EVENT_MODIFIER_CTRL)
     return value * 2;
   else if (modifier & ECORE_EVENT_MODIFIER_ALT)
     {
        value /= 2;
        if (value)
          return value;
        else
          return 1;
     }

   return value;
}

static Eina_Bool
_e_border_action_move_timeout(void *data __UNUSED__)
{
   _e_border_move_end(action_border);
   _e_border_action_finish();
   return ECORE_CALLBACK_CANCEL;
}

static void
_e_border_action_move_timeout_add(void)
{
   E_FREE_FUNC(action_timer, ecore_timer_del);
   if (e_config->border_keyboard.timeout)
     action_timer = ecore_timer_add(e_config->border_keyboard.timeout, _e_border_action_move_timeout, NULL);
}

static Eina_Bool
_e_border_move_key_down(void *data __UNUSED__,
                        int type   __UNUSED__,
                        void *event)
{
   Ecore_Event_Key *ev = event;
   int x, y;

   if (ev->event_window != action_input_win)
     return ECORE_CALLBACK_PASS_ON;
   if (!action_border)
     {
        fputs("ERROR: no action_border!\n", stderr);
        goto stop;
     }

   x = action_border->x;
   y = action_border->y;

   if ((strcmp(ev->key, "Up") == 0) || (strcmp(ev->key, "k") == 0))
     y -= _e_border_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dy, 1));
   else if ((strcmp(ev->key, "Down") == 0) || (strcmp(ev->key, "j") == 0))
     y += _e_border_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dy, 1));
   else if ((strcmp(ev->key, "Left") == 0) || (strcmp(ev->key, "h") == 0))
     x -= _e_border_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dx, 1));
   else if ((strcmp(ev->key, "Right") == 0) || (strcmp(ev->key, "l") == 0))
     x += _e_border_key_down_modifier_apply(ev->modifiers, MAX(e_config->border_keyboard.move.dx, 1));
   else if (strcmp(ev->key, "Return") == 0)
     goto stop;
   else if (strcmp(ev->key, "Escape") == 0)
     {
        _e_border_action_restore_orig(action_border);
        goto stop;
     }
   else if ((strncmp(ev->key, "Control", sizeof("Control") - 1) != 0) &&
            (strncmp(ev->key, "Alt", sizeof("Alt") - 1) != 0))
     goto stop;

   e_border_move(action_border, x, y);
   _e_border_action_move_timeout_add();

   return ECORE_CALLBACK_PASS_ON;

stop:
   _e_border_move_end(action_border);
   _e_border_action_finish();
   return ECORE_CALLBACK_DONE;
}

static Eina_Bool
_e_border_move_mouse_down(void *data __UNUSED__,
                          int type   __UNUSED__,
                          void *event)
{
   Ecore_Event_Mouse_Button *ev = event;

   if (ev->event_window != action_input_win)
     return ECORE_CALLBACK_PASS_ON;

   if (!action_border)
     fputs("ERROR: no action_border!\n", stderr);

   _e_border_move_end(action_border);
   _e_border_action_finish();
   return ECORE_CALLBACK_DONE;
}

EAPI void
e_border_act_move_keyboard(E_Border *bd)
{
   if (!bd)
     return;

   if (!_e_border_move_begin(bd))
     return;

   if (!_e_border_action_input_win_new(bd))
     {
        _e_border_move_end(bd);
        return;
     }

   _e_border_action_init(bd);
   _e_border_action_move_timeout_add();
   _e_border_move_update(bd);

   if (action_handler_key)
     ecore_event_handler_del(action_handler_key);
   action_handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_border_move_key_down, NULL);

   if (action_handler_mouse)
     ecore_event_handler_del(action_handler_mouse);
   action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_border_move_mouse_down, NULL);
}

static Eina_Bool
_e_border_action_resize_timeout(void *data __UNUSED__)
{
   _e_border_resize_end(action_border);
   _e_border_action_finish();
   return ECORE_CALLBACK_CANCEL;
}

static void
_e_border_action_resize_timeout_add(void)
{
   E_FREE_FUNC(action_timer, ecore_timer_del);
   if (e_config->border_keyboard.timeout)
     action_timer = ecore_timer_add(e_config->border_keyboard.timeout, _e_border_action_resize_timeout, NULL);
}

static Eina_Bool
_e_border_resize_key_down(void *data __UNUSED__,
                          int type   __UNUSED__,
                          void *event)
{
   Ecore_Event_Key *ev = event;
   int w, h, dx, dy;

   if (ev->event_window != action_input_win)
     return ECORE_CALLBACK_PASS_ON;
   if (!action_border)
     {
        fputs("ERROR: no action_border!\n", stderr);
        goto stop;
     }

   w = action_border->w;
   h = action_border->h;

   dx = e_config->border_keyboard.resize.dx;
   if (dx < action_border->client.icccm.step_w)
     dx = action_border->client.icccm.step_w;
   dx = _e_border_key_down_modifier_apply(ev->modifiers, dx);
   if (dx < action_border->client.icccm.step_w)
     dx = action_border->client.icccm.step_w;

   dy = e_config->border_keyboard.resize.dy;
   if (dy < action_border->client.icccm.step_h)
     dy = action_border->client.icccm.step_h;
   dy = _e_border_key_down_modifier_apply(ev->modifiers, dy);
   if (dy < action_border->client.icccm.step_h)
     dy = action_border->client.icccm.step_h;

   if ((strcmp(ev->key, "Up") == 0) || (strcmp(ev->key, "k") == 0))
     h -= dy;
   else if ((strcmp(ev->key, "Down") == 0) || (strcmp(ev->key, "j") == 0))
     h += dy;
   else if ((strcmp(ev->key, "Left") == 0) || (strcmp(ev->key, "h") == 0))
     w -= dx;
   else if ((strcmp(ev->key, "Right") == 0) || (strcmp(ev->key, "l") == 0))
     w += dx;
   else if (strcmp(ev->key, "Return") == 0)
     goto stop;
   else if (strcmp(ev->key, "Escape") == 0)
     {
        _e_border_action_restore_orig(action_border);
        goto stop;
     }
   else if ((strncmp(ev->key, "Control", sizeof("Control") - 1) != 0) &&
            (strncmp(ev->key, "Alt", sizeof("Alt") - 1) != 0))
     goto stop;

   e_border_resize_limit(action_border, &w, &h);
   e_border_resize(action_border, w, h);
   _e_border_action_resize_timeout_add();

   return ECORE_CALLBACK_PASS_ON;

stop:
   _e_border_resize_end(action_border);
   _e_border_action_finish();
   return ECORE_CALLBACK_DONE;
}

static Eina_Bool
_e_border_resize_mouse_down(void *data __UNUSED__,
                            int type   __UNUSED__,
                            void *event)
{
   Ecore_Event_Mouse_Button *ev = event;

   if (ev->event_window != action_input_win)
     return ECORE_CALLBACK_PASS_ON;

   if (!action_border)
     fputs("ERROR: no action_border!\n", stderr);

   _e_border_resize_end(action_border);
   _e_border_action_finish();
   return ECORE_CALLBACK_DONE;
}

EAPI void
e_border_act_resize_keyboard(E_Border *bd)
{
   if (!bd)
     return;

   if (!_e_border_resize_begin(bd))
     return;

   _e_border_action_init(bd);
   _e_border_action_resize_timeout_add();
   _e_border_resize_update(bd);

   if (action_handler_key)
     ecore_event_handler_del(action_handler_key);
   action_handler_key = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _e_border_resize_key_down, NULL);

   if (action_handler_mouse)
     ecore_event_handler_del(action_handler_mouse);
   action_handler_mouse = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _e_border_resize_mouse_down, NULL);
}

EAPI void
e_border_act_move_begin(E_Border *bd,
                        E_Binding_Event_Mouse_Button *ev)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if ((bd->resize_mode != E_POINTER_RESIZE_NONE) || (bd->moving)) return;
   if (!_e_border_move_begin(bd))
     return;

   if (!_e_border_action_input_win_new(bd))
     {
        _e_border_move_end(bd);
        return;
     }
   _e_border_action_init(bd);
   e_zone_edge_disable();
   bd->moving = 1;
   e_pointer_mode_push(bd, E_POINTER_MOVE);
   if (ev)
     {
        char source[256];

        snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button);
        _e_border_moveinfo_gather(bd, source);
     }
}

EAPI void
e_border_act_move_end(E_Border *bd,
                      E_Binding_Event_Mouse_Button *ev __UNUSED__)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (!bd->moving) return;
   e_zone_edge_enable();
   _e_border_move_end(bd);
   e_zone_flip_coords_handle(bd->zone, -1, -1);
   _e_border_action_finish();
}

EAPI void
e_border_act_resize_begin(E_Border *bd,
                          E_Binding_Event_Mouse_Button *ev)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (bd->lock_user_size || bd->shaded || bd->shading) return;
   if ((bd->resize_mode != E_POINTER_RESIZE_NONE) || (bd->moving)) return;
   if (!_e_border_resize_begin(bd))
     return;
   _e_border_action_init(bd);
   if (bd->mouse.current.mx < (bd->x + bd->w / 2))
     {
        if (bd->mouse.current.my < (bd->y + bd->h / 2))
          {
             bd->resize_mode = E_POINTER_RESIZE_TL;
             GRAV_SET(bd, ECORE_X_GRAVITY_SE);
          }
        else
          {
             bd->resize_mode = E_POINTER_RESIZE_BL;
             GRAV_SET(bd, ECORE_X_GRAVITY_NE);
          }
     }
   else
     {
        if (bd->mouse.current.my < (bd->y + bd->h / 2))
          {
             bd->resize_mode = E_POINTER_RESIZE_TR;
             GRAV_SET(bd, ECORE_X_GRAVITY_SW);
          }
        else
          {
             bd->resize_mode = E_POINTER_RESIZE_BR;
             GRAV_SET(bd, ECORE_X_GRAVITY_NW);
          }
     }
   e_pointer_mode_push(bd, bd->resize_mode);
   if (ev)
     {
        char source[256];

        snprintf(source, sizeof(source) - 1, "mouse,down,%i", ev->button);
        _e_border_moveinfo_gather(bd, source);
     }
}

EAPI void
e_border_act_resize_end(E_Border *bd,
                        E_Binding_Event_Mouse_Button *ev __UNUSED__)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (bd->resize_mode != E_POINTER_RESIZE_NONE)
     {
        _e_border_resize_end(bd);
        bd->changes.reset_gravity = 1;
        BD_CHANGED(bd);
     }
   _e_border_action_finish();
}

EAPI void
e_border_act_menu_begin(E_Border *bd,
                        E_Binding_Event_Mouse_Button *ev,
                        int key)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (bd->border_menu) return;
   if (ev)
     e_int_border_menu_show(bd, ev->canvas.x, ev->canvas.y, key, ev->timestamp);
   else
     {
        int x, y;

        ecore_x_pointer_xy_get(bd->zone->container->win, &x, &y);
        e_int_border_menu_show(bd, x, y, key, 0);
     }
}

EAPI void
e_border_act_close_begin(E_Border *bd)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (bd->lock_close) return;
   if (bd->client.icccm.delete_request)
     {
        bd->delete_requested = 1;
        ecore_x_window_delete_request_send(bd->client.win);
        if (bd->client.netwm.ping)
          e_border_ping(bd);
     }
   else if (e_config->kill_if_close_not_possible)
     {
        e_border_act_kill_begin(bd);
     }
}

EAPI void
e_border_act_kill_begin(E_Border *bd)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (bd->internal) return;
   if (bd->lock_close) return;
   if ((bd->client.netwm.pid > 1) && (e_config->kill_process))
     {
        kill(bd->client.netwm.pid, SIGINT);
        bd->kill_timer = ecore_timer_add(e_config->kill_timer_wait,
                                         _e_border_cb_kill_timer, bd);
     }
   else
     {
        if (!bd->internal) ecore_x_kill(bd->client.win);
     }
}

EAPI Evas_Object *
e_border_icon_add(E_Border *bd,
                  Evas *evas)
{
   Evas_Object *o;

   E_OBJECT_CHECK_RETURN(bd, NULL);
   E_OBJECT_TYPE_CHECK_RETURN(bd, E_BORDER_TYPE, NULL);

   o = NULL;
   if (bd->internal)
     {
        if (!bd->internal_icon)
          {
             o = e_icon_add(evas);
             e_util_icon_theme_set(o, "enlightenment");
          }
        else
          {
             if (!bd->internal_icon_key)
               {
                  char *ext;

                  ext = strrchr(bd->internal_icon, '.');
                  if ((ext) && ((!strcmp(ext, ".edj"))))
                    {
                       o = edje_object_add(evas);
                       if (!edje_object_file_set(o, bd->internal_icon, "icon"))
                         e_util_icon_theme_set(o, "enlightenment");
                    }
                  else if (ext)
                    {
                       o = e_icon_add(evas);
                       e_icon_file_set(o, bd->internal_icon);
                    }
                  else
                    {
                       o = e_icon_add(evas);
                       if (!e_util_icon_theme_set(o, bd->internal_icon))
                         e_util_icon_theme_set(o, "enlightenment");
                    }
               }
             else
               {
                  o = edje_object_add(evas);
                  edje_object_file_set(o, bd->internal_icon,
                                       bd->internal_icon_key);
               }
          }
        return o;
     }
   if ((e_config->use_app_icon) && (bd->icon_preference != E_ICON_PREF_USER))
     {
        if (bd->client.netwm.icons)
          {
             o = e_icon_add(evas);
             e_icon_data_set(o, bd->client.netwm.icons[0].data,
                             bd->client.netwm.icons[0].width,
                             bd->client.netwm.icons[0].height);
             e_icon_alpha_set(o, 1);
             return o;
          }
     }
   if (!o)
     {
        if ((bd->desktop) && (bd->icon_preference != E_ICON_PREF_NETWM))
          {
             o = e_icon_add(evas);
             if (o)
               {
                  e_icon_fdo_icon_set(o, bd->desktop->icon);
                  return o;
               }
          }
        else if (bd->client.netwm.icons)
          {
             o = e_icon_add(evas);
             e_icon_data_set(o, bd->client.netwm.icons[0].data,
                             bd->client.netwm.icons[0].width,
                             bd->client.netwm.icons[0].height);
             e_icon_alpha_set(o, 1);
             return o;
          }
     }

   o = e_icon_add(evas);
   e_util_icon_theme_set(o, "unknown");
   return o;
}

EAPI void
e_border_button_bindings_ungrab_all(void)
{
   Eina_List *l;
   E_Border *bd;

   EINA_LIST_FOREACH(borders, l, bd)
     {
        e_focus_setdown(bd);
        e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win);
        e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win);
     }
}

EAPI void
e_border_button_bindings_grab_all(void)
{
   Eina_List *l;
   E_Border *bd;

   EINA_LIST_FOREACH(borders, l, bd)
     {
        e_bindings_mouse_grab(E_BINDING_CONTEXT_WINDOW, bd->win);
        e_bindings_wheel_grab(E_BINDING_CONTEXT_WINDOW, bd->win);
        e_focus_setup(bd);
     }
}

EAPI Eina_List *
e_border_focus_stack_get(void)
{
   return focus_stack;
}

EAPI Eina_List *
e_border_raise_stack_get(void)
{
   return raise_stack;
}

EAPI Eina_List *
e_border_lost_windows_get(E_Zone *zone)
{
   Eina_List *list = NULL, *l;
   E_Border *bd;
   int loss_overlap = 5;

   E_OBJECT_CHECK_RETURN(zone, NULL);
   E_OBJECT_TYPE_CHECK_RETURN(zone, E_ZONE_TYPE, NULL);
   EINA_LIST_FOREACH(borders, l, bd)
     {
        if ((bd->zone != zone) ||
            (bd->zone->container != zone->container))
          continue;

        if (!E_INTERSECTS(bd->zone->x + loss_overlap,
                          bd->zone->y + loss_overlap,
                          bd->zone->w - (2 * loss_overlap),
                          bd->zone->h - (2 * loss_overlap),
                          bd->x, bd->y, bd->w, bd->h))
          {
             list = eina_list_append(list, bd);
          }
     }
   return list;
}

static void
_e_border_zones_layout_calc(E_Border *bd, int *zx, int *zy, int *zw, int *zh)
{
   int x, y, w, h;
   E_Zone *zone_above, *zone_below, *zone_left, *zone_right;

   x = bd->zone->x;
   y = bd->zone->y;
   w = bd->zone->w;
   h = bd->zone->h;

   if (eina_list_count(bd->zone->container->zones) == 1)
     {
        if (zx) *zx = x;
        if (zy) *zy = y;
        if (zw) *zw = w;
        if (zh) *zh = h;
        return;
     }

   zone_left = e_container_zone_at_point_get(bd->zone->container, (x - w + 5), y);
   zone_right = e_container_zone_at_point_get(bd->zone->container, (x + w + 5), y);
   zone_above = e_container_zone_at_point_get(bd->zone->container, x, (y - h + 5));
   zone_below = e_container_zone_at_point_get(bd->zone->container, x, (y + h + 5));

   if (!(zone_above) && (y))
     zone_above = e_container_zone_at_point_get(bd->zone->container, x, (h - 5));

   if (!(zone_left) && (x))
     zone_left = e_container_zone_at_point_get(bd->zone->container, (x - 5), y);

   if (zone_right)
     w = zone_right->x + zone_right->w;

   if (zone_left)
     w = bd->zone->x + bd->zone->w;

   if (zone_below)
     h = zone_below->y + zone_below->h;

   if (zone_above)
     h = bd->zone->y + bd->zone->h;

   if ((zone_left) && (zone_right))
     w = bd->zone->w + zone_right->x;

   if ((zone_above) && (zone_below))
     h = bd->zone->h + zone_below->y;

   if (x) x -= bd->zone->w;
   if (y) y -= bd->zone->h;

   if (zx) *zx = x > 0 ? x : 0;
   if (zy) *zy = y > 0 ? y : 0;
   if (zw) *zw = w;
   if (zh) *zh = h;
}

static void
_e_border_move_lost_window_to_center(E_Border *bd)
{
   int loss_overlap = 5;
   int zw, zh, zx, zy;

   if (bd->during_lost) return;

   _e_border_zones_layout_calc(bd, &zx, &zy, &zw, &zh);

   if (!E_INTERSECTS(zx + loss_overlap,
                     zy + loss_overlap,
                     zw - (2 * loss_overlap),
                     zh - (2 * loss_overlap),
                     bd->x, bd->y, bd->w, bd->h))
     {
        if (e_config->edge_flip_dragging)
          {
             Eina_Bool lf, rf, tf, bf;

             lf = rf = tf = bf = EINA_TRUE;

             if (bd->zone->desk_x_count <= 1) lf = rf = EINA_FALSE;
             else if (!e_config->desk_flip_wrap)
               {
                  if (bd->zone->desk_x_current == 0) lf = EINA_FALSE;
                  if (bd->zone->desk_x_current == (bd->zone->desk_x_count - 1)) rf = EINA_FALSE;
               }

             if (bd->zone->desk_y_count <= 1) tf = bf = EINA_FALSE;
             else if (!e_config->desk_flip_wrap)
               {
                  if (bd->zone->desk_y_current == 0) tf = EINA_FALSE;
                  if (bd->zone->desk_y_current == (bd->zone->desk_y_count - 1)) bf = EINA_FALSE;
               }

             if (!(lf) && (bd->x <= loss_overlap) && !(bd->zone->flip.switching))
               _e_border_reset_lost_window(bd);

             if (!(rf) && (bd->x >= (bd->zone->w - loss_overlap)) && !(bd->zone->flip.switching))
               _e_border_reset_lost_window(bd);

             if (!(tf) && (bd->y <= loss_overlap) && !(bd->zone->flip.switching))
               _e_border_reset_lost_window(bd);

             if (!(bf) && (bd->y >= (bd->zone->h - loss_overlap)) && !(bd->zone->flip.switching))
               _e_border_reset_lost_window(bd);
          }

        if (!e_config->edge_flip_dragging)
          _e_border_reset_lost_window(bd);
     }
}

static void
_e_border_reset_lost_window(E_Border *bd)
{
   E_OBJECT_CHECK(bd);

   if (bd->during_lost) return;
   bd->during_lost = EINA_TRUE;

   if (bd->iconic) e_border_uniconify(bd);
   if (!bd->moving) e_border_center(bd);

   e_border_raise(bd);
   if (!bd->lock_focus_out)
     e_border_focus_set(bd, 1, 1);

   e_border_pointer_warp_to_center(bd);
   bd->during_lost = EINA_FALSE;
}

EAPI void
e_border_ping(E_Border *bd)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (!e_config->ping_clients) return;
   bd->ping_ok = 0;
   ecore_x_netwm_ping_send(bd->client.win);
   bd->ping = ecore_loop_time_get();
   if (bd->ping_poller) ecore_poller_del(bd->ping_poller);
   bd->ping_poller = ecore_poller_add(ECORE_POLLER_CORE,
                                      e_config->ping_clients_interval,
                                      _e_border_cb_ping_poller, bd);
}

EAPI void
e_border_move_cancel(void)
{
   if (bdmove)
     {
        if (bdmove->cur_mouse_action)
          {
             E_Border *bd;

             bd = bdmove;
             e_object_ref(E_OBJECT(bd));
             if (bd->cur_mouse_action->func.end_mouse)
               bd->cur_mouse_action->func.end_mouse(E_OBJECT(bd), "", NULL);
             else if (bd->cur_mouse_action->func.end)
               bd->cur_mouse_action->func.end(E_OBJECT(bd), "");
             e_object_unref(E_OBJECT(bd->cur_mouse_action));
             bd->cur_mouse_action = NULL;
             e_object_unref(E_OBJECT(bd));
          }
        else
          _e_border_move_end(bdmove);
     }
}

EAPI void
e_border_resize_cancel(void)
{
   if (bdresize)
     {
        if (bdresize->cur_mouse_action)
          {
             E_Border *bd;

             bd = bdresize;
             e_object_ref(E_OBJECT(bd));
             if (bd->cur_mouse_action->func.end_mouse)
               bd->cur_mouse_action->func.end_mouse(E_OBJECT(bd), "", NULL);
             else if (bd->cur_mouse_action->func.end)
               bd->cur_mouse_action->func.end(E_OBJECT(bd), "");
             e_object_unref(E_OBJECT(bd->cur_mouse_action));
             bd->cur_mouse_action = NULL;
             e_object_unref(E_OBJECT(bd));
          }
        else
          {
             _e_border_resize_end(bdresize);
          }
     }
}

EAPI void
e_border_frame_recalc(E_Border *bd)
{
   int w, h;
   if (!bd->bg_object) return;

   w = bd->w, h = bd->h;
   bd->w -= e_border_inset_width_get(bd);
   bd->h -= e_border_inset_height_get(bd);

   _e_border_client_inset_calc(bd);

   bd->w += e_border_inset_width_get(bd);
   bd->h += e_border_inset_height_get(bd);

   if (bd->changes.shading || bd->changes.shaded) return;
   if ((w != bd->w) || (h != bd->h))
     {
        BD_CHANGED(bd);
        bd->changes.size = 1;
        if (bd->client.shaped)
          {
             bd->need_shape_merge = 1;
             bd->need_shape_export = 1;
          }
        if (bd->shaped_input)
          {
             bd->need_shape_merge = 1;
          }
        _e_border_client_move_resize_send(bd);
     }
}

EAPI Eina_List *
e_border_immortal_windows_get(void)
{
   Eina_List *list = NULL, *l;
   E_Border *bd;

   EINA_LIST_FOREACH(borders, l, bd)
     {
        if (bd->lock_life)
          list = eina_list_append(list, bd);
     }
   return list;
}

EAPI const char *
e_border_name_get(const E_Border *bd)
{
   E_OBJECT_CHECK_RETURN(bd, "");
   E_OBJECT_TYPE_CHECK_RETURN(bd, E_BORDER_TYPE, "");
   if (bd->client.netwm.name)
     return bd->client.netwm.name;
   else if (bd->client.icccm.title)
     return bd->client.icccm.title;
   return "";
}

EAPI void
e_border_signal_move_begin(E_Border *bd,
                           const char *sig,
                           const char *src __UNUSED__)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   if ((bd->resize_mode != E_POINTER_RESIZE_NONE) || (bd->moving)) return;
   if (!_e_border_move_begin(bd)) return;
   bd->moving = 1;
   e_pointer_mode_push(bd, E_POINTER_MOVE);
   e_zone_edge_disable();
   _e_border_moveinfo_gather(bd, sig);
   if (bd->cur_mouse_action)
     {
        if ((!bd->cur_mouse_action->func.end_mouse) &&
            (!bd->cur_mouse_action->func.end))
          bd->cur_mouse_action = NULL;
        else
          e_object_unref(E_OBJECT(bd->cur_mouse_action));
     }
   bd->cur_mouse_action = e_action_find("window_move");
   if (bd->cur_mouse_action)
     e_object_ref(E_OBJECT(bd->cur_mouse_action));
}

EAPI void
e_border_signal_move_end(E_Border *bd,
                         const char *sig __UNUSED__,
                         const char *src __UNUSED__)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (!bd->moving) return;
   e_zone_edge_enable();
   _e_border_move_end(bd);
   e_zone_flip_coords_handle(bd->zone, -1, -1);
}

EAPI int
e_border_resizing_get(E_Border *bd)
{
   E_OBJECT_CHECK_RETURN(bd, 0);
   E_OBJECT_TYPE_CHECK_RETURN(bd, E_BORDER_TYPE, 0);
   if (bd->resize_mode == E_POINTER_RESIZE_NONE) return 0;
   return 1;
}

EAPI void
e_border_signal_resize_begin(E_Border *bd,
                             const char *dir,
                             const char *sig,
                             const char *src __UNUSED__)
{
   Ecore_X_Gravity grav = ECORE_X_GRAVITY_NW;
   int resize_mode = E_POINTER_RESIZE_BR;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   if ((bd->resize_mode != E_POINTER_RESIZE_NONE) || (bd->moving)) return;
   if (!_e_border_resize_begin(bd))
     return;
   if (!strcmp(dir, "tl"))
     {
        resize_mode = E_POINTER_RESIZE_TL;
        grav = ECORE_X_GRAVITY_SE;
     }
   else if (!strcmp(dir, "t"))
     {
        resize_mode = E_POINTER_RESIZE_T;
        grav = ECORE_X_GRAVITY_S;
     }
   else if (!strcmp(dir, "tr"))
     {
        resize_mode = E_POINTER_RESIZE_TR;
        grav = ECORE_X_GRAVITY_SW;
     }
   else if (!strcmp(dir, "r"))
     {
        resize_mode = E_POINTER_RESIZE_R;
        grav = ECORE_X_GRAVITY_W;
     }
   else if (!strcmp(dir, "br"))
     {
        resize_mode = E_POINTER_RESIZE_BR;
        grav = ECORE_X_GRAVITY_NW;
     }
   else if (!strcmp(dir, "b"))
     {
        resize_mode = E_POINTER_RESIZE_B;
        grav = ECORE_X_GRAVITY_N;
     }
   else if (!strcmp(dir, "bl"))
     {
        resize_mode = E_POINTER_RESIZE_BL;
        grav = ECORE_X_GRAVITY_NE;
     }
   else if (!strcmp(dir, "l"))
     {
        resize_mode = E_POINTER_RESIZE_L;
        grav = ECORE_X_GRAVITY_E;
     }
   bd->resize_mode = resize_mode;
   e_pointer_mode_push(bd, bd->resize_mode);
   _e_border_moveinfo_gather(bd, sig);
   GRAV_SET(bd, grav);
   if (bd->cur_mouse_action)
     {
        if ((!bd->cur_mouse_action->func.end_mouse) &&
            (!bd->cur_mouse_action->func.end))
          bd->cur_mouse_action = NULL;
        else
          e_object_unref(E_OBJECT(bd->cur_mouse_action));
     }
   bd->cur_mouse_action = e_action_find("window_resize");
   if (bd->cur_mouse_action)
     e_object_ref(E_OBJECT(bd->cur_mouse_action));
}

EAPI void
e_border_signal_resize_end(E_Border *bd,
                           const char *dir __UNUSED__,
                           const char *sig __UNUSED__,
                           const char *src __UNUSED__)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);
   if (bd->resize_mode == E_POINTER_RESIZE_NONE) return;
   _e_border_resize_handle(bd);
   _e_border_resize_end(bd);
   bd->changes.reset_gravity = 1;
   BD_CHANGED(bd);
}

EAPI void
e_border_resize_limit(E_Border *bd,
                      int *w,
                      int *h)
{
   double a;
   Eina_Bool inc_h;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   inc_h = (*h - bd->h > 0);
   *w -= e_border_inset_width_get(bd);
   *h -= e_border_inset_height_get(bd);
   if (*h < 1) *h = 1;
   if (*w < 1) *w = 1;
   if ((bd->client.icccm.base_w >= 0) &&
       (bd->client.icccm.base_h >= 0))
     {
        int tw, th;

        tw = *w - bd->client.icccm.base_w;
        th = *h - bd->client.icccm.base_h;
        if (tw < 1) tw = 1;
        if (th < 1) th = 1;
        a = (double)(tw) / (double)(th);
        if ((bd->client.icccm.min_aspect != 0.0) &&
            (a < bd->client.icccm.min_aspect))
          {
             if (inc_h)
               tw = th * bd->client.icccm.min_aspect;
             else
               th = tw / bd->client.icccm.max_aspect;
             *w = tw + bd->client.icccm.base_w;
             *h = th + bd->client.icccm.base_h;
          }
        else if ((bd->client.icccm.max_aspect != 0.0) &&
                 (a > bd->client.icccm.max_aspect))
          {
             tw = th * bd->client.icccm.max_aspect;
             *w = tw + bd->client.icccm.base_w;
          }
     }
   else
     {
        a = (double)*w / (double)*h;
        if ((bd->client.icccm.min_aspect != 0.0) &&
            (a < bd->client.icccm.min_aspect))
          {
             if (inc_h)
               *w = *h * bd->client.icccm.min_aspect;
             else
               *h = *w / bd->client.icccm.min_aspect;
          }
        else if ((bd->client.icccm.max_aspect != 0.0) &&
                 (a > bd->client.icccm.max_aspect))
          *w = *h * bd->client.icccm.max_aspect;
     }
   if (bd->client.icccm.step_w > 0)
     {
        if (bd->client.icccm.base_w >= 0)
          *w = bd->client.icccm.base_w +
            (((*w - bd->client.icccm.base_w) / bd->client.icccm.step_w) *
             bd->client.icccm.step_w);
        else
          *w = bd->client.icccm.min_w +
            (((*w - bd->client.icccm.min_w) / bd->client.icccm.step_w) *
             bd->client.icccm.step_w);
     }
   if (bd->client.icccm.step_h > 0)
     {
        if (bd->client.icccm.base_h >= 0)
          *h = bd->client.icccm.base_h +
            (((*h - bd->client.icccm.base_h) / bd->client.icccm.step_h) *
             bd->client.icccm.step_h);
        else
          *h = bd->client.icccm.min_h +
            (((*h - bd->client.icccm.min_h) / bd->client.icccm.step_h) *
             bd->client.icccm.step_h);
     }

   if (*h < 1) *h = 1;
   if (*w < 1) *w = 1;

   if (*w > bd->client.icccm.max_w) *w = bd->client.icccm.max_w;
   else if (*w < bd->client.icccm.min_w)
     *w = bd->client.icccm.min_w;
   if (*h > bd->client.icccm.max_h) *h = bd->client.icccm.max_h;
   else if (*h < bd->client.icccm.min_h)
     *h = bd->client.icccm.min_h;

   *w += e_border_inset_width_get(bd);
   *h += e_border_inset_height_get(bd);
}

EAPI void 
e_border_input_object_set(E_Border *bd, Evas_Object *input_obj)
{
   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   bd->input_object = input_obj;
   if (!bd->input_object) return;

   evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_IN, 
                                  _e_border_cb_mouse_in, bd);
   evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_MOVE, 
                                  _e_border_cb_mouse_move, bd);
   evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_OUT, 
                                  _e_border_cb_mouse_out, bd);
   evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_DOWN, 
                                  _e_border_cb_mouse_down, bd);
   evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_UP, 
                                  _e_border_cb_mouse_up, bd);
   evas_object_event_callback_add(bd->input_object, EVAS_CALLBACK_MOUSE_WHEEL, 
                                  _e_border_cb_mouse_wheel, bd);

   bd->callbacks_set = EINA_TRUE;
}

/* local subsystem functions */
static void
_e_border_free(E_Border *bd)
{
#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
   if (bd->client.e.state.profile.use)
     {
        if (bd->client.e.state.profile.available_list)
          {
             int i;
             for (i = 0; i < bd->client.e.state.profile.num; i++)
               {
                  if (bd->client.e.state.profile.available_list[i])
                    {
                       eina_stringshare_del(bd->client.e.state.profile.available_list[i]);
                       bd->client.e.state.profile.available_list[i] = NULL;
                    }
               }
             E_FREE(bd->client.e.state.profile.available_list);
             bd->client.e.state.profile.available_list = NULL;
          }

        bd->client.e.state.profile.num = 0;

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

        bd->client.e.state.profile.wait_for_done = 0;
        bd->client.e.state.profile.use = 0;
     }
#endif
   if (bd->client.e.state.video_parent && bd->client.e.state.video_parent_border)
     {
        bd->client.e.state.video_parent_border->client.e.state.video_child =
          eina_list_remove
            (bd->client.e.state.video_parent_border->client.e.state.video_child,
            bd);
     }
   if (bd->client.e.state.video_child)
     {
        E_Border *tmp;

        EINA_LIST_FREE(bd->client.e.state.video_child, tmp)
          {
             tmp->client.e.state.video_parent_border = NULL;
          }
     }
   if (bd->internal_ecore_evas)
     {
        e_canvas_del(bd->internal_ecore_evas);
        ecore_evas_free(bd->internal_ecore_evas);
        bd->internal_ecore_evas = NULL;
     }
   if (bd->desktop)
     {
        efreet_desktop_free(bd->desktop);
        bd->desktop = NULL;
     }
   if (bd->post_job)
     {
        ecore_idle_enterer_del(bd->post_job);
        bd->post_job = NULL;
     }

   if ((bdresize == bd) || (bd->resize_mode != E_POINTER_RESIZE_NONE))
     _e_border_resize_end(bd);
   if (bdmove == bd)
     _e_border_move_end(bd);
   /* TODO: Other states to end before dying? */

   if (bd->cur_mouse_action)
     {
        e_object_unref(E_OBJECT(bd->cur_mouse_action));
        bd->cur_mouse_action = NULL;
     }

/*
   if (bd->dangling_ref_check)
     {
        ecore_timer_del(bd->dangling_ref_check);
        bd->dangling_ref_check = NULL;
     }
 */
   if (bd->kill_timer)
     {
        ecore_timer_del(bd->kill_timer);
        bd->kill_timer = NULL;
     }
   if (bd->ping_poller)
     {
        ecore_poller_del(bd->ping_poller);
        bd->ping_poller = NULL;
     }
   E_FREE_LIST(bd->pending_move_resize, free);

   if (bd->shade.anim) ecore_animator_del(bd->shade.anim);
   if (bd->border_menu) e_menu_deactivate(bd->border_menu);

   if (bd->border_locks_dialog)
     {
        e_object_del(E_OBJECT(bd->border_locks_dialog));
        bd->border_locks_dialog = NULL;
     }
   if (bd->border_remember_dialog)
     {
        e_object_del(E_OBJECT(bd->border_remember_dialog));
        bd->border_remember_dialog = NULL;
     }
   if (bd->border_border_dialog)
     {
        e_object_del(E_OBJECT(bd->border_border_dialog));
        bd->border_border_dialog = NULL;
     }
   if (bd->border_prop_dialog)
     {
        e_object_del(E_OBJECT(bd->border_prop_dialog));
        bd->border_prop_dialog = NULL;
     }

   e_int_border_menu_del(bd);

   if (focusing == bd)
     focusing = NULL;

   focus_next = eina_list_remove(focus_next, bd);

   if ((focused == bd) ||
       (e_grabinput_last_focus_win_get() == bd->client.win))
     {
        if ((!focus_next) && (!focusing))
          {
             e_grabinput_focus(bd->zone->container->bg_win,
                               E_FOCUS_METHOD_PASSIVE);
             e_hints_active_window_set(bd->zone->container->manager, NULL);
          }

        focused = NULL;
     }
   if (bd->remember)
     {
        E_Remember *rem;

        rem = bd->remember;
        bd->remember = NULL;
        e_remember_unuse(rem);
     }
   if (!bd->already_unparented)
     {
        ecore_x_window_reparent(bd->client.win, bd->zone->container->manager->root,
                                bd->x + bd->client_inset.l, bd->y + bd->client_inset.t);
        ecore_x_window_save_set_del(bd->client.win);
        bd->already_unparented = 1;
     }
   if (bd->group) eina_list_free(bd->group);
   bd->group = NULL;
   if (bd->transients) eina_list_free(bd->transients);
   bd->transients = NULL;
   if (bd->stick_desks) eina_list_free(bd->stick_desks);
   bd->stick_desks = NULL;
   if (bd->client.netwm.icons)
     {
        int i;
        for (i = 0; i < bd->client.netwm.num_icons; i++)
          free(bd->client.netwm.icons[i].data);
        free(bd->client.netwm.icons);
        bd->client.netwm.icons = NULL;
     }
   free(bd->client.netwm.extra_types);
   bd->client.netwm.extra_types = NULL;
   if (bd->client.border.name)
     eina_stringshare_del(bd->client.border.name);
   bd->client.border.name = NULL;
   if (bd->bordername)
     eina_stringshare_del(bd->bordername);
   bd->bordername = NULL;
   if (bd->client.icccm.name)
     eina_stringshare_del(bd->client.icccm.name);
   bd->client.icccm.name = NULL;
   if (bd->client.icccm.class)
     {
        if (bd->client.hacks.mapping_change)
          e_bindings_mapping_change_enable(EINA_TRUE);
        eina_stringshare_del(bd->client.icccm.class);
        bd->client.icccm.class = NULL;
     }
   if (bd->client.icccm.title)
     eina_stringshare_del(bd->client.icccm.title);
   bd->client.icccm.title = NULL;
   if (bd->client.icccm.icon_name)
     eina_stringshare_del(bd->client.icccm.icon_name);
   bd->client.icccm.icon_name = NULL;
   if (bd->client.icccm.machine)
     eina_stringshare_del(bd->client.icccm.machine);
   bd->client.icccm.machine = NULL;
   if (bd->client.icccm.window_role)
     eina_stringshare_del(bd->client.icccm.window_role);
   bd->client.icccm.window_role = NULL;
   
   if ((bd->client.icccm.command.argc > 0) && (bd->client.icccm.command.argv))
     {
        int i;

        for (i = 0; i < bd->client.icccm.command.argc; i++)
          free(bd->client.icccm.command.argv[i]);
        free(bd->client.icccm.command.argv);
        bd->client.icccm.command.argv = NULL;
     }
   if (bd->client.netwm.name)
     eina_stringshare_del(bd->client.netwm.name);
   bd->client.netwm.name = NULL;
   if (bd->client.netwm.icon_name)
     eina_stringshare_del(bd->client.netwm.icon_name);
   bd->client.netwm.icon_name = NULL;
   if (bd->shape) e_object_del(E_OBJECT(bd->shape));
   bd->shape = NULL;
   if (bd->internal_icon) eina_stringshare_del(bd->internal_icon);
   bd->internal_icon = NULL;
   if (bd->internal_icon_key) eina_stringshare_del(bd->internal_icon_key);
   bd->internal_icon_key = NULL;
   if (bd->icon_object) evas_object_del(bd->icon_object);
   bd->icon_object = NULL;
   evas_object_del(bd->bg_object);
   bd->bg_object = NULL;
   e_focus_setdown(bd);
   e_bindings_mouse_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win);
   e_bindings_wheel_ungrab(E_BINDING_CONTEXT_WINDOW, bd->win);
   eina_hash_del(borders_hash, e_util_winid_str_get(bd->client.win), bd);
   eina_hash_del(borders_hash, e_util_winid_str_get(bd->win), bd);
   ecore_x_window_free(bd->win);
   bd->win = 0;
   
   borders = eina_list_remove(borders, bd);
   focus_stack = eina_list_remove(focus_stack, bd);
   raise_stack = eina_list_remove(raise_stack, bd);

   e_container_border_remove(bd);
   free(bd);
}

/*
   static int
   _e_border_del_dangling_ref_check(void *data)
   {
   E_Border *bd;

   bd = data;
   printf("---\n");
   printf("EEK EEK border still around 1 second after being deleted!\n");
   printf("%p, %i, \"%s\" [\"%s\" \"%s\"]\n",
          bd, e_object_ref_get(E_OBJECT(bd)), bd->client.icccm.title,
          bd->client.icccm.name, bd->client.icccm.class);
   //   e_object_breadcrumb_debug(E_OBJECT(bd));
   printf("---\n");
   return 1;
   }
 */

static void
_e_border_shadow(E_Border *bd)
{
   if (!bd->bg_object) return;
   if (e_util_border_shadow_state_get(bd))
     edje_object_signal_emit(bd->bg_object, "e,state,shadow,on", "e");
   else
     edje_object_signal_emit(bd->bg_object, "e,state,shadow,off", "e");
}

static void
_e_border_del(E_Border *bd)
{
   E_Event_Border_Remove *ev;
   E_Border *child;

   if (bd == focused)
     {
        focused = NULL;
     }

   if (bd == focusing)
     focusing = NULL;

   focus_next = eina_list_remove(focus_next, bd);
   bd->changed = 0;

   if (bd->exe_inst)
     {
        if (bd->exe_inst->phony && (eina_list_count(bd->exe_inst->borders) == 1))
          e_exec_phony_del(bd->exe_inst);
        else
          bd->exe_inst->borders = eina_list_remove(bd->exe_inst->borders, bd);
        bd->exe_inst = NULL;
     }

   if (bd->fullscreen) bd->desk->fullscreen_borders--;

   if (bd->cur_mouse_action)
     {
        if (bd->cur_mouse_action->func.end)
          bd->cur_mouse_action->func.end(E_OBJECT(bd), "");
     }
   if (action_border == bd) _e_border_action_finish();
   e_pointer_type_pop(e_comp_get(bd)->pointer, bd, NULL);

   if (warp_timer_border == bd)
     {
        if (warp_timer) ecore_timer_del(warp_timer);
        warp_timer = NULL;
        warp_timer_border = NULL;
        e_border_focus_lock_set(EINA_FALSE);
     }

   if ((drag_border) && (drag_border->data == bd))
     {
        e_object_del(E_OBJECT(drag_border));
        drag_border = NULL;
     }
   if (bd->border_menu) e_menu_deactivate(bd->border_menu);

   if (bd->border_locks_dialog)
     {
        e_object_del(E_OBJECT(bd->border_locks_dialog));
        bd->border_locks_dialog = NULL;
     }
   if (bd->border_remember_dialog)
     {
        e_object_del(E_OBJECT(bd->border_remember_dialog));
        bd->border_remember_dialog = NULL;
     }
   if (bd->border_border_dialog)
     {
        e_object_del(E_OBJECT(bd->border_border_dialog));
        bd->border_border_dialog = NULL;
     }
   if (bd->border_prop_dialog)
     {
        e_object_del(E_OBJECT(bd->border_prop_dialog));
        bd->border_prop_dialog = NULL;
     }

   e_int_border_menu_del(bd);

   if (bd->raise_timer)
     {
        ecore_timer_del(bd->raise_timer);
        bd->raise_timer = NULL;
     }
   if ((!bd->already_unparented) && (!bd->destroyed))
     {
        ecore_x_window_reparent(bd->client.win,
                                bd->zone->container->manager->root,
                                bd->x + bd->client_inset.l,
                                bd->y + bd->client_inset.t);
        ecore_x_window_save_set_del(bd->client.win);
//	bd->client.win = 0;
     }
   bd->already_unparented = 1;

   if ((!bd->new_client) && (!stopping))
     {
        ev = E_NEW(E_Event_Border_Remove, 1);
        ev->border = bd;
        e_object_ref(E_OBJECT(bd));
        // e_object_breadcrumb_add(E_OBJECT(bd), "border_remove_event");
        ecore_event_add(E_EVENT_BORDER_REMOVE, ev, _e_border_event_border_remove_free, NULL);
     }

   if (bd->parent)
     {
        bd->parent->transients = eina_list_remove(bd->parent->transients, bd);
        if (bd->parent->modal == bd)
          {
             if (bd->parent->client.lock_win)
               {
                  eina_hash_del_by_key(borders_hash, e_util_winid_str_get(bd->parent->client.lock_win));
                  ecore_x_window_hide(bd->parent->client.lock_win);
                  ecore_x_window_free(bd->parent->client.lock_win);
                  bd->parent->client.lock_win = 0;
               }
             bd->parent->lock_close = 0;
             bd->parent->modal = NULL;
          }
        bd->parent = NULL;
     }
   EINA_LIST_FREE(bd->transients, child)
     {
        child->parent = NULL;
     }

   if (bd->leader)
     {
        bd->leader->group = eina_list_remove(bd->leader->group, bd);
        if (bd->leader->modal == bd)
          bd->leader->modal = NULL;
        bd->leader = NULL;
     }
   EINA_LIST_FREE(bd->group, child)
     {
        child->leader = NULL;
     }
}

#ifdef PRINT_LOTS_OF_DEBUG
static void
_e_border_print(E_Border *bd,
                const char *func)
{
   if (!bd) return;

   DBG("*Window Info*"
       "\tPointer: %p\n"
       "\tName: %s\n"
       "\tTitle: %s\n"
       "\tBorderless: %s\n",
       bd, bd->client.icccm.name, bd->client.icccm.title,
       bd->borderless ? "TRUE" : "FALSE");
}

#endif

static Eina_Bool
_e_border_cb_window_show_request(void *data  __UNUSED__,
                                 int ev_type __UNUSED__,
                                 void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Show_Request *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd) return ECORE_CALLBACK_PASS_ON;
   if (bd->iconic)
     {
        if (!bd->lock_client_iconify)
          e_border_uniconify(bd);
     }
   else
     {
        /* FIXME: make border "urgent" for a bit - it wants attention */
/*	e_border_show(bd); */
        if (!bd->lock_client_stacking)
          e_border_raise(bd);
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_destroy(void *data  __UNUSED__,
                            int ev_type __UNUSED__,
                            void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Destroy *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd) return ECORE_CALLBACK_PASS_ON;
   bd->destroyed = 1;
   e_object_del(E_OBJECT(bd));
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_hide(void *data  __UNUSED__,
                         int ev_type __UNUSED__,
                         void *ev)
{
   E_Border *bd = NULL;
   Ecore_X_Event_Window_Hide *e;

   e = ev;
//   printf("HIDE: %x, event %x send: %i\n", e->win, e->event_win, e->send_event);
// not interested in hide events from windows other than the window in question
   if (e->win != e->event_win)
     {
#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
        bd = e_border_find_by_client_window(e->win);
        if (!bd) return ECORE_CALLBACK_PASS_ON;
        if (!e->send_event) return ECORE_CALLBACK_PASS_ON;
        else
          {
             if (bd->zone->container->manager->root != e->event_win)
               return ECORE_CALLBACK_PASS_ON;
          }
#else
        return ECORE_CALLBACK_PASS_ON;
#endif
     }
   if (!bd) bd = e_border_find_by_client_window(e->win);
//   printf("  bd = %p\n", bd);
   if (!bd) return ECORE_CALLBACK_PASS_ON;
//   printf("  bd->ignore_first_unmap = %i\n", bd->ignore_first_unmap);
   if (bd->ignore_first_unmap > 0)
     {
        bd->ignore_first_unmap--;
        return ECORE_CALLBACK_PASS_ON;
     }
   /* Don't delete hidden or iconified windows */
   if ((bd->iconic) || (bd->await_hide_event > 0))
     {
//        printf("  Don't delete hidden or iconified windows\n");
//        printf("  bd->iconic = %i, bd->visible = %i, bd->new_client = %i, bd->await_hide_event = %i\n",
//               bd->iconic, bd->visible, bd->new_client, bd->await_hide_event);
        if (bd->await_hide_event > 0)
          {
             bd->await_hide_event--;
          }
        else
          {
//             printf("  hide really\n");
             /* Only hide the border if it is visible */
             if (bd->visible) e_border_hide(bd, 1);
          }
     }
   else
     {
//             printf("  hide2\n");

        e_border_hide(bd, 0);
        e_object_del(E_OBJECT(bd));
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_reparent(void *data  __UNUSED__,
                             int ev_type __UNUSED__,
                             void *ev    __UNUSED__)
{
#if 0
   E_Border *bd;
   Ecore_X_Event_Window_Reparent *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd) return 1;
   if (e->parent == bd->win) return 1;
   if (ecore_x_window_parent_get(e->win) == bd->win)
     {
        return 1;
     }
   e_border_hide(bd, 0);
   e_object_del(E_OBJECT(bd));
#endif
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_configure_request(void *data  __UNUSED__,
                                      int ev_type __UNUSED__,
                                      void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Configure_Request *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd)
     {
        if (e_stolen_win_get(e->win)) return ECORE_CALLBACK_PASS_ON;
        if (!e_util_container_window_find(e->win))
          ecore_x_window_configure(e->win, e->value_mask,
                                   e->x, e->y, e->w, e->h, e->border,
                                   e->abovewin, e->detail);
        return ECORE_CALLBACK_PASS_ON;
     }

   if ((e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X) ||
       (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y))
     {
        int x, y;
        int zx = 0, zy = 0, zw = 0, zh = 0;

        x = bd->x;
        y = bd->y;

        e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh);
        if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_X)
          {
             /* ignore moves (usually from wine clients)
              * which would cause the window to jump
              * by the size of the frame
              */
             if (bd->x + bd->client_inset.l == e->x)
               x = bd->x;
             else if (e_config->screen_limits == E_SCREEN_LIMITS_WITHIN)
               x = E_CLAMP(e->x, zx, zx + zw - bd->w);
             else
               x = e->x;
          }
        if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_Y)
          {
             /* ignore moves (usually from wine clients)
              * which would cause the window to jump
              * by the size of the frame
              */
             if (bd->y + bd->client_inset.t == e->y)
               y = bd->y;
             else if (e_config->screen_limits == E_SCREEN_LIMITS_WITHIN)
               y = E_CLAMP(e->y, zy, zy + zh - bd->h);
             else
               y = e->y;
          }
        if ((e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W) ||
            (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H))
          {
             int w, h;

             h = bd->h;
             w = bd->w;
             if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W)
               w = e->w + e_border_inset_width_get(bd);
             if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H)
               h = e->h + e_border_inset_height_get(bd);
             if ((!bd->lock_client_location) && (!bd->lock_client_size))
               {
                  if ((bd->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE)
                    {
                       bd->saved.x = x - bd->zone->x;
                       bd->saved.y = y - bd->zone->y;
                       bd->saved.w = w;
                       bd->saved.h = h;
                    }
                  else
                    e_border_move_resize(bd, x, y, w, h);
               }
             else if (!bd->lock_client_location)
               {
                  if ((bd->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE)
                    {
                       bd->saved.x = x - bd->zone->x;
                       bd->saved.y = y - bd->zone->y;
                    }
                  else
                    e_border_move(bd, x, y);
               }
             else if (!bd->lock_client_size)
               {
                  if ((bd->shaded) || (bd->shading))
                    {
                       int pw, ph;

                       pw = bd->client.w;
                       ph = bd->client.h;
                       if ((bd->shade.dir == E_DIRECTION_UP) ||
                           (bd->shade.dir == E_DIRECTION_DOWN))
                         {
                            e_border_resize(bd, w, bd->h);
                            bd->client.h = ph;
                         }
                       else
                         {
                            e_border_resize(bd, bd->w, h);
                            bd->client.w = pw;
                         }
                    }
                  else
                    {
                       if ((bd->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE)
                         {
                            bd->saved.w = w;
                            bd->saved.h = h;
                         }
                       else
                         e_border_resize(bd, w, h);
                    }
               }
          }
        else
          {
             if (!bd->lock_client_location)
               {
                  if ((bd->maximized & E_MAXIMIZE_TYPE) != E_MAXIMIZE_NONE)
                    {
                       bd->saved.x = x - bd->zone->x;
                       bd->saved.y = y - bd->zone->y;
                    }
                  else
                    {
                       if ((e_config->screen_limits != E_SCREEN_LIMITS_COMPLETELY) && bd->zone &&
                           (!E_INSIDE(x, y, 0, 0, bd->zone->w - 5, bd->zone->h - 5)) &&
                           (!E_INSIDE(x, y, 0 - bd->w + 5, 0 - bd->h + 5, bd->zone->w - 5, bd->zone->h - 5))
                          )
                         _e_border_move_lost_window_to_center(bd);
                       else
                         e_border_move(bd, x, y);
                    }
               }
          }
     }
   else if ((e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W) ||
            (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H))
     {
        int w, h;

        h = bd->h;
        w = bd->w;
        if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_W)
          w = e->w + e_border_inset_width_get(bd);
        if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_H)
          h = e->h + e_border_inset_height_get(bd);
        if (!bd->lock_client_size)
          {
             if ((bd->shaded) || (bd->shading))
               {
                  int pw, ph;

                  pw = bd->client.w;
                  ph = bd->client.h;
                  if ((bd->shade.dir == E_DIRECTION_UP) ||
                      (bd->shade.dir == E_DIRECTION_DOWN))
                    {
                       e_border_resize(bd, w, bd->h);
                       bd->client.h = ph;
                    }
                  else
                    {
                       e_border_resize(bd, bd->w, h);
                       bd->client.w = pw;
                    }
               }
             else
               {
                  if ((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_NONE)
                    {
                       int zx, zy, zw, zh;
                       zx = zy = zw = zh = 0;

                       /*
                        * This code does resize and move a window on a
                        * X configure request into an useful geometry.
                        * This is really useful for size jumping file dialogs.
                        */
                       e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh);

                       if (e_config->geometry_auto_resize_limit == 1)
                         {
                            if (w > zw)
                              w = zw;

                            if (h > zh)
                              h = zh;
                         }
                       e_border_resize(bd, w, h);
                    }
               }
            /* note: we USED to forcibly apply a window placement policy here
             * this is WRONG. the geometry_auto_move option is ONLY for
             * new clients, in which case we will autocorrect the positioning anyway.
             */
          }
     }
   if (!bd->lock_client_stacking)
     {
        if ((e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE) &&
            (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING))
          {
             E_Border *obd;

             if (e->detail == ECORE_X_WINDOW_STACK_ABOVE)
               {
                  obd = e_border_find_by_client_window(e->abovewin);
                  if (obd)
                    {
                       e_border_stack_above(bd, obd);
                    }
                  else
                    {
                       ecore_x_window_configure(bd->win,
                                                ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
                                                ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
                                                0, 0, 0, 0, 0,
                                                e->abovewin, ECORE_X_WINDOW_STACK_ABOVE);
                       /* FIXME: need to rebuiuld border list from current stacking */
                    }
               }
             else if (e->detail == ECORE_X_WINDOW_STACK_BELOW)
               {
                  obd = e_border_find_by_client_window(e->abovewin);
                  if (obd)
                    {
                       e_border_stack_below(bd, obd);
                    }
                  else
                    {
                       ecore_x_window_configure(bd->win,
                                                ECORE_X_WINDOW_CONFIGURE_MASK_SIBLING |
                                                ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE,
                                                0, 0, 0, 0, 0,
                                                e->abovewin, ECORE_X_WINDOW_STACK_BELOW);
                       /* FIXME: need to rebuiuld border list from current stacking */
                    }
               }
             else if (e->detail == ECORE_X_WINDOW_STACK_TOP_IF)
               {
                  /* FIXME: do */
               }
             else if (e->detail == ECORE_X_WINDOW_STACK_BOTTOM_IF)
               {
                  /* FIXME: do */
               }
             else if (e->detail == ECORE_X_WINDOW_STACK_OPPOSITE)
               {
                  /* FIXME: do */
               }
          }
        else if (e->value_mask & ECORE_X_WINDOW_CONFIGURE_MASK_STACK_MODE)
          {
             if (e->detail == ECORE_X_WINDOW_STACK_ABOVE)
               {
                  e_border_raise(bd);
               }
             else if (e->detail == ECORE_X_WINDOW_STACK_BELOW)
               {
                  e_border_lower(bd);
               }
             else if (e->detail == ECORE_X_WINDOW_STACK_TOP_IF)
               {
                  /* FIXME: do */
               }
             else if (e->detail == ECORE_X_WINDOW_STACK_BOTTOM_IF)
               {
                  /* FIXME: do */
               }
             else if (e->detail == ECORE_X_WINDOW_STACK_OPPOSITE)
               {
                  /* FIXME: do */
               }
          }
     }

   /* FIXME: need to send synthetic stacking event too as well as move/resize */
   _e_border_client_move_resize_send(bd);
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_resize_request(void *data  __UNUSED__,
                                   int ev_type __UNUSED__,
                                   void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Resize_Request *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd)
     {
        if (e_stolen_win_get(e->win)) return ECORE_CALLBACK_PASS_ON;
        ecore_x_window_resize(e->win, e->w, e->h);
        return ECORE_CALLBACK_PASS_ON;
     }
   {
      int w, h;

      w = e->w + e_border_inset_width_get(bd);
      h = e->h + e_border_inset_height_get(bd);
      if ((bd->shaded) || (bd->shading))
        {
           int pw, ph;

           pw = bd->client.w;
           ph = bd->client.h;
           if ((bd->shade.dir == E_DIRECTION_UP) ||
               (bd->shade.dir == E_DIRECTION_DOWN))
             {
                e_border_resize(bd, w, bd->h);
                bd->client.h = ph;
             }
           else
             {
                e_border_resize(bd, bd->w, h);
                bd->client.w = pw;
             }
        }
      else
        e_border_resize(bd, w, h);
   }

   _e_border_client_move_resize_send(bd);
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_gravity(void *data  __UNUSED__,
                            int ev_type __UNUSED__,
                            void *ev    __UNUSED__)
{
//   E_Border *bd;
//   Ecore_X_Event_Window_Gravity *e;

//   e = ev;
//   bd = e_border_find_by_client_window(e->win);
//   if (!bd) return 1;
   return 1;
}

static Eina_Bool
_e_border_cb_window_stack_request(void *data  __UNUSED__,
                                  int ev_type __UNUSED__,
                                  void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Stack_Request *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd)
     {
        if (e_stolen_win_get(e->win)) return ECORE_CALLBACK_PASS_ON;
        if (!e_util_container_window_find(e->win))
          {
             if (e->detail == ECORE_X_WINDOW_STACK_ABOVE)
               ecore_x_window_raise(e->win);
             else if (e->detail == ECORE_X_WINDOW_STACK_BELOW)
               ecore_x_window_lower(e->win);
          }
        return ECORE_CALLBACK_PASS_ON;
     }
   if (e->detail == ECORE_X_WINDOW_STACK_ABOVE)
     e_border_raise(bd);
   else if (e->detail == ECORE_X_WINDOW_STACK_BELOW)
     e_border_lower(bd);
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_property(void *data  __UNUSED__,
                             int ev_type __UNUSED__,
                             void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Property *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd) return ECORE_CALLBACK_PASS_ON;

   if (e->atom == ECORE_X_ATOM_WM_NAME)
     {
        if ((!bd->client.netwm.name) &&
            (!bd->client.netwm.fetch.name))
          {
             bd->client.icccm.fetch.title = 1;
             BD_CHANGED(bd);
          }
     }
   else if (e->atom == ECORE_X_ATOM_NET_WM_NAME)
     {
        bd->client.netwm.fetch.name = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_WM_CLASS)
     {
        bd->client.icccm.fetch.name_class = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_WM_ICON_NAME)
     {
        if ((!bd->client.netwm.icon_name) &&
            (!bd->client.netwm.fetch.icon_name))
          {
             bd->client.icccm.fetch.icon_name = 1;
             BD_CHANGED(bd);
          }
     }
   else if (e->atom == ECORE_X_ATOM_NET_WM_ICON_NAME)
     {
        bd->client.netwm.fetch.icon_name = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_WM_CLIENT_MACHINE)
     {
        bd->client.icccm.fetch.machine = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_WM_PROTOCOLS)
     {
        bd->client.icccm.fetch.protocol = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_WM_HINTS)
     {
        bd->client.icccm.fetch.hints = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_WM_NORMAL_HINTS)
     {
        bd->client.icccm.fetch.size_pos_hints = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_MOTIF_WM_HINTS)
     {
        /*
           if ((bd->client.netwm.type == ECORE_X_WINDOW_TYPE_UNKNOWN) &&
            (!bd->client.netwm.fetch.type))
           {
         */
        bd->client.mwm.fetch.hints = 1;
        BD_CHANGED(bd);
        /*
           }
         */
     }
   else if (e->atom == ECORE_X_ATOM_WM_TRANSIENT_FOR)
     {
        bd->client.icccm.fetch.transient_for = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_WM_CLIENT_LEADER)
     {
        bd->client.icccm.fetch.client_leader = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_WM_WINDOW_ROLE)
     {
        bd->client.icccm.fetch.window_role = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_NET_WM_ICON)
     {
        bd->client.netwm.fetch.icon = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ATM__QTOPIA_SOFT_MENU)
     {
        bd->client.qtopia.fetch.soft_menu = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ATM__QTOPIA_SOFT_MENUS)
     {
        bd->client.qtopia.fetch.soft_menus = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD_STATE)
     {
        bd->client.vkbd.fetch.state = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_VIRTUAL_KEYBOARD)
     {
        bd->client.vkbd.fetch.vkbd = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_ILLUME_CONFORMANT)
     {
        bd->client.illume.conformant.fetch.conformant = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_STATE)
     {
        bd->client.illume.quickpanel.fetch.state = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL)
     {
        bd->client.illume.quickpanel.fetch.quickpanel = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MAJOR)
     {
        bd->client.illume.quickpanel.fetch.priority.major = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_PRIORITY_MINOR)
     {
        bd->client.illume.quickpanel.fetch.priority.minor = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_ILLUME_QUICKPANEL_ZONE)
     {
        bd->client.illume.quickpanel.fetch.zone = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_ILLUME_DRAG_LOCKED)
     {
        bd->client.illume.drag.fetch.locked = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_ILLUME_DRAG)
     {
        bd->client.illume.drag.fetch.drag = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_ILLUME_WINDOW_STATE)
     {
        bd->client.illume.win_state.fetch.state = 1;
        BD_CHANGED(bd);
     }
   /*
      else if (e->atom == ECORE_X_ATOM_NET_WM_USER_TIME)
      {
        bd->client.netwm.fetch.user_time = 1;
        BD_CHANGED(bd);
      }
      else if (e->atom == ECORE_X_ATOM_NET_WM_STRUT)
      {
        bd->client.netwm.fetch.strut = 1;
        BD_CHANGED(bd);
      }
      else if (e->atom == ECORE_X_ATOM_NET_WM_STRUT_PARTIAL)
      {
        bd->client.netwm.fetch.strut = 1;
        BD_CHANGED(bd);
      }
    */
   else if (e->atom == ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER)
     {
        //printf("ECORE_X_ATOM_NET_WM_SYNC_REQUEST_COUNTER\n");
     }
   else if (e->atom == ECORE_X_ATOM_E_VIDEO_POSITION)
     {
        bd->client.e.fetch.video_position = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_VIDEO_PARENT)
     {
        bd->client.e.fetch.video_parent = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_NET_WM_STATE)
     {
        bd->client.netwm.fetch.state = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY)
     {
        if (bd->client.netwm.opacity_changed)
          bd->client.netwm.opacity_changed = 0;
        else
          {
             bd->client.netwm.fetch.opacity = 1;
             BD_CHANGED(bd);
          }
     }
#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
   else if (e->atom == ECORE_X_ATOM_E_WINDOW_PROFILE_SUPPORTED)
     {
        bd->client.e.fetch.profile = 1;
        BD_CHANGED(bd);
     }
   else if (e->atom == ECORE_X_ATOM_E_WINDOW_PROFILE_AVAILABLE_LIST)
     {
        bd->client.e.fetch.profile = 1;
        BD_CHANGED(bd);
     }
#endif
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_colormap(void *data  __UNUSED__,
                             int ev_type __UNUSED__,
                             void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Colormap *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd) return ECORE_CALLBACK_PASS_ON;
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_shape(void *data  __UNUSED__,
                          int ev_type __UNUSED__,
                          void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Shape *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);

   if (e->type == ECORE_X_SHAPE_INPUT)
     {
        if (bd)
          {
             bd->need_shape_merge = 1;
// YYY             bd->shaped_input = 1;
             bd->changes.shape_input = 1;
             BD_CHANGED(bd);
          }

        return ECORE_CALLBACK_PASS_ON;
     }

   if (bd)
     {
        bd->changes.shape = 1;
        BD_CHANGED(bd);
        return ECORE_CALLBACK_PASS_ON;
     }
   bd = e_border_find_by_window(e->win);
   if (bd)
     {
        bd->need_shape_export = 1;
        BD_CHANGED(bd);
        return ECORE_CALLBACK_PASS_ON;
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_focus_in(void *data  __UNUSED__,
                             int ev_type __UNUSED__,
                             void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Focus_In *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd) return ECORE_CALLBACK_PASS_ON;

   /* block refocus attempts on iconic windows
    * these result from iconifying a window during a grab */
   if (bd->iconic) return ECORE_CALLBACK_RENEW;
#ifdef INOUTDEBUG_FOCUS
   {
      time_t t;
      char *ct;

      const char *modes[] = {
         "MODE_NORMAL",
         "MODE_WHILE_GRABBED",
         "MODE_GRAB",
         "MODE_UNGRAB"
      };
      const char *details[] = {
         "DETAIL_ANCESTOR",
         "DETAIL_VIRTUAL",
         "DETAIL_INFERIOR",
         "DETAIL_NON_LINEAR",
         "DETAIL_NON_LINEAR_VIRTUAL",
         "DETAIL_POINTER",
         "DETAIL_POINTER_ROOT",
         "DETAIL_DETAIL_NONE"
      };
      t = time(NULL);
      ct = ctime(&t);
      ct[strlen(ct) - 1] = 0;
      DBG("FF ->IN %i 0x%x %s md=%s dt=%s\n",
          e->time,
          e->win,
          ct,
          modes[e->mode],
          details[e->detail]);

      DBG("%s cb focus in %d %d\n",
          e_border_name_get(bd),
          bd->client.icccm.accepts_focus,
          bd->client.icccm.take_focus);
   }
#endif
   _e_border_pri_raise(bd);
   if (e->mode == ECORE_X_EVENT_MODE_GRAB)
     {
        if (e->detail == ECORE_X_EVENT_DETAIL_POINTER) return ECORE_CALLBACK_PASS_ON;
     }
   else if (e->mode == ECORE_X_EVENT_MODE_UNGRAB)
     {
        /* this seems to break winlist...
        if (e->detail == ECORE_X_EVENT_DETAIL_POINTER)
        */
        return ECORE_CALLBACK_PASS_ON;
     }

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

   /* should be equal, maybe some clients dont reply with the proper timestamp ? */
   if (e->time >= focus_time)
     e_border_focus_set(bd, 1, 0);
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_focus_out(void *data  __UNUSED__,
                              int ev_type __UNUSED__,
                              void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Focus_Out *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd) return ECORE_CALLBACK_PASS_ON;
#ifdef INOUTDEBUG_FOCUS
   {
      time_t t;
      char *ct;

      const char *modes[] = {
         "MODE_NORMAL",
         "MODE_WHILE_GRABBED",
         "MODE_GRAB",
         "MODE_UNGRAB"
      };
      const char *details[] = {
         "DETAIL_ANCESTOR",
         "DETAIL_VIRTUAL",
         "DETAIL_INFERIOR",
         "DETAIL_NON_LINEAR",
         "DETAIL_NON_LINEAR_VIRTUAL",
         "DETAIL_POINTER",
         "DETAIL_POINTER_ROOT",
         "DETAIL_DETAIL_NONE"
      };
      t = time(NULL);
      ct = ctime(&t);
      ct[strlen(ct) - 1] = 0;
      DBG("FF <-OUT %i 0x%x %s md=%s dt=%s",
          e->time,
          e->win,
          ct,
          modes[e->mode],
          details[e->detail]);

      DBG("%s cb focus out %d %d",
          e_border_name_get(bd),
          bd->client.icccm.accepts_focus,
          bd->client.icccm.take_focus);
   }
#endif
   _e_border_pri_norm(bd);
   if (e->mode == ECORE_X_EVENT_MODE_NORMAL)
     {
        if (e->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
          return ECORE_CALLBACK_PASS_ON;
        else if (e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR)
          return ECORE_CALLBACK_PASS_ON;
        else if (e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL)
          return ECORE_CALLBACK_PASS_ON;
     }
   else if (e->mode == ECORE_X_EVENT_MODE_GRAB)
     {
        if (e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR)
          return ECORE_CALLBACK_PASS_ON;
        else if (e->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
          return ECORE_CALLBACK_PASS_ON;
        else if (e->detail == ECORE_X_EVENT_DETAIL_NON_LINEAR_VIRTUAL)
          return ECORE_CALLBACK_PASS_ON;
        else if (e->detail == ECORE_X_EVENT_DETAIL_ANCESTOR)
          return ECORE_CALLBACK_PASS_ON;
        else if (e->detail == ECORE_X_EVENT_DETAIL_VIRTUAL)
          return ECORE_CALLBACK_PASS_ON;
     }
   else if (e->mode == ECORE_X_EVENT_MODE_UNGRAB)
     {
        /* for firefox/thunderbird (xul) menu walking */
        /* NB: why did i disable this before? */
        if (e->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
          return ECORE_CALLBACK_PASS_ON;
        else if (e->detail == ECORE_X_EVENT_DETAIL_POINTER)
          return ECORE_CALLBACK_PASS_ON;
     }
   else if (e->mode == ECORE_X_EVENT_MODE_WHILE_GRABBED)
     {
        if (e->detail == ECORE_X_EVENT_DETAIL_ANCESTOR)
          return ECORE_CALLBACK_PASS_ON;
        else if (e->detail == ECORE_X_EVENT_DETAIL_INFERIOR)
          return ECORE_CALLBACK_PASS_ON;
     }
   e_border_focus_set(bd, 0, 0);
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_client_message(void *data  __UNUSED__, int ev_type __UNUSED__, void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Client_Message *e = ev;
   
   bd = e_border_find_by_client_window(e->win);
   if (!bd) return ECORE_CALLBACK_PASS_ON;

   if (e->message_type == ECORE_X_ATOM_NET_WM_WINDOW_OPACITY)
     {
        bd->client.netwm.fetch.opacity = 1;
        BD_CHANGED(bd);
     }
#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
   else if (e->message_type == ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE)
     {
        if (bd->client.e.state.profile.use)
          {
             char *profile;
             profile = ecore_x_atom_name_get(e->data.l[1]);
             ecore_x_e_window_profile_change_request_send(bd->client.win,
                                                          profile);
             bd->client.e.state.profile.wait_for_done = 1;
             free(profile);
          }
     }
   else if (e->message_type == ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE_DONE)
     {
        if ((bd->client.e.state.profile.use) &&
            (bd->client.e.state.profile.wait_for_done))
          {
             E_Container *con = bd->zone->container;
             E_Desk *desk = NULL;
             char *profile;

             profile = ecore_x_atom_name_get(e->data.l[1]);
             if (profile)
               eina_stringshare_replace(&bd->client.e.state.profile.name, profile);

             bd->client.e.state.profile.wait_for_done = 0;

             if (bd->desk && e_util_strcmp(bd->desk->window_profile, profile))
               {
                  desk = e_container_desk_window_profile_get(con, profile);
                  if (desk)
                    e_border_desk_set(bd, desk);
               }
             free(profile);
          }
     }
#endif

   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_state_request(void *data  __UNUSED__,
                                  int ev_type __UNUSED__,
                                  void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_State_Request *e;
   int i;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd) return ECORE_CALLBACK_PASS_ON;

   for (i = 0; i < 2; i++)
     e_hints_window_state_update(bd, e->state[i], e->action);

   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_window_move_resize_request(void *data  __UNUSED__,
                                        int ev_type __UNUSED__,
                                        void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Window_Move_Resize_Request *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (!bd) return ECORE_CALLBACK_PASS_ON;

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

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

   if (!bd->lock_user_stacking)
     e_border_raise(bd);

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

   e_object_ref(E_OBJECT(bd->cur_mouse_action));
   bd->cur_mouse_action->func.go(E_OBJECT(bd), NULL);
   switch (e->direction)
     {
      case E_POINTER_RESIZE_TL:
        bd->resize_mode = E_POINTER_RESIZE_TL;
        GRAV_SET(bd, ECORE_X_GRAVITY_SE);
        break;

      case E_POINTER_RESIZE_T:
        bd->resize_mode = E_POINTER_RESIZE_T;
        GRAV_SET(bd, ECORE_X_GRAVITY_S);
        break;

      case E_POINTER_RESIZE_TR:
        bd->resize_mode = E_POINTER_RESIZE_TR;
        GRAV_SET(bd, ECORE_X_GRAVITY_SW);
        break;

      case E_POINTER_RESIZE_R:
        bd->resize_mode = E_POINTER_RESIZE_R;
        GRAV_SET(bd, ECORE_X_GRAVITY_W);
        break;

      case E_POINTER_RESIZE_BR:
        bd->resize_mode = E_POINTER_RESIZE_BR;
        GRAV_SET(bd, ECORE_X_GRAVITY_NW);
        break;

      case E_POINTER_RESIZE_B:
        bd->resize_mode = E_POINTER_RESIZE_B;
        GRAV_SET(bd, ECORE_X_GRAVITY_N);
        break;

      case E_POINTER_RESIZE_BL:
        bd->resize_mode = E_POINTER_RESIZE_BL;
        GRAV_SET(bd, ECORE_X_GRAVITY_NE);
        break;

      case E_POINTER_RESIZE_L:
        bd->resize_mode = E_POINTER_RESIZE_L;
        GRAV_SET(bd, ECORE_X_GRAVITY_E);
        break;

      default:
        return ECORE_CALLBACK_PASS_ON;
     }

   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_desktop_change(void *data  __UNUSED__,
                            int ev_type __UNUSED__,
                            void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Desktop_Change *e;

   e = ev;
   bd = e_border_find_by_client_window(e->win);
   if (bd)
     {
        if (e->desk == 0xffffffff)
          e_border_stick(bd);
        else if ((int)e->desk < (bd->zone->desk_x_count * bd->zone->desk_y_count))
          {
             E_Desk *desk;

             desk = e_desk_at_pos_get(bd->zone, e->desk);
             if (desk)
               e_border_desk_set(bd, desk);
          }
     }
   else
     {
        ecore_x_netwm_desktop_set(e->win, e->desk);
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_sync_alarm(void *data  __UNUSED__,
                        int ev_type __UNUSED__,
                        void *ev)
{
   E_Border *bd;
   Ecore_X_Event_Sync_Alarm *e;
   unsigned int serial;

   e = ev;
   bd = e_border_find_by_alarm(e->alarm);
   if (!bd) return ECORE_CALLBACK_PASS_ON;

   if (bd->client.netwm.sync.wait)
     bd->client.netwm.sync.wait--;

   if (ecore_x_sync_counter_query(bd->client.netwm.sync.counter, &serial))
     {
        E_Border_Pending_Move_Resize *pnd = NULL;

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

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

             E_FREE(pnd);
          }

        if (pnd)
          {
             bd->x = pnd->x;
             bd->y = pnd->y;
             bd->w = pnd->w;
             bd->h = pnd->h;
             bd->client.w = bd->w - (e_border_inset_width_get(bd));
             bd->client.h = bd->h - (e_border_inset_height_get(bd));
             E_FREE(pnd);
          }
     }

   bd->changes.size = 1;
   bd->changes.pos = 1;

   _e_border_eval(bd);

   ecore_x_pointer_xy_get(e_manager_current_get()->root,
                          &bd->mouse.current.mx,
                          &bd->mouse.current.my);

   bd->client.netwm.sync.send_time = ecore_loop_time_get();
   _e_border_resize_handle(bd);

   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_efreet_cache_update(void *data  __UNUSED__,
                                 int ev_type __UNUSED__,
                                 void *ev    __UNUSED__)
{
   Eina_List *l;
   E_Border *bd;

   /* mark all borders for desktop/icon updates */
   EINA_LIST_FOREACH(borders, l, bd)
     {
        if (e_object_is_del(E_OBJECT(bd))) continue;
        if (bd->desktop)
          {
             efreet_desktop_free(bd->desktop);
             bd->desktop = NULL;
          }
        bd->changes.icon = 1;
        BD_CHANGED(bd);
     }
   /*
      e_init_status_set(_("Desktop files scan done"));
      e_init_done();
    */
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_config_icon_theme(void *data  __UNUSED__,
                               int ev_type __UNUSED__,
                               void *ev    __UNUSED__)
{
   Eina_List *l;
   E_Border *bd;

   /* mark all borders for desktop/icon updates */
   EINA_LIST_FOREACH(borders, l, bd)
     {
        bd->changes.icon = 1;
        BD_CHANGED(bd);
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_config_mode(void *data    __UNUSED__,
                         int ev_type __UNUSED__,
                         void *ev      __UNUSED__)
{
   Eina_List *l;
   E_Border *bd;

   /* move fullscreen borders above everything */
   if (e_config->mode.presentation)
     {
        EINA_LIST_FOREACH(borders, l, bd)
          {
             if ((bd->fullscreen) || (bd->need_fullscreen))
               {
                  bd->fullscreen = 0;
                  e_border_layer_set(bd, E_LAYER_TOP);
                  bd->fullscreen = 1;
               }
          }
     }
   else if (!e_config->allow_above_fullscreen)
     {
        EINA_LIST_FOREACH(borders, l, bd)
          {
             if ((bd->fullscreen) || (bd->need_fullscreen))
               {
                  bd->fullscreen = 0;
                  e_border_layer_set(bd, E_LAYER_FULLSCREEN);
                  bd->fullscreen = 1;
               }
          }
     }
   return ECORE_CALLBACK_PASS_ON;
}

static Eina_Bool
_e_border_cb_pointer_warp(void *data  __UNUSED__,
                          int ev_type __UNUSED__,
                          void *ev)
{
   E_Event_Pointer_Warp *e;

   e = ev;
   if (!bdmove) return ECORE_CALLBACK_PASS_ON;
   e_border_move(bdmove, bdmove->x + (e->curr.x - e->prev.x), bdmove->y + (e->curr.y - e->prev.y));
   return ECORE_CALLBACK_PASS_ON;
}

static void
_e_border_cb_signal_bind(void *data,
                         Evas_Object *obj __UNUSED__,
                         const char *emission,
                         const char *source)
{
   E_Border *bd;

   bd = data;
   if (e_dnd_active() || e_object_is_del(E_OBJECT(bd))) return;
   e_bindings_signal_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(bd),
                            emission, source);
}

static void
_e_border_cb_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
   Evas_Event_Mouse_In *ev = event_info;
   E_Border *bd = data;

   if (grabbed) return;
   if (focus_locked && (bd != warp_timer_border)) return;
   if (e_object_is_del(E_OBJECT(bd))) return;
   if (bd->desk && bd->desk->animate_count) return;
   bd->mouse.current.mx = ev->output.x;
   bd->mouse.current.my = ev->output.y;
   if (!bd->iconic)
     e_focus_event_mouse_in(bd);
}

static Eina_Bool
_e_border_cb_mouse_x_in(void *data EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Mouse_In *ev)
{
   E_Border *bd;

   if (grabbed) return ECORE_CALLBACK_RENEW;
   bd = e_border_find_by_window(ev->event_win);
   if (!bd) return ECORE_CALLBACK_RENEW;
   if (bd->input_object) return ECORE_CALLBACK_RENEW;
   if (focus_locked && (bd != warp_timer_border)) return ECORE_CALLBACK_RENEW;
   if (e_object_is_del(E_OBJECT(bd))) return ECORE_CALLBACK_RENEW;
   if (bd->desk && bd->desk->animate_count) return ECORE_CALLBACK_RENEW;
   bd->mouse.current.mx = ev->root.x;
   bd->mouse.current.my = ev->root.y;
   if (!bd->iconic)
     e_focus_event_mouse_in(bd);
   return ECORE_CALLBACK_RENEW;
}

static void
_e_border_cb_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
   Evas_Event_Mouse_Out *ev = event_info;
   E_Border *bd = data;

   if (grabbed) return;
   if (bd->fullscreen) return;
   if ((bd != focused) && (bd == focusing)) return;
   if (e_object_is_del(E_OBJECT(bd))) return;
   if (bd->desk && bd->desk->animate_count) return;
   if (!bd->input_object)
     if (E_INSIDE(ev->output.x, ev->output.y, bd->x, bd->y, bd->w, bd->h)) return;
   bd->mouse.current.mx = ev->output.x;
   bd->mouse.current.my = ev->output.y;
   if (!bd->iconic)
     e_focus_event_mouse_out(bd);
}

static Eina_Bool
_e_border_cb_mouse_x_out(void *data EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Mouse_Out *ev)
{
   E_Border *bd;

   if (grabbed) return ECORE_CALLBACK_RENEW;
   bd = e_border_find_by_window(ev->event_win);
   if (!bd) return ECORE_CALLBACK_RENEW;
   if (bd->input_object) return ECORE_CALLBACK_RENEW;
   if (bd->fullscreen) return ECORE_CALLBACK_RENEW;
   if ((bd != focused) && (bd == focusing)) return ECORE_CALLBACK_RENEW;
   if (e_object_is_del(E_OBJECT(bd))) return ECORE_CALLBACK_RENEW;
   if (bd->desk && bd->desk->animate_count) return ECORE_CALLBACK_RENEW;
   if (E_INSIDE(ev->root.x, ev->root.y, bd->x, bd->y, bd->w, bd->h)) 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;
   bd->mouse.current.mx = ev->root.x;
   bd->mouse.current.my = ev->root.y;
   if (!bd->iconic)
     e_focus_event_mouse_out(bd);
   return ECORE_CALLBACK_RENEW;
}

static void
_e_border_cb_mouse_wheel_helper(E_Border *bd, Evas_Point *output, E_Binding_Event_Wheel *ev)
{
   bd->mouse.current.mx = output->x;
   bd->mouse.current.my = output->y;
   if (!bd->cur_mouse_action)
     {
        e_bindings_wheel_event_handle(E_BINDING_CONTEXT_WINDOW,
                                      E_OBJECT(bd), ev);
     }
}

static Eina_Bool
_e_border_cb_mouse_x_wheel(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Wheel *ev)
{
   E_Border *bd;
   E_Binding_Event_Wheel ev2;

   if (action_border)
     bd = action_border;
   else
     {
        bd = e_border_find_by_client_window(ev->window);
        if (!bd) bd = e_border_find_by_window(ev->window);
        if (!bd) return ECORE_CALLBACK_RENEW;
        /* event_window here should be bd->win if it isn't the same as window, not sure if this can NOT happen */
        if ((ev->window != ev->event_window) && (bd->win != ev->event_window) && (bd->client.lock_win != ev->event_window))
          return ECORE_CALLBACK_RENEW;
     }
   e_bindings_ecore_event_mouse_wheel_convert(ev, &ev2);
   _e_border_cb_mouse_wheel_helper(bd, (Evas_Point*)&ev->root, &ev2);
   return ECORE_CALLBACK_RENEW;
}

static void
_e_border_cb_mouse_wheel(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
   Evas_Event_Mouse_Wheel *ev = event_info;
   E_Border *bd = data;
   E_Binding_Event_Wheel ev2;

   if (action_border) return; // already existing border doing something
   e_bindings_evas_event_mouse_wheel_convert(ev, &ev2);
   _e_border_cb_mouse_wheel_helper(bd, &ev->output, &ev2);
}

static void
_e_border_cb_mouse_down_helper(E_Border *bd, int button, Evas_Point *output, E_Binding_Event_Mouse_Button *ev)
{
   if ((button >= 1) && (button <= 3))
     {
        bd->mouse.last_down[button - 1].mx = output->x;
        bd->mouse.last_down[button - 1].my = output->y;
        bd->mouse.last_down[button - 1].x = bd->x;
        bd->mouse.last_down[button - 1].y = bd->y;
        bd->mouse.last_down[button - 1].w = bd->w;
        bd->mouse.last_down[button - 1].h = bd->h;
     }
   else
     {
        bd->moveinfo.down.x = bd->x;
        bd->moveinfo.down.y = bd->y;
        bd->moveinfo.down.w = bd->w;
        bd->moveinfo.down.h = bd->h;
     }
   bd->mouse.current.mx = output->x;
   bd->mouse.current.my = output->y;
   if (!bd->cur_mouse_action)
     {
        bd->cur_mouse_action =
          e_bindings_mouse_down_event_handle(E_BINDING_CONTEXT_WINDOW,
                                             E_OBJECT(bd), ev);
        if (bd->cur_mouse_action)
          {
             if ((!bd->cur_mouse_action->func.end_mouse) &&
                 (!bd->cur_mouse_action->func.end))
               bd->cur_mouse_action = NULL;
             if (bd->cur_mouse_action)
               e_object_ref(E_OBJECT(bd->cur_mouse_action));
          }
     }
   e_focus_event_mouse_down(bd);
   if ((button >= 1) && (button <= 3))
     {
        bd->mouse.last_down[button - 1].mx = output->x;
        bd->mouse.last_down[button - 1].my = output->y;
        bd->mouse.last_down[button - 1].x = bd->x;
        bd->mouse.last_down[button - 1].y = bd->y;
        bd->mouse.last_down[button - 1].w = bd->w;
        bd->mouse.last_down[button - 1].h = bd->h;
     }
   else
     {
        bd->moveinfo.down.x = bd->x;
        bd->moveinfo.down.y = bd->y;
        bd->moveinfo.down.w = bd->w;
        bd->moveinfo.down.h = bd->h;
     }
   bd->mouse.current.mx = output->x;
   bd->mouse.current.my = output->y;
/*
   if (bd->moving)
     {
     }
   else if (bd->resize_mode != E_POINTER_RESIZE_NONE)
     {
     }
   else
 */
}

static Eina_Bool
_e_border_cb_mouse_x_down(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev)
{
   E_Border *bd;
   E_Binding_Event_Mouse_Button ev2;

   if (action_border)
     bd = action_border;
   else
     {
        bd = e_border_find_by_client_window(ev->window);
        if (!bd) bd = e_border_find_by_window(ev->window);
        if (!bd) return ECORE_CALLBACK_RENEW;
        /* event_window here should be bd->win if it isn't the same as window, not sure if this can NOT happen */
        if ((ev->window != ev->event_window) && (bd->win != ev->event_window) && (bd->client.lock_win != ev->event_window))
          return ECORE_CALLBACK_RENEW;
     }
   e_bindings_ecore_event_mouse_button_convert(ev, &ev2);
   _e_border_cb_mouse_down_helper(bd, ev->buttons, (Evas_Point*)&ev->root, &ev2);
   return ECORE_CALLBACK_RENEW;
}

static void
_e_border_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
   Evas_Event_Mouse_Down *ev = event_info;
   E_Border *bd = data;
   E_Binding_Event_Mouse_Button ev2;

   if (action_border) return; // already existing border doing something
   e_bindings_evas_event_mouse_button_convert(ev, &ev2);
   _e_border_cb_mouse_down_helper(bd, ev->button, &ev->output, &ev2);
}

static void
_e_border_cb_mouse_up_helper(E_Border *bd, int button, Evas_Point *output, E_Binding_Event_Mouse_Button* ev)
{
   if ((button >= 1) && (button <= 3))
     {
        bd->mouse.last_up[button - 1].mx = output->x;
        bd->mouse.last_up[button - 1].my = output->y;
        bd->mouse.last_up[button - 1].x = bd->x;
        bd->mouse.last_up[button - 1].y = bd->y;
     }
   bd->mouse.current.mx = output->x;
   bd->mouse.current.my = output->y;
   /* also we dont pass the same params that went in - then again that */
   /* should be ok as we are just ending the action if it has an end */
   if (bd->cur_mouse_action)
     {
        if (bd->cur_mouse_action->func.end_mouse)
          bd->cur_mouse_action->func.end_mouse(E_OBJECT(bd), "", ev);
        else if (bd->cur_mouse_action->func.end)
          bd->cur_mouse_action->func.end(E_OBJECT(bd), "");
        e_object_unref(E_OBJECT(bd->cur_mouse_action));
        bd->cur_mouse_action = NULL;
     }
   else
     {
        if (!e_bindings_mouse_up_event_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(bd), ev))
          e_focus_event_mouse_up(bd);
     }
   if ((button >= 1) && (button <= 3))
     {
        bd->mouse.last_up[button - 1].mx = output->x;
        bd->mouse.last_up[button - 1].my = output->y;
        bd->mouse.last_up[button - 1].x = bd->x;
        bd->mouse.last_up[button - 1].y = bd->y;
     }

   bd->drag.start = 0;
}

static Eina_Bool
_e_border_cb_mouse_x_up(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev)
{
   E_Border *bd;
   E_Binding_Event_Mouse_Button ev2;

   if (action_border)
     bd = action_border;
   else
     {
        bd = e_border_find_by_client_window(ev->window);
        if (!bd) bd = e_border_find_by_window(ev->window);
        if (!bd) return ECORE_CALLBACK_RENEW;
        /* event_window here should be bd->win if it isn't the same as window, not sure if this can NOT happen */
        if ((ev->window != ev->event_window) && (bd->win != ev->event_window) && (bd->client.lock_win != ev->event_window))
          return ECORE_CALLBACK_RENEW;
     }
   e_bindings_ecore_event_mouse_button_convert(ev, &ev2);
   _e_border_cb_mouse_up_helper(bd, ev->buttons, (Evas_Point*)&ev->root, &ev2);
   return ECORE_CALLBACK_RENEW;
}

static void
_e_border_cb_mouse_up(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
   Evas_Event_Mouse_Down *ev = event_info;
   E_Border *bd = data;
   E_Binding_Event_Mouse_Button ev2;

   if (action_border) return; // already existing border doing something
   e_bindings_evas_event_mouse_button_convert(ev, &ev2);
   _e_border_cb_mouse_up_helper(bd, ev->button, &ev->output, &ev2);
}

static void
_e_border_stay_within_container(E_Border *bd, int x, int y, int *new_x, int *new_y)
{
   int new_x_max, new_y_max;
   int zw, zh;
   Eina_Bool lw, lh;

   _e_border_zones_layout_calc(bd, NULL, NULL, &zw, &zh);

   new_x_max = zw - bd->w;
   new_y_max = zh - bd->h;
   lw = bd->w > zw ? EINA_TRUE : EINA_FALSE;
   lh = bd->h > zh ? EINA_TRUE : EINA_FALSE;

   if (lw)
     {
        if (x <= new_x_max)
          *new_x = new_x_max;
        else if (x >= 0)
          *new_x = 0;
     }
   else
     {
        if (x >= new_x_max)
          *new_x = new_x_max;
        else if (x <= 0)
          *new_x = 0;
     }

   if (lh)
     {
        if (y <= new_y_max)
          *new_y = new_y_max;
        else if (y >= 0)
          *new_y = 0;
     }
   else
     {
        if (y >= new_y_max)
          *new_y = new_y_max;
        else if (y <= 0)
          *new_y = 0;
     }
}

static void
_e_border_cb_mouse_move_helper(E_Border *bd, Evas_Point *output)
{

   bd->mouse.current.mx = output->x;
   bd->mouse.current.my = output->y;
   if (bd->moving)
     {
        int x, y, new_x, new_y;
        int new_w, new_h;
        Eina_List *skiplist = NULL;
#if 0
        // FIXME: remove? sync what for when only moving?
        if ((ecore_loop_time_get() - bd->client.netwm.sync.time) > 0.5)
          bd->client.netwm.sync.wait = 0;
        if ((bd->client.netwm.sync.request) &&
            (bd->client.netwm.sync.alarm) &&
            (bd->client.netwm.sync.wait > 1)) return;
#endif
        if ((bd->moveinfo.down.button >= 1) && (bd->moveinfo.down.button <= 3))
          {
             x = bd->mouse.last_down[bd->moveinfo.down.button - 1].x +
               (bd->mouse.current.mx - bd->moveinfo.down.mx);
             y = bd->mouse.last_down[bd->moveinfo.down.button - 1].y +
               (bd->mouse.current.my - bd->moveinfo.down.my);
          }
        else
          {
             x = bd->moveinfo.down.x +
               (bd->mouse.current.mx - bd->moveinfo.down.mx);
             y = bd->moveinfo.down.y +
               (bd->mouse.current.my - bd->moveinfo.down.my);
          }
        new_x = x;
        new_y = y;

        skiplist = eina_list_append(skiplist, bd);
        e_resist_container_border_position(bd->zone->container, skiplist,
                                           bd->x, bd->y, bd->w, bd->h,
                                           x, y, bd->w, bd->h,
                                           &new_x, &new_y, &new_w, &new_h);
        eina_list_free(skiplist);

        if (e_config->screen_limits == E_SCREEN_LIMITS_WITHIN)
          _e_border_stay_within_container(bd, x, y, &new_x, &new_y);

        bd->shelf_fix.x = 0;
        bd->shelf_fix.y = 0;
        bd->shelf_fix.modified = 0;
        e_border_move(bd, new_x, new_y);
        e_zone_flip_coords_handle(bd->zone, output->x, output->y);
     }
   else if (bd->resize_mode != E_POINTER_RESIZE_NONE)
     {
        if ((bd->client.netwm.sync.request) &&
            (bd->client.netwm.sync.alarm))
          {
             if ((ecore_loop_time_get() - bd->client.netwm.sync.send_time) > 0.5)
               {
                  E_Border_Pending_Move_Resize *pnd;

                  if (bd->pending_move_resize)
                    {
                       bd->changes.pos = 1;
                       bd->changes.size = 1;
                       BD_CHANGED(bd);
                       _e_border_client_move_resize_send(bd);
                    }
                  EINA_LIST_FREE(bd->pending_move_resize, pnd)
                    E_FREE(pnd);

                  bd->client.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.
              */
             if (!bd->client.netwm.sync.wait)
               _e_border_resize_handle(bd);
          }
        else
          _e_border_resize_handle(bd);
     }
   else if (bd->drag.start)
     {
        if ((bd->drag.x == -1) && (bd->drag.y == -1))
          {
             bd->drag.x = output->x;
             bd->drag.y = output->y;
          }
        else
          {
             int dx, dy;

             dx = bd->drag.x - output->x;
             dy = bd->drag.y - output->y;
             if (((dx * dx) + (dy * dy)) >
                 (e_config->drag_resist * e_config->drag_resist))
               {
                  /* start drag! */
                  if (bd->icon_object)
                    {
                       Evas_Object *o = NULL;
                       Evas_Coord x, y, w, h;
                       const char *drag_types[] = { "enlightenment/border" };

                       e_object_ref(E_OBJECT(bd));
                       evas_object_geometry_get(bd->icon_object,
                                                &x, &y, &w, &h);
                       drag_border = e_drag_new(bd->zone->container,
                                                x, y,
                                                drag_types, 1, bd, -1,
                                                NULL,
                                                _e_border_cb_drag_finished);
                       o = e_border_icon_add(bd, drag_border->evas);
                       if (!o)
                         {
                            /* FIXME: fallback icon for drag */
                            o = evas_object_rectangle_add(drag_border->evas);
                            evas_object_color_set(o, 255, 255, 255, 255);
                         }
                       e_drag_object_set(drag_border, o);

                       e_drag_resize(drag_border, w, h);
                       e_drag_start(drag_border, bd->drag.x, bd->drag.y);
                    }
                  bd->drag.start = 0;
               }
          }
     }
}

static Eina_Bool
_e_border_cb_mouse_x_move(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev)
{
   if (!action_border) return ECORE_CALLBACK_RENEW;
   _e_border_cb_mouse_move_helper(action_border, (Evas_Point*)&ev->root);
   return ECORE_CALLBACK_RENEW;
}

static void
_e_border_cb_mouse_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
   Evas_Event_Mouse_Move *ev = event_info;
   E_Border *bd = data;

   if (action_border) return; // already existing border doing something
   _e_border_cb_mouse_move_helper(bd, &ev->cur.output);
}

static Eina_Bool
_e_border_cb_grab_replay(void *data __UNUSED__,
                         int type,
                         void *event)
{
   Ecore_Event_Mouse_Button *ev;

   if (type != ECORE_EVENT_MOUSE_BUTTON_DOWN) return ECORE_CALLBACK_DONE;
   ev = event;
   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
       )
     {
        E_Border *bd;

        bd = e_border_find_by_window(ev->event_window);
        if (bd)
          {
             if (bd->cur_mouse_action)
               return ECORE_CALLBACK_DONE;
             if (ev->event_window == bd->win)
               {
                  E_Binding_Event_Mouse_Button ev2;

                  e_bindings_ecore_event_mouse_button_convert(ev, &ev2);
                  if (!e_bindings_mouse_button_find(E_BINDING_CONTEXT_WINDOW,
                                                    &ev2, NULL))
                    return ECORE_CALLBACK_PASS_ON;
               }
          }
     }
   return ECORE_CALLBACK_DONE;
}

static void
_e_border_cb_drag_finished(E_Drag *drag,
                           int dropped __UNUSED__)
{
   E_Border *bd;

   bd = drag->data;
   e_object_unref(E_OBJECT(bd));
   drag_border = NULL;
}

#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
static Eina_Bool
_e_border_cb_desk_window_profile_change(void *data  __UNUSED__,
                                        int ev_type __UNUSED__,
                                        void *ev __UNUSED__)
{
//   E_Event_Desk_Window_Profile_Change *e = ev;
   Eina_List *l = NULL;
   E_Border *bd;

   EINA_LIST_FOREACH(borders, l, bd)
     {
        if (!e_object_is_del(E_OBJECT(bd)))
          {
             bd->client.e.fetch.profile = 1;
             BD_CHANGED(bd);
          }
     }
   return ECORE_CALLBACK_PASS_ON;
}

#endif
static Eina_Bool
_e_border_post_move_resize_job(void *data)
{
   E_Border *bd;

   bd = (E_Border *)data;
   if (bd->post_move)
     {
        E_Border *tmp;
        Eina_List *l;

        EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp)
          ecore_x_window_move(tmp->win,
                              bd->x +
                              bd->client_inset.l +
                              tmp->client.e.state.video_position.x,
                              bd->y +
                              bd->client_inset.t +
                              tmp->client.e.state.video_position.y);
     }
   if (bd->client.e.state.video)
     {
        E_Border *parent;

        parent = bd->client.e.state.video_parent_border;
        ecore_x_window_move(bd->win,
                            parent->x +
                            parent->client_inset.l +
                            bd->client.e.state.video_position.x,
                            parent->y +
                            parent->client_inset.t +
                            bd->client.e.state.video_position.y);
     }
   else if ((bd->post_move) && (bd->post_resize))
     {
        ecore_x_window_move_resize(bd->win,
                                   bd->x + bd->client_inset.l,
                                   bd->y + bd->client_inset.t,
                                   bd->w - (e_border_inset_width_get(bd)),
                                   bd->h - (e_border_inset_height_get(bd)));
     }
   else if (bd->post_move)
     {
        ecore_x_window_move(bd->win, bd->x + bd->client_inset.l, bd->y + bd->client_inset.t);
     }
   else if (bd->post_resize)
     {
        ecore_x_window_resize(bd->win,
                              bd->w - (e_border_inset_width_get(bd)),
                              bd->h - (e_border_inset_height_get(bd)));
     }

   if (bd->client.e.state.video)
     {
        fprintf(stderr, "%x: [%i, %i] [%i, %i]\n",
                bd->win,
                bd->client.e.state.video_parent_border->x +
                bd->client.e.state.video_parent_border->client_inset.l +
                bd->client.e.state.video_position.x,
                bd->client.e.state.video_parent_border->y +
                bd->client.e.state.video_parent_border->client_inset.t +
                bd->client.e.state.video_position.y,
                bd->w, bd->h);
     }

   if (bd->post_show)
     {
        if (bd->visible)
          {
             bd->post_job = NULL;
             _e_border_show(bd);
          }
     }
   bd->post_show = 0;
   bd->post_move = 0;
   bd->post_resize = 0;
   bd->post_job = NULL;
   return ECORE_CALLBACK_CANCEL;
}

static void
_e_border_container_layout_hook(E_Container *con)
{
   _e_border_hook_call(E_BORDER_HOOK_CONTAINER_LAYOUT, con);
}

static void
_e_border_eval0(E_Border *bd)
{
   int change_urgent = 0;
   int rem_change = 0;
   int title_change = 0;
   Eina_Bool new_cw = !bd->cw;
#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
   Eina_Bool need_desk_set = EINA_FALSE;
#endif

   if (e_object_is_del(E_OBJECT(bd)))
     {
        CRI("_e_border_eval(%p) with deleted border!\n", bd);
        bd->changed = 0;
        return;
     }

   _e_border_hook_call(E_BORDER_HOOK_EVAL_PRE_FETCH, bd);

   bd->changes.border = 0;

   /* fetch any info queued to be fetched */
   if (bd->changes.prop || bd->client.netwm.fetch.state)
     {
        e_hints_window_state_get(bd);
        bd->client.netwm.fetch.state = 0;
        rem_change = 1;
     }
   if (bd->client.icccm.fetch.client_leader)
     {
        /* TODO: What do to if the client leader isn't mapped yet? */
        E_Border *bd_leader = NULL;

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

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

        if (bd->bg_object)
          edje_object_part_text_set(bd->bg_object, "e.text.title",
                                    bd->client.icccm.title);

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

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

        if (bd->bg_object)
          edje_object_part_text_set(bd->bg_object, "e.text.title",
                                    bd->client.netwm.name);

        bd->client.netwm.fetch.name = 0;
        rem_change = 1;
        title_change = 1;
     }
   if (title_change)
   {
       E_Event_Border_Title_Change *ev;
        ev = E_NEW(E_Event_Border_Title_Change, 1);
        ev->border = bd;
        e_object_ref(E_OBJECT(bd));
        ecore_event_add(E_EVENT_BORDER_TITLE_CHANGE, ev,
                           _e_border_event_border_title_change_free, NULL);
   }
   if (bd->client.icccm.fetch.name_class)
     {
        const char *pname, *pclass;
        char *nname, *nclass;

        ecore_x_icccm_name_class_get(bd->client.win, &nname, &nclass);
        pname = bd->client.icccm.name;
        pclass = bd->client.icccm.class;
        bd->client.icccm.name = eina_stringshare_add(nname);
        bd->client.icccm.class = eina_stringshare_add(nclass);
        bd->client.hacks.mapping_change =
          ((!e_util_strcasecmp(bd->client.icccm.class, "vmplayer")) || 
           (!e_util_strcasecmp(bd->client.icccm.class, "vmware")));
        if (bd->client.hacks.mapping_change)
          e_bindings_mapping_change_enable(EINA_FALSE);
        free(nname);
        free(nclass);

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

        eina_stringshare_del(pname);
        eina_stringshare_del(pclass);
        bd->client.icccm.fetch.name_class = 0;
     }
   if (bd->changes.prop || bd->client.icccm.fetch.state)
     {
        bd->client.icccm.state = ecore_x_icccm_state_get(bd->client.win);
        bd->client.icccm.fetch.state = 0;
        rem_change = 1;
     }
   if (bd->changes.prop || bd->client.e.fetch.state)
     {
        e_hints_window_e_state_get(bd);
        bd->client.e.fetch.state = 0;
        rem_change = 1;
     }
#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
   if (bd->client.e.fetch.profile)
     {
        const char **list = NULL;
        int n, i, res;
        unsigned int use;

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

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

        res = ecore_x_window_prop_card32_get(bd->client.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(bd->client.win,
                                                ECORE_X_ATOM_E_WINDOW_PROFILE_CHANGE,
                                                &val, 1);
             if (res == 1)
               {
                  char *name = ecore_x_atom_name_get(val);
                  if (name)
                    {
                       bd->client.e.state.profile.name = eina_stringshare_add(name);
                       free(name);
                    }
               }

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

        bd->client.e.fetch.profile = 0;
     }
#endif
   if (bd->changes.prop || bd->client.netwm.fetch.type)
     {
        e_hints_window_type_get(bd);
        if ((!bd->lock_border) || (!bd->client.border.name))
          bd->client.border.changed = 1;

        if (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DOCK)
          {
             if (!bd->client.netwm.state.skip_pager)
               {
                  bd->client.netwm.state.skip_pager = 1;
                  bd->client.netwm.update.state = 1;
               }
             if (!bd->client.netwm.state.skip_taskbar)
               {
                  bd->client.netwm.state.skip_taskbar = 1;
                  bd->client.netwm.update.state = 1;
               }
          }
        else if (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DESKTOP)
          {
             bd->focus_policy_override = E_FOCUS_CLICK;
             e_focus_setup(bd);
             if (!bd->client.netwm.state.skip_pager)
               {
                  bd->client.netwm.state.skip_pager = 1;
                  bd->client.netwm.update.state = 1;
               }
             if (!bd->client.netwm.state.skip_taskbar)
               {
                  bd->client.netwm.state.skip_taskbar = 1;
                  bd->client.netwm.update.state = 1;
               }
          }
        bd->client.netwm.fetch.type = 0;
     }
   if (bd->client.icccm.fetch.machine)
     {
        char *machine = ecore_x_icccm_client_machine_get(bd->client.win);

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

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

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

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

        accepts_focus = EINA_TRUE;
        is_urgent = EINA_FALSE;
        bd->client.icccm.initial_state = ECORE_X_WINDOW_STATE_HINT_NORMAL;
        if (ecore_x_icccm_hints_get(bd->client.win,
                                    &accepts_focus,
                                    &bd->client.icccm.initial_state,
                                    &bd->client.icccm.icon_pixmap,
                                    &bd->client.icccm.icon_mask,
                                    &bd->client.icccm.icon_window,
                                    &bd->client.icccm.window_group,
                                    &is_urgent))
          {
             bd->client.icccm.accepts_focus = accepts_focus;
             if ((bd->client.icccm.urgent != is_urgent) && ((!bd->focused) || (!is_urgent)))
               change_urgent = 1;
             bd->client.icccm.urgent = is_urgent;

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

        request_pos = EINA_FALSE;
        if (ecore_x_icccm_size_pos_hints_get(bd->client.win,
                                             &request_pos,
                                             &bd->client.icccm.gravity,
                                             &bd->client.icccm.min_w,
                                             &bd->client.icccm.min_h,
                                             &bd->client.icccm.max_w,
                                             &bd->client.icccm.max_h,
                                             &bd->client.icccm.base_w,
                                             &bd->client.icccm.base_h,
                                             &bd->client.icccm.step_w,
                                             &bd->client.icccm.step_h,
                                             &bd->client.icccm.min_aspect,
                                             &bd->client.icccm.max_aspect))
          {
             bd->client.icccm.request_pos = request_pos;
          }
        else
          {
          }
        if (bd->client.icccm.min_w > 32767) bd->client.icccm.min_w = 32767;
        if (bd->client.icccm.min_h > 32767) bd->client.icccm.min_h = 32767;
        if (bd->client.icccm.max_w > 32767) bd->client.icccm.max_w = 32767;
        if (bd->client.icccm.max_h > 32767) bd->client.icccm.max_h = 32767;
        if (bd->client.icccm.base_w > 32767) bd->client.icccm.base_w = 32767;
        if (bd->client.icccm.base_h > 32767) bd->client.icccm.base_h = 32767;
        //	if (bd->client.icccm.step_w < 1) bd->client.icccm.step_w = 1;
        //	if (bd->client.icccm.step_h < 1) bd->client.icccm.step_h = 1;
        // if doing a resize, fix it up
        if (bd->resize_mode != E_POINTER_RESIZE_NONE)
          {
             int x, y, w, h, new_w, new_h;

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

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

        bd->client.icccm.transient_for = ecore_x_icccm_transient_for_get(bd->client.win);
        if (bd->client.icccm.transient_for)
          bd_parent = e_border_find_by_client_window(bd->client.icccm.transient_for);
        /* If we already have a parent, remove it */
        if (bd->parent)
          {
             if (bd_parent != bd->parent)
               {
                  bd->parent->transients = eina_list_remove(bd->parent->transients, bd);
                  if (bd->parent->modal == bd) bd->parent->modal = NULL;
                  bd->parent = NULL;
               }
             else
               bd_parent = NULL;
          }
        if ((bd_parent) && (bd_parent != bd) &&
            (eina_list_data_find(bd->transients, bd_parent) != bd_parent))
          {
             bd_parent->transients = eina_list_append(bd_parent->transients, bd);
             bd->parent = bd_parent;
          }
        if (bd->parent)
          {
             if (bd->parent->layer != bd->layer)
               e_border_layer_set(bd, bd->parent->layer);
             if (bd->client.netwm.state.modal)
               {
                  bd->parent->modal = bd;
                  bd->parent->lock_close = 1;
                  if (!bd->parent->client.lock_win)
                    {
                       bd->parent->client.lock_win = ecore_x_window_input_new(bd->parent->win, 0, 0, bd->parent->client.w, bd->parent->client.h);
                       e_comp_ignore_win_add(bd->parent->client.lock_win);
                       eina_hash_add(borders_hash, e_util_winid_str_get(bd->parent->client.lock_win), bd->parent);
                       ecore_x_window_show(bd->parent->client.lock_win);
                       ecore_x_icccm_name_class_set(bd->parent->client.lock_win, "lock_win", "lock_win");
                    }
               }

             if (e_config->focus_setting == E_FOCUS_NEW_DIALOG ||
                 (bd->parent->focused && (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))
               bd->take_focus = 1;
          }
        bd->client.icccm.fetch.transient_for = 0;
        rem_change = 1;
     }
   if (bd->client.icccm.fetch.window_role)
     {
        char *role = ecore_x_icccm_window_role_get(bd->client.win);
        eina_stringshare_replace(&bd->client.icccm.window_role, role);
        free(role);

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

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

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

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

        if (ecore_x_window_prop_card32_get(bd->client.win, ECORE_X_ATOM_NET_WM_WINDOW_OPACITY, &val, 1) > 0)
          bd->client.netwm.opacity = (val >> 24);
     }
   if (bd->client.netwm.fetch.icon)
     {
        int i;
        if (bd->client.netwm.icons)
          {
             for (i = 0; i < bd->client.netwm.num_icons; i++)
               {
                  free(bd->client.netwm.icons[i].data);
                  bd->client.netwm.icons[i].data = NULL;
               }
             free(bd->client.netwm.icons);
          }
        bd->client.netwm.icons = NULL;
        bd->client.netwm.num_icons = 0;
        if (ecore_x_netwm_icons_get(bd->client.win,
                                    &bd->client.netwm.icons,
                                    &bd->client.netwm.num_icons))
          {
             // unless the rest of e17 uses border icons OTHER than icon #0
             // then free the rest that we don't need anymore.
             for (i = 1; i < bd->client.netwm.num_icons; i++)
               {
                  free(bd->client.netwm.icons[i].data);
                  bd->client.netwm.icons[i].data = NULL;
               }
             bd->client.netwm.num_icons = 1;
             bd->changes.icon = 1;
          }
        bd->client.netwm.fetch.icon = 0;
     }
   if (bd->client.netwm.fetch.user_time)
     {
        ecore_x_netwm_user_time_get(bd->client.win, &bd->client.netwm.user_time);
        bd->client.netwm.fetch.user_time = 0;
     }
   if (bd->client.netwm.fetch.strut)
     {
        if (!ecore_x_netwm_strut_partial_get(bd->client.win,
                                             &bd->client.netwm.strut.left,
                                             &bd->client.netwm.strut.right,
                                             &bd->client.netwm.strut.top,
                                             &bd->client.netwm.strut.bottom,
                                             &bd->client.netwm.strut.left_start_y,
                                             &bd->client.netwm.strut.left_end_y,
                                             &bd->client.netwm.strut.right_start_y,
                                             &bd->client.netwm.strut.right_end_y,
                                             &bd->client.netwm.strut.top_start_x,
                                             &bd->client.netwm.strut.top_end_x,
                                             &bd->client.netwm.strut.bottom_start_x,
                                             &bd->client.netwm.strut.bottom_end_x))
          {
             ecore_x_netwm_strut_get(bd->client.win,
                                     &bd->client.netwm.strut.left, &bd->client.netwm.strut.right,
                                     &bd->client.netwm.strut.top, &bd->client.netwm.strut.bottom);

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

        bd->changes.shape = 0;
        rects = ecore_x_window_shape_rectangles_get(bd->client.win, &num);
        if (rects)
          {
             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(bd->client.win, &cw, &ch);
             if ((cw != bd->client.w) || (ch != bd->client.h))
               bd->changes.shape = 1;
             if ((num == 1) &&
                 (rects[0].x == 0) &&
                 (rects[0].y == 0) &&
                 ((int)rects[0].width == cw) &&
                 ((int)rects[0].height == ch))
               {
                  if (bd->client.shaped)
                    {
                       bd->client.shaped = 0;
                       if (!bd->bordername)
                         bd->client.border.changed = 1;
                    }
               }
             else
               {
                  if (!bd->client.shaped)
                    {
                       bd->client.shaped = 1;
                       if (!bd->bordername)
                         bd->client.border.changed = 1;
                    }
                  ecore_x_window_shape_rectangles_set(bd->win, rects, num);
                  bd->changes.shape_input = 0;
                  e_container_shape_input_rects_set(bd->shape, NULL, 0);
               }
             free(rects);
          }
        else
          {
             // FIXME: no rects i think can mean... totally empty window
             bd->client.shaped = 0;
             if (!bd->bordername)
               bd->client.border.changed = 1;
          }
        bd->need_shape_merge = 1;
     }
   if (bd->changes.shape_input)
     {
        Ecore_X_Rectangle *rects;
        int num;

        bd->changes.shape_input = 0;
        rects = ecore_x_window_shape_input_rectangles_get(bd->client.win, &num);
        if (rects)
          {
             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(bd->client.win, &cw, &ch);
             if ((cw != bd->client.w) || (ch != bd->client.h))
               bd->changes.shape_input = 1;
             if ((num == 1) &&
                 (rects[0].x == 0) &&
                 (rects[0].y == 0) &&
                 ((int)rects[0].width == cw) &&
                 ((int)rects[0].height == ch))
               {
                  if (bd->shaped_input)
                    {
                       bd->shaped_input = 0;
                       if (!bd->bordername)
                         bd->client.border.changed = 1;
                    }
                  free(rects);
               }
             else
               {
                  if (!bd->shaped_input)
                    {
                       bd->shaped_input = 1;
                       if (!bd->bordername)
                         bd->client.border.changed = 1;
                    }
                  ecore_x_window_shape_input_rectangles_set(bd->win, rects, num);
                  e_container_shape_input_rects_set(bd->shape, (Eina_Rectangle *)rects, num);
               }
          }
        else
          {
             bd->shaped_input = 1;
             if (!bd->bordername)
               bd->client.border.changed = 1;
          }
        bd->need_shape_merge = 1;
     }
   if (bd->changes.prop || bd->client.mwm.fetch.hints)
     {
        int pb;

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

        ecore_x_window_prop_card32_get(bd->client.win,
                                       ECORE_X_ATOM_E_VIDEO_PARENT,
                                       &bd->client.e.state.video_parent,
                                       1);

        /* linking child/parent */
        if (bd->client.e.state.video_parent != 0)
          {
             E_Border *tmp;
             Eina_List *l;

             EINA_LIST_FOREACH(borders, l, tmp)
               if (tmp->client.win == bd->client.e.state.video_parent)
                 {
                    /* fprintf(stderr, "child added to parent \\o/\n"); */
                    bd->client.e.state.video_parent_border = tmp;
                    tmp->client.e.state.video_child = eina_list_append(tmp->client.e.state.video_child,
                                                                       bd);
                    if (bd->desk != tmp->desk)
                      e_border_desk_set(bd, tmp->desk);
                    break;
                 }
          }

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

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

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

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

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

#if (ECORE_VERSION_MAJOR > 1) || (ECORE_VERSION_MINOR >= 8)
   if ((e_config->use_desktop_window_profile) && (need_desk_set))
     {
        if (!(bd->client.e.state.profile.name) &&
            (bd->client.e.state.profile.num >= 1))
          {
             const char *p = NULL;
             int i;
             for (i = 0; i < bd->client.e.state.profile.num; i++)
               {
                  if (!bd->client.e.state.profile.available_list[i])
                    continue;
                  p = bd->client.e.state.profile.available_list[i];
                  if (strcmp(bd->desk->window_profile, p) == 0)
                    {
                       bd->client.e.state.profile.name = eina_stringshare_add(bd->desk->window_profile);
                       break;
                    }
               }

             if (!bd->client.e.state.profile.name)
               {
                  E_Container *con = bd->zone->container;
                  E_Desk *desk = NULL;

                  for (i = 0; i < bd->client.e.state.profile.num; i++)
                    {
                       if (!bd->client.e.state.profile.available_list[i])
                         continue;
                       p = bd->client.e.state.profile.available_list[i];
                       desk = e_container_desk_window_profile_get(con, p);
                       if ((desk) && (bd->desk != desk))
                         {
                            bd->client.e.state.profile.name = eina_stringshare_add(p);
                            break;
                         }
                    }
               }
          }

        if (!bd->client.e.state.profile.name)
          {
             bd->client.e.state.profile.name = eina_stringshare_add(bd->desk->window_profile);
          }

        ecore_x_e_window_profile_change_request_send(bd->client.win,
                                                     bd->client.e.state.profile.name);
        bd->client.e.state.profile.wait_for_done = 1;
     }
#endif
   if (bd->new_client)
     {
        E_Event_Border_Add *ev;
        E_Exec_Instance *inst;

        ev = E_NEW(E_Event_Border_Add, 1);
        ev->border = bd;
        e_object_ref(E_OBJECT(bd));
        //	e_object_breadcrumb_add(E_OBJECT(bd), "border_add_event");
        ecore_event_add(E_EVENT_BORDER_ADD, ev, _e_border_event_border_add_free, NULL);

        if ((!bd->lock_border) || (!bd->client.border.name))
          bd->client.border.changed = 1;

        {
           char *str = NULL;

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

                     id = atoi(str + 8);
                     if (id > 0) bd->client.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(bd->client.win, &bd->client.netwm.pid))
          {
             if (bd->client.icccm.client_leader)
               {
                  if (!ecore_x_netwm_pid_get(bd->client.icccm.client_leader, &bd->client.netwm.pid))
                    bd->client.netwm.pid = -1;
               }
             else
               bd->client.netwm.pid = -1;
          }

        if (!bd->re_manage)
          {
             inst = e_exec_startup_id_pid_instance_find(bd->client.netwm.startup_id,
                                                        bd->client.netwm.pid);
             if (inst)
               {
                  Eina_Bool found;
                  if (inst->used == 0)
                    {
                       E_Zone *zone;
                       E_Desk *desk;

                       inst->used++;
                       zone = e_container_zone_number_get(bd->zone->container,
                                                          inst->screen);
                       if (zone) e_border_zone_set(bd, zone);
                       desk = e_desk_at_xy_get(bd->zone, inst->desk_x,
                                               inst->desk_y);
                       if (desk) e_border_desk_set(bd, desk);
                       if (bd->client.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->borders;
                  e_exec_instance_client_add(inst, bd);
                  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_Border *bdl = NULL;

                  bdl = bd->parent;
                  if (!bdl)
                    {
                       if (bd->leader) bdl = bd->leader;
                    }
                  if (!bdl)
                    {
                       E_Border *child;
                       E_Border_List *bl;

                       bl = e_container_border_list_first(bd->zone->container);
                       while ((child = e_container_border_list_next(bl)))
                         {
                            if (child == bd) continue;
                            if (e_object_is_del(E_OBJECT(child))) continue;
                            if ((bd->client.icccm.client_leader) &&
                                (child->client.icccm.client_leader ==
                                 bd->client.icccm.client_leader))
                              {
                                 bdl = child;
                                 break;
                              }
                         }
                       e_container_border_list_free(bl);
                    }
                  if (bdl)
                    {
                       if (bdl->zone)
                         e_border_zone_set(bd, bdl->zone);
                       if (bdl->desk)
                         e_border_desk_set(bd, bdl->desk);
                       else
                         e_border_stick(bd);
                    }
               }
          }
     }

   /* PRE_POST_FETCH calls e_remember apply for new client */
   _e_border_hook_call(E_BORDER_HOOK_EVAL_PRE_POST_FETCH, bd);
   _e_border_hook_call(E_BORDER_HOOK_EVAL_POST_FETCH, bd);
   _e_border_hook_call(E_BORDER_HOOK_EVAL_PRE_BORDER_ASSIGN, bd);

   if (bd->need_reparent)
     {
        if (!bd->internal)
          ecore_x_window_save_set_add(bd->client.win);
        ecore_x_window_reparent(bd->client.win, bd->win, bd->client_inset.l, bd->client_inset.t);
        if (bd->visible)
          {
             if ((bd->new_client) && (bd->internal) &&
                 (bd->internal_ecore_evas))
               ecore_evas_show(bd->internal_ecore_evas);
          }
        if (bd->new_client)
          {
             ecore_x_window_show(bd->client.win);
             _e_border_show(bd);
          }
        bd->need_reparent = 0;
     }

   if ((bd->client.border.changed) && (!bd->shaded) &&
       (!(((bd->maximized & E_MAXIMIZE_TYPE) == E_MAXIMIZE_FULLSCREEN))))
     {
        const char *bordername;

        if (bd->fullscreen || bd->borderless)
          bordername = "borderless";
        else if (bd->bordername)
          bordername = bd->bordername;
        else if ((bd->client.mwm.borderless) || (bd->borderless))
          bordername = "borderless";
        else if (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DESKTOP)
          bordername = "borderless";
        else if (((bd->client.icccm.transient_for != 0) ||
                  (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG)) &&
                 (bd->client.icccm.min_w == bd->client.icccm.max_w) &&
                 (bd->client.icccm.min_h == bd->client.icccm.max_h))
          bordername = "noresize_dialog";
        else if ((bd->client.icccm.min_w == bd->client.icccm.max_w) &&
                 (bd->client.icccm.min_h == bd->client.icccm.max_h))
          bordername = "noresize";
        else if (bd->client.shaped)
          bordername = "shaped";
        else if ((!bd->client.icccm.accepts_focus) &&
                 (!bd->client.icccm.take_focus))
          bordername = "nofocus";
        else if (bd->client.icccm.urgent)
          bordername = "urgent";
        else if ((bd->client.icccm.transient_for != 0) ||
                 (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG))
          bordername = "dialog";
        else if (bd->client.netwm.state.modal)
          bordername = "modal";
        else if ((bd->client.netwm.state.skip_taskbar) ||
                 (bd->client.netwm.state.skip_pager))
          bordername = "skipped";
/*
        else if ((bd->internal) && (bd->client.icccm.class) &&
                 (!strncmp(bd->client.icccm.class, "e_fwin", 6)))
          bordername = "internal_fileman";
 */
        else
          bordername = e_config->theme_default_border_style;
        if (!bordername) bordername = "default";

        if ((!bd->client.border.name) || (strcmp(bd->client.border.name, bordername)))
          {
             Evas_Object *o, *pbg = bd->bg_object;
             char buf[4096];
             int ok;

             bd->changes.border = 1;
             eina_stringshare_replace(&bd->client.border.name, bordername);

             if (bd->bg_object)
               {
                  int w, h;

                  w = bd->w, h = bd->h;
                  bd->w -= (e_border_inset_width_get(bd));
                  bd->h -= (e_border_inset_height_get(bd));
                  if ((bd->w != w) || (h != bd->h)) bd->changes.size = 1;
                  evas_object_del(bd->bg_object);
               }
             o = edje_object_add(e_comp_get(bd)->evas);
             snprintf(buf, sizeof(buf), "e/widgets/border/%s/border", bd->client.border.name);
             ok = e_theme_edje_object_set(o, "base/theme/borders", buf);
             if ((!ok) && (strcmp(bd->client.border.name, "borderless")))
               {
                  if (bd->client.border.name != e_config->theme_default_border_style)
                    {
                       snprintf(buf, sizeof(buf), "e/widgets/border/%s/border", e_config->theme_default_border_style);
                       ok = e_theme_edje_object_set(o, "base/theme/borders", buf);
                    }
                  if (!ok)
                    {
                       ok = e_theme_edje_object_set(o, "base/theme/borders",
                                                    "e/widgets/border/default/border");
                       if (ok)
                         {
                            /* Reset default border style to default */
                            eina_stringshare_replace(&e_config->theme_default_border_style, "default");
                            e_config_save_queue();
                         }
                    }
               }

             if (ok)
               {
                  bd->bg_object = o;
                  evas_object_name_set(o, "bd->bg_object");

                  if (bd->client.netwm.name)
                    edje_object_part_text_set(o, "e.text.title",
                                              bd->client.netwm.name);
                  else if (bd->client.icccm.title)
                    edje_object_part_text_set(o, "e.text.title",
                                              bd->client.icccm.title);
                  bd->theme_shadow = !!edje_object_data_get(o, "shadow");
                  _e_border_shadow(bd);

                  if (pbg)
                    {
                       if (bd->icon_object)
                         edje_object_part_swallow(bd->bg_object, "e.swallow.icon", bd->icon_object);
                    }
                  else bd->changes.icon = 1;
               }
             else
               {
                  if (strcmp(bordername, "borderless"))
                  /* it should never happen that a theme fails to set the edje
                   * unless it's using borderless
                   */
                    CRI("USER IS USING A SHITTY THEME! ABORT!!!!");
                  evas_object_del(o);
                  bd->bg_object = NULL;
                  E_FREE_FUNC(bd->icon_object, evas_object_del);
                  o = bd->cw ? bd->cw->obj : NULL;
               }
             if (bd->cw) e_comp_win_reshadow(bd->cw);
             /* FIXME: it's theoretically possible that o is NULL here if first border eval occurs for a fullscreen
              * borderless window before its comp win has been set up;
              * E19 material imo
              */
             {
                // previously calculated
                Eina_Bool calc = bd->client_inset.calc;
                // previously was borderless
                Eina_Bool inset, pinset = !!(e_border_inset_width_get(bd) + e_border_inset_height_get(bd));

                _e_border_client_inset_calc(bd);
                inset = !!(e_border_inset_width_get(bd) + e_border_inset_height_get(bd));
                if (calc && (inset != pinset) && (pbg || (!bd->bg_object)))
                  {
                     if (inset)
                       bd->x -= bd->client_inset.l, bd->y -= bd->client_inset.t;
                     else
                       bd->x += bd->client_inset.l, bd->y += bd->client_inset.t;
                  }
             }

             bd->w += (e_border_inset_width_get(bd));
             bd->h += (e_border_inset_height_get(bd));
             bd->changes.size = 1;

             if (bd->maximized != E_MAXIMIZE_NONE)
               {
                  E_Maximize maximized = bd->maximized;

                  /* to force possible resizes */
                  bd->maximized = E_MAXIMIZE_NONE;

                  _e_border_maximize(bd, maximized);

                  /* restore maximized state */
                  bd->maximized = maximized;

                  e_hints_window_maximized_set(bd, bd->maximized & E_MAXIMIZE_HORIZONTAL,
                                               bd->maximized & E_MAXIMIZE_VERTICAL);
               }
             if (bd->bg_object)
               {
                  edje_object_signal_callback_add(bd->bg_object, "*", "*",
                                                  _e_border_cb_signal_bind, bd);
                  if (bd->focused)
                    {
                       edje_object_signal_emit(bd->bg_object, "e,state,focused", "e");
                       if (bd->icon_object)
                         edje_object_signal_emit(bd->icon_object, "e,state,focused", "e");
                    }
                  if (bd->shaded)
                    edje_object_signal_emit(bd->bg_object, "e,state,shaded", "e");
                  if (bd->sticky)
                    edje_object_signal_emit(bd->bg_object, "e,state,sticky", "e");
                  if (bd->hung)
                    edje_object_signal_emit(bd->bg_object, "e,state,hung", "e");
                  // FIXME: in eval -do differently
                  //	     edje_object_message_signal_process(bd->bg_object);
                  //	     e_border_frame_recalc(bd);
               }
             rem_change = 1;
          }
        bd->client.border.changed = 0;
     }

   bd->changes.prop = 0;
   if (rem_change) e_remember_update(bd);
   /* the below function updates the border's remember
    * and relevant netwm atom
    * ...eventually
    */
   if (bd->cw) e_comp_win_opacity_set(bd->cw, bd->client.netwm.opacity);

   if (change_urgent)
     {
        E_Event_Border_Urgent_Change *ev;

        if (bd->client.icccm.urgent)
          edje_object_signal_emit(bd->bg_object, "e,state,urgent", "e");
        else
          edje_object_signal_emit(bd->bg_object, "e,state,not_urgent", "e");

        ev = E_NEW(E_Event_Border_Urgent_Change, 1);
        ev->border = bd;
        e_object_ref(E_OBJECT(bd));
        ecore_event_add(E_EVENT_BORDER_URGENT_CHANGE, ev,
                        _e_border_event_border_urgent_change_free, NULL);
     }

   _e_border_hook_call(E_BORDER_HOOK_EVAL_POST_BORDER_ASSIGN, bd);
   if (!new_cw) return;
   evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_IN, _e_border_cb_mouse_in, bd);
   evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_MOVE, _e_border_cb_mouse_move, bd);
   evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_OUT, _e_border_cb_mouse_out, bd);
   evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_DOWN, _e_border_cb_mouse_down, bd);
   evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_UP, _e_border_cb_mouse_up, bd);
   evas_object_event_callback_add(bd->cw->effect_obj, EVAS_CALLBACK_MOUSE_WHEEL, _e_border_cb_mouse_wheel, bd);
}

static void
_e_border_eval(E_Border *bd)
{
   E_Event_Border_Property *event;
   E_Border_Pending_Move_Resize *pnd;
   int rem_change = 0;
   int send_event = 1;

   if (e_object_is_del(E_OBJECT(bd)))
     {
        CRI("_e_border_eval(%p) with deleted border! - %d\n", bd, bd->new_client);
        bd->changed = 0;
        return;
     }

   _e_border_hook_call(E_BORDER_HOOK_EVAL_PRE_NEW_BORDER, bd);

   if (bd->new_client)
     {
        int zx = 0, zy = 0, zw = 0, zh = 0;

        e_zone_useful_geometry_get(bd->zone, &zx, &zy, &zw, &zh);

        /*
         * Limit maximum size of windows to useful geometry
         */
        // TODO: temoporary limited maximize algorithm
        // ->
        /*if (bd->w > zw)
           rw = zw;
           else
           rw = bd->w;

           if (bd->h > zh)
           rh = zh;
           else
           rh = bd->h;

           if ((rw != bd->w) || (rh != bd->h))
           {
           bd->w = rw;
           bd->h = rh;
           e_border_resize (bd, bd->w, bd->h);
           }*/
        // <-

        if (bd->re_manage)
          {
             int x = bd->x, y = bd->y;
             if (bd->x) bd->x -= bd->client_inset.l;
             if (bd->y) bd->y -= bd->client_inset.t;
             if ((x != bd->x) || (y != bd->y)) bd->changes.pos = 1;
             bd->placed = 1;
          }
        else if ((!bd->placed) && (bd->client.icccm.request_pos))
          {
             Ecore_X_Window_Attributes *att;
             int bw;

             att = &bd->client.initial_attributes;
             bw = att->border * 2;
             switch (bd->client.icccm.gravity)
               {
                case ECORE_X_GRAVITY_N:
                  bd->x = (att->x - (bw / 2)) - (bd->client_inset.l / 2);
                  bd->y = att->y;
                  break;

                case ECORE_X_GRAVITY_NE:
                  bd->x = (att->x - (bw)) - (bd->client_inset.l);
                  bd->y = att->y;
                  break;

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

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

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

                case ECORE_X_GRAVITY_SW:
                  bd->x = att->x;
                  bd->y = (att->y - (bw)) - (bd->client_inset.t);
                  break;

                case ECORE_X_GRAVITY_W:
                  bd->x = att->x;
                  bd->y = (att->y - (bw)) - (bd->client_inset.t);
                  break;

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

                case ECORE_X_GRAVITY_NW:
                default:
                  bd->x = att->x;
                  bd->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 (bd->x < zx)
                    bd->x = zx;

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

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

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

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

                  // <--
                  if (bd->zone && e_container_zone_at_point_get(bd->zone->container, bd->x, bd->y))
                    {
                       if (!E_INSIDE(bd->x, bd->y, bd->zone->x, bd->zone->y, bd->zone->w, bd->zone->h))
                         {
                            bd->x = E_CLAMP(bd->x, bd->zone->x, bd->zone->x + bd->zone->w);
                            bd->y = E_CLAMP(bd->y, bd->zone->y, bd->zone->y + bd->zone->h);
                         }
                       /* some application failing to correctly center a window */
                       if (eina_list_count(bd->zone->container->zones) > 1)
                         {
                            if (((abs((bd->zone->container->w / 2) - bd->x) < 3) || //bd->x is center of container
                                 ((abs((bd->zone->container->w / 2) - bd->x - bd->w) < 3) || //bd->x - bd->w is center of container
                                  (abs((bd->zone->container->w / 2) - bd->x - (bd->w / 2)) < 3))) || //bd->x - bd->w/2 is center of container
                                ((abs((bd->zone->container->h / 2) - bd->y) < 3) || //bd->y is center of container
                                 ((abs((bd->zone->container->h / 2) - bd->y - bd->h) < 3) || //bd->y - bd->h is center of container
                                  (abs((bd->zone->container->h / 2) - bd->y - (bd->h / 2)) < 3))) //bd->y - bd->h/2 is center of container
                                )
                              e_border_center(bd);
                         }
                       bd->changes.pos = 1;
                       bd->placed = 1;
                    }
               }
             else
               {
                  bd->changes.pos = 1;
                  bd->placed = 1;
               }
          }
        if (!bd->placed)
          {
             /* FIXME: special placement for dialogs etc. etc. etc goes
              * here */
             /* FIXME: what if parent is not on this desktop - or zone? */
             if ((bd->parent) && (bd->parent->visible))
               {
                  bd->x = bd->parent->x + ((bd->parent->w - bd->w) / 2);
                  bd->y = bd->parent->y + ((bd->parent->h - bd->h) / 2);
                  bd->changes.pos = 1;
                  bd->placed = 1;
               }
#if 0
             else if ((bd->leader) && (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG))
               {
                  /* TODO: Place in center of group */
               }
#endif
             else if (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG)
               {
                  bd->x = zx + ((zw - bd->w) / 2);
                  bd->y = zy + ((zh - bd->h) / 2);
                  bd->changes.pos = 1;
                  bd->placed = 1;
               }
          }
        if (!bd->placed)
          {
             Eina_List *skiplist = NULL;
             int new_x, new_y;

             if (zw > bd->w)
               new_x = zx + (rand() % (zw - bd->w));
             else
               new_x = zx;
             if (zh > bd->h)
               new_y = zy + (rand() % (zh - bd->h));
             else
               new_y = zy;

             if ((e_config->window_placement_policy == E_WINDOW_PLACEMENT_SMART) || (e_config->window_placement_policy == E_WINDOW_PLACEMENT_ANTIGADGET))
               {
                  skiplist = eina_list_append(skiplist, bd);
                  if (bd->desk)
                    e_place_desk_region_smart(bd->desk, skiplist,
                                              bd->x, bd->y, bd->w, bd->h,
                                              &new_x, &new_y);
                  else
                    e_place_zone_region_smart(bd->zone, skiplist,
                                              bd->x, bd->y, bd->w, bd->h,
                                              &new_x, &new_y);
                  eina_list_free(skiplist);
               }
             else if (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL)
               {
                  e_place_zone_manual(bd->zone, bd->w, bd->client_inset.t,
                                      &new_x, &new_y);
               }
             else
               {
                  e_place_zone_cursor(bd->zone, bd->x, bd->y, bd->w, bd->h,
                                      bd->client_inset.t, &new_x, &new_y);
               }
             bd->x = new_x;
             bd->y = new_y;
             bd->changes.pos = 1;
          }

        EINA_LIST_FREE(bd->pending_move_resize, pnd)
          {
             if ((!bd->lock_client_location) && (pnd->move))
               {
                  bd->x = pnd->x;
                  bd->y = pnd->y;
                  bd->changes.pos = 1;
                  bd->placed = 1;
                  if (pnd->without_border)
                    {
                       bd->x -= bd->client_inset.l;
                       bd->y -= bd->client_inset.t;
                    }
               }
             if ((!bd->lock_client_size) && (pnd->resize))
               {
                  bd->w = pnd->w + (e_border_inset_width_get(bd));
                  bd->h = pnd->h + (e_border_inset_height_get(bd));
                  bd->client.w = pnd->w;
                  bd->client.h = pnd->h;
                  bd->changes.size = 1;
               }

             free(pnd);
          }

        /* Recreate state */
        e_hints_window_init(bd);
        if ((bd->client.e.state.centered) &&
            ((!bd->remember) ||
             ((bd->remember) && (!(bd->remember->apply & E_REMEMBER_APPLY_POS)))))
          {
             bd->x = zx + (zw - bd->w) / 2;
             bd->y = zy + (zh - bd->h) / 2;
             bd->changes.pos = 1;
             bd->placed = 1;
          }

        _e_border_client_move_resize_send(bd);

        /* if the explicit geometry request asks for the app to be
         * in another zone - well move it there */
        {
           E_Zone *zone;

           zone = e_container_zone_at_point_get(bd->zone->container,
                                                bd->x + (bd->w / 2),
                                                bd->y + (bd->h / 2));
           if (!zone)
             zone = e_container_zone_at_point_get(bd->zone->container,
                                                  bd->x,
                                                  bd->y);
           if (!zone)
             zone = e_container_zone_at_point_get(bd->zone->container,
                                                  bd->x + bd->w - 1,
                                                  bd->y);
           if (!zone)
             zone = e_container_zone_at_point_get(bd->zone->container,
                                                  bd->x + bd->w - 1,
                                                  bd->y + bd->h - 1);
           if (!zone)
             zone = e_container_zone_at_point_get(bd->zone->container,
                                                  bd->x,
                                                  bd->y + bd->h - 1);
           if ((zone) && (zone != bd->zone))
             e_border_zone_set(bd, zone);
        }
     }

   _e_border_hook_call(E_BORDER_HOOK_EVAL_POST_NEW_BORDER, bd);

   /* effect changes to the window border itself */
   if ((bd->changes.shading))
     {
        /*  show at start of unshade (but don't hide until end of shade) */
        //if (bd->shaded)
          //ecore_x_window_raise(bd->win);
        bd->changes.shading = 0;
        send_event = 0;
        rem_change = 1;
     }
   if (bd->changes.shaded) send_event = 0;
   if ((bd->changes.shaded) && (bd->changes.pos) && (bd->changes.size))
     {
        //if (bd->shaded)
          //ecore_x_window_lower(bd->win);
        //else
          //ecore_x_window_raise(bd->win);
        bd->changes.shaded = 0;
        rem_change = 1;
     }
   else if ((bd->changes.shaded) && (bd->changes.pos))
     {
        //if (bd->shaded)
          //ecore_x_window_lower(bd->win);
        //else
          //ecore_x_window_raise(bd->win);
        bd->changes.size = 1;
        bd->changes.shaded = 0;
        rem_change = 1;
     }
   else if ((bd->changes.shaded) && (bd->changes.size))
     {
        //if (bd->shaded)
          //ecore_x_window_lower(bd->win);
        //else
          //ecore_x_window_raise(bd->win);
        bd->changes.shaded = 0;
        rem_change = 1;
     }
   else if (bd->changes.shaded)
     {
        //if (bd->shaded)
          //ecore_x_window_lower(bd->win);
        //else
          //ecore_x_window_raise(bd->win);
        bd->changes.shaded = 0;
        rem_change = 1;
     }

   if (bd->changes.size)
     {
        int x, y, w = 0, h = 0;

        x = bd->x + bd->client_inset.l;
        y = bd->y + bd->client_inset.t;
        if ((!bd->shaded) || (bd->shading))
          {
             w = bd->w - (e_border_inset_width_get(bd));
             h = bd->h - (e_border_inset_height_get(bd));

             if (bd->shading)
               {
                  if (bd->shade.dir == E_DIRECTION_UP)
                    {
                       y = h - bd->client.h;
                    }
                  else if (bd->shade.dir == E_DIRECTION_LEFT)
                    {
                       x = w - bd->client.w;
                    }
               }
          }

        if (bd->client.e.state.video)
          {
             if (bd->client.e.state.video_position.updated)
               {
                  ecore_x_window_move(bd->win,
                                      bd->client.e.state.video_parent_border->x +
                                      bd->client.e.state.video_parent_border->client_inset.l +
                                      bd->client.e.state.video_position.x,
                                      bd->client.e.state.video_parent_border->y +
                                      bd->client.e.state.video_parent_border->client_inset.t +
                                      bd->client.e.state.video_position.y);
                  bd->client.e.state.video_position.updated = 0;
               }
          }
        else if (!bd->changes.pos)
          {
             if (bd->post_job) ecore_idle_enterer_del(bd->post_job);
             bd->post_job = ecore_idle_enterer_add(_e_border_post_move_resize_job, bd);
             bd->post_resize = 1;
          }
        else
          {
             E_Border *tmp;
             Eina_List *l;

             EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp)
               ecore_x_window_move(tmp->win,
                                   bd->x + bd->client_inset.l + tmp->client.e.state.video_position.x,
                                   bd->y + bd->client_inset.t + tmp->client.e.state.video_position.y);
          }

        if ((!bd->shaded) && (!bd->shading))
          {
             ecore_x_window_move_resize(bd->win, x, y, w, h);

             if (bd->internal_ecore_evas)
               ecore_evas_move_resize(bd->internal_ecore_evas, 0, 0, w, h);
             else if (!bd->client.e.state.video)
               {
                  ecore_x_window_move_resize(bd->client.win, 0, 0, bd->client.w, bd->client.h);
                  if (bd->client.lock_win)
                    ecore_x_window_move_resize(bd->client.lock_win, 0, 0, bd->client.w, bd->client.h);
               }
             _e_border_client_move_resize_send(bd);
          }
        else if (bd->changes.pos)
          ecore_x_window_move(bd->win, x, y);

        e_container_shape_resize(bd->shape, w, h);
        if (bd->changes.pos)
          e_container_shape_move(bd->shape, x, y);

        bd->changes.pos = 0;
        bd->changes.size = 0;
        rem_change = 1;
     }
   else if (bd->changes.pos)
     {
        if (bd->post_job) ecore_idle_enterer_del(bd->post_job);
        bd->post_job = ecore_idle_enterer_add(_e_border_post_move_resize_job, bd);
        bd->post_move = 1;

        e_container_shape_move(bd->shape, bd->x + bd->client_inset.l, bd->y + bd->client_inset.t);

        _e_border_client_move_resize_send(bd);

        bd->changes.pos = 0;
        rem_change = 1;
     }

   if (bd->changes.reset_gravity)
     {
        GRAV_SET(bd, ECORE_X_GRAVITY_NW);
        bd->changes.reset_gravity = 0;
        rem_change = 1;
     }

   if (bd->need_shape_merge)
     {
        _e_border_shape_input_rectangle_set(bd);
        if (!bd->client.shaped)
          ecore_x_window_shape_mask_set(bd->win, 0);
        //bd->need_shape_export = 1;
        bd->need_shape_merge = 0;
     }

   if (bd->need_shape_export)
     {
        Ecore_X_Rectangle *rects, *orects;
        int num;

        rects = ecore_x_window_shape_rectangles_get(bd->client.win, &num);
        if (rects)
          {
             int changed;

             changed = 1;
             if ((num == bd->shape->shape_rects_num) && (bd->shape->shape_rects))
               {
                  int i;

                  orects = (Ecore_X_Rectangle*)bd->shape->shape_rects;
                  changed = 0;
                  for (i = 0; i < num; i++)
                    {
                       if (rects[i].x < 0)
                         {
                            rects[i].width -= rects[i].x;
                            rects[i].x = 0;
                         }
                       if ((rects[i].x + (int)rects[i].width) > bd->w)
                         rects[i].width = rects[i].width - rects[i].x;
                       if (rects[i].y < 0)
                         {
                            rects[i].height -= rects[i].y;
                            rects[i].y = 0;
                         }
                       if ((rects[i].y + (int)rects[i].height) > bd->h)
                         rects[i].height = rects[i].height - rects[i].y;

                       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)
               {
                  if (bd->client.shaped)
                    e_container_shape_solid_rect_set(bd->shape, 0, 0, 0, 0);
                  e_container_shape_rects_set(bd->shape, (Eina_Rectangle*)rects, num);
               }
             else
               free(rects);
          }
        else
          {
             e_container_shape_rects_set(bd->shape, NULL, 0);
          }
        bd->need_shape_export = 0;
     }

   if ((bd->changes.visible) && (bd->visible) && (bd->new_client))
     {
        int x, y;

        ecore_x_pointer_xy_get(bd->zone->container->win, &x, &y);
        if ((!bd->placed) && (!bd->re_manage) &&
            (e_config->window_placement_policy == E_WINDOW_PLACEMENT_MANUAL) &&
            (!((bd->client.icccm.transient_for != 0) ||
               (bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG))) &&
            (!bdmove) && (!bdresize))
          {
             /* Set this window into moving state */

             bd->cur_mouse_action = e_action_find("window_move");
             if (bd->cur_mouse_action)
               {
                  if ((!bd->cur_mouse_action->func.end_mouse) &&
                      (!bd->cur_mouse_action->func.end))
                    bd->cur_mouse_action = NULL;
                  if (bd->cur_mouse_action)
                    {
                       bd->x = x - (bd->w >> 1);
                       bd->y = y - (bd->client_inset.t >> 1);
                       BD_CHANGED(bd);
                       bd->changes.pos = 1;

                       _e_border_client_move_resize_send(bd);
                    }
               }
          }

        _e_border_show(bd);

        if (bd->cur_mouse_action)
          {
             bd->moveinfo.down.x = bd->x;
             bd->moveinfo.down.y = bd->y;
             bd->moveinfo.down.w = bd->w;
             bd->moveinfo.down.h = bd->h;
             bd->mouse.current.mx = x;
             bd->mouse.current.my = y;
             bd->moveinfo.down.button = 0;
             bd->moveinfo.down.mx = x;
             bd->moveinfo.down.my = y;

             grabbed = 1;
             e_object_ref(E_OBJECT(bd->cur_mouse_action));
             bd->cur_mouse_action->func.go(E_OBJECT(bd), NULL);
             if (e_config->border_raise_on_mouse_action)
               e_border_raise(bd);
             e_border_focus_set(bd, 1, 1);
          }
        bd->changes.visible = 0;
        rem_change = 1;
        {
           E_Event_Border_Show *ev;

           ev = E_NEW(E_Event_Border_Show, 1);
           ev->border = bd;
           e_object_ref(E_OBJECT(bd));
        //   e_object_breadcrumb_add(E_OBJECT(bd), "border_show_event");
           ecore_event_add(E_EVENT_BORDER_SHOW, ev, _e_border_event_border_show_free, NULL);
        }
     }
   else if ((bd->changes.visible) && (bd->new_client))
     {
        bd->changes.visible = 0;
        {
           E_Event_Border_Hide *ev;

           ev = E_NEW(E_Event_Border_Hide, 1);
           ev->border = bd;
           e_object_ref(E_OBJECT(bd));
        //   e_object_breadcrumb_add(E_OBJECT(bd), "border_hide_event");
           ecore_event_add(E_EVENT_BORDER_HIDE, ev, _e_border_event_border_hide_free, NULL);
        }
     }

   if (bd->changes.icon)
     {
        if (bd->desktop && (!bd->new_client))
          {
             efreet_desktop_free(bd->desktop);
             bd->desktop = NULL;
          }
        if (bd->icon_object && (!bd->new_client))
          {
             evas_object_del(bd->icon_object);
             bd->icon_object = NULL;
          }
        if (bd->remember && bd->remember->prop.desktop_file)
          {
             const char *desktop = bd->remember->prop.desktop_file;

             bd->desktop = efreet_desktop_get(desktop);
             if (!bd->desktop)
               bd->desktop = efreet_util_desktop_name_find(desktop);
          }
        if (!bd->desktop)
          {
             if (bd->internal && (bd->client.icccm.class && (!strncmp(bd->client.icccm.class, "e_fwin::", 8))))
               bd->desktop = efreet_util_desktop_exec_find("enlightenment_filemanager");
          }
        if (!bd->desktop)
          {
             if ((bd->client.icccm.name) && (bd->client.icccm.class))
               bd->desktop = efreet_util_desktop_wm_class_find(bd->client.icccm.name,
                                                               bd->client.icccm.class);
          }
        if (!bd->desktop)
          {
             /* libreoffice and maybe others match window class
                with .desktop file name */
             if (bd->client.icccm.class)
               {
                  char buf[128];
                  snprintf(buf, sizeof(buf), "%s.desktop", bd->client.icccm.class);
                  bd->desktop = efreet_util_desktop_file_id_find(buf);
               }
             if ((!bd->desktop) && (bd->client.icccm.class))
               {
                  char buf[4096], *s;

                  strncpy(buf, bd->client.icccm.class, sizeof(buf) - 1);
                  buf[sizeof(buf) - 1] = 0;
                  s = buf;
                  eina_str_tolower(&s);
                  if (strcmp(s, bd->client.icccm.class))
                    bd->desktop = efreet_util_desktop_exec_find(s);
               }
          }
        if (!bd->desktop)
          {
             bd->desktop = e_exec_startup_id_pid_find(bd->client.netwm.startup_id,
                                                      bd->client.netwm.pid);
             if (bd->desktop) efreet_desktop_ref(bd->desktop);
          }
        if (!bd->desktop && bd->client.icccm.name)
          {
             /* this works for most cases as fallback. useful when app is
                run from a shell  */
             bd->desktop = efreet_util_desktop_exec_find(bd->client.icccm.name);
          }
        if (!bd->desktop && bd->client.icccm.transient_for)
          {
             E_Border *bd2 = e_border_find_by_client_window(bd->client.icccm.transient_for);
             if (bd2 && bd2->desktop)
               {
                  efreet_desktop_ref(bd2->desktop);
                  bd->desktop = bd2->desktop;
               }
          }
        if (bd->desktop)
          {
             ecore_x_window_prop_string_set(bd->client.win, E_ATOM_DESKTOP_FILE,
                                            bd->desktop->orig_path);
          }

        bd->icon_object = e_border_icon_add(bd, e_comp_get(bd)->evas);
        if ((bd->focused) && (bd->icon_object))
          edje_object_signal_emit(bd->icon_object, "e,state,focused", "e");
        if (bd->bg_object)
          {
             evas_object_show(bd->icon_object);
             edje_object_part_swallow(bd->bg_object, "e.swallow.icon", bd->icon_object);
          }
        else
          evas_object_hide(bd->icon_object);

        {
           E_Event_Border_Icon_Change *ev;

           ev = E_NEW(E_Event_Border_Icon_Change, 1);
           ev->border = bd;
           e_object_ref(E_OBJECT(bd));
           //	     e_object_breadcrumb_add(E_OBJECT(bd), "border_icon_change_event");
           ecore_event_add(E_EVENT_BORDER_ICON_CHANGE, ev,
                           _e_border_event_border_icon_change_free, NULL);
        }
        if ((bd->new_client || bd->re_manage) && bd->desktop && (!bd->exe_inst))
          e_exec_phony(bd);
        bd->changes.icon = 0;
     }

   bd->new_client = 0;
   bd->changed = 0;
   bd->changes.stack = 0;

   if ((bd->take_focus) || (bd->want_focus))
     {
        bd->take_focus = 0;
        if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) || (bd->want_focus))
          {
             bd->want_focus = 0;
             e_border_focus_set_with_pointer(bd);
          }
        else if ((bd->client.netwm.type == ECORE_X_WINDOW_TYPE_DIALOG) ||
                 (bd->parent && (bd->parent->modal == bd)))
          {
             if ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) ||
                 ((e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED) &&
                  (e_border_find_by_client_window(bd->client.icccm.transient_for) ==
                   e_border_focused_get())))
               {
                  e_border_focus_set_with_pointer(bd);
               }
          }
        else
          {
             /* focus window by default when it is the only one on desk */
             E_Border *bd2 = NULL;
             Eina_List *l;
             EINA_LIST_FOREACH(focus_stack, l, bd2)
               {
                  if (bd == bd2) continue;
                  if ((!bd2->iconic) && (bd2->visible) &&
                      ((bd->desk == bd2->desk) || bd2->sticky))
                    break;
               }

             if (!bd2)
               {
                  e_border_focus_set_with_pointer(bd);
               }
          }
     }

   if (bd->need_maximize)
     {
        E_Maximize max;
        max = bd->maximized;
        bd->maximized = E_MAXIMIZE_NONE;
        e_border_maximize(bd, max);
        bd->need_maximize = 0;
     }

   if (bd->need_fullscreen)
     {
        e_border_fullscreen(bd, e_config->fullscreen_policy);
        bd->need_fullscreen = 0;
     }

   if (rem_change)
     e_remember_update(bd);

   if (send_event) // FIXME: send only if a property changed - above need to
     { // check on that. for now - always send.
       event = E_NEW(E_Event_Border_Property, 1);
       event->border = bd;
       e_object_ref(E_OBJECT(bd));
       ecore_event_add(E_EVENT_BORDER_PROPERTY, event, _e_border_event_border_property_free, NULL);
     }
   _e_border_hook_call(E_BORDER_HOOK_EVAL_END, bd);
}

static void
_e_border_moveinfo_gather(E_Border *bd,
                          const char *source)
{
   if (e_util_glob_match(source, "mouse,*,1")) bd->moveinfo.down.button = 1;
   else if (e_util_glob_match(source, "mouse,*,2"))
     bd->moveinfo.down.button = 2;
   else if (e_util_glob_match(source, "mouse,*,3"))
     bd->moveinfo.down.button = 3;
   else bd->moveinfo.down.button = 0;
   if ((bd->moveinfo.down.button >= 1) && (bd->moveinfo.down.button <= 3))
     {
        bd->moveinfo.down.mx = bd->mouse.last_down[bd->moveinfo.down.button - 1].mx;
        bd->moveinfo.down.my = bd->mouse.last_down[bd->moveinfo.down.button - 1].my;
     }
   else
     {
        bd->moveinfo.down.mx = bd->mouse.current.mx;
        bd->moveinfo.down.my = bd->mouse.current.my;
     }
}

static void
_e_border_resize_handle(E_Border *bd)
{
   int x, y, w, h;
   int new_x, new_y, new_w, new_h;
   int tw, th;
   Eina_List *skiplist = NULL;

   x = bd->x;
   y = bd->y;
   w = bd->w;
   h = bd->h;

   if ((bd->resize_mode == E_POINTER_RESIZE_TR) ||
       (bd->resize_mode == E_POINTER_RESIZE_R) ||
       (bd->resize_mode == E_POINTER_RESIZE_BR))
     {
        if ((bd->moveinfo.down.button >= 1) &&
            (bd->moveinfo.down.button <= 3))
          w = bd->mouse.last_down[bd->moveinfo.down.button - 1].w +
            (bd->mouse.current.mx - bd->moveinfo.down.mx);
        else
          w = bd->moveinfo.down.w + (bd->mouse.current.mx - bd->moveinfo.down.mx);
     }
   else if ((bd->resize_mode == E_POINTER_RESIZE_TL) ||
            (bd->resize_mode == E_POINTER_RESIZE_L) ||
            (bd->resize_mode == E_POINTER_RESIZE_BL))
     {
        if ((bd->moveinfo.down.button >= 1) &&
            (bd->moveinfo.down.button <= 3))
          w = bd->mouse.last_down[bd->moveinfo.down.button - 1].w -
            (bd->mouse.current.mx - bd->moveinfo.down.mx);
        else
          w = bd->moveinfo.down.w - (bd->mouse.current.mx - bd->moveinfo.down.mx);
     }

   if ((bd->resize_mode == E_POINTER_RESIZE_TL) ||
       (bd->resize_mode == E_POINTER_RESIZE_T) ||
       (bd->resize_mode == E_POINTER_RESIZE_TR))
     {
        if ((bd->moveinfo.down.button >= 1) &&
            (bd->moveinfo.down.button <= 3))
          h = bd->mouse.last_down[bd->moveinfo.down.button - 1].h -
            (bd->mouse.current.my - bd->moveinfo.down.my);
        else
          h = bd->moveinfo.down.h - (bd->mouse.current.my - bd->moveinfo.down.my);
     }
   else if ((bd->resize_mode == E_POINTER_RESIZE_BL) ||
            (bd->resize_mode == E_POINTER_RESIZE_B) ||
            (bd->resize_mode == E_POINTER_RESIZE_BR))
     {
        if ((bd->moveinfo.down.button >= 1) &&
            (bd->moveinfo.down.button <= 3))
          h = bd->mouse.last_down[bd->moveinfo.down.button - 1].h +
            (bd->mouse.current.my - bd->moveinfo.down.my);
        else
          h = bd->moveinfo.down.h + (bd->mouse.current.my - bd->moveinfo.down.my);
     }

   tw = bd->w;
   th = bd->h;

   if ((bd->resize_mode == E_POINTER_RESIZE_TL) ||
       (bd->resize_mode == E_POINTER_RESIZE_L) ||
       (bd->resize_mode == E_POINTER_RESIZE_BL))
     x += (tw - w);
   if ((bd->resize_mode == E_POINTER_RESIZE_TL) ||
       (bd->resize_mode == E_POINTER_RESIZE_T) ||
       (bd->resize_mode == E_POINTER_RESIZE_TR))
     y += (th - h);

   skiplist = eina_list_append(skiplist, bd);
   e_resist_container_border_position(bd->zone->container, skiplist,
                                      bd->x, bd->y, bd->w, bd->h,
                                      x, y, w, h,
                                      &new_x, &new_y, &new_w, &new_h);
   eina_list_free(skiplist);

   w = new_w;
   h = new_h;
   e_border_resize_limit(bd, &new_w, &new_h);
   if ((bd->resize_mode == E_POINTER_RESIZE_TL) ||
       (bd->resize_mode == E_POINTER_RESIZE_L) ||
       (bd->resize_mode == E_POINTER_RESIZE_BL))
     new_x += (w - new_w);
   if ((bd->resize_mode == E_POINTER_RESIZE_TL) ||
       (bd->resize_mode == E_POINTER_RESIZE_T) ||
       (bd->resize_mode == E_POINTER_RESIZE_TR))
     new_y += (h - new_h);

   e_border_move_resize(bd, new_x, new_y, new_w, new_h);
}

static Eina_Bool
_e_border_shade_animator(void *data)
{
   E_Border *bd = data;
   E_Event_Border_Simple *ev;
   Eina_Bool move = EINA_FALSE;
   double dt, val;
   double dur = bd->client.h / e_config->border_shade_speed;

   dt = ecore_loop_time_get() - bd->shade.start;
   val = dt / dur;

   if (val < 0.0) val = 0.0;
   else if (val > 1.0)
     val = 1.0;

   if (e_config->border_shade_transition == E_TRANSITION_SINUSOIDAL)
     {
        bd->shade.val =
          ecore_animator_pos_map(val, ECORE_POS_MAP_SINUSOIDAL, 0.0, 0.0);
        if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val;
     }
   else if (e_config->border_shade_transition == E_TRANSITION_DECELERATE)
     {
        bd->shade.val =
          ecore_animator_pos_map(val, ECORE_POS_MAP_DECELERATE, 0.0, 0.0);
        if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val;
     }
   else if (e_config->border_shade_transition == E_TRANSITION_ACCELERATE)
     {
        bd->shade.val =
          ecore_animator_pos_map(val, ECORE_POS_MAP_ACCELERATE, 0.0, 0.0);
        if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val;
     }
   else if (e_config->border_shade_transition == E_TRANSITION_LINEAR)
     {
        bd->shade.val =
          ecore_animator_pos_map(val, ECORE_POS_MAP_LINEAR, 0.0, 0.0);
        if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val;
     }
   else if (e_config->border_shade_transition == E_TRANSITION_ACCELERATE_LOTS)
     {
        bd->shade.val =
          ecore_animator_pos_map(val, ECORE_POS_MAP_ACCELERATE_FACTOR, 1.7, 0.0);
        if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val;
     }
   else if (e_config->border_shade_transition == E_TRANSITION_DECELERATE_LOTS)
     {
        bd->shade.val =
          ecore_animator_pos_map(val, ECORE_POS_MAP_DECELERATE_FACTOR, 1.7, 0.0);
        if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val;
     }
   else if (e_config->border_shade_transition == E_TRANSITION_SINUSOIDAL_LOTS)
     {
        bd->shade.val =
          ecore_animator_pos_map(val, ECORE_POS_MAP_SINUSOIDAL_FACTOR, 1.7, 0.0);
        if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val;
     }
   else if (e_config->border_shade_transition == E_TRANSITION_BOUNCE)
     {
        bd->shade.val =
          ecore_animator_pos_map(val, ECORE_POS_MAP_BOUNCE, 1.2, 3.0);
        if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val;
     }
   else if (e_config->border_shade_transition == E_TRANSITION_BOUNCE_LOTS)
     {
        bd->shade.val =
          ecore_animator_pos_map(val, ECORE_POS_MAP_BOUNCE, 1.2, 5.0);
        if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val;
     }
   else
     {
        bd->shade.val =
          ecore_animator_pos_map(val, ECORE_POS_MAP_LINEAR, 0.0, 0.0);
        if (!bd->shaded) bd->shade.val = 1.0 - bd->shade.val;
     }

   /* due to M_PI's innacuracy, cos(M_PI/2) != 0.0, so we need this */
   if (bd->shade.val < 0.001) bd->shade.val = 0.0;
   else if (bd->shade.val > .999)
     bd->shade.val = 1.0;

   if (bd->shade.dir == E_DIRECTION_UP)
     bd->h = bd->client_inset.t + bd->client.h * bd->shade.val;
   else if (bd->shade.dir == E_DIRECTION_DOWN)
     {
        bd->h = bd->client_inset.t + bd->client.h * bd->shade.val;
        bd->y = bd->shade.y + bd->client.h * (1 - bd->shade.val);
        move = EINA_TRUE;
     }
   else if (bd->shade.dir == E_DIRECTION_LEFT)
     bd->w = bd->client_inset.t + bd->client.w * bd->shade.val;
   else if (bd->shade.dir == E_DIRECTION_RIGHT)
     {
        bd->w = bd->client_inset.t + bd->client.w * bd->shade.val;
        bd->x = bd->shade.x + bd->client.w * (1 - bd->shade.val);
        move = EINA_TRUE;
     }

   if (bd->client.shaped)
     {
        bd->need_shape_merge = 1;
        bd->need_shape_export = 1;
     }
   if (bd->shaped_input)
     {
        bd->need_shape_merge = 1;
     }
   BD_CHANGED(bd);

   /* we're done */
   if (val == 1)
     {
        bd->shading = 0;
        bd->shaded = !(bd->shaded);
        bd->changes.shaded = 1;
        bd->changes.shading = 1;
        bd->shade.anim = NULL;

        if (bd->shaded)
          edje_object_signal_emit(bd->bg_object, "e,state,shaded", "e");
        else
          edje_object_signal_emit(bd->bg_object, "e,state,unshaded", "e");
        edje_object_message_signal_process(bd->bg_object);
        e_border_frame_recalc(bd);
        e_border_comp_hidden_set(bd, bd->shaded);
     }
   if (move)
     {
        ev = E_NEW(E_Event_Border_Simple, 1);
        ev->border = bd;
        e_object_ref(E_OBJECT(bd));
        ecore_event_add(E_EVENT_BORDER_MOVE, ev, _e_border_event_border_move_free, NULL);
        e_container_shape_move(bd->shape, bd->x, bd->y);
     }
   e_container_shape_resize(bd->shape, bd->w, bd->h);
   ev = E_NEW(E_Event_Border_Simple, 1);
   ev->border = bd;
   e_object_ref(E_OBJECT(bd));
//	e_object_breadcrumb_add(E_OBJECT(bd), "border_resize_event");
   ecore_event_add(E_EVENT_BORDER_RESIZE, ev, _e_border_event_border_resize_free, NULL);
   return (val != 1);
}

static void
_e_border_event_border_resize_free(void *data __UNUSED__,
                                   void *ev)
{
   E_Event_Border_Resize *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_resize_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_move_free(void *data __UNUSED__,
                                 void *ev)
{
   E_Event_Border_Move *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_move_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_add_free(void *data __UNUSED__,
                                void *ev)
{
   E_Event_Border_Add *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_add_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_remove_free(void *data __UNUSED__,
                                   void *ev)
{
   E_Event_Border_Remove *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_remove_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_show_free(void *data __UNUSED__,
                                 void *ev)
{
   E_Event_Border_Show *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_show_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_hide_free(void *data __UNUSED__,
                                 void *ev)
{
   E_Event_Border_Hide *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_hide_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_iconify_free(void *data __UNUSED__,
                                    void *ev)
{
   E_Event_Border_Iconify *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_iconify_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_uniconify_free(void *data __UNUSED__,
                                      void *ev)
{
   E_Event_Border_Uniconify *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_uniconify_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_stick_free(void *data __UNUSED__,
                                  void *ev)
{
   E_Event_Border_Stick *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_stick_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_unstick_free(void *data __UNUSED__,
                                    void *ev)
{
   E_Event_Border_Unstick *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_unstick_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_zone_set_free(void *data __UNUSED__,
                                     void *ev)
{
   E_Event_Border_Zone_Set *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_zone_set_event");
   e_object_unref(E_OBJECT(e->border));
   e_object_unref(E_OBJECT(e->zone));
   E_FREE(e);
}

static void
_e_border_event_border_desk_set_free(void *data __UNUSED__,
                                     void *ev)
{
   E_Event_Border_Desk_Set *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_desk_set_event");
   e_object_unref(E_OBJECT(e->border));
   e_object_unref(E_OBJECT(e->desk));
   E_FREE(e);
}

static void
_e_border_event_border_stack_free(void *data __UNUSED__,
                                  void *ev)
{
   E_Event_Border_Stack *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_raise_event");
   e_object_unref(E_OBJECT(e->border));
   if (e->stack)
     {
//	e_object_breadcrumb_del(E_OBJECT(e->above), "border_raise_event.above");
        e_object_unref(E_OBJECT(e->stack));
     }
   E_FREE(e);
}

static void
_e_border_event_border_icon_change_free(void *data __UNUSED__,
                                        void *ev)
{
   E_Event_Border_Icon_Change *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_icon_change_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_title_change_free(void *data __UNUSED__,
                                        void *ev)
{
   E_Event_Border_Title_Change *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_icon_change_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_urgent_change_free(void *data __UNUSED__,
                                          void *ev)
{
   E_Event_Border_Urgent_Change *e;

   e = ev;
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_focus_in_free(void *data __UNUSED__,
                                     void *ev)
{
   E_Event_Border_Focus_In *e;

   e = ev;
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_focus_out_free(void *data __UNUSED__,
                                      void *ev)
{
   E_Event_Border_Focus_Out *e;

   e = ev;
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_property_free(void *data __UNUSED__,
                                     void *ev)
{
   E_Event_Border_Property *e;

   e = ev;
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_fullscreen_free(void *data __UNUSED__,
                                       void *ev)
{
   E_Event_Border_Fullscreen *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_fullscreen_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_event_border_unfullscreen_free(void *data __UNUSED__,
                                         void *ev)
{
   E_Event_Border_Unfullscreen *e;

   e = ev;
//   e_object_breadcrumb_del(E_OBJECT(e->border), "border_unfullscreen_event");
   e_object_unref(E_OBJECT(e->border));
   E_FREE(e);
}

static void
_e_border_zone_update(E_Border *bd)
{
   E_Container *con;
   Eina_List *l;
   E_Zone *zone;

   /* still within old zone - leave it there */
   if (E_INTERSECTS(bd->x, bd->y, bd->w, bd->h,
                    bd->zone->x, bd->zone->y, bd->zone->w, bd->zone->h))
     return;
   /* find a new zone */
   con = bd->zone->container;
   EINA_LIST_FOREACH(con->zones, l, zone)
     {
        if (E_INTERSECTS(bd->x, bd->y, bd->w, bd->h,
                         zone->x, zone->y, zone->w, zone->h))
          {
             e_border_zone_set(bd, zone);
             return;
          }
     }
}

static int
_e_border_resize_begin(E_Border *bd)
{
   if (!bd->lock_user_stacking)
     {
        if (e_config->border_raise_on_mouse_action)
          e_border_raise(bd);
     }
   if ((bd->shaded) || (bd->shading) ||
       (bd->fullscreen) || (bd->lock_user_size))
     return 0;

   if (!_e_border_action_input_win_new(bd))
     {
        grabbed = 0;
        return 0;
     }

   if (bd->client.netwm.sync.request)
     {
        bd->client.netwm.sync.alarm = ecore_x_sync_alarm_new(bd->client.netwm.sync.counter);
        bd->client.netwm.sync.serial = 1;
        bd->client.netwm.sync.wait = 0;
        bd->client.netwm.sync.send_time = ecore_loop_time_get();
     }

   _e_border_hook_call(E_BORDER_HOOK_RESIZE_BEGIN, bd);

   bdresize = bd;
   return 1;
}

static int
_e_border_resize_end(E_Border *bd)
{
   if (grabbed)
     {
        e_grabinput_release(bd->win, bd->win);
        grabbed = 0;
     }
   if (bd->client.netwm.sync.alarm)
     {
        E_Border_Pending_Move_Resize *pnd;

        ecore_x_sync_alarm_free(bd->client.netwm.sync.alarm);
        bd->client.netwm.sync.alarm = 0;
        /* resize to last geometry if sync alarm for it was not yet handled */
        if (bd->pending_move_resize)
          {
             BD_CHANGED(bd);
             bd->changes.pos = 1;
             bd->changes.size = 1;
             _e_border_client_move_resize_send(bd);
          }

        EINA_LIST_FREE(bd->pending_move_resize, pnd)
          E_FREE(pnd);
     }
   e_pointer_mode_pop(bd, bd->resize_mode);
   bd->resize_mode = E_POINTER_RESIZE_NONE;
   _e_border_hook_call(E_BORDER_HOOK_RESIZE_END, bd);

   bdresize = NULL;

   /* If this border was maximized, we need to unset Maximized state or
    * on restart, E still thinks it's maximized */
   if (bd->maximized != E_MAXIMIZE_NONE)
     e_hints_window_maximized_set(bd, bd->maximized & E_MAXIMIZE_NONE,
                                  bd->maximized & E_MAXIMIZE_NONE);
   return 1;
}

static void
_e_border_resize_update(E_Border *bd)
{
   _e_border_hook_call(E_BORDER_HOOK_RESIZE_UPDATE, bd);
}

static int
_e_border_move_begin(E_Border *bd)
{
   if (!bd->lock_user_stacking)
     {
        if (e_config->border_raise_on_mouse_action)
          e_border_raise(bd);
     }
   if ((bd->fullscreen) || (bd->lock_user_location))
     return 0;

   if (grabbed && !e_grabinput_get(bd->win, 0, bd->win))
     {
        grabbed = 0;
        return 0;
     }
#if 0
   if (bd->client.netwm.sync.request)
     {
        bd->client.netwm.sync.alarm = ecore_x_sync_alarm_new(bd->client.netwm.sync.counter);
        bd->client.netwm.sync.serial = 0;
        bd->client.netwm.sync.wait = 0;
        bd->client.netwm.sync.time = ecore_loop_time_get();
     }
#endif
   _e_border_hook_call(E_BORDER_HOOK_MOVE_BEGIN, bd);

   bdmove = bd;
   return 1;
}

static int
_e_border_move_end(E_Border *bd)
{
   if (grabbed)
     {
        e_grabinput_release(bd->win, bd->win);
        grabbed = 0;
     }
#if 0
   if (bd->client.netwm.sync.alarm)
     {
        ecore_x_sync_alarm_free(bd->client.netwm.sync.alarm);
        bd->client.netwm.sync.alarm = 0;
     }
#endif
   e_pointer_mode_pop(bd, E_POINTER_MOVE);
   bd->moving = 0;
   _e_border_hook_call(E_BORDER_HOOK_MOVE_END, bd);

   bdmove = NULL;
   return 1;
}

static void
_e_border_move_update(E_Border *bd)
{
   _e_border_hook_call(E_BORDER_HOOK_MOVE_UPDATE, bd);
}

static Eina_Bool
_e_border_cb_ping_poller(void *data)
{
   E_Border *bd;

   bd = data;
   if (bd->ping_ok)
     {
        if (bd->hung)
          {
             bd->hung = 0;
             edje_object_signal_emit(bd->bg_object, "e,state,unhung", "e");
             if (bd->kill_timer)
               {
                  ecore_timer_del(bd->kill_timer);
                  bd->kill_timer = NULL;
               }
          }
     }
   else
     {
        /* if time between last ping and now is greater
         * than half the ping interval... */
        if ((ecore_loop_time_get() - bd->ping) >
            ((e_config->ping_clients_interval *
              ecore_poller_poll_interval_get(ECORE_POLLER_CORE)) / 2.0))
          {
             if (!bd->hung)
               {
                  bd->hung = 1;
                  edje_object_signal_emit(bd->bg_object, "e,state,hung", "e");
                  /* FIXME: if below dialog is up - hide it now */
               }
             if (bd->delete_requested)
               {
                  /* FIXME: pop up dialog saying app is hung - kill client, or pid */
                  e_border_act_kill_begin(bd);
               }
          }
     }
   bd->ping_poller = NULL;
   e_border_ping(bd);
   return ECORE_CALLBACK_CANCEL;
}

static Eina_Bool
_e_border_cb_kill_timer(void *data)
{
   E_Border *bd;

   bd = data;
// dont wait until it's hung -
//   if (bd->hung)
//     {
   if (bd->client.netwm.pid > 1)
     kill(bd->client.netwm.pid, SIGKILL);
//     }
   bd->kill_timer = NULL;
   return ECORE_CALLBACK_CANCEL;
}

static Eina_List *_e_border_hooks = NULL;
static int _e_border_hooks_delete = 0;
static int _e_border_hooks_walking = 0;

static void
_e_border_hooks_clean(void)
{
   Eina_List *l, *ln;
   E_Border_Hook *bh;

   EINA_LIST_FOREACH_SAFE(_e_border_hooks, l, ln, bh)
     {
        if (bh->delete_me)
          {
             _e_border_hooks = eina_list_remove_list(_e_border_hooks, l);
             free(bh);
          }
     }
}

static void
_e_border_hook_call(E_Border_Hook_Point hookpoint,
                    void *bd)
{
   Eina_List *l;
   E_Border_Hook *bh;

   _e_border_hooks_walking++;
   EINA_LIST_FOREACH(_e_border_hooks, l, bh)
     {
        if (bh->delete_me) continue;
        if (bh->hookpoint == hookpoint) bh->func(bh->data, bd);
     }
   _e_border_hooks_walking--;
   if ((_e_border_hooks_walking == 0) && (_e_border_hooks_delete > 0))
     _e_border_hooks_clean();
}

EAPI E_Border_Hook *
e_border_hook_add(E_Border_Hook_Point hookpoint,
                  void (*func)(void *data,
                               void *bd),
                  void *data)
{
   E_Border_Hook *bh;

   bh = E_NEW(E_Border_Hook, 1);
   if (!bh) return NULL;
   bh->hookpoint = hookpoint;
   bh->func = func;
   bh->data = data;
   _e_border_hooks = eina_list_append(_e_border_hooks, bh);
   return bh;
}

EAPI void
e_border_hook_del(E_Border_Hook *bh)
{
   bh->delete_me = 1;
   if (_e_border_hooks_walking == 0)
     {
        _e_border_hooks = eina_list_remove(_e_border_hooks, bh);
        free(bh);
     }
   else
     _e_border_hooks_delete++;
}

EAPI void
e_border_focus_track_freeze(void)
{
   focus_track_frozen++;
}

EAPI void
e_border_focus_track_thaw(void)
{
   focus_track_frozen--;
}

static E_Border *
_e_border_under_pointer_helper(E_Desk *desk, E_Border *exclude, int x, int y)
{
   E_Border *bd = NULL, *cbd;
   Eina_List *l;

   EINA_LIST_FOREACH(e_border_raise_stack_get(), l, cbd)
     {
        if (!cbd) continue;
        /* If a border was specified which should be excluded from the list
         * (because it will be closed shortly for example), skip */
        if ((exclude) && (cbd == exclude)) continue;
        if ((desk) && (cbd->desk != desk)) continue;
        if (!E_INSIDE(x, y, cbd->x, cbd->y, cbd->w, cbd->h))
          continue;
        /* If the layer is higher, the position of the window is higher
         * (always on top vs always below) */
        if (!bd || (cbd->layer > bd->layer))
          bd = cbd;
     }
   return bd;
}

EAPI E_Border *
e_border_under_pointer_get(E_Desk *desk,
                           E_Border *exclude)
{
   int x, y;

   /* We need to ensure that we can get the container window for the
    * zone of either the given desk or the desk of the excluded
    * window, so return if neither is given */
   if (desk)
     ecore_x_pointer_xy_get(desk->zone->container->win, &x, &y);
   else if (exclude)
     ecore_x_pointer_xy_get(exclude->desk->zone->container->win, &x, &y);
   else
     return NULL;

   return _e_border_under_pointer_helper(desk, exclude, x, y);
}

static Eina_Bool
_e_border_pointer_warp_to_center_timer(void *data __UNUSED__)
{
   if (warp_to)
     {
        int x, y;
        double spd;

        ecore_x_pointer_xy_get(warp_to_win, &x, &y);
        /* move hasn't happened yet */
        if ((x == warp_x[1]) && (y == warp_y[1]))
           return EINA_TRUE;
        if ((abs(x - warp_x[0]) > 5) || (abs(y - warp_y[0]) > 5))
          {
             /* User moved the mouse, so stop warping */
             warp_to = 0;
             goto cleanup;
          }

        spd = e_config->pointer_warp_speed;
        warp_x[1] = x = warp_x[0];
        warp_y[1] = y = warp_y[0];
        warp_x[0] = (x * (1.0 - spd)) + (warp_to_x * spd);
        warp_y[0] = (y * (1.0 - spd)) + (warp_to_y * spd);
        if ((warp_x[0] == x) && (warp_y[0] == y))
          {
             warp_x[0] = warp_to_x;
             warp_y[0] = warp_to_y;
             warp_to = 0;
             goto cleanup;
          }
        ecore_x_pointer_warp(warp_to_win, warp_x[0], warp_y[0]);
        return ECORE_CALLBACK_RENEW;
     }
cleanup:
   if (warp_timer) ecore_timer_del(warp_timer);
   warp_timer = NULL;
   e_border_focus_lock_set(EINA_FALSE);
   if (warp_timer_border)
     {
        warp_x[0] = warp_x[1] = warp_y[0] = warp_y[1] = -1;
        if (warp_timer_border->modal)
          {
             /* got a modal dialog during pointer warp...whoops */
             e_border_raise(warp_timer_border->modal);
             warp_timer_border = NULL;
             return ECORE_CALLBACK_CANCEL;
          }
        e_focus_event_mouse_in(warp_timer_border);
        if (warp_timer_border->iconic)
          {
             if (!warp_timer_border->lock_user_iconify)
               e_border_uniconify(warp_timer_border);
          }
        if (warp_timer_border->shaded)
          {
             if (!warp_timer_border->lock_user_shade)
               e_border_unshade(warp_timer_border, warp_timer_border->shade.dir);
          }

        if (!warp_timer_border->lock_focus_out)
          {
             e_border_focus_set(warp_timer_border, 1, 1);
             e_border_focus_latest_set(warp_timer_border);
          }
        warp_timer_border = NULL;
     }
   return ECORE_CALLBACK_CANCEL;
}

EAPI int
e_border_pointer_warp_to_center_now(E_Border *bd)
{
   if (e_config->disable_all_pointer_warps) return 0;
   if (warp_timer_border == bd)
     {
        ecore_x_pointer_warp(warp_to_win, warp_to_x, warp_to_y);
        warp_to = 0;
     }
   else
     {
        if (e_border_pointer_warp_to_center(bd))
          e_border_pointer_warp_to_center_now(bd);
     }
   return 1;
}

EAPI int
e_border_pointer_warp_to_center(E_Border *bd)
{
   int x, y;
   E_Border *cbd = NULL;

   if (e_config->disable_all_pointer_warps) return 0;
   /* Only warp the pointer if it is not already in the area of
    * the given border */
   ecore_x_pointer_xy_get(bd->zone->container->win, &x, &y);
   if ((x >= bd->x) && (x <= (bd->x + bd->w)) &&
       (y >= bd->y) && (y <= (bd->y + bd->h)))
     {
        cbd = _e_border_under_pointer_helper(bd->desk, bd, x, y);
        if (cbd == bd) return 0;
     }

   warp_to_x = bd->x + (bd->w / 2);
   if (warp_to_x < (bd->zone->x + 1))
     warp_to_x = bd->zone->x + ((bd->x + bd->w - bd->zone->x) / 2);
   else if (warp_to_x > (bd->zone->x + bd->zone->w))
     warp_to_x = (bd->zone->x + bd->zone->w + bd->x) / 2;

   warp_to_y = bd->y + (bd->h / 2);
   if (warp_to_y < (bd->zone->y + 1))
     warp_to_y = bd->zone->y + ((bd->y + bd->h - bd->zone->y) / 2);
   else if (warp_to_y > (bd->zone->y + bd->zone->h))
     warp_to_y = (bd->zone->y + bd->zone->h + bd->y) / 2;

   /* TODO: handle case where another border is over the exact center,
    * find a place where the requested border is not overlapped?
    *
   if (!cbd) cbd = _e_border_under_pointer_helper(bd->desk, bd, x, y);
   if (cbd != bd)
     {
     }
   */

   warp_to = 1;
   warp_to_win = bd->zone->container->win;
   ecore_x_pointer_xy_get(bd->zone->container->win, &warp_x[0], &warp_y[0]);
   if (warp_timer) ecore_timer_del(warp_timer);
   warp_timer = ecore_timer_add(0.01, _e_border_pointer_warp_to_center_timer, bd);
   warp_timer_border = bd;
   e_border_focus_lock_set(EINA_TRUE);
   return 1;
}

EAPI void
e_border_comp_hidden_set(E_Border *bd,
                         Eina_Bool hidden)
{
   E_Border *tmp;
   Eina_List *l;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp)
     {
        if (hidden)
          ecore_x_window_hide(tmp->win);
        else
          ecore_x_window_show(tmp->win);
     }

   if (bd->comp_hidden == hidden) return;

   bd->comp_hidden = hidden;

   if ((bd->comp_hidden) || (bd->tmp_input_hidden > 0))
     {
        ecore_x_composite_window_events_disable(bd->win);
        ecore_x_window_ignore_set(bd->win, EINA_TRUE);
     }
   else
     {
        ecore_x_composite_window_events_enable(bd->win);
        ecore_x_window_ignore_set(bd->win, EINA_FALSE);
     }
}

EAPI void
e_border_tmp_input_hidden_push(E_Border *bd)
{
   E_Border *tmp;
   Eina_List *l;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp)
     e_border_tmp_input_hidden_push(tmp);

   bd->tmp_input_hidden++;
   if (bd->tmp_input_hidden != 1) return;

   if ((bd->comp_hidden) || (bd->tmp_input_hidden > 0))
     {
        ecore_x_composite_window_events_disable(bd->win);
        ecore_x_window_ignore_set(bd->win, EINA_TRUE);
     }
   else
     {
        _e_border_shape_input_rectangle_set(bd);
        ecore_x_window_ignore_set(bd->win, EINA_FALSE);
     }
}

EAPI void
e_border_tmp_input_hidden_pop(E_Border *bd)
{
   E_Border *tmp;
   Eina_List *l;

   E_OBJECT_CHECK(bd);
   E_OBJECT_TYPE_CHECK(bd, E_BORDER_TYPE);

   EINA_LIST_FOREACH(bd->client.e.state.video_child, l, tmp)
     e_border_tmp_input_hidden_pop(tmp);

   bd->tmp_input_hidden--;
   if (bd->tmp_input_hidden != 0) return;

   if ((bd->comp_hidden) || (bd->tmp_input_hidden > 0))
     {
        ecore_x_composite_window_events_disable(bd->win);
        ecore_x_window_ignore_set(bd->win, EINA_TRUE);
     }
   else
     {
        _e_border_shape_input_rectangle_set(bd);
        ecore_x_window_ignore_set(bd->win, EINA_FALSE);
     }
}

EAPI void
e_border_activate(E_Border *bd, Eina_Bool just_do_it)
{
   if ((e_config->focus_setting == E_FOCUS_NEW_WINDOW) ||
       ((bd->parent) &&
        ((e_config->focus_setting == E_FOCUS_NEW_DIALOG) ||
         ((bd->parent->focused) &&
          (e_config->focus_setting == E_FOCUS_NEW_DIALOG_IF_OWNER_FOCUSED)))) ||
       (just_do_it))
     {
        if (bd->iconic)
          {
             if (e_config->clientlist_warp_to_iconified_desktop == 1)
               e_desk_show(bd->desk);

             if (!bd->lock_user_iconify)
               e_border_uniconify(bd);
          }
        if ((!bd->iconic) && (!bd->sticky))
          e_desk_show(bd->desk);
        if (!bd->lock_user_stacking) e_border_raise(bd);
        if (!bd->lock_focus_out)
          {
             /* XXX ooffice does send this request for
                config dialogs when the main window gets focus.
                causing the pointer to jump back and forth.  */
             if ((e_config->focus_policy != E_FOCUS_CLICK) && (!bd->new_client) &&
                 (!e_config->disable_all_pointer_warps) &&
                 !(bd->client.icccm.name && !strcmp(bd->client.icccm.name, "VCLSalFrame")))
               ecore_x_pointer_warp(bd->zone->container->win,
                                    bd->x + (bd->w / 2), bd->y + (bd->h / 2));
             e_border_focus_set(bd, 1, 1);
          }
     }
}

/*vim:ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0*/
