diff --git a/Makefile.am b/Makefile.am index a52b50e..34250a9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -24,6 +24,7 @@ glow_top.png include src/Makefile.mk +include src/gadgets/Makefile.mk e-module-desksanity.edj: e-module-desksanity.edc $(EDJE_CC) -id $(top_srcdir) $< $@ diff --git a/src/e_mod_main.c b/src/e_mod_main.c index 449d653..b4be099 100644 --- a/src/e_mod_main.c +++ b/src/e_mod_main.c @@ -1,4 +1,10 @@ #include "e_mod_main.h" +#include "gadget.h" + +EINTERN Evas_Object * +start_create(Evas_Object *parent, unsigned int *id EINA_UNUSED); +EINTERN void +gadget_demo(void); EAPI E_Module_Api e_modapi = {E_MODULE_API_VERSION, "Desksanity"}; static E_Config_DD *conf_edd = NULL; @@ -268,6 +274,9 @@ e_modapi_init(E_Module *m) e_action_predef_name_set(D_("Desksanity"), D_("Manage Window Focus For Me"), "ds_key", NULL, NULL, 0); act->func.go = ds_key; + z_gadget_type_add("Start", start_create); + gadget_demo(); + return m; } @@ -297,6 +306,8 @@ e_modapi_shutdown(E_Module *m EINA_UNUSED) E_FREE_FUNC(ds_key_focus_timeout, ecore_timer_del); E_FREE_LIST(ds_key_focus_desks, e_object_unref); //efx_shutdown(); broken... + + z_gadget_type_del("Start"); return 1; } diff --git a/src/gadgets/Makefile.mk b/src/gadgets/Makefile.mk new file mode 100644 index 0000000..2d9639f --- /dev/null +++ b/src/gadgets/Makefile.mk @@ -0,0 +1,8 @@ +AM_CPPFLAGS += \ +-Isrc/gadgets + +module_la_SOURCES += \ +src/gadgets/core.c \ +src/gadgets/demo.c \ +src/gadgets/gadget.h \ +src/gadgets/start/start.c diff --git a/src/gadgets/clock/clock.c b/src/gadgets/clock/clock.c new file mode 100644 index 0000000..3462812 --- /dev/null +++ b/src/gadgets/clock/clock.c @@ -0,0 +1,554 @@ +#include "e.h" +#include "clock.h" + +/* actual module specifics */ +typedef struct _Instance Instance; + +struct _Instance +{ + E_Gadcon_Client *gcc; + Evas_Object *o_clock, *o_table, *o_popclock, *o_cal; + E_Gadcon_Popup *popup; + + int madj; + + char year[8]; + char month[64]; + const char *daynames[7]; + unsigned char daynums[7][6]; + Eina_Bool dayweekends[7][6]; + Eina_Bool dayvalids[7][6]; + Eina_Bool daytoday[7][6]; + Config_Item *cfg; +}; + +/* gadcon requirements */ +static E_Gadcon_Client *_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style); +static void _gc_shutdown(E_Gadcon_Client *gcc); +static void _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient); +static const char *_gc_label(const E_Gadcon_Client_Class *client_class); +static Evas_Object *_gc_icon(const E_Gadcon_Client_Class *client_class, Evas *evas); +static const char *_gc_id_new(const E_Gadcon_Client_Class *client_class); +static Config_Item *_conf_item_get(const char *id); +static void _clock_popup_free(Instance *inst); + +Config *clock_config = NULL; + +static E_Config_DD *conf_edd = NULL; +static E_Config_DD *conf_item_edd = NULL; +static Eina_List *clock_instances = NULL; +static E_Action *act = NULL; + +/* and actually define the gadcon class that this module provides (just 1) */ +static const E_Gadcon_Client_Class _gadcon_class = +{ + GADCON_CLIENT_CLASS_VERSION, + "clock", + { + _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL, NULL + }, + E_GADCON_CLIENT_STYLE_PLAIN +}; + + +static void +_clock_month_update(Instance *inst) +{ + Evas_Object *od, *oi; + int x, y; + + oi = elm_layout_edje_get(inst->o_cal); + edje_object_part_text_set(oi, "e.text.month", inst->month); + edje_object_part_text_set(oi, "e.text.year", inst->year); + for (x = 0; x < 7; x++) + { + od = edje_object_part_table_child_get(oi, "e.table.daynames", x, 0); + edje_object_part_text_set(od, "e.text.label", inst->daynames[x]); + edje_object_message_signal_process(od); + if (inst->dayweekends[x][0]) + edje_object_signal_emit(od, "e,state,weekend", "e"); + else + edje_object_signal_emit(od, "e,state,weekday", "e"); + } + + for (y = 0; y < 6; y++) + { + for (x = 0; x < 7; x++) + { + char buf[32]; + + od = edje_object_part_table_child_get(oi, "e.table.days", x, y); + snprintf(buf, sizeof(buf), "%i", (int)inst->daynums[x][y]); + edje_object_part_text_set(od, "e.text.label", buf); + if (inst->dayweekends[x][y]) + edje_object_signal_emit(od, "e,state,weekend", "e"); + else + edje_object_signal_emit(od, "e,state,weekday", "e"); + if (inst->dayvalids[x][y]) + edje_object_signal_emit(od, "e,state,visible", "e"); + else + edje_object_signal_emit(od, "e,state,hidden", "e"); + if (inst->daytoday[x][y]) + edje_object_signal_emit(od, "e,state,today", "e"); + else + edje_object_signal_emit(od, "e,state,someday", "e"); + edje_object_message_signal_process(od); + } + } + edje_object_message_signal_process(oi); +} + +static void +_clock_month_prev_cb(void *data, Evas_Object *obj EINA_UNUSED, const char *emission EINA_UNUSED, const char *source EINA_UNUSED) +{ + Instance *inst = data; + inst->madj--; + _time_eval(inst); + _clock_month_update(inst); +} + +static void +_clock_month_next_cb(void *data, Evas_Object *obj EINA_UNUSED, const char *emission EINA_UNUSED, const char *source EINA_UNUSED) +{ + Instance *inst = data; + inst->madj++; + _time_eval(inst); + _clock_month_update(inst); +} + +static void +_clock_settings_cb(void *d1, void *d2 EINA_UNUSED) +{ + Instance *inst = d1; + e_int_config_clock_module(NULL, inst->cfg); + e_object_del(E_OBJECT(inst->popup)); + inst->popup = NULL; + inst->o_popclock = NULL; +} + +static void +_popclock_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED) +{ + Instance *inst = data; + if (inst->o_popclock == obj) + { + inst->o_popclock = NULL; + } +} + +static void +_clock_popup_new(Instance *inst) +{ + Evas *evas; + Evas_Object *o, *oi; + char todaystr[128]; + + if (inst->popup) return; + + _todaystr_eval(inst, todaystr, sizeof(todaystr) - 1); + + inst->madj = 0; + + _time_eval(inst); + + inst->popup = e_gadcon_popup_new(inst->gcc, 0); + evas = e_comp->evas; + + inst->o_table = elm_table_add(e_comp->elm); + + oi = elm_layout_add(inst->o_table); + inst->o_popclock = oi; + evas_object_size_hint_weight_set(oi, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(oi, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_event_callback_add(oi, EVAS_CALLBACK_DEL, _popclock_del_cb, inst); + + if (inst->cfg->digital_clock) + e_theme_edje_object_set(oi, "base/theme/modules/clock", + "e/modules/clock/digital"); + else + e_theme_edje_object_set(oi, "base/theme/modules/clock", + "e/modules/clock/main"); + if (inst->cfg->show_date) + elm_object_signal_emit(oi, "e,state,date,on", "e"); + else + elm_object_signal_emit(oi, "e,state,date,off", "e"); + if (inst->cfg->digital_24h) + elm_object_signal_emit(oi, "e,state,24h,on", "e"); + else + elm_object_signal_emit(oi, "e,state,24h,off", "e"); + if (inst->cfg->show_seconds) + elm_object_signal_emit(oi, "e,state,seconds,on", "e"); + else + elm_object_signal_emit(oi, "e,state,seconds,off", "e"); + + elm_object_part_text_set(oi, "e.text.today", todaystr); + + elm_layout_sizing_eval(oi); + elm_table_pack(inst->o_table, oi, 0, 0, 1, 1); + evas_object_show(oi); + + o = evas_object_rectangle_add(evas); + evas_object_size_hint_min_set(o, 80 * e_scale, 80 * e_scale); + elm_table_pack(inst->o_table, o, 0, 0, 1, 1); + + o = e_widget_button_add(evas, _("Settings"), "preferences-system", + _clock_settings_cb, inst, NULL); + elm_table_pack(inst->o_table, o, 0, 2, 1, 1); + evas_object_show(o); + + oi = elm_layout_add(inst->o_table); + inst->o_cal = oi; + e_theme_edje_object_set(oi, "base/theme/modules/clock", + "e/modules/clock/calendar"); + _clock_month_update(inst); + + elm_object_signal_callback_add(oi, "e,action,prev", "*", + _clock_month_prev_cb, inst); + elm_object_signal_callback_add(oi, "e,action,next", "*", + _clock_month_next_cb, inst); + edje_object_message_signal_process(elm_layout_edje_get(oi)); + elm_layout_sizing_eval(oi); + elm_table_pack(inst->o_table, oi, 0, 1, 1, 1); + evas_object_show(oi); + + evas_smart_objects_calculate(evas); + e_gadcon_popup_content_set(inst->popup, inst->o_table); + e_gadcon_popup_show(inst->popup); +} + +static void +_eval_instance_size(Instance *inst) +{ + Evas_Coord mw, mh, omw, omh; + + edje_object_size_min_get(inst->o_clock, &mw, &mh); + omw = mw; + omh = mh; + + if ((mw < 1) || (mh < 1)) + { + Evas_Coord x, y, sw = 0, sh = 0, ow, oh; + Eina_Bool horiz; + const char *orient; + + switch (inst->gcc->gadcon->orient) + { + case E_GADCON_ORIENT_TOP: + case E_GADCON_ORIENT_CORNER_TL: + case E_GADCON_ORIENT_CORNER_TR: + case E_GADCON_ORIENT_BOTTOM: + case E_GADCON_ORIENT_CORNER_BL: + case E_GADCON_ORIENT_CORNER_BR: + case E_GADCON_ORIENT_HORIZ: + horiz = EINA_TRUE; + orient = "e,state,horizontal"; + break; + + case E_GADCON_ORIENT_LEFT: + case E_GADCON_ORIENT_CORNER_LB: + case E_GADCON_ORIENT_CORNER_LT: + case E_GADCON_ORIENT_RIGHT: + case E_GADCON_ORIENT_CORNER_RB: + case E_GADCON_ORIENT_CORNER_RT: + case E_GADCON_ORIENT_VERT: + horiz = EINA_FALSE; + orient = "e,state,vertical"; + break; + + default: + horiz = EINA_TRUE; + orient = "e,state,float"; + } + + if (inst->gcc->gadcon->shelf) + { + if (horiz) + sh = inst->gcc->gadcon->shelf->h; + else + sw = inst->gcc->gadcon->shelf->w; + } + + evas_object_geometry_get(inst->o_clock, NULL, NULL, &ow, &oh); + if (orient) + edje_object_signal_emit(inst->o_clock, orient, "e"); + evas_object_resize(inst->o_clock, sw, sh); + edje_object_message_signal_process(inst->o_clock); + + edje_object_parts_extends_calc(inst->o_clock, &x, &y, &mw, &mh); + evas_object_resize(inst->o_clock, ow, oh); + } + + if (mw < 4) mw = 4; + if (mh < 4) mh = 4; + + if (mw < omw) mw = omw; + if (mh < omh) mh = omh; + + e_gadcon_client_aspect_set(inst->gcc, mw, mh); + e_gadcon_client_min_size_set(inst->gcc, mw, mh); +} + +void +e_int_clock_instances_redo(Eina_Bool all) +{ + Eina_List *l; + Instance *inst; + char todaystr[128]; + + EINA_LIST_FOREACH(clock_instances, l, inst) + { + Evas_Object *o = inst->o_clock; + + if ((!all) && (!inst->cfg->changed)) continue; + _todaystr_eval(inst, todaystr, sizeof(todaystr) - 1); + if (inst->cfg->digital_clock) + e_theme_edje_object_set(o, "base/theme/modules/clock", + "e/modules/clock/digital"); + else + e_theme_edje_object_set(o, "base/theme/modules/clock", + "e/modules/clock/main"); + if (inst->cfg->show_date) + edje_object_signal_emit(o, "e,state,date,on", "e"); + else + edje_object_signal_emit(o, "e,state,date,off", "e"); + if (inst->cfg->digital_24h) + edje_object_signal_emit(o, "e,state,24h,on", "e"); + else + edje_object_signal_emit(o, "e,state,24h,off", "e"); + if (inst->cfg->show_seconds) + edje_object_signal_emit(o, "e,state,seconds,on", "e"); + else + edje_object_signal_emit(o, "e,state,seconds,off", "e"); + + edje_object_part_text_set(o, "e.text.today", todaystr); + edje_object_message_signal_process(o); + _eval_instance_size(inst); + + if (inst->o_popclock) + { + o = inst->o_popclock; + + if (inst->cfg->digital_clock) + e_theme_edje_object_set(o, "base/theme/modules/clock", + "e/modules/clock/digital"); + else + e_theme_edje_object_set(o, "base/theme/modules/clock", + "e/modules/clock/main"); + if (inst->cfg->show_date) + edje_object_signal_emit(o, "e,state,date,on", "e"); + else + edje_object_signal_emit(o, "e,state,date,off", "e"); + if (inst->cfg->digital_24h) + edje_object_signal_emit(o, "e,state,24h,on", "e"); + else + edje_object_signal_emit(o, "e,state,24h,off", "e"); + if (inst->cfg->show_seconds) + edje_object_signal_emit(o, "e,state,seconds,on", "e"); + else + edje_object_signal_emit(o, "e,state,seconds,off", "e"); + + edje_object_part_text_set(o, "e.text.today", todaystr); + edje_object_message_signal_process(o); + } + } +} + + +static void +_clock_popup_free(Instance *inst) +{ + if (!inst->popup) return; + E_FREE_FUNC(inst->popup, e_object_del); + inst->o_popclock = NULL; +} + +static void +_clock_menu_cb_cfg(void *data, E_Menu *menu EINA_UNUSED, E_Menu_Item *mi EINA_UNUSED) +{ + Instance *inst = data; + + E_FREE_FUNC(inst->popup, e_object_del); + e_int_config_clock_module(NULL, inst->cfg); +} + +static void +_clock_cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) +{ + Instance *inst = data; + Evas_Event_Mouse_Down *ev = event; + + if (ev->button == 1) + { + if (inst->popup) _clock_popup_free(inst); + else _clock_popup_new(inst); + } + else if (ev->button == 3) + { + E_Zone *zone; + E_Menu *m; + E_Menu_Item *mi; + int x, y; + + zone = e_zone_current_get(); + + m = e_menu_new(); + + mi = e_menu_item_new(m); + e_menu_item_label_set(mi, _("Settings")); + e_util_menu_item_theme_icon_set(mi, "configure"); + e_menu_item_callback_set(mi, _clock_menu_cb_cfg, inst); + + m = e_gadcon_client_util_menu_items_append(inst->gcc, m, 0); + + e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &x, &y, NULL, NULL); + e_menu_activate_mouse(m, zone, x + ev->output.x, y + ev->output.y, + 1, 1, E_MENU_POP_DIRECTION_AUTO, ev->timestamp); + evas_event_feed_mouse_up(inst->gcc->gadcon->evas, ev->button, + EVAS_BUTTON_NONE, ev->timestamp, NULL); + } +} + +static void +_clock_sizing_changed_cb(void *data, Evas_Object *obj EINA_UNUSED, const char *emission EINA_UNUSED, const char *source EINA_UNUSED) +{ + _eval_instance_size(data); +} + +static E_Gadcon_Client * +_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style) +{ + Evas_Object *o; + E_Gadcon_Client *gcc; + Instance *inst; + char todaystr[128]; + + inst = E_NEW(Instance, 1); + inst->cfg = _conf_item_get(id); + + _todaystr_eval(inst, todaystr, sizeof(todaystr) - 1); + + o = edje_object_add(gc->evas); + edje_object_signal_callback_add(o, "e,state,sizing,changed", "*", + _clock_sizing_changed_cb, inst); + if (inst->cfg->digital_clock) + e_theme_edje_object_set(o, "base/theme/modules/clock", + "e/modules/clock/digital"); + else + e_theme_edje_object_set(o, "base/theme/modules/clock", + "e/modules/clock/main"); + if (inst->cfg->show_date) + edje_object_signal_emit(o, "e,state,date,on", "e"); + else + edje_object_signal_emit(o, "e,state,date,off", "e"); + if (inst->cfg->digital_24h) + edje_object_signal_emit(o, "e,state,24h,on", "e"); + else + edje_object_signal_emit(o, "e,state,24h,off", "e"); + if (inst->cfg->show_seconds) + edje_object_signal_emit(o, "e,state,seconds,on", "e"); + else + edje_object_signal_emit(o, "e,state,seconds,off", "e"); + + edje_object_part_text_set(o, "e.text.today", todaystr); + edje_object_message_signal_process(o); + evas_object_show(o); + + gcc = e_gadcon_client_new(gc, name, id, style, o); + gcc->data = inst; + + inst->gcc = gcc; + inst->o_clock = o; + + evas_object_event_callback_add(inst->o_clock, + EVAS_CALLBACK_MOUSE_DOWN, + _clock_cb_mouse_down, + inst); + + clock_instances = eina_list_append(clock_instances, inst); + + + + return gcc; +} + +static void +_gc_shutdown(E_Gadcon_Client *gcc) +{ + Instance *inst; + + inst = gcc->data; + clock_instances = eina_list_remove(clock_instances, inst); + evas_object_del(inst->o_clock); + _clock_popup_free(inst); + _clear_timestrs(inst); + free(inst); + + if ((!clock_instances) && (update_today)) + { + ecore_timer_del(update_today); + update_today = NULL; + } +} + +static void +_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient EINA_UNUSED) +{ + _eval_instance_size(gcc->data); +} + +static const char * +_gc_label(const E_Gadcon_Client_Class *client_class EINA_UNUSED) +{ + return _("Clock"); +} + +static Evas_Object * +_gc_icon(const E_Gadcon_Client_Class *client_class EINA_UNUSED, Evas *evas) +{ + Evas_Object *o; + char buf[4096]; + + o = edje_object_add(evas); + snprintf(buf, sizeof(buf), "%s/e-module-clock.edj", + e_module_dir_get(clock_config->module)); + edje_object_file_set(o, buf, "icon"); + return o; +} + +static const char * +_gc_id_new(const E_Gadcon_Client_Class *client_class EINA_UNUSED) +{ + Config_Item *ci = NULL; + + ci = _conf_item_get(NULL); + return ci->id; +} + +static Config_Item * +_conf_item_get(const char *id) +{ + Config_Item *ci; + + GADCON_CLIENT_CONFIG_GET(Config_Item, clock_config->items, _gadcon_class, id); + + ci = E_NEW(Config_Item, 1); + ci->id = eina_stringshare_add(id); + ci->weekend.start = 6; + ci->weekend.len = 2; + ci->week.start = 1; + ci->digital_clock = 1; + ci->digital_24h = 0; + ci->show_seconds = 0; + ci->show_date = 0; + + clock_config->items = eina_list_append(clock_config->items, ci); + e_config_save_queue(); + + return ci; +} + +EINTERN Evas_Object * +clock_create(Evas_Object *parent, unsigned int *id) +{ + +} diff --git a/src/gadgets/clock/clock.h b/src/gadgets/clock/clock.h new file mode 100644 index 0000000..362ddfd --- /dev/null +++ b/src/gadgets/clock/clock.h @@ -0,0 +1,42 @@ +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H + +E_API extern E_Module_Api e_modapi; + +E_API void *e_modapi_init (E_Module *m); +E_API int e_modapi_shutdown (E_Module *m); +E_API int e_modapi_save (E_Module *m); + +typedef struct _Config Config; +typedef struct _Config_Item Config_Item; + +struct _Config +{ + Eina_List *items; + + E_Module *module; + E_Config_Dialog *config_dialog; +}; + +struct _Config_Item +{ + const char *id; + struct { + int start, len; // 0->6 0 == sun, 6 == sat, number of days + } weekend; + struct { + int start; // 0->6 0 == sun, 6 == sat + } week; + int digital_clock; + int digital_24h; + int show_seconds; + int show_date; + Eina_Bool changed; +}; + +void e_int_config_clock_module(Evas_Object *parent, Config_Item *ci); +void e_int_clock_instances_redo(Eina_Bool all); + +extern Config *clock_config; + +#endif diff --git a/src/gadgets/clock/mod.c b/src/gadgets/clock/mod.c new file mode 100644 index 0000000..452fcd4 --- /dev/null +++ b/src/gadgets/clock/mod.c @@ -0,0 +1,122 @@ +#include "e.h" +#include "clock.h" + + +static void +_e_mod_action(const char *params) +{ + Eina_List *l; + Instance *inst; + + if (!params) return; + if (strcmp(params, "show_calendar")) return; + + EINA_LIST_FOREACH(clock_instances, l, inst) + if (inst->popup) + _clock_popup_free(inst); + else + _clock_popup_new(inst); +} + +static void +_e_mod_action_cb(E_Object *obj EINA_UNUSED, const char *params) +{ + _e_mod_action(params); +} + + +/* module setup */ +E_API E_Module_Api e_modapi = +{ + E_MODULE_API_VERSION, + "Clock" +}; + +E_API void * +e_modapi_init(E_Module *m) +{ + conf_item_edd = E_CONFIG_DD_NEW("Config_Item", Config_Item); +#undef T +#undef D +#define T Config_Item +#define D conf_item_edd + E_CONFIG_VAL(D, T, id, STR); + E_CONFIG_VAL(D, T, weekend.start, INT); + E_CONFIG_VAL(D, T, weekend.len, INT); + E_CONFIG_VAL(D, T, week.start, INT); + E_CONFIG_VAL(D, T, digital_clock, INT); + E_CONFIG_VAL(D, T, digital_24h, INT); + E_CONFIG_VAL(D, T, show_seconds, INT); + E_CONFIG_VAL(D, T, show_date, INT); + + conf_edd = E_CONFIG_DD_NEW("Config", Config); +#undef T +#undef D +#define T Config +#define D conf_edd + E_CONFIG_LIST(D, T, items, conf_item_edd); + + clock_config = e_config_domain_load("module.clock", conf_edd); + + if (!clock_config) + clock_config = E_NEW(Config, 1); + + act = e_action_add("clock"); + if (act) + { + act->func.go = _e_mod_action_cb; + act->func.go_key = _e_mod_action_cb; + act->func.go_mouse = _e_mod_action_cb; + act->func.go_edge = _e_mod_action_cb; + + e_action_predef_name_set(N_("Clock"), N_("Toggle calendar"), "clock", "show_calendar", NULL, 0); + } + + clock_config->module = m; + + z_gadget_type_add("clock", clock_create); + + return m; +} + +E_API int +e_modapi_shutdown(E_Module *m EINA_UNUSED) +{ + if (act) + { + e_action_predef_name_del("Clock", "Toggle calendar"); + e_action_del("clock"); + act = NULL; + } + if (clock_config) + { + Config_Item *ci; + + if (clock_config->config_dialog) + e_object_del(E_OBJECT(clock_config->config_dialog)); + + EINA_LIST_FREE(clock_config->items, ci) + { + eina_stringshare_del(ci->id); + free(ci); + } + + free(clock_config); + clock_config = NULL; + } + E_CONFIG_DD_FREE(conf_edd); + E_CONFIG_DD_FREE(conf_item_edd); + conf_item_edd = NULL; + conf_edd = NULL; + + e_gadcon_provider_unregister(&_gadcon_class); + + return 1; +} + +E_API int +e_modapi_save(E_Module *m EINA_UNUSED) +{ + e_config_domain_save("module.clock", conf_edd, clock_config); + return 1; +} diff --git a/src/gadgets/clock/time.c b/src/gadgets/clock/time.c new file mode 100644 index 0000000..561351e --- /dev/null +++ b/src/gadgets/clock/time.c @@ -0,0 +1,288 @@ +#include "e.h" +#include "clock.h" + +#include +#include + +static Eio_Monitor *clock_tz_monitor = NULL; +static Eio_Monitor *clock_tz2_monitor = NULL; +static Eio_Monitor *clock_tzetc_monitor = NULL; +static Eina_List *clock_eio_handlers = NULL; + +static Ecore_Timer *update_today = NULL; + +static void +_clear_timestrs(Instance *inst) +{ + int x; + + for (x = 0; x < 7; x++) + { + if (inst->daynames[x]) + { + eina_stringshare_del(inst->daynames[x]); + inst->daynames[x] = NULL; + } + } +} + +static void +_todaystr_eval(Instance *inst, char *buf, int bufsz) +{ + if (!inst->cfg->show_date) + { + buf[0] = 0; + } + else + { + struct timeval timev; + struct tm *tm; + time_t tt; + + tzset(); + gettimeofday(&timev, NULL); + tt = (time_t)(timev.tv_sec); + tm = localtime(&tt); + if (tm) + { + if (inst->cfg->show_date == 1) + strftime(buf, bufsz, _("%a, %e %b, %Y"), (const struct tm *)tm); + else if (inst->cfg->show_date == 2) + strftime(buf, bufsz, _("%a, %x"), (const struct tm *)tm); + else if (inst->cfg->show_date == 3) + strftime(buf, bufsz, "%x", (const struct tm *)tm); + else if (inst->cfg->show_date == 4) + strftime(buf, bufsz, "%F", (const struct tm *)tm); + } + else + buf[0] = 0; + } +} + + +static void +_time_eval(Instance *inst) +{ + struct timeval timev; + struct tm *tm, tms, tmm, tm2; + time_t tt; + int started = 0, num, i; + + tzset(); + gettimeofday(&timev, NULL); + tt = (time_t)(timev.tv_sec); + tm = localtime(&tt); + + _clear_timestrs(inst); + if (tm) + { + int day; + + // tms == current date time "saved" + // tm2 == date to look at adjusting for madj + // tm2 == month baseline @ 1st + memcpy(&tms, tm, sizeof(struct tm)); + num = 0; + for (day = (0 - 6); day < (31 + 16); day++) + { + memcpy(&tmm, &tms, sizeof(struct tm)); + tmm.tm_sec = 0; + tmm.tm_min = 0; + tmm.tm_hour = 10; + tmm.tm_mon += inst->madj; + tmm.tm_mday = 1; // start at the 1st of the month + tmm.tm_wday = 0; // ignored by mktime + tmm.tm_yday = 0; // ignored by mktime + tmm.tm_isdst = 0; // ignored by mktime + tt = mktime(&tmm); + tm = localtime(&tt); + memcpy(&tm2, tm, sizeof(struct tm)); + + tt = mktime(&tmm); + tt += (day * 60 * 60 * 24); + tm = localtime(&tt); + memcpy(&tmm, tm, sizeof(struct tm)); + if (!started) + { + if (tm->tm_wday == inst->cfg->week.start) + { + char buf[32]; + + for (i = 0; i < 7; i++, tm->tm_wday = (tm->tm_wday + 1) % 7) + { + strftime(buf, sizeof(buf), "%a", tm); + inst->daynames[i] = eina_stringshare_add(buf); + } + started = 1; + } + } + if (started) + { + int y = num / 7; + int x = num % 7; + + if (y < 6) + { + inst->daynums[x][y] = tmm.tm_mday; + + inst->dayvalids[x][y] = 0; + if (tmm.tm_mon == tm2.tm_mon) inst->dayvalids[x][y] = 1; + + inst->daytoday[x][y] = 0; + if ((tmm.tm_mon == tms.tm_mon) && + (tmm.tm_year == tms.tm_year) && + (tmm.tm_mday == tms.tm_mday)) + inst->daytoday[x][y] = 1; + + inst->dayweekends[x][y] = 0; + for (i = inst->cfg->weekend.start; + i < (inst->cfg->weekend.start + inst->cfg->weekend.len); + i++) + { + if (tmm.tm_wday == (i % 7)) + { + inst->dayweekends[x][y] = 1; + break; + } + } + } + num++; + } + } + + memcpy(&tmm, &tms, sizeof(struct tm)); + tmm.tm_sec = 0; + tmm.tm_min = 0; + tmm.tm_hour = 10; + tmm.tm_mon += inst->madj; + tmm.tm_mday = 1; // start at the 1st of the month + tmm.tm_wday = 0; // ignored by mktime + tmm.tm_yday = 0; // ignored by mktime + tmm.tm_isdst = 0; // ignored by mktime + tt = mktime(&tmm); + tm = localtime(&tt); + memcpy(&tm2, tm, sizeof(struct tm)); + inst->year[sizeof(inst->year) - 1] = 0; + strftime(inst->year, sizeof(inst->year) - 1, "%Y", (const struct tm *)&tm2); + inst->month[sizeof(inst->month) - 1] = 0; + strftime(inst->month, sizeof(inst->month) - 1, "%B", (const struct tm *)&tm2); // %b for short month + } +} + + +static Eina_Bool +_update_today_timer(void *data EINA_UNUSED) +{ + time_t t, t_tomorrow; + const struct tm *now; + struct tm today; + + t = time(NULL); + now = localtime(&t); + memcpy(&today, now, sizeof(today)); + today.tm_sec = 1; + today.tm_min = 0; + today.tm_hour = 0; + + t_tomorrow = mktime(&today) + 24 * 60 * 60; + if (update_today) ecore_timer_interval_set(update_today, t_tomorrow - t); + else update_today = ecore_timer_add(t_tomorrow - t, _update_today_timer, NULL); + return EINA_TRUE; +} + + +static Eina_Bool +_clock_eio_update(void *d EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Eio_Monitor_Event *ev = event; + + if ((ev->monitor == clock_tz_monitor) || + (ev->monitor == clock_tz2_monitor) || + (ev->monitor == clock_tzetc_monitor)) + { + if ((ev->filename) && + ((!strcmp(ev->filename, "/etc/localtime")) || + (!strcmp(ev->filename, "/etc/timezone")))) + { + e_int_clock_instances_redo(EINA_TRUE); + } + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_clock_time_update(void *d EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED) +{ + e_int_clock_instances_redo(EINA_TRUE); + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_clock_eio_error(void *d EINA_UNUSED, int type EINA_UNUSED, void *event) +{ + Eio_Monitor_Event *ev = event; + + if ((ev->monitor == clock_tz_monitor) || + (ev->monitor == clock_tz2_monitor) || + (ev->monitor == clock_tzetc_monitor)) + { + if (clock_tz_monitor) + { + eio_monitor_del(clock_tz_monitor); + clock_tz_monitor = NULL; + } + if (ecore_file_exists("/etc/localtime")) + clock_tz_monitor = eio_monitor_add("/etc/localtime"); + + if (clock_tz2_monitor) + { + eio_monitor_del(clock_tz2_monitor); + clock_tz2_monitor = NULL; + } + if (ecore_file_exists("/etc/timezone")) + clock_tz2_monitor = eio_monitor_add("/etc/timezone"); + if (clock_tzetc_monitor) + { + eio_monitor_del(clock_tzetc_monitor); + clock_tzetc_monitor = NULL; + } + if (ecore_file_is_dir("/etc")) + clock_tzetc_monitor = eio_monitor_add("/etc"); + } + + E_LIST_HANDLER_APPEND(clock_eio_handlers, EIO_MONITOR_ERROR, _clock_eio_error, NULL); + E_LIST_HANDLER_APPEND(clock_eio_handlers, EIO_MONITOR_FILE_CREATED, _clock_eio_update, NULL); + E_LIST_HANDLER_APPEND(clock_eio_handlers, EIO_MONITOR_FILE_MODIFIED, _clock_eio_update, NULL); + E_LIST_HANDLER_APPEND(clock_eio_handlers, EIO_MONITOR_FILE_DELETED, _clock_eio_update, NULL); + E_LIST_HANDLER_APPEND(clock_eio_handlers, EIO_MONITOR_SELF_DELETED, _clock_eio_update, NULL); + E_LIST_HANDLER_APPEND(clock_eio_handlers, EIO_MONITOR_SELF_RENAME, _clock_eio_update, NULL); + E_LIST_HANDLER_APPEND(clock_eio_handlers, E_EVENT_SYS_RESUME, _clock_time_update, NULL); + E_LIST_HANDLER_APPEND(clock_eio_handlers, ECORE_EVENT_SYSTEM_TIMEDATE_CHANGED, _clock_time_update, NULL); + + return ECORE_CALLBACK_PASS_ON; +} + +EINTERN void +time_init(void) +{ + if (ecore_file_exists("/etc/localtime")) + clock_tz_monitor = eio_monitor_add("/etc/localtime"); + if (ecore_file_exists("/etc/timezone")) + clock_tz2_monitor = eio_monitor_add("/etc/timezone"); + if (ecore_file_is_dir("/etc")) + clock_tzetc_monitor = eio_monitor_add("/etc"); + _update_today_timer(NULL); +} + +EINTERN void +time_shutdown(void) +{ + E_FREE_FUNC(update_today, ecore_timer_del); + if (clock_tz_monitor) eio_monitor_del(clock_tz_monitor); + if (clock_tz2_monitor) eio_monitor_del(clock_tz2_monitor); + if (clock_tzetc_monitor) eio_monitor_del(clock_tzetc_monitor); + clock_tz_monitor = NULL; + clock_tz2_monitor = NULL; + clock_tzetc_monitor = NULL; + +} diff --git a/src/gadgets/core.c b/src/gadgets/core.c new file mode 100644 index 0000000..27f8677 --- /dev/null +++ b/src/gadgets/core.c @@ -0,0 +1,736 @@ +#include "e_mod_main.h" +#include "gadget.h" + +#define ZGS_IS_HORIZ(gravity) \ + ((gravity) == Z_GADGET_SITE_GRAVITY_LEFT) || ((gravity) == Z_GADGET_SITE_GRAVITY_RIGHT) + +#define ZGS_GET(obj) \ + zgs = evas_object_data_get((obj), "__z_gadget_site"); \ + if (!zgs) abort() + +typedef struct Z_Gadget_Config Z_Gadget_Config; + +typedef struct Z_Gadget_Site +{ + Evas_Object *layout; + Evas_Object *events; + Z_Gadget_Site_Gravity gravity; + Eina_List *gadgets; + int cur_size; + + Z_Gadget_Config *action; + Ecore_Event_Handler *move_handler; + Ecore_Event_Handler *mouse_up_handler; + int button; +} Z_Gadget_Site; + + +/* refcount? */ +struct Z_Gadget_Config +{ + E_Object *e_obj_inherit; //list? + Evas_Object *gadget; //list? + unsigned int id; + Eina_Stringshare *type; + Z_Gadget_Site *site; + + double x, y; //fixed % positioning + Evas_Point offset; //offset from mouse down + Z_Gadget_Config *over; //gadget is animating over another gadget during drag + Eina_Bool modifying : 1; +}; + +static Eina_Hash *gadget_types; + +static Eina_List *sites; + +static E_Action *move_act; + +static Z_Gadget_Config * +_gadget_at_xy(Z_Gadget_Site *zgs, int x, int y) +{ + Eina_List *l; + Z_Gadget_Config *zgc; + Evas_Object *win; + int wx, wy; + + win = e_win_evas_object_win_get(zgs->layout); + evas_object_geometry_get(win, &wx, &wy, NULL, NULL); + EINA_LIST_FOREACH(zgs->gadgets, l, zgc) + { + int ox, oy, ow, oh; + + if (!zgc->gadget) continue; + + evas_object_geometry_get(zgc->gadget, &ox, &oy, &ow, &oh); + if (E_INSIDE(x, y, ox + wx, oy + wy, ow, oh)) return zgc; + } + return NULL; +} + +static void +_gravity_apply(Evas_Object *ly, Z_Gadget_Site_Gravity gravity) +{ + elm_box_horizontal_set(ly, ZGS_IS_HORIZ(gravity)); + elm_box_align_set(ly, + ZGS_IS_HORIZ(gravity) ? gravity - Z_GADGET_SITE_GRAVITY_LEFT : 0.5, + ZGS_IS_HORIZ(gravity) ? 0.5 : gravity - Z_GADGET_SITE_GRAVITY_TOP); +} + +static void +_gadget_reparent(Z_Gadget_Site *zgs, Evas_Object *g) +{ + switch (zgs->gravity) + { + case Z_GADGET_SITE_GRAVITY_NONE: + /* fake */ + break; + case Z_GADGET_SITE_GRAVITY_LEFT: + case Z_GADGET_SITE_GRAVITY_TOP: + elm_box_pack_end(zgs->layout, g); + break; + default: + /* right aligned: pack on left */ + elm_box_pack_start(zgs->layout, g); + } +} + +static void +_gadget_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Z_Gadget_Config *zgc = data; + + if (!e_object_is_del(zgc->e_obj_inherit)) + e_object_del(zgc->e_obj_inherit); +} + +static void +_gadget_object_free(E_Object *eobj) +{ + Z_Gadget_Config *zgc; + Evas_Object *g; + + g = e_object_data_get(eobj); + zgc = evas_object_data_get(g, "__z_gadget"); + evas_object_smart_callback_call(zgc->site->layout, "gadget_removed", zgc->gadget); + E_FREE_FUNC(zgc->gadget, evas_object_del); + E_FREE(zgc->e_obj_inherit); +} + +static void +_site_extents_calc(Evas_Object *box, Evas_Object_Box_Data *priv, Eina_Bool horizontal) +{ + Evas_Coord minw, minh, mnw, mnh, maxw, maxh; + Evas_Coord *rw, *rh, *rminw, *rminh, *rmaxw, *rmaxh; + const Eina_List *l; + Evas_Object_Box_Option *opt; + Eina_Bool max = EINA_TRUE; + + minw = 0; + minh = 0; + maxw = -1; + maxh = -1; + + /* calculate but after switched w and h for horizontal mode */ + if (!horizontal) + { + /* use pointer for real w/h to allow size hint calcs to run only once + * for both orientations + */ + rw = &mnw; + rh = &mnh; + rminw = &minw; + rminh = &minh; + rmaxw = &maxw; + rmaxh = &maxh; + } + else + { + rw = &mnh; + rh = &mnw; + rminw = &minh; + rminh = &minw; + rmaxw = &maxh; + rmaxh = &maxw; + } + EINA_LIST_FOREACH(priv->children, l, opt) + { + evas_object_size_hint_min_get(opt->obj, &mnw, &mnh); + if (*rminw < *rw) *rminw = *rw; + *rminh += *rh; + + /* FIXME: worthwhile to allow object padding? */ + + evas_object_size_hint_max_get(opt->obj, &mnw, &mnh); + if (*rh < 0) + { + *rmaxh = -1; + max = EINA_FALSE; + } + if (max) *rmaxh += *rh; + + if (*rw >= 0) + { + if (*rmaxw == -1) *rmaxw = *rw; + else if (*rmaxw > *rw) *rmaxw = *rw; + } + } + if ((maxw >= 0) && (minw > maxw)) maxw = minw; + if ((maxh >= 0) && (minh > maxh)) maxh = minh; + evas_object_size_hint_min_set(box, minw, minh); + evas_object_size_hint_max_set(box, maxw, maxh); +} + +static void +_site_gadget_resize(Evas_Object *g, int w, int h, Evas_Coord *ww, Evas_Coord *hh, Evas_Coord *ow, Evas_Coord *oh) +{ + Evas_Coord mnw, mnh, mxw, mxh; + Z_Gadget_Config *zgc; + + zgc = evas_object_data_get(g, "__z_gadget"); + + evas_object_size_hint_min_get(g, &mnw, &mnh); + evas_object_size_hint_max_get(g, &mxw, &mxh); + + /* TODO: aspect */ + if (ZGS_IS_HORIZ(zgc->site->gravity)) + { + *ww = mnw, *hh = h; + if (!(*ww)) *ww = *hh; + } + else + { + *hh = mnh, *ww = w; + if (!(*hh)) *hh = *ww; + } + *ow = *ww; + if ((mxw >= 0) && (mxw < *ow)) *ow = mxw; + *oh = *hh; + if ((mxh >= 0) && (mxh < *oh)) *oh = mxh; + + evas_object_resize(g, *ow, *oh); +} + +static void +_site_layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data) +{ + Z_Gadget_Site *zgs = data; + Evas_Coord x, y, w, h, xx, yy, px, py; + Eina_List *l, *fixed = NULL; + Evas_Coord minw, minh; + double ax, ay; + Z_Gadget_Config *zgc; + + _site_extents_calc(o, priv, ZGS_IS_HORIZ(zgs->gravity)); + + evas_object_geometry_get(o, &x, &y, &w, &h); + evas_object_geometry_set(zgs->events, x, y, w, h); + + evas_object_size_hint_min_get(o, &minw, &minh); + evas_object_box_align_get(o, &ax, &ay); + if (w < minw) + { + x = x + ((w - minw) * (1.0 - ax)); + w = minw; + } + if (h < minh) + { + y = y + ((h - minh) * (1.0 - ay)); + h = minh; + } + + px = xx = x; + py = yy = y; + + /* do layout for rest of gadgets now to avoid fixed gadgets */ + if (zgs->gravity % 2)//left/top + { + EINA_LIST_FOREACH(zgs->gadgets, l, zgc) + { + Evas_Coord gx = xx, gy = yy; + int ww, hh, ow, oh; + + if ((zgc->x > -1) || (zgc->y > -1)) break; //one fixed gadget reached + _site_gadget_resize(zgc->gadget, w, h, &ww, &hh, &ow, &oh); + gx += (Evas_Coord)(((double)(ww - ow)) * 0.5); + gy += (Evas_Coord)(((double)(hh - oh)) * 0.5); + evas_object_move(zgc->gadget, gx, gy); + if (ZGS_IS_HORIZ(zgs->gravity)) + xx += ww; + else + yy += hh; + } + } + else + { + EINA_LIST_REVERSE_FOREACH(zgs->gadgets, l, zgc) + { + Evas_Coord gx = xx, gy = yy; + int ww, hh, ow, oh; + + if ((zgc->x > -1) || (zgc->y > -1)) continue; //one fixed gadget reached + _site_gadget_resize(zgc->gadget, w, h, &ww, &hh, &ow, &oh); + gx += (Evas_Coord)(((double)(ww - ow)) * 0.5); + gy += (Evas_Coord)(((double)(hh - oh)) * 0.5); + evas_object_move(zgc->gadget, gx, gy); + if (ZGS_IS_HORIZ(zgs->gravity)) + xx += ww; + else + yy += hh; + } + } + px = xx; + py = yy; + + if (ZGS_IS_HORIZ(zgs->gravity)) + zgs->cur_size = px; + else + zgs->cur_size = py; + + /* do layout for fixed position gadgets after */ + EINA_LIST_REVERSE_FOREACH(zgs->gadgets, l, zgc) + { + Evas_Coord gx = xx, gy = yy; + int ww, hh, ow, oh; + + if ((zgc->x < 0) && (zgc->y < 0)) break; //once non-fixed gadget reached + _site_gadget_resize(zgc->gadget, w, h, &ww, &hh, &ow, &oh); + fixed = eina_list_append(fixed, zgc); + if (ZGS_IS_HORIZ(zgc->site->gravity)) + gx = zgc->x * (xx + MAX(w, minw)); + else + gy = zgc->y * (yy + MAX(h, minh)); + gx += (Evas_Coord)(((double)(ww - ow)) * 0.5); + gy += (Evas_Coord)(((double)(hh - oh)) * 0.5); + if (gx < px) gx = px; + if (gy < py) gy = py; + + evas_object_move(zgc->gadget, gx, gy); + if (ZGS_IS_HORIZ(zgs->gravity)) + px = gx + ww; + else + py = gy + hh; + } + + + eina_list_free(fixed); +} + +static int +_site_gadgets_sort(Z_Gadget_Config *a, Z_Gadget_Config *b) +{ + double *ax, *bx; + if (ZGS_IS_HORIZ(a->site->gravity)) + ax = &a->x, bx = &b->x; + else + ax = &a->y, bx = &b->y; + if (a->site->gravity % 2)//left/top + return lround(*ax - *bx); + return lround(*bx - *ax); +} + +static Eina_Bool +_gadget_mouse_move(Z_Gadget_Config *zgc, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev) +{ + int wx, wy;//window coords + int x, y, w, h;//site geom + int mx, my;//mouse coords normalized for layout orientation + int gw, gh;//"relative" region size + int *rw, *rh;//"relative" region size aliasing + int ox, oy, ow, oh;//gadget geom + Eina_List *fixed; + Z_Gadget_Config *z; + Evas_Object *win; + + /* adjust window -> screen coords */ + win = e_win_evas_object_win_get(zgc->site->layout); + evas_object_geometry_get(win, &wx, &wy, NULL, NULL); + evas_object_geometry_get(zgc->site->layout, &x, &y, &w, &h); + x += wx, y += wy; + gw = w, gh = h; + + mx = ev->x; + my = ev->y; + + evas_object_geometry_get(zgc->gadget, &ox, &oy, &ow, &oh); + ox += wx, oy += wy; + + rw = &gw; + rh = &gh; + /* normalize constrained axis to get a valid coordinate */ + if (ZGS_IS_HORIZ(zgc->site->gravity)) + { + my = y + 1; + *rw = zgc->site->cur_size; + } + else + { + mx = x + 1; + *rh = zgc->site->cur_size; + } + + /* find first "fixed" position gadget for later use */ + EINA_LIST_FOREACH(zgc->site->gadgets, fixed, z) + if ((z->x > -1) || (z->y > -1)) break; + + if (E_INSIDE(mx, my, x, y, w, h)) + { + /* dragging inside site */ + int sx = x, sy = y; + double ax, ay; + + /* adjust contiguous site geometry for gravity */ + elm_box_align_get(zgc->site->layout, &ax, &ay); + if (ZGS_IS_HORIZ(zgc->site->gravity)) + sx = x + ((w - zgc->site->cur_size) * (1.0 - ax)); + else + sy = y + ((h - zgc->site->cur_size) * (1.0 - ay)); + if (E_INSIDE(mx, my, sx, sy, *rw, *rh)) + { + /* dragging inside relative area */ + Eina_List *l; + + EINA_LIST_FOREACH(zgc->site->gadgets, l, z) + { + int ggx, ggy, ggw, ggh; + Eina_Bool left;//moving gadget is "left" of this gadget + int *pmx, *pggx, *pggw, *pwx, *pw; + double *zx; + + if (z == zgc) continue; + if (!z->gadget) continue; //no gadget object for this config + + evas_object_geometry_get(z->gadget, &ggx, &ggy, &ggw, &ggh); + ggx += wx, ggy += wy; + /* not inside this gadget! */ + if (!E_INSIDE(mx, my, ggx, ggy, ggw, ggh)) continue; + + if (ZGS_IS_HORIZ(zgc->site->gravity)) + left = ox < ggx; + else + left = oy < ggy; + + if (ZGS_IS_HORIZ(zgc->site->gravity)) + pmx = &mx, pggx = &ggx, pggw = &ggw, pwx = &wx, pw = &w, zx = &zgc->x; + else + pmx = &my, pggx = &ggy, pggw = &ggh, pwx = &wy, pw = &h, zx = &zgc->y; + if (left) + { + if (*pmx > *pggx + (*pggw / 2)) // more than halfway over + { + zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); + zgc->site->gadgets = eina_list_append_relative_list(zgc->site->gadgets, zgc, l); + zgc->over = NULL; + *zx = -1.0; + } + else // less + { + *zx = (double)(*pmx - *pwx) / (double)*pw; + zgc->over = z; + } + } + else + { + if (*pmx < *pggx + (*pggw / 2)) // more than halfway over + { + zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); + zgc->site->gadgets = eina_list_prepend_relative_list(zgc->site->gadgets, zgc, l); + zgc->over = NULL; + *zx = -1.0; + } + else // less + { + *zx = (double)(*pmx - *pwx) / (double)*pw; + zgc->over = z; + } + } + } + } + else + { + /* dragging outside relative area */ + if (fixed) + { + Eina_List *l; + Z_Gadget_Config *zz; + + for (l = fixed; l; l = l->next) + { + int zx, zy, zw, zh; + + zz = eina_list_data_get(l); + + if ((zz = zgc) || (!zz->gadget)) continue; + + /* FIXME: shortcut */ + evas_object_geometry_get(zz->gadget, &zx, &zy, &zw, &zh); + if (E_INSIDE(mx, my, zx, zy, zw, zh)) + { + zgc->over = zz; + break; + } + } + } + if (!((zgc->x > -1) || (zgc->y > -1))) + { + zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); + zgc->site->gadgets = eina_list_append(zgc->site->gadgets, zgc); + } + if (ZGS_IS_HORIZ(zgc->site->gravity)) + zgc->x = (double)(mx - wx - zgc->offset.x) / (double)w; + else + zgc->y = (double)(my - wy - zgc->offset.y) / (double)h; + } + } + else + { + /* dragging to edge of site */ + Eina_Bool left; + double *fx; + + if (ZGS_IS_HORIZ(zgc->site->gravity)) + { + fx = &zgc->x; + left = mx <= x; + } + else + { + fx = &zgc->y; + left = my <= y; + } + if (left) + { + if ((zgc->site->gravity == Z_GADGET_SITE_GRAVITY_LEFT) || (zgc->site->gravity == Z_GADGET_SITE_GRAVITY_TOP)) + { + *fx = -1.0; + zgc->site->gadgets = eina_list_promote_list(zgc->site->gadgets, eina_list_data_find_list(zgc->site->gadgets, zgc)); + } + else + { + *fx = 0.0; + zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); + zgc->site->gadgets = eina_list_prepend_relative_list(zgc->site->gadgets, zgc, fixed); + } + } + else + { + if ((zgc->site->gravity == Z_GADGET_SITE_GRAVITY_LEFT) || (zgc->site->gravity == Z_GADGET_SITE_GRAVITY_TOP)) + { + *fx = 1.0; + zgc->site->gadgets = eina_list_demote_list(zgc->site->gadgets, eina_list_data_find_list(zgc->site->gadgets, zgc)); + } + else + { + *fx = -1.0; + zgc->site->gadgets = eina_list_remove(zgc->site->gadgets, zgc); + zgc->site->gadgets = eina_list_prepend_relative_list(zgc->site->gadgets, zgc, fixed); + } + } + } + elm_box_recalculate(zgc->site->layout); + + return ECORE_CALLBACK_RENEW; +} + +static void +_gadget_act_modify_end(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) +{ + Z_Gadget_Config *zgc; + Evas_Object *g; + + g = e_object_data_get(obj); + zgc = evas_object_data_get(g, "__z_gadget"); + zgc->modifying = 0; + if (zgc->over) + { + /* FIXME: animate */ + zgc->x = zgc->y = -1.0; + evas_object_smart_need_recalculate_set(zgc->site->layout, 1); + } + zgc->over = NULL; + + E_FREE_FUNC(zgc->site->move_handler, ecore_event_handler_del); +} + +static void +_gadget_act_modify(E_Object *obj, const char *params EINA_UNUSED, E_Binding_Event_Mouse_Button *ev EINA_UNUSED) +{ + Z_Gadget_Config *zgc; + Evas_Object *g; + + if (obj->type != Z_GADGET_TYPE) return; + + g = e_object_data_get(obj); + zgc = evas_object_data_get(g, "__z_gadget"); + zgc->modifying = 1; + if (!zgc->site->move_handler) + zgc->site->move_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, (Ecore_Event_Handler_Cb)_gadget_mouse_move, zgc); +} + +static Eina_Bool +_site_mouse_up(Z_Gadget_Site *zgs, int t EINA_UNUSED, Ecore_Event_Mouse_Button *ev) +{ + if (e_bindings_mouse_up_ecore_event_handle(E_BINDING_CONTEXT_ANY, zgs->action->e_obj_inherit, ev)) + { + evas_object_pointer_mode_set(zgs->events, EVAS_OBJECT_POINTER_MODE_NOGRAB); + zgs->action = NULL; + E_FREE_FUNC(zgs->mouse_up_handler, ecore_event_handler_del); + } + return ECORE_CALLBACK_RENEW; +} + +static void +_site_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info) +{ + Z_Gadget_Site *zgs = data; + Evas_Event_Mouse_Down *ev = event_info; + Z_Gadget_Config *zgc; + + zgc = _gadget_at_xy(zgs, ev->output.x, ev->output.y); + if (!zgc) return; + if (e_bindings_mouse_down_evas_event_handle(E_BINDING_CONTEXT_ANY, zgc->e_obj_inherit, event_info)) + { + int x, y; + + evas_object_pointer_mode_set(obj, EVAS_OBJECT_POINTER_MODE_NOGRAB_NO_REPEAT_UPDOWN); + zgs->action = zgc; + if (!zgs->mouse_up_handler) + zgs->mouse_up_handler = ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, (Ecore_Event_Handler_Cb)_site_mouse_up, zgs); + + + evas_object_geometry_get(zgc->gadget, &x, &y, NULL, NULL); + zgc->offset.x = ev->canvas.x - x; + zgc->offset.y = ev->canvas.y - y; + } +} + +Z_API Evas_Object * +z_gadget_site_add(Evas_Object *parent, Z_Gadget_Site_Gravity gravity) +{ + Z_Gadget_Site *zgs; + + zgs = E_NEW(Z_Gadget_Site, 1); + + zgs->gravity = gravity; + if (gravity) + { + zgs->layout = elm_box_add(parent); + _gravity_apply(zgs->layout, gravity); + elm_box_layout_set(zgs->layout, _site_layout, zgs, NULL); + } + else + zgs->layout = elm_layout_add(parent); + + zgs->events = evas_object_rectangle_add(evas_object_evas_get(parent)); + evas_object_pointer_mode_set(zgs->events, EVAS_OBJECT_POINTER_MODE_NOGRAB); + evas_object_smart_member_add(zgs->events, zgs->layout); + evas_object_color_set(zgs->events, 0, 0, 0, 0); + evas_object_repeat_events_set(zgs->events, 1); + evas_object_show(zgs->events); + evas_object_event_callback_add(zgs->events, EVAS_CALLBACK_MOUSE_DOWN, _site_mouse_down, zgs); + + evas_object_data_set(zgs->layout, "__z_gadget_site", zgs); + + sites = eina_list_append(sites, zgs); + + if (!move_act) + { + move_act = e_action_add("gadget_modify"); + e_action_predef_name_set(D_("Gadgets"), D_("Move gadget"), "gadget_modify", NULL, NULL, 0); + move_act->func.go_mouse = _gadget_act_modify; + move_act->func.end_mouse = _gadget_act_modify_end; + } + + return zgs->layout; +} + +Z_API Z_Gadget_Site_Gravity +z_gadget_site_gravity_get(Evas_Object *obj) +{ + Z_Gadget_Site *zgs; + + ZGS_GET(obj); + return zgs->gravity; +} + +Z_API void +z_gadget_site_gadget_add(Evas_Object *obj, const char *type) +{ + char buf[1024]; + Z_Gadget_Create_Cb cb; + Evas_Object *g; + Z_Gadget_Site *zgs; + Z_Gadget_Config *zgc; + unsigned int id = 0; + + EINA_SAFETY_ON_NULL_RETURN(gadget_types); + ZGS_GET(obj); + + strncpy(buf, type, sizeof(buf)); + + cb = eina_hash_find(gadget_types, buf); + EINA_SAFETY_ON_NULL_RETURN(cb); + + /* if id is 0, gadget creates new config and returns id + * otherwise, config of `id` is applied to created object + */ + g = cb(obj, &id); + EINA_SAFETY_ON_NULL_RETURN(g); + + zgc = E_NEW(Z_Gadget_Config, 1); + zgc->e_obj_inherit = E_OBJECT_ALLOC(E_Object, Z_GADGET_TYPE, _gadget_object_free); + e_object_data_set(zgc->e_obj_inherit, g); + zgc->id = id; + zgc->type = eina_stringshare_add(buf); + zgc->gadget = g; + zgc->x = -1; + zgc->y = -1; + zgc->site = zgs; + evas_object_data_set(g, "__z_gadget", zgc); + + evas_object_event_callback_add(g, EVAS_CALLBACK_DEL, _gadget_del, zgc); + zgs->gadgets = eina_list_sorted_insert(zgs->gadgets, (Eina_Compare_Cb)_site_gadgets_sort, zgc); + _gadget_reparent(zgs, g); + evas_object_raise(zgs->events); + + evas_object_smart_callback_call(obj, "gadget_added", g); + evas_object_smart_callback_call(obj, "gadget_gravity", g); + + evas_object_show(g); +} + +Z_API Evas_Object * +z_gadget_site_get(Evas_Object *g) +{ + Z_Gadget_Site *zgs; + + EINA_SAFETY_ON_NULL_RETURN_VAL(g, NULL); + zgs = evas_object_data_get(g, "__z_gadget"); + EINA_SAFETY_ON_NULL_RETURN_VAL(zgs, NULL); + return zgs->layout; +} + +Z_API void +z_gadget_type_add(const char *type, Z_Gadget_Create_Cb callback) +{ + if (!gadget_types) gadget_types = eina_hash_string_superfast_new(NULL); + eina_hash_add(gadget_types, type, callback); +} + +Z_API void +z_gadget_type_del(const char *type) +{ + Eina_List *l, *ll; + Z_Gadget_Site *zgs; + Z_Gadget_Config *zgc; + char buf[1024]; + + strncpy(buf, type, sizeof(buf)); + + if (!gadget_types) return; + + EINA_LIST_FOREACH(sites, l, zgs) + EINA_LIST_FOREACH(zgs->gadgets, ll, zgc) + if (eina_streq(buf, zgc->type)) + evas_object_del(zgc->gadget); +} diff --git a/src/gadgets/demo.c b/src/gadgets/demo.c new file mode 100644 index 0000000..ed3a4db --- /dev/null +++ b/src/gadgets/demo.c @@ -0,0 +1,32 @@ +#include "gadget.h" + + +static Evas_Object *shelf; +static Evas_Object *site; + +EINTERN void +gadget_demo(void) +{ + Evas_Object *ly; + + if (!eina_streq(getenv("USER"), "zmike")) return; + + if (e_comp->w > 1200) return; + + ly = elm_layout_add(e_comp->elm); + e_theme_edje_object_set(ly, NULL, "e/shelf/default/base"); + + site = z_gadget_site_add(ly, Z_GADGET_SITE_GRAVITY_BOTTOM); + elm_object_part_content_set(ly, "e.swallow.content", site); + elm_layout_signal_emit(ly, "e,state,orientation,left", "e"); + evas_object_geometry_set(ly, 0, 0, 48, e_comp->h); + evas_object_show(ly); + shelf = e_comp_object_util_add(ly, E_COMP_OBJECT_TYPE_NONE); + evas_object_data_set(shelf, "comp_skip", (void*)1); + evas_object_layer_set(shelf, E_LAYER_DESKTOP); + evas_object_lower(shelf); + + evas_object_clip_set(shelf, e_comp_zone_xy_get(0, 0)->bg_clip_object); + + z_gadget_site_gadget_add(site, "Start"); +} diff --git a/src/gadgets/gadget.h b/src/gadgets/gadget.h new file mode 100644 index 0000000..1090367 --- /dev/null +++ b/src/gadgets/gadget.h @@ -0,0 +1,27 @@ +#ifndef Z_GADGET_H +# define Z_GADGET_H + +#include "e.h" +#define Z_API __attribute__ ((visibility("default"))) + +#define Z_GADGET_TYPE 0xE31337 + +typedef enum +{ + Z_GADGET_SITE_GRAVITY_NONE = 0, + Z_GADGET_SITE_GRAVITY_LEFT, + Z_GADGET_SITE_GRAVITY_RIGHT, + Z_GADGET_SITE_GRAVITY_TOP, + Z_GADGET_SITE_GRAVITY_BOTTOM, +} Z_Gadget_Site_Gravity; + +typedef Evas_Object *(*Z_Gadget_Create_Cb)(Evas_Object *parent, unsigned int *id); + +Z_API Evas_Object *z_gadget_site_add(Evas_Object *parent, Z_Gadget_Site_Gravity gravity); +Z_API Z_Gadget_Site_Gravity z_gadget_site_gravity_get(Evas_Object *obj); +Z_API void z_gadget_site_gadget_add(Evas_Object *obj, const char *type); +Z_API Evas_Object *z_gadget_site_get(Evas_Object *g); +Z_API void z_gadget_type_add(const char *type, Z_Gadget_Create_Cb callback); +Z_API void z_gadget_type_del(const char *type); + +#endif diff --git a/src/gadgets/start/mod.c b/src/gadgets/start/mod.c new file mode 100644 index 0000000..4efbb5b --- /dev/null +++ b/src/gadgets/start/mod.c @@ -0,0 +1,30 @@ +#include "e.h" + +/* module setup */ +E_API E_Module_Api e_modapi = +{ + E_MODULE_API_VERSION, + "Start" +}; + +E_API void * +e_modapi_init(E_Module *m) +{ + start_module = m; + e_gadcon_provider_register(&_gadcon_class); + return m; +} + +E_API int +e_modapi_shutdown(E_Module *m EINA_UNUSED) +{ + start_module = NULL; + e_gadcon_provider_unregister(&_gadcon_class); + return 1; +} + +E_API int +e_modapi_save(E_Module *m EINA_UNUSED) +{ + return 1; +} diff --git a/src/gadgets/start/start.c b/src/gadgets/start/start.c new file mode 100644 index 0000000..9563d1e --- /dev/null +++ b/src/gadgets/start/start.c @@ -0,0 +1,160 @@ +/** + * @addtogroup Optional_Gadgets + * @{ + * + * @defgroup Module_Start Start Button + * + * Shows a "start here" button or icon. + * + * @} + */ + +#include "gadget.h" + +/* actual module specifics */ +typedef struct _Instance Instance; + +struct _Instance +{ + Evas_Object *o_button; + E_Menu *main_menu; +}; + +static void +orient(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + Instance *inst = data; + char buf[4096]; + const char *s = "float"; + + switch (z_gadget_site_gravity_get(obj)) + { + case Z_GADGET_SITE_GRAVITY_LEFT: + s = "left"; + break; + + case Z_GADGET_SITE_GRAVITY_RIGHT: + s = "right"; + break; + + case Z_GADGET_SITE_GRAVITY_TOP: + s = "top"; + break; + + case Z_GADGET_SITE_GRAVITY_BOTTOM: + s = "bottom"; + break; + + default: + s = "none"; + break; + } + snprintf(buf, sizeof(buf), "e,state,orientation,%s", s); + elm_layout_signal_emit(inst->o_button, buf, "e"); +} + +static void +_menu_cb_post(void *data, E_Menu *m) +{ + Instance *inst = data; + Eina_Bool fin; + + if (stopping || (!inst->main_menu)) return; + fin = m == inst->main_menu; + e_object_del(E_OBJECT(m)); + if (!fin) return; + /* FIXME + e_gadcon_locked_set(inst->gcc->gadcon, 0); + */ + elm_layout_signal_emit(inst->o_button, "e,state,unfocused", "e"); + inst->main_menu = NULL; +} + +static void +_button_cb_mouse_down(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ + Instance *inst = data; + Evas_Event_Mouse_Down *ev = event_info; + Evas_Coord x, y, w, h; + int cx, cy; + Evas_Object *win; + + if (ev->button != 1) return; + + evas_object_geometry_get(inst->o_button, &x, &y, &w, &h); + win = e_win_evas_object_win_get(inst->o_button); + evas_object_geometry_get(win, &cx, &cy, NULL, NULL); + x += cx; + y += cy; + if (!inst->main_menu) + inst->main_menu = e_int_menus_main_new(); + if (!inst->main_menu) return; + e_menu_post_deactivate_callback_set(inst->main_menu, + _menu_cb_post, inst); + /* FIXME + e_gadcon_locked_set(inst->gcc->gadcon, 1); + */ + e_menu_activate_mouse(inst->main_menu, + e_zone_current_get(), + x, y, w, h, E_MENU_POP_DIRECTION_AUTO, ev->timestamp); + elm_layout_signal_emit(inst->o_button, "e,state,focused", "e"); +} + +static void +start_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Instance *inst = data; + + if (inst->main_menu) + { + e_menu_post_deactivate_callback_set(inst->main_menu, NULL, NULL); + e_object_del(E_OBJECT(inst->main_menu)); + } + free(inst); +} + +EINTERN Evas_Object * +start_create(Evas_Object *parent, unsigned int *id EINA_UNUSED) +{ + Evas_Object *o; + Instance *inst; + + inst = E_NEW(Instance, 1); + + o = elm_layout_add(parent); + + e_theme_edje_object_set(o, "base/theme/modules/start", + "e/modules/start/main"); + elm_layout_signal_emit(o, "e,state,unfocused", "e"); + + inst->o_button = o; + + evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, + _button_cb_mouse_down, inst); + evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, start_del, inst); + evas_object_smart_callback_add(parent, "gadget_gravity", orient, inst); + + return o; +} +#if 0 +/* module setup */ +E_API E_Module_Api e_modapi = +{ + E_MODULE_API_VERSION, + "Start" +}; + +E_API void * +e_modapi_init(E_Module *m) +{ + z_gadget_type_add("Start", start_create); + return m; +} + +E_API int +e_modapi_shutdown(E_Module *m EINA_UNUSED) +{ + z_gadget_type_del("Start"); + return 1; +} +#endif