Excellent !! :) Btw, if someone wanted to get a jump on this, the "emprint" tool in git already has the ability to select a crop region ... someone could, if they wanted to, snarf some code out of emprint and implement that feature in E pretty easily ;)
Cheers, dh On 12/19/19 6:25 PM, Carsten Haitzler wrote: > raster pushed a commit to branch master. > > https://protect2.fireeye.com/url?k=dcbf7a16-81717bc5-dcbef159-000babff317b-4e052b12d58063b7&u=http://git.enlightenment.org/core/enlightenment.git/commit/?id=7227aaeb813fddb6a42da848152bfecf4a9497e8 > > commit 7227aaeb813fddb6a42da848152bfecf4a9497e8 > Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com> > Date: Wed Dec 18 19:01:40 2019 +0000 > > shot - move save of shot and upload to slave binary tool and tidy code > > this gets rid of that annoying freeze in e due to the sync save and > possibly sync dns lookups in curl. slave binary handles it now and > talks back to e via stdout. > > this also splits up the code into more files for specific purposes to > make it easier to add features to and maintain. given on the todo is > the ability to explicitly select a crop region and do some basic > "drawing" too, this sets the stage for that and it made it easier to > do the above upload/save tool. > --- > src/modules/shot/e_mod_main.c | 819 > +-------------------------------------- > src/modules/shot/e_mod_main.h | 28 ++ > src/modules/shot/e_mod_preview.c | 291 ++++++++++++++ > src/modules/shot/e_mod_save.c | 273 +++++++++++++ > src/modules/shot/e_mod_share.c | 217 +++++++++++ > src/modules/shot/meson.build | 18 +- > src/modules/shot/upload.c | 208 ++++++++++ > 7 files changed, 1053 insertions(+), 801 deletions(-) > > 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 <time.h> > -#include <sys/mman.h> > +#include "e_mod_main.h" > > -#if defined(__FreeBSD__) || defined(__DragonFly__) > -#include <sys/types.h> > -#include <sys/sysctl.h> > -#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.<ps/>" > - "Please use '.jpg' or '.png' extensions<ps/>" > - "only as other formats are not<ps/>" > - "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:<ps/>" > - "%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://protect2.fireeye.com/url?k=d49fc69a-8951c749-d49e4dd5-000babff317b-084fde3e78e5eb55&u=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<ps/>" > - "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 <time.h> > +#include <sys/mman.h> > + > +#if defined(__FreeBSD__) || defined(__DragonFly__) > +# include <sys/types.h> > +# include <sys/sysctl.h> > +#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.<ps/>" > + "Please use '.jpg' or '.png' extensions<ps/>" > + "only as other formats are not<ps/>" > + "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:<ps/>%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<ps/>" > + "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 <Elementary.h> > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <fcntl.h> > + > +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://protect2.fireeye.com/url?k=b9adc0a4-e463c177-b9ac4beb-000babff317b-06320a5be253eae2&u=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() > _______________________________________________ enlightenment-devel mailing list enlightenment-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/enlightenment-devel