X-Git-Url: http://git.maemo.org/git/?p=espeaktime;a=blobdiff_plain;f=src%2Fdaemon.c;h=065c99010822d8287b3ddd3345feb5478874aebc;hp=50bc2c9992a356a9cd67e6b0897b839fdafd97bb;hb=f8ea8092025549dd33256b2ec80ef8167cade30b;hpb=2cda80cf3e013567e14f1c762ee20fa40a1d275b diff --git a/src/daemon.c b/src/daemon.c index 50bc2c9..065c990 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -1,4 +1,204 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define HAL_COND_BUTTONPRESSED "ButtonPressed" +#define HAL_BUTTON_POWER "power" +#define HAL_INPUTDEV_PATH "/org/freedesktop/Hal/devices/computer_logicaldev_input" + +struct app_data { + DBusGConnection *bus; + LibHalContext *hal; + + gboolean mode_locked; + gboolean display_on; + time_t last_press; + unsigned press_count; +}; + +static void speak_time(struct app_data *app) +{ + int res = system("espeaktime-now.sh"); + g_debug("speak script: %d", res); +} + +static void sig_tklock_mode(DBusGProxy *proxy, const char *mode, gpointer user_data) +{ + struct app_data *app = user_data; + g_debug("sig_tklock_mode [%s]", mode); + app->mode_locked = !strcmp(mode, MCE_TK_LOCKED); +} + +static void sig_display_status(DBusGProxy *proxy, const char *status, gpointer user_data) +{ + struct app_data *app = user_data; + g_debug("sig_display_status [%s]", status); + app->display_on = !strcmp(status, MCE_DISPLAY_ON_STRING); + + /* Double-pressing the button at a normal rate will usually result + * in the two ButtonPress events being received before the display_status==on + * event. Check here if that's the case. + */ + if (app->display_on && app->press_count > 1 && time(NULL) - app->last_press <= 1) + speak_time(app); +} + +static void debug_log(const gchar *log_domain, + GLogLevelFlags log_level, const gchar *message, gpointer unused_data) +{ + g_print("# %s\n", message); +} + +static void power_button(struct app_data *app) +{ + time_t now; + + time(&now); + if (now - app->last_press > 1) + app->press_count = 0; + app->press_count++; + app->last_press = now; + + g_debug("power button: count=%d", app->press_count); + if (app->mode_locked && app->display_on) + speak_time(app); +} + +/** + * Call a method with no input arguments and one string output argument. + * Return the allocaed result string on success, NULL on failure. + */ +static char *mce_call_getstr(DBusGProxy *proxy, const char *method) +{ + GError *err = NULL; + char *s = NULL; + + if (dbus_g_proxy_call(proxy, method, &err, + G_TYPE_INVALID, + G_TYPE_STRING, &s, G_TYPE_INVALID)) + return s; + + g_error("Couldn't call MCE (%s): %s\n", method, err->message); + g_error_free(err); + return NULL; +} + +static gboolean prefill_status(struct app_data *app) +{ + DBusGProxy *mce_req; + char *mode, *status; + + mce_req = dbus_g_proxy_new_for_name(app->bus, MCE_SERVICE, MCE_REQUEST_PATH, MCE_REQUEST_IF); + g_assert(mce_req); + + mode = mce_call_getstr(mce_req, MCE_TKLOCK_MODE_GET); + status = mce_call_getstr(mce_req, MCE_DISPLAY_STATUS_GET); + if (mode) + sig_tklock_mode(NULL, mode, app); + if (status) + sig_display_status(NULL, status, app); + g_free(mode); + g_free(status); + g_object_unref(mce_req); + + return mode && status; +} + +static void connect_signals(struct app_data *app) +{ + DBusGProxy *mce_sig; + + mce_sig = dbus_g_proxy_new_for_name(app->bus, MCE_SERVICE, MCE_SIGNAL_PATH, MCE_SIGNAL_IF); + g_assert(mce_sig); + dbus_g_proxy_add_signal(mce_sig, MCE_TKLOCK_MODE_SIG, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_add_signal(mce_sig, MCE_DISPLAY_SIG, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(mce_sig, MCE_TKLOCK_MODE_SIG, G_CALLBACK(sig_tklock_mode), app, NULL); + dbus_g_proxy_connect_signal(mce_sig, MCE_DISPLAY_SIG, G_CALLBACK(sig_display_status), app, NULL); +} + + +static void device_condition(LibHalContext *ctx, + const char *udi, + const char *condition_name, + const char *condition_detail) +{ + g_debug("device_condition: name [%s] detail [%s]", + condition_name, condition_detail); + if (!strcmp(condition_name, HAL_COND_BUTTONPRESSED) && !strcmp(condition_detail, HAL_BUTTON_POWER)) { + struct app_data *app = libhal_ctx_get_user_data(ctx); + power_button(app); + } +} + + +static gboolean init_hal(struct app_data *app) +{ + DBusError err; + + app->hal = libhal_ctx_new(); + if (!app->hal) { + g_error("Couldn't get a HAL context"); + return FALSE; + } + libhal_ctx_set_dbus_connection(app->hal, + dbus_g_connection_get_connection(app->bus)); + libhal_ctx_set_device_condition(app->hal, device_condition); + libhal_ctx_set_user_data(app->hal, app); + + dbus_error_init(&err); + if (!libhal_ctx_init(app->hal, &err)) { + g_error("Couldn't initialize HAL context: %s", err.message); + dbus_error_free(&err); + libhal_ctx_free(app->hal); + return FALSE; + } + + if (!libhal_device_add_property_watch(app->hal, HAL_INPUTDEV_PATH, &err)) { + g_error("Couldn't add HAL watch: %s", err.message); + dbus_error_free(&err); + libhal_ctx_free(app->hal); + } + return TRUE; +} + int main(int argc, char *argv[]) { + GMainLoop *loop; + GError *err = NULL; + struct app_data app; + + if (argc > 1 && !strcmp(argv[1], "-v")) + g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, debug_log, NULL); + + g_debug("init"); + memset(&app, 0, sizeof(app)); + + g_type_init(); + loop = g_main_loop_new(NULL, FALSE); + + app.bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &err); + if (!app.bus) { + g_error("Couldn't get DBUS connection: %s\n", err->message); + g_error_free(err); + return 1; + } + + if (!init_hal(&app)) + return 1; + + if (!prefill_status(&app)) + return 1; + connect_signals(&app); + + g_debug("running"); + g_main_loop_run(loop); + dbus_g_connection_unref(app.bus); return 0; }