diff options
Diffstat (limited to 'src/GsWidget.cxx')
-rw-r--r-- | src/GsWidget.cxx | 266 |
1 files changed, 216 insertions, 50 deletions
diff --git a/src/GsWidget.cxx b/src/GsWidget.cxx index 1bb2e53..e92a71d 100644 --- a/src/GsWidget.cxx +++ b/src/GsWidget.cxx @@ -29,11 +29,14 @@ #include <errno.h> #include <sys/wait.h> #include <fcntl.h> +#include <signal.h> #include <FL/fl_draw.H> #include "GsWidget.H" +#include "PostscriptDSC.H" +#define MIN(A,B) ((A)<(B)?(A):(B)) void GsWidget::draw() { if (!offscreen) { @@ -66,7 +69,7 @@ void GsWidget::setProps() { atoms[3] = XInternAtom(fl_display,"PAGE" , false); atoms[4] = XInternAtom(fl_display,"DONE" , false); - snprintf(data, 512, "%d %d %d %d %d %d %d.0 %d.0", + snprintf(data, sizeof(data), "%d %d %d %d %d %d %d.0 %d.0", 0, 0, 0, 0, paper_x, paper_y, xdpi, ydpi); int xid = fl_xid(window()); @@ -75,7 +78,7 @@ void GsWidget::setProps() { XA_STRING, 8, PropModeReplace, (unsigned char*) data, strlen(data)); - snprintf(data, 512, "%s %d %d", "Color", + snprintf(data, sizeof(data), "%s %d %d", "Color", (int) BlackPixel(fl_display, DefaultScreen(fl_display)), (int) WhitePixel(fl_display, DefaultScreen(fl_display))); @@ -111,6 +114,8 @@ GsWidget::GsWidget(int X,int Y,int W, int H) : Fl_Widget(X, Y, W, H) { initial_height = H; in_fd = -1; reload_needed = 0; + dsc = NULL; + feeding = 0; } GsWidget::~GsWidget() { @@ -120,22 +125,58 @@ GsWidget::~GsWidget() { } } -int GsWidget::load(char *f) { +int GsWidget::open_file(char *f) { int fd = open(f, O_RDONLY); if (fd == -1) { perror("open"); return 1; } - return load(fd); + return open_file(fd); } -int GsWidget::load(int fd) { +int GsWidget::open_file(int fd) { if (in_fd >= 0 && fd != in_fd) { close (in_fd); } - in_fd = fd; + if (dsc) { + delete(dsc); + } + dsc = new PostscriptDSC(); + + if (dsc->parse(in_fd) == 0) { + int bb_x, bb_y, bb_w, bb_h; + + dsc->get_bounding_box(&bb_x, &bb_y, &bb_w, &bb_h); + paper_x = bb_w; + paper_y = bb_h; + } else { + delete(dsc); + dsc = NULL; + paper_x = 594; // DIN A4 + paper_y = 841; // + } + + page = 0; + + return 0; +} + + +int GsWidget::load() { + pid_t pid; + + if (dsc) { + return load_page(1); + } + + if (in_fd < 0) { + return 1; + } + + lseek(in_fd, 0L, SEEK_SET); + fl_cursor(FL_CURSOR_WAIT); kill_gs(); @@ -146,48 +187,145 @@ int GsWidget::load(int fd) { setProps(); - pid_t pid = fork(); + pid = fork(); if (pid == (pid_t) 0) { - char *argv[16]; - char gvenv[256]; - int d_null = open("/dev/null", O_WRONLY); - - dup2(d_null, STDOUT_FILENO); - close(d_null); dup2(in_fd, STDIN_FILENO); - snprintf(gvenv, 256, "%d %d", (int) fl_xid(window()), (int) offscreen); - - setenv("GHOSTVIEW", gvenv, 1); - argv[0] = "gs"; - argv[1] = "-dSAFER"; - argv[2] = "-dQUIET"; - argv[3] = "-sDEVICE=x11alpha"; - argv[4] = "-dNOPLATFONTS"; - argv[5] = "-"; - argv[6] = NULL; - execvp(argv[0], argv); - perror("exec"); - fprintf(stderr, "Please install ghostscript and make sure 'gs' " - "is in the PATH.\n"); - exit(1); + exec_gs(); } else { gs_pid = pid; - page = 0; + page = 1; } return 0; } +int +GsWidget::load_page(int p) { + pid_t pid; + int pdes[2]; + + if (feeding || in_fd < 0) { + return 1; + } + + if (p < 1 || p > dsc->get_pages()) { + fprintf(stderr, "Page %d not found in document\n", p); + return 1; + } + + fl_cursor(FL_CURSOR_WAIT); + kill_gs(); + + page = p; + + if (!offscreen) { + reload_needed = 1; + return 0; + } + + if (pipe(pdes) < 0) { + perror("pipe"); + return 1; + } + + feeding = 1; + + lseek(in_fd, 0L, SEEK_SET); + setProps(); + + pid = fork(); + if (pid == (pid_t) 0) { + close(in_fd); + close(pdes[1]); + dup2(pdes[0], STDIN_FILENO); + exec_gs(); + } else { + size_t len; + + gs_pid = pid; + + close(pdes[0]); + + lseek(in_fd, 0L, SEEK_SET); + len = dsc->get_setup_len(); + if (fd_copy(pdes[1], in_fd, len) != 0) { + close(pdes[1]); + feeding = 0; + return 1; + } + + lseek(in_fd, dsc->get_page_off(p), SEEK_SET); + len = dsc->get_page_len(p); + if (fd_copy(pdes[1], in_fd, len) != 0) { + close(pdes[1]); + feeding = 0; + return 1; + } + + close(pdes[1]); + } + + feeding = 0; + return 0; +} + +int GsWidget::fd_copy(int to, int from, size_t len) { + size_t n, r; + char buf[1024]; + + n = 0; + while(len > 0) { + Fl::check(); // let fltk do its stuff - otherwise + // gs can't get the GHOSTVIEW property + r = read(from, buf, MIN(sizeof(buf), len)); + + if (r < 0) { + perror("read"); + return 1; + } + + write(to, buf, r); + len -= r; + } + + return 0; +} + +void GsWidget::exec_gs() { + char *argv[16]; + char gvenv[256]; + int d_null = open("/dev/null", O_WRONLY); + + dup2(d_null, STDOUT_FILENO); + + snprintf(gvenv, sizeof(gvenv), "%d %d", + (int) fl_xid(window()), (int) offscreen); + + setenv("GHOSTVIEW", gvenv, 1); + argv[0] = "gs"; + argv[1] = "-dSAFER"; + argv[2] = "-dQUIET"; + argv[3] = "-sDEVICE=x11alpha"; + argv[4] = "-dNOPLATFONTS"; + argv[5] = "-dNOPAUSE"; + argv[6] = "-"; + argv[7] = NULL; + execvp(argv[0], argv); + perror("exec"); + fprintf(stderr, "Please install ghostscript and make sure 'gs' " + "is in the PATH.\n"); + exit(1); +} + int GsWidget::reload() { int ret; if (in_fd >= 0) { - ret = lseek(in_fd, 0L, SEEK_SET); - if (ret == -1) { - perror("lseek"); - return 1; + if (dsc) { + load_page(page); + } else { + load(); } - load(in_fd); return 0; } else { return 1; @@ -195,35 +333,54 @@ int GsWidget::reload() { } int GsWidget::next() { - if (!gs_active()) { - return 1; + if (dsc) { + load_page(page + 1); } else { - fl_cursor(FL_CURSOR_WAIT); - - XEvent e; - e.xclient.type = ClientMessage; - e.xclient.display = fl_display; - e.xclient.window = gs_win; - e.xclient.message_type = atoms[2]; - e.xclient.format = 32; - - XSendEvent(fl_display, gs_win, false, 0, &e); - XFlush(fl_display); + if (!gs_active()) { + return 1; + } else { + fl_cursor(FL_CURSOR_WAIT); + + XEvent e; + e.xclient.type = ClientMessage; + e.xclient.display = fl_display; + e.xclient.window = gs_win; + e.xclient.message_type = atoms[2]; + e.xclient.format = 32; + + XSendEvent(fl_display, gs_win, false, 0, &e); + XFlush(fl_display); + } } return 0; } +int GsWidget::prev() { + if (dsc) { + load_page(page - 1); + return 0; + } else { + return 1; + } +} + int GsWidget::handleX11(int ev) { if (fl_xevent->type == ClientMessage) { gs_win = fl_xevent->xclient.data.l[0]; - if(fl_xevent->xclient.message_type == atoms[3]) { - page++; // PAGE revceived + if(fl_xevent->xclient.message_type == atoms[3]) { // PAGE received damage(FL_DAMAGE_ALL); fl_cursor(FL_CURSOR_DEFAULT); + if (dsc) { + kill_gs(); + } else { + page++; + } } else if(fl_xevent->xclient.message_type == atoms[4] ) { - reload(); // go back to page 1 + if (!dsc) { + reload(); // go back to page 1 + } } return 1; } @@ -260,3 +417,12 @@ int GsWidget::zoom(int p) { return 0; } + +int +GsWidget::get_pages() { + if (dsc) { + return dsc->get_pages(); + } else { + return 0; + } +} |