add new time module with clock gadgets

this is the successor to the clock module/gadget. it uses separate config files
and theme groups from the "clock" module.
This commit is contained in:
Mike Blumenkrantz 2016-03-03 09:42:11 -05:00
parent 24fe43d735
commit dad9160ffa
11 changed files with 1759 additions and 0 deletions

View File

@ -925,6 +925,7 @@ AC_E_OPTIONAL_MODULE([policy_mobile], true)
AC_E_OPTIONAL_MODULE([geolocation], true)
AC_E_OPTIONAL_MODULE([xwayland], $have_wayland, [CHECK_MODULE_XWAYLAND])
AC_E_OPTIONAL_MODULE([wireless], true)
AC_E_OPTIONAL_MODULE([time], true)
if test "x${HAVE_WL_X11}" != "xyes" && test "x${have_wayland}" = "xyes" && test "x${HAVE_XWAYLAND}" != "xyes"; then
AC_DEFINE_UNQUOTED([HAVE_WAYLAND_ONLY],[1],[enable wayland-only version of enlightenment])
@ -1127,6 +1128,7 @@ src/modules/music-control/module.desktop
src/modules/packagekit/module.desktop
src/modules/wl_desktop_shell/module.desktop
src/modules/wireless/module.desktop
src/modules/time/module.desktop
data/xsession/enlightenment.desktop
data/etc/sysactions.conf
data/units/enlightenment.service

View File

@ -1024,6 +1024,7 @@ _e_module_whitelist_check(void)
"teamwork",
"temperature",
"tiling",
"time",
"winlist",
"wireless",
"wizard",

View File

@ -129,3 +129,4 @@ include src/modules/Makefile_policy_mobile.mk
include src/modules/Makefile_geolocation.mk
include src/modules/Makefile_wireless.mk
include src/modules/Makefile_time.mk

View File

@ -0,0 +1,25 @@
EXTRA_DIST += src/modules/time/module.desktop.in \
src/modules/time/e-module-time.edj
if USE_MODULE_TIME
timedir = $(MDIR)/time
time_DATA = src/modules/time/e-module-time.edj \
src/modules/time/module.desktop
timepkgdir = $(MDIR)/time/$(MODULE_ARCH)
timepkg_LTLIBRARIES = src/modules/time/module.la
src_modules_time_module_la_LIBADD = $(MOD_LIBS)
src_modules_time_module_la_CPPFLAGS = $(MOD_CPPFLAGS)
src_modules_time_module_la_LDFLAGS = $(MOD_LDFLAGS)
src_modules_time_module_la_SOURCES = \
src/modules/time/clock.c \
src/modules/time/clock.h \
src/modules/time/config.c \
src/modules/time/mod.c \
src/modules/time/time.c
PHONIES += time install-time
time: $(timepkg_LTLIBRARIES) $(time_DATA)
install-time: install-timeDATA install-timepkgLTLIBRARIES
endif

507
src/modules/time/clock.c Normal file
View File

@ -0,0 +1,507 @@
#include "clock.h"
EINTERN Config *time_config = NULL;
EINTERN Eina_List *clock_instances = NULL;
static Ecore_Timer *clock_timer;
static void
_clock_calendar_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_instance_update(inst);
_clock_calendar_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_instance_update(inst);
_clock_calendar_month_update(inst);
}
static void
_clock_popup_dismissed(void *data EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
{
evas_object_del(obj);
}
static void
_eval_instance_size(Instance *inst)
{
Evas_Coord mw, mh;
int sw = 0, sh = 0;
Evas_Object *ed = elm_layout_edje_get(inst->o_clock);
edje_object_size_min_get(ed, &mw, &mh);
if ((mw < 1) || (mh < 1))
{
if (edje_object_part_exists(ed, "e.sizer"))
{
edje_object_part_geometry_get(ed, "e.sizer", NULL, NULL, &mw, &mh);
}
else
{
Evas_Object *owner;
owner = e_gadget_site_get(inst->o_clock);
switch (e_gadget_site_orient_get(owner))
{
case E_GADGET_SITE_ORIENT_HORIZONTAL:
evas_object_geometry_get(owner, NULL, NULL, NULL, &sh);
break;
case E_GADGET_SITE_ORIENT_VERTICAL:
evas_object_geometry_get(owner, NULL, NULL, &sw, NULL);
break;
default: break;
}
evas_object_resize(inst->o_clock, sw, sh);
edje_object_message_signal_process(ed);
edje_object_parts_extends_calc(ed, NULL, NULL, &mw, &mh);
}
}
if (mw < 4) mw = 4;
if (mh < 4) mh = 4;
if (mw < sw) mw = sw;
if (mh < sh) mh = sh;
evas_object_size_hint_aspect_set(inst->o_clock, EVAS_ASPECT_CONTROL_BOTH, mw, mh);
}
static void
_clock_edje_init(Instance *inst, Evas_Object *o)
{
char datestr[128];
const char *digital[] =
{
"e/gadget/clock/digital",
"e/gadget/clock/digital/advanced",
};
time_datestring_format(inst, datestr, sizeof(datestr) - 1);
if (inst->cfg->digital_clock)
e_theme_edje_object_set(o, NULL, digital[inst->cfg->advanced]);
else
e_theme_edje_object_set(o, NULL, "e/gadget/clock/analog");
if (inst->cfg->show_date)
elm_layout_signal_emit(o, "e,state,date,on", "e");
else
elm_layout_signal_emit(o, "e,state,date,off", "e");
if (inst->cfg->digital_24h)
elm_layout_signal_emit(o, "e,state,24h,on", "e");
else
elm_layout_signal_emit(o, "e,state,24h,off", "e");
if (inst->cfg->show_seconds)
elm_layout_signal_emit(o, "e,state,seconds,on", "e");
else
elm_layout_signal_emit(o, "e,state,seconds,off", "e");
elm_object_part_text_set(o, "e.text.sub", datestr);
if (inst->cfg->timezone)
{
Edje_Message_String msg;
msg.str = (char*)inst->cfg->timezone;
edje_object_message_send(elm_layout_edje_get(o), EDJE_MESSAGE_STRING, 1, &msg);
}
{
Edje_Message_String_Int msg;
msg.str = (char*)inst->cfg->colorclass[0] ?: "";
msg.val = !!inst->cfg->colorclass[0];
edje_object_message_send(elm_layout_edje_get(o), EDJE_MESSAGE_STRING_INT, 2, &msg);
msg.str = (char*)inst->cfg->colorclass[1] ?: "";
msg.val = !!inst->cfg->colorclass[1];
edje_object_message_send(elm_layout_edje_get(o), EDJE_MESSAGE_STRING_INT, 3, &msg);
}
edje_object_message_signal_process(elm_layout_edje_get(o));
}
static Eina_Bool
_clock_timer(void *d EINA_UNUSED)
{
Eina_List *l;
Instance *inst;
Eina_Bool seconds = EINA_FALSE;
int sec;
char buf[128];
EINA_LIST_FOREACH(clock_instances, l, inst)
{
if (!inst->cfg->advanced) continue;
seconds |= inst->cfg->show_seconds;
sec = time_string_format(inst, buf, sizeof(buf));
elm_object_part_text_set(inst->o_clock, "e.text", buf);
_eval_instance_size(inst);
}
sec = seconds ? 1 : (61 - sec);
if (clock_timer)
ecore_timer_interval_set(clock_timer, sec);
else
clock_timer = ecore_timer_add(sec, _clock_timer, NULL);
return EINA_TRUE;
}
static void
_clock_popup_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Instance *inst = data;
if (obj != inst->popup) return;
inst->popup = inst->o_table = inst->o_cal = NULL;
}
EINTERN void
clock_popup_new(Instance *inst)
{
Evas_Object *oi;
if (inst->popup) return;
inst->madj = 0;
time_instance_update(inst);
inst->popup = elm_ctxpopup_add(inst->o_clock);
elm_object_style_set(inst->popup, "noblock");
evas_object_smart_callback_add(inst->popup, "dismissed", _clock_popup_dismissed, inst);
evas_object_event_callback_add(inst->popup, EVAS_CALLBACK_DEL, _clock_popup_del, inst);
inst->o_table = elm_table_add(inst->popup);
oi = elm_layout_add(inst->o_table);
inst->o_cal = oi;
e_theme_edje_object_set(oi, "base/theme/gadget/clock",
"e/gadget/clock/calendar");
_clock_calendar_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);
elm_object_content_set(inst->popup, inst->o_table);
e_gadget_util_ctxpopup_place(inst->o_clock, inst->popup, NULL);
evas_object_show(inst->popup);
}
void
clock_instances_redo(void)
{
Eina_List *l;
Instance *inst;
EINA_LIST_FOREACH(clock_instances, l, inst)
{
_clock_edje_init(inst, inst->o_clock);
_eval_instance_size(inst);
}
}
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->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
if (ev->button == 1)
{
if (inst->popup) elm_ctxpopup_dismiss(inst->popup);
else clock_popup_new(inst);
}
else if (ev->button == 3)
e_gadget_configure(inst->o_clock);
}
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 void
clock_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Instance *inst = data;
Eina_List *l;
Eina_Bool advanced = EINA_FALSE, seconds = EINA_FALSE;
clock_instances = eina_list_remove(clock_instances, inst);
evas_object_del(inst->popup);
time_daynames_clear(inst);
free(inst);
EINA_LIST_FOREACH(clock_instances, l, inst)
{
advanced |= !!inst->cfg->advanced;
seconds |= !!inst->cfg->show_seconds;
if (seconds) break;
}
if (seconds) return; //no change possible
E_FREE_FUNC(clock_timer, ecore_timer_del);
if (advanced)
_clock_timer(NULL);
}
static Config_Item *
_conf_item_get(int *id, Eina_Bool digital)
{
Config_Item *ci;
Eina_List *l;
if (*id > 0)
{
EINA_LIST_FOREACH(time_config->items, l, ci)
if (*id == ci->id) return ci;
}
ci = E_NEW(Config_Item, 1);
if (!*id)
ci->id = time_config->items ? eina_list_count(time_config->items) + 1 : 1;
else
ci->id = -1;
ci->weekend.start = 6;
ci->weekend.len = 2;
ci->week.start = 1;
ci->digital_clock = digital;
ci->digital_24h = 0;
ci->show_seconds = 0;
ci->show_date = 0;
ci->time_str[0] = eina_stringshare_add("%I:%M");
ci->time_str[1] = eina_stringshare_add("%F");
if (ci->id < 1) return ci;
time_config->items = eina_list_append(time_config->items, ci);
e_config_save_queue();
return ci;
}
static Evas_Object *
_clock_gadget_configure(Evas_Object *g)
{
Instance *inst = evas_object_data_get(g, "clock");
return config_clock(inst->cfg);
}
static void
_clock_gadget_removed_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Instance *inst = data;
if (inst->o_clock != event_info) return;
time_config->items = eina_list_remove(time_config->items, inst->cfg);
eina_stringshare_del(inst->cfg->timezone);
eina_stringshare_del(inst->cfg->time_str[0]);
eina_stringshare_del(inst->cfg->time_str[1]);
E_FREE(inst->cfg);
}
static void
_clock_gadget_created_cb(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Instance *inst = data;
e_gadget_configure_cb_set(inst->o_clock, _clock_gadget_configure);
evas_object_smart_callback_del_full(obj, "gadget_created", _clock_gadget_created_cb, data);
if (inst->cfg->advanced)
{
_clock_timer(NULL);
ecore_timer_reset(clock_timer);
}
_eval_instance_size(inst);
}
static Evas_Object *
clock_create(Evas_Object *parent, Instance *inst, E_Gadget_Site_Orient orient)
{
Evas_Object *o;
const char *sig = NULL;
inst->o_clock = o = elm_layout_add(parent);
elm_layout_signal_callback_add(o, "e,state,sizing,changed", "*",
_clock_sizing_changed_cb, inst);
_clock_edje_init(inst, o);
switch (orient)
{
case E_GADGET_SITE_ORIENT_HORIZONTAL:
sig = "e,state,horizontal";
break;
case E_GADGET_SITE_ORIENT_VERTICAL:
sig = "e,state,vertical";
break;
default:
sig = "e,state,float";
}
elm_layout_signal_emit(inst->o_clock, sig, "e");
evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, clock_del, inst);
evas_object_smart_callback_add(parent, "gadget_created", _clock_gadget_created_cb, inst);
evas_object_smart_callback_add(parent, "gadget_removed", _clock_gadget_removed_cb, inst);
evas_object_data_set(o, "clock", inst);
evas_object_event_callback_add(inst->o_clock,
EVAS_CALLBACK_MOUSE_DOWN,
_clock_cb_mouse_down,
inst);
if (inst->cfg->id < 0) return o;
clock_instances = eina_list_append(clock_instances, inst);
return o;
}
EINTERN Evas_Object *
digital_clock_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient)
{
Instance *inst;
inst = E_NEW(Instance, 1);
inst->cfg = _conf_item_get(id, 1);
return clock_create(parent, inst, orient);
}
EINTERN Evas_Object *
analog_clock_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient)
{
Instance *inst;
inst = E_NEW(Instance, 1);
inst->cfg = _conf_item_get(id, 0);
return clock_create(parent, inst, orient);
}
typedef struct Wizard_Item
{
E_Gadget_Wizard_End_Cb cb;
void *data;
int id;
} Wizard_Item;
static void
_wizard_end(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Wizard_Item *wi = data;
wi->cb(wi->data, wi->id);
free(wi);
}
static void
clock_wizard(E_Gadget_Wizard_End_Cb cb, void *data, Eina_Bool digital)
{
int id = 0;
Config_Item *ci;
Wizard_Item *wi;
wi = E_NEW(Wizard_Item, 1);
wi->cb = cb;
wi->data = data;
ci = _conf_item_get(&id, digital);
wi->id = ci->id;
evas_object_event_callback_add(config_clock(ci), EVAS_CALLBACK_DEL, _wizard_end, wi);
}
EINTERN void
digital_clock_wizard(E_Gadget_Wizard_End_Cb cb, void *data)
{
clock_wizard(cb, data, 1);
}
EINTERN void
analog_clock_wizard(E_Gadget_Wizard_End_Cb cb, void *data)
{
clock_wizard(cb, data, 0);
}
EINTERN void
time_config_update(Config_Item *ci)
{
Eina_List *l;
Instance *inst;
Eina_Bool advanced = EINA_FALSE;
ci->week.start = (ci->weekend.start + ci->weekend.len) % 7;
EINA_LIST_FOREACH(clock_instances, l, inst)
{
if (inst->cfg != ci) continue;
_clock_edje_init(inst, inst->o_clock);
if (!advanced)
{
advanced |= inst->cfg->advanced;
if (!inst->cfg->advanced) continue;
_clock_timer(NULL);
ecore_timer_reset(clock_timer);
}
_eval_instance_size(inst);
}
if (!advanced)
E_FREE_FUNC(clock_timer, ecore_timer_del);
e_config_save_queue();
}

93
src/modules/time/clock.h Normal file
View File

@ -0,0 +1,93 @@
#ifndef CLOCK_H
#define CLOCK_H
#include "e.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;
typedef struct _Instance Instance;
typedef enum
{
CLOCK_DATE_DISPLAY_NONE,
CLOCK_DATE_DISPLAY_FULL,
CLOCK_DATE_DISPLAY_NUMERIC,
CLOCK_DATE_DISPLAY_DATE_ONLY,
CLOCK_DATE_DISPLAY_ISO8601,
CLOCK_DATE_DISPLAY_CUSTOM,
} Clock_Date_Display;
struct _Config
{
Eina_List *items;
E_Module *module;
Evas_Object *config_dialog;
};
struct _Config_Item
{
int 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;
Eina_Bool digital_clock;
Eina_Bool digital_24h;
Eina_Bool show_seconds;
Clock_Date_Display show_date;
Eina_Bool advanced;
Eina_Stringshare *timezone;
Eina_Stringshare *time_str[2];
Eina_Stringshare *colorclass[2];
};
struct _Instance
{
Evas_Object *o_clock, *o_table, *o_cal;
Evas_Object *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;
};
EINTERN Evas_Object *config_clock(Config_Item *);
EINTERN void config_timezone_populate(Evas_Object *obj, const char *name);
void clock_instances_redo(void);
EINTERN void time_daynames_clear(Instance *inst);
EINTERN void time_datestring_format(Instance *inst, char *buf, int bufsz);
EINTERN int time_string_format(Instance *inst, char *buf, int bufsz);
EINTERN void time_instance_update(Instance *inst);
EINTERN void time_init(void);
EINTERN void time_shutdown(void);
EINTERN void time_zoneinfo_scan(Evas_Object *obj);
EINTERN Evas_Object *digital_clock_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient);
EINTERN Evas_Object *analog_clock_create(Evas_Object *parent, int *id, E_Gadget_Site_Orient orient);
EINTERN void digital_clock_wizard(E_Gadget_Wizard_End_Cb cb, void *data);
EINTERN void analog_clock_wizard(E_Gadget_Wizard_End_Cb cb, void *data);
EINTERN void clock_popup_new(Instance *inst);
EINTERN void time_config_update(Config_Item *ci);
extern Config *time_config;
extern Eina_List *clock_instances;
#endif

627
src/modules/time/config.c Normal file
View File

@ -0,0 +1,627 @@
#include "clock.h"
#include <time.h>
static const char *datecfg[] =
{
N_("None"),
N_("Full"),
N_("Numeric"),
N_("Date-only"),
N_("ISO 8601"),
N_("Custom"),
};
static void
_config_rect_click(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Evas_Event_Mouse_Up *ev = event_info;
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
evas_object_del(data);
}
static Evas_Object *
_config_autoclose_rect_add(Evas_Object *obj)
{
Evas_Object *rect;
rect = evas_object_rectangle_add(e_comp->evas);
e_comp_object_util_fullscreen(rect);
evas_object_color_set(rect, 0, 0, 0, 0);
evas_object_layer_set(rect, E_LAYER_MENU - 1);
evas_object_show(rect);
evas_object_event_callback_add(rect, EVAS_CALLBACK_MOUSE_UP, _config_rect_click, obj);
return rect;
}
static void
_config_close(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
time_config->config_dialog = NULL;
}
static void
_config_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
time_config_update(data);
}
static void
_clock_color_dismissed(void *data EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
evas_object_del(obj);
}
static void
_config_color_reset(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Config_Item *ci = data;
Evas_Object *cs;
int num;
num = !evas_object_data_get(obj, "bg_color");
if (ci->colorclass[num])
{
elm_config_color_overlay_unset(ci->colorclass[num]);
edje_color_class_del(ci->colorclass[num]);
}
eina_stringshare_replace(&ci->colorclass[num], NULL);
cs = evas_object_data_get(obj, "colorselector");
elm_colorselector_color_set(cs, 0, 0, 0, 0);
elm_colorselector_palette_item_color_set(evas_object_data_get(cs, "colorselector_it"),
0, 0, 0, 0);
time_config_update(data);
}
static void
_config_color_change(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Config_Item *ci = data;
int r, g, b, a;
int num;
char buf[1024];
num = !evas_object_data_get(obj, "bg_color");
elm_colorselector_color_get(obj, &r, &g, &b, &a);
if (!ci->colorclass[num])
{
snprintf(buf, sizeof(buf), "e.clock_color_%s.%d", num ? "fg" : "bg", ci->id);
eina_stringshare_replace(&ci->colorclass[num], buf);
}
elm_config_color_overlay_set(ci->colorclass[num], r, g, b, a, 0, 0, 0, 0, 0, 0, 0, 0);
edje_color_class_set(ci->colorclass[num], r, g, b, a, 0, 0, 0, 0, 0, 0, 0, 0);
elm_colorselector_palette_item_color_set(evas_object_data_get(obj, "colorselector_it"), r, g, b, a);
time_config_update(data);
}
static void
_config_color_setup(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Config_Item *ci = data;
Evas_Object *cs, *ctx, *bx, *bt, *rect;
int r, g, b, a, x, y;
Eina_Bool bg;
const char *ccname, *ccnames[] =
{
"e.clock_color_bg",
"e.clock_color_fg",
};
bg = !!evas_object_data_get(obj, "bg_color");
ccname = ci->colorclass[!bg];
if (!ccname) ccname = ccnames[!bg];
edje_color_class_get(ccname, &r, &g, &b, &a,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
bx = elm_box_add(obj);
E_FILL(bx);
evas_object_show(bx);
cs = elm_colorselector_add(obj);
evas_object_data_set(cs, "colorselector_bt", evas_object_data_get(obj, "colorselector_tt"));
evas_object_data_set(cs, "bg_color", (void*)(long)bg);
evas_object_smart_callback_add(cs, "changed,user", _config_color_change, ci);
elm_colorselector_mode_set(cs, ELM_COLORSELECTOR_COMPONENTS);
elm_colorselector_color_set(cs, r, g, b, a);
E_FILL(cs);
elm_box_pack_end(bx, cs);
evas_object_show(cs);
bt = elm_button_add(bx);
evas_object_data_set(bt, "colorselector", cs);
evas_object_data_set(bt, "bg_color", (void*)(long)bg);
elm_object_text_set(bt, _("Reset"));
evas_object_smart_callback_add(bt, "clicked", _config_color_reset, ci);
evas_object_show(bt);
elm_box_pack_end(bx, bt);
/* size hints: the final frontier */
rect = evas_object_rectangle_add(e_comp->elm);
evas_object_geometry_get(time_config->config_dialog, NULL, NULL, &x, &y);
evas_object_size_hint_min_set(rect, x - 10, 1);
e_comp_object_util_del_list_append(bx, rect);
elm_box_pack_end(bx, rect);
ctx = elm_ctxpopup_add(obj);
elm_ctxpopup_hover_parent_set(ctx, e_comp->elm);
evas_object_layer_set(ctx, E_LAYER_MENU);
elm_object_style_set(ctx, "noblock");
e_comp_object_util_del_list_append(ctx, _config_autoclose_rect_add(ctx));
evas_object_smart_callback_add(ctx, "dismissed", _clock_color_dismissed, NULL);
elm_object_content_set(ctx, bx);
evas_pointer_canvas_xy_get(e_comp->evas, &x, &y);
evas_object_move(ctx, x, y);
evas_object_show(ctx);
}
static void
_config_digital_timestr_update(Config_Item *ci, Evas_Object *obj, int idx)
{
const char *str, *p;
char seconds[] =
{
'S',
's',
'r',
'T',
};
unsigned int i;
str = elm_entry_entry_get(obj);
eina_stringshare_replace(&ci->time_str[idx], str);
ci->show_seconds = 0;
for (p = strchr(str, '%'); p; p = strchr(p + 1, '%'))
{
for (i = 0; i < EINA_C_ARRAY_LENGTH(seconds); i++)
if (p[1] == seconds[i])
{
ci->show_seconds = 1;
time_config_update(ci);
return;
}
}
time_config_update(ci);
}
static void
_config_digital_datestr_changed(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
_config_digital_timestr_update(data, obj, 1);
}
static Evas_Object *
_config_date_custom(Config_Item *ci, Evas_Object *bx)
{
Evas_Object *o;
o = elm_entry_add(bx);
elm_entry_single_line_set(o, 1);
elm_object_tooltip_text_set(o, _("strftime() format string"));
elm_entry_entry_set(o, ci->time_str[1]);
evas_object_smart_callback_add(o, "changed,user", _config_digital_datestr_changed, ci);
E_FILL(o);
E_EXPAND(o);
evas_object_show(o);
elm_box_pack_end(bx, o);
return o;
}
static void
_config_date_changed(void *data, Evas_Object *obj, void *event_info)
{
Config_Item *ci = data;
Evas_Object *bx = elm_object_parent_widget_get(obj);
Eina_Bool custom;
custom = ci->show_date == CLOCK_DATE_DISPLAY_CUSTOM;
ci->show_date = (intptr_t)elm_object_item_data_get(event_info);
if (custom)
{
elm_box_unpack(bx, obj);
elm_box_clear(bx);
E_FILL(obj);
E_EXPAND(obj);
elm_box_pack_end(bx, obj);
}
else if (ci->show_date == CLOCK_DATE_DISPLAY_CUSTOM)
{
E_WEIGHT(obj, 0, 0);
E_ALIGN(obj, 0, 0.5);
elm_object_focus_set(_config_date_custom(ci, bx), 1);
}
time_config_update(ci);
}
static void
_config_weekend_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Config_Item *ci = data;
ci->weekend.start = (intptr_t)elm_object_item_data_get(event_info);
time_config_update(ci);
}
static void
_config_weekend_end_changed(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Config_Item *ci = data;
int end;
end = (intptr_t)elm_object_item_data_get(event_info);
if (end < ci->weekend.start) end += 7;
ci->weekend.len = end - ci->weekend.start + 1;
time_config_update(ci);
}
static void
_config_date_populate(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Config_Item *ci = data;
unsigned int i;
elm_hoversel_clear(obj);
for (i = 0; i <= 5; i++)
if (ci->show_date != i)
elm_hoversel_item_add(obj, datecfg[i], NULL, ELM_ICON_NONE, NULL, (uintptr_t*)(unsigned long)i);
}
static void
_config_weekend_populate(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Config_Item *ci = data;
char daynames[7][64];
struct tm tm;
int i;
memset(&tm, 0, sizeof(struct tm));
for (i = 0; i < 7; i++)
{
tm.tm_wday = i;
strftime(daynames[i], sizeof(daynames[i]), "%A", &tm);
}
elm_hoversel_clear(obj);
for (i = ci->weekend.start + 1; i <= 6; i++)
if (ci->weekend.start != i)
elm_hoversel_item_add(obj, daynames[i], NULL, ELM_ICON_NONE, NULL, (intptr_t*)(long)i);
for (i = 0; i < ci->weekend.start; i++)
elm_hoversel_item_add(obj, daynames[i], NULL, ELM_ICON_NONE, NULL, (intptr_t*)(long)i);
}
static void
_config_weekend_end_populate(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Config_Item *ci = data;
char daynames[7][64];
struct tm tm;
int i, end;
memset(&tm, 0, sizeof(struct tm));
for (i = 0; i < 7; i++)
{
tm.tm_wday = i;
strftime(daynames[i], sizeof(daynames[i]), "%A", &tm);
}
elm_hoversel_clear(obj);
end = (ci->weekend.start + ci->weekend.len - 1) % 7;
for (i = end + 1; i <= 6; i++)
if (end != i)
elm_hoversel_item_add(obj, daynames[i], NULL, ELM_ICON_NONE, NULL, (intptr_t*)(long)i);
for (i = 0; i < end; i++)
elm_hoversel_item_add(obj, daynames[i], NULL, ELM_ICON_NONE, NULL, (intptr_t*)(long)i);
}
static void
_config_timezone_setup(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Evas_Object *hover, *gl;
hover = elm_hover_add(e_comp->elm);
evas_object_layer_set(hover, E_LAYER_MENU);
elm_hover_parent_set(hover, elm_object_parent_widget_get(obj));
elm_hover_target_set(hover, elm_object_parent_widget_get(obj));
gl = elm_genlist_add(hover);
evas_object_layer_set(gl, E_LAYER_MENU);
evas_object_data_set(gl, "config_item", data);
evas_object_data_set(gl, "button", obj);
elm_genlist_mode_set(gl, ELM_LIST_COMPRESS);
elm_genlist_homogeneous_set(gl, 1);
elm_scroller_bounce_set(gl, 0, 0);
evas_object_show(gl);
elm_object_part_content_set(hover, "middle", gl);
time_zoneinfo_scan(gl);
e_comp_object_util_del_list_append(gl, hover);
e_comp_object_util_del_list_append(gl, _config_autoclose_rect_add(gl));
evas_object_show(hover);
}
static void
_config_digital_timestr_changed(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
_config_digital_timestr_update(data, obj, 0);
}
static void
_config_label_add(Evas_Object *tb, const char *txt, int row)
{
Evas_Object *o;
o = elm_label_add(tb);
E_ALIGN(o, 0, 0.5);
elm_object_text_set(o, txt);
evas_object_show(o);
elm_table_pack(tb, o, 0, row, 1, 1);
}
static void
_config_digital_rows_setup(Config_Item *ci, Evas_Object *tb)
{
int row = 1;
Evas_Object *o;
evas_object_del(elm_table_child_get(tb, 0, 1));
evas_object_del(elm_table_child_get(tb, 1, 1));
evas_object_del(elm_table_child_get(tb, 0, 2));
evas_object_del(elm_table_child_get(tb, 1, 2));
if (ci->advanced)
{
_config_label_add(tb, _("Time string:"), row);
o = elm_entry_add(tb);
E_FILL(o);
evas_object_show(o);
elm_entry_single_line_set(o, 1);
elm_entry_entry_set(o, ci->time_str[0]);
elm_object_focus_set(o, 1);
evas_object_smart_callback_add(o, "changed,user", _config_digital_timestr_changed, ci);
elm_table_pack(tb, o, 1, row++, 1, 1);
o = elm_separator_add(tb);
E_EXPAND(o);
E_FILL(o);
elm_separator_horizontal_set(o, 1);
evas_object_show(o);
elm_table_pack(tb, o, 0, row++, 2, 1);
return;
}
if (ci->digital_clock)
{
_config_label_add(tb, _("24-hour Display:"), row);
o = elm_check_add(tb);
E_FILL(o);
evas_object_show(o);
elm_object_style_set(o, "toggle");
elm_object_part_text_set(o, "on", "On");
elm_object_part_text_set(o, "off", "Off");
elm_check_state_pointer_set(o, &ci->digital_24h);
evas_object_smart_callback_add(o, "changed", _config_changed, ci);
elm_table_pack(tb, o, 1, row++, 1, 1);
}
_config_label_add(tb, _("Show Seconds:"), row);
o = elm_check_add(tb);
E_FILL(o);
evas_object_show(o);
elm_object_style_set(o, "toggle");
elm_object_part_text_set(o, "on", _("On"));
elm_object_part_text_set(o, "off", _("Off"));
elm_check_state_pointer_set(o, &ci->show_seconds);
evas_object_smart_callback_add(o, "changed", _config_changed, ci);
elm_table_pack(tb, o, 1, row++, 1, 1);
}
static void
_config_advanced_changed(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
{
Config_Item *ci = data;
_config_digital_rows_setup(data, evas_object_data_get(obj, "table"));
time_config_update(ci);
}
EINTERN Evas_Object *
config_clock(Config_Item *ci)
{
Evas_Object *popup, *tb, *o, *bx;
int i, row = 0;
char daynames[7][64];
struct tm tm;
memset(&tm, 0, sizeof(struct tm));
for (i = 0; i < 7; i++)
{
tm.tm_wday = i;
strftime(daynames[i], sizeof(daynames[i]), "%A", &tm);
}
popup = elm_popup_add(e_comp->elm);
E_EXPAND(popup);
evas_object_layer_set(popup, E_LAYER_POPUP);
elm_popup_allow_events_set(popup, 1);
elm_popup_scrollable_set(popup, 1);
tb = elm_table_add(popup);
E_EXPAND(tb);
evas_object_show(tb);
elm_object_content_set(popup, tb);
if (ci->digital_clock)
{
_config_label_add(tb, _("Mode"), row);
o = elm_check_add(tb);
E_FILL(o);
evas_object_show(o);
elm_object_style_set(o, "toggle");
elm_object_part_text_set(o, "on", _("Advanced"));
elm_object_part_text_set(o, "off", _("Simple"));
elm_check_state_pointer_set(o, &ci->advanced);
evas_object_smart_callback_add(o, "changed", _config_advanced_changed, ci);
evas_object_data_set(o, "table", tb);
elm_table_pack(tb, o, 1, row++, 1, 1);
}
_config_digital_rows_setup(ci, tb);
row = 3;
_config_label_add(tb, _("Date Display:"), row);
bx = elm_box_add(tb);
elm_box_horizontal_set(bx, 1);
evas_object_show(bx);
elm_table_pack(tb, bx, 1, row++, 1, 1);
E_FILL(bx);
E_EXPAND(bx);
o = elm_hoversel_add(tb);
elm_box_pack_end(bx, o);
elm_hoversel_hover_parent_set(o, popup);
elm_hoversel_auto_update_set(o, 1);
evas_object_show(o);
evas_object_smart_callback_add(o, "clicked", _config_date_populate, ci);
evas_object_smart_callback_add(o, "selected", _config_date_changed, ci);
elm_object_text_set(o, datecfg[ci->show_date]);
if (ci->show_date == CLOCK_DATE_DISPLAY_CUSTOM)
{
E_ALIGN(o, 0, 0.5);
E_WEIGHT(o, 0, 0);
o = _config_date_custom(ci, bx);
}
else
{
E_FILL(o);
E_EXPAND(o);
}
_config_label_add(tb, _("Weekend Start:"), row);
o = elm_hoversel_add(tb);
E_FILL(o);
elm_hoversel_hover_parent_set(o, popup);
elm_hoversel_auto_update_set(o, 1);
evas_object_show(o);
elm_table_pack(tb, o, 1, row++, 1, 1);
elm_object_text_set(o, daynames[ci->weekend.start]);
evas_object_smart_callback_add(o, "clicked", _config_weekend_populate, ci);
evas_object_smart_callback_add(o, "selected", _config_weekend_changed, ci);
_config_label_add(tb, _("Weekend End:"), row);
o = elm_hoversel_add(tb);
E_FILL(o);
elm_hoversel_hover_parent_set(o, popup);
elm_hoversel_auto_update_set(o, 1);
evas_object_show(o);
elm_table_pack(tb, o, 1, row++, 1, 1);
elm_object_text_set(o, daynames[(ci->weekend.start + ci->weekend.len - 1) % 7]);
evas_object_smart_callback_add(o, "clicked", _config_weekend_end_populate, ci);
evas_object_smart_callback_add(o, "selected", _config_weekend_end_changed, ci);
_config_label_add(tb, _("Timezone:"), row);
o = elm_button_add(tb);
E_FILL(o);
elm_object_text_set(o, ci->timezone ?: _("System"));
evas_object_show(o);
evas_object_smart_callback_add(o, "clicked", _config_timezone_setup, ci);
elm_table_pack(tb, o, 1, row++, 1, 1);
for (i = 0; i <= 1; i++)
{
const char *ccname, *names[] =
{
N_("Background"),
N_("Foreground"),
};
const char *ccnames[] =
{
"e.clock_color_bg",
"e.clock_color_fg",
};
Evas_Object *cs;
Elm_Object_Item *it;
int r, g, b, a;
cs = elm_colorselector_add(tb);
elm_colorselector_mode_set(cs, ELM_COLORSELECTOR_PALETTE);
ccname = ci->colorclass[i];
if (!ccname) ccname = ccnames[i];
edje_color_class_get(ccname, &r, &g, &b, &a,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
it = elm_colorselector_palette_color_add(cs, r, g, b, a);
o = elm_button_add(tb);
elm_object_text_set(o, names[i]);
elm_object_content_set(o, cs);
E_FILL(o);
if (!i)
evas_object_data_set(o, "bg_color", (void*)1L);
evas_object_data_set(o, "colorselector_it", it);
evas_object_smart_callback_add(o, "clicked", _config_color_setup, ci);
evas_object_show(o);
elm_table_pack(tb, o, i, row, 1, 1);
}
popup = e_comp_object_util_add(popup, E_COMP_OBJECT_TYPE_NONE);
evas_object_layer_set(popup, E_LAYER_POPUP);
evas_object_resize(popup, e_zone_current_get()->w / 4, e_zone_current_get()->h / 3);
e_comp_object_util_center(popup);
evas_object_show(popup);
e_comp_object_util_autoclose(popup, NULL, e_comp_object_util_autoclose_on_escape, NULL);
evas_object_event_callback_add(popup, EVAS_CALLBACK_DEL, _config_close, NULL);
return time_config->config_dialog = popup;
}
static char *
_config_timezone_text_get(const char *str, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
{
return strdup(str);
}
static void
_config_timezone_text_del(void *d, Evas_Object *obj EINA_UNUSED)
{
free(d);
}
static int
_config_timezone_sort(void *ita, void *itb)
{
const char *a, *b;
a = elm_object_item_data_get(ita);
b = elm_object_item_data_get(itb);
return strcmp(a, b);
}
static void
_config_timezone_set(void *data EINA_UNUSED, Evas_Object *obj, void *event_info)
{
char *tz = elm_object_item_data_get(event_info);
Config_Item *ci;
Evas_Object *bt;
ci = evas_object_data_get(obj, "config_item");
bt = evas_object_data_get(obj, "button");
eina_stringshare_replace(&ci->timezone, tz);
elm_object_text_set(bt, tz);
time_config_update(ci);
evas_object_del(obj);
}
EINTERN void
config_timezone_populate(Evas_Object *obj, const char *name)
{
static const Elm_Genlist_Item_Class itc =
{
.item_style = "default",
.func = {
.text_get = (Elm_Genlist_Item_Text_Get_Cb)_config_timezone_text_get,
.del = _config_timezone_text_del,
},
.version = ELM_GENLIST_ITEM_CLASS_VERSION
};
Config_Item *ci;
Elm_Object_Item *it;
it = elm_genlist_item_sorted_insert(obj, &itc, strdup(name), NULL, 0, (Eina_Compare_Cb)_config_timezone_sort, _config_timezone_set, NULL);
ci = evas_object_data_get(obj, "config_item");
if (eina_streq(name, ci->timezone))
elm_genlist_item_bring_in(it, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
}

Binary file not shown.

142
src/modules/time/mod.c Normal file
View File

@ -0,0 +1,142 @@
#include "clock.h"
static E_Config_DD *conf_edd = NULL;
static E_Config_DD *conf_item_edd = NULL;
static E_Action *act = NULL;
static void
_e_mod_action_cb(E_Object *obj EINA_UNUSED, const char *params, ...)
{
Eina_List *l;
Instance *inst;
if (!eina_streq(params, "show_calendar")) return;
EINA_LIST_FOREACH(clock_instances, l, inst)
if (inst->popup)
{
elm_ctxpopup_dismiss(inst->popup);
inst->popup = NULL;
}
else
clock_popup_new(inst);
}
EINTERN void
clock_init(void)
{
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, INT);
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);
E_CONFIG_VAL(D, T, advanced, UCHAR);
E_CONFIG_VAL(D, T, timezone, STR);
E_CONFIG_VAL(D, T, time_str[0], STR);
E_CONFIG_VAL(D, T, time_str[1], STR);
E_CONFIG_VAL(D, T, colorclass[0], STR);
E_CONFIG_VAL(D, T, colorclass[1], STR);
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);
time_config = e_config_domain_load("module.time", conf_edd);
if (!time_config)
time_config = E_NEW(Config, 1);
act = e_action_add("clock");
if (act)
{
act->func.go = (void*)_e_mod_action_cb;
act->func.go_key = (void*)_e_mod_action_cb;
act->func.go_mouse = (void*)_e_mod_action_cb;
act->func.go_edge = (void*)_e_mod_action_cb;
e_action_predef_name_set(N_("Clock"), N_("Toggle calendar"), "clock", "show_calendar", NULL, 0);
}
e_gadget_type_add("Digital Clock", digital_clock_create, digital_clock_wizard);
e_gadget_type_add("Analog Clock", analog_clock_create, analog_clock_wizard);
time_init();
}
EINTERN void
clock_shutdown(void)
{
if (act)
{
e_action_predef_name_del("Clock", "Toggle calendar");
e_action_del("clock");
act = NULL;
}
if (time_config)
{
Config_Item *ci;
if (time_config->config_dialog)
{
evas_object_hide(time_config->config_dialog);
evas_object_del(time_config->config_dialog);
}
EINA_LIST_FREE(time_config->items, ci)
{
eina_stringshare_del(ci->timezone);
eina_stringshare_del(ci->time_str[0]);
eina_stringshare_del(ci->time_str[1]);
eina_stringshare_del(ci->colorclass[0]);
eina_stringshare_del(ci->colorclass[1]);
free(ci);
}
E_FREE(time_config);
}
E_CONFIG_DD_FREE(conf_edd);
E_CONFIG_DD_FREE(conf_item_edd);
e_gadget_type_del("Digital Clock");
e_gadget_type_del("Analog Clock");
time_shutdown();
}
/* module setup */
E_API E_Module_Api e_modapi =
{
E_MODULE_API_VERSION,
"Time"
};
E_API void *
e_modapi_init(E_Module *m)
{
clock_init();
time_config->module = m;
return m;
}
E_API int
e_modapi_shutdown(E_Module *m EINA_UNUSED)
{
clock_shutdown();
return 1;
}
E_API int
e_modapi_save(E_Module *m EINA_UNUSED)
{
e_config_domain_save("module.time", conf_edd, time_config);
return 1;
}

View File

@ -0,0 +1,7 @@
[Desktop Entry]
Encoding=UTF-8
Type=Link
Name=Time
Comment=Time-related gadgets and utilities
Icon=e-module-time
X-Enlightenment-ModuleType=utils

354
src/modules/time/time.c Normal file
View File

@ -0,0 +1,354 @@
#include "clock.h"
#include <sys/time.h>
#include <time.h>
static Eio_Monitor *clock_te_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;
#define ZONEINFO_DIR "/usr/share/zoneinfo/posix"
#define ZONEINFO_DIR_LEN sizeof(ZONEINFO_DIR) - 1
#define TE_DECL \
const char *tzenv; \
char prevtz[128] = {0}
#define TZSET(inst) \
tzenv = getenv("TZ"); \
if (tzenv) \
strncpy(prevtz, tzenv, sizeof(prevtz) - 1); \
if (inst->cfg->timezone) \
setenv("TZ", inst->cfg->timezone, 1); \
tzset()
#define TZUNSET() \
if (prevtz[0]) \
setenv("TZ", prevtz, 1); \
else \
unsetenv("TZ"); \
tzset()
static void
_zoneinfo_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
eio_file_cancel(data);
}
static void
_zoneinfo_done(void *data, Eio_File *handler EINA_UNUSED)
{
evas_object_event_callback_del(data, EVAS_CALLBACK_DEL, _zoneinfo_del);
}
static void
_zoneinfo_error(void *data, Eio_File *handler EINA_UNUSED, int error EINA_UNUSED)
{
evas_object_event_callback_del(data, EVAS_CALLBACK_DEL, _zoneinfo_del);
}
static Eina_Bool
_zoneinfo_filter(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, const Eina_File_Direct_Info *info)
{
return (info->type == EINA_FILE_REG) || (info->type == EINA_FILE_DIR);
}
static void
_zoneinfo_main(void *data, Eio_File *handler EINA_UNUSED, const Eina_File_Direct_Info *info)
{
if (info->type == EINA_FILE_REG)
config_timezone_populate(data, &info->path[ZONEINFO_DIR_LEN + 1]);
else
{
Eio_File *ls;
ls = eio_file_direct_ls(info->path, _zoneinfo_filter, _zoneinfo_main, _zoneinfo_done, _zoneinfo_error, data);
evas_object_event_callback_add(data, EVAS_CALLBACK_DEL, _zoneinfo_del, ls);
}
}
EINTERN void
time_zoneinfo_scan(Evas_Object *obj)
{
Eio_File *ls;
ls = eio_file_direct_ls(ZONEINFO_DIR, _zoneinfo_filter, _zoneinfo_main, _zoneinfo_done, _zoneinfo_error, obj);
evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _zoneinfo_del, ls);
}
EINTERN void
time_daynames_clear(Instance *inst)
{
int x;
for (x = 0; x < 7; x++)
eina_stringshare_replace(&inst->daynames[x], NULL);
}
EINTERN void
time_datestring_format(Instance *inst, char *buf, int bufsz)
{
struct timeval timev;
struct tm *tm;
time_t tt;
const char *default_str = "%F";
TE_DECL;
buf[0] = 0;
if (!inst->cfg->show_date) return;
TZSET(inst);
gettimeofday(&timev, NULL);
tt = (time_t)(timev.tv_sec);
tm = localtime(&tt);
TZUNSET();
switch (inst->cfg->show_date)
{
case CLOCK_DATE_DISPLAY_FULL:
strftime(buf, bufsz, _("%a, %e %b, %Y"), (const struct tm *)tm);
break;
case CLOCK_DATE_DISPLAY_NUMERIC:
strftime(buf, bufsz, _("%a, %x"), (const struct tm *)tm);
break;
case CLOCK_DATE_DISPLAY_DATE_ONLY:
strftime(buf, bufsz, "%x", (const struct tm *)tm);
break;
case CLOCK_DATE_DISPLAY_ISO8601:
strftime(buf, bufsz, "%F", (const struct tm *)tm);
break;
case CLOCK_DATE_DISPLAY_CUSTOM:
if (!strftime(buf, bufsz, inst->cfg->time_str[1] ?: default_str, (const struct tm *)tm))
strncpy(buf, "ERROR", bufsz - 1);
break;
default: break;
}
}
EINTERN int
time_string_format(Instance *inst, char *buf, int bufsz)
{
struct timeval timev;
struct tm *tm;
time_t tt;
const char *default_fmt = "%R";
TE_DECL;
buf[0] = 0;
TZSET(inst);
gettimeofday(&timev, NULL);
tt = (time_t)(timev.tv_sec);
tm = localtime(&tt);
TZUNSET();
if (!strftime(buf, bufsz, inst->cfg->time_str[0] ?: default_fmt, (const struct tm *)tm))
strncpy(buf, "ERROR", bufsz - 1);
return tm->tm_sec;
}
EINTERN void
time_instance_update(Instance *inst)
{
struct timeval timev;
struct tm *tm, tms, tmm, tm2;
time_t tt;
int started = 0, num, i;
int day;
tzset();
gettimeofday(&timev, NULL);
tt = (time_t)(timev.tv_sec);
tm = localtime(&tt);
time_daynames_clear(inst);
if (!tm) return;
// 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_te_monitor) ||
(ev->monitor == clock_tz2_monitor) ||
(ev->monitor == clock_tzetc_monitor))
{
if (eina_streq(ev->filename, "/etc/localtime") ||
eina_streq(ev->filename, "/etc/timezone"))
clock_instances_redo();
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_clock_time_update(void *d EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
{
clock_instances_redo();
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_te_monitor) ||
(ev->monitor == clock_tz2_monitor) ||
(ev->monitor == clock_tzetc_monitor))
{
E_FREE_FUNC(clock_te_monitor, eio_monitor_del);
if (ecore_file_exists("/etc/localtime"))
clock_te_monitor = eio_monitor_add("/etc/localtime");
E_FREE_FUNC(clock_tz2_monitor, eio_monitor_del);
if (ecore_file_exists("/etc/timezone"))
clock_tz2_monitor = eio_monitor_add("/etc/timezone");
E_FREE_FUNC(clock_tzetc_monitor, eio_monitor_del);
if (ecore_file_is_dir("/etc"))
clock_tzetc_monitor = eio_monitor_add("/etc");
}
return ECORE_CALLBACK_PASS_ON;
}
EINTERN void
time_init(void)
{
if (ecore_file_exists("/etc/localtime"))
clock_te_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");
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);
_update_today_timer(NULL);
}
EINTERN void
time_shutdown(void)
{
E_FREE_FUNC(update_today, ecore_timer_del);
E_FREE_FUNC(clock_te_monitor, eio_monitor_del);
E_FREE_FUNC(clock_tz2_monitor, eio_monitor_del);
E_FREE_FUNC(clock_tzetc_monitor, eio_monitor_del);
}