diff --git a/configure.ac b/configure.ac index 0c88e559e..b2e1fc929 100644 --- a/configure.ac +++ b/configure.ac @@ -690,6 +690,37 @@ define([CHECK_MODULE_NOTIFICATION], fi ]) +have_ephysics=no +AM_CONDITIONAL([HAVE_EPHYSICS], [false]) +AC_ARG_ENABLE([ephysics], + AC_HELP_STRING([--disable-ephysics], [disable Ephysics support @<:@default=detect@:>@]), + [e_cv_want_ephysics=$enableval], + AC_CACHE_VAL([e_cv_want_ephysics], [e_cv_want_ephysics=yes]) +) +if test "x$e_cv_want_ephysics" != "xno" ; then + AC_E_CHECK_PKG(EPHYSICS, [ ephysics ], + [ + AC_DEFINE_UNQUOTED([HAVE_EPHYSICS], [1], [enable ephysics]) + ], + [ + AC_MSG_NOTICE([ephysics disabled]) + e_cv_want_ephysics=no + ]) +else + AC_MSG_NOTICE([ephysics disabled]) + e_cv_want_ephysics=no +fi +AC_SUBST([EPHYSICS_CFLAGS]) +AC_SUBST([EPHYSICS_LIBS]) + +AM_CONDITIONAL(HAVE_PHYSICS, false) +define([CHECK_MODULE_PHYSICS], +[ + if test "x$e_cv_want_ephysics" = "xno" ; then + PHYSICS=false + fi +]) + AM_CONDITIONAL(HAVE_ALSA, false) define([CHECK_MODULE_MIXER], [ @@ -806,6 +837,7 @@ AC_E_OPTIONAL_MODULE([syscon], true) AC_E_OPTIONAL_MODULE([everything], true) AC_E_OPTIONAL_MODULE([systray], true) AC_E_OPTIONAL_MODULE([comp], true) +AC_E_OPTIONAL_MODULE([physics], true, [CHECK_MODULE_PHYSICS]) AC_E_OPTIONAL_MODULE([shot], true) AC_E_OPTIONAL_MODULE([backlight], true) AC_E_OPTIONAL_MODULE([tasks], true) @@ -961,6 +993,8 @@ src/modules/systray/Makefile src/modules/systray/module.desktop src/modules/comp/Makefile src/modules/comp/module.desktop +src/modules/physics/Makefile +src/modules/physics/module.desktop src/modules/shot/Makefile src/modules/shot/module.desktop src/modules/backlight/Makefile diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index 0701b45b8..e65791342 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -175,6 +175,10 @@ if USE_MODULE_COMP SUBDIRS += comp endif +if USE_MODULE_PHYSICS +SUBDIRS += physics +endif + if USE_MODULE_OFONO SUBDIRS += ofono endif diff --git a/src/modules/physics/Makefile.am b/src/modules/physics/Makefile.am new file mode 100644 index 000000000..d1279f53c --- /dev/null +++ b/src/modules/physics/Makefile.am @@ -0,0 +1,36 @@ +MAINTAINERCLEANFILES = Makefile.in +MODULE = physics + +# data files for the module +filesdir = $(libdir)/enlightenment/modules/$(MODULE) +files_DATA = e-module-$(MODULE).edj module.desktop + +EXTRA_DIST = $(files_DATA) + +# the module .so file +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src/modules/$(MODULE) \ + -I$(top_srcdir)/src/bin \ + -I$(top_builddir)/src/bin \ + -I$(top_srcdir)/src/modules \ + @e_cflags@ @EPHYSICS_CFLAGS@ + +pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH) +pkg_LTLIBRARIES = module.la + +module_la_SOURCES = e_mod_main.c \ + e_mod_main.h \ + e_mod_config.c \ + e_mod_config.h \ + e_mod_physics_cfdata.c \ + e_mod_physics_cfdata.h \ + e_mod_physics.c \ + e_mod_physics.h + +module_la_LIBADD = @e_libs@ @dlopen_libs@ @EPHYSICS_LIBS@ +module_la_LDFLAGS = -module -avoid-version +module_la_DEPENDENCIES = $(top_builddir)/config.h + +uninstall: + rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE) diff --git a/src/modules/physics/e-module-physics.edj b/src/modules/physics/e-module-physics.edj new file mode 100644 index 000000000..1401ab4b8 Binary files /dev/null and b/src/modules/physics/e-module-physics.edj differ diff --git a/src/modules/physics/e_mod_config.c b/src/modules/physics/e_mod_config.c new file mode 100644 index 000000000..d637a4ab3 --- /dev/null +++ b/src/modules/physics/e_mod_config.c @@ -0,0 +1,142 @@ +#include "e.h" +#include "e_mod_main.h" +#include "e_mod_config.h" +#include "e_mod_physics.h" + +struct _E_Config_Dialog_Data +{ + double delay; + double max_mass; + double gravity; + Eina_Bool ignore_fullscreen; + Eina_Bool ignore_maximized; +}; + +/* Protos */ +static void *_create_data(E_Config_Dialog *cfd); +static void _free_data(E_Config_Dialog *cfd, + E_Config_Dialog_Data *cfdata); +static Evas_Object *_basic_create_widgets(E_Config_Dialog *cfd, + Evas *evas, + E_Config_Dialog_Data *cfdata); +static int _basic_apply_data(E_Config_Dialog *cfd, + E_Config_Dialog_Data *cfdata); + +E_Config_Dialog * +e_int_config_physics_module(E_Container *con, + const char *params __UNUSED__) +{ + E_Config_Dialog *cfd; + E_Config_Dialog_View *v; + char buf[4096]; + Mod *mod = _physics_mod; + + if (e_config_dialog_find("E", "appearance/physics")) return NULL; + v = E_NEW(E_Config_Dialog_View, 1); + + v->create_cfdata = _create_data; + v->free_cfdata = _free_data; + v->basic.apply_cfdata = _basic_apply_data; + v->basic.create_widgets = _basic_create_widgets; + + cfd = e_config_dialog_new(con, _("Physics Settings"), + "E", "appearance/physics", buf, 0, v, mod); + mod->config_dialog = cfd; + return cfd; +} + +static void * +_create_data(E_Config_Dialog *cfd __UNUSED__) +{ + E_Config_Dialog_Data *cfdata; + + cfdata = E_NEW(E_Config_Dialog_Data, 1); + + cfdata->delay = _physics_mod->conf->delay; + cfdata->max_mass = _physics_mod->conf->max_mass; + + return cfdata; +} + +static void +_free_data(E_Config_Dialog *cfd __UNUSED__, + E_Config_Dialog_Data *cfdata) +{ + _physics_mod->config_dialog = NULL; + free(cfdata); +} + +static Evas_Object * +_basic_create_widgets(E_Config_Dialog *cfd, + Evas *evas, + E_Config_Dialog_Data *cfdata) +{ + Evas_Object *ob, *ol, *otb, *tab; + + tab = e_widget_table_add(evas, 0); + evas_object_name_set(tab, "dia_table"); + + otb = e_widget_toolbook_add(evas, 48 * e_scale, 48 * e_scale); + + /////////////////////////////////////////// + + ol = e_widget_list_add(evas, 0, 0); + ob = e_widget_label_add(evas, _("Physics delay after drag")); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_slider_add(evas, 1, 0, _("%2.0f Frames"), 5, 20, 1, 0, &(cfdata->delay), NULL, 150); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_label_add(evas, _("Maximum window mass")); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_slider_add(evas, 1, 0, _("%2.1f Kg"), 1, 6, 1, 0, &(cfdata->max_mass), NULL, 150); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_label_add(evas, _("Desktop gravity")); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + ob = e_widget_slider_add(evas, 1, 0, _("%1.1f m/s^2"), -5, 5, 1, 0, &(cfdata->gravity), NULL, 150); + e_widget_list_object_append(ol, ob, 1, 1, 0.5); + + e_widget_toolbook_page_append(otb, NULL, _("General"), ol, 1, 1, 1, 1, 0.5, 0.5); + + /////////////////////////////////////////// + + ol = e_widget_list_add(evas, 0, 0); + ob = e_widget_check_add(evas, _("Ignore Fullscreen"), (int*)&(cfdata->ignore_fullscreen)); + e_widget_list_object_append(ol, ob, 1, 0, 0.5); + + ob = e_widget_check_add(evas, _("Ignore Maximized"), (int*)&(cfdata->ignore_maximized)); + e_widget_list_object_append(ol, ob, 1, 0, 0.5); + + e_widget_toolbook_page_append(otb, NULL, _("Ignore"), ol, 1, 1, 1, 1, 0.5, 0.5); + + e_widget_toolbook_page_show(otb, 0); + + e_dialog_resizable_set(cfd->dia, 1); + + e_widget_table_object_append(tab, otb, 0, 0, 1, 1, 1, 1, 1, 1); + return tab; +} + + +static int +_basic_apply_data(E_Config_Dialog *cfd __UNUSED__, + E_Config_Dialog_Data *cfdata) +{ + if ((cfdata->delay != _physics_mod->conf->delay) || + (cfdata->max_mass != _physics_mod->conf->max_mass) || + (cfdata->ignore_fullscreen != _physics_mod->conf->ignore_fullscreen) || + (cfdata->ignore_maximized != _physics_mod->conf->ignore_maximized) || + (cfdata->gravity != _physics_mod->conf->gravity) + ) + { +#define SET(X) _physics_mod->conf->X = cfdata->X + _physics_mod->conf->delay = (unsigned int)cfdata->delay; + SET(max_mass); + SET(ignore_fullscreen); + SET(ignore_maximized); + SET(gravity); + e_mod_physics_shutdown(); + e_mod_physics_init(); + } + e_config_save_queue(); + return 1; +} + diff --git a/src/modules/physics/e_mod_config.h b/src/modules/physics/e_mod_config.h new file mode 100644 index 000000000..248d3c67e --- /dev/null +++ b/src/modules/physics/e_mod_config.h @@ -0,0 +1,8 @@ +#ifdef E_TYPEDEFS +#else +#ifndef E_MOD_CONFIG_H +#define E_MOD_CONFIG_H +E_Config_Dialog *e_int_config_physics_module(E_Container *con, + const char *params __UNUSED__); +#endif +#endif diff --git a/src/modules/physics/e_mod_main.c b/src/modules/physics/e_mod_main.c new file mode 100644 index 000000000..ca6dd4042 --- /dev/null +++ b/src/modules/physics/e_mod_main.c @@ -0,0 +1,101 @@ +#include "e.h" +#include "e_mod_main.h" +#include "e_mod_physics.h" +#include "e_mod_config.h" +#include + +/* module private routines */ +Mod *_physics_mod = NULL; + +/* public module routines. all modules must have these */ +EAPI E_Module_Api e_modapi = +{ + E_MODULE_API_VERSION, + "Physics" +}; + +EAPI void * +e_modapi_init(E_Module *m) +{ + Mod *mod; + char buf[4096]; + + if (!ephysics_init()) return NULL; + mod = calloc(1, sizeof(Mod)); + m->data = mod; + + mod->module = m; + + snprintf(buf, sizeof(buf), "%s/e-module-physics.edj", e_module_dir_get(m)); + e_configure_registry_category_add("appearance", 10, _("Look"), NULL, + "preferences-look"); + e_configure_registry_item_add("appearance/physics", 120, _("Physics"), NULL, + buf, e_int_config_physics_module); + mod->conf_edd = e_mod_physics_cfdata_edd_init(); + + mod->conf = e_config_domain_load("module.physics", mod->conf_edd); + if (!mod->conf) _e_mod_config_new(m); + _physics_mod = mod; + + if (!e_mod_physics_init()) + { + e_util_dialog_internal(_("Physics Error"), _("The physics module could not be started")); + e_modapi_shutdown(mod->module); + return NULL; + } + + e_module_delayed_set(m, 0); + e_module_priority_set(m, -1000); + return mod; +} + +void +_e_mod_config_new(E_Module *m) +{ + Mod *mod = m->data; + + mod->conf = e_mod_physics_cfdata_config_new(); +} + +void +_e_mod_config_free(E_Module *m) +{ + Mod *mod = m->data; + + e_mod_cfdata_config_free(mod->conf); + mod->conf = NULL; +} + +EAPI int +e_modapi_shutdown(E_Module *m) +{ + Mod *mod = m->data; + + e_mod_physics_shutdown(); + + e_configure_registry_item_del("appearance/physics"); + e_configure_registry_category_del("appearance"); + + if (mod->config_dialog) + { + e_object_del(E_OBJECT(mod->config_dialog)); + mod->config_dialog = NULL; + } + _e_mod_config_free(m); + + E_CONFIG_DD_FREE(mod->conf_edd); + free(mod); + + if (mod == _physics_mod) _physics_mod = NULL; + + return 1; +} + +EAPI int +e_modapi_save(E_Module *m) +{ + Mod *mod = m->data; + e_config_domain_save("module.physics", mod->conf_edd, mod->conf); + return 1; +} + diff --git a/src/modules/physics/e_mod_main.h b/src/modules/physics/e_mod_main.h new file mode 100644 index 000000000..7558e3028 --- /dev/null +++ b/src/modules/physics/e_mod_main.h @@ -0,0 +1,31 @@ +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H + +#include "e_mod_physics_cfdata.h" + +typedef struct _Mod Mod; + +struct _Mod +{ + E_Module *module; + + E_Config_DD *conf_edd; + E_Config_DD *conf_match_edd; + Config *conf; + + E_Config_Dialog *config_dialog; +}; + +extern Mod *_physics_mod; + +EAPI extern E_Module_Api e_modapi; + +EAPI void *e_modapi_init(E_Module *m); +EAPI int e_modapi_shutdown(E_Module *m); +EAPI int e_modapi_save(E_Module *m); +EAPI int e_modapi_info(E_Module *m); + +void _e_mod_config_new(E_Module *m); +void _e_mod_config_free(E_Module *m); + +#endif diff --git a/src/modules/physics/e_mod_physics.c b/src/modules/physics/e_mod_physics.c new file mode 100644 index 000000000..279003542 --- /dev/null +++ b/src/modules/physics/e_mod_physics.c @@ -0,0 +1,815 @@ +#include "e.h" +#include "e_mod_main.h" +#include "e_mod_physics.h" +#include + +struct _E_Physics +{ + EPhysics_World *world; + Ecore_X_Window win; + E_Manager *man; + Eina_Inlist *wins; +}; + +struct _E_Physics_Win +{ + EINA_INLIST; + + E_Physics *p; // parent compositor + Ecore_X_Window win; // raw window - for menus etc. + E_Border *bd; // if its a border - later + E_Popup *pop; // if its a popup - later + E_Menu *menu; // if it is a menu - later + 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_Object_Delfn *dfn; // delete function handle for objects being tracked + + 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 1 +#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); +/* TODO +static void +_e_mod_physics_fps_update(E_Physics *p) +{ + if (_comp_mod->conf->fps_show) + { + if (!p->fps_bg) + { + p->fps_bg = evas_object_rectangle_add(p->evas); + evas_object_color_set(p->fps_bg, 0, 0, 0, 128); + evas_object_layer_set(p->fps_bg, EVAS_LAYER_MAX); + evas_object_show(p->fps_bg); + + p->fps_fg = evas_object_text_add(p->evas); + evas_object_text_font_set(p->fps_fg, "Sans", 10); + evas_object_text_text_set(p->fps_fg, "???"); + evas_object_color_set(p->fps_fg, 255, 255, 255, 255); + evas_object_layer_set(p->fps_fg, EVAS_LAYER_MAX); + evas_object_show(p->fps_fg); + } + } + else + { + if (p->fps_fg) + { + evas_object_del(p->fps_fg); + p->fps_fg = NULL; + } + if (p->fps_bg) + { + evas_object_del(p->fps_bg); + p->fps_bg = NULL; + } + } +} +*/ + + +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_rotation_on_z_axis_enable_set(pw->body, 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); + 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) +{ + if (pw->dfn) + { + eina_hash_del(borders, e_util_winid_str_get(pw->bd->client.win), pw); + e_object_delfn_del(E_OBJECT(pw->bd), pw->dfn); + pw->bd = NULL; + pw->dfn = NULL; + } + e_border_move_intercept_cb_set(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; + + 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, w, border + h); + pw->show_ready = 1; + } +} + + +////////////////////////////////////////////////////////////////////////// + + +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)); + } + +out: + 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; +} + +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; +} + +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, p->man->w, p->man->h); + 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_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; + + 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, man->w, man->h); + ephysics_world_gravity_set(p->world, 0, _physics_mod->conf->gravity); + + 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); + } + + return p; +} + +static void +_e_mod_physics_del(E_Physics *p) +{ + E_Physics_Win *pw; + + while (p->wins) + { + pw = (E_Physics_Win *)(p->wins); + _e_mod_physics_win_del(pw); + } + 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); + 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); + +// handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_X_EVENT_WINDOW_REPARENT, _e_mod_physics_reparent, NULL)); + handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_X_EVENT_WINDOW_CONFIGURE, _e_mod_physics_configure, NULL)); + //handlers = eina_list_append(handlers, ecore_event_handler_add(ECORE_X_EVENT_WINDOW_STACK, _e_mod_physics_stack, NULL)); + + if (_physics_mod->conf->ignore_maximized) + handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_PROPERTY, _e_mod_physics_bd_property, NULL)); + if (_physics_mod->conf->ignore_fullscreen) + { + handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_FULLSCREEN, _e_mod_physics_bd_fullscreen, NULL)); + handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_UNFULLSCREEN, _e_mod_physics_bd_fullscreen, NULL)); + } + handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_CONTAINER_RESIZE, _e_mod_physics_randr, NULL)); + + handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_ADD, _e_mod_physics_bd_add, NULL)); + handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_REMOVE, _e_mod_physics_bd_del, NULL)); + handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_SHOW, _e_mod_physics_bd_show, NULL)); + handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_HIDE, _e_mod_physics_bd_hide, NULL)); +// handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_MOVE, _e_mod_physics_bd_move, NULL)); + handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_RESIZE, _e_mod_physics_bd_resize, NULL)); +#if 0 + handlers = eina_list_append(handlers, ecore_event_handler_add(E_EVENT_BORDER_ICONIFY, _e_mod_physics_bd_iconify, NULL)); + handlers = eina_list_append(handlers, ecore_event_handler_add(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_Physics *p; + + EINA_LIST_FREE (physicists, p) + _e_mod_physics_del(p); + + E_FREE_LIST(handlers, ecore_event_handler_del); + + if (borders) eina_hash_free(borders); + borders = NULL; +} + diff --git a/src/modules/physics/e_mod_physics.h b/src/modules/physics/e_mod_physics.h new file mode 100644 index 000000000..468ecdb73 --- /dev/null +++ b/src/modules/physics/e_mod_physics.h @@ -0,0 +1,14 @@ +#ifdef E_TYPEDEFS +#else +#ifndef E_MOD_PHYSICS_H +#define E_MOD_PHYSICS_H + +typedef struct _E_Physics E_Physics; +typedef struct _E_Physics_Win E_Physics_Win; + +void e_mod_physics_mass_update(void); +Eina_Bool e_mod_physics_init(void); +void e_mod_physics_shutdown(void); + +#endif +#endif diff --git a/src/modules/physics/e_mod_physics_cfdata.c b/src/modules/physics/e_mod_physics_cfdata.c new file mode 100644 index 000000000..95f83a236 --- /dev/null +++ b/src/modules/physics/e_mod_physics_cfdata.c @@ -0,0 +1,43 @@ +#include "e.h" +#include "e_mod_main.h" +#include "e_mod_physics_cfdata.h" + +EAPI E_Config_DD * +e_mod_physics_cfdata_edd_init(void) +{ + E_Config_DD *conf_edd; + + conf_edd = E_CONFIG_DD_NEW("Physics_Config", Config); +#undef T +#undef D +#define T Config +#define D conf_edd + E_CONFIG_VAL(D, T, delay, UINT); + E_CONFIG_VAL(D, T, max_mass, DOUBLE); + E_CONFIG_VAL(D, T, gravity, DOUBLE); + E_CONFIG_VAL(D, T, ignore_fullscreen, UCHAR); + E_CONFIG_VAL(D, T, ignore_maximized, UCHAR); + return conf_edd; +} + +EAPI Config * +e_mod_physics_cfdata_config_new(void) +{ + Config *cfg; + + cfg = E_NEW(Config, 1); + cfg->delay = 10; + cfg->max_mass = 3.0; + cfg->gravity = 0.0; + cfg->ignore_fullscreen = EINA_TRUE; + cfg->ignore_maximized = EINA_TRUE; + + return cfg; +} + +EAPI void +e_mod_cfdata_config_free(Config *cfg) +{ + free(cfg); +} + diff --git a/src/modules/physics/e_mod_physics_cfdata.h b/src/modules/physics/e_mod_physics_cfdata.h new file mode 100644 index 000000000..19883b50b --- /dev/null +++ b/src/modules/physics/e_mod_physics_cfdata.h @@ -0,0 +1,19 @@ +#ifndef E_MOD_PHYSICS_CFDATA_H +#define E_MOD_PHYSICS_CFDATA_H + +typedef struct _Config Config; + +struct _Config +{ + unsigned int delay; /* delay before applying physics */ + double max_mass; /* maximum mass for a window */ + double gravity; /* maximum mass for a window */ + Eina_Bool ignore_fullscreen; + Eina_Bool ignore_maximized; +}; + +EAPI E_Config_DD *e_mod_physics_cfdata_edd_init(void); +EAPI Config *e_mod_physics_cfdata_config_new(void); +EAPI void e_mod_cfdata_config_free(Config *cfg); + +#endif diff --git a/src/modules/physics/module.desktop.in b/src/modules/physics/module.desktop.in new file mode 100644 index 000000000..10f8ac87e --- /dev/null +++ b/src/modules/physics/module.desktop.in @@ -0,0 +1,6 @@ +[Desktop Entry] +Type=Link +Name=Physics +Icon=e-module-physics +Comment=Enlightenment Physics Professor +X-Enlightenment-ModuleType=look