add tysend cmdline and support in escapes for sending single files

this allows you to send a file via escapes to terminology which will
pop up a file save dialog and ask what to save it as and where (based
on the original name). terminology will show a progress bar too. this
is not useful locally but remotely (e.g. you ssh'd into another
machine) it's a VERY handy way of fetching a file from the remote
machine to the local machine with a display just with tysend FILE. you
can send multiple in a sequence with tysend FILE1 FILE2 FILE3 ... ...
and terminology will ask for a location and filename per file you send
(just hit cancel if you don't want to do it).

note - it needs new theme features to work. it'll fail without them.

@feature
This commit is contained in:
Carsten Haitzler 2017-12-17 23:36:51 +09:00
parent 076093da5e
commit 125d475068
13 changed files with 860 additions and 10 deletions

19
README
View File

@ -299,3 +299,22 @@ ib
ie
= end media replace sequence run
fr[PATH/FILE]
= begin file send for a file named PATH/FILE
fs[SIZE_BYTES]
= set the size in bytes of a file send started with the above fr escape
fd[CHECKSUM DATA]
= block of data for the current file transfer with checksum as a
string decimal which is the sum of every byte when taken as an
unsigned char per byte. the checksum is a signed 32bit integer.
the checksum is the sum of the data after escaping. data will be
escaped using a 0xff byte as the escape header. the escape sequence
of 0xff 0x01 represents a 0x00 (nul) bytes, and 0xff 0x02 represents
a 0xff byte. all other bytes are transitted as-is.
fx
= exit file send mode (normally at the end of the file or when it's
complete)

View File

@ -651,6 +651,171 @@ collections {
target: "terminology.tabmissed.label";
}
////////////////////////////////////////////////////////////////////
// sendfile request
part { name: "sendfile_request_clip"; type: RECT;
description { state: "default" 0.0;
color: 255 255 255 0;
visible: 0;
}
description { state: "on" 0.0;
inherit: "default" 0.0;
visible: 1;
color: 255 255 255 255;
}
}
part { name: "sendfile_request_shadow";
mouse_events: 0;
clip_to: "sendfile_request_clip";
description { state: "default" 0.0;
fixed: 1 1;
rel.to: "sendfile_request_bg";
rel1.offset: -32 -32;
rel2.offset: 31 31;
image.normal: "pm_shadow.png";
image.border: 64 64 64 64;
fill.smooth: 0;
}
}
part { name: "sendfile_request_bg"; type: RECT;
clip_to: "sendfile_request_clip";
description { state: "default" 0.0;
color: 64 64 64 255;
rel1.relative: 0.0 -1.0;
rel2.relative: 1.0 0.0;
}
description { state: "on" 0.0;
inherit: "default" 0.0;
rel1.relative: 0.0 0.0;
rel2.relative: 1.0 1.0;
}
}
part { name: "terminology.sendfile.request"; type: SWALLOW;
clip_to: "sendfile_request_clip";
scale: 1;
description { state: "default" 0.0;
rel.to: "sendfile_request_bg";
rel1.offset: 4 4;
rel2.offset: -5 -5;
offscale;
}
description { state: "on" 0.0;
inherit: "default" 0.0;
rel1.relative: 0.0 0.0;
rel2.relative: 1.0 1.0;
}
}
program {
signal: "sendfile,request,on"; source: "terminology";
action: ACTION_STOP;
target: "sendfile_request_on";
target: "sendfile_request_off";
}
program {
signal: "sendfile,request,off"; source: "terminology";
action: ACTION_STOP;
target: "sendfile_request_on";
target: "sendfile_request_off";
}
program { name: "sendfile_request_on";
signal: "sendfile,request,on"; source: "terminology";
in: 0.5 0.0;
action: STATE_SET "on" 0.0;
transition: DECELERATE 0.5;
target: "sendfile_request_clip";
target: "sendfile_request_bg";
}
program { name: "sendfile_request_off";
signal: "sendfile,request,off"; source: "terminology";
action: STATE_SET "default" 0.0;
transition: DECELERATE 0.5;
target: "sendfile_request_clip";
target: "sendfile_request_bg";
}
////////////////////////////////////////////////////////////////////
// sendfile progress
part { name: "sendfile_progress_clip"; type: RECT;
description { state: "default" 0.0;
color: 255 255 255 0;
visible: 0;
}
description { state: "on" 0.0;
inherit: "default" 0.0;
visible: 1;
color: 255 255 255 255;
}
}
part { name: "sendfile_progress_shadow";
mouse_events: 0;
clip_to: "sendfile_progress_clip";
description { state: "default" 0.0;
fixed: 1 1;
rel.to: "sendfile_progress_bg";
rel1.offset: -32 -32;
rel2.offset: 31 31;
image.normal: "pm_shadow.png";
image.border: 64 64 64 64;
fill.smooth: 0;
}
}
part { name: "sendfile_progress_bg"; type: RECT;
clip_to: "sendfile_progress_clip";
scale : 1;
description { state: "default" 0.0;
color: 64 64 64 255;
rel.to: "terminology.sendfile.progress";
rel1.offset: -4 -4;
rel2.offset: 4 4;
offscale;
}
}
part { name: "terminology.sendfile.progress"; type: SWALLOW;
clip_to: "sendfile_progress_clip";
scale : 1;
description { state: "default" 0.0;
rel1.relative: 0.0 0.0;
rel1.offset: 4 -5;
rel2.relative: 1.0 0.0;
rel2.offset: -5 -5;
align: 0.5 1.0;
offscale;
}
description { state: "on" 0.0;
inherit: "default" 0.0;
rel1.offset: 4 4;
rel2.offset: -5 4;
align: 0.5 0.0;
}
}
program {
signal: "sendfile,progress,on"; source: "terminology";
action: ACTION_STOP;
target: "sendfile_progress_on";
target: "sendfile_progress_off";
}
program {
signal: "sendfile,progress,off"; source: "terminology";
action: ACTION_STOP;
target: "sendfile_progress_on";
target: "sendfile_progress_off";
}
program { name: "sendfile_progress_on";
signal: "sendfile,progress,on"; source: "terminology";
in: 0.5 0.0;
action: STATE_SET "on" 0.0;
transition: DECELERATE 0.5;
target: "sendfile_progress_clip";
target: "terminology.sendfile.progress";
}
program { name: "sendfile_progress_off";
signal: "sendfile,progress,off"; source: "terminology";
action: STATE_SET "default" 0.0;
transition: DECELERATE 0.5;
target: "sendfile_progress_clip";
target: "terminology.sendfile.progress";
}
////////////////////////////////////////////////////////////////////
// miniview
part { name: "terminology.miniview"; type: SWALLOW;

View File

@ -47,6 +47,7 @@ typop_sources = ['tycommon.c', 'tycommon.h', 'typop.c']
tyq_sources = ['tycommon.c', 'tycommon.h', 'tyq.c']
tycat_sources = ['tycommon.c', 'tycommon.h', 'tycat.c', 'extns.c', 'extns.h']
tyls_sources = ['extns.c', 'extns.h', 'tyls.c', 'tycommon.c', 'tycommon.h']
tysend_sources = ['tycommon.c', 'tycommon.h', 'tysend.c']
tyfuzz_sources = ['termptyesc.c', 'termptyesc.h',
'termptysave.c', 'termptysave.h',
'termptyops.c', 'termptyops.h',
@ -94,6 +95,11 @@ executable('tyls',
install: true,
include_directories: config_dir,
dependencies: terminology_dependencies)
executable('tysend',
tysend_sources,
install: true,
include_directories: config_dir,
dependencies: terminology_dependencies)
if fuzzing
executable('tyfuzz',

View File

@ -62,6 +62,13 @@ struct _Termio
unsigned char dndobjdel : 1;
} down;
} link;
struct {
const char *file;
FILE *f;
double progress;
unsigned long long total, size;
Eina_Bool active : 1;
} sendfile;
Evas_Object *ctxpopup;
int zoom_fontsize_start;
int scroll;
@ -4729,6 +4736,70 @@ _smart_cb_gest_zoom_abort(void *data, void *_event EINA_UNUSED)
}
/* }}} */
Eina_Bool
termio_file_send_ok(const Evas_Object *obj, const char *file)
{
Termio *sd = evas_object_smart_data_get(obj);
Termpty *ty;
if (!sd) return EINA_FALSE;
if (!file) return EINA_FALSE;
ty = sd->pty;
sd->sendfile.f = fopen(file, "w");
if (sd->sendfile.f)
{
if (sd->sendfile.file) eina_stringshare_del(sd->sendfile.file);
sd->sendfile.file = eina_stringshare_add(file);
sd->sendfile.active = EINA_TRUE;
termpty_write(ty, "k\n", 2);
return EINA_TRUE;
}
if (sd->sendfile.file) eina_stringshare_del(sd->sendfile.file);
sd->sendfile.file = NULL;
sd->sendfile.active = EINA_FALSE;
termpty_write(ty, "n\n", 2);
return EINA_FALSE;
}
void
termio_file_send_cancel(const Evas_Object *obj)
{
Termio *sd = evas_object_smart_data_get(obj);
Termpty *ty;
if (!sd) return;
ty = sd->pty;
if (!sd->sendfile.active) goto done;
sd->sendfile.progress = 0.0;
sd->sendfile.total = 0;
sd->sendfile.size = 0;
if (sd->sendfile.file)
{
ecore_file_unlink(sd->sendfile.file);
eina_stringshare_del(sd->sendfile.file);
sd->sendfile.file = NULL;
}
if (sd->sendfile.f)
{
fclose(sd->sendfile.f);
sd->sendfile.f = NULL;
}
sd->sendfile.active = EINA_FALSE;
done:
termpty_write(ty, "n\n", 2);
}
double
termio_file_send_progress_get(const Evas_Object *obj)
{
Termio *sd = evas_object_smart_data_get(obj);
if (!sd) return 0.0;
if (!sd->sendfile.active) return 0.0;
return sd->sendfile.progress;
}
/* {{{ Smart */
static void
@ -5431,6 +5502,21 @@ _smart_del(Evas_Object *obj)
evas_object_del(o);
}
if (sd->link.down.dndobj) evas_object_del(sd->link.down.dndobj);
if (sd->sendfile.active)
{
if (sd->sendfile.file)
{
ecore_file_unlink(sd->sendfile.file);
eina_stringshare_del(sd->sendfile.file);
sd->sendfile.file = NULL;
}
if (sd->sendfile.f)
{
fclose(sd->sendfile.f);
sd->sendfile.f = NULL;
}
sd->sendfile.active = EINA_FALSE;
}
keyin_compose_seq_reset(&sd->khdl);
if (sd->sel_str) eina_stringshare_del(sd->sel_str);
if (sd->preedit_str) eina_stringshare_del(sd->preedit_str);
@ -5927,6 +6013,116 @@ _smart_pty_command(void *data)
return;
}
}
else if (ty->cur_cmd[0] == 'f') // file...
{
if (ty->cur_cmd[1] == 'r') // receive
{
sd->sendfile.progress = 0.0;
sd->sendfile.total = 0;
sd->sendfile.size = 0;
}
else if (ty->cur_cmd[1] == 's') // file size
{
sd->sendfile.total = 0;
sd->sendfile.size = atoll(&(ty->cur_cmd[2]));
}
else if (ty->cur_cmd[1] == 'd') // data packet
{
int pksum = atoi(&(ty->cur_cmd[2]));
int sum;
char *p = strchr(ty->cur_cmd, ' ');
Eina_Bool valid = EINA_TRUE;
if (p)
{
Eina_Binbuf *bb = eina_binbuf_new();
unsigned char v;
int inp = 0;
if (bb)
{
p++;
sum = 0;
for (; *p; p++)
{
v = (unsigned char)(*p);
sum += v;
inp++;
if ((v == 0x1b) || (v == 0x07))
{
p++;
v = *p;
inp++;
sum += (unsigned char)(*p);
if (*p == 0x01) v = 0x00;
else if (*p == 0x02) v = 0xff;
else valid = EINA_FALSE;
}
eina_binbuf_append_char(bb, v);
}
if ((valid) && (sum == pksum) && (sd->sendfile.active))
{
// write "ok" (k) to term
size_t size = eina_binbuf_length_get(bb);
sd->sendfile.total += size;
if (sd->sendfile.size > 0.0)
{
sd->sendfile.progress =
(double)sd->sendfile.total /
(double)sd->sendfile.size;
evas_object_smart_callback_call
(obj, "send,progress", NULL);
}
fwrite(eina_binbuf_string_get(bb), size, 1,
sd->sendfile.f);
termpty_write(ty, "k\n", 2);
}
else
{
// write "not valid" (n) to term
if (sd->sendfile.file)
{
ecore_file_unlink(sd->sendfile.file);
eina_stringshare_del(sd->sendfile.file);
sd->sendfile.file = NULL;
}
if (sd->sendfile.f)
{
fclose(sd->sendfile.f);
sd->sendfile.f = NULL;
}
sd->sendfile.active = EINA_FALSE;
termpty_write(ty, "n\n", 2);
evas_object_smart_callback_call
(obj, "send,end", NULL);
}
eina_binbuf_free(bb);
}
}
}
else if (ty->cur_cmd[1] == 'x') // exit data stream
{
if (sd->sendfile.active)
{
sd->sendfile.progress = 0.0;
sd->sendfile.size = 0;
if (sd->sendfile.file)
{
eina_stringshare_del(sd->sendfile.file);
sd->sendfile.file = NULL;
}
if (sd->sendfile.f)
{
fclose(sd->sendfile.f);
sd->sendfile.f = NULL;
}
sd->sendfile.active = EINA_FALSE;
evas_object_smart_callback_call
(obj, "send,end", NULL);
}
}
}
evas_object_smart_callback_call(obj, "command", (void *)ty->cur_cmd);
}

View File

@ -45,6 +45,9 @@ void termio_media_mute_set(Evas_Object *obj, Eina_Bool mute);
void termio_media_visualize_set(Evas_Object *obj, Eina_Bool visualize);
void termio_config_set(Evas_Object *obj, Config *config);
Config *termio_config_get(const Evas_Object *obj);
Eina_Bool termio_file_send_ok(const Evas_Object *obj, const char *file);
void termio_file_send_cancel(const Evas_Object *obj);
double termio_file_send_progress_get(const Evas_Object *obj);
Termpty *termio_pty_get(const Evas_Object *obj);
Evas_Object * termio_miniview_get(const Evas_Object *obj);

View File

@ -46,7 +46,7 @@ main(int argc, char **argv)
snprintf(tbuf, sizeof(tbuf), "%c}ap%s", 0x1b, argv[i]);
else
snprintf(tbuf, sizeof(tbuf), "%c}at%s", 0x1b, argv[i]);
if (write(0, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write");
if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write");
}
return 0;
}

View File

@ -31,7 +31,7 @@ main(int argc, char **argv)
{
char tbuf[32];
snprintf(tbuf, sizeof(tbuf), "%c}bt", 0x1b);
if (write(0, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write");
if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write");
return 0;
}
for (i = 1; i < argc; i++)
@ -50,7 +50,7 @@ main(int argc, char **argv)
snprintf(tbuf, sizeof(tbuf), "%c}bp%s", 0x1b, path);
else
snprintf(tbuf, sizeof(tbuf), "%c}bt%s", 0x1b, path);
if (write(0, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write");
if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write");
}
return 0;
}

View File

@ -97,7 +97,7 @@ prnt(const char *path, int w, int h, int mode)
snprintf(buf, sizeof(buf), "%c}if#%i;%i;%s", 0x1b, w, h, path);
else
snprintf(buf, sizeof(buf), "%c}is#%i;%i;%s", 0x1b, w, h, path);
if (write(0, buf, strlen(buf) + 1) < 0) perror("write");
if (write(1, buf, strlen(buf) + 1) < 0) perror("write");
i = 0;
line[i++] = 0x1b;
line[i++] = '}';
@ -113,7 +113,7 @@ prnt(const char *path, int w, int h, int mode)
line[i++] = '\n';
for (y = 0; y < h; y++)
{
if (write(0, line, i) < 0) perror("write");
if (write(1, line, i) < 0) perror("write");
}
free(line);
}
@ -336,7 +336,7 @@ main(int argc, char **argv)
evas = ecore_evas_get(ee);
echo_off();
snprintf(buf, sizeof(buf), "%c}qs", 0x1b);
if (write(0, buf, strlen(buf) + 1) < 0) perror("write");
if (write(1, buf, strlen(buf) + 1) < 0) perror("write");
if (scanf("%i;%i;%i;%i", &tw, &th, &cw, &ch) != 4 ||
((tw <= 0) || (th <= 0) || (cw <= 1) || (ch <= 1)))
{

View File

@ -765,7 +765,7 @@ main(int argc, char **argv)
echo_off();
snprintf(buf, sizeof(buf), "%c}qs", 0x1b);
len = strlen(buf);
if (write(0, buf, len + 1) < (signed)len + 1) perror("write");
if (write(1, buf, len + 1) < (signed)len + 1) perror("write");
if ((scanf("%i;%i;%i;%i", &tw, &th, &cw, &ch) != 4)
|| (tw <= 0) || (th <= 0) || (cw <= 1) || (ch <= 1))
{

View File

@ -39,7 +39,7 @@ main(int argc, char **argv)
path = argv[i];
if (realpath(path, buf)) path = buf;
snprintf(tbuf, sizeof(tbuf), "%c}pn%s", 0x1b, path);
if (write(0, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write");
if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write");
}
return 0;
}

View File

@ -39,7 +39,7 @@ main(int argc, char **argv)
path = argv[i];
if (realpath(path, buf)) path = buf;
snprintf(tbuf, sizeof(tbuf), "%c}pq%s", 0x1b, path);
if (write(0, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write");
if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1)) perror("write");
}
return 0;
}

149
src/bin/tysend.c Normal file
View File

@ -0,0 +1,149 @@
#include "private.h"
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <Eina.h>
#include "tycommon.h"
static void
print_usage(const char *argv0)
{
printf("Usage: %s"HELP_ARGUMENT_SHORT" FILE1 [FILE2 ...]\n"
" Send file(s) to the terminal to save\n"
HELP_ARGUMENT_DOC"\n"
"\n",
argv0);
}
static struct termios told, tnew;
static int
echo_off(void)
{
if (tcgetattr(0, &told) != 0) return -1;
tnew = told;
tnew.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
tnew.c_oflag &= ~(OPOST);
tnew.c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN);
tnew.c_cflag &= ~(CSIZE | PARENB);
tnew.c_cflag |= CS8;
tnew.c_cc[VMIN] = 1;
tnew.c_cc[VTIME] = 0;
if (tcsetattr(0, TCSAFLUSH, &tnew) != 0) return -1;
return 0;
}
static int
echo_on(void)
{
return tcsetattr(0, TCSAFLUSH, &told);
}
int
main(int argc, char **argv)
{
int i;
ON_NOT_RUNNING_IN_TERMINOLOGY_EXIT_1();
ARGUMENT_ENTRY_CHECK(argc, argv, print_usage);
if (argc <= 1)
{
print_usage(argv[0]);
return 0;
}
echo_off();
for (i = 1; i < argc; i++)
{
char *path, buf[8192], tbuf[PATH_MAX * 3];
unsigned char rawbuf[8192 + 128], rawbuf2[8192 + 128];
int file_fd, pksize, pksum, bin, bout;
path = argv[i];
snprintf(tbuf, sizeof(tbuf), "%c}fr%s", 0x1b, path);
if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1))
goto err;
file_fd = open(path, O_RDONLY);
if (file_fd >= 0)
{
off_t off;
off = lseek(file_fd, 0, SEEK_END);
lseek(file_fd, 0, SEEK_SET);
snprintf(tbuf, sizeof(tbuf), "%c}fs%llu", 0x1b, (unsigned long long)off);
if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1))
goto err;
for (;;)
{
if (read(0, buf, 2) == 2)
{
if (buf[0] == 'k')
{
pksize = read(file_fd, rawbuf, 8192);
if (pksize > 0)
{
bout = 0;
for (bin = 0; bin < pksize; bin++)
{
if (rawbuf[bin] == 0x00)
{
rawbuf2[bout++] = 0xff;
rawbuf2[bout++] = 0x01;
}
else if (rawbuf[bin] == 0xff)
{
rawbuf2[bout++] = 0xff;
rawbuf2[bout++] = 0x02;
}
else
{
rawbuf2[bout++] = rawbuf[bin];
}
}
rawbuf2[bout] = 0;
pksum = 0;
for (bin = 0; bin < bout; bin++)
{
pksum += rawbuf2[bin];
}
snprintf(tbuf, sizeof(tbuf), "%c}fd%i ", 0x1b, pksum);
if (write(1, tbuf, strlen(tbuf)) != (signed)(strlen(tbuf)))
goto err;
if (write(1, rawbuf2, bout + 1) != bout + 1)
goto err;
}
else break;
}
else
{
echo_on();
fprintf(stderr, "Send Fail\n");
goto err;
}
}
else goto err;
}
close(file_fd);
}
snprintf(tbuf, sizeof(tbuf), "%c}fx", 0x1b);
if (write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1))
goto err;
tbuf[0] = 0;
if (write(1, tbuf, 1) != 1)
goto err;
}
echo_on();
return 0;
err:
echo_on();
return -1;
}

View File

@ -88,11 +88,17 @@ struct _Term
Evas_Object *popmedia;
Evas_Object *miniview;
Evas_Object *sel;
Evas_Object *sendfile_request;
Evas_Object *sendfile_progress;
Evas_Object *sendfile_progress_bar;
Evas_Object *tabcount_spacer;
Evas_Object *tab_spacer;
Evas_Object *tab_region_base;
Evas_Object *tab_region_bg;
Eina_List *popmedia_queue;
Ecore_Timer *sendfile_request_hide_timer;
Ecore_Timer *sendfile_progress_hide_timer;
const char *sendfile_dir;
Media_Type poptype, mediatype;
Tabbar tabbar;
int step_x, step_y, min_w, min_h, req_w, req_h;
@ -105,6 +111,9 @@ struct _Term
unsigned char missed_bell : 1;
unsigned char miniview_shown : 1;
unsigned char popmedia_deleted : 1;
Eina_Bool sendfile_request_enabled : 1;
Eina_Bool sendfile_progress_enabled : 1;
};
typedef struct _Solo Solo;
@ -3733,6 +3742,247 @@ _set_alpha(Config *config, const char *val, Eina_Bool save)
if (save) config_save(config, NULL);
}
static void
_sendfile_progress_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
{
Evas_Object *o = obj;
Term *term = evas_object_data_get(o, "sendfile-progress-term");
Ecore_Timer *t;
evas_object_data_del(o, "sendfile-progress-term");
if (term)
{
term->sendfile_progress = NULL;
term->sendfile_progress_bar = NULL;
}
t = evas_object_data_get(o, "sendfile-progress-timer");
evas_object_data_del(o, "sendfile-progress-term");
if (t) ecore_timer_del(t);
}
static Eina_Bool
_sendfile_progress_reset(void *data)
{
Evas_Object *o = data;
Term *term = evas_object_data_get(o, "sendfile-progress-term");
if (term)
{
term->sendfile_progress = NULL;
term->sendfile_progress_bar = NULL;
}
evas_object_data_del(o, "sendfile-progress-timer");
evas_object_data_del(o, "sendfile-progress-term");
evas_object_del(o);
return EINA_FALSE;
}
static Eina_Bool
_sendfile_progress_hide_delay(void *data)
{
Term *term = data;
Ecore_Timer *t;
term->sendfile_progress_hide_timer = NULL;
if (!term->sendfile_progress_enabled) return EINA_FALSE;
term->sendfile_progress_enabled = EINA_FALSE;
edje_object_signal_emit(term->bg, "sendfile,progress,off", "terminology");
t = evas_object_data_get(term->sendfile_progress, "sendfile-progress-timer");
if (t) ecore_timer_del(t);
t = ecore_timer_add(10.0, _sendfile_progress_reset, term->sendfile_progress);
evas_object_data_set(term->sendfile_progress, "sendfile-progress-timer", t);
return EINA_FALSE;
}
static void
_sendfile_progress_hide(Term *term)
{
if (!term->sendfile_progress_enabled) return;
if (term->sendfile_progress_hide_timer)
ecore_timer_del(term->sendfile_progress_hide_timer);
term->sendfile_progress_hide_timer =
ecore_timer_add(0.5, _sendfile_progress_hide_delay, term);
}
static void
_sendfile_progress_cancel(void *data, Evas_Object *obj EINA_UNUSED, void *info EINA_UNUSED)
{
Term *term = data;
if (!term->sendfile_progress) return;
termio_file_send_cancel(term->termio);
_sendfile_progress_hide(term);
}
static void
_sendfile_progress(Term *term)
{
Evas_Object *o, *base;
if (term->sendfile_progress)
{
evas_object_del(term->sendfile_progress);
term->sendfile_progress = NULL;
}
if (!edje_object_part_exists(term->bg, "terminology.sendfile.progress"))
{
return;
}
if (term->sendfile_progress_hide_timer)
{
ecore_timer_del(term->sendfile_progress_hide_timer);
term->sendfile_progress_hide_timer = NULL;
}
o = elm_box_add(term->wn->win);
evas_object_data_set(o, "sendfile-progress-term", term);
base = o;
term->sendfile_progress = o;
evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _sendfile_progress_del, NULL);
elm_box_horizontal_set(o, EINA_TRUE);
o = elm_button_add(term->wn->win);
elm_object_text_set(o, "Cancel");
evas_object_smart_callback_add(o, "clicked", _sendfile_progress_cancel, term);
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(base, o);
evas_object_show(o);
o = elm_progressbar_add(term->wn->win);
term->sendfile_progress_bar = o;
elm_progressbar_unit_format_set(o, "%1.0f%%");
evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(base, o);
evas_object_show(o);
term->sendfile_progress_enabled = EINA_TRUE;
edje_object_part_swallow(term->bg, "terminology.sendfile.progress", base);
evas_object_show(base);
edje_object_signal_emit(term->bg, "sendfile,progress,on", "terminology");
}
static void
_sendfile_request_del(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *info EINA_UNUSED)
{
Evas_Object *o = obj;
Term *term = evas_object_data_get(o, "sendfile-request-term");
Ecore_Timer *t;
evas_object_data_del(o, "sendfile-request-term");
if (term) term->sendfile_request = NULL;
t = evas_object_data_get(o, "sendfile-request-timer");
evas_object_data_del(o, "sendfile-request-term");
if (t) ecore_timer_del(t);
}
static Eina_Bool
_sendfile_request_reset(void *data)
{
Evas_Object *o = data;
Term *term = evas_object_data_get(o, "sendfile-request-term");
if (term) term->sendfile_request = NULL;
evas_object_data_del(o, "sendfile-request-timer");
evas_object_data_del(o, "sendfile-request-term");
evas_object_del(o);
return EINA_FALSE;
}
static Eina_Bool
_sendfile_request_hide_delay(void *data)
{
Term *term = data;
Ecore_Timer *t;
term->sendfile_request_hide_timer = NULL;
if (!term->sendfile_request_enabled) return EINA_FALSE;
term->sendfile_request_enabled = EINA_FALSE;
edje_object_signal_emit(term->bg, "sendfile,request,off", "terminology");
t = evas_object_data_get(term->sendfile_request, "sendfile-request-timer");
if (t) ecore_timer_del(t);
t = ecore_timer_add(10.0, _sendfile_request_reset, term->sendfile_request);
evas_object_data_set(term->sendfile_request, "sendfile-request-timer", t);
elm_object_focus_set(term->sendfile_request, EINA_FALSE);
_term_focus(term);
return EINA_FALSE;
}
static void
_sendfile_request_hide(Term *term)
{
if (!term->sendfile_request_enabled) return;
if (term->sendfile_request_hide_timer)
ecore_timer_del(term->sendfile_request_hide_timer);
term->sendfile_request_hide_timer =
ecore_timer_add(0.2, _sendfile_request_hide_delay, term);
}
static void
_sendfile_request_done(void *data, Evas_Object *obj EINA_UNUSED, void *info)
{
Term *term = data;
const char *path, *selpath = info;
if (!term->sendfile_request) return;
path = elm_fileselector_path_get(term->sendfile_request);
eina_stringshare_replace(&term->sendfile_dir, path);
if (selpath)
{
_sendfile_progress(term);
termio_file_send_ok(term->termio, selpath);
}
else termio_file_send_cancel(term->termio);
_sendfile_request_hide(term);
}
static void
_sendfile_request(Term *term, const char *path)
{
Evas_Object *o;
const char *p;
if (term->sendfile_request)
{
evas_object_del(term->sendfile_request);
term->sendfile_request = NULL;
}
if (!edje_object_part_exists(term->bg, "terminology.sendfile.request"))
{
termio_file_send_cancel(term->termio);
return;
}
if (term->sendfile_request_hide_timer)
{
ecore_timer_del(term->sendfile_request_hide_timer);
term->sendfile_request_hide_timer = NULL;
}
o = elm_fileselector_add(term->wn->win);
evas_object_data_set(o, "sendfile-request-term", term);
term->sendfile_request = o;
evas_object_event_callback_add(o, EVAS_CALLBACK_DEL, _sendfile_request_del, NULL);
elm_fileselector_is_save_set(o, EINA_TRUE);
elm_fileselector_expandable_set(o, EINA_FALSE);
if (!term->sendfile_dir)
{
const char *dir = eina_environment_home_get();
if (dir) term->sendfile_dir = eina_stringshare_add(dir);
}
if (term->sendfile_dir) elm_fileselector_path_set(o, term->sendfile_dir);
p = strrchr(path, '/');
if (p) elm_fileselector_current_name_set(o, p + 1);
else elm_fileselector_current_name_set(o, path);
evas_object_smart_callback_add(o, "done", _sendfile_request_done, term);
term->sendfile_request_enabled = EINA_TRUE;
edje_object_part_swallow(term->bg, "terminology.sendfile.request", o);
evas_object_show(o);
edje_object_signal_emit(term->bg, "sendfile,request,on", "terminology");
elm_object_focus_set(term->termio, EINA_FALSE);
elm_object_focus_set(o, EINA_TRUE);
}
static void
_cb_command(void *data,
Evas_Object *_obj EINA_UNUSED,
@ -3749,7 +3999,7 @@ _cb_command(void *data,
}
else if (cmd[1] == 'q') // queue it to display after current one
{
_popmedia_queue_add(term, cmd + 2);
_popmedia_queue_add(term, cmd + 2);
}
}
else if (cmd[0] == 'b') // set background
@ -3793,6 +4043,19 @@ _cb_command(void *data,
else if (cmd[1] == 'p') // permanent
_set_alpha(termio_config_get(term->termio), cmd + 2, EINA_TRUE);
}
else if (cmd[0] == 'f') // file...
{
if (cmd[1] == 'r') // receive
{
_sendfile_request(term, cmd + 2);
}
else if (cmd[1] == 'd') // data packet
{
}
else if (cmd[1] == 'x') // exit data stream
{
}
}
}
static void
@ -3872,6 +4135,28 @@ _cb_icon(void *data,
elm_win_icon_name_set(term->wn->win, termio_icon_name_get(term->termio));
}
static void
_cb_send_progress(void *data,
Evas_Object *_obj EINA_UNUSED,
void *_event EINA_UNUSED)
{
Term *term = data;
elm_progressbar_value_set(term->sendfile_progress_bar,
termio_file_send_progress_get(term->termio));
}
static void
_cb_send_end(void *data,
Evas_Object *_obj EINA_UNUSED,
void *_event EINA_UNUSED)
{
Term *term = data;
if (!term->sendfile_progress) return;
_sendfile_request_hide(term);
_sendfile_progress_hide(term);
}
static Eina_Bool
_cb_cmd_focus(void *data)
{
@ -4227,6 +4512,31 @@ _term_free(Term *term)
{
const char *s;
if (term->sendfile_request)
{
evas_object_del(term->sendfile_request);
term->sendfile_request = NULL;
}
if (term->sendfile_progress)
{
evas_object_del(term->sendfile_progress);
term->sendfile_progress = NULL;
}
if (term->sendfile_request_hide_timer)
{
ecore_timer_del(term->sendfile_request_hide_timer);
term->sendfile_request_hide_timer = NULL;
}
if (term->sendfile_progress_hide_timer)
{
ecore_timer_del(term->sendfile_progress_hide_timer);
term->sendfile_progress_hide_timer = NULL;
}
if (term->sendfile_dir)
{
eina_stringshare_del(term->sendfile_dir);
term->sendfile_dir = NULL;
}
EINA_LIST_FREE(term->popmedia_queue, s)
{
eina_stringshare_del(s);
@ -4616,6 +4926,8 @@ term_new(Win *wn, Config *config, const char *cmd,
evas_object_smart_callback_add(o, "split,v", _cb_split_v, term);
evas_object_smart_callback_add(o, "title,change", _cb_title, term);
evas_object_smart_callback_add(o, "icon,change", _cb_icon, term);
evas_object_smart_callback_add(o, "send,progress", _cb_send_progress, term);
evas_object_smart_callback_add(o, "send,end", _cb_send_end, term);
evas_object_show(o);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN,