diff options
-rw-r--r-- | view.c | 91 |
1 files changed, 84 insertions, 7 deletions
@@ -1,6 +1,10 @@ #include <stdlib.h> +#include <stdio.h> +#include <stdbool.h> +#include <assert.h> #include <math.h> #include <unistd.h> +#include <termios.h> #include <glib.h> #include <gio/gio.h> @@ -8,12 +12,73 @@ #include <gdk-pixbuf/gdk-pixbuf.h> #include <gdk-pixbuf/gdk-pixdata.h> -// TODO Unhardcode these -const int char_width = 8; -const int char_height = 15; +static FILE* tty; +static int tty_fd; +static struct termios tty_tio; -const int window_width = 8 * 80; -const int window_height = 15 * 25; +static int char_width = 8; +static int char_height = 15; +static int window_columns = 25; +static int window_rows = 80; +static int window_width = 8 * 80; +static int window_height = 15 * 25; + +static bool init_terminal(int fd); +static void close_terminal(); + +static bool init_terminal(int fd) +{ + const char *name_of_tty = ttyname(fd); + if (!name_of_tty) { + return FALSE; + } + + tty = fopen(name_of_tty, "r+"); + if (tty == NULL) { + g_printerr("Cannot open terminal %s", name_of_tty); + return FALSE; + } + tty_fd = fileno(tty); + + tcgetattr(tty_fd, &tty_tio); + struct termios tio = tty_tio; + + tio.c_lflag &= ~(ICANON | ECHO); + tio.c_cc[VMIN] = 4; + tio.c_cc[VTIME] = 1; + tcsetattr(tty_fd, TCSADRAIN, &tio); + + // Try to get window width and height in pixels using a xterm command + fprintf(tty, "\033[14;t"); + fflush(tty); + + if (fscanf(tty, "\033[4;%d;%dt", &window_height, &window_width) != 2) { + close_terminal(); + return FALSE; + } + + // Also use a xterm command to get the window size in chars, + // (could also use termios...) + fprintf(tty, "\033[18;t"); + fflush(tty); + + if (fscanf(tty, "\033[8;%d;%dt", &window_rows, &window_columns) != 2) { + close_terminal(); + return FALSE; + } + + // Now calculate char height & width based on the above data + char_width = window_width / window_columns; + char_height = window_height / window_rows; + + return TRUE; +} + +static void close_terminal() +{ + tcsetattr(tty_fd, TCSADRAIN, &tty_tio); + fclose(tty); +} static gboolean view_pixbuf(GdkPixbuf *pixbuf) { @@ -52,13 +117,15 @@ static gboolean view_pixbuf(GdkPixbuf *pixbuf) guint8 *data = gdk_pixdata_serialize(&pixdata, &size); gchar *str = g_base64_encode(data, size); - g_print("\033]v;%s\007", str); + fprintf(tty, "\033]v;%s\007", str); int rows = ceil(height / (double)char_height); while (rows > 0) { - g_print("\n"); + fprintf(tty, "\n"); rows--; } + + fflush(tty); g_free(str); g_free(data); @@ -80,16 +147,23 @@ int main(int argc, char * argv[]) return EXIT_FAILURE; } + if (!init_terminal((STDOUT_FILENO))) { + g_printerr("Refusing to display image on non-graphical terminal\n"); + return EXIT_FAILURE; + } + if (argc > 1) { int i; for (i = 1; i < argc; i++) { GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[i], &error); if (pixbuf == NULL) { g_printerr("Failed to open image '%s': %s\n", argv[i], error->message); + close_terminal(); return EXIT_FAILURE; } if (!view_pixbuf(pixbuf)) { g_printerr("Failed to view image '%s'\n", argv[i]); + close_terminal(); return EXIT_FAILURE; } g_object_unref(pixbuf); @@ -99,14 +173,17 @@ int main(int argc, char * argv[]) GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream(input, NULL, &error); if (pixbuf == NULL) { g_printerr("Failed to open stdin image: %s\n", error->message); + close_terminal(); return EXIT_FAILURE; } if (!view_pixbuf(pixbuf)) { g_printerr("Failed to view stdin image\n"); + close_terminal(); return EXIT_FAILURE; } g_object_unref(pixbuf); } + close_terminal(); return EXIT_SUCCESS; } |