diff --git a/src/modules/shot/e_mod_main.c b/src/modules/shot/e_mod_main.c index f0ff786d2..ac3f9bcab 100644 --- a/src/modules/shot/e_mod_main.c +++ b/src/modules/shot/e_mod_main.c @@ -8,807 +8,28 @@ * * @} */ -#include "e.h" -#include -#include +#include "e_mod_main.h" -#if defined(__FreeBSD__) || defined(__DragonFly__) -#include -#include -#endif - -static E_Module *shot_module = NULL; +E_Module *shot_module = NULL; static E_Action *border_act = NULL, *act = NULL; static E_Int_Menu_Augmentation *maug = NULL; static Ecore_Timer *timer, *border_timer = NULL; -static Evas_Object *win = NULL; static Evas_Object *snap = NULL; -E_Confirm_Dialog *cd = NULL; -static Evas_Object *o_bg = NULL, *o_box = NULL, *o_content = NULL; -static Evas_Object *o_event = NULL, *o_img = NULL, *o_hlist = NULL; -static int quality = 90; -static int screen = -1; -#define MAXZONES 64 -static Evas_Object *o_rectdim[MAXZONES] = { NULL }; -static Evas_Object *o_radio_all = NULL; -static Evas_Object *o_radio[MAXZONES] = { NULL }; -static Evas_Object *o_fsel = NULL; -static Evas_Object *o_label = NULL; -static Evas_Object *o_entry = NULL; -static unsigned char *fdata = NULL; -static int fsize = 0; -static Ecore_Con_Url *url_up = NULL; -static Eina_List *handlers = NULL; -static char *url_ret = NULL; -static E_Dialog *fsel_dia = NULL; static E_Client_Menu_Hook *border_hook = NULL; static E_Client *shot_ec = NULL; static E_Zone *shot_zone = NULL; static char *shot_params; -static void _file_select_ok_cb(void *data EINA_UNUSED, E_Dialog *dia); -static void _file_select_cancel_cb(void *data EINA_UNUSED, E_Dialog *dia); - -static void -_win_cancel_cb(void *data EINA_UNUSED, void *data2 EINA_UNUSED) -{ - E_FREE_FUNC(win, evas_object_del); -} - -static void -_win_delete_cb() -{ - win = NULL; -} - -static void -_on_focus_cb(void *data EINA_UNUSED, Evas_Object *obj) -{ - if (obj == o_content) e_widget_focused_object_clear(o_box); - else if (o_content) e_widget_focused_object_clear(o_content); -} - -static void -_key_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) -{ - Evas_Event_Key_Down *ev = event; - - if (!strcmp(ev->key, "Tab")) - { - if (evas_key_modifier_is_set(evas_key_modifier_get(evas_object_evas_get(win)), "Shift")) - { - if (e_widget_focus_get(o_box)) - { - if (!e_widget_focus_jump(o_box, 0)) - { - e_widget_focus_set(o_content, 0); - if (!e_widget_focus_get(o_content)) - e_widget_focus_set(o_box, 0); - } - } - else - { - if (!e_widget_focus_jump(o_content, 0)) - e_widget_focus_set(o_box, 0); - } - } - else - { - if (e_widget_focus_get(o_box)) - { - if (!e_widget_focus_jump(o_box, 1)) - { - e_widget_focus_set(o_content, 1); - if (!e_widget_focus_get(o_content)) - e_widget_focus_set(o_box, 1); - } - } - else - { - if (!e_widget_focus_jump(o_content, 1)) - e_widget_focus_set(o_box, 1); - } - } - } - else if (((!strcmp(ev->key, "Return")) || - (!strcmp(ev->key, "KP_Enter")) || - (!strcmp(ev->key, "space")))) - { - Evas_Object *o = NULL; - - if ((o_content) && (e_widget_focus_get(o_content))) - o = e_widget_focused_object_get(o_content); - else - o = e_widget_focused_object_get(o_box); - if (o) e_widget_activate(o); - } - else if (!strcmp(ev->key, "Escape")) - _win_cancel_cb(NULL, NULL); -} - -static void -_save_key_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) -{ - Evas_Event_Key_Down *ev = event; - - if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter"))) - _file_select_ok_cb(NULL, fsel_dia); - else if (!strcmp(ev->key, "Escape")) - _file_select_cancel_cb(NULL, fsel_dia); -} - -static void -_screen_change_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) -{ - Eina_List *l; - E_Zone *z; - - EINA_LIST_FOREACH(e_comp->zones, l, z) - { - if (screen == -1) - evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 0); - else if (screen == (int)z->num) - evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 0); - else - evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 200); - } -} - -static void -_save_to(const char *file) -{ - char opts[256]; - - if (eina_str_has_extension(file, ".png")) - snprintf(opts, sizeof(opts), "compress=%i", 9); - else - snprintf(opts, sizeof(opts), "quality=%i", quality); - if (screen == -1) - { - if (o_img) - { - if (!evas_object_image_save(o_img, file, NULL, opts)) - e_util_dialog_show(_("Error saving screenshot file"), - _("Path: %s"), file); - } - } - else - { - Evas_Object *o; - Eina_List *l; - E_Zone *z = NULL; - - EINA_LIST_FOREACH(e_comp->zones, l, z) - { - if (screen == (int)z->num) break; - z = NULL; - } - if (z) - { - unsigned char *src, *dst, *s, *d; - int sstd, dstd, y; - - o = evas_object_image_add(evas_object_evas_get(o_img)); - evas_object_image_colorspace_set(o, EVAS_COLORSPACE_ARGB8888); - evas_object_image_alpha_set(o, EINA_FALSE); - evas_object_image_size_set(o, z->w, z->h); - dstd = evas_object_image_stride_get(o); - src = evas_object_image_data_get(o_img, EINA_FALSE); - sstd = evas_object_image_stride_get(o_img); - dst = evas_object_image_data_get(o, EINA_TRUE); - if ((dstd > 0) && (sstd > 0) && (src) && (dst)) - { - d = dst; - for (y = z->y; y < z->y + z->h; y++) - { - s = src + (sstd * y) + (z->x * 4); - memcpy(d, s, z->w * 4); - d += dstd; - } - if (!evas_object_image_save(o, file, NULL, opts)) - e_util_dialog_show(_("Error saving screenshot file"), - _("Path: %s"), file); - } - - evas_object_del(o); - } - } -} - -static void -_file_select_ok_cb(void *data EINA_UNUSED, E_Dialog *dia) -{ - const char *file; - - dia = fsel_dia; - file = e_widget_fsel_selection_path_get(o_fsel); - if ((!file) || (!file[0]) || - ((!eina_str_has_extension(file, ".jpg")) && - (!eina_str_has_extension(file, ".png")))) - { - e_util_dialog_show - (_("Error - Unknown format"), - _("File has an unspecified extension." - "Please use '.jpg' or '.png' extensions" - "only as other formats are not" - "supported currently.")); - return; - } - _save_to(file); - if (dia) e_util_defer_object_del(E_OBJECT(dia)); - E_FREE_FUNC(win, evas_object_del); - fsel_dia = NULL; -} - -static void -_file_select_cancel_cb(void *data EINA_UNUSED, E_Dialog *dia) -{ - if (dia) e_util_defer_object_del(E_OBJECT(dia)); - fsel_dia = NULL; -} - -static void -_file_select_del_cb(void *d EINA_UNUSED) -{ - fsel_dia = NULL; -} - -static void -_win_save_cb(void *data EINA_UNUSED, void *data2 EINA_UNUSED) -{ - E_Dialog *dia; - Evas_Object *o; - Evas_Coord mw, mh; - int mask = 0; - time_t tt; - struct tm *tm; - char buf[PATH_MAX]; - - time(&tt); - tm = localtime(&tt); - if (quality == 100) - strftime(buf, sizeof(buf), "shot-%Y-%m-%d_%H-%M-%S.png", tm); - else - strftime(buf, sizeof(buf), "shot-%Y-%m-%d_%H-%M-%S.jpg", tm); - fsel_dia = dia = e_dialog_new(NULL, "E", "_e_shot_fsel"); - e_dialog_resizable_set(dia, EINA_TRUE); - e_dialog_title_set(dia, _("Select screenshot save location")); - o = e_widget_fsel_add(evas_object_evas_get(dia->win), "desktop", "/", - buf, NULL, NULL, NULL, NULL, NULL, 1); - e_object_del_attach_func_set(E_OBJECT(dia), _file_select_del_cb); - e_widget_fsel_window_set(o, dia->win); - o_fsel = o; - evas_object_show(o); - e_widget_size_min_get(o, &mw, &mh); - e_dialog_content_set(dia, o, mw, mh); - e_dialog_button_add(dia, _("Save"), NULL, - _file_select_ok_cb, NULL); - e_dialog_button_add(dia, _("Cancel"), NULL, - _file_select_cancel_cb, NULL); - elm_win_center(dia->win, 1, 1); - o = evas_object_rectangle_add(evas_object_evas_get(dia->win)); - if (!evas_object_key_grab(o, "Return", mask, ~mask, 0)) - printf("grab err\n"); - mask = 0; - if (!evas_object_key_grab(o, "KP_Enter", mask, ~mask, 0)) - printf("grab err\n"); - mask = 0; - if (!evas_object_key_grab(o, "Escape", mask, ~mask, 0)) - printf("grab err\n"); - evas_object_event_callback_add(o, EVAS_CALLBACK_KEY_DOWN, - _save_key_down_cb, NULL); - e_dialog_show(dia); -} - -static void -_share_done(void) -{ - E_FREE_LIST(handlers, ecore_event_handler_del); - o_label = NULL; - E_FREE(url_ret); - E_FREE_FUNC(url_up, ecore_con_url_free); - url_up = NULL; -} - -static void -_upload_ok_cb(void *data EINA_UNUSED, E_Dialog *dia) -{ - // ok just hides dialog and does background upload - o_label = NULL; - if (dia) e_util_defer_object_del(E_OBJECT(dia)); - if (!win) return; - E_FREE_FUNC(win, evas_object_del); -} - -static void -_upload_cancel_cb(void *data EINA_UNUSED, E_Dialog *dia) -{ - o_label = NULL; - if (dia) e_util_defer_object_del(E_OBJECT(dia)); - E_FREE_FUNC(win, evas_object_del); - _share_done(); -} - -static Eina_Bool -_upload_data_cb(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event) -{ - Ecore_Con_Event_Url_Data *ev = event; - - if (ev->url_con != url_up) return EINA_TRUE; - if ((o_label) && (ev->size < 1024)) - { - char *txt = alloca(ev->size + 1); - - memcpy(txt, ev->data, ev->size); - txt[ev->size] = 0; -/* - printf("GOT %i bytes: '%s'\n", ev->size, txt); - int i; - for (i = 0; i < ev->size; i++) printf("%02x.", ev->data[i]); - printf("\n"); - */ - if (!url_ret) url_ret = strdup(txt); - else - { - char *n; - - n = malloc(strlen(url_ret) + ev->size + 1); - if (n) - { - strcpy(n, url_ret); - free(url_ret); - strcat(n, txt); - url_ret = n; - } - } - } - return EINA_FALSE; -} - -static Eina_Bool -_upload_progress_cb(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event) -{ - size_t total, current; - Ecore_Con_Event_Url_Progress *ev = event; - - if (ev->url_con != url_up) return ECORE_CALLBACK_RENEW; - total = ev->up.total; - current = ev->up.now; - if (o_label) - { - char buf[1024]; - char *buf_now, *buf_total; - - buf_now = e_util_size_string_get(current); - buf_total = e_util_size_string_get(total); - snprintf(buf, sizeof(buf), _("Uploaded %s / %s"), buf_now, buf_total); - E_FREE(buf_now); - E_FREE(buf_total); - e_widget_label_text_set(o_label, buf); - } - return ECORE_CALLBACK_RENEW; -} - -static Eina_Bool -_upload_complete_cb(void *data, int ev_type EINA_UNUSED, void *event) -{ - int status; - Ecore_Con_Event_Url_Complete *ev = event; - - if (ev->url_con != url_up) return ECORE_CALLBACK_RENEW; - status = ev->status; - - if (data) - e_widget_disabled_set(data, 1); - if (status != 200) - { - e_util_dialog_show(_("Error - Upload Failed"), - _("Upload failed with status code:" - "%i"), status); - _share_done(); - return EINA_FALSE; - } - if ((o_entry) && (url_ret)) - e_widget_entry_text_set(o_entry, url_ret); - _share_done(); - return ECORE_CALLBACK_RENEW; -} - -static void -_win_share_del(void *data EINA_UNUSED) -{ - if (handlers) - ecore_event_handler_data_set(eina_list_last_data_get(handlers), NULL); - _upload_cancel_cb(NULL, NULL); - if (cd) e_object_del(E_OBJECT(cd)); -} - -static void -_win_share_cb(void *data EINA_UNUSED, void *data2 EINA_UNUSED) -{ - E_Dialog *dia; - Evas_Object *o, *ol; - Evas_Coord mw, mh; - char buf[PATH_MAX]; - FILE *f; - int i, fd = -1; - - srand(time(NULL)); - for (i = 0; i < 10240; i++) - { - int v = rand(); - - if (quality == 100) - snprintf(buf, sizeof(buf), "/tmp/e-shot-%x.png", v); - else - snprintf(buf, sizeof(buf), "/tmp/e-shot-%x.jpg", v); - fd = open(buf, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); - if (fd >= 0) break; - } - if (fd < 0) - { - e_util_dialog_show(_("Error - Can't create file"), - _("Cannot create temporary file '%s': %s"), - buf, strerror(errno)); - E_FREE_FUNC(win, evas_object_del); - return; - } - _save_to(buf); - E_FREE_FUNC(win, evas_object_del); - f = fdopen(fd, "rb"); - if (!f) - { - e_util_dialog_show(_("Error - Can't open file"), - _("Cannot open temporary file '%s': %s"), - buf, strerror(errno)); - return; - } - fseek(f, 0, SEEK_END); - fsize = ftell(f); - if (fsize < 1) - { - e_util_dialog_show(_("Error - Bad size"), - _("Cannot get size of file '%s'"), - buf); - fclose(f); - return; - } - rewind(f); - free(fdata); - fdata = malloc(fsize); - if (!fdata) - { - e_util_dialog_show(_("Error - Can't allocate memory"), - _("Cannot allocate memory for picture: %s"), - strerror(errno)); - fclose(f); - return; - } - if (fread(fdata, fsize, 1, f) != 1) - { - e_util_dialog_show(_("Error - Can't read picture"), - _("Cannot read picture")); - E_FREE(fdata); - fclose(f); - return; - } - fclose(f); - ecore_file_unlink(buf); - - _share_done(); - - E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_DATA, - _upload_data_cb, NULL); - E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_PROGRESS, - _upload_progress_cb, NULL); - - url_up = ecore_con_url_new("https://www.enlightenment.org/shot.php"); - // why use http 1.1? proxies like squid don't handle 1.1 posts with expect - // like curl uses by default, so go to 1.0 and this all works dandily - // out of the box - ecore_con_url_http_version_set(url_up, ECORE_CON_URL_HTTP_VERSION_1_0); - ecore_con_url_post(url_up, fdata, fsize, "application/x-e-shot"); - dia = e_dialog_new(NULL, "E", "_e_shot_share"); - e_dialog_resizable_set(dia, EINA_TRUE); - e_dialog_title_set(dia, _("Uploading screenshot")); - - o = e_widget_list_add(evas_object_evas_get(dia->win), 0, 0); - ol = o; - - o = e_widget_label_add(evas_object_evas_get(dia->win), _("Uploading ...")); - o_label = o; - e_widget_list_object_append(ol, o, 0, 0, 0.5); - - o = e_widget_label_add(evas_object_evas_get(dia->win), - _("Screenshot is available at this location:")); - e_widget_list_object_append(ol, o, 0, 0, 0.5); - - o = e_widget_entry_add(dia->win, NULL, NULL, NULL, NULL); - o_entry = o; - e_widget_list_object_append(ol, o, 1, 0, 0.5); - - e_widget_size_min_get(ol, &mw, &mh); - e_dialog_content_set(dia, ol, mw, mh); - e_dialog_button_add(dia, _("Hide"), NULL, _upload_ok_cb, NULL); - e_dialog_button_add(dia, _("Cancel"), NULL, _upload_cancel_cb, NULL); - e_object_del_attach_func_set(E_OBJECT(dia), _win_share_del); - E_LIST_HANDLER_APPEND(handlers, ECORE_CON_EVENT_URL_COMPLETE, - _upload_complete_cb, - eina_list_last_data_get(dia->buttons)); - elm_win_center(dia->win, 1, 1); - e_dialog_show(dia); -} - -static void -_win_share_confirm_del(void *d EINA_UNUSED) -{ - cd = NULL; -} - -static void -_win_share_confirm_yes(void *d EINA_UNUSED) -{ - _win_share_cb(NULL, NULL); -} - -static void -_win_share_confirm_cb(void *d EINA_UNUSED, void *d2 EINA_UNUSED) -{ - if (cd) return; - cd = e_confirm_dialog_show(_("Confirm Share"), NULL, - _("This image will be uploaded" - "to enlightenment.org. It will be publicly visible."), - _("Confirm"), _("Cancel"), - _win_share_confirm_yes, NULL, - NULL, NULL, _win_share_confirm_del, NULL); -} - -static void -_rect_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) -{ - Evas_Event_Mouse_Down *ev = event_info; - Eina_List *l; - E_Zone *z; - - if (ev->button != 1) return; - - e_widget_radio_toggle_set(o_radio_all, 0); - EINA_LIST_FOREACH(e_comp->zones, l, z) - { - if (obj == o_rectdim[z->num]) - { - screen = z->num; - e_widget_radio_toggle_set(o_radio[z->num], 1); - } - else - e_widget_radio_toggle_set(o_radio[z->num], 0); - } - - EINA_LIST_FOREACH(e_comp->zones, l, z) - { - if (screen == -1) - evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 0); - else if (screen == (int)z->num) - evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 0); - else - evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 200); - } -} - -static void -_save_dialog_show(E_Zone *zone, E_Client *ec, const char *params, void *dst, int sw, int sh) -{ - Evas *evas, *evas2; - Evas_Object *o, *oa, *op, *ol; - Evas_Modifier_Mask mask; - E_Radio_Group *rg; - int w, h; - char smode[128], squal[128], sscreen[128]; - - win = elm_win_add(NULL, NULL, ELM_WIN_BASIC); - - evas = evas_object_evas_get(win); - elm_win_title_set(win, _("Where to put Screenshot...")); - evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, _win_delete_cb, NULL); - elm_win_center(win, 1, 1); - ecore_evas_name_class_set(e_win_ee_get(win), "E", "_shot_dialog"); - - o = elm_layout_add(e_win_evas_win_get(evas)); - elm_win_resize_object_add(win, o); - o_bg = o;; - e_theme_edje_object_set(o, "base/theme/dialog", "e/widgets/dialog/main"); - evas_object_show(o); - - o = e_widget_list_add(evas, 0, 0); - o_content = o; - elm_object_part_content_set(o_bg, "e.swallow.content", o); - evas_object_show(o); - - w = sw / 4; - if (w < 220) w = 220; - h = (w * sh) / sw; - - o = e_widget_aspect_add(evas, w, h); - oa = o; - o = e_widget_preview_add(evas, w, h); - op = o; - - evas2 = e_widget_preview_evas_get(op); - - o = evas_object_image_filled_add(evas2); - o_img = o; - evas_object_image_colorspace_set(o, EVAS_COLORSPACE_ARGB8888); - evas_object_image_alpha_set(o, EINA_FALSE); - evas_object_image_size_set(o, sw, sh); - evas_object_image_data_copy_set(o, dst); - - evas_object_image_data_update_add(o, 0, 0, sw, sh); - e_widget_preview_extern_object_set(op, o); - evas_object_show(o); - - evas_object_show(op); - evas_object_show(oa); - - e_widget_aspect_child_set(oa, op); - e_widget_list_object_append(o_content, oa, 0, 0, 0.5); - - o = e_widget_list_add(evas, 1, 1); - o_hlist = o; - - o = e_widget_framelist_add(evas, _("Quality"), 0); - ol = o; - - rg = e_widget_radio_group_new(&quality); - o = e_widget_radio_add(evas, _("Perfect"), 100, rg); - e_widget_framelist_object_append(ol, o); - o = e_widget_radio_add(evas, _("High"), 90, rg); - e_widget_framelist_object_append(ol, o); - o = e_widget_radio_add(evas, _("Medium"), 70, rg); - e_widget_framelist_object_append(ol, o); - o = e_widget_radio_add(evas, _("Low"), 50, rg); - e_widget_framelist_object_append(ol, o); - - e_widget_list_object_append(o_hlist, ol, 1, 0, 0.5); - - if (zone) - { - screen = -1; - if (eina_list_count(e_comp->zones) > 1) - { - Eina_List *l; - E_Zone *z; - int i; - - o = e_widget_framelist_add(evas, _("Screen"), 0); - ol = o; - - rg = e_widget_radio_group_new(&screen); - o = e_widget_radio_add(evas, _("All"), -1, rg); - o_radio_all = o; - evas_object_smart_callback_add(o, "changed", - _screen_change_cb, NULL); - e_widget_framelist_object_append(ol, o); - i = 0; - EINA_LIST_FOREACH(e_comp->zones, l, z) - { - char buf[32]; - - if (z->num >= MAXZONES) continue; - snprintf(buf, sizeof(buf), "%i", z->num); - o = e_widget_radio_add(evas, buf, z->num, rg); - o_radio[z->num] = o; - evas_object_smart_callback_add(o, "changed", - _screen_change_cb, NULL); - e_widget_framelist_object_append(ol, o); - - o = evas_object_rectangle_add(evas2); - evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, - _rect_down_cb, NULL); - o_rectdim[z->num] = o; - evas_object_color_set(o, 0, 0, 0, 0); - evas_object_show(o); - evas_object_geometry_get(o_img, NULL, NULL, &w, &h); - evas_object_move(o, (z->x * w) / sw, (z->y * h) / sh); - evas_object_resize(o, (z->w * w) / sw, (z->h * h) / sh); - i++; - } - - e_widget_list_object_append(o_hlist, ol, 1, 0, 0.5); - } - - } - e_widget_list_object_append(o_content, o_hlist, 0, 0, 0.5); - - o = o_content; - e_widget_size_min_get(o, &w, &h); - evas_object_size_hint_min_set(o, w, h); - elm_object_part_content_set(o_bg, "e.swallow.content", o); - evas_object_show(o); - - /////////////////////////////////////////////////////////////////////// - - o = e_widget_list_add(evas, 1, 1); - o_box = o; - e_widget_on_focus_hook_set(o, _on_focus_cb, NULL); - elm_object_part_content_set(o_bg, "e.swallow.buttons", o); - - o = e_widget_button_add(evas, _("Save"), NULL, _win_save_cb, win, NULL); - e_widget_list_object_append(o_box, o, 1, 0, 0.5); - o = e_widget_button_add(evas, _("Share"), NULL, - _win_share_confirm_cb, win, NULL); - e_widget_list_object_append(o_box, o, 1, 0, 0.5); - o = e_widget_button_add(evas, _("Cancel"), NULL, _win_cancel_cb, win, NULL); - e_widget_list_object_append(o_box, o, 1, 0, 0.5); - - o = o_box; - e_widget_size_min_get(o, &w, &h); - evas_object_size_hint_min_set(o, w, h); - elm_object_part_content_set(o_bg, "e.swallow.buttons", o); - - o = evas_object_rectangle_add(evas); - o_event = o; - mask = 0; - if (!evas_object_key_grab(o, "Tab", mask, ~mask, 0)) printf("grab err\n"); - mask = evas_key_modifier_mask_get(evas, "Shift"); - if (!evas_object_key_grab(o, "Tab", mask, ~mask, 0)) printf("grab err\n"); - mask = 0; - if (!evas_object_key_grab(o, "Return", mask, ~mask, 0)) printf("grab err\n"); - mask = 0; - if (!evas_object_key_grab(o, "KP_Enter", mask, ~mask, 0)) printf("grab err\n"); - mask = 0; - if (!evas_object_key_grab(o, "space", mask, ~mask, 0)) printf("grab err\n"); - mask = 0; - if (!evas_object_key_grab(o, "Escape", mask, ~mask, 0)) printf("grab err\n"); - evas_object_event_callback_add(o, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, NULL); - - evas_object_size_hint_min_get(o_bg, &w, &h); - evas_object_resize(o_bg, w, h); - evas_object_resize(win, w, h); - evas_object_size_hint_min_set(win, w, h); - evas_object_size_hint_max_set(win, 99999, 99999); - - if ((params) && - (sscanf(params, "%100s %100s %100s", smode, squal, sscreen) == 3)) - { - screen = -1; - if ((zone) && (!strcmp(sscreen, "current"))) screen = zone->num; - else if (!strcmp(sscreen, "all")) screen = -1; - else screen = atoi(sscreen); - - quality = 90; - if (!strcmp(squal, "perfect")) quality = 100; - else if (!strcmp(squal, "high")) quality = 90; - else if (!strcmp(squal, "medium")) quality = 70; - else if (!strcmp(squal, "low")) quality = 50; - else quality = atoi(squal); - - if (!strcmp(smode, "save")) _win_save_cb(NULL, NULL); - else if (!strcmp(smode, "share")) _win_share_cb(NULL, NULL); - } - else - { - evas_object_show(win); - e_win_client_icon_set(win, "screenshot"); - - if (!e_widget_focus_get(o_bg)) e_widget_focus_set(o_box, 1); - if (ec) - { - E_Client *c = e_win_client_get(win); - - if (c) evas_object_layer_set(c->frame, ec->layer); - } - } -} - static void _shot_post(void *buffer EINA_UNUSED, Evas *e EINA_UNUSED, void *event EINA_UNUSED) { int w, h; evas_object_geometry_get(snap, NULL, NULL, &w, &h); evas_event_callback_del(e_comp->evas, EVAS_CALLBACK_RENDER_POST, _shot_post); - _save_dialog_show(shot_zone, shot_ec, shot_params, (void*)evas_object_image_data_get(snap, 0), w, h); + preview_dialog_show(shot_zone, shot_ec, shot_params, + (void *)evas_object_image_data_get(snap, 0), w, h); E_FREE_FUNC(snap, evas_object_del); shot_ec = NULL; shot_zone = NULL; @@ -819,7 +40,7 @@ static void _shot_now(E_Zone *zone, E_Client *ec, const char *params) { int x, y, w, h; - if ((win) || (url_up) || snap) return; + if (preview_have() || save_have() || share_have() || (snap)) return; if ((!zone) && (!ec)) return; if (zone) { @@ -852,7 +73,9 @@ _shot_now(E_Zone *zone, E_Client *ec, const char *params) } if (eina_streq(ecore_evas_engine_name_get(e_comp->ee), "buffer")) { - _save_dialog_show(zone, ec, params, (void*)ecore_evas_buffer_pixels_get(e_comp->ee), w, h); + preview_dialog_show(zone, ec, params, + (void *)ecore_evas_buffer_pixels_get(e_comp->ee), + w, h); return; } shot_ec = ec; @@ -979,12 +202,9 @@ _e_mod_action_cb(E_Object *obj, const char *params) if (obj) { - if (obj->type == E_COMP_TYPE) - zone = e_zone_current_get(); - else if (obj->type == E_ZONE_TYPE) - zone = ((void *)obj); - else - zone = e_zone_current_get(); + if (obj->type == E_COMP_TYPE) zone = e_zone_current_get(); + else if (obj->type == E_ZONE_TYPE) zone = ((void *)obj); + else zone = e_zone_current_get(); } if (!zone) zone = e_zone_current_get(); if (!zone) return; @@ -993,9 +213,8 @@ _e_mod_action_cb(E_Object *obj, const char *params) e_object_ref(E_OBJECT(zone)); ds->zone = zone; ds->params = params ? strdup(params) : NULL; - /* forced main loop iteration in screenshots causes bugs if the action - * executes immediately - */ + // forced main loop iteration in screenshots causes bugs if the action + // executes immediately ecore_job_add(_delayed_shot, ds); } @@ -1010,9 +229,11 @@ _bd_hook(void *d EINA_UNUSED, E_Client *ec) if (ec->iconic || (ec->desk != e_desk_current_get(ec->zone))) return; m = ec->border_menu; - /* position menu item just before first separator */ + // position menu item just before first separator EINA_LIST_FOREACH(m->items, l, mi) - if (mi->separator) break; + { + if (mi->separator) break; + } if ((!mi) || (!mi->separator)) return; l = eina_list_prev(l); mi = eina_list_data_get(l); @@ -1083,9 +304,9 @@ e_modapi_init(E_Module *m) E_API int e_modapi_shutdown(E_Module *m EINA_UNUSED) { - _share_done(); - E_FREE_FUNC(win, evas_object_del); - E_FREE_FUNC(cd, e_object_del); + share_abort(); + save_abort(); + preview_abort(); if (timer) { ecore_timer_del(timer); diff --git a/src/modules/shot/e_mod_main.h b/src/modules/shot/e_mod_main.h new file mode 100644 index 000000000..1a3ce1a09 --- /dev/null +++ b/src/modules/shot/e_mod_main.h @@ -0,0 +1,28 @@ +#include "e.h" +#include +#include + +#if defined(__FreeBSD__) || defined(__DragonFly__) +# include +# include +#endif + +extern E_Module *shot_module; + +#define MAXZONES 64 + +void share_save (const char *cmd); +void share_write_end_watch (void *data); +void share_write_status_watch(void *data); +void share_dialog_show (void); +void share_confirm (void); +Eina_Bool share_have (void); +void share_abort (void); +void preview_dialog_show (E_Zone *zone, E_Client *ec, const char *params, void *dst, int sw, int sh); +Eina_Bool preview_have (void); +void preview_abort (void); +Evas_Object *preview_image_get (void); +void save_to (const char *file); +void save_dialog_show (void); +Eina_Bool save_have (void); +void save_abort (void); diff --git a/src/modules/shot/e_mod_preview.c b/src/modules/shot/e_mod_preview.c new file mode 100644 index 000000000..9232a655d --- /dev/null +++ b/src/modules/shot/e_mod_preview.c @@ -0,0 +1,291 @@ +#include "e_mod_main.h" + +static Evas_Object *win = NULL; +static Evas_Object *o_bg = NULL, *o_box = NULL, *o_content = NULL; +static Evas_Object *o_event = NULL, *o_img = NULL, *o_hlist = NULL; +static Evas_Object *o_rectdim[MAXZONES] = { NULL }; +static Evas_Object *o_radio_all = NULL; +static Evas_Object *o_radio[MAXZONES] = { NULL }; +static int quality = 90; +static int screen = -1; + +static void +_win_save_cb(void *data EINA_UNUSED, void *data2 EINA_UNUSED) +{ + save_dialog_show(); +} + +static void +_win_share_cb(void *d EINA_UNUSED, void *d2 EINA_UNUSED) +{ + share_confirm(); +} + +static void +_win_cancel_cb(void *data EINA_UNUSED, void *data2 EINA_UNUSED) +{ + E_FREE_FUNC(win, evas_object_del); +} + +static void +_win_delete_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) +{ + win = NULL; +} + +static void +_screen_change_cb(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Eina_List *l; + E_Zone *z; + + EINA_LIST_FOREACH(e_comp->zones, l, z) + { + if (screen == -1) + evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 0); + else if (screen == (int)z->num) + evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 0); + else + evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 200); + } +} + +static void +_rect_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info) +{ + Evas_Event_Mouse_Down *ev = event_info; + Eina_List *l; + E_Zone *z; + + if (ev->button != 1) return; + + e_widget_radio_toggle_set(o_radio_all, 0); + EINA_LIST_FOREACH(e_comp->zones, l, z) + { + if (obj == o_rectdim[z->num]) + { + screen = z->num; + e_widget_radio_toggle_set(o_radio[z->num], 1); + } + else + e_widget_radio_toggle_set(o_radio[z->num], 0); + } + + EINA_LIST_FOREACH(e_comp->zones, l, z) + { + if (screen == -1) + evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 0); + else if (screen == (int)z->num) + evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 0); + else + evas_object_color_set(o_rectdim[z->num], 0, 0, 0, 200); + } +} + +void +preview_dialog_show(E_Zone *zone, E_Client *ec, const char *params, void *dst, + int sw, int sh) +{ + Evas *evas, *evas2; + Evas_Object *o, *oa, *op, *ol; + E_Radio_Group *rg; + int w, h; + char smode[128], squal[128], sscreen[128]; + + win = elm_win_add(NULL, NULL, ELM_WIN_BASIC); + + evas = evas_object_evas_get(win); + elm_win_title_set(win, _("Select action to take with screenshot")); + evas_object_event_callback_add(win, EVAS_CALLBACK_DEL, _win_delete_cb, NULL); + elm_win_center(win, 1, 1); + ecore_evas_name_class_set(e_win_ee_get(win), "E", "_shot_dialog"); + + o = elm_layout_add(e_win_evas_win_get(evas)); + elm_win_resize_object_add(win, o); + o_bg = o; + e_theme_edje_object_set(o, "base/theme/dialog", "e/widgets/dialog/main"); + evas_object_show(o); + + o = e_widget_list_add(evas, 0, 0); + o_content = o; + elm_object_part_content_set(o_bg, "e.swallow.content", o); + evas_object_show(o); + + w = sw / 4; + if (w < 220) w = 220; + h = (w * sh) / sw; + + o = e_widget_aspect_add(evas, w, h); + oa = o; + o = e_widget_preview_add(evas, w, h); + op = o; + + evas2 = e_widget_preview_evas_get(op); + + o = evas_object_image_filled_add(evas2); + o_img = o; + evas_object_image_colorspace_set(o, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(o, EINA_FALSE); + evas_object_image_size_set(o, sw, sh); + evas_object_image_data_copy_set(o, dst); + + evas_object_image_data_update_add(o, 0, 0, sw, sh); + e_widget_preview_extern_object_set(op, o); + evas_object_show(o); + + evas_object_show(op); + evas_object_show(oa); + + e_widget_aspect_child_set(oa, op); + e_widget_list_object_append(o_content, oa, 0, 0, 0.5); + + o = e_widget_list_add(evas, 1, 1); + o_hlist = o; + + o = e_widget_framelist_add(evas, _("Quality"), 0); + ol = o; + + rg = e_widget_radio_group_new(&quality); + o = e_widget_radio_add(evas, _("Perfect"), 100, rg); + e_widget_framelist_object_append(ol, o); + o = e_widget_radio_add(evas, _("High"), 90, rg); + e_widget_framelist_object_append(ol, o); + o = e_widget_radio_add(evas, _("Medium"), 70, rg); + e_widget_framelist_object_append(ol, o); + o = e_widget_radio_add(evas, _("Low"), 50, rg); + e_widget_framelist_object_append(ol, o); + + e_widget_list_object_append(o_hlist, ol, 1, 0, 0.5); + + if (zone) + { + screen = -1; + if (eina_list_count(e_comp->zones) > 1) + { + Eina_List *l; + E_Zone *z; + int i; + + o = e_widget_framelist_add(evas, _("Screen"), 0); + ol = o; + + rg = e_widget_radio_group_new(&screen); + o = e_widget_radio_add(evas, _("All"), -1, rg); + o_radio_all = o; + evas_object_smart_callback_add(o, "changed", + _screen_change_cb, NULL); + e_widget_framelist_object_append(ol, o); + i = 0; + EINA_LIST_FOREACH(e_comp->zones, l, z) + { + char buf[32]; + + if (z->num >= MAXZONES) continue; + snprintf(buf, sizeof(buf), "%i", z->num); + o = e_widget_radio_add(evas, buf, z->num, rg); + o_radio[z->num] = o; + evas_object_smart_callback_add(o, "changed", + _screen_change_cb, NULL); + e_widget_framelist_object_append(ol, o); + + o = evas_object_rectangle_add(evas2); + evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, + _rect_down_cb, NULL); + o_rectdim[z->num] = o; + evas_object_color_set(o, 0, 0, 0, 0); + evas_object_show(o); + evas_object_geometry_get(o_img, NULL, NULL, &w, &h); + evas_object_move(o, (z->x * w) / sw, (z->y * h) / sh); + evas_object_resize(o, (z->w * w) / sw, (z->h * h) / sh); + i++; + } + e_widget_list_object_append(o_hlist, ol, 1, 0, 0.5); + } + + } + e_widget_list_object_append(o_content, o_hlist, 0, 0, 0.5); + + o = o_content; + e_widget_size_min_get(o, &w, &h); + evas_object_size_hint_min_set(o, w, h); + elm_object_part_content_set(o_bg, "e.swallow.content", o); + evas_object_show(o); + + /////////////////////////////////////////////////////////////////////// + + o = e_widget_list_add(evas, 1, 1); + o_box = o; + elm_object_part_content_set(o_bg, "e.swallow.buttons", o); + + o = e_widget_button_add(evas, _("Save"), NULL, _win_save_cb, win, NULL); + e_widget_list_object_append(o_box, o, 1, 0, 0.5); + o = e_widget_button_add(evas, _("Share"), NULL, _win_share_cb, win, NULL); + e_widget_list_object_append(o_box, o, 1, 0, 0.5); + o = e_widget_button_add(evas, _("Cancel"), NULL, _win_cancel_cb, win, NULL); + e_widget_list_object_append(o_box, o, 1, 0, 0.5); + + o = o_box; + e_widget_size_min_get(o, &w, &h); + evas_object_size_hint_min_set(o, w, h); + elm_object_part_content_set(o_bg, "e.swallow.buttons", o); + + o = evas_object_rectangle_add(evas); + o_event = o; + + evas_object_size_hint_min_get(o_bg, &w, &h); + evas_object_resize(o_bg, w, h); + evas_object_resize(win, w, h); + evas_object_size_hint_min_set(win, w, h); + evas_object_size_hint_max_set(win, 99999, 99999); + + if ((params) && + (sscanf(params, "%100s %100s %100s", smode, squal, sscreen) == 3)) + { + screen = -1; + if ((zone) && (!strcmp(sscreen, "current"))) screen = zone->num; + else if (!strcmp(sscreen, "all")) screen = -1; + else screen = atoi(sscreen); + + quality = 90; + if (!strcmp(squal, "perfect")) quality = 100; + else if (!strcmp(squal, "high")) quality = 90; + else if (!strcmp(squal, "medium")) quality = 70; + else if (!strcmp(squal, "low")) quality = 50; + else quality = atoi(squal); + + if (!strcmp(smode, "save")) _win_save_cb(NULL, NULL); + else if (!strcmp(smode, "share")) _win_share_cb(NULL, NULL); + } + else + { + evas_object_show(win); + e_win_client_icon_set(win, "screenshot"); + + if (!e_widget_focus_get(o_bg)) e_widget_focus_set(o_box, 1); + if (ec) + { + E_Client *c = e_win_client_get(win); + + if (c) evas_object_layer_set(c->frame, ec->layer); + } + } +} + +Eina_Bool +preview_have(void) +{ + if (win) return EINA_TRUE; + else return EINA_FALSE; +} + +void +preview_abort(void) +{ + E_FREE_FUNC(win, evas_object_del); +} + +Evas_Object * +preview_image_get(void) +{ + return o_img; +} diff --git a/src/modules/shot/e_mod_save.c b/src/modules/shot/e_mod_save.c new file mode 100644 index 000000000..9736f0d2c --- /dev/null +++ b/src/modules/shot/e_mod_save.c @@ -0,0 +1,273 @@ +#include "e_mod_main.h" + +static int quality = 90; +static int screen = -1; +static Evas_Object *o_fsel = NULL; +static E_Dialog *fsel_dia = NULL; + +static void _file_select_ok_cb(void *data EINA_UNUSED, E_Dialog *dia); +static void _file_select_cancel_cb(void *data EINA_UNUSED, E_Dialog *dia); + +typedef struct +{ + char *path, *outfile; + void *data; + int w, h, stride, quality; + size_t size; + int fd; +} Rgba_Writer_Data; + +static void +_rgba_data_free(Rgba_Writer_Data *rdata) +{ + free(rdata->path); + free(rdata->outfile); + free(rdata->data); + close(rdata->fd); + free(rdata); +} + +static void +_cb_rgba_writer_do(void *data, Ecore_Thread *th EINA_UNUSED) +{ + Rgba_Writer_Data *rdata = data; + if (write(rdata->fd, rdata->data, rdata->size) < 0) + ERR("Write of shot rgba data failed"); +} + +static void +_cb_rgba_writer_done(void *data, Ecore_Thread *th EINA_UNUSED) +{ + Rgba_Writer_Data *rdata = data; + char buf[PATH_MAX]; + + if (rdata->outfile) + snprintf(buf, sizeof(buf), "%s/%s/upload '%s' %i %i %i %i '%s'", + e_module_dir_get(shot_module), MODULE_ARCH, + rdata->path, rdata->w, rdata->h, rdata->stride, + rdata->quality, rdata->outfile); + else + snprintf(buf, sizeof(buf), "%s/%s/upload '%s' %i %i %i %i", + e_module_dir_get(shot_module), MODULE_ARCH, + rdata->path, rdata->w, rdata->h, rdata->stride, + rdata->quality); + share_save(buf); + _rgba_data_free(rdata); +} + +static void +_cb_rgba_writer_cancel(void *data, Ecore_Thread *th EINA_UNUSED) +{ + Rgba_Writer_Data *rdata = data; + _rgba_data_free(rdata); +} + +void +save_to(const char *file) +{ + int fd; + char tmpf[256] = "e-shot-rgba-XXXXXX"; + Eina_Tmpstr *path = NULL; + int imw = 0, imh = 0, imstride; + + fd = eina_file_mkstemp(tmpf, &path); + if (fd >= 0) + { + unsigned char *data = NULL; + Rgba_Writer_Data *thdat = NULL; + size_t size = 0; + Evas_Object *img = preview_image_get(); + + if (screen == -1) + { + if (img) + { + int w = 0, h = 0; + int stride = evas_object_image_stride_get(img); + unsigned char *src_data = evas_object_image_data_get(img, EINA_FALSE); + + evas_object_image_size_get(img, &w, &h); + if ((stride > 0) && (src_data) && (h > 0)) + { + imw = w; + imh = h; + imstride = stride; + size = stride * h; + data = malloc(size); + if (data) memcpy(data, src_data, size); + } + } + } + else + { + if (img) + { + int w = 0, h = 0; + int stride = evas_object_image_stride_get(img); + unsigned char *src_data = evas_object_image_data_get(img, EINA_FALSE); + + evas_object_image_size_get(img, &w, &h); + if ((stride > 0) && (src_data) && (h > 0)) + { + Eina_List *l; + E_Zone *z = NULL; + + EINA_LIST_FOREACH(e_comp->zones, l, z) + { + if (screen == (int)z->num) break; + z = NULL; + } + if (z) + { + size = z->w * z->h * 4; + data = malloc(size); + if (data) + { + int y; + unsigned char *s, *d; + + imw = z->w; + imh = z->h; + imstride = imw * 4; + d = data; + for (y = z->y; y < (z->y + z->h); y++) + { + s = src_data + (stride * y) + (z->x * 4); + memcpy(d, s, z->w * 4); + d += z->w * 4; + } + } + } + } + } + } + if (data) + { + thdat = calloc(1, sizeof(Rgba_Writer_Data)); + if (thdat) + { + thdat->path = strdup(path); + if (file) thdat->outfile = strdup(file); + if ((thdat->path) && + (((file) && (thdat->outfile)) || + (!file))) + { + thdat->data = data; + thdat->size = size; + thdat->fd = fd; + thdat->w = imw; + thdat->h = imh; + thdat->stride = imstride; + thdat->quality = quality; + ecore_thread_run(_cb_rgba_writer_do, + _cb_rgba_writer_done, + _cb_rgba_writer_cancel, thdat); + } + else + { + free(thdat->path); + free(thdat->outfile); + free(thdat); + thdat = NULL; + } + } + else + { + close(fd); + free(data); + } + } + if (!thdat) close(fd); + eina_tmpstr_del(path); + } + return; +} + +static void +_file_select_ok_cb(void *data EINA_UNUSED, E_Dialog *dia) +{ + const char *file; + + dia = fsel_dia; + file = e_widget_fsel_selection_path_get(o_fsel); + if ((!file) || (!file[0]) || + ((!eina_str_has_extension(file, ".jpg")) && + (!eina_str_has_extension(file, ".png")))) + { + e_util_dialog_show + (_("Error - Unknown format"), + _("File has an unspecified extension." + "Please use '.jpg' or '.png' extensions" + "only as other formats are not" + "supported currently.")); + return; + } + save_to(file); + if (dia) e_util_defer_object_del(E_OBJECT(dia)); + preview_abort(); + fsel_dia = NULL; +} + +static void +_file_select_cancel_cb(void *data EINA_UNUSED, E_Dialog *dia) +{ + if (dia) e_util_defer_object_del(E_OBJECT(dia)); + preview_abort(); + fsel_dia = NULL; +} + +static void +_file_select_del_cb(void *d EINA_UNUSED) +{ + preview_abort(); + fsel_dia = NULL; +} + +void +save_dialog_show(void) +{ + E_Dialog *dia; + Evas_Object *o; + Evas_Coord mw, mh; + time_t tt; + struct tm *tm; + char buf[PATH_MAX]; + + time(&tt); + tm = localtime(&tt); + if (quality == 100) + strftime(buf, sizeof(buf), "shot-%Y-%m-%d_%H-%M-%S.png", tm); + else + strftime(buf, sizeof(buf), "shot-%Y-%m-%d_%H-%M-%S.jpg", tm); + fsel_dia = dia = e_dialog_new(NULL, "E", "_e_shot_fsel"); + e_dialog_resizable_set(dia, EINA_TRUE); + e_dialog_title_set(dia, _("Select screenshot save location")); + o = e_widget_fsel_add(evas_object_evas_get(dia->win), "desktop", "/", + buf, NULL, NULL, NULL, NULL, NULL, 1); + e_object_del_attach_func_set(E_OBJECT(dia), _file_select_del_cb); + e_widget_fsel_window_set(o, dia->win); + o_fsel = o; + evas_object_show(o); + e_widget_size_min_get(o, &mw, &mh); + e_dialog_content_set(dia, o, mw, mh); + e_dialog_button_add(dia, _("Save"), NULL, + _file_select_ok_cb, NULL); + e_dialog_button_add(dia, _("Cancel"), NULL, + _file_select_cancel_cb, NULL); + elm_win_center(dia->win, 1, 1); + o = evas_object_rectangle_add(evas_object_evas_get(dia->win)); + e_dialog_show(dia); +} + +Eina_Bool +save_have(void) +{ + if (fsel_dia) return EINA_TRUE; + return EINA_FALSE; +} + +void +save_abort(void) +{ + E_FREE_FUNC(fsel_dia, e_object_del); +} diff --git a/src/modules/shot/e_mod_share.c b/src/modules/shot/e_mod_share.c new file mode 100644 index 000000000..2024f7fc9 --- /dev/null +++ b/src/modules/shot/e_mod_share.c @@ -0,0 +1,217 @@ +#include "e_mod_main.h" + +static Evas_Object *win = NULL; +static E_Confirm_Dialog *cd = NULL; +static Ecore_Exe *img_write_exe = NULL; +static Evas_Object *o_label = NULL; +static Evas_Object *o_entry = NULL; +static Eina_List *handlers = NULL; +static char *url_ret = NULL; + +// clean up and be done +static void +_share_done(void) +{ + E_FREE_LIST(handlers, ecore_event_handler_del); + free(url_ret); + o_label = NULL; + img_write_exe = NULL; + url_ret = NULL; + preview_abort(); +} + +// the upload dialog +static void +_upload_ok_cb(void *data EINA_UNUSED, E_Dialog *dia) +{ + // ok just hides dialog and does background upload + o_label = NULL; + if (dia) e_util_defer_object_del(E_OBJECT(dia)); + if (!win) return; + E_FREE_FUNC(win, evas_object_del); +} + +static void +_upload_cancel_cb(void *data EINA_UNUSED, E_Dialog *dia) +{ + o_label = NULL; + if (dia) e_util_defer_object_del(E_OBJECT(dia)); + E_FREE_FUNC(win, evas_object_del); + _share_done(); +} + +static Eina_Bool +_img_write_end_cb(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event) +{ + Ecore_Exe_Event_Del *ev = event; + + if (ev->exe != img_write_exe) return EINA_TRUE; + _share_done(); + return EINA_FALSE; +} + +static Eina_Bool +_img_write_out_cb(void *data, int ev_type EINA_UNUSED, void *event) +{ + Ecore_Exe_Event_Data *ev = event; + int i; + + if (ev->exe != img_write_exe) return EINA_TRUE; + if (!((ev->lines) && (ev->lines[0].line))) goto done; + for (i = 0; ev->lines[i].line; i++) + { + const char *l = ev->lines[i].line; + + if ((l[0] == 'U') && (l[1] == ' ')) + { + int v = atoi(l + 2); + if ((v >= 0) && (v <= 1000)) + { + char buf[128]; + // update gui... + snprintf(buf, sizeof(buf), _("Uploaded %i%%"), (v * 100) / 1000); + e_widget_label_text_set(o_label, buf); + } + } + else if ((l[0] == 'R') && (l[1] == ' ')) + { + const char *r = l + 2; + // finished - got final url + if (!url_ret) url_ret = strdup(r); + } + else if ((l[0] == 'E') && (l[1] == ' ')) + { + int err = atoi(l + 2); + if (data) e_widget_disabled_set(data, 1); + e_util_dialog_show(_("Error - Upload Failed"), + _("Upload failed with status code:%i"), + err); + _share_done(); + break; + } + else if ((l[0] == 'O')) + { + if (data) e_widget_disabled_set(data, 1); + if ((o_entry) && (url_ret)) + e_widget_entry_text_set(o_entry, url_ret); + _share_done(); + break; + } + } +done: + return EINA_FALSE; +} + +void +share_save(const char *cmd) +{ + share_write_end_watch(NULL); + img_write_exe = ecore_exe_pipe_run + (cmd, ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_READ_LINE_BUFFERED | + ECORE_EXE_NOT_LEADER | ECORE_EXE_TERM_WITH_PARENT, NULL); +} + +void +share_write_end_watch(void *data) +{ + E_LIST_HANDLER_APPEND(handlers, ECORE_EXE_EVENT_DEL, + _img_write_end_cb, data); +} + +void +share_write_status_watch(void *data) +{ + E_LIST_HANDLER_APPEND(handlers, ECORE_EXE_EVENT_DATA, + _img_write_out_cb, data); +} + +static void +_win_share_del(void *data EINA_UNUSED) +{ + if (handlers) + ecore_event_handler_data_set(eina_list_last_data_get(handlers), NULL); + _upload_cancel_cb(NULL, NULL); + if (cd) e_object_del(E_OBJECT(cd)); +} + +void +share_dialog_show(void) +{ + E_Dialog *dia; + Evas_Object *o, *ol; + Evas_Coord mw, mh; + + E_FREE_LIST(handlers, ecore_event_handler_del); + + save_to(NULL); + + E_FREE_FUNC(win, evas_object_del); + + dia = e_dialog_new(NULL, "E", "_e_shot_share"); + e_dialog_resizable_set(dia, EINA_TRUE); + e_dialog_title_set(dia, _("Uploading screenshot")); + + o = e_widget_list_add(evas_object_evas_get(dia->win), 0, 0); + ol = o; + + o = e_widget_label_add(evas_object_evas_get(dia->win), _("Uploading ...")); + o_label = o; + e_widget_list_object_append(ol, o, 0, 0, 0.5); + + o = e_widget_label_add(evas_object_evas_get(dia->win), + _("Screenshot is available at this location:")); + e_widget_list_object_append(ol, o, 0, 0, 0.5); + + o = e_widget_entry_add(dia->win, NULL, NULL, NULL, NULL); + o_entry = o; + e_widget_list_object_append(ol, o, 1, 0, 0.5); + + e_widget_size_min_get(ol, &mw, &mh); + e_dialog_content_set(dia, ol, mw, mh); + e_dialog_button_add(dia, _("Hide"), NULL, _upload_ok_cb, NULL); + e_dialog_button_add(dia, _("Cancel"), NULL, _upload_cancel_cb, NULL); + e_object_del_attach_func_set(E_OBJECT(dia), _win_share_del); + share_write_status_watch(eina_list_last_data_get(dia->buttons)); + elm_win_center(dia->win, 1, 1); + e_dialog_show(dia); +} + +// confirm dialog that it's ok to share +static void +_win_share_confirm_del(void *d EINA_UNUSED) +{ + cd = NULL; +} + +static void +_win_share_confirm_yes(void *d EINA_UNUSED) +{ + share_dialog_show(); +} + +void +share_confirm(void) +{ + if (cd) return; + cd = e_confirm_dialog_show + (_("Confirm Share"), NULL, + _("This image will be uploaded" + "to enlightenment.org. It will be publicly visible."), + _("Confirm"), _("Cancel"), + _win_share_confirm_yes, NULL, + NULL, NULL, _win_share_confirm_del, NULL); +} + +Eina_Bool +share_have(void) +{ + if (img_write_exe) return EINA_TRUE; + return EINA_FALSE; +} + +void +share_abort(void) +{ + E_FREE_FUNC(cd, e_object_del); + E_FREE_FUNC(win, evas_object_del); +} diff --git a/src/modules/shot/meson.build b/src/modules/shot/meson.build index 42119f40e..132fc98a3 100644 --- a/src/modules/shot/meson.build +++ b/src/modules/shot/meson.build @@ -1,3 +1,17 @@ src = files( - 'e_mod_main.c' - ) + 'e_mod_main.c', + 'e_mod_main.h', + 'e_mod_preview.c', + 'e_mod_save.c', + 'e_mod_share.c' +) + +if get_option(m) == true + executable('upload', + 'upload.c', + include_directories: include_directories(module_includes), + dependencies : [ dep_elementary ], + install_dir : _dir_bin, + install : true + ) +endif diff --git a/src/modules/shot/upload.c b/src/modules/shot/upload.c new file mode 100644 index 000000000..b7236a30c --- /dev/null +++ b/src/modules/shot/upload.c @@ -0,0 +1,208 @@ +#include +#include +#include +#include + +static Ecore_Con_Url *url_up = NULL; + +static Eina_Bool +_upload_data_cb(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Url_Data *ev = event; + + if (ev->url_con != url_up) return EINA_TRUE; + if (ev->size < 1024) + { + char *txt = alloca(ev->size + 1); + + memcpy(txt, ev->data, ev->size); + txt[ev->size] = 0; + printf("R %s\n", txt); + fflush(stdout); + } + return EINA_FALSE; +} + +static Eina_Bool +_upload_progress_cb(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event) +{ + size_t total, current; + Ecore_Con_Event_Url_Progress *ev = event; + + if (ev->url_con != url_up) return EINA_TRUE; + total = ev->up.total; + current = ev->up.now; + if (total > 0) + { + printf("U %i\n", (int)((current * 1000) / total)); + fflush(stdout); + } + return EINA_FALSE; +} + +static Eina_Bool +_upload_complete_cb(void *data EINA_UNUSED, int ev_type EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Url_Complete *ev = event; + + if (ev->url_con != url_up) return EINA_TRUE; + if (ev->status != 200) printf("E %i\n", ev->status); + else printf("O\n"); + fflush(stdout); + elm_exit(); + return EINA_FALSE; +} + +static Eina_Bool +find_tmpfile(int quality, char *buf, size_t buf_size) +{ + int i; + + // come up with a tmp file - not really that critical as its due for + // sharing to the internet as a whole + srand(time(NULL)); + for (i = 0; i < 100; i++) + { + int fd, v = rand(); + + if (quality == 100) snprintf(buf, buf_size, "/tmp/e-shot-%x.png", v); + else snprintf(buf, buf_size, "/tmp/e-shot-%x.jpg", v); + fd = open(buf, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + if (fd >= 0) + { + close(fd); + return EINA_TRUE; + } + close(fd); + } + return EINA_FALSE; +} + +EAPI int +elm_main(int argc, char **argv) +{ + Evas_Object *win, *image; + Eina_File *infile; + void *fdata; + size_t fsize; + Eina_Bool upload = EINA_FALSE; + const char *rgba_file, *out_file = NULL; + int w, h, stride, quality, image_stride, y; + char *image_data, *src; + char opts[256]; + + if (argc < 6) return 1; + + rgba_file = argv[1]; // path to raw linear memory format rgba32 pixel data + w = atoi(argv[2]); // width in pixels + h = atoi(argv[3]); // height in pixels + stride = atoi(argv[4]); // stride per line in bytes + quality = atoi(argv[5]); // qwuality to save out as (100 == lossless png) + if (argc >= 7) out_file = eina_stringshare_add(argv[6]); // out file path + + // set up buffer window as scratch space + elm_config_preferred_engine_set("buffer"); + win = elm_win_add(NULL, "Shot-Upload", ELM_WIN_BASIC); + elm_win_norender_push(win); + + // come up with tmp out file if no dest out provided + if (!out_file) + { + char buf[PATH_MAX]; + + upload = EINA_TRUE; + if (find_tmpfile(quality, buf, sizeof(buf))) + out_file = eina_stringshare_add(buf); + } + // open raw rgba data file which we willl mmap + infile = eina_file_open(rgba_file, EINA_FALSE); + if (!infile) return 2; + fsize = eina_file_size_get(infile); + fdata = eina_file_map_all(infile, EINA_FILE_SEQUENTIAL); + if (!((fsize > 0) && (fdata))) + { + ecore_file_unlink(rgba_file); + return 3; + } + + // create image objectfor saving out with right format and size + image = evas_object_image_add(evas_object_evas_get(win)); + evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(image, EINA_FALSE); + evas_object_image_size_set(image, w, h); + image_stride = evas_object_image_stride_get(image); + image_data = evas_object_image_data_get(image, EINA_TRUE); + if (!((image_stride > 0) && (image_data))) + { + ecore_file_unlink(rgba_file); + return 4; + } + // copy data into output image (could also set data straight in + src = fdata; + for (y = 0; y < h; y++) + { + memcpy(image_data, src, w * 4); + image_data += image_stride; + src += stride; + } + if (quality == 100) + snprintf(opts, sizeof(opts), "compress=%i", 9); + else + snprintf(opts, sizeof(opts), "quality=%i", quality); + eina_file_close(infile); + ecore_file_unlink(rgba_file); + // save the file + if (!evas_object_image_save(image, out_file, NULL, opts)) + return 5; + + // if we have to upload it, open our output file, mmap it and upload + if (upload) + { + infile = eina_file_open(out_file, EINA_FALSE); + if (infile) + { + fsize = eina_file_size_get(infile); + fdata = eina_file_map_all(infile, EINA_FILE_SEQUENTIAL); + if ((fsize > 0) && (fdata)) + { + Ecore_Event_Handler *h1, *h2, *h3; + + h1 = ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, + _upload_data_cb, NULL); + h2 = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, + _upload_progress_cb, NULL); + h3 = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, + _upload_complete_cb, NULL); + if ((h1) && (h2) && (h3)) + { + url_up = ecore_con_url_new + ("https://www.enlightenment.org/shot.php"); + if (url_up) + { + // why use http 1.1? proxies like squid don't + // handle 1.1 posts with expect like curl uses + // by default, so go to 1.0 and this all works + // dandily out of the box + ecore_con_url_http_version_set + (url_up, ECORE_CON_URL_HTTP_VERSION_1_0); + ecore_con_url_post + (url_up, fdata, fsize, "application/x-e-shot"); + // need loop to run to drive the uploading + elm_run(); + } + } + ecore_event_handler_del(h1); + ecore_event_handler_del(h2); + ecore_event_handler_del(h3); + } + if (fdata) eina_file_map_free(infile, fdata); + eina_file_close(infile); + } + // output was temporary here + ecore_file_unlink(out_file); + } + evas_object_del(win); + eina_stringshare_del(out_file); + return 0; +} +ELM_MAIN()