/*
   pspresent: PostScript presentation tool
   gs.c: Interface to Ghostscript
   Copyright (C) Matthew Chapman 2001-2003

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "pspresent.h"
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <X11/Xatom.h>

extern Display *display;
extern Screen *screen;

static Window gs_wnd;
static pid_t gs_pid;
static Atom next, page, done;

static void GSExec(int gs_stdin, Window wnd)
{
	char *args[] = { "gs", "-sDEVICE=x11alpha", "-q", "-dNOPAUSE", "-dSAFER", "-", NULL };
	char ghostview[32];

	snprintf(ghostview, sizeof(ghostview)-1, "GHOSTVIEW=%ld",
				(unsigned long)wnd);
	putenv(ghostview);

	dup2(gs_stdin, STDIN_FILENO);

	execvp(args[0], args);
	perror(args[0]);
}

/* set Ghostscript-related properties on a window */
int GSStart(Window draw_wnd, Pixmap draw_pix, int wnd_width, int wnd_height, int bounds[4], int orientation)
{
	Atom gv, gv_colors;
	unsigned long fg, bg;
	float xdpi, ydpi;
	int xsize, ysize;
	char prop[64];
	int fds[2];
	int flags, len, gs_fd;

	fg = BlackPixelOfScreen(screen);
	bg = WhitePixelOfScreen(screen);

	if (orientation % 180 == 0)
	{
		xsize = bounds[2]-bounds[0];
		ysize = bounds[3]-bounds[1];
	}
	else
	{
		xsize = bounds[3]-bounds[1];
		ysize = bounds[2]-bounds[0];
	}

	xdpi = 72.0*wnd_width/xsize;
	ydpi = 72.0*wnd_height/ysize;

	gv = XInternAtom(display, "GHOSTVIEW", False);
	len = snprintf(prop, sizeof(prop)-1, "%ld %d %d %d %d %d %g %g %d %d %d %d",
			draw_pix, orientation, bounds[0], bounds[1], bounds[2], bounds[3], xdpi, ydpi, 0, 0, 0, 0);
	XChangeProperty(display, draw_wnd, gv, XA_STRING, 8, PropModeReplace,
			prop, len);

	gv_colors = XInternAtom(display, "GHOSTVIEW_COLORS", False);
	len = snprintf(prop, sizeof(prop)-1, "Color %ld %ld", fg, bg);
	XChangeProperty(display, draw_wnd, gv_colors, XA_STRING, 8, PropModeReplace,
			prop, len);

	next = XInternAtom(display, "NEXT", False);
	page = XInternAtom(display, "PAGE", False);
	done = XInternAtom(display, "DONE", False);

	pipe(fds);
	switch (gs_pid = fork())
	{
		case -1: /* failure */
			perror("fork");
			return -1;

		case 0: /* child */
			GSExec(fds[0], draw_wnd);
			exit(1);
	}

	flags = fcntl(fds[1], F_GETFL);
	fcntl(fds[1], F_SETFL, flags | O_NONBLOCK);
	gs_fd = fds[1];
	return gs_fd;
}

char *GSWrite(int gs_fd, char *start, char *end)
{
	int length;

	while (start < end)
	{
		length = end - start;
		length = write(gs_fd, start, length);
		if (length == -1)
		{
			if (errno != EWOULDBLOCK)
				perror("write");
			break;
		}
		start += length;
	}

	return start;
}

void GSStop(int gs_fd)
{
	int status;

	close(gs_fd);
	kill(gs_pid, SIGTERM);
	waitpid(gs_pid, &status, 0);
}

void GSNextPage(void)
{
	XEvent event;

	event.xclient.type = ClientMessage;
	event.xclient.display = display;
	event.xclient.window = gs_wnd;
	event.xclient.message_type = next;
	event.xclient.format = 32;
	XSendEvent(display, gs_wnd, False, 0, &event);
	XFlush(display);
}

Bool GSProcessMessage(XClientMessageEvent *message)
{
	gs_wnd = (Window)message->data.l[0];
	return (message->message_type == page);
}

