#ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include "gettext.h" #include "eulogium.h" #define COPYRIGHT "Copyright © 2015 Olliver Schinagl and various contributors (see AUTHORS)." #define SECOND 1UL #define MINUTE (60UL * SECOND) #define HOUR (60UL * MINUTE) #define DAY (24UL * HOUR) #define WEEK (7UL * DAY) #define MONTH (4UL * WEEK) #define YEAR (52UL * WEEK) static void _on_print_abort_ret(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED); static void _cb_content_prev_set(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED); static void _print_abort_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED); static void _on_blink_ret(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED); static void _but_maint_bp_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED); static void _but_mat_ch_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED); static void _but_mat_set_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED); static void _eulogium_button_main_maintanance_cb(void *data, Evas_Object *object EINA_UNUSED, void *event_info EINA_UNUSED); static void _cb_button_main_print(void *data, Evas_Object *object EINA_UNUSED, void *event_info EINA_UNUSED); static void _but_print_local_cb(void *data, Evas_Object *object EINA_UNUSED, void *event_info EINA_UNUSED); static void _but_print_usb_cb(void *data, Evas_Object *object EINA_UNUSED, void *event_info EINA_UNUSED); static void _but_maint_adv_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED); static void _eulogium_button_main_mat_cb(void *data, Evas_Object *object EINA_UNUSED, void *event_info EINA_UNUSED); /* Buttons */ static struct button_def but_return = { .text = "RETURN", .cb = { .func = &_cb_content_prev_set, .data = NULL, .info = "return button pressed", }, .data = NULL, }; static struct button_def but_print_abort = { .text = "ABORT", .cb = { .func = &_print_abort_cb, .data = NULL, .info = "print abort button pressed", }, .data = NULL, }; static struct button_def but_print_progress_tune = { .text = "TUNE", .cb = { .func = NULL, .data = NULL, .info = "tune progress button pressed", }, .data = NULL, }; static struct button_def but_main_print = { .text = "PRINT", .cb = { .func = &_cb_button_main_print, .data = NULL, .info = "print button pressed", }, .data = NULL, }; static struct button_def but_print_local = { .text = "LOCAL", .cb = { .func = &_but_print_local_cb, .data = NULL, .info = "local storage button pressed", }, .data = NULL, }; static struct button_def but_print_mmc = { .text = "SD", .cb = { .func = &_but_print_usb_cb, .data = NULL, .info = "usb storage button pressed", }, .data = NULL, }; static struct button_def but_print_usb = { .text = "USB", .cb = { .func = &_but_print_usb_cb, .data = NULL, .info = "usb storage button pressed", }, .data = NULL, }; static struct button_def but_main_material = { .text = "MATERIAL", .cb = { .func = &_eulogium_button_main_mat_cb, .data = NULL, .info = "material button pressed", }, .data = NULL, }; static struct button_def but_main_maintanance = { .text = "MAINTANANCE", .cb = { .func = &_eulogium_button_main_maintanance_cb, .data = NULL, .info = "maintenance button pressed", }, .data = NULL, }; static struct button_def but_maintanance_advanced = { .text = "ADVANCED", .cb = { .func = &_but_maint_adv_cb, .data = NULL, }, .data = NULL, }; static struct button_def but_maintanance_buildplate = { .text = "BUILD-PLATE", .cb = { .func = &_but_maint_bp_cb, .data = NULL, }, .data = NULL, }; static struct button_def but_mat_change = { .text = "CHANGE", .cb = { .func = &_but_mat_ch_cb, .data = NULL, }, .data = NULL, }; static struct button_def but_mat_settings = { .text = "SETTINGS", .cb = { .func = &_but_mat_set_cb, .data = NULL, }, .data = NULL, }; static void eulogium_print_data_clear(struct eulogium_data *eulogium) { if (eulogium->progress_data_refresh) ecore_timer_del(eulogium->progress_data_refresh); eulogium->progress_data_refresh = NULL; eulogium->progress = NULL; /* XXX memleak here? when or how is this freeed by efl */ eulogium->status = NULL; /* XXX memleak here too? how does efl do it */ eulogium->time = NULL; /* XXX memleak here too? how does efl do it */ eulogium->name = NULL; /* XXX memleak here too? how does efl do it */ // if (eulogium->print.name) // free(eulogium->print.name); eulogium->print.name = NULL; eulogium->print.name_changed = EINA_FALSE; // if (eulogium->print.file) // free(eulogium->print.file); eulogium->print.file = NULL; eulogium->print.time = 0; eulogium->print.material = 0; eulogium->print.progress = 0; eulogium->print.flags = ""; } static void _on_print_abort_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { struct eulogium_data *eulogium = data; const char *errname, *errmsg; Eina_Bool print_abort = EINA_FALSE; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "b", &print_abort)) { EINA_LOG_ERR("Failed to abort print."); return; } if (print_abort == EINA_TRUE) { EINA_LOG_INFO("Successfully aborted print."); eulogium_print_data_clear(eulogium); } else { EINA_LOG_WARN("Unable to abort print."); } } static void _cb_content_prev_set(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = data; uint_fast8_t list_size; printf("prev ret\n"); list_size = eina_list_count(elm_naviframe_items_get(eulogium->navi)); if (list_size < 2) printf("Not popping last item cowboy\n"); /* TODO, use proper debug contruct */ else elm_naviframe_item_pop(eulogium->navi); } static void _print_abort_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = data; eldbus_proxy_call(eulogium->dbus.proxy[HARMA], "abortPrint", _on_print_abort_ret, eulogium, -1, ""); } static void _on_blink_ret(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { const char *errname, *errmsg; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } } static void _but_maint_bp_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = data; printf("But build-plate\n"); eldbus_proxy_call(eulogium->dbus.proxy[LED], "blink", _on_blink_ret, NULL, -1, ""); } static void _but_mat_ch_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { printf("But matterial change\n"); } static void _but_mat_set_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { printf("But matterial settings\n"); } static void _eulogium_button_main_maintanance_cb(void *data, Evas_Object *object EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = data; Evas_Object *content; printf("Button maintanance pressed\n"); content = eulogium_tripple_button_menu(eulogium->navi, &but_maintanance_buildplate, &but_maintanance_advanced, &but_return); if (!content) return; elm_naviframe_item_simple_push(eulogium->navi, content); } static void _but_print_local_cb(void *data, Evas_Object *object EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = data; Evas_Object *content; /* Fake entry for local storage, ideally this is a separate partition that is user mounted and trigged via the initial scan */ content = eulogium_print_menu(eulogium, "/home"); /* TODO: replace later with sane storage location */ if (!content) return; elm_naviframe_item_simple_push(eulogium->navi, content); } static void _but_print_usb_cb(void *data, Evas_Object *object EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = data; Evas_Object *content; struct mount_data *mount; /* Only care about last entry. Yes this is wrong as we need a UI element to handle this properly first. XXX */ mount = eina_list_data_get(eina_list_last(eulogium->mounts)); if (!mount) return; content = eulogium_print_menu(eulogium, (char *)eeze_disk_mount_point_get(mount->disk)); if (!content) return; elm_naviframe_item_simple_push(eulogium->navi, content); } static void _cb_button_main_print(void *data, Evas_Object *object EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = data; Evas_Object *content = NULL; struct mount_data *mount; /* TODO: Right now we just implement 1 or 2 buttons horizontally, ideally this should be something scrollable where more storage locations are usable */ if (eina_list_count(eulogium->mounts) < 1) { content = eulogium_print_menu(eulogium, "/home"); /* TODO: replace later with sane storage location */ } else { mount = eina_list_data_get(eina_list_last(eulogium->mounts)); if (!mount) return; if (eeze_disk_type_get(mount->disk) == EEZE_DISK_TYPE_FLASH) content = eulogium_tripple_button_menu(eulogium->navi, &but_print_local, &but_print_mmc, &but_return); if (eeze_disk_type_get(mount->disk) == EEZE_DISK_TYPE_USB) content = eulogium_tripple_button_menu(eulogium->navi, &but_print_local, &but_print_usb, &but_return); } if (!content) return; elm_naviframe_item_simple_push(eulogium->navi, content); } static void _but_maint_adv_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = data; Evas_Object *box, *object; printf("But maint advanced\n"); /* XXX Quick hack to make the adv feature a little more useful, this needs to be made much better! */ box = elm_box_add(eulogium->navi); evas_object_show(box); object = elm_label_add(box); elm_object_text_set(object, "Ethernet IP: 1.2.3.4
WiFi IP: 5.6.7.8"); /* TODO: text outline left */ evas_object_show(object); elm_box_pack_end(box, object); object = elm_button_add(box); elm_object_text_set(object, but_return.text); /* not pretty using the global XXX */ evas_object_smart_callback_add(object, "clicked", but_return.cb.func, but_return.cb.data); evas_object_show(object); elm_box_pack_end(box, object); elm_naviframe_item_simple_push(eulogium->navi, box); } static void _eulogium_button_main_mat_cb(void *data, Evas_Object *object EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = data; Evas_Object *content; printf("Button matts pressed\n"); content = eulogium_tripple_button_menu(eulogium->navi, &but_mat_change, &but_mat_settings, &but_return); if (!content) return; elm_naviframe_item_simple_push(eulogium->navi, content); } Evas_Object *eulogium_button_list_add(Evas_Object *parent) { Evas_Object *list, *box; Eina_List *l = NULL; list = elm_scroller_add(parent); evas_object_data_set(list, "eulogium_list", l); box = elm_box_add(list); evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, 0); evas_object_data_set(list, "content", box); elm_object_content_set(list, box); evas_object_show(box); return list; } Evas_Object *eulogium_button_list_prepend(Evas_Object *list, const char *label, Evas_Object *icon, Evas_Smart_Cb func, const void *data) { Evas_Object *box = evas_object_data_get(list, "content"); Eina_List *l = evas_object_data_get(list, "eulogium_list"); Evas_Object *button; if ((!box) && (!list)) return NULL; button = elm_button_add(box); if (label) elm_object_text_set(button, label); if (icon) elm_object_part_content_set(button, "icon", icon); if (func) evas_object_smart_callback_add(button, "clicked", func, data); evas_object_show(button); if (l) l = eina_list_prepend(l, button); else l = eina_list_prepend(NULL, button); evas_object_data_set(list, "eulogium_list", l); evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0); evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0); return button; } Evas_Object *eulogium_button_list_sorted_insert(Evas_Object *list, const char *label, Evas_Object *icon, Evas_Smart_Cb func, const void *data, Eina_Compare_Cb cmp_func) { Evas_Object *box = evas_object_data_get(list, "content"); Eina_List *l = evas_object_data_get(list, "eulogium_list"); Evas_Object *button; if ((!box) && (!list)) return NULL; button = elm_button_add(box); if (label) elm_object_text_set(button, label); if (icon) elm_object_part_content_set(button, "icon", icon); if (data) evas_object_data_set(button, "filelist_data", data); if (func) evas_object_smart_callback_add(button, "clicked", func, data); evas_object_show(button); if (l) l = eina_list_sorted_insert(l, cmp_func, button); else l = eina_list_sorted_insert(NULL, cmp_func, button); evas_object_data_set(list, "eulogium_list", l); evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, 0); evas_object_size_hint_align_set(button, EVAS_HINT_FILL, 0); return button; } void eulogium_button_list_go(Evas_Object *list) { Evas_Object *box = evas_object_data_get(list, "content"); Eina_List *l, *item_list = evas_object_data_get(list, "eulogium_list"); Evas_Object *button; if ((!box) && (!list)) return; EINA_LIST_FOREACH(item_list, l, button) elm_box_pack_end(box, button); } void eulogium_button_cb_set(struct button_def *button, struct button_cb *cb) { if (cb && button) button->cb = *cb; } void eulogium_button_cb_data_set(struct button_def *button, void *data) { if (data && button) button->cb.data = data; } void eulogium_button_data_set(struct button_def *button, void *data) { if (data && button) button->data = data; } void eulogium_print_data_set(struct eulogium_data *eulogium, char *filepath) { char *buf; size_t buf_size; if (!filepath) EINA_LOG_CRIT("Incorrect filename passed %s", filepath); buf_size = strlen(filepath) + strlen("file://") + 1; buf = malloc(buf_size); /* TODO: remember to free this later! */ snprintf(buf, buf_size, "file://%s", filepath); eulogium->print.file = buf; eulogium->print.name = ecore_file_strip_ext(ecore_file_file_get(filepath)); eulogium->print.flags = ""; eulogium->print.material = 100.23; /* TODO */ eulogium->print.time = 12; } /* Function to make the Z-axis of any wheel focus the next/previous focusable widget */ static void _cb_eulogium_input_wheel(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) { Evas_Event_Mouse_Wheel *ev = event_info; if (ev->z > 0) elm_object_focus_next((Evas_Object *)data, ELM_FOCUS_NEXT); else elm_object_focus_next((Evas_Object *)data, ELM_FOCUS_PREVIOUS); } static void _cb_eulogium_exit(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { elm_exit(); } Evas_Object *eulogium_split_screen(Evas_Object *parent, Evas_Object *top, Evas_Object *bottom) { Evas_Object *table; Evas_Object *sep; table = elm_table_add(parent); evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_size_hint_weight_set(top, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(top, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_table_pack(table, top, 0, 0, 1, 4); sep = elm_separator_add(table); elm_separator_horizontal_set(sep, EINA_TRUE); evas_object_size_hint_weight_set(sep, EVAS_HINT_EXPAND, 0); evas_object_show(sep); elm_table_pack(table, sep, 0, 4, 1, 1); elm_table_pack(table, bottom, 0, 5, 1, 1); evas_object_size_hint_weight_set(bottom, EVAS_HINT_EXPAND, 0); evas_object_size_hint_align_set(bottom, EVAS_HINT_FILL, 0); evas_object_show(table); return table; } static void _on_get_progress_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { const char *errname, *errmsg; double *progress = data; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "d", progress)) { EINA_LOG_ERR("Failed to get print progress."); return; } } static void _on_get_time_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { const char *errname, *errmsg; uint_fast32_t *time = data; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "u", time)) { EINA_LOG_ERR("Failed to get remaining print time."); return; } } static Eina_Bool _timer_progress_data_update_cb(void *data) { struct eulogium_data *eulogium = data; static enum printer_status status = -1; static double progress = 0; static double time = -1; eldbus_proxy_call(eulogium->dbus.proxy[PRINTER], "getProgress", _on_get_progress_ret, &eulogium->print.progress, -1, ""); eldbus_proxy_call(eulogium->dbus.proxy[PRINTER], "getTime", _on_get_time_ret, &eulogium->print.time, -1, ""); if (eulogium->printer.status != status) { elm_object_text_set(eulogium->status, griffin_print_status[eulogium->printer.status]); if (eulogium->printer.status == COOLING) elm_progressbar_inverted_set(eulogium->progress, EINA_TRUE); status = eulogium->printer.status; } if (eulogium->print.progress != progress) { elm_progressbar_value_set(eulogium->progress, eulogium->print.progress); progress = eulogium->print.progress; } if (eulogium->print.name_changed == EINA_TRUE) { elm_object_text_set(eulogium->name, eulogium->print.name); eulogium->print.name_changed = EINA_FALSE; } if (eulogium->print.time != time) { char buf[255], *str; uint_fast32_t time = 0; if (eulogium->print.time < 1) { str = "Print time unknown"; time = 0; } if (eulogium->print.time > 0) { str = "Time left: %d second%s"; time = eulogium->print.time; } if (eulogium->print.time > MINUTE) { str = "Time left: %d minute%s"; time = eulogium->print.time / MINUTE; } if (eulogium->print.time > HOUR) { str = "Time left: %d hour%s"; time = eulogium->print.time / HOUR; } if (eulogium->print.time > DAY) { str = "Time left: %d day%s"; time = eulogium->print.time / DAY; } if (eulogium->print.time > WEEK) { str = "Time left: %d week%s"; time = eulogium->print.time / WEEK; } if (eulogium->print.time > MONTH) { str = "Time left: %d month%s"; time = eulogium->print.time / MONTH; } if (eulogium->print.time > YEAR) { str = "Time left: %d year%s"; time = eulogium->print.time / YEAR; } snprintf(buf, sizeof(buf), str, (int)eulogium->print.time, (time > 1) ? "s" : ""); /* TODO: This won't work with in10 */ elm_object_text_set(eulogium->time, buf); eulogium->print.time = time; } return ECORE_CALLBACK_RENEW; } Evas_Object *eulogium_print_progress(struct eulogium_data *eulogium) { Evas_Object *_top, *_bottom; eulogium->progress_data_refresh = ecore_timer_add(0.5, _timer_progress_data_update_cb, eulogium); if (!eulogium->progress_data_refresh) { /* TODO make define for the timeout */ EINA_LOG_CRIT("Unable to create progress update timer"); return NULL; } _top = elm_box_add(eulogium->navi); evas_object_size_hint_weight_set(_top, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(_top, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_box_homogeneous_set(_top, EINA_FALSE); evas_object_show(_top); eulogium->time = elm_label_add(_top); elm_object_text_set(eulogium->time, "Calculating time ..."); elm_label_slide_mode_set(eulogium->time, ELM_LABEL_SLIDE_MODE_NONE); evas_object_size_hint_align_set(eulogium->time, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(eulogium->time); elm_box_pack_end(_top, eulogium->time); eulogium->status = elm_label_add(_top); elm_object_text_set(eulogium->status, "Unknown print status"); elm_label_slide_mode_set(eulogium->status, ELM_LABEL_SLIDE_MODE_NONE); evas_object_size_hint_align_set(eulogium->status, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(eulogium->status); elm_box_pack_end(_top, eulogium->status); eulogium->name = elm_label_add(_top); elm_object_text_set(eulogium->name, eulogium->print.name); elm_label_slide_mode_set(eulogium->name, ELM_LABEL_SLIDE_MODE_AUTO); //elm_label_slide_speed_set(object, 2); elm_label_slide_go(eulogium->name); elm_object_style_set(eulogium->name, "slide_bounce"); evas_object_size_hint_align_set(eulogium->name, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(eulogium->name); elm_box_pack_end(_top, eulogium->name); eulogium->progress = elm_progressbar_add(_top); /* TODO: depending on i18n sig, change inverted */ elm_progressbar_horizontal_set(eulogium->progress, EINA_TRUE); elm_progressbar_pulse_set(eulogium->progress, EINA_FALSE); /* TODO: pulse = time-unknown/pause */ elm_progressbar_pulse(eulogium->progress, EINA_FALSE); elm_progressbar_value_set(eulogium->progress, eulogium->print.progress); elm_progressbar_unit_format_set(eulogium->progress, "%1.1f %%"); evas_object_size_hint_align_set(eulogium->progress, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(eulogium->progress); elm_box_pack_end(_top, eulogium->progress); _bottom = eulogium_dual_button_add(eulogium->navi, &but_print_progress_tune, &but_print_abort); evas_object_show(_bottom); return eulogium_split_screen(eulogium->navi, _top, _bottom); } Evas_Object *eulogium_generic_error(struct eulogium_data *eulogium, uint8_t eulogium_error) { Evas_Object *box, *object; char buf[] = "Printer error -255.
Please contact support via
http://ultimaker.com/support."; /* TODO, replace with define of strings to collect all strings centrally */ box = elm_box_add(eulogium->navi); evas_object_show(box); object = elm_label_add(eulogium->navi); snprintf(buf, sizeof(buf), "Printer error %d.
Please contact support via
http://ultimaker.com/support.", eulogium_error); elm_object_text_set(object, buf); evas_object_show(object); elm_box_pack_end(box, object); #if 0 /* XXX what to do here, reboot? make support notice via wget? */ object = elm_button_add(eulogium->navi); elm_object_text_set(object, "ABORT"); /* TODO create abort button */ evas_object_size_hint_align_set(object, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_size_hint_weight_set(object, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_smart_callback_add(object, "clicked", _print_abort_cb, eulogium); /* TODO what button to use here? */ evas_object_show(object); elm_box_pack_end(box, object); #endif return box; } static void _on_start_print_ret(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { const char *errname, *errmsg; Eina_Bool print_started = EINA_FALSE; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "b", &print_started)) { EINA_LOG_ERR("Failed to start print."); return; } if (print_started == EINA_TRUE) EINA_LOG_INFO("Print has been successfully started"); else EINA_LOG_ERR("Unable to start print"); } static void _on_cleared_printer_ret(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { const char *errname, *errmsg; Eina_Bool cleared_bed = EINA_FALSE; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "b", &cleared_bed)) { EINA_LOG_ERR("Failed to get bed clear status."); return; } if (cleared_bed == EINA_TRUE) EINA_LOG_INFO("Bed has been successfully Cleared"); else EINA_LOG_WARN("Unable to clear printer bed"); } static void _cleared_bed_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = data; eldbus_proxy_call(eulogium->dbus.proxy[PRINTER], "clearedPrinter", _on_cleared_printer_ret, eulogium, -1, ""); } Evas_Object *eulogium_clear_print_bed(struct eulogium_data *eulogium) { Evas_Object *box, *obj; box = elm_box_add(eulogium->navi); evas_object_show(box); obj = elm_label_add(box); elm_object_text_set(obj, "Please empty print bed."); evas_object_show(obj); elm_box_pack_end(box, obj); /* TODO replace with left/right button call, this is just a quick Hack XXX */ obj = elm_button_add(box); elm_object_text_set(obj, "Print removed"); evas_object_smart_callback_add(obj, "clicked", _cleared_bed_cb, eulogium); evas_object_show(obj); elm_box_pack_end(box, obj); return box; } struct _filelist_data { void (*func)(void *data, Evas_Object *obj, void *event_info); struct eulogium_data *eulogium; char *filepath; }; static void _cb_select_file(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { struct eulogium_data *eulogium = ((struct _filelist_data *)data)->eulogium; char *filepath = ((struct _filelist_data *)data)->filepath; Evas_Object *content; if (filepath) { if (ecore_file_is_dir(filepath)) { content = eulogium_print_menu(eulogium, filepath); elm_naviframe_item_simple_push(eulogium->navi, content); } else { eulogium_print_data_set(eulogium, filepath); eldbus_proxy_call(eulogium->dbus.proxy[HARMA], "startPrint", _on_start_print_ret, eulogium, -1, "sss", eulogium->print.name, eulogium->print.file, eulogium->print.flags); } } } static int _cb_dirfile_sort(const void *data1, const void *data2) { const char *filepath1 = ((struct _filelist_data *)evas_object_data_get(data1, "filelist_data"))->filepath; const char *filepath2 = ((struct _filelist_data *)evas_object_data_get(data2, "filelist_data"))->filepath; if (!filepath1) return 1; if (!filepath2) return -1; if (ecore_file_is_dir(filepath1) != (ecore_file_is_dir(filepath2))) { return (ecore_file_is_dir(filepath1) ? -1 : 1); } return strcoll(filepath1, filepath2); } char *ecore_file_ext_get(const char *path) { char *p, *file = NULL; p = strrchr(path, '.'); if ((!path) || (!p)) return NULL; else if (p != path) { size_t l = strlen(p); if (l < 2) return NULL; file = malloc(strlen(p) * sizeof(char)); if (file) { memcpy(file, &p[1], l); } } return file; } static void _cb_populate_filelist(const char *name, const char *path, void *data) { struct eulogium_data *eulogium = data; Evas_Object *list = (Evas_Object *)eulogium->data; Evas_Object *icon; char *filepath; char *ext; size_t dir_len; uint_fast8_t hidden_visible = 1; struct _filelist_data *filelist; if (hidden_visible && (name[0] == '.')) return; dir_len = strlen(name) + strlen(path) + sizeof('/') + 1; filepath = malloc(dir_len); snprintf(filepath, dir_len, "%s/%s", path, name); if (!ecore_file_is_dir(filepath)) { int i, valid_ext = 0; ext = ecore_file_ext_get(name); if (!ext) return; if (!eulogium->printer.file_handlers) return; for (i = 0; eulogium->printer.file_handlers[i] != NULL; i++) if (strncmp(ext, eulogium->printer.file_handlers[i], strlen(ext)) == 0) valid_ext++; if (!valid_ext) return; } icon = elm_icon_add(list); if (ecore_file_is_dir(filepath)) { elm_icon_standard_set(icon, "folder"); } else { elm_icon_standard_set(icon, "file"); } elm_image_resizable_set(icon, EINA_FALSE, EINA_FALSE); filelist = malloc(sizeof(struct _filelist_data)); /* never freed, memleak! XXX check cb */ filelist->eulogium = eulogium; filelist->filepath = filepath; eulogium_button_list_sorted_insert(list, name, icon, _cb_select_file, filelist, _cb_dirfile_sort); // free(filepath); /* TODO is this required?, yes! / } Evas_Object *eulogium_print_menu(struct eulogium_data *eulogium, char *filepath) /* TODO make const out of filepath */ { Evas_Object *box; Evas_Object *list; Evas_Object *icon; box = elm_box_add(eulogium->navi); list = elm_label_add(box); elm_object_text_set(list, "SD Card"); /* TODO This may be more then just the SD card */ evas_object_size_hint_align_set(list, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(list); elm_box_pack_start(box, list); list = eulogium_button_list_add(box); elm_scroller_bounce_set(list, EINA_FALSE, EINA_FALSE); elm_scroller_policy_set(list, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO); evas_object_size_hint_weight_set(list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(list, EVAS_HINT_FILL, EVAS_HINT_FILL); //elm_list_mode_set(list, ELM_LIST_COMPRESS); elm_scroller_movement_block_set(list, ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL | ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL); elm_box_pack_end(box, list); evas_object_show(list); eulogium->data = (void *)list; eina_file_dir_list(filepath, EINA_FALSE, _cb_populate_filelist, eulogium); eulogium->data = NULL; icon = elm_icon_add(list); elm_icon_standard_set(icon, "user-home"); eulogium_button_list_prepend(list, "RETURN", icon, _cb_content_prev_set, eulogium); /* XXX TODO: when we pop the filelist from the stack, who calls elm_list_free();? */ eulogium_button_list_go(list); // evas_object_smart_callback_add(list, "longpressed", _cb_filelist_filedetails, NULL); /* TODO, use inwin */ evas_object_show(list); evas_object_show(box); return box; } struct _multi_screen_next_cb_data { struct eulogium_data *eulogium; struct multi_screen_data *screen_data; uint_fast8_t pagenum; Eina_Bool pageindex; }; static void _eulogium_multi_screen_next_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { Evas_Object *content; struct eulogium_data *eulogium = ((struct _multi_screen_next_cb_data *)data)->eulogium; uint_fast8_t pagenum = ((struct _multi_screen_next_cb_data *)data)->pagenum; Eina_Bool pageindex = ((struct _multi_screen_next_cb_data *)data)->pageindex; struct multi_screen_data *screen_data = ((struct _multi_screen_next_cb_data *)data)->screen_data; if (pagenum >= screen_data->count) { Elm_Object_Item *item; item = elm_naviframe_bottom_item_get(eulogium->navi); if (item) elm_naviframe_item_pop_to(item); /* XXX what else? */ } else { content = eulogium_multi_screen_menu(eulogium, eulogium->navi, screen_data, pagenum, pageindex); if (content) elm_naviframe_item_simple_push(eulogium->navi, content); /* XXX what else? */ } free(data); } static void _cb_material_set(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) { printf("Material: %s selected\n", (char *)data); } Evas_Object *eulogium_multi_screen_menu(struct eulogium_data *eulogium, Evas_Object *parent, struct multi_screen_data *screen_data, uint_fast8_t pagenum, Eina_Bool pageindex) /* TODO swap parent/eulogium */ { Evas_Object *object; Evas_Object *_top, *_bottom; struct _multi_screen_next_cb_data *multi_screen_next_cb_data; char buf[6]; _top = elm_box_add(parent); evas_object_show(_top); if (screen_data->count == 0) { EINA_LOG_WARN("Tut tut, we can't have a count of 0!\n"); return NULL; } if (pagenum >= screen_data->count) pagenum = screen_data->count - 1; if (pageindex) { object = elm_label_add(_top); snprintf(buf, sizeof(buf), "%d/%d", pagenum + 1, screen_data->count); elm_object_text_set(object, buf); evas_object_show(object); evas_object_size_hint_weight_set(object, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(object, 1.0, 0); elm_box_pack_end(_top, object); } if (screen_data->screen[pagenum].text) { object = elm_label_add(_top); elm_object_text_set(object, screen_data->screen[pagenum].text); evas_object_size_hint_align_set(object, 0.5, 0.5); evas_object_show(object); elm_box_pack_end(_top, object); } switch (screen_data->screen[pagenum].type) { Evas_Object *box; /* TODO rename to 'type' or something */ case MATERIAL: box = elm_box_add(_top); elm_box_horizontal_set(box, EINA_TRUE); evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_show(box); object = elm_button_add(box); evas_object_size_hint_align_set(object, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_size_hint_weight_set(object, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_object_text_set(object, "PLA"); /* Materials need to be handled differently */ evas_object_smart_callback_add(object, "clicked", _cb_material_set, "PLA"); evas_object_show(object); elm_box_pack_end(box, object); object = elm_button_add(box); evas_object_size_hint_align_set(object, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_size_hint_weight_set(object, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_object_text_set(object, "ABS"); evas_object_smart_callback_add(object, "clicked", _cb_material_set, "ABS"); evas_object_show(object); elm_box_pack_end(box, object); elm_box_pack_end(_top, box); break; case PROGRESS: box = elm_progressbar_add(_top); elm_progressbar_horizontal_set(box, EINA_TRUE); elm_progressbar_pulse_set(box, EINA_FALSE); /* TODO: pulse = time-unknown/pause */ elm_progressbar_pulse(box, EINA_FALSE); elm_progressbar_value_set(box, 0.5); elm_progressbar_unit_format_set(box, "%1.0f%%"); evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(box); elm_box_pack_end(_top, box); break; case FUNC: /* call function pointer from screen_data.func */ break; case END: /* fall through */ default: break; } _bottom = elm_box_add(parent); elm_box_horizontal_set(_bottom, EINA_TRUE); evas_object_show(_bottom); multi_screen_next_cb_data = malloc(sizeof(struct _multi_screen_next_cb_data)); multi_screen_next_cb_data->eulogium = eulogium; multi_screen_next_cb_data->screen_data = screen_data; multi_screen_next_cb_data->pagenum = pagenum + 1; multi_screen_next_cb_data->pageindex = EINA_TRUE; if (screen_data->screen[pagenum].prev_button) { object = elm_button_add(parent); evas_object_size_hint_align_set(object, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_size_hint_weight_set(object, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_object_text_set(object, screen_data->screen[pagenum].prev_button); evas_object_smart_callback_add(object, "clicked", _cb_content_prev_set, eulogium); evas_object_show(object); elm_box_pack_end(_bottom, object); } if (screen_data->screen[pagenum].next_button) { object = elm_button_add(parent); evas_object_size_hint_align_set(object, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_size_hint_weight_set(object, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_object_text_set(object, screen_data->screen[pagenum].next_button); evas_object_smart_callback_add(object, "clicked", _eulogium_multi_screen_next_cb, multi_screen_next_cb_data); evas_object_show(object); elm_box_pack_end(_bottom, object); } return eulogium_split_screen(parent, _top, _bottom); } Evas_Object *eulogium_dual_button_add(Evas_Object *parent, const struct button_def *left, const struct button_def *right) { Evas_Object *box; Evas_Object *obj, *butbox; box = elm_box_add(parent); elm_box_homogeneous_set(box, EINA_TRUE); evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_box_horizontal_set(box, EINA_TRUE); butbox = elm_box_add(box); evas_object_size_hint_weight_set(butbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(butbox, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(butbox); elm_box_horizontal_set(butbox, EINA_TRUE); elm_box_pack_end(box, butbox); /* Dummy seperator that is not visible to make both buttons identical in size */ obj = elm_separator_add(box); elm_separator_horizontal_set(obj, EINA_FALSE); evas_object_size_hint_weight_set(obj, 0, 0); elm_box_pack_end(butbox, obj); obj = elm_button_add(box); evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_object_text_set(obj, left->text); evas_object_smart_callback_add(obj, "clicked", left->cb.func, left->cb.data); evas_object_show(obj); elm_box_pack_end(butbox, obj); butbox = elm_box_add(box); evas_object_size_hint_weight_set(butbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(butbox, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(butbox); elm_box_horizontal_set(butbox, EINA_TRUE); elm_box_pack_end(box, butbox); obj = elm_separator_add(box); elm_separator_horizontal_set(obj, EINA_FALSE); evas_object_size_hint_weight_set(obj, 0, 0); evas_object_show(obj); elm_box_pack_end(butbox, obj); obj = elm_button_add(box); evas_object_size_hint_weight_set(obj, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(obj, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_object_text_set(obj, right->text); evas_object_smart_callback_add(obj, "clicked", right->cb.func, right->cb.data); evas_object_show(obj); elm_box_pack_end(butbox, obj); return box; } Evas_Object *eulogium_tripple_button_menu(Evas_Object *parent, const struct button_def *left, const struct button_def *right, const struct button_def *bottom) { Evas_Object *_top, *_bottom; _top = eulogium_dual_button_add(parent, left, right); evas_object_show(_top); _bottom = elm_button_add(parent); elm_object_text_set(_bottom, bottom->text); evas_object_smart_callback_add(_bottom, "clicked", bottom->cb.func, bottom->cb.data); evas_object_show(_bottom); return eulogium_split_screen(parent, _top, _bottom); } static struct multi_screen screen[] = { { .type = NONE, .text = "Welcome
to your new Ultimaker", .func = NULL, .data = NULL, .prev_button = "Skip Wizzard!", .next_button = "Continue", }, { .type = MATERIAL, .text = "Choose material", .func = NULL, .data = NULL, .prev_button = "Skip Wizzard!", .next_button = "Continue", }, { .type = FUNC, .text = "Level bed", .func = NULL, .data = "Bed leveling call", .prev_button = "Skip Wizzard!", .next_button = "Continue", }, { .type = PROGRESS, .text = "Heating ...", .func = NULL, .data = "progress object", .prev_button = "Skip Wizzard!", .next_button = "Continue", }, { .type = NONE, .text = "Lets print!", .func = NULL, .data = NULL, .prev_button = NULL, .next_button = "Let's Print!", }, { .type = END, /* sentinel */ }, }; static struct multi_screen_data screen_data = { .screen = &screen[0], }; Evas_Object *eulogium_main_menu(Evas_Object *window, struct eulogium_data *eulogium) { Evas_Object *content; eulogium->navi = elm_naviframe_add(window); if (!eulogium->navi) return NULL; elm_naviframe_prev_btn_auto_pushed_set(eulogium->navi, EINA_FALSE); /* We removed this from the theme, enabling it causes errors */ content = eulogium_tripple_button_menu(eulogium->navi, &but_main_print, &but_main_material, &but_main_maintanance); if (!content) return NULL; elm_naviframe_item_simple_push(eulogium->navi, content); return eulogium->navi; } static void eulogium_setup(struct eulogium_data *eulogium) { while (screen_data.screen[screen_data.count].type != END) screen_data.count++; eulogium->mounts = NULL; eulogium->progress_data_refresh = NULL; eulogium->print.name = NULL; eulogium->print.file = NULL; eulogium_print_data_clear(eulogium); eulogium->printer.status = DISCONNECTED; eulogium->printer.file_handlers = NULL; eulogium_button_cb_data_set(&but_return, eulogium); eulogium_button_cb_data_set(&but_print_abort, eulogium); eulogium_button_cb_data_set(&but_print_progress_tune, eulogium); eulogium_button_cb_data_set(&but_main_print, eulogium); eulogium_button_cb_data_set(&but_print_local, eulogium); eulogium_button_cb_data_set(&but_print_usb, eulogium); eulogium_button_cb_data_set(&but_main_material, eulogium); eulogium_button_cb_data_set(&but_main_maintanance, eulogium); eulogium_button_cb_data_set(&but_maintanance_advanced, eulogium); eulogium_button_cb_data_set(&but_maintanance_buildplate, eulogium); eulogium_button_cb_data_set(&but_mat_change, eulogium); eulogium_button_cb_data_set(&but_mat_settings, eulogium); } /* TODO May need this later to change certain connections to objects */ static void on_name_owner_changed(void *data EINA_UNUSED, const char *bus, const char *old_id, const char *new_id) { printf("Bus=%s | old=%s | new=%s\n", bus, old_id, new_id); } static void _on_get_error_ret(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { const char *errname, *errmsg, *errormsg; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "s", &errormsg)) { EINA_LOG_ERR("Message content does not match expected \"s\" signature. (%s)", eldbus_message_signature_get(msg)); return; } EINA_LOG_ERR("%s", errormsg); /* TODO Call generic error screen in case of trouble here? */ } static void _on_get_print_name_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { struct eulogium_data *eulogium = data; const char *errname, *errmsg; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "s", &eulogium->print.name)) { EINA_LOG_ERR("Failed to get printName message."); return; } eulogium->print.name_changed = EINA_TRUE; EINA_LOG_INFO("Printer name updated"); /* TODO Call generic error screen in case of trouble here? */ } struct _status_msg { enum printer_status i; char *s; }; static void eulogium_printer_status_set(struct eulogium_data *eulogium, struct _status_msg *status) { Evas_Object *content = NULL; EINA_LOG_WARN("Printer status: %s", status->s); if (eulogium->printer.status != status->i) { switch (status->i) { Elm_Object_Item *item; /* Cases missing: First run wizard, heating, cooling */ #if 0 case (FIRST_RUN_WIZARD): content = eulogium_multi_screen_menu(eulogium, eulogium->navi, &screen_data, 0, EINA_TRUE); if (content) elm_naviframe_item_simple_push(eulogium->navi, content); break; #endif case (PAUSED): /* fall through TODO: make pause screen with resume/other button */ case (HEATING): /* fall through */ case (SLICING): /* fall through */ case (PRINTING): /* fall through */ case (COOLING): /* Check if the previous state was already one of the printing states. * If the state was one of the various printing states, do nothing. */ if (!((eulogium->printer.status == PAUSED) || (eulogium->printer.status == HEATING) || (eulogium->printer.status == SLICING) || (eulogium->printer.status == PRINTING) || (eulogium->printer.status == COOLING))) { eldbus_proxy_call(eulogium->dbus.proxy[PRINTER], "getPrintName", _on_get_print_name_ret, eulogium, -1, ""); content = eulogium_print_progress(eulogium); } break; case (WAIT_FOR_REMOVAL): if (eulogium->printer.status != status->i) { eulogium_print_data_clear(eulogium); content = eulogium_clear_print_bed(eulogium); } break; case (DISCONNECTED): /* fall through */ case (ERROR): eldbus_proxy_call(eulogium->dbus.proxy[PRINTER], "getError", _on_get_error_ret, eulogium, -1, ""); content = eulogium_generic_error(eulogium, 4); break; case (IDLE): /* Pop to the bottom of the stack. TODO: evaluate if a) we want this in a seperate function, b) popping to the bottom may not be the right frame to pop too? */ eulogium_print_data_clear(eulogium); item = elm_naviframe_bottom_item_get(eulogium->navi); if (item) elm_naviframe_item_pop_to(item); /* XXX what to do else? | XXX stack corrupted after this? (see error log) */ else EINA_LOG_CRIT("There is no bottom of the stack!"); break; default: break; } if (content) elm_naviframe_item_simple_push(eulogium->navi, content); //elm_naviframe_item_push(eulogium->navi, NULL, NULL, NULL, content, NULL); /* TODO: When status is printing for example, or waiting_for_Removal, pop to those screens immediatly? */ eulogium->printer.status = status->i; } } static void _on_get_file_handlers_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { const char *errname, *errmsg; Eldbus_Message_Iter *array; uint_fast8_t i; char *file_handler; char **file_handlers = NULL; struct eulogium_data *eulogium = data; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "as", &array)) { EINA_LOG_ERR("Message content does not match expected \"as\" signature."); return; } for (i = 0; (eldbus_message_iter_get_and_next(array, 's', &file_handler)); i++) { size_t fhandler_size = strlen(file_handler) + 1; file_handlers = realloc(file_handlers, (i + 1) * sizeof(char *)); if (!file_handlers) EINA_LOG_ERR("Unable to allocate memory."); else file_handlers[i] = malloc(fhandler_size); if (!file_handlers[i]) EINA_LOG_ERR("Unable to allocate memory."); else strncpy(file_handlers[i], file_handler, fhandler_size); } file_handlers[i] = NULL; /* sentinel */ eulogium->printer.file_handlers = file_handlers; } static void _on_get_status_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { const char *errname, *errmsg; struct eulogium_data *eulogium = data; char *state; struct _status_msg status; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); status.i = ERROR; status.s = griffin_print_status[ERROR]; } else if (!eldbus_message_arguments_get(msg, "s", &state)) { EINA_LOG_ERR("Message content does not match expected \"s\" signature."); status.i = ERROR; status.s = griffin_print_status[ERROR]; } else if (!strncmp(state, "DISCONNECTED", 12)) { /* XXX replace this with something better and maintainable, function, LUT etc */ status.i = DISCONNECTED; status.s = griffin_print_status[DISCONNECTED]; } else if (!strncmp(state, "ERROR", 5)) { status.i = ERROR; status.s = griffin_print_status[ERROR]; } else if (!strncmp(state, "FIRST_RUN_WIZZARD", 17)) { status.i = FIRST_RUN_WIZZARD; status.s = griffin_print_status[FIRST_RUN_WIZZARD]; } else if (!strncmp(state, "IDLE", 4)) { status.i = IDLE; status.s = griffin_print_status[IDLE]; } else if (!strncmp(state, "SLICING", 7)) { status.i = SLICING; status.s = griffin_print_status[SLICING]; } else if (!strncmp(state, "HEATING", 7)) { status.i = HEATING; status.s = griffin_print_status[HEATING]; } else if (!strncmp(state, "PRINTING", 8)) { status.i = PRINTING; status.s = griffin_print_status[PRINTING]; } else if (!strncmp(state, "COOLING", 7)) { status.i = COOLING; status.s = griffin_print_status[COOLING]; } else if (!strncmp(state, "WAIT_FOR_REMOVAL", 16)) { status.i = WAIT_FOR_REMOVAL; status.s = griffin_print_status[WAIT_FOR_REMOVAL]; } else if (!strncmp(state, "PAUSED", 6)) { status.i = PAUSED; status.s = griffin_print_status[PAUSED]; } else { status.i = UNKNOWN; status.s = griffin_print_status[UNKNOWN]; } eulogium_printer_status_set(eulogium, &status); } static void _on_status_changed_ret(void *data, const Eldbus_Message *msg) { _on_get_status_ret(data, msg, NULL); } static void eulogium_disk_free(struct mount_data *mount) { eeze_disk_free(mount->disk); if (mount->id) free(mount->id); eldbus_proxy_unref(mount->proxy); free(mount); mount = NULL; } static void _on_where_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { struct mount_data *mount = data; const char *errname, *errmsg; Eldbus_Message_Iter *var = NULL; char *where; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "v", &var)) { EINA_LOG_ERR("Message content does not match expected \"v\" signature. (%s)", eldbus_message_signature_get(msg)); return; } if (!eldbus_message_iter_arguments_get(var, "s", &where)) { EINA_LOG_ERR("Message content does not match expected \"s\" signature. (%s)", eldbus_message_iter_signature_get(var)); return; } if (!where) return; /* Never use a medium that is mounted under dev, proc, run or sys. */ if (!(strncmp(where, "/dev/", 5) && strncmp(where, "/proc/", 6) && strncmp(where, "/run/", 5) && strncmp(where, "/sys/", 5))) return; mount->disk = eeze_disk_new_from_mount(where); eeze_disk_scan(mount->disk); EINA_LOG_ERR("Medium mounted at %s of type %d", where, eeze_disk_type_get(mount->disk)); if (eeze_disk_type_get(mount->disk) == EEZE_DISK_TYPE_USB) *mount->mounts = eina_list_append(*mount->mounts, mount); if ((eeze_disk_type_get(mount->disk) == EEZE_DISK_TYPE_FLASH) && (!strstr(eeze_disk_devpath_get(mount->disk), "mmcblk0"))) /* XXX skip using mmcblk0 as that is our root fs for now. This may be handled by udev making it invisible. */ *mount->mounts = eina_list_append(*mount->mounts, mount); else eulogium_disk_free(mount); /* TODO: UI Stuffs/signals */ } static void _on_result_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED) { struct mount_data *mount = data; const char *errname, *errmsg; Eldbus_Message_Iter *var = NULL; char *result; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "v", &var)) { EINA_LOG_ERR("Message content does not match expected \"v\" signature. (%s)", eldbus_message_signature_get(msg)); return; } if (!eldbus_message_iter_arguments_get(var, "s", &result)) { EINA_LOG_ERR("Message content does not match expected \"s\" signature. (%s)", eldbus_message_iter_signature_get(var)); return; } if (strncmp(result, "success", 7)) { return; } eldbus_proxy_property_get(mount->proxy, "Where", _on_where_ret, mount); } static void _on_unit_new_ret(void *data, const Eldbus_Message *msg) { const char *errname, *errmsg; struct eulogium_data *eulogium = data; char *id, *unit, *ext; size_t id_len; Eldbus_Object *obj; struct mount_data *mount; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "so", &id, &unit)) { EINA_LOG_ERR("Message content does not match expected \"so\" signature."); return; } ext = ecore_file_ext_get(id); if (strncmp(ext, "mount", 5)) return; obj = eldbus_object_get(eulogium->dbus.conn, "org.freedesktop.systemd1", unit); if (!obj) { EINA_LOG_WARN("Could not get org.freedesktop.systemd1-mount object. (%s)", unit); return; } mount = calloc(1, sizeof(struct mount_data)); if (!mount) { EINA_LOG_ERR("Unable to allocate memory for mountpoint %s", id); return; } id_len = strlen(id); mount->id = malloc(id_len + 1); if (!mount->id) { EINA_LOG_ERR("Unable to allocate memory for id %s", id); free(mount); return; } strncpy(mount->id, id, id_len); mount->proxy = eldbus_proxy_get(obj, "org.freedesktop.systemd1.Mount"); mount->mounts = &eulogium->mounts; if (!mount->proxy) { EINA_LOG_WARN("Could not get dbus proxy for (%s).", id); free(mount->id); free(mount); return; } EINA_LOG_ERR("Medium inserted (%s)", id); eldbus_proxy_property_get(mount->proxy, "Result", _on_result_ret, mount); } static void _on_list_units_ret(void *data, const Eldbus_Message *msg, Eldbus_Pending *Pending EINA_UNUSED) { const char *errname, *errmsg; struct eulogium_data *eulogium = data; Eldbus_Message_Iter *array, *dbus_struct; char *id, *unit; char *dummy; uint_fast32_t dummy_int; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "a(ssssssouso)", &array)) { EINA_LOG_ERR("Message content does not match expected \"a(ssssssouso)\" signature. (%s)", eldbus_message_signature_get(msg)); return; } while (eldbus_message_iter_get_and_next(array, 'r', &dbus_struct)) { if (eldbus_message_iter_arguments_get(dbus_struct, "ssssssouso", &id, &dummy, &dummy, &dummy, &dummy, &dummy, &unit, &dummy_int, &dummy, &dummy)) { Eldbus_Object *obj; struct mount_data *mount; size_t id_len; obj = eldbus_object_get(eulogium->dbus.conn, "org.freedesktop.systemd1", unit); if (!obj) { EINA_LOG_WARN("Could not get org.freedesktop.systemd1-mount object. (%s)", unit); return; } mount = calloc(1, sizeof(struct mount_data)); if (!mount) { EINA_LOG_ERR("Unable to allocate memory for mountpoint %s", id); break; } id_len = strlen(id); mount->id = malloc(id_len + 1); if (!mount->id) { EINA_LOG_ERR("Unable to allocate memory for id %s", id); free(mount); break; } strncpy(mount->id, id, id_len); mount->proxy = eldbus_proxy_get(obj, "org.freedesktop.systemd1.Mount"); if (!mount->proxy) { EINA_LOG_WARN("Could not get dbus proxy for (%s).", id); free(mount->id); free(mount); break; } mount->mounts = &eulogium->mounts; EINA_LOG_ERR("Medium detected (%s)", id); eldbus_proxy_property_get(mount->proxy, "Result", _on_result_ret, mount); } else { EINA_LOG_ERR("Unable to decode dbus-struct\n"); } } } static int _mount_find_cb(const void *haystack, const void *needle) { const struct mount_data *mount = haystack; const char *id = needle; return strncmp(id, mount->id, strlen(id)); } static void _on_unit_removed_ret(void *data, const Eldbus_Message *msg) { const char *errname, *errmsg; struct eulogium_data *eulogium = data; char *id, *unit, *ext; Eldbus_Object *obj; struct mount_data *mount; Eina_List *list; if (eldbus_message_error_get(msg, &errname, &errmsg)) { EINA_LOG_ERR("%s %s", errname, errmsg); return; } if (!eldbus_message_arguments_get(msg, "so", &id, &unit)) { EINA_LOG_ERR("Message content does not match expected \"so\" signature."); return; } ext = ecore_file_ext_get(id); if (strncmp(ext, "mount", 5)) return; obj = eldbus_object_get(eulogium->dbus.conn, "org.freedesktop.systemd1", unit); if (!obj) { EINA_LOG_WARN("Could not get org.freedesktop.systemd1-mount object (%s).", unit); return; } EINA_LOG_ERR("Medium remove request (%s)", id); list = eina_list_search_unsorted_list(eulogium->mounts, _mount_find_cb, id); mount = eina_list_data_get(list); if (!mount) { EINA_LOG_CRIT("Mount %s is NULL, this should not happen!", id); } else { eulogium_disk_free(mount); eulogium->mounts = eina_list_remove_list(eulogium->mounts, list); } /* TODO: UI Stuff/signals */ } static int eulogium_dbus_init(struct eulogium_data *eulogium) { Eldbus_Object *obj; Eldbus_Proxy *proxy; Eldbus_Message_Iter *iter, *array; Eldbus_Message *msg; eulogium->dbus.conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM); if (!eulogium->dbus.conn) { EINA_LOG_CRIT("Could not get system dbus."); return -ECONNREFUSED; } obj = eldbus_object_get(eulogium->dbus.conn, "org.freedesktop.systemd1", "/org/freedesktop/systemd1"); if (!obj) { EINA_LOG_WARN("Could not get org.freedesktop.systemd1 object."); return -EFAULT; } /* XXX We currently monitor systemd for new mounts. This functionality should really be handled by eeze and once it may does, this has to be re-written. */ proxy = eldbus_proxy_get(obj, "org.freedesktop.systemd1.Manager"); if (!proxy) { EINA_LOG_WARN("Could not get dbus systemd-manager proxy."); return -EFAULT; } eldbus_name_owner_changed_callback_add(eulogium->dbus.conn, "org.freedesktop.systemd1.Manager", on_name_owner_changed, eulogium->dbus.conn, EINA_TRUE); /* TODO: Make nice loop that gets BUS/PATH from a predefined array? */ obj = eldbus_object_get(eulogium->dbus.conn, "nl.ultimaker.harma", "/nl/ultimaker/harma"); if (!obj) { EINA_LOG_WARN("Could not get nl.ultimaker.harma object."); return -EFAULT; } eulogium->dbus.proxy[HARMA] = eldbus_proxy_get(obj, "nl.ultimaker"); if (!eulogium->dbus.proxy[HARMA]) { EINA_LOG_WARN("Could not get dbus harma proxy."); return -EFAULT; } eldbus_name_owner_changed_callback_add(eulogium->dbus.conn, "nl.ultimaker.harma", on_name_owner_changed, eulogium->dbus.conn, EINA_TRUE); obj = eldbus_object_get(eulogium->dbus.conn, "nl.ultimaker.led", "/nl/ultimaker/led"); if (!obj) { return -EFAULT; EINA_LOG_WARN("Could not get nl.ultimaker.led object."); } eulogium->dbus.proxy[LED] = eldbus_proxy_get(obj, "nl.ultimaker"); if (!eulogium->dbus.proxy[LED]) { EINA_LOG_WARN("Could not get dbus led proxy."); return -EFAULT; } eldbus_name_owner_changed_callback_add(eulogium->dbus.conn, "nl.ultimaker.led", on_name_owner_changed, eulogium->dbus.conn, EINA_TRUE); obj = eldbus_object_get(eulogium->dbus.conn, "nl.ultimaker.printer", "/nl/ultimaker/printer"); if (!obj) { EINA_LOG_WARN("Could not get nl.ultimaker.printer object."); return -EFAULT; } eulogium->dbus.proxy[PRINTER] = eldbus_proxy_get(obj, "nl.ultimaker"); if (!eulogium->dbus.proxy[PRINTER]) { EINA_LOG_WARN("Could not get dbus printer proxy."); return -EFAULT; } eldbus_name_owner_changed_callback_add(eulogium->dbus.conn, "nl.ultimaker.printer", on_name_owner_changed, eulogium->dbus.conn, EINA_TRUE); /* First query the status and store it, we don't know the initial status, * and the statusChanged signal may not have been fired yet */ /* TODO: put signal/method name strings in macro/LUT */ eldbus_proxy_call(eulogium->dbus.proxy[HARMA], "getFileHandlers", _on_get_file_handlers_ret, eulogium, -1, ""); eldbus_proxy_call(eulogium->dbus.proxy[PRINTER], "getStatus", _on_get_status_ret, eulogium, -1, ""); eldbus_proxy_call(eulogium->dbus.proxy[PRINTER], "getPrintName", _on_get_print_name_ret, eulogium, -1, ""); eldbus_proxy_signal_handler_add(eulogium->dbus.proxy[PRINTER], "statusChanged", _on_status_changed_ret, eulogium); eldbus_proxy_signal_handler_add(proxy, "UnitNew", _on_unit_new_ret, eulogium); eldbus_proxy_signal_handler_add(proxy, "UnitRemoved", _on_unit_removed_ret, eulogium); msg = eldbus_proxy_method_call_new(proxy, "ListUnitsFiltered"); iter = eldbus_message_iter_get(msg); array = eldbus_message_iter_container_new(iter, 'a', "s"); if (!array) EINA_LOG_ERR("Empty container"); eldbus_message_iter_basic_append(array, 's', "mounted"); eldbus_message_iter_container_close(iter, array); eldbus_proxy_send(proxy, msg, _on_list_units_ret, eulogium, -1); /* eldbus_proxy_call(proxy, "ListUnitsFiltered", _on_list_units_ret, eulogium, -1, "as", "{mounted}"); */ return 0; } EAPI_MAIN int elm_main(int argc, char **argv) { Eina_Bool quit_option = EINA_FALSE; static const Ecore_Getopt optdesc = { PACKAGE_NAME, "%prog [options]", PACKAGE_VERSION, COPYRIGHT, "Affero GPLv3", "eulogium program", 0, { ECORE_GETOPT_LICENSE('L', "license"), ECORE_GETOPT_COPYRIGHT('C', "copyright"), ECORE_GETOPT_VERSION('V', "version"), ECORE_GETOPT_HELP('h', "help"), ECORE_GETOPT_SENTINEL } }; Ecore_Getopt_Value values[] = { ECORE_GETOPT_VALUE_BOOL(quit_option), ECORE_GETOPT_VALUE_BOOL(quit_option), ECORE_GETOPT_VALUE_BOOL(quit_option), ECORE_GETOPT_VALUE_BOOL(quit_option), ECORE_GETOPT_VALUE_NONE }; int args; uint_fast8_t i; struct eulogium_data eulogium; Evas_Object *window, *object; // Evas_Object *splash_window; // Eina_List *engines, *l; eeze_init(); eeze_disk_function(); if (!(eeze_disk_can_mount() && eeze_disk_can_unmount())) EINA_LOG_ERR("No disk (u)mount support available"); elm_need_eldbus(); args = ecore_getopt_parse(&optdesc, values, argc, argv); if (args < 0) { EINA_LOG_CRIT("Could not parse arguments."); return EXIT_FAILURE; } // elm_prefs_data_new(); /* TODO */ elm_policy_set(ELM_POLICY_QUIT, /* ELM_POLICY_QUIT_NONE */ ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); elm_app_compile_bin_dir_set(PACKAGE_BIN_DIR); elm_app_compile_lib_dir_set(PACKAGE_LIB_DIR); elm_app_compile_data_dir_set(PACKAGE_DATA_DIR); #if HAVE_GETTEXT && ENABLE_NLS elm_app_compile_locale_set(LOCALE_DIR); #endif #if ENABLE_NLS /* TODO Check for removal, elm_app_compile may solve this allready */ // setlocale(LC_ALL, ""); // bindtextdomain(PACKAGE, LOCALE_DIR); // bind_textdomain_codeset(PACKAGE, "UTF-8"); // textdomain(PACKAGE); #endif elm_app_info_set(NULL, PACKAGE, NULL); /* TODO */ #if (ELM_VERSION_MAJOR > 1) || (ELM_VERSION_MINOR >= 10) elm_config_accel_preference_set("accel"); #endif elm_theme_overlay_add(NULL, "./default.edj"); #if 0 /* TODO make icon */ icon = evas_object_image_add(evas_object_evas_get(win)); snprintf(buf, sizeof(buf), "%s/images/rage.png", elm_app_data_dir_get()); evas_object_image_file_set(o, buf, NULL); elm_win_icon_object_set(win, o); #endif elm_config_focus_highlight_enabled_set(EINA_FALSE); elm_config_focus_highlight_animate_set(EINA_FALSE); elm_config_softcursor_mode_set(ELM_SOFTCURSOR_MODE_OFF); if (eulogium_dbus_init(&eulogium)) EINA_LOG_CRIT("Griffin D-Bus initialization failed!"); /* TODO: move into its own init */ window = elm_win_add(NULL, PACKAGE_NAME, ELM_WIN_BASIC); if (!window) return EXIT_FAILURE; evas_object_resize(window, 128, 64); elm_win_title_set(window, PACKAGE_NAME); evas_object_repeat_events_set(window, EINA_TRUE); elm_win_autodel_set(window, EINA_TRUE); evas_object_smart_callback_add(window, "delete,request", _cb_eulogium_exit, NULL); object = elm_bg_add(window); if (!object) return EXIT_FAILURE; evas_object_size_hint_weight_set(object, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(object, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_win_resize_object_add(window, object); evas_object_show(object); eulogium_setup(&eulogium); object = eulogium_main_menu(window, &eulogium); if (!object) return EXIT_FAILURE; evas_object_size_hint_weight_set(object, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(object, EVAS_HINT_FILL, EVAS_HINT_FILL); elm_win_resize_object_add(window, object); evas_object_show(object); #if 0 /* Ideally we want to add the callbacks to the window. This currently does not work */ evas_object_event_callback_add(window, EVAS_CALLBACK_MOUSE_WHEEL, _cb_eulogium_input_wheel, NULL); #else /* HACK: draw a transparent rectangle over the entire window and capture events we are interested in */ object = evas_object_rectangle_add(evas_object_evas_get(window)); if (!object) return EXIT_FAILURE; evas_object_size_hint_weight_set(object, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_color_set(object, 0, 0, 0, 0); evas_object_repeat_events_set(object, EINA_TRUE); evas_object_event_callback_add(object, EVAS_CALLBACK_MOUSE_WHEEL, _cb_eulogium_input_wheel, window); /* TODO: don't these two input events repeat/fall through, everything else, may/should. */ evas_object_show(object); elm_win_resize_object_add(window, object); #endif evas_object_show(window); elm_run(); eldbus_connection_unref(eulogium.dbus.conn); if (eulogium.printer.file_handlers != NULL) for (i = 0; eulogium.printer.file_handlers[i] != NULL; i++) free(eulogium.printer.file_handlers[i]); free(eulogium.printer.file_handlers); /* TODO: Cleanup function? */ elm_shutdown(); eeze_shutdown(); return EXIT_SUCCESS; } ELM_MAIN();