enlightenment/src/modules/physics/e_mod_physics.c

912 lines
28 KiB
C

#include "e.h"
#include "e_mod_main.h"
#include "e_mod_physics.h"
#include <EPhysics.h>
typedef struct _E_Physics E_Physics;
typedef struct _E_Physics_Win E_Physics_Win;
typedef struct _E_Physics_Shelf E_Physics_Shelf;
struct _E_Physics
{
EPhysics_World *world;
Ecore_X_Window win;
E_Manager *man;
Eina_Inlist *wins;
Eina_Inlist *shelves;
};
struct _E_Physics_Shelf
{
EINA_INLIST;
E_Physics *p;
E_Shelf *es;
EPhysics_Body *body;
};
struct _E_Physics_Win
{
EINA_INLIST;
E_Physics *p; // parent physics
Ecore_X_Window win; // raw window - for menus etc.
E_Border *bd; // if its a border - later
E_Popup *pop; // if its a popup - later
E_Menu *menu; // if it is a menu - later
EPhysics_Body *body; // physics body
int x, y, w, h; // geometry
int ix, iy; // impulse geometry (next move coord */
struct
{
int x, y, w, h; // hidden geometry (used when its unmapped and re-instated on map)
} hidden;
int border; // border width
E_Border_Hook *begin; // begin move
E_Border_Hook *end; // end move
E_Maximize maximize;
unsigned int stopped; /* number of frames window has been stopped for */
unsigned int started; /* number of frames window has been moving for */
double impulse_x, impulse_y; /* x,y for impulse vector */
Eina_Bool visible : 1; // is visible
Eina_Bool inhash : 1; // is in the windows hash
Eina_Bool show_ready : 1; // is this window ready for its first show
Eina_Bool moving : 1;
Eina_Bool impulse : 1;
};
static Eina_List *handlers = NULL;
static Eina_List *physicists = NULL;
static Eina_Hash *borders = NULL;
//////////////////////////////////////////////////////////////////////////
#undef DBG
#if 0
#define DBG(f, x ...) printf(f, ##x)
#else
#define DBG(f, x ...)
#endif
static Eina_Bool _e_mod_physics_bd_fullscreen(void *data __UNUSED__, int type, void *event);
static void _e_mod_physics_bd_move_intercept_cb(E_Border *bd, int x, int y);
static void _e_mod_physics_win_update_cb(E_Physics_Win *pw, EPhysics_Body *body, void *event_info __UNUSED__);
static void _e_mod_physics_win_del(E_Physics_Win *pw);
static void _e_mod_physics_win_show(E_Physics_Win *pw);
static void _e_mod_physics_win_hide(E_Physics_Win *pw);
static void _e_mod_physics_win_configure(E_Physics_Win *pw,
int x,
int y,
int w,
int h,
int border);
static void _e_mod_physics_shelf_new(E_Physics *p, E_Shelf *es);
static void
_e_mod_physics_move_end(void *p_w, void *b_d)
{
E_Physics_Win *pw = p_w;
/* wrong border */
if (b_d != pw->bd) return;
DBG("PHYS: DRAG END %d\n", pw->win);
pw->impulse = pw->moving = EINA_FALSE;
}
static void
_e_mod_physics_move_begin(void *p_w, void *b_d)
{
E_Physics_Win *pw = p_w;
/* wrong border */
if (b_d != pw->bd) return;
DBG("PHYS: DRAG BEGIN %d\n", pw->win);
pw->moving = EINA_TRUE;
pw->started = 0;
/* hacks! */
if ((!pw->impulse_x) && (!pw->impulse_y)) return;
_e_mod_physics_win_hide(pw);
_e_mod_physics_win_show(pw);
pw->show_ready = 0;
_e_mod_physics_win_configure(pw, pw->bd->x, pw->bd->y, pw->bd->w, pw->bd->h, pw->border);
pw->impulse_x = pw->impulse_y = 0;
}
static E_Physics *
_e_mod_physics_find(Ecore_X_Window root)
{
Eina_List *l;
E_Physics *p;
// fixme: use hash if physicists list > 4
EINA_LIST_FOREACH (physicists, l, p)
{
if (p->man->root == root) return p;
}
return NULL;
}
static E_Physics_Win *
_e_mod_physics_win_find(Ecore_X_Window win)
{
return eina_hash_find(borders, e_util_winid_str_get(win));
}
static void
_e_mod_physics_win_show(E_Physics_Win *pw)
{
if (pw->visible) return;
DBG("PHYS: SHOW %d\n", pw->win);
pw->visible = 1;
pw->body = ephysics_body_box_add(pw->p->world);
ephysics_body_friction_set(pw->body, 1.0);
ephysics_body_angular_movement_enable_set(pw->body, EINA_FALSE, EINA_FALSE,
EINA_FALSE);
ephysics_body_event_callback_add(pw->body, EPHYSICS_CALLBACK_BODY_UPDATE, (EPhysics_Body_Event_Cb)_e_mod_physics_win_update_cb, pw);
pw->begin = e_border_hook_add(E_BORDER_HOOK_MOVE_BEGIN, _e_mod_physics_move_begin, pw);
pw->end = e_border_hook_add(E_BORDER_HOOK_MOVE_END, _e_mod_physics_move_end, pw);
e_border_move_intercept_cb_set(pw->bd, _e_mod_physics_bd_move_intercept_cb);
}
static void
_e_mod_physics_bd_move_intercept_cb(E_Border *bd, int x, int y)
{
E_Physics_Win *pw;
pw = _e_mod_physics_win_find(bd->client.win);
if ((bd->x == x) && (bd->y == y))
{
DBG("PHYS: STOPPED %d\n", pw->win);
if (pw->moving) pw->started = 0;
pw->show_ready = 0;
_e_mod_physics_win_configure(pw, x, y, pw->bd->w, pw->bd->h, pw->border);
return;
}
if (!pw) return;
DBG("PHYS: MOVE %d - (%d,%d) ->(WANT) (%d,%d)\n", pw->win, bd->x, bd->y, x, y);
if ((!pw->body) || (!pw->moving) || (pw->started < _physics_mod->conf->delay))
{
DBG("PHYS: MOVE THROUGH\n");
bd->x = x, bd->y = y;
if (pw->moving) pw->started++;
pw->show_ready = 0;
_e_mod_physics_win_configure(pw, x, y, pw->bd->w, pw->bd->h, pw->border);
return;
}
if (!pw->impulse)
{
DBG("PHYS: IMPULSE APPLY\n");
pw->impulse_x = (x - bd->x) * 5;
pw->impulse_y = (bd->y - y) * 5;
ephysics_body_central_impulse_apply(pw->body, pw->impulse_x, pw->impulse_y, 0);
bd->x = x, bd->y = y;
pw->impulse = EINA_TRUE;
return;
}
if ((pw->ix == x) && (pw->iy == y))
bd->x = x, bd->y = y;
else
{
if (E_INSIDE(bd->x, bd->y, pw->p->man->x, pw->p->man->y, pw->p->man->w, pw->p->man->h) &&
E_INSIDE(bd->x + bd->w, bd->y, pw->p->man->x, pw->p->man->y, pw->p->man->w, pw->p->man->h) &&
E_INSIDE(bd->x, bd->y + bd->h, pw->p->man->x, pw->p->man->y, pw->p->man->w, pw->p->man->h) &&
E_INSIDE(bd->x + bd->w, bd->y + bd->h, pw->p->man->x, pw->p->man->y, pw->p->man->w, pw->p->man->h))
DBG("REJECTED!\n");
else if (pw->moving)
{
DBG("UPDATE\n");
bd->x = x, bd->y = y;
pw->show_ready = 0;
_e_mod_physics_win_configure(pw, x, y, pw->bd->w, pw->bd->h, pw->border);
}
}
}
static E_Physics_Win *
_e_mod_physics_win_add(E_Physics *p, E_Border *bd)
{
Ecore_X_Window_Attributes att;
E_Physics_Win *pw;
memset((&att), 0, sizeof(Ecore_X_Window_Attributes));
if (!ecore_x_window_attributes_get(bd->client.win, &att))
return NULL;
/* don't physics on input grab windows or tooltips */
if (att.input_only || att.override) return NULL;
pw = calloc(1, sizeof(E_Physics_Win));
if (!pw) return NULL;
pw->win = bd->client.win;
pw->p = p;
pw->bd = bd;
eina_hash_add(borders, e_util_winid_str_get(pw->bd->client.win), pw);
if (pw->bd->visible)
_e_mod_physics_win_show(pw);
DBG("PHYS: WIN %d ADD\n", bd->client.win);
p->wins = eina_inlist_append(p->wins, EINA_INLIST_GET(pw));
return pw;
}
static void
_e_mod_physics_win_del(E_Physics_Win *pw)
{
eina_hash_del(borders, e_util_winid_str_get(pw->bd->client.win), pw);
e_border_move_intercept_cb_set(pw->bd, NULL);
pw->bd = NULL;
pw->p->wins = eina_inlist_remove(pw->p->wins, EINA_INLIST_GET(pw));
if (pw->body) ephysics_body_del(pw->body);
memset(pw, 0, sizeof(E_Physics_Win));
free(pw);
}
static void
_e_mod_physics_win_hide(E_Physics_Win *pw)
{
if (!pw->visible) return;
DBG("PHYS: HIDE %d\n", pw->win);
pw->show_ready = pw->visible = 0;
ephysics_body_del(pw->body);
pw->body = NULL;
e_border_hook_del(pw->begin);
e_border_hook_del(pw->end);
pw->begin = pw->end = NULL;
e_border_move_intercept_cb_set(pw->bd, NULL);
}
#if 0
static void
_e_mod_physics_win_raise_above(E_Physics_Win *pw,
E_Physics_Win *cw2)
{
DBG(" [0x%x] abv [0x%x]\n", pw->win, cw2->win);
pw->p->wins_invalid = 1;
pw->p->wins = eina_inlist_remove(pw->p->wins, EINA_INLIST_GET(pw));
pw->p->wins = eina_inlist_append_relative(pw->p->wins,
EINA_INLIST_GET(pw),
EINA_INLIST_GET(cw2));
evas_object_stack_above(pw->shobj, cw2->shobj);
if (pw->bd)
{
Eina_List *l;
E_Border *tmp;
EINA_LIST_FOREACH (pw->bd->client.e.state.video_child, l, tmp)
{
E_Physics_Win *tcw;
tcw = eina_hash_find(borders, e_util_winid_str_get(tmp->client.win));
if (!tcw) continue;
evas_object_stack_below(tcw->shobj, pw->shobj);
}
}
_e_mod_physics_win_render_queue(pw);
pw->pending_count++;
e_manager_comp_event_src_config_send
(pw->p->man, (E_Manager_Comp_Source *)pw,
_e_mod_physics_cb_pending_after, pw->p);
}
static void
_e_mod_physics_win_raise(E_Physics_Win *pw)
{
DBG(" [0x%x] rai\n", pw->win);
pw->p->wins_invalid = 1;
pw->p->wins = eina_inlist_remove(pw->p->wins, EINA_INLIST_GET(pw));
pw->p->wins = eina_inlist_append(pw->p->wins, EINA_INLIST_GET(pw));
evas_object_raise(pw->shobj);
if (pw->bd)
{
Eina_List *l;
E_Border *tmp;
EINA_LIST_FOREACH (pw->bd->client.e.state.video_child, l, tmp)
{
E_Physics_Win *tcw;
tcw = eina_hash_find(borders, e_util_winid_str_get(tmp->client.win));
if (!tcw) continue;
evas_object_stack_below(tcw->shobj, pw->shobj);
}
}
_e_mod_physics_win_render_queue(pw);
pw->pending_count++;
e_manager_comp_event_src_config_send
(pw->p->man, (E_Manager_Comp_Source *)pw,
_e_mod_physics_cb_pending_after, pw->p);
}
static void
_e_mod_physics_win_lower(E_Physics_Win *pw)
{
DBG(" [0x%x] low\n", pw->win);
pw->p->wins_invalid = 1;
pw->p->wins = eina_inlist_remove(pw->p->wins, EINA_INLIST_GET(pw));
pw->p->wins = eina_inlist_prepend(pw->p->wins, EINA_INLIST_GET(pw));
evas_object_lower(pw->shobj);
if (pw->bd)
{
Eina_List *l;
E_Border *tmp;
EINA_LIST_FOREACH (pw->bd->client.e.state.video_child, l, tmp)
{
E_Physics_Win *tcw;
tcw = eina_hash_find(borders, e_util_winid_str_get(tmp->client.win));
if (!tcw) continue;
evas_object_stack_below(tcw->shobj, pw->shobj);
}
}
_e_mod_physics_win_render_queue(pw);
pw->pending_count++;
e_manager_comp_event_src_config_send
(pw->p->man, (E_Manager_Comp_Source *)pw,
_e_mod_physics_cb_pending_after, pw->p);
}
#endif
static void
_e_mod_physics_win_mass_set(E_Physics_Win *pw)
{
double mass;
E_Border *bd = pw->bd;
if (!bd) return;
if (bd->remember)
{
if ((bd->remember->apply & E_REMEMBER_APPLY_POS) ||
(bd->remember->prop.lock_client_location) ||
(bd->remember->prop.lock_user_location))
ephysics_body_mass_set(pw->body, 50000);
return;
}
mass = _physics_mod->conf->max_mass * (((double)pw->w / (double)pw->p->man->w) + ((double)pw->h / (double)pw->p->man->h) / 2.);
DBG("PHYS: WIN %d MASS %g\n", pw->win, mass);
ephysics_body_mass_set(pw->body, mass);
}
static void
_e_mod_physics_win_configure(E_Physics_Win *pw,
int x,
int y,
int w,
int h,
int border)
{
//DBG("PHYS: CONFIG %d\n", pw->win);
if (!pw->visible)
{
pw->hidden.x = x;
pw->hidden.y = y;
pw->border = border;
}
else
{
if (!((x == pw->x) && (y == pw->y)))
{
pw->x = x;
pw->y = y;
}
pw->hidden.x = x;
pw->hidden.y = y;
}
pw->maximize = pw->bd->maximized;
pw->hidden.w = w;
pw->hidden.h = h;
if (!((w == pw->w) && (h == pw->h)))
{
pw->w = w;
pw->h = h;
}
if (pw->border != border)
{
pw->border = border;
}
if ((!pw->show_ready) && pw->body)
{
_e_mod_physics_win_mass_set(pw);
ephysics_body_geometry_set(pw->body, x, y, -15, w, border + h, 30);
pw->show_ready = 1;
}
}
static E_Physics_Shelf *
_e_mod_physics_shelf_find(E_Physics *p, E_Shelf *es)
{
E_Physics_Shelf *eps;
EINA_INLIST_FOREACH(p->shelves, eps)
if (eps->es == es) return eps;
return NULL;
}
static void
_e_mod_physics_shelf_free(E_Physics *p, E_Shelf *es)
{
E_Physics_Shelf *eps;
eps = _e_mod_physics_shelf_find(p, es);
if (!eps) return;
if (eps->body) ephysics_body_del(eps->body);
p->shelves = eina_inlist_remove(p->shelves, EINA_INLIST_GET(eps));
free(eps);
}
static void
_e_mod_physics_shelf_new(E_Physics *p, E_Shelf *es)
{
EPhysics_Body *eb;
E_Physics_Shelf *eps;
eps = E_NEW(E_Physics_Shelf, 1);
eps->p = p;
eps->es = es;
if (!_physics_mod->conf->ignore_shelves)
{
if (_physics_mod->conf->shelf.disable_move)
{
eps->body = eb = ephysics_body_box_add(p->world);
ephysics_body_evas_object_set(eb, es->o_base, EINA_TRUE);
ephysics_body_linear_movement_enable_set(eb, EINA_FALSE,
EINA_FALSE, EINA_FALSE);
ephysics_body_mass_set(eb, 50000);
}
else
{
eps->body = eb = ephysics_body_box_add(p->world);
ephysics_body_evas_object_set(eb, es->o_base, EINA_TRUE);
if (es->cfg->overlap || es->cfg->autohide)
ephysics_body_mass_set(eb, 0);
else
ephysics_body_mass_set(eb, 50000);
if (es->cfg->popup && (!_physics_mod->conf->shelf.disable_rotate))
ephysics_body_angular_movement_enable_set(eb, EINA_FALSE,
EINA_FALSE,
EINA_FALSE);
}
}
p->shelves = eina_inlist_append(p->shelves, EINA_INLIST_GET(eps));
}
//////////////////////////////////////////////////////////////////////////
static Eina_Bool
_e_mod_physics_bd_property(void *data __UNUSED__, int type __UNUSED__, void *event)
{
E_Event_Border_Property *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->border->client.win);
if (pw->maximize == ev->border->maximized) return ECORE_CALLBACK_PASS_ON;
if (ev->border->maximized)
_e_mod_physics_win_del(pw);
else
{
E_Physics *p = _e_mod_physics_find(ev->border->zone->container->manager->root);
pw = _e_mod_physics_win_add(p, ev->border);
if (!pw) return ECORE_CALLBACK_PASS_ON;
_e_mod_physics_win_configure(pw, pw->bd->x, pw->bd->y,
pw->bd->w, pw->bd->h,
ecore_x_window_border_width_get(pw->bd->client.win));
}
pw->maximize = ev->border->maximized;
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_mod_physics_bd_fullscreen(void *data __UNUSED__, int type, void *event)
{
E_Event_Border_Fullscreen *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->border->client.win);
if (type == E_EVENT_BORDER_FULLSCREEN)
{
if (pw)
_e_mod_physics_win_del(pw);
}
else
{
E_Physics *p = _e_mod_physics_find(ev->border->zone->container->manager->root);
if (!pw)
{
pw = _e_mod_physics_win_add(p, ev->border);
if (!pw) return ECORE_CALLBACK_PASS_ON;
_e_mod_physics_win_configure(pw, pw->bd->x, pw->bd->y,
pw->bd->w, pw->bd->h,
ecore_x_window_border_width_get(pw->bd->client.win));
}
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_mod_physics_bd_add(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
E_Event_Border_Add *ev = event;
DBG("PHYS: NEW %d\n", ev->border->client.win);
E_Physics *p = _e_mod_physics_find(ev->border->zone->container->manager->root);
E_Physics_Win *pw = _e_mod_physics_win_find(ev->border->client.win);
if (pw) return ECORE_CALLBACK_PASS_ON;
pw = _e_mod_physics_win_add(p, ev->border);
if (pw) _e_mod_physics_win_configure(pw, ev->border->x, ev->border->y, ev->border->w, ev->border->h,
ecore_x_window_border_width_get(ev->border->client.win));
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_mod_physics_bd_del(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
E_Event_Border_Add *ev = event;
DBG("PHYS: DEL %d\n", ev->border->client.win);
E_Physics_Win *pw = _e_mod_physics_win_find(ev->border->client.win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
_e_mod_physics_win_del(pw);
return ECORE_CALLBACK_PASS_ON;
}
/*
static Eina_Bool
_e_mod_physics_reparent(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
Ecore_X_Event_Window_Reparent *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
if (ev->parent != pw->p->man->root)
_e_mod_physics_win_del(pw);
return ECORE_CALLBACK_PASS_ON;
}
*/
static Eina_Bool
_e_mod_physics_configure(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
Ecore_X_Event_Window_Configure *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
/* TODO: stacking
if (ev->abovewin == 0)
{
if (EINA_INLIST_GET(pw)->prev) _e_mod_physics_win_lower(pw);
}
else
{
E_Physics_Win *cw2 = _e_mod_physics_win_find(ev->abovewin);
if (cw2)
{
E_Physics_Win *cw3 = (E_Physics_Win *)(EINA_INLIST_GET(pw)->prev);
if (cw3 != cw2) _e_mod_physics_win_raise_above(pw, cw2);
}
}
*/
if (!((pw->x == ev->x) && (pw->y == ev->y) &&
(pw->w == ev->w) && (pw->h == ev->h) &&
(pw->border == ev->border)))
{
_e_mod_physics_win_configure(pw, ev->x, ev->y, ev->w, ev->h, ev->border);
}
return ECORE_CALLBACK_PASS_ON;
}
#if 0
static Eina_Bool
_e_mod_physics_stack(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
Ecore_X_Event_Window_Stack *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
/* TODO
if (ev->detail == ECORE_X_WINDOW_STACK_ABOVE) _e_mod_physics_win_raise(pw);
else _e_mod_physics_win_lower(pw);
*/
return ECORE_CALLBACK_PASS_ON;
}
#endif
static Eina_Bool
_e_mod_physics_randr(void *data __UNUSED__,
int type __UNUSED__,
__UNUSED__ void *event __UNUSED__)
{
Eina_List *l;
E_Physics *p;
EINA_LIST_FOREACH(physicists, l, p)
ephysics_world_render_geometry_set(p->world, 0, 0, -5,
p->man->w, p->man->h, 10);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_mod_physics_bd_resize(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
E_Event_Border_Move *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->border->client.win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
if (!pw->visible) return ECORE_CALLBACK_PASS_ON;
pw->show_ready = 0;
_e_mod_physics_win_configure(pw, pw->x, pw->y, ev->border->w, ev->border->h, pw->border);
pw->show_ready = 1;
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_mod_physics_shelf_add(void *data __UNUSED__, int type __UNUSED__, void *event)
{
E_Event_Shelf *ev = event;
E_Physics *p;
Eina_List *l;
EINA_LIST_FOREACH(physicists, l, p)
if (p->man == ev->shelf->zone->container->manager)
{
_e_mod_physics_shelf_new(p, ev->shelf);
break;
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_mod_physics_shelf_del(void *data __UNUSED__, int type __UNUSED__, void *event)
{
E_Event_Shelf *ev = event;
E_Physics *p;
Eina_List *l;
EINA_LIST_FOREACH(physicists, l, p)
if (p->man == ev->shelf->zone->container->manager)
{
_e_mod_physics_shelf_free(p, ev->shelf);
break;
}
return ECORE_CALLBACK_RENEW;
}
static Eina_Bool
_e_mod_physics_remember_update(void *data __UNUSED__, int type __UNUSED__, void *event)
{
E_Event_Remember_Update *ev = event;
E_Border *bd = ev->border;
E_Physics_Win *pw = _e_mod_physics_win_find(bd->client.win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
_e_mod_physics_win_mass_set(pw);
return ECORE_CALLBACK_PASS_ON;
}
/*
static Eina_Bool
_e_mod_physics_bd_move(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
E_Event_Border_Move *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->border->client.win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
if (!pw->visible) return ECORE_CALLBACK_PASS_ON;
_e_mod_physics_win_configure(pw, pw->x, pw->y, ev->border->w, ev->border->h, pw->border);
return ECORE_CALLBACK_PASS_ON;
}
*/
static Eina_Bool
_e_mod_physics_bd_show(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
E_Event_Border_Hide *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->border->client.win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
_e_mod_physics_win_show(pw);
_e_mod_physics_win_configure(pw, pw->bd->x, pw->bd->y, pw->bd->w, pw->bd->h, pw->border);
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_mod_physics_bd_hide(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
E_Event_Border_Hide *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->border->client.win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
_e_mod_physics_win_hide(pw);
return ECORE_CALLBACK_PASS_ON;
}
#if 0
static Eina_Bool
_e_mod_physics_bd_iconify(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
E_Event_Border_Iconify *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->border->client.win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
// fimxe: special iconfiy anim
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_mod_physics_bd_uniconify(void *data __UNUSED__,
int type __UNUSED__,
void *event)
{
E_Event_Border_Uniconify *ev = event;
E_Physics_Win *pw = _e_mod_physics_win_find(ev->border->client.win);
if (!pw) return ECORE_CALLBACK_PASS_ON;
// fimxe: special uniconfiy anim
return ECORE_CALLBACK_PASS_ON;
}
#endif
static E_Physics *
_e_mod_physics_add(E_Manager *man)
{
E_Physics *p;
EPhysics_Body *bound;
Eina_List *l;
E_Border *bd;
E_Shelf *es;
p = calloc(1, sizeof(E_Physics));
if (!p) return NULL;
p->man = man;
p->world = ephysics_world_new();
/* TODO: world per zone */
DBG("PHYS: world++ || %dx%d\n", man->w, man->h);
ephysics_world_render_geometry_set(p->world, 0, 0, -5, man->w, man->h, 10);
ephysics_world_gravity_set(p->world, 0, _physics_mod->conf->gravity, 0);
bound = ephysics_body_left_boundary_add(p->world);
ephysics_body_restitution_set(bound, 1);
ephysics_body_friction_set(bound, 3);
bound = ephysics_body_right_boundary_add(p->world);
ephysics_body_restitution_set(bound, 1);
ephysics_body_friction_set(bound, 3);
bound = ephysics_body_top_boundary_add(p->world);
ephysics_body_restitution_set(bound, 1);
ephysics_body_friction_set(bound, 3);
bound = ephysics_body_bottom_boundary_add(p->world);
ephysics_body_restitution_set(bound, 1);
ephysics_body_friction_set(bound, 3);
EINA_LIST_FOREACH(e_border_client_list(), l, bd)
{
E_Physics_Win *pw;
int border;
pw = _e_mod_physics_win_add(p, bd);
if (!pw) continue;
border = ecore_x_window_border_width_get(bd->client.win);
_e_mod_physics_win_configure(pw, bd->x, bd->y, bd->w, bd->h, border);
}
l = e_shelf_list_all();
EINA_LIST_FREE(l, es)
_e_mod_physics_shelf_new(p, es);
return p;
}
static void
_e_mod_physics_del(E_Physics *p)
{
E_Physics_Win *pw;
Eina_Inlist *l;
E_Physics_Shelf *eps;
while (p->wins)
{
pw = (E_Physics_Win *)(p->wins);
_e_mod_physics_win_del(pw);
}
if (p->world)
ephysics_world_del(p->world);
EINA_INLIST_FOREACH_SAFE(p->shelves, l, eps)
{
free(eps);
}
free(p);
}
static void
_e_mod_physics_win_update_cb(E_Physics_Win *pw, EPhysics_Body *body, void *event_info __UNUSED__)
{
//DBG("PHYS: TICKER %d\n", pw->win);
if (pw->moving && (pw->started < _physics_mod->conf->delay))
{
pw->show_ready = 0;
_e_mod_physics_win_configure(pw, pw->x, pw->y, pw->w, pw->h, pw->border);
return;
}
ephysics_body_geometry_get(body, &pw->ix, &pw->iy, NULL, NULL, NULL, NULL);
e_border_move(pw->bd, pw->ix, pw->iy);
}
//////////////////////////////////////////////////////////////////////////
void
e_mod_physics_mass_update(void)
{
Eina_List *l;
E_Physics *p;
E_Physics_Win *pw;
EINA_LIST_FOREACH(physicists, l, p)
EINA_INLIST_FOREACH(p->wins, pw)
_e_mod_physics_win_mass_set(pw);
}
Eina_Bool
e_mod_physics_init(void)
{
Eina_List *l;
E_Manager *man;
borders = eina_hash_string_superfast_new(NULL);
// E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_REPARENT, _e_mod_physics_reparent, NULL);
E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_CONFIGURE, _e_mod_physics_configure, NULL);
//E_LIST_HANDLER_APPEND(handlers, ECORE_X_EVENT_WINDOW_STACK, _e_mod_physics_stack, NULL);
if (_physics_mod->conf->ignore_maximized)
E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_PROPERTY, _e_mod_physics_bd_property, NULL);
if (_physics_mod->conf->ignore_fullscreen)
{
E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_FULLSCREEN, _e_mod_physics_bd_fullscreen, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_UNFULLSCREEN, _e_mod_physics_bd_fullscreen, NULL);
}
E_LIST_HANDLER_APPEND(handlers, E_EVENT_CONTAINER_RESIZE, _e_mod_physics_randr, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_ADD, _e_mod_physics_bd_add, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_REMOVE, _e_mod_physics_bd_del, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_SHOW, _e_mod_physics_bd_show, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_HIDE, _e_mod_physics_bd_hide, NULL);
// E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_MOVE, _e_mod_physics_bd_move, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_RESIZE, _e_mod_physics_bd_resize, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_REMEMBER_UPDATE, _e_mod_physics_remember_update, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_SHELF_ADD, _e_mod_physics_shelf_add, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_SHELF_DEL, _e_mod_physics_shelf_del, NULL);
#if 0
E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_ICONIFY, _e_mod_physics_bd_iconify, NULL);
E_LIST_HANDLER_APPEND(handlers, E_EVENT_BORDER_UNICONIFY, _e_mod_physics_bd_uniconify, NULL);
#endif
EINA_LIST_FOREACH (e_manager_list(), l, man)
{
E_Physics *p;
p = _e_mod_physics_add(man);
if (p) physicists = eina_list_append(physicists, p);
}
ecore_x_sync();
return 1;
}
void
e_mod_physics_shutdown(void)
{
E_FREE_LIST(physicists, _e_mod_physics_del);
E_FREE_LIST(handlers, ecore_event_handler_del);
if (borders) eina_hash_free(borders);
borders = NULL;
}