Terminal emulator with all the bells and whistles https://www.enlightenment.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

409 lines
8.8 KiB

#include <Eina.h>
#include <Ecore.h>
#include <Evas.h>
#include <Ecore_Evas.h>
#include <Ecore_File.h>
#include <Edje.h>
#include <Emotion.h>
#include <termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "private.h"
#include "tycommon.h"
enum {
CENTER,
FILL,
STRETCH,
NOIMG
};
#define VIDEO_DECODE_TIMEOUT 1.0
static Evas *evas = NULL;
static struct termios told, tnew;
static int tw = 0, th = 0, cw = 0, ch = 0, maxw = 0, maxh = 0, _mode = CENTER;
static Ecore_Timer *timeout_t = NULL;
#include "extns.h"
static int
echo_off(void)
{
if (tcgetattr(0, &told) != 0) return -1;
tnew = told;
tnew.c_lflag &= ~ECHO;
if (tcsetattr(0, TCSAFLUSH, &tnew) != 0) return -1;
return 0;
}
static int
echo_on(void)
{
return tcsetattr(0, TCSAFLUSH, &told);
}
static void
scaleterm(int w, int h, int *iw, int *ih)
{
int width = maxw ? maxw : tw;
if (w > (width * cw))
{
*iw = width;
*ih = DIV_ROUND_UP((h * (width * cw) / w), ch);
}
else
{
*iw = DIV_ROUND_UP(w, cw);
*ih = DIV_ROUND_UP(h, ch);
}
if (maxh && *ih > maxh)
{
*ih = maxh;
*iw = DIV_ROUND_UP((w * (maxh * ch) / h), cw);
}
}
static void
prnt(const char *path, int w, int h, int mode)
{
int x, y, i;
char *line, buf[4096];
if ((w >= 512) || (h >= 512)) return;
line = malloc(w + 100);
if (!line) return;
if (mode == CENTER)
snprintf(buf, sizeof(buf), "%c}ic#%i;%i;%s", 0x1b, w, h, path);
else if (mode == FILL)
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 (ty_write(1, buf, strlen(buf) + 1) < 0)
perror("write");
i = 0;
line[i++] = 0x1b;
line[i++] = '}';
line[i++] = 'i';
line[i++] = 'b';
line[i++] = 0;
for (x = 0; x < w; x++) line[i++] = '#';
line[i++] = 0x1b;
line[i++] = '}';
line[i++] = 'i';
line[i++] = 'e';
line[i++] = 0;
line[i++] = '\n';
for (y = 0; y < h; y++)
{
if (ty_write(1, line, i) < 0)
perror("write");
}
free(line);
}
static void
print_usage(const char *argv0)
{
printf("Usage: %s "HELP_ARGUMENT_SHORT" [-s|-f|-c] [-g <width>x<height>] FILE1 [FILE2 ...]\n"
"\n"
" -s Stretch file to fill nearest character cell size\n"
" -f Fill file to totally cover character cells with no gaps\n"
" -c Center file in nearest character cells but only scale down (default)\n"
" -g <width>x<height> Set maximum geometry for the image (cell count)\n"
HELP_ARGUMENT_DOC"\n",
argv0);
}
static Eina_Bool
timeout_cb(void *data)
{
evas_object_del(data);
timeout_t = NULL;
return ECORE_CALLBACK_CANCEL;
}
static int
handle_image(const char *rp, size_t len)
{
Evas_Object *o;
int w = 0, h = 0;
int iw = 0, ih = 0;
int r = -1;
if (!extn_matches(rp, len, extn_img) &&
!extn_matches(rp, len, extn_scale) &&
!extn_matches(rp, len, extn_mov))
return -1;
o = evas_object_image_add(evas);
evas_object_image_file_set(o, rp, NULL);
evas_object_image_size_get(o, &w, &h);
if ((w >= 0) && (h > 0))
{
scaleterm(w, h, &iw, &ih);
prnt(rp, iw, ih, _mode);
r = 0;
}
evas_object_del(o);
return r;
}
static int
handle_edje(const char *rp, size_t len)
{
Evas_Object *o;
int iw = 0, ih = 0;
int r = -1;
if (!extn_matches(rp, len, extn_edj)) return -1;
o = edje_object_add(evas);
if (edje_object_file_set
(o, rp, "terminology/background") == EINA_TRUE ||
!edje_object_file_set
(o, rp, "e/desktop/background"))
{
Evas_Coord mw = 0, mh = 0;
edje_object_size_min_get(o, &mw, &mh);
if ((mw <= 0) || (mh <= 0))
edje_object_size_min_calc(o, &mw, &mh);
if ((mw <= 0) || (mh <= 0))
{
mw = (tw) * cw;
mh = (th - 1) * ch;
}
scaleterm(mw, mh, &iw, &ih);
prnt(rp, iw, ih, _mode);
r = 0;
}
evas_object_del(o);
return r;
}
static void
video_decoded(void *data, Evas_Object *o, void *ei EINA_UNUSED)
{
int w = 0, h = 0;
int iw = 0, ih = 0;
if (emotion_object_video_handled_get(o))
{
emotion_object_size_get(o, &w, &h);
if ((w >= 0) && (h > 0))
{
scaleterm(w, h, &iw, &ih);
prnt(data, iw, ih, _mode);
goto done;
}
else
{
double ar = emotion_object_ratio_get(o);
if (ar > 0.0)
{
scaleterm(tw * cw, (int) ((tw * cw) / ar), &iw, &ih);
prnt(data, iw, ih, _mode);
goto done;
}
}
}
prnt(data, tw, 3, NOIMG);
done:
ecore_timer_del(timeout_t);
timeout_t = NULL;
evas_object_del(o);
free(data);
}
static int
handle_video(const char *rp, size_t len)
{
Evas_Object *o;
if (!extn_matches(rp, len, extn_aud) &&
!extn_matches(rp, len, extn_mov))
return -1;
o = emotion_object_add(evas);
if (emotion_object_init(o, NULL) == EINA_TRUE)
{
if (emotion_object_file_set(o, rp))
{
emotion_object_audio_mute_set(o, EINA_TRUE);
emotion_object_play_set(o, EINA_TRUE);
timeout_t = ecore_timer_add(VIDEO_DECODE_TIMEOUT,
timeout_cb, o);
evas_object_smart_callback_add(o, "frame_decode",
video_decoded,
strdup(rp));
return 0;
}
}
evas_object_del(o);
return -1;
}
static Eina_Bool
handle_file(void *data)
{
Eina_List **file_q = data;
size_t len;
int (*handlers[])(const char *rp, size_t len) = {
handle_image,
handle_edje,
handle_video,
NULL
};
char *rp;
int i;
if (timeout_t) return ECORE_CALLBACK_RENEW;
if (!(*file_q))
{
ecore_main_loop_quit();
return ECORE_CALLBACK_CANCEL;
}
rp = eina_list_data_get(*file_q);
*file_q = eina_list_remove_list(*file_q, *file_q);
if (!rp) return ECORE_CALLBACK_RENEW;
len = strlen(rp);
for (i = 0; handlers[i]; i++)
{
if (handlers[i](rp, len) == 0) break;
}
free(rp);
return ECORE_CALLBACK_RENEW;
}
int
main(int argc, char **argv)
{
Ecore_Evas *ee;
char buf[64];
int i;
char *rp;
Eina_List *file_q = NULL;
ON_NOT_RUNNING_IN_TERMINOLOGY_EXIT_1();
ARGUMENT_ENTRY_CHECK(argc, argv, print_usage);
if (argc <= 1)
{
print_usage(argv[0]);
return 0;
}
eina_init();
ecore_app_no_system_modules();
ecore_init();
ecore_file_init();
evas_init();
ecore_evas_init();
edje_init();
emotion_init();
ee = ecore_evas_buffer_new(1, 1);
if (!ee)
goto shutdown;
evas = ecore_evas_get(ee);
echo_off();
snprintf(buf, sizeof(buf), "%c}qs", 0x1b);
if (ty_write(1, buf, strlen(buf) + 1) < 0)
{
perror("write");
echo_on();
goto shutdown;
}
if (scanf("%i;%i;%i;%i", &tw, &th, &cw, &ch) != 4 ||
((tw <= 0) || (th <= 0) || (cw <= 1) || (ch <= 1)))
{
echo_on();
goto shutdown;
}
echo_on();
for (i = 1; i < argc; i++)
{
char *path;
if (!strcmp(argv[i], "-c"))
{
_mode = CENTER;
i++;
if (i >= argc) goto done;
}
else if (!strcmp(argv[i], "-s"))
{
_mode = STRETCH;
i++;
if (i >= argc) goto done;
}
else if (!strcmp(argv[i], "-f"))
{
_mode = FILL;
i++;
if (i >= argc) goto done;
}
if (!strcmp(argv[i], "-g"))
{
unsigned int width = 0, height = 0;
int cnt;
if (i + 2 >= argc)
{
print_usage(argv[0]);
goto shutdown;
}
i++;
cnt = sscanf(argv[i], "%ux%u", &width, &height);
if (cnt != 2)
{
print_usage(argv[0]);
goto done;
}
if (!width || tw > (int)width) maxw = width;
maxh = height;
}
path = argv[i];
rp = ecore_file_realpath(path);
if (rp)
file_q = eina_list_append(file_q, rp);
}
if (!file_q) goto done;
ecore_idler_add(handle_file, &file_q);
ecore_main_loop_begin();
done:
EINA_LIST_FREE(file_q, rp)
free(rp);
ecore_evas_free(ee);
shutdown:
emotion_shutdown();
edje_shutdown();
ecore_evas_shutdown();
evas_shutdown();
ecore_file_shutdown();
ecore_shutdown();
eina_shutdown();
return 0;
}