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.
This commit is contained in:
Carsten Haitzler 2019-12-18 19:01:40 +00:00
parent 5ce109ab8f
commit 7227aaeb81
7 changed files with 1053 additions and 801 deletions

View File

@ -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://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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

208
src/modules/shot/upload.c Normal file
View File

@ -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://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()