You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

4697 lines
153 KiB

#include "e.h"
/* data keys:
= keys that return objects =
- E_Client: the client associated with the object (E_Client*)
- comp_smart_obj: cw->smart_obj (Evas_Object*)
- comp_obj: cw (E_Comp_Object*)
= keys that are bool flags =
- client_restack: client needs a protocol-level restack
- comp_override: object is triggering a nocomp override to force compositing
- comp_ref: object has a ref from visibility animations
- comp_showing: object is currently running its show animation
- comp_hiding: object is currently running its hiding animation
- comp_object: object is a compositor-created object
- comp_object_skip: object has a name which prohibits theme shadows
- comp_object-to_del: list of objects which will be deleted when this object is deleted
- comp_mirror: object is the result of e_comp_object_util_mirror_add()
*/
#define UPDATE_MAX 512 // same as evas
#define FAILURE_MAX 2 // seems reasonable
#define SMART_NAME "e_comp_object"
/* for non-util functions */
#define API_ENTRY E_Comp_Object *cw; \
cw = evas_object_smart_data_get(obj); \
if ((!obj) || (!cw) || (e_util_strcmp(evas_object_type_get(obj), SMART_NAME))) return
/* for util functions (obj may or may not be E_Comp_Object */
#define SOFT_ENTRY(...) E_Comp_Object *cw; \
if (!obj) \
{ \
CRI("YOU PASSED NULL! ARGH!"); \
return __VA_ARGS__; \
} \
cw = evas_object_smart_data_get(obj); \
if ((!cw) || (e_util_strcmp(evas_object_type_get(obj), SMART_NAME))) \
cw = NULL
#define INTERNAL_ENTRY E_Comp_Object *cw; cw = evas_object_smart_data_get(obj);
/* enable for lots of client size info in console output */
#if 1
# define e_util_size_debug_set(x, y)
#endif
/* enable along with display-specific damage INF calls to enable render tracing
* SLOW!
*/
static int render_debug_enabled;
#define RENDER_DEBUG(...) do { if ((render_debug_enabled == 1) || ((render_debug_enabled == -1) && cw->ec->focused)) INF(__VA_ARGS__); } while (0)
typedef struct _E_Comp_Object
{
//EINA_INLIST;
int x, y, w, h; // geometry
Eina_Tiler *input_area;
E_Client *ec;
E_Comp_Object_Frame client_inset;
struct
{
double start;
double val;
int x, y;
E_Direction dir;
Ecore_Animator *anim;
} shade;
Eina_Stringshare *frame_theme;
Eina_Stringshare *frame_name;
Eina_Stringshare *visibility_effect; //effect when toggling visibility
Evas_Object *smart_obj; // smart object
Evas_Object *clip; // clipper over effect object
Eina_Array *input_objs; // input rect
Evas_Object *obj; // composite object
Evas_Object *frame_object; // for client frames
Evas_Object *frame_icon; // for client frames
Evas_Object *zoomobj; // zoomap
Evas_Object *shobj; // shadow object
Evas_Object *effect_obj; // effects object
Evas_Object *frame_volume; // volume level object
unsigned int layer; //e_comp_canvas_layer_map(cw->ec->layer)
Eina_List *obj_mirror; // extra mirror objects
Eina_List *obj_agent; // extra agent objects
Eina_Tiler *updates; //render update regions
Eina_Tiler *pending_updates; //render update regions which are about to render
Evas_Native_Surface *ns; //for custom gl rendering
double action_client_loop_time; //loop time when client's action ended
unsigned int update_count; // how many updates have happened to this obj
unsigned int opacity; // opacity set with _NET_WM_WINDOW_OPACITY
unsigned int animating; // it's busy animating
unsigned int failures; //number of consecutive e_pixmap_image_draw() failures
unsigned int force_visible; //number of visible obj_mirror objects
Eina_Bool deleted E_BITFIELD; // deleted
Eina_Bool defer_hide E_BITFIELD; // flag to get hide to work on deferred hide
Eina_Bool showing E_BITFIELD; // object is currently in "show" animation
Eina_Bool visible E_BITFIELD; // is visible
Eina_Bool shaped E_BITFIELD; // is shaped
Eina_Bool update E_BITFIELD; // has updates to fetch
Eina_Bool redirected E_BITFIELD; // has updates to fetch
Eina_Bool native E_BITFIELD; // native
Eina_Bool nocomp E_BITFIELD; // nocomp applied
Eina_Bool nocomp_need_update E_BITFIELD; // nocomp in effect, but this window updated while in nocomp mode
Eina_Bool real_hid E_BITFIELD; // last hide was a real window unmap
Eina_Bool effect_set E_BITFIELD; //effect_obj has a valid group
Eina_Bool effect_running E_BITFIELD; //effect_obj is playing an animation
Eina_Bool effect_clip E_BITFIELD; //effect_obj is clipped
Eina_Bool effect_clip_able E_BITFIELD; //effect_obj will be clipped for effects
Eina_Bool zoomap_disabled E_BITFIELD; //whether zoomap is usable
Eina_Bool updates_exist E_BITFIELD;
Eina_Bool updates_full E_BITFIELD; // entire object will be updated
Eina_Bool force_move E_BITFIELD;
Eina_Bool frame_extends E_BITFIELD; //frame may extend beyond object size
Eina_Bool blanked E_BITFIELD; //window is rendering blank content (externally composited)
Eina_Bool agent_updating E_BITFIELD; //updating agents
} E_Comp_Object;
struct E_Comp_Object_Mover
{
EINA_INLIST;
E_Comp_Object_Mover_Cb func;
const char *sig;
void *data;
int pri;
};
static Eina_Inlist *_e_comp_object_movers = NULL;
static Evas_Smart *_e_comp_smart = NULL;
/* sekrit functionzzz */
EINTERN void e_client_focused_set(E_Client *ec);
/* emitted every time a new noteworthy comp object is added */
E_API int E_EVENT_COMP_OBJECT_ADD = -1;
static void
_e_comp_object_event_free(void *d EINA_UNUSED, void *event)
{
E_Event_Comp_Object *ev = event;
E_Client *ec;
ec = evas_object_data_get(ev->comp_object, "E_Client");
if (ec)
{
UNREFD(ec, 1);
e_object_unref(E_OBJECT(ec));
}
evas_object_unref(ev->comp_object);
free(ev);
}
static void
_e_comp_object_event_add(Evas_Object *obj)
{
E_Event_Comp_Object *ev;
E_Client *ec;
ev = E_NEW(E_Event_Comp_Object, 1);
evas_object_ref(obj);
ev->comp_object = obj;
ec = evas_object_data_get(ev->comp_object, "E_Client");
if (ec)
{
REFD(ec, 1);
e_object_ref(E_OBJECT(ec));
}
ecore_event_add(E_EVENT_COMP_OBJECT_ADD, ev, _e_comp_object_event_free, NULL);
}
/////////////////////////////////////
static void
_e_comp_object_cb_agent_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
E_Comp_Object *cw = data;
cw->obj_agent = eina_list_remove(cw->obj_agent, obj);
}
static void
_e_comp_object_cb_agent_resize(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
E_Comp_Object *cw = data;
int w, h;
if (cw->agent_updating) return;
evas_object_geometry_get(obj, NULL, NULL, &w, &h);
evas_object_resize(cw->smart_obj, w, h);
}
static void
_e_comp_object_cb_agent_move(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
E_Comp_Object *cw = data;
int x, y;
if (cw->agent_updating) return;
evas_object_geometry_get(obj, &x, &y, NULL, NULL);
evas_object_move(cw->smart_obj, x, y);
}
/////////////////////////////////////
static void
_e_comp_object_cb_mirror_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
E_Comp_Object *cw = data;
cw->obj_mirror = eina_list_remove(cw->obj_mirror, obj);
}
static void
_e_comp_object_cb_mirror_show(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Comp_Object *cw = data;
if ((!cw->force_visible) && (!cw->deleted) && (!e_object_is_del(E_OBJECT(cw->ec))))
evas_object_smart_callback_call(cw->smart_obj, "visibility_force", cw->ec);
cw->force_visible++;
if ((!cw->native) && cw->pending_updates && (!cw->update) && cw->real_hid)
e_comp_object_render(cw->smart_obj);
}
static void
_e_comp_object_cb_mirror_hide(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
E_Comp_Object *cw = data;
cw->force_visible--;
if ((!cw->force_visible) && (!cw->deleted) && (!e_object_is_del(E_OBJECT(cw->ec))))
evas_object_smart_callback_call(cw->smart_obj, "visibility_normal", cw->ec);
}
/////////////////////////////////////
static inline Eina_Bool
_e_comp_shaped_check(int w, int h, const Eina_Rectangle *rects, int num)
{
if (num > 1) return EINA_TRUE;
if ((rects[0].x == 0) && (rects[0].y == 0) &&
((int)rects[0].w == w) && ((int)rects[0].h == h))
return EINA_FALSE;
return EINA_TRUE;
}
/////////////////////////////////////
/* add a client to the layer-client list */
static void
_e_comp_object_layers_add(E_Comp_Object *cw, E_Comp_Object *above, E_Comp_Object *below, Eina_Bool prepend)
{
E_Comp_Object *layer_cw = NULL;
/* try to get the internal data for the layer;
* will return NULL for fake layers (eg. wayland)
*/
if (e_comp->layers[cw->layer].obj)
layer_cw = evas_object_smart_data_get(e_comp->layers[cw->layer].obj);
if (layer_cw == cw) layer_cw = NULL;
/*
if (above)
e_comp->layers[cw->layer].objs = eina_inlist_append_relative(e_comp->layers[cw->layer].objs, EINA_INLIST_GET(cw), EINA_INLIST_GET(cw2));
else if (below)
e_comp->layers[cw->layer].objs = eina_inlist_prepend_relative(e_comp->layers[cw->layer].objs, EINA_INLIST_GET(cw), EINA_INLIST_GET(cw2));
else
{
if (prepend)
e_comp->layers[cw->layer].objs = eina_inlist_prepend(e_comp->layers[cw->layer].objs, EINA_INLIST_GET(cw));
else
e_comp->layers[cw->layer].objs = eina_inlist_append(e_comp->layers[cw->layer].objs, EINA_INLIST_GET(cw));
}
e_comp->layers[cw->layer].objs_count++;
if (!cw->ec) return;
*/
if (above)
e_comp->layers[above->layer].clients = eina_inlist_append_relative(e_comp->layers[above->layer].clients, EINA_INLIST_GET(cw->ec), EINA_INLIST_GET(above->ec));
else if (below)
e_comp->layers[below->layer].clients = eina_inlist_prepend_relative(e_comp->layers[below->layer].clients, EINA_INLIST_GET(cw->ec), EINA_INLIST_GET(below->ec));
if ((!above) && (!below))
{
if (prepend)
e_comp->layers[cw->layer].clients = eina_inlist_prepend(e_comp->layers[cw->layer].clients, EINA_INLIST_GET(cw->ec));
else if (layer_cw)
e_comp->layers[cw->layer].clients = eina_inlist_prepend_relative(e_comp->layers[cw->layer].clients, EINA_INLIST_GET(cw->ec), EINA_INLIST_GET(layer_cw->ec));
else //this is either the layer object or a tough actin tinactin^W^W^Wfast stacking client
e_comp->layers[cw->layer].clients = eina_inlist_append(e_comp->layers[cw->layer].clients, EINA_INLIST_GET(cw->ec));
}
e_comp->layers[cw->layer].clients_count++;
#ifndef E_RELEASE_BUILD
if (layer_cw)
{
E_Client *below_ec = e_client_below_get(cw->ec);
if (below_ec)
{
if (e_comp->layers[cw->layer].obj == below_ec->frame)
CRI("ACK!");
}
}
#endif
}
static void
_e_comp_object_layers_remove(E_Comp_Object *cw)
{
if (cw->ec && e_comp->layers[cw->layer].clients)
{
e_comp->layers[cw->layer].clients = eina_inlist_remove(e_comp->layers[cw->layer].clients, EINA_INLIST_GET(cw->ec));
e_comp->layers[cw->layer].clients_count--;
}
/*
e_comp->layers[cw->layer].objs = eina_inlist_remove(e_comp->layers[cw->layer].objs, EINA_INLIST_GET(cw));
e_comp->layers[cw->layer].objs_count--;
*/
}
/////////////////////////////////////
static void
_e_comp_object_updates_init(E_Comp_Object *cw)
{
int pw, ph;
if (cw->updates) return;
pw = cw->ec->client.w, ph = cw->ec->client.h;
if ((!pw) || (!ph))
e_pixmap_size_get(cw->ec->pixmap, &pw, &ph);
if ((!pw) || (!ph)) return;
cw->updates = eina_tiler_new(pw, ph);
if (cw->updates)
eina_tiler_tile_size_set(cw->updates, 1, 1);
}
static void
_e_comp_object_alpha_set(E_Comp_Object *cw)
{
Eina_Bool alpha;
if (!e_pixmap_is_x(cw->ec->pixmap))
alpha = e_pixmap_image_is_argb(cw->ec->pixmap);
else
alpha = cw->ec->argb;
if (cw->blanked || cw->ns || cw->ec->shaped) alpha = EINA_TRUE;
evas_object_image_alpha_set(cw->obj, alpha);
}
static void
_e_comp_object_shadow(E_Comp_Object *cw)
{
if (e_client_util_shadow_state_get(cw->ec))
edje_object_signal_emit(cw->frame_object ?: cw->shobj, "e,state,shadow,on", "e");
else
edje_object_signal_emit(cw->frame_object ?: cw->shobj, "e,state,shadow,off", "e");
if (cw->frame_object)
edje_object_signal_emit(cw->shobj, "e,state,shadow,off", "e");
evas_object_smart_callback_call(cw->smart_obj, "shadow_change", cw->ec);
}
/* trigger e_binding from an edje signal on a client frame */
static void
_e_comp_object_cb_signal_bind(void *data, Evas_Object *obj EINA_UNUSED, const char *emission, const char *source)
{
E_Comp_Object *cw = data;
#ifndef HAVE_WAYLAND_ONLY
if (e_dnd_active()) return;
#endif
if (cw->ec->iconic || cw->ec->cur_mouse_action) return;
if (!dblequal(cw->action_client_loop_time, ecore_loop_time_get()))
e_bindings_signal_handle(E_BINDING_CONTEXT_WINDOW, E_OBJECT(cw->ec),
emission, source);
}
/////////////////////////////////////
/* handle evas mouse-in events on client object */
static void
_e_comp_object_cb_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info)
{
Evas_Event_Mouse_In *ev = event_info;
E_Comp_Object *cw = data;
if (e_pixmap_is_x(cw->ec->pixmap))
{
if (!e_comp_object_frame_allowed(obj)) return;
if (E_INSIDE(ev->output.x, ev->output.y, cw->ec->client.x, cw->ec->client.y,
cw->ec->client.w, cw->ec->client.h)) return;
}
if (e_grabinput_mouse_win_get() && (e_grabinput_mouse_win_get() != e_client_util_win_get(cw->ec)))
return;
e_client_mouse_in(cw->ec, ev->output.x, ev->output.y);
}
/* handle evas mouse-out events on client object */
static void
_e_comp_object_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_Comp_Object *cw = data;
if (e_grabinput_mouse_win_get() && (e_grabinput_mouse_win_get() != e_client_util_win_get(cw->ec)))
return;
e_client_mouse_out(cw->ec, ev->output.x, ev->output.y);
}
/* handle evas mouse wheel events on client object */
static void
_e_comp_object_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_Comp_Object *cw = data;
E_Binding_Event_Wheel ev2;
if (!cw->ec) return;
if (e_client_action_get()) return;
e_bindings_evas_event_mouse_wheel_convert(ev, &ev2);
e_client_mouse_wheel(cw->ec, &ev->output, &ev2);
}
/* handle evas mouse down events on client object */
static void
_e_comp_object_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_Comp_Object *cw = data;
E_Binding_Event_Mouse_Button ev2;
if (!cw->ec) return;
if (e_client_action_get()) return;
e_bindings_evas_event_mouse_button_convert(ev, &ev2);
e_client_mouse_down(cw->ec, ev->button, &ev->output, &ev2);
}
/* handle evas mouse up events on client object */
static void
_e_comp_object_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_Comp_Object *cw = data;
E_Binding_Event_Mouse_Button ev2;
Eina_Bool acting;
if (!cw->ec) return;
if (e_client_action_get() && (e_client_action_get() != cw->ec)) return;
e_bindings_evas_event_mouse_button_convert(ev, &ev2);
acting = !!cw->ec->cur_mouse_action;
e_client_mouse_up(cw->ec, ev->button, &ev->output, &ev2);
if (acting && (!e_client_action_get()))
cw->action_client_loop_time = ecore_loop_time_get();
}
/* handle evas mouse movement events on client object */
static void
_e_comp_object_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_Comp_Object *cw = data;
if (!cw->ec) return;
if (e_client_action_get() && (e_client_action_get() != cw->ec)) return;
e_client_mouse_move(cw->ec, &ev->cur.output);
}
/////////////////////////////////////
/* helper function for checking compositor themes based on user-defined matches */
static Eina_Bool
_e_comp_object_shadow_client_match(const E_Client *ec, E_Comp_Match *m)
{
if (((m->title) && (!ec->netwm.name)) ||
((ec->netwm.name) && (m->title) && (!e_util_glob_match(ec->netwm.name, m->title))))
return EINA_FALSE;
if (((m->clas) && (!ec->icccm.class)) ||
((ec->icccm.class) && (m->clas) && (!e_util_glob_match(ec->icccm.class, m->clas))))
return EINA_FALSE;
if (((m->role) && (!ec->icccm.window_role)) ||
((ec->icccm.window_role) && (m->role) && (!e_util_glob_match(ec->icccm.window_role, m->role))))
return EINA_FALSE;
if (m->primary_type)
{
if (ec->netwm.type)
{
if ((int)ec->netwm.type != m->primary_type)
return EINA_FALSE;
}
else if (m->primary_type != E_WINDOW_TYPE_REAL_UNKNOWN)
return EINA_FALSE;
}
if (m->borderless != 0)
{
int borderless = 0;
if (e_client_util_borderless(ec))
borderless = 1;
if (!(((m->borderless == -1) && (!borderless)) ||
((m->borderless == 1) && (borderless))))
return EINA_FALSE;
}
if (m->dialog != 0)
{
int dialog = 0;
if (((ec->icccm.transient_for != 0) ||
(ec->dialog)))
dialog = 1;
if (!(((m->dialog == -1) && (!dialog)) ||
((m->dialog == 1) && (dialog))))
return EINA_FALSE;
}
if (m->accepts_focus != 0)
{
int accepts_focus = 0;
if (ec->icccm.accepts_focus)
accepts_focus = 1;
if (!(((m->accepts_focus == -1) && (!accepts_focus)) ||
((m->accepts_focus == 1) && (accepts_focus))))
return EINA_FALSE;
}
if (m->vkbd != 0)
{
int vkbd = 0;
if (ec->vkbd.vkbd)
vkbd = 1;
if (!(((m->vkbd == -1) && (!vkbd)) ||
((m->vkbd == 1) && (vkbd))))
return EINA_FALSE;
}
if (m->argb != 0)
{
if (!(((m->argb == -1) && (!ec->argb)) ||
((m->argb == 1) && (ec->argb))))
return EINA_FALSE;
}
if (m->fullscreen != 0)
{
int fullscreen = ec->fullscreen;
if (!(((m->fullscreen == -1) && (!fullscreen)) ||
((m->fullscreen == 1) && (fullscreen))))
return EINA_FALSE;
}
if (m->modal != 0)
{
int modal = 0;
if (ec->netwm.state.modal)
modal = 1;
if (!(((m->modal == -1) && (!modal)) ||
((m->modal == 1) && (modal))))
return EINA_FALSE;
}
return EINA_TRUE;
}
/* function for setting up a client's compositor frame theme (cw->shobj) */
static Eina_Bool
_e_comp_object_shadow_setup(E_Comp_Object *cw)
{
int ok = 0;
char buf[4096];
Eina_List *list = NULL, *l;
E_Comp_Match *m;
Eina_Stringshare *reshadow_group = NULL;
Eina_Bool focus = EINA_FALSE, urgent = EINA_FALSE, skip = EINA_FALSE,
fast = EINA_FALSE, reshadow = EINA_FALSE, no_shadow = EINA_FALSE, override;
Eina_Stringshare *name, *title;
E_Comp_Config *conf = e_comp_config_get();
edje_object_file_get(cw->shobj, NULL, &reshadow_group);
override = cw->ec->override || (cw->ec->netwm.type == E_WINDOW_TYPE_POPUP_MENU);
/* match correct client type */
list = override ? conf->match.overrides : conf->match.borders;
name = cw->ec->icccm.name;
title = cw->ec->icccm.title;
skip = (override ? conf->match.disable_overrides : conf->match.disable_borders) || (title && (!strncmp(title, "noshadow", 8)));
fast = override ? conf->fast_overrides : conf->fast_borders;
/* skipping here is mostly a hack for systray because I hate it */
if (!skip)
{
EINA_LIST_FOREACH(list, l, m)
{
if (((m->name) && (!name)) ||
((name) && (m->name) && (!e_util_glob_match(name, m->name))))
continue;
if (!_e_comp_object_shadow_client_match(cw->ec, m)) continue;
focus = m->focus;
urgent = m->urgent;
no_shadow = m->no_shadow;
if (m->shadow_style)
{
/* fast effects are just themes with "/fast" appended and shorter effect times */
if (fast)
{
snprintf(buf, sizeof(buf), "e/comp/frame/%s/fast", m->shadow_style);
reshadow = ok = !e_util_strcmp(reshadow_group, buf);
if (!ok)
ok = e_theme_edje_object_set(cw->shobj, "base/theme/comp", buf);
}
/* default to non-fast style if fast not available */
if (!ok)
{
snprintf(buf, sizeof(buf), "e/comp/frame/%s", m->shadow_style);
reshadow = ok = !e_util_strcmp(reshadow_group, buf);
if (!ok)
ok = e_theme_edje_object_set(cw->shobj, "base/theme/comp", buf);
}
if (ok && m->visibility_effect)
eina_stringshare_refplace(&cw->visibility_effect, m->visibility_effect);
if (ok) break;
}
}
}
while (!ok)
{
if (skip || (cw->ec->e.state.video))
{
reshadow = ok = !e_util_strcmp(reshadow_group, "e/comp/frame/none");
if (!ok)
ok = e_theme_edje_object_set(cw->shobj, "base/theme/comp", "e/comp/frame/none");
}
if (ok) break;
if (conf->shadow_style)
{
if (fast)
{
snprintf(buf, sizeof(buf), "e/comp/frame/%s/fast", conf->shadow_style);
reshadow = ok = !e_util_strcmp(reshadow_group, buf);
if (!ok)
ok = e_theme_edje_object_set(cw->shobj, "base/theme/comp", buf);
}
if (!ok)
{
snprintf(buf, sizeof(buf), "e/comp/frame/%s", conf->shadow_style);
reshadow = ok = !e_util_strcmp(reshadow_group, buf);
if (!ok)
ok = e_theme_edje_object_set(cw->shobj, "base/theme/comp", buf);
}
}
if (!ok)
{
if (fast)
{
reshadow = ok = !e_util_strcmp(reshadow_group, "e/comp/frame/default/fast");
if (!ok)
ok = e_theme_edje_object_set(cw->shobj, "base/theme/comp", "e/comp/frame/default/fast");
}
if (!ok)
{
reshadow = ok = !e_util_strcmp(reshadow_group, "e/comp/frame/default");
if (!ok)
ok = e_theme_edje_object_set(cw->shobj, "base/theme/comp", "e/comp/frame/default");
}
}
break;
}
/* reshadow means this entire function call has been a no-op since we're re-setting the current style */
if (reshadow)
{
if (cw->zoomap_disabled)
{
if (cw->frame_object && (e_zoomap_child_get(cw->zoomobj) == cw->frame_object)) return EINA_FALSE;
}
else
{
if (cw->frame_object && (edje_object_part_swallow_get(cw->shobj, "e.swallow.content") == cw->frame_object)) return EINA_FALSE;
}
}
if (override)
{
if ((!cw->ec->shaped) && (!no_shadow) && (!cw->ec->argb))
edje_object_signal_emit(cw->shobj, "e,state,shadow,on", "e");
else
edje_object_signal_emit(cw->shobj, "e,state,shadow,off", "e");
evas_object_smart_callback_call(cw->smart_obj, "shadow_change", cw->ec);
}
else
{
if (no_shadow)
{
edje_object_signal_emit(cw->shobj, "e,state,shadow,off", "e");
evas_object_smart_callback_call(cw->smart_obj, "shadow_change", cw->ec);
}
else
_e_comp_object_shadow(cw);
}
if (focus || cw->ec->focused || override)
e_comp_object_signal_emit(cw->smart_obj, "e,state,focused", "e");
else
e_comp_object_signal_emit(cw->smart_obj, "e,state,unfocused", "e");
if (urgent || cw->ec->urgent)
e_comp_object_signal_emit(cw->smart_obj, "e,state,urgent", "e");
else
e_comp_object_signal_emit(cw->smart_obj, "e,state,not_urgent", "e");
if (cw->ec->shaded)
e_comp_object_signal_emit(cw->smart_obj, "e,state,shaded", "e");
if (cw->ec->sticky)
e_comp_object_signal_emit(cw->smart_obj, "e,state,sticky", "e");
if (cw->ec->hung)
e_comp_object_signal_emit(cw->smart_obj, "e,state,hung", "e");
/* visibility must always be enabled for re_manage clients to prevent
* pop-in animations every time the user sees a persistent client again;
* applying visibility for iconic clients prevents the client from getting
* stuck as hidden
*/
if (cw->visible || cw->ec->iconic || cw->ec->re_manage)
{
if ((cw->w > 0) && (cw->h > 0))
e_comp_object_signal_emit(cw->smart_obj, "e,state,visible", "e");
}
else
e_comp_object_signal_emit(cw->smart_obj, "e,state,hidden", "e");
if (e_comp_object_frame_allowed(cw->smart_obj))
e_comp_object_signal_emit(cw->smart_obj, "e,state,focus,enabled", "e");
else
e_comp_object_signal_emit(cw->smart_obj, "e,state,focus,disabled", "e");
/* breaks animation counter */
//if (cw->ec->iconic)
//e_comp_object_signal_emit(cw->smart_obj, "e,action,iconify", "e");
if (!cw->zoomap_disabled)
e_zoomap_child_set(cw->zoomobj, NULL);
if (cw->frame_object)
{
edje_object_part_swallow(cw->frame_object, "e.swallow.client", cw->obj);
edje_object_part_swallow(cw->frame_object, "e.swallow.icon", cw->frame_icon);
edje_object_part_swallow(cw->frame_object, "e.swallow.volume", cw->frame_volume);
if (cw->zoomap_disabled)
edje_object_part_swallow(cw->shobj, "e.swallow.content", cw->frame_object);
else
{
e_zoomap_child_set(cw->zoomobj, cw->frame_object);
edje_object_part_swallow(cw->shobj, "e.swallow.content", cw->zoomobj);
}
no_shadow = 1;
}
else
{
no_shadow = 1;
if (cw->zoomobj)
{
e_zoomap_child_set(cw->zoomobj, cw->obj);
edje_object_part_swallow(cw->shobj, "e.swallow.content", cw->zoomobj);
}
else
edje_object_part_swallow(cw->shobj, "e.swallow.content", cw->obj);
}
if (cw->input_objs)
evas_object_pass_events_set(cw->obj, 1);
else
evas_object_pass_events_set(cw->obj, 0);
#ifdef BORDER_ZOOMAPS
e_zoomap_child_edje_solid_setup(cw->zoomobj);
#endif
return EINA_TRUE;
}
/////////////////////////////////////////////
static void
_e_comp_object_animating_begin(E_Comp_Object *cw)
{
cw->animating++;
if (cw->animating == 1)
{
e_comp->animating++;
REFD(cw->ec, 2);
e_object_ref(E_OBJECT(cw->ec));
evas_object_image_border_center_fill_set(cw->obj, EVAS_BORDER_FILL_DEFAULT);
}
}
static Eina_Bool
_e_comp_object_animating_end(E_Comp_Object *cw)
{
if (cw->animating)
{
cw->animating--;
if (!cw->animating)
{
e_comp->animating--;
cw->showing = 0;
evas_object_image_border_center_fill_set(cw->obj, EVAS_BORDER_FILL_SOLID);
UNREFD(cw->ec, 2);
/* remove ref from animation start, account for possibility of deletion from unref */
return !!e_object_unref(E_OBJECT(cw->ec));
}
}
return EINA_TRUE;
}
/* handle the end of a compositor animation */
static void
_e_comp_object_done_defer(void *data, Evas_Object *obj EINA_UNUSED, const char *emission, const char *source EINA_UNUSED)
{
E_Comp_Object *cw = data;
//INF("DONE DEFER %p: %dx%d - %s", cw->ec, cw->w, cw->h, emission);
/* visible clients which have never been sized are a bug */
if ((!cw->ec->new_client) && (!cw->ec->changes.size) && ((cw->w < 0) || (cw->h < 0)) && (!strcmp(emission, "e,action,show,done")))
CRI("ACK!");
if (!_e_comp_object_animating_end(cw)) return;
if (cw->animating) return;
/* hide only after animation finishes to guarantee a full run of the animation */
if (cw->defer_hide && ((!strcmp(emission, "e,action,hide,done")) || (!strcmp(emission, "e,action,done"))))
evas_object_hide(cw->smart_obj);
else
{
e_comp_shape_queue();
if (cw->visible && cw->updates_exist)
e_comp_object_render_update_add(cw->smart_obj);
}
}
/* run a visibility compositor effect if available, return false if object is dead */
static Eina_Bool
_e_comp_object_effect_visibility_start(E_Comp_Object *cw, Eina_Bool state)
{
int x, y, zw, zh;
if ((!cw->visibility_effect) || (!e_comp_object_effect_allowed_get(cw->smart_obj))) return EINA_TRUE;;
if (!cw->effect_running)
_e_comp_object_animating_begin(cw);
if (!e_comp_object_effect_stop(cw->smart_obj, _e_comp_object_done_defer))
return _e_comp_object_animating_end(cw);
if (!e_comp_object_effect_set(cw->smart_obj, cw->visibility_effect))
return _e_comp_object_animating_end(cw);
/* mouse position is not available for some windows under X11
* only fetch pointer position if absolutely necessary
*/
if (edje_object_data_get(cw->effect_obj, "need_pointer") &&
(e_comp->comp_type == E_PIXMAP_TYPE_X))
ecore_evas_pointer_xy_get(e_comp->ee, &x, &y);
else
evas_pointer_canvas_xy_get(e_comp->evas, &x, &y);
x -= cw->ec->x;
y -= cw->ec->y;
if (cw->ec->zone)
zw = cw->ec->zone->w, zh = cw->ec->zone->h;
else
{
E_Zone *zone;
zone = e_comp_object_util_zone_get(cw->smart_obj);
if (!zone) zone = e_zone_current_get();
zw = zone->w, zh = zone->h;
}
e_comp_object_effect_params_set(cw->smart_obj, 1, (int[]){cw->ec->x, cw->ec->y,
cw->ec->w, cw->ec->h, zw, zh, x, y}, 8);
e_comp_object_effect_params_set(cw->smart_obj, 0, (int[]){state}, 1);
e_comp_object_effect_start(cw->smart_obj, _e_comp_object_done_defer, cw);
return EINA_TRUE;
}
/////////////////////////////////////////////
/* create necessary objects for clients that e manages */
static void
_e_comp_object_setup(E_Comp_Object *cw)
{
cw->clip = evas_object_rectangle_add(e_comp->evas);
evas_object_resize(cw->clip, 999999, 999999);
evas_object_smart_member_add(cw->clip, cw->smart_obj);
cw->effect_obj = edje_object_add(e_comp->evas);
evas_object_move(cw->effect_obj, cw->x, cw->y);
evas_object_clip_set(cw->effect_obj, cw->clip);
evas_object_smart_member_add(cw->effect_obj, cw->smart_obj);
e_theme_edje_object_set(cw->effect_obj, "base/theme/comp", "e/comp/effects/none");
cw->shobj = edje_object_add(e_comp->evas);
evas_object_data_set(cw->shobj, "comp_smart_obj", cw->smart_obj);
edje_object_part_swallow(cw->effect_obj, "e.swallow.content", cw->shobj);
edje_object_signal_callback_add(cw->shobj, "e,action,*,done", "e", _e_comp_object_done_defer, cw);
/* name objects appropriately for nicer printing when using e_comp_util_wins_print() */
if (cw->ec->override)
{
evas_object_name_set(cw->shobj, "cw->shobj::WINDOW");
evas_object_name_set(cw->effect_obj, "cw->effect_obj::WINDOW");
evas_object_name_set(cw->clip, "cw->clip::WINDOW");
}
else if (!cw->ec->input_only)
{
evas_object_name_set(cw->shobj, "cw->shobj::CLIENT");
evas_object_name_set(cw->effect_obj, "cw->effect_obj::CLIENT");
evas_object_name_set(cw->clip, "cw->clip::CLIENT");
}
cw->real_hid = !cw->ec->input_only;
if (!cw->ec->input_only)
{
//e_util_size_debug_set(cw->clip, 1);
e_util_size_debug_set(cw->effect_obj, 1);
//e_util_size_debug_set(cw->shobj, 1);
evas_object_event_callback_add(cw->smart_obj, EVAS_CALLBACK_MOUSE_IN, _e_comp_object_cb_mouse_in, cw);
evas_object_event_callback_add(cw->smart_obj, EVAS_CALLBACK_MOUSE_OUT, _e_comp_object_cb_mouse_out, cw);
evas_object_event_callback_add(cw->smart_obj, EVAS_CALLBACK_MOUSE_DOWN, _e_comp_object_cb_mouse_down, cw);
evas_object_event_callback_add(cw->smart_obj, EVAS_CALLBACK_MOUSE_UP, _e_comp_object_cb_mouse_up, cw);
evas_object_event_callback_add(cw->smart_obj, EVAS_CALLBACK_MOUSE_MOVE, _e_comp_object_cb_mouse_move, cw);
evas_object_event_callback_add(cw->smart_obj, EVAS_CALLBACK_MOUSE_WHEEL, _e_comp_object_cb_mouse_wheel, cw);
}
}
static void
_e_comp_object_mirror_pixels_get(void *data, Evas_Object *obj)
{
E_Comp_Object *cw = data;
E_Client *ec = cw->ec;
int pw, ph;
if ((!ec->pixmap) || (!e_pixmap_size_get(ec->pixmap, &pw, &ph)))
{
evas_object_image_data_set(obj, NULL);
return;
}
/* This is a big fat hack - ideally we're already on this list
* if the parent is visible, but there are some circumstances
* where a client receives damage while visible but its own pixels_get
* callback doesn't fire (new damage during the start frame of a desk
* switch animation).
* Thus we can't make this addition conditional on visibility or we can
* (under wayland at least) lose a frame callback and stop updating.
*
* e_comp_client_post_update_add() prevents clients from being
* on the list twice, so this is theoretically not harmful.
*/
e_comp_client_post_update_add(ec);
if (cw->native) return;
evas_object_image_data_set(obj, e_pixmap_image_data_get(cw->ec->pixmap));
}
/////////////////////////////////////////////
/* for fast path evas rendering; only called during render */
static void
_e_comp_object_pixels_get(void *data, Evas_Object *obj)
{
E_Comp_Object *cw = data;
E_Client *ec = cw->ec;
int pw, ph;
if ((!ec->pixmap) || (!e_pixmap_size_get(ec->pixmap, &pw, &ph)))
{
evas_object_image_data_set(obj, NULL);
return;
}
//INF("PIXEL GET %p: %dx%d || %dx%d", ec, ec->w, ec->h, pw, ph);
/* queue another render if client is still dirty; cannot refresh here. */
if (e_pixmap_dirty_get(ec->pixmap) && e_pixmap_size_get(ec->pixmap, &pw, &ph))
{
e_comp_object_damage(ec->frame, 0, 0, ec->w, ec->h);
/* if updates for existing pixmap don't exist then avoid unsetting existing image */
if ((!cw->pending_updates) || eina_tiler_empty(cw->pending_updates)) return;
}
if (cw->native)
{
E_FREE_FUNC(cw->pending_updates, eina_tiler_free);
e_comp_client_post_update_add(cw->ec);
}
else if (e_comp_object_render(ec->frame))
{
/* apply shape mask if necessary */
if ((!cw->native) && (ec->shaped || ec->shape_changed))
e_comp_object_shape_apply(ec->frame);
ec->shape_changed = 0;
}
if (e_object_is_del(E_OBJECT(ec))) return;
/* shaped clients get precise mouse events to handle transparent pixels */
evas_object_precise_is_inside_set(cw->obj, ec->shaped || ec->shaped_input);
//INF("%p PX(%dx%d) EC(%dx%d) CW(%dx%d)", ec, pw, ph, ec->w, ec->h, cw->w, cw->h);
//e_comp_object_frame_wh_adjust(cw->smart_obj, pw, ph, &pw, &ph);
//if ((ec->w != pw) || (ec->h != ph))
//{
///* DO NOT RESIZE HERE. */
//INF("CW RSZ FIX: %dx%d -> %dx%d", ec->w, ec->h, pw, ph);
//ec->w = pw, ec->h = ph;
//ec->changes.size = 1;
//EC_CHANGED(ec);
//}
}
/////////////////////////////////////////////
static void
_e_comp_object_ssd_mouse_in(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
E_Comp_Object *cw = data;
evas_object_smart_callback_call(cw->smart_obj, "mouse_in", event_info);
}
static void
_e_comp_object_ssd_mouse_out(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
E_Comp_Object *cw = data;
evas_object_smart_callback_call(cw->smart_obj, "mouse_out", event_info);
}
/////////////////////////////////////////////
static void
_e_comp_object_client_pending_resize_add(E_Client *ec,
int w,
int h,
unsigned int serial)
{
E_Client_Pending_Resize *pnd;
pnd = E_NEW(E_Client_Pending_Resize, 1);
if (!pnd) return;
pnd->w = w;
pnd->h = h;
pnd->serial = serial;
ec->pending_resize = eina_list_append(ec->pending_resize, pnd);
}
static void
_e_comp_intercept_move(void *data, Evas_Object *obj, int x, int y)
{
E_Comp_Object *cw = data;
int ix, iy, fx, fy;
/* if frame_object does not exist, client_inset indicates CSD.
* this means that ec->client matches cw->x/y, the opposite
* of SSD.
*/
fx = (!cw->frame_object) * cw->client_inset.l;
fy = (!cw->frame_object) * cw->client_inset.t;
if ((cw->x == x + fx) && (cw->y == y + fy))
{
if ((cw->ec->x != x) || (cw->ec->y != y))
{
/* handle case where client tries to move to position and back very quickly */
cw->ec->x = x, cw->ec->y = y;
cw->ec->client.x = x + cw->client_inset.l;
cw->ec->client.y = y + cw->client_inset.t;
}
return;
}
if (!cw->ec->maximize_override)
{
/* prevent moving in some directions while directionally maximized */
if ((cw->ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_VERTICAL)
y = cw->y;
if ((cw->ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_HORIZONTAL)
x = cw->x;
}
ix = x + cw->client_inset.l;
iy = y + cw->client_inset.t;
if (cw->ec->maximized && (!cw->ec->maximize_override) && ((cw->ec->x != x) || (cw->ec->y != y)) &&
((cw->ec->maximized & E_MAXIMIZE_DIRECTION) != E_MAXIMIZE_VERTICAL) &&
((cw->ec->maximized & E_MAXIMIZE_DIRECTION) != E_MAXIMIZE_HORIZONTAL))
{
/* prevent moving at all if move isn't allowed in current maximize state */
if ((!e_config->allow_manip) && ((cw->ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_BOTH)) return;
/* queue unmaximize if we are allowing move and update unmaximize geometry */
if ((!cw->ec->shading) && (!cw->ec->shaded))
{
cw->ec->changes.need_unmaximize = 1;
cw->ec->saved.x = ix - cw->ec->zone->x;
cw->ec->saved.y = iy - cw->ec->zone->y;
cw->ec->saved.w = cw->ec->client.w;
cw->ec->saved.h = cw->ec->client.h;
EC_CHANGED(cw->ec);
return;
}
return;
}
/* only update during resize if triggered by resize */
if (e_client_util_resizing_get(cw->ec) && (!cw->force_move)) return;
cw->ec->x = x, cw->ec->y = y;
if (cw->ec->new_client)
{
/* don't actually do anything until first client idler loop */
if (!cw->ec->placed)
cw->ec->placed = ((!cw->ec->dialog) && (!cw->ec->parent));
cw->ec->changes.pos = 1;
EC_CHANGED(cw->ec);
}
else
{
/* only update xy position of client to avoid invalid
* first damage region if it is not a new_client. */
cw->ec->placed = 1;
if (!cw->ec->shading)
{
cw->ec->client.x = ix;
cw->ec->client.y = iy;
}
/* flip SSD->CSD */
if (!cw->frame_object)
x = ix, y = iy;
evas_object_move(obj, x, y);
}
}
static void
_e_comp_intercept_resize(void *data, Evas_Object *obj, int w, int h)
{
E_Comp_Object *cw = data;
int pw = 0, ph = 0, fw, fh, iw, ih, prev_w, prev_h, x, y;
if ((w < 1) || (h < 1)) return;
/* if frame_object does not exist, client_inset indicates CSD.
* this means that ec->client matches cw->w/h, the opposite
* of SSD.
*/
fw = (!cw->frame_object) * (-cw->client_inset.l - cw->client_inset.r);
fh = (!cw->frame_object) * (-cw->client_inset.t - cw->client_inset.b);
if ((cw->w == w + fw) && (cw->h == h + fh))
{
if (cw->ec->shading || cw->ec->shaded) return;
if (((cw->ec->w != w) || (cw->ec->h != h)) ||
(cw->ec->client.w != w - cw->client_inset.l - cw->client_inset.r) ||
(cw->ec->client.h != h - cw->client_inset.t - cw->client_inset.b))
{
/* handle case where client tries to resize itself and back very quickly */
cw->ec->w = w, cw->ec->h = h;
cw->ec->client.w = w - cw->client_inset.l - cw->client_inset.r;
cw->ec->client.h = h - cw->client_inset.t - cw->client_inset.b;
evas_object_smart_callback_call(obj, "client_resize", NULL);
}
return;
}
/* guarantee that fullscreen is fullscreen */
if (cw->ec->fullscreen && ((w != cw->ec->zone->w) || (h != cw->ec->zone->h)))
return;
/* calculate client size */
iw = w - cw->client_inset.l - cw->client_inset.r;
ih = h - cw->client_inset.t - cw->client_inset.b;
if (cw->ec->maximized && (!cw->ec->maximize_override) && ((cw->ec->w != w) || (cw->ec->h != h)))
{
/* prevent resizing while maximized depending on direction and config */
if ((!e_config->allow_manip) && ((cw->ec->maximized & E_MAXIMIZE_DIRECTION) == E_MAXIMIZE_BOTH)) return;
if ((!cw->ec->shading) && (!cw->ec->shaded))
{
Eina_Bool reject = EINA_FALSE;
if (cw->ec->maximized & E_MAXIMIZE_VERTICAL)
{
if (cw->ec->client.h != ih)
{
cw->ec->saved.h = ih;
cw->ec->saved.y = cw->ec->client.y - cw->ec->zone->y;
reject = cw->ec->changes.need_unmaximize = 1;
}
}
if (cw->ec->maximized & E_MAXIMIZE_HORIZONTAL)
{
if (cw->ec->client.w != iw)
{
cw->ec->saved.w = iw;
cw->ec->saved.x = cw->ec->client.x - cw->ec->zone->x;
reject = cw->ec->changes.need_unmaximize = 1;
}
}
if (reject)
{
EC_CHANGED(cw->ec);
return;
}
}
}
if (cw->ec->new_client || (!cw->ec->visible) || (!cw->effect_obj))
{
/* do nothing until client idler loops */
if (!cw->ec->maximized)
{
/* NO. DO NOT DO THIS OR YOU WILL BREAK WINDOW RESIZING. */
//if ((w != cw->ec->w) || (h != cw->ec->h))
{
cw->ec->w = w, cw->ec->h = h;
cw->ec->changes.size = 1;
EC_CHANGED(cw->ec);
}
}
return;
}
if ((!cw->ec->internal) && e_client_util_resizing_get(cw->ec) && cw->ec->netwm.sync.request &&
((cw->ec->w != w) || (cw->ec->h != h)))
{
/* this is ugly. */
//INF("PENDING %dx%d", iw, ih);
/* netwm sync resizes queue themselves and then trigger later on */
_e_comp_object_client_pending_resize_add(cw->ec, iw, ih, cw->ec->netwm.sync.serial);
}
cw->ec->w = w, cw->ec->h = h;
if ((!cw->ec->shading) && (!cw->ec->shaded))
{
/* client geom never changes when shading since the client is never altered */
INF("%p: CUR(%dx%d) || REQ(%dx%d)", cw->ec, cw->ec->client.w, cw->ec->client.h, iw, ih);
cw->ec->client.w = iw;
cw->ec->client.h = ih;
if ((cw->ec->client.w < 0) || (cw->ec->client.h < 0)) CRI("WTF");
}
if ((!cw->ec->input_only) && cw->redirected && (!cw->ec->shading) && (!cw->ec->shaded) &&
(e_pixmap_dirty_get(cw->ec->pixmap) || (!e_pixmap_size_get(cw->ec->pixmap, &pw, &ph))))
{
if (e_comp->comp_type != E_PIXMAP_TYPE_X) return;
if (e_object_is_del(E_OBJECT(cw->ec))) return;
/* shapeless clients smh */
if (cw->ec->shaped && (!cw->ec->shape_rects)) return;
/* pending shape change gtfo */
if (!cw->ec->changes.shape)
{
/* client can't be resized if its pixmap isn't usable, try again */
e_pixmap_dirty(cw->ec->pixmap);
if (e_comp->nocomp)
e_pixmap_refresh(cw->ec->pixmap);
else
{
e_comp_object_render_update_add(obj);
e_comp_render_queue();
}
}
cw->ec->changes.size = 1;
EC_CHANGED(cw->ec);
return;
}
if (e_pixmap_failures_get(cw->ec->pixmap) && (!cw->redirected))
{
e_comp_object_redirected_set(obj, 1);
return;
}
prev_w = cw->w, prev_h = cw->h;
e_comp_object_frame_wh_adjust(obj, 0, 0, &fw, &fh);
/* check shading and clamp to pixmap size for regular clients */
if ((!cw->ec->shading) && (!cw->ec->shaded) && (!cw->ec->input_only) && (!cw->ec->override) &&
(((w - fw != pw) || (h - fh != ph))))
{
//INF("CALLBACK: REQ(%dx%d) != CUR(%dx%d)", w - fw, h - fh, pw, ph);
evas_object_smart_callback_call(obj, "client_resize", NULL);
/* flip for CSD */
if (cw->frame_object || cw->ec->input_only)
e_comp_object_frame_wh_adjust(obj, pw, ph, &w, &h);
else
w = pw, h = ph;
if ((cw->w == w) && (cw->h == h))
{
/* going to be a noop resize which won't trigger smart resize */
RENDER_DEBUG("DAMAGE RESIZE(%p): %dx%d", cw->ec, cw->ec->client.w, cw->ec->client.h);
if (cw->updates) eina_tiler_area_size_set(cw->updates, cw->ec->client.w, cw->ec->client.h);
}
evas_object_resize(obj, w, h);
}
else
{
/* flip for CSD */
if ((!cw->frame_object) && (!cw->ec->input_only))
w = pw, h = ph;
/* "just do it" for overrides */
//INF("INTERCEPT %dx%d", w, h);
evas_object_resize(obj, w, h);
}
if (!cw->ec->override)
{
/* shape probably changed for non-overrides */
cw->ec->need_shape_merge |= cw->ec->shaped || cw->ec->shaped_input;
cw->ec->need_shape_export |= cw->ec->shaped;
if (cw->ec->shaped || cw->ec->shaped_input)
EC_CHANGED(cw->ec);
}
/* this fixes positioning jiggles when using a resize mode
* which also changes the client's position
*/
cw->force_move = 1;
if (cw->frame_object)
x = cw->x, y = cw->y;
else
x = cw->ec->x, y = cw->ec->y;
switch (cw->ec->resize_mode)
{
case E_POINTER_RESIZE_BL:
case E_POINTER_RESIZE_L:
evas_object_move(obj, x + prev_w - cw->w, y);
break;
case E_POINTER_RESIZE_TL:
evas_object_move(obj, x + prev_w - cw->w, y + prev_h - cw->h);
break;
case E_POINTER_RESIZE_T:
case E_POINTER_RESIZE_TR:
evas_object_move(obj, x, y + prev_h - cw->h);
break;
default:
break;
}
if (cw->ec->internal_elm_win && (!cw->ec->moving) && (!e_client_util_resizing_get(cw->ec)) &&
(!cw->ec->fullscreen) && (!cw->ec->maximized) &&
e_win_centered_get(cw->ec->internal_elm_win))
{
e_comp_object_util_center(obj);
}
cw->force_move = 0;
}
static void
_e_comp_intercept_layer_set(void *data, Evas_Object *obj, int layer)
{
E_Comp_Object *cw = data;
unsigned int l = e_comp_canvas_layer_map(layer);
int oldraise;
E_Client *ec;
if (cw->ec->layer_block)
{
/* doing a compositor effect, follow directions */
evas_object_layer_set(obj, layer);
if (layer == cw->ec->layer) //trying to put layer back
{
if (cw->visible)
{
e_comp_shape_queue();
e_comp_render_queue();
}
ec = e_client_above_get(cw->ec);
if (ec && (evas_object_layer_get(ec->frame) != evas_object_layer_get(obj)))
{
ec = e_client_below_get(cw->ec);
if (ec && (evas_object_layer_get(ec->frame) == evas_object_layer_get(cw->smart_obj)))
{
evas_object_stack_above(obj, ec->frame);
return;
}
ec = NULL;
}
if (ec && (cw->ec->parent == ec))
evas_object_stack_above(obj, ec->frame);
else
evas_object_stack_below(obj, ec ? ec->frame : e_comp->layers[cw->layer].obj);
}
return;
}
if (cw->layer == l) return;
if (e_comp_canvas_client_layer_map(layer) == 9999)
return; //invalid layer for clients not doing comp effects
if (cw->ec->fullscreen)
{
cw->ec->saved.layer = layer;
return;
}
oldraise = e_config->transient.raise;
_e_comp_object_layers_remove(cw);
/* clamp to valid client layer */
layer = e_comp_canvas_client_layer_map_nearest(layer);
ec = cw->ec;
ec->layer = layer;
if (ec->stack.prev || ec->stack.next)
{
if (ec->stack.ignore == 0)
{
Eina_List *ll, *list = e_client_stack_list_prepare(ec);
E_Client *child;
EINA_LIST_FOREACH(list, ll, child)
{
if (child == ec) continue;
evas_object_layer_set(child->frame, layer);
}
e_client_stack_list_finish(list);
evas_object_raise(ec->frame);
}
}
else
{
if (e_config->transient.layer)
{
E_Client *child;
Eina_List *list = eina_list_clone(cw->ec->transients);
/* 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)
evas_object_layer_set(child->frame, layer);
}
}
if (!cw->ec->override)
{
/* set client stacking hints based on layer */
if (layer == E_LAYER_CLIENT_BELOW)
e_hints_window_stacking_set(cw->ec, E_STACKING_BELOW);
else if (layer == E_LAYER_CLIENT_ABOVE)
e_hints_window_stacking_set(cw->ec, E_STACKING_ABOVE);
else
e_hints_window_stacking_set(cw->ec, E_STACKING_NONE);
}
e_config->transient.raise = oldraise;
cw->layer = e_comp_canvas_layer_map(layer);
_e_comp_object_layers_add(cw, NULL, NULL, 0);
//if (cw->ec->new_client)
//INF("CLIENT STACKED %p: %u", cw->ec, layer);
evas_object_layer_set(obj, layer);
if (!e_comp->layers[cw->layer].obj) return; //this is a layer marker
evas_object_stack_below(obj, e_comp->layers[cw->layer].obj);
if (evas_object_below_get(obj) == e_comp->layers[cw->layer].obj)
{
/* can't stack a client above its own layer marker */
CRI("STACKING ERROR!!!");
}
if (!cw->visible) return;
e_comp_render_queue();
e_comp_shape_queue();
}
typedef void (*E_Comp_Object_Stack_Func)(Evas_Object *obj, Evas_Object *stack);
static void
_e_comp_intercept_stack_helper(E_Comp_Object *cw, Evas_Object *stack, E_Comp_Object_Stack_Func stack_cb)
{
E_Comp_Object *cw2 = NULL;
E_Client *ecstack;
short layer;
Evas_Object *o = stack;
Eina_Bool raising = stack_cb == evas_object_stack_above;
if (cw->ec->layer_block)
{
/* obey compositor effects! */
if (cw->ec->layer == evas_object_layer_get(cw->smart_obj))
evas_object_data_set(cw->smart_obj, "client_restack", (void*)1);
stack_cb(cw->smart_obj, stack);
if (cw->ec->layer == evas_object_layer_get(cw->smart_obj))
evas_object_data_del(cw->smart_obj, "client_restack");
return;
}
/* assume someone knew what they were doing during client init */
if (cw->ec->new_client)
layer = cw->ec->layer;
else
layer = evas_object_layer_get(stack);
ecstack = e_client_below_get(cw->ec);
if (layer != e_comp_canvas_layer_map_to(cw->layer))
{
/* some FOOL is trying to restack a layer marker */
if (cw->smart_obj == e_comp->layers[cw->layer].obj) return;
evas_object_layer_set(cw->smart_obj, layer);
/* we got our layer wrangled, return now! */
if (layer != e_comp_canvas_layer_map_to(cw->layer)) return;
}
/* check if we're stacking below another client */
cw2 = evas_object_data_get(o, "comp_obj");
while (!cw2)
{
/* check for non-client layer object */
if (!e_util_strcmp(evas_object_name_get(o), "layer_obj"))
break;
/* find an existing client to use for layering
* by walking up the object stack
*
* this is guaranteed to be pretty quick since we'll either:
* - run out of client layers
* - find a stacking client
*/
o = evas_object_above_get(o);
if ((!o) || (o == cw->smart_obj)) break;
if (evas_object_layer_get(o) != layer)
{
/* reached the top client layer somehow
* use top client object
*/
o = e_comp->layers[e_comp_canvas_layer_map(E_LAYER_CLIENT_PRIO)].obj;
}
if (!o)
/* top client layer window hasn't been stacked yet. this probably shouldn't happen?
* return here since the top client layer window
*/
{
E_Client *ec;
ec = e_client_top_get();
if (ec)
o = ec->frame;
//else //wat
}
if (o) cw2 = evas_object_data_get(o, "comp_obj");
}
/* remove existing layers */
_e_comp_object_layers_remove(cw);
if (cw2)
{
if (o == stack) //if stacking above, cw2 is above; else cw2 is below
_e_comp_object_layers_add(cw, raising ? cw2 : NULL, raising ? NULL : cw2, 0);
else if (o == cw->smart_obj) //prepend (lower) if not stacking above
_e_comp_object_layers_add(cw, NULL, NULL, !raising);
else //if no stacking objects found, either raise or lower
_e_comp_object_layers_add(cw, raising ? NULL : cw2, raising ? cw2 : NULL, 0);
}
else
_e_comp_object_layers_add(cw, NULL, NULL, 0);
/* set restack if stacking has changed */
if (cw->ec->new_client || (!ecstack) || (ecstack->frame != o))
evas_object_data_set(cw->smart_obj, "client_restack", (void*)1);
stack_cb(cw->smart_obj, stack);
if (e_comp->layers[cw->layer].obj)
if (evas_object_below_get(cw->smart_obj) == e_comp->layers[cw->layer].obj)
{
CRI("STACKING ERROR!!!");
}
if (cw->ec->new_client || (!ecstack) || (ecstack->frame != o))
evas_object_data_del(cw->smart_obj, "client_restack");
if (!cw->visible) return;
e_comp_render_queue();
e_comp_shape_queue();
}
static void
_e_comp_intercept_stack_above(void *data, Evas_Object *obj, Evas_Object *above)
{
EINA_SAFETY_ON_TRUE_RETURN(obj == above);
if (evas_object_below_get(obj) == above) return;
_e_comp_intercept_stack_helper(data, above, evas_object_stack_above);
}
static void
_e_comp_intercept_stack_below(void *data, Evas_Object *obj, Evas_Object *below)
{
EINA_SAFETY_ON_TRUE_RETURN(obj == below);
if (evas_object_above_get(obj) == below) return;
_e_comp_intercept_stack_helper(data, below, evas_object_stack_below);
}
static void
_e_comp_intercept_lower(void *data, Evas_Object *obj)
{
E_Comp_Object *cw = data;
Evas_Object *o;
if (cw->ec->layer_block)
{
evas_object_lower(obj);
return;
}
if (!EINA_INLIST_GET(cw->ec)->prev) return; //already lowest on layer
o = evas_object_below_get(obj);
_e_comp_object_layers_remove(cw);
/* prepend to client list since this client should be the first item now */
_e_comp_object_layers_add(cw, NULL, NULL, 1);
if (evas_object_layer_get(o) != evas_object_layer_get(obj)) return; //already at bottom!
if (obj == e_comp->layers[cw->layer].obj) return; //never lower a layer marker!
evas_object_data_set(obj, "client_restack", (void*)1);
evas_object_lower(obj);
evas_object_data_del(obj, "client_restack");
if (!cw->visible) return;
e_comp_render_queue();
e_comp_shape_queue();
}
static void
_e_comp_intercept_raise(void *data, Evas_Object *obj)
{
E_Comp_Object *cw = data;
Evas_Object *o;
if (cw->ec->layer_block)
{
evas_object_raise(obj);
return;
}
if (!EINA_INLIST_GET(cw->ec)->next) return;//already highest on layer
o = evas_object_above_get(obj);
{
E_Client *ecabove = e_client_above_get(cw->ec);
if (ecabove && (ecabove->frame == e_comp->layers[cw->layer].obj) &&
(ecabove->frame == o)) return; //highest below marker
}
if (evas_object_layer_get(o) != evas_object_layer_get(obj)) return; //already at top!
if (obj == e_comp->layers[cw->layer].obj) //never raise a non-layer marker!
evas_object_raise(obj);
else
{
Evas_Object *op;
/* still stack below override below the layer marker */
for (op = o = e_comp->layers[cw->layer].obj;
o && o != e_comp->layers[cw->layer - 1].obj;
op = o, o = evas_object_below_get(o))
{
E_Client *ec;
ec = e_comp_object_client_get(o);
if (ec && (!ec->override)) break;
}
evas_object_stack_below(obj, op);
if (e_client_focus_track_enabled())
e_client_raise_latest_set(cw->ec); //modify raise list if necessary
}
if (!cw->visible) return;
e_comp_render_queue();
e_comp_shape_queue();
}
static void
_e_comp_intercept_hide(void *data, Evas_Object *obj)
{
E_Comp_Object *cw = data;
if (cw->ec->hidden)
{
/* hidden flag = just do it */
evas_object_hide(obj);
return;
}
if (cw->ec->input_only)
{
/* input_only = who cares */
evas_object_hide(obj);
return;
}
/* already hidden or currently animating */
if ((!cw->visible) || (cw->animating && (!cw->showing) && (!cw->ec->iconic))) return;
/* don't try hiding during shutdown */
cw->defer_hide |= stopping;
if (!cw->defer_hide)
{
if ((!cw->ec->iconic) && (!cw->ec->override))
/* unset delete requested so the client doesn't break */
cw->ec->delete_requested = 0;
if ((!cw->animating) || cw->showing || cw->ec->iconic)
{
if (cw->ec->iconic)
e_comp_object_signal_emit(obj, "e,action,iconify", "e");
if ((!cw->ec->iconic) || (cw->ec->iconic && (!cw->animating)))
{
e_comp_object_signal_emit(obj, "e,state,hidden", "e");
if (!cw->showing)
_e_comp_object_animating_begin(cw);
if (!_e_comp_object_effect_visibility_start(cw, 0)) return;
}
evas_object_smart_callback_call(obj, "hiding", cw->ec);
cw->defer_hide = !!cw->animating;
if (!cw->animating)
e_comp_object_effect_set(obj, NULL);
}
}
if (cw->animating) return;
/* if we have no animations running, go ahead and hide */
cw->defer_hide = 0;
evas_object_hide(obj);
}
static void
_e_comp_intercept_show_helper(E_Comp_Object *cw)
{
int w = 0, h = 0;
if (cw->ec->sticky)
e_comp_object_signal_emit(cw->smart_obj, "e,state,sticky", "e");
if (cw->visible)
{
if (cw->ec->iconic && cw->animating)
{
/* triggered during iconify animation */
e_comp_object_signal_emit(cw->smart_obj, "e,action,uniconify", "e");
cw->defer_hide = 0;
}
return;
}
if ((!cw->updates) && (!cw->ec->input_only) && (!cw->ec->ignored))
{
_e_comp_object_updates_init(cw);
if (!cw->updates)
{
cw->ec->changes.visible = !cw->ec->hidden;
cw->ec->visible = 1;
EC_CHANGED(cw->ec);
return;
}
}
if (cw->ec->new_client)
{
/* ignore until client idler first run */
cw->ec->changes.visible = !cw->ec->hidden;
cw->ec->visible = 1;
EC_CHANGED(cw->ec);
return;
}
/* ensure that some kind of frame calc has occurred if there's a frame */
if (e_pixmap_is_x(cw->ec->pixmap) && cw->frame_object &&
(cw->ec->h == cw->ec->client.h) && (cw->ec->w == cw->ec->client.w))
CRI("ACK!");
/* force resize in case it hasn't happened yet, or just to update size */
evas_object_resize(cw->smart_obj, cw->ec->w, cw->ec->h);
if ((cw->w < 1) || (cw->h < 1))
{
/* if resize didn't go through, try again */
cw->ec->visible = cw->ec->changes.visible = 1;
EC_CHANGED(cw->ec);
return;
}
/* re-set geometry */
if (cw->ec->placed)
evas_object_move(cw->smart_obj, cw->ec->x, cw->ec->y);
/* if pixmap not available, clear pixmap since we're going to fetch it again */
if (!e_pixmap_size_get(cw->ec->pixmap, &w, &h))
e_pixmap_clear(cw->ec->pixmap);
if (cw->real_hid && w && h)
{
DBG(" [%p] real hid - fix", cw->ec);
cw->real_hid = 0;
/* force comp theming in case it didn't happen already */
e_comp_object_frame_theme_set(cw->smart_obj, E_COMP_OBJECT_FRAME_RESHADOW);
}
/* only do the show if show is allowed */
if (!cw->real_hid)
{
if (cw->ec->internal) //internal clients render when they feel like it
e_comp_object_damage(cw->smart_obj, 0, 0, cw->w, cw->h);
evas_object_show(cw->smart_obj);
}
}
static void
_e_comp_intercept_show(void *data, Evas_Object *obj EINA_UNUSED)
{
E_Comp_Object *cw = data;
E_Client *ec = cw->ec;
if (ec->ignored) return;
if (cw->effect_obj)
{
//INF("SHOW2 %p", ec);
_e_comp_intercept_show_helper(cw);
return;
}
//INF("SHOW %p", ec);
if (ec->input_only)
{
cw->effect_obj = evas_object_rectangle_add(e_comp->evas);
evas_object_color_set(cw->effect_obj, 0, 0, 0, 0);
evas_object_smart_member_add(cw->effect_obj, cw->smart_obj);
}
else
{
_e_comp_object_setup(cw);
cw->obj = evas_object_image_filled_add(e_comp->evas);
evas_object_image_border_center_fill_set(cw->obj, EVAS_BORDER_FILL_SOLID);
e_util_size_debug_set(cw->obj, 1);
evas_object_image_pixels_get_callback_set(cw->obj, _e_comp_object_pixels_get, cw);
evas_object_image_smooth_scale_set(cw->obj, e_comp_config_get()->smooth_windows);
evas_object_name_set(cw->obj, "cw->obj");
evas_object_image_colorspace_set(cw->obj, EVAS_COLORSPACE_ARGB8888);
_e_comp_object_alpha_set(cw);
if (cw->frame_object)
{
evas_object_event_callback_add(cw->obj, EVAS_CALLBACK_MOUSE_IN, _e_comp_object_ssd_mouse_in, cw);
evas_object_event_callback_add(cw->obj, EVAS_CALLBACK_MOUSE_OUT, _e_comp_object_ssd_mouse_out, cw);
}
#ifdef BORDER_ZOOMAPS
e_comp_object_zoomap_set(o, 1);
#else
cw->zoomap_disabled = 1;
#endif
cw->redirected = 1;
evas_object_color_set(cw->clip, ec->netwm.opacity, ec->netwm.opacity, ec->netwm.opacity, ec->netwm.opacity);
}
_e_comp_intercept_show_helper(cw);
}
static void
_e_comp_intercept_focus(void *data, Evas_Object *obj, Eina_Bool focus)
{
E_Comp_Object *cw = data;
E_Client *ec = cw->ec;
if (focus)
{
ec = e_client_stack_active_adjust(ec);
obj = ec->frame;
cw = evas_object_data_get(obj, "comp_obj");
}
/* 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 focus set on such windows */
/* be strict about accepting focus hint */
if (e_client_has_xwindow(ec))
{
/* be strict about accepting focus hint */
if ((!ec->icccm.accepts_focus) &&
(!ec->icccm.take_focus)) return;
}
if (focus && ec->lock_focus_out) return;
if (e_object_is_del(E_OBJECT(ec)) && focus)
{
CRI("CAN'T FOCUS DELETED CLIENT!");
return;
}
/* filter focus setting based on current state */
if (focus)
{
if (ec->focused)
{
evas_object_focus_set(obj, focus);
return;
}
if ((ec->iconic) && (!ec->deskshow))
{
/* don't focus an iconified window. that's silly! */
e_client_uniconify(ec);
if (e_client_focus_track_enabled())
e_client_focus_latest_set(ec);
return;
}
if (!ec->visible)
{
return;
}
if ((!ec->sticky) && (ec->desk) && (!ec->desk->visible))
{
if (ec->desk->animate_count) return;
e_desk_show(ec->desk);
if (!ec->desk->visible) return;
}
}
if (focus)
{
/* check for dialog children that steal focus */
if ((ec->modal) && (ec->modal != ec) &&
(ec->modal->visible) && (!e_object_is_del(E_OBJECT(ec->modal))))
{
evas_object_focus_set(ec->modal->frame, focus);
return;
}
else if ((ec->leader) && (ec->leader->modal) &&
(ec->leader->modal != ec) && ec->leader->modal->visible &&
(!e_object_is_del(E_OBJECT(ec->leader->modal))))
{
evas_object_focus_set(ec->leader->modal->frame, focus);
return;
}
if (!cw->visible)
{
/* not yet visible, wait till the next time... */
ec->want_focus = !ec->hidden;
if (ec->want_focus)
EC_CHANGED(ec);
return;
}
e_client_focused_set(ec);
}
else
{
if (e_client_focused_get() == ec)
e_client_focused_set(NULL);
}
evas_object_focus_set(obj, focus);
}
////////////////////////////////////////////////////
static void
_e_comp_object_frame_recalc(E_Comp_Object *cw)
{
int w, h, ox, oy, ow, oh;
if (cw->frame_object)
{
if (cw->obj) edje_object_part_unswallow(cw->frame_object, cw->obj);
evas_object_geometry_get(cw->frame_object, NULL, NULL, &w, &h);
/* set a fixed size, force edje calc, check size difference */
evas_object_resize(cw->frame_object, MAX(w, 50), MAX(h, 50));
edje_object_message_signal_process(cw->frame_object);
edje_object_calc_force(cw->frame_object);
edje_object_part_geometry_get(cw->frame_object, "e.swallow.client", &ox, &oy, &ow, &oh);
cw->client_inset.l = ox;
cw->client_inset.r = MAX(w, 50) - (ox + ow);
cw->client_inset.t = oy;
cw->client_inset.b = MAX(h, 50) - (oy + oh);
if (cw->obj) edje_object_part_swallow(cw->frame_object, "e.swallow.client", cw->obj);
evas_object_resize(cw->frame_object, w, h);
if (!cw->input_objs)
evas_object_pass_events_set(cw->obj, 0);
}
else
{
cw->client_inset.l = 0;
cw->client_inset.r = 0;
cw->client_inset.t = 0;
cw->client_inset.b = 0;
}
cw->client_inset.calc = !!cw->frame_object;
}
static void
_e_comp_smart_cb_frame_recalc(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
E_Comp_Object *cw = data;
int w = 0, h = 0, pw = 0, ph = 0;
/* - get current size
* - calc new size
* - readjust for new frame size
*/
w = cw->ec->w, h = cw->ec->h;
e_comp_object_frame_wh_unadjust(obj, w, h, &pw, &ph);
_e_comp_object_frame_recalc(cw);
if (!cw->ec->fullscreen)
e_comp_object_frame_wh_adjust(obj, cw->ec->client.w, cw->ec->client.h, &w, &h);
evas_object_smart_callback_call(cw->smart_obj, "frame_recalc_done", &cw->client_inset);
if (cw->ec->shading || cw->ec->shaded) return;
if (cw->ec->fullscreen)
evas_object_resize(cw->ec->frame, cw->ec->zone->w, cw->ec->zone->h);
else if (cw->ec->new_client)
{
if ((cw->ec->w < 1) || (cw->ec->h < 1)) return;
e_comp_object_frame_wh_adjust(obj, pw, ph, &w, &h);
evas_object_resize(cw->ec->frame, w, h);
}
else if ((w != cw->ec->w) || (h != cw->ec->h))
evas_object_resize(cw->ec->frame, w, h);
}
static Eina_Bool
_e_comp_object_shade_animator(void *data)
{
E_Comp_Object *cw = data;
Eina_Bool move = EINA_FALSE;
int x, y, w, h;
double dt, val;
double dur;
dt = ecore_loop_time_get() - cw->shade.start;
dur = cw->ec->client.h / e_config->border_shade_speed;
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)
{
cw->shade.val =
ecore_animator_pos_map(val, ECORE_POS_MAP_SINUSOIDAL, 0.0, 0.0);
if (!cw->ec->shaded) cw->shade.val = 1.0 - cw->shade.val;
}
else if (e_config->border_shade_transition == E_TRANSITION_DECELERATE)
{
cw->shade.val =
ecore_animator_pos_map(val, ECORE_POS_MAP_DECELERATE, 0.0, 0.0);
if (!cw->ec->shaded) cw->shade.val = 1.0 - cw->shade.val;
}
else if (e_config->border_shade_transition == E_TRANSITION_ACCELERATE)
{
cw->shade.val =
ecore_animator_pos_map(val, ECORE_POS_MAP_ACCELERATE, 0.0, 0.0);
if (!cw->ec->shaded) cw->shade.val = 1.0 - cw->shade.val;
}
else if (e_config->border_shade_transition == E_TRANSITION_LINEAR)
{
cw->shade.val =
ecore_animator_pos_map(val, ECORE_POS_MAP_LINEAR, 0.0, 0.0);
if (!cw->ec->shaded) cw->shade.val = 1.0 - cw->shade.val;
}
else if (e_config->border_shade_transition == E_TRANSITION_ACCELERATE_LOTS)
{
cw->shade.val =
ecore_animator_pos_map(val, ECORE_POS_MAP_ACCELERATE_FACTOR, 1.7, 0.0);
if (!cw->ec->shaded) cw->shade.val = 1.0 - cw->shade.val;
}
else if (e_config->border_shade_transition == E_TRANSITION_DECELERATE_LOTS)
{
cw->shade.val =
ecore_animator_pos_map(val, ECORE_POS_MAP_DECELERATE_FACTOR, 1.7, 0.0);
if (!cw->ec->shaded) cw->shade.val = 1.0 - cw->shade.val;
}
else if (e_config->border_shade_transition == E_TRANSITION_SINUSOIDAL_LOTS)
{
cw->shade.val =
ecore_animator_pos_map(val, ECORE_POS_MAP_SINUSOIDAL_FACTOR, 1.7, 0.0);
if (!cw->ec->shaded) cw->shade.val = 1.0 - cw->shade.val;
}
else if (e_config->border_shade_transition == E_TRANSITION_BOUNCE)
{
cw->shade.val =
ecore_animator_pos_map(val, ECORE_POS_MAP_BOUNCE, 1.2, 3.0);
if (!cw->ec->shaded) cw->shade.val = 1.0 - cw->shade.val;
}
else if (e_config->border_shade_transition == E_TRANSITION_BOUNCE_LOTS)
{
cw->shade.val =
ecore_animator_pos_map(val, ECORE_POS_MAP_BOUNCE, 1.2, 5.0);
if (!cw->ec->shaded) cw->shade.val = 1.0 - cw->shade.val;
}
else
{
cw->shade.val =
ecore_animator_pos_map(val, ECORE_POS_MAP_LINEAR, 0.0, 0.0);
if (!cw->ec->shaded) cw->shade.val = 1.0 - cw->shade.val;
}
/* due to M_PI's inaccuracy, cos(M_PI/2) != 0.0, so we need this */
if (cw->shade.val < 0.001) cw->shade.val = 0.0;
else if (cw->shade.val > .999)
cw->shade.val = 1.0;
x = cw->ec->x, y = cw->ec->y, w = cw->ec->w, h = cw->ec->h;
if (cw->shade.dir == E_DIRECTION_UP)
h = cw->client_inset.t + cw->ec->client.h * cw->shade.val;
else if (cw->shade.dir == E_DIRECTION_DOWN)
{
h = cw->client_inset.t + cw->ec->client.h * cw->shade.val;
y = cw->shade.y + cw->ec->client.h * (1 - cw->shade.val);
move = EINA_TRUE;
}
else if (cw->shade.dir == E_DIRECTION_LEFT)
w = cw->client_inset.t + cw->ec->client.w * cw->shade.val;
else if (cw->shade.dir == E_DIRECTION_RIGHT)
{
w = cw->client_inset.t + cw->ec->client.w * cw->shade.val;
x = cw->shade.x + cw->ec->client.w * (1 - cw->shade.val);
move = EINA_TRUE;
}
if (move) evas_object_move(cw->smart_obj, x, y);
evas_object_resize(cw->smart_obj, w, h);
/* we're done */
if (EINA_DBL_EQ(val, 1))
{
cw->shade.anim = NULL;
evas_object_smart_callback_call(cw->smart_obj, "shade_done", NULL);
if (cw->ec->shaded)
e_comp_object_signal_emit(cw->smart_obj, "e,state,shaded", "e");
else
e_comp_object_signal_emit(cw->smart_obj, "e,state,unshaded", "e");
edje_object_message_signal_process(cw->frame_object);
_e_comp_smart_cb_frame_recalc(cw, cw->smart_obj, NULL);
}
return cw->ec->shading;
}
static void
_e_comp_smart_cb_shaded(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
{
E_Comp_Object *cw = data;
if (!cw->ec) return; //NYI
E_FREE_FUNC(cw->shade.anim, ecore_animator_del);
e_comp_object_signal_emit(cw->smart_obj, "e,state,shaded", "e");
cw->shade.start = -100;
cw->shade.dir = (E_Direction)event_info;
_e_comp_object_shade_animator(cw);
}
static void
_e_comp_smart_cb_shading(void *data, Evas_Object *obj, void *event_info)
{
E_Comp_Object *cw = data;
if (!cw->ec) return; //NYI
if (cw->shade.anim && EINA_DBL_EQ(cw->shade.val, 0.0))
{
cw->ec->shaded = 0;
_e_comp_smart_cb_shaded(data, obj, event_info);
return;
}
E_FREE_FUNC(cw->shade.anim, ecore_animator_del);
cw->shade.x = cw->x;
cw->shade.y = cw->y;
e_comp_object_signal_emit(cw->smart_obj, "e,state,shading", "e");
cw->shade.start = ecore_loop_time_get();
cw->shade.dir = (E_Direction)event_info;
cw->shade.anim = ecore_animator_add(_e_comp_object_shade_animator, cw);
}
static void
_e_comp_smart_cb_unshaded(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
{
E_Comp_Object *cw = data;
if (!cw->ec) return; //NYI
E_FREE_FUNC(cw->shade.anim, ecore_animator_del);
cw->shade.dir = (E_Direction)event_info;
if (cw->shade.dir == E_DIRECTION_UP ||
cw->shade.dir == E_DIRECTION_LEFT)
{
cw->shade.x = cw->x;
cw->shade.y = cw->y;
}
else
{
cw->shade.x = cw->x - cw->w;
cw->shade.y = cw->y - cw->h;
}
e_comp_object_signal_emit(cw-</