/* Hello, Emacs, this is -*-C-*-
 * $Id: x11.trm,v 1.193.2.3 2013/08/24 22:46:48 sfeam Exp $
 *
 */

/* GNUPLOT - x11.trm */

/*[
 * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
 *
 * Permission to use, copy, and distribute this software and its
 * documentation for any purpose with or without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.
 *
 * Permission to modify the software is granted, but not the right to
 * distribute the complete modified source code.  Modifications are to
 * be distributed as patches to the released version.  Permission to
 * distribute binaries produced by compiling modified sources is granted,
 * provided you
 *   1. distribute the corresponding source modifications from the
 *    released version in the form of a patch file along with the binaries,
 *   2. add special version identification to distinguish your version
 *    in addition to the base release version number,
 *   3. provide your name and address as the primary contact for the
 *    support of your modified version, and
 *   4. retain our contact information in regard to use of the base
 *    software.
 * Permission to distribute the released version of the source code along
 * with corresponding source modifications in the form of a patch file is
 * granted with same provisions 2 through 4 for binary distributions.
 *
 * This software is provided "as is" without express or implied warranty
 * to the extent permitted by applicable law.
]*/

/*
 *    x11.trm  --- inboard terminal driver for X11
 */

/* Petr Mikulik and Johannes Zellner: added mouse support (October 1999)
 * Implementation and functionality is based on pm.trm
 */

/* X11 support for Petr Mikulik's pm3d
 * by Johannes Zellner <johannes@zellner.org>
 * (November 1999 - January 2000)
 */

/* Dynamic font support, enhanced text mode support,
 * additional feedback from outboard driver
 * Ethan A Merritt <merritt@u.washington.edu>
 * 2003
 */

/* Daniel Sebald: added X11 support for images. (27 February 2003)
 */

#include "driver.h"

#ifdef TERM_REGISTER
register_term(x11)
#endif

#ifdef TERM_PROTO
int X11_args __PROTO((int argc, char *argv[]));

TERM_PUBLIC void X11_options __PROTO((void));
TERM_PUBLIC void X11_init __PROTO((void));
TERM_PUBLIC void X11_graphics __PROTO((void));
TERM_PUBLIC void X11_text __PROTO((void));
TERM_PUBLIC int  X11_set_font __PROTO((const char * fontname));
TERM_PUBLIC void X11_reset __PROTO((void));
TERM_PUBLIC void X11_move __PROTO((unsigned int x, unsigned int y));
TERM_PUBLIC void X11_vector __PROTO((unsigned int x, unsigned int y));
TERM_PUBLIC void X11_linewidth __PROTO((double lw));
TERM_PUBLIC void X11_pointsize __PROTO((double ps));
TERM_PUBLIC void X11_linetype __PROTO((int lt));
TERM_PUBLIC void X11_put_text __PROTO((unsigned int x, unsigned int y, const char str[]));
TERM_PUBLIC int X11_text_angle __PROTO((int i));
TERM_PUBLIC int X11_justify_text __PROTO((enum JUSTIFY mode));
TERM_PUBLIC void X11_point __PROTO((unsigned int x, unsigned int y, int number));
TERM_PUBLIC void X11_fillbox __PROTO((int style, unsigned int x, unsigned int y, unsigned int width, unsigned int height));

TERM_PUBLIC void X11_send_endianess __PROTO((void));

# ifdef USE_MOUSE
TERM_PUBLIC int X11_waitforinput __PROTO((void));
TERM_PUBLIC void X11_set_ruler __PROTO((int, int));
TERM_PUBLIC void X11_set_cursor __PROTO((int, int, int));
TERM_PUBLIC void X11_put_tmptext __PROTO((int, const char str[]));
TERM_PUBLIC void X11_set_clipboard __PROTO((const char[]));
# endif

TERM_PUBLIC void X11_update_opts __PROTO((void));
TERM_PUBLIC int X11_make_palette __PROTO((t_sm_palette *));
TERM_PUBLIC void X11_set_color __PROTO((t_colorspec *));
TERM_PUBLIC void X11_filled_polygon __PROTO((int, gpiPoint *));

TERM_PUBLIC void X11_image __PROTO((unsigned int, unsigned int, coordval *, gpiPoint *, t_imagecolor));

/* To support "set term x11 enhanced" */
TERM_PUBLIC void ENHX11_put_text __PROTO((unsigned int x, unsigned int y, const char str[]));
TERM_PUBLIC void ENHX11_OPEN __PROTO((char * fontname, double fontsize,
				double base, TBOOLEAN widthflag, TBOOLEAN showflag,
				int overprint));
TERM_PUBLIC void ENHX11_FLUSH __PROTO((void));

# define X11_XMAX 4096
# define X11_YMAX 4096

static int X11_SIZE_X = 640;
static int X11_SIZE_Y = 450;
static int X11_POSITION_X = 0;
static int X11_POSITION_Y = 0;

/* approximations for typical font/screen sizes */
# define X11_VCHAR (X11_YMAX/25)
# define X11_HCHAR (X11_XMAX/100)
# define X11_VTIC (X11_YMAX/100)
# define X11_HTIC (X11_XMAX/150)
#endif	/* TERM_PROTO */


#ifndef TERM_PROTO_ONLY

#ifdef TERM_BODY

#include "gplt_x11.h"

/* non-zero if '-display' found on command line */
static int X11_Display = 0;

/* Fonts can have very long names */
/* EAM FIXME - these should be dynamically allocated */
#define X11_MAX_FONTNAME_LENGTH 255
static char X11_default_font[X11_MAX_FONTNAME_LENGTH+1] = {'\0'};
static int  X11_default_fontsize = 12;
static char X11_last_font_used[X11_MAX_FONTNAME_LENGTH+1] = {'\01','\0'};
static char X11_next_font_used[X11_MAX_FONTNAME_LENGTH+1] = {'\0'};
static enum JUSTIFY X11_last_justification = LEFT;

static void X11_atexit __PROTO((void));
static void X11_set_default_font __PROTO((void));

static void transmit_gradient __PROTO((gradient_struct *gradient, int cnt));

/* Merged the old char X11_opts[] and int X11_optarg[]
 * into one array of structs.
 * Loosely based on XrmOptionDescRec, the use of which
 * would probably be overkill here. */
typedef enum { hasNoArg, hasArg } OptionArg;

static struct x11opt {
    const char *option;		/* Name of option */
    OptionArg arg;		/* Whether option has argument */
} X11_cmdopts[] = {
    { "-mono", hasNoArg}, { "-gray", hasNoArg}, { "-clear", hasNoArg},
    { "-tvtwm", hasNoArg}, { "-pointsize", hasArg},
    { "-iconic", hasNoArg}, { "-rv", hasNoArg},
    { "-reverse", hasNoArg}, { "+rv", hasNoArg},
    { "-synchronous", hasNoArg},
    { "-display", hasArg}, { "-geometry", hasArg}, { "-bg", hasArg},
    { "-background", hasArg}, { "-bd", hasArg},
    { "-bordercolor", hasArg}, { "-bw", hasArg},
    { "-borderwidth", hasArg}, { "-fg", hasArg},
    { "-foreground", hasArg}, { "-fn", hasArg}, { "-font", hasArg},
    { "-name", hasArg},
    { "-selectionTimeout", hasArg}, { "-title", hasArg},
    { "-xnllanguage", hasArg}, { "-xrm", hasArg},
    { "-raise", hasNoArg}, { "-noraise", hasNoArg},
    { "-solid", hasNoArg}, { "-dashed", hasNoArg}
#ifdef USE_MOUSE
    , { "-nofeedback", hasNoArg}
    , { "-noevents", hasNoArg}
    , { "-ctrlq", hasNoArg}
#endif
};

#define X11_nopts (sizeof(X11_cmdopts) / sizeof(X11_cmdopts[0]))

static FILE *X11_ipc = (FILE *) 0;
#ifdef PIPE_IPC
#define X11_ipc_back_fd ipc_back_fd
#endif

/* reserve a minimum 10 driver opts */
static char *optvec[2 * X11_nopts + 1 + 10];
static char x11_userbkg[] = "#RRGGBB";

/* gnuplot_x11 has extension .exe on OS/2 and Windows (and on RSX/VMS, but
   these construct their own full path GNUPLOT_X11 in their build script).
*/
# if defined(OS2) || defined(_Windows)
#   ifndef GNUPLOT_X11
static char X11_default_command[] = "gnuplot_x11.exe";
#   else
static char X11_default_command[] = GNUPLOT_X11 ".exe";
#   endif
# else  /* thus !OS/2 && !Windows */
#   ifndef GNUPLOT_X11
static char X11_default_command[] = "gnuplot_x11";
#   else
static char X11_default_command[] = GNUPLOT_X11;
#   endif
# endif	/* OS/2 || Windows */

static char *X11_command = X11_default_command;
static char *X11_command_parsed = NULL;
static char *X11_full_command_path = NULL;

/* must match the definition in src/gplt_x11.c: */
static int persist = UNSET;
static int do_raise = UNSET;
static int dashedlines = UNSET;
static int ctrlq = UNSET;
static int set_size = UNSET;
static int set_position = UNSET;

/* driver properties managed by x11.trm rather than gnuplot_x11 */
static double X11_linewidth_multiplier = 1.0;

#ifdef USE_MOUSE
/* Interlock to prevent the mouse channel from being coopted more than
 * once per plot by the gnuplot_x11<->x11.trm font information query.
 */
static TBOOLEAN default_font_size_known = FALSE;
static TBOOLEAN X11_MOUSE_FEEDBACK = TRUE;
#endif
#ifdef PIPE_IPC
static TBOOLEAN IPC_LOCK = FALSE;
#endif

static int parse_driver __PROTO((const char *));

static int
parse_driver(const char *cmd)
{
    int nr = 0;
    char *ptr;

    /* make a copy of cmd, as parsing will modify the string */
    X11_command_parsed = gp_realloc(X11_command_parsed,
				    strlen(cmd) + 1, "x11->parse_driver");
    strcpy(X11_command_parsed, X11_command);
    ptr = X11_command_parsed;

    while (*ptr != '\0' && nr < sizeof(optvec) / sizeof(char)) {

	/* Strip whitespace.  Use nulls, so that
	 * the previous argument is terminated
	 * automatically.
	 */
	while (isspace((unsigned char)*ptr))
	    *ptr++ = '\0';

	if (!(*ptr))		/* don't count the terminating NULL */
	    break;

	/* Save the argument. */
	optvec[nr++] = ptr;

	/* Skip over the argument. */
	while ('\0' != *ptr && !isspace((unsigned char)*ptr)) {
	    ptr++;
	}
    }

    /* HBB 20020214: new code to prepend the environment X11_DRIVER_DIR
     * to the command name, if it doesn't contain any slashes yet */
    if (!strchr(optvec[0],'/')) {
	char *dir = getenv("GNUPLOT_DRIVER_DIR");

	if (!dir)
	    dir = X11_DRIVER_DIR;
#ifndef OS2
	if (dir[0] != '/' && dir[0] != '.') {
	    /* Can't call int_error because longjump has not been set up yet */
	    int_warn(NO_CARET, "Illegal X11 driver directory name! Using default");
	    dir = "";
	}
#endif
	X11_full_command_path = gp_realloc(X11_full_command_path,
					   strlen(dir) + strlen(optvec[0]) + 2,
					   "x11 driver pathname");
	/* optvec[0] = X11_full_command_path; */
	if (*dir)
	    sprintf(X11_full_command_path, "%s/%s", dir, optvec[0]);
	else
	    sprintf(X11_full_command_path, "%s", optvec[0]);
    }

    return nr;
}

/*   X11_args - scan gnuplot command line for standard X Toolkit options
 * called from plot.c so must not be TERM_PUBLIC (which may be static)
 */

int
X11_args(int argc, char *argv[])
{
    int nx11 = 0, i, n;
    char **xargv, **xargv_orig; 

    xargv = xargv_orig = (char **) gp_alloc(argc * sizeof(char *), "<xargv>");

    /* We make a copy of the argument vector because
     * argv is modified later. */
    memcpy(xargv, argv, argc * sizeof(char *));
    i = parse_driver(X11_command);

    if (persist_cl) {
	optvec[i++] = "-persist";
    }

    while (++argv, ++xargv, --argc > 0) {
	if (!strcmp(*argv,"--persist") || !strncmp(*argv,"-p",2)) {
	    nx11++;
	    continue;
	}
	for (n = 0; n < X11_nopts; n++) {
	    if (strcmp(*argv, X11_cmdopts[n].option) == 0) {
		optvec[i++] = *xargv;
#ifdef USE_MOUSE
		if (strcmp(*argv, "-nofeedback") == 0)
		    X11_MOUSE_FEEDBACK = FALSE;
#endif
		if (strcmp(*argv, "-display") == 0)
		    X11_Display++;
		if (X11_cmdopts[n].arg == hasArg) {
		    if (--argc <= 0) {
			free(xargv_orig);
			return nx11;
		    }
		    optvec[i++] = *++xargv, ++argv;
		    nx11++;
		}
		if (i >= (sizeof(optvec) / sizeof(char))) {
		    fprintf(stderr, "warning: X11 options will be truncated\n");
		    free(xargv_orig);
		    return nx11;	/* optvec is full */
		}
		nx11++;
		break;
	    }
	}
	if (n == X11_nopts)
	    break;
    }
    free(xargv_orig);
    return (nx11);
}


enum X11_id {
    X11_RESET,
    X11_CLOSE,
    X11_PERSIST,
    X11_NOPERSIST,
    X11_RAISE,
    X11_NORAISE,
    X11_FONT,
    X11_TITLE,
    X11_ENHANCED,
    X11_NOENHANCED,
    X11_SOLID,
    X11_DASHED,
    X11_LINEWIDTH,
    X11_CTRLQ,
    X11_NOCTRLQ,
    X11_SIZE,
    X11_POSITION,
    X11_BACKGROUND,
#ifdef EXTERNAL_X11_WINDOW
    X11_WINDOW,
#endif
    X11_OTHER
};

static struct gen_table X11_opts[] = {
    {"res$et", X11_RESET},
    {"cl$ose", X11_CLOSE},
    {"per$sist", X11_PERSIST},
    {"noper$sist", X11_NOPERSIST},
    {"rai$se", X11_RAISE},
    {"norai$se", X11_NORAISE},
    {"font",   X11_FONT},
    {"fn$ame", X11_FONT},
    {"ti$tle", X11_TITLE},
    {"enh$anced", X11_ENHANCED},
    {"noenh$anced", X11_NOENHANCED},
    {"solid", X11_SOLID},
    {"dash$ed", X11_DASHED},
    {"linew$idth", X11_LINEWIDTH},
    {"lw", X11_LINEWIDTH},
    {"ctrl$q", X11_CTRLQ},
    {"noctrl$q", X11_NOCTRLQ},
    {"si$ze", X11_SIZE},
    {"pos$ition", X11_POSITION},
    {"backg$round", X11_BACKGROUND},
#ifdef EXTERNAL_X11_WINDOW
    {"w$indow", X11_WINDOW},
#endif
    {NULL, X11_OTHER}
};


TERM_PUBLIC void
X11_options()
{

#define NOT_PROCESS_IF_DUPLICATION 1

    int c_title_token = 0;
    int new_term_number = 0;
    int background;
    TBOOLEAN duplication = FALSE;
    TBOOLEAN set_reset = FALSE, set_persist = FALSE, set_raise = FALSE, set_font = FALSE;
    TBOOLEAN set_ctrlq = FALSE;
    TBOOLEAN set_title = FALSE, set_number = FALSE, set_close = FALSE, set_solid = FALSE;
#ifdef EXTERNAL_X11_WINDOW
    unsigned long existing_X11_window_id = 0;
    TBOOLEAN set_window = FALSE;
#endif

    do_raise = dashedlines = ctrlq = UNSET;
    set_size = set_position = UNSET;
    persist = persist_cl;	/* previously set from command line */
    strcpy(x11_userbkg,"#RRGGBB");

    while (!END_OF_COMMAND) {
	switch (lookup_table(&X11_opts[0], c_token)) {
	case X11_RESET:
	    c_token++;
	    if (set_reset) duplication=TRUE;
	    set_reset = TRUE;
	    break;
	case X11_CLOSE:
	    c_token++;
	    if (set_close) duplication=TRUE;
	    set_close = TRUE;
	    break;
	case X11_PERSIST:
	    persist = yes;
	    c_token++;
	    if (set_persist) duplication=TRUE;
	    set_persist = TRUE;
	    break;
	case X11_NOPERSIST:
	    persist = no;
	    c_token++;
	    if (set_persist) duplication=TRUE;
	    set_persist = TRUE;
	    break;
	case X11_CTRLQ:
	    ctrlq = yes;
	    c_token++;
	    if (set_ctrlq) duplication=TRUE;
	    set_ctrlq = TRUE;
	    break;
	case X11_NOCTRLQ:
	    ctrlq = no;
	    c_token++;
	    if (set_ctrlq) duplication=TRUE;
	    set_ctrlq = TRUE;
	    break;
	case X11_SOLID:
	    dashedlines = FALSE;
	    c_token++;
	    if (set_solid) duplication=TRUE;
	    set_solid = TRUE;
	    break;
	case X11_DASHED:
	    dashedlines = TRUE;
	    c_token++;
	    if (set_solid) duplication=TRUE;
	    set_solid = TRUE;
	    break;
	case X11_LINEWIDTH:
	    c_token++;
	    X11_linewidth_multiplier = real_expression();
	    if (X11_linewidth_multiplier <= 0)
		X11_linewidth_multiplier = 1.0;
	    break;
	case X11_RAISE:
	    do_raise = yes;
	    c_token++;
	    if (set_raise) duplication=TRUE;
	    set_raise = TRUE;
	    break;
	case X11_NORAISE:
	    do_raise = no;
	    c_token++;
	    if (set_raise) duplication=TRUE;
	    set_raise = TRUE;
	    break;
	case X11_FONT:
	    c_token++;
	    if (END_OF_COMMAND)
		int_error(c_token, "expecting font name");
	    if (isstringvalue(c_token)) {
		char *s = try_to_get_string();
		strncpy(X11_default_font, s, sizeof(X11_default_font));
		free(s);
	    } else {
		copy_str(X11_default_font, c_token, sizeof(X11_default_font));
		c_token++;
	    }
	    if (strchr(X11_default_font,','))
		sscanf(strchr(X11_default_font,',')+1, "%d",
			&X11_default_fontsize);
	    if (set_font) duplication=TRUE;
	    set_font = TRUE;
	    break;
	case X11_TITLE:
	    c_token++;
	    if (END_OF_COMMAND)
		int_error(c_token, "expecting title text");
	    c_title_token = c_token;
	    c_token++;
	    if (set_title) duplication=TRUE;
	    set_title = TRUE;
	    break;
	case X11_ENHANCED:
	    term->put_text = ENHX11_put_text;
	    term->flags |= TERM_ENHANCED_TEXT;
	    c_token++;
	    break;
	case X11_NOENHANCED:
	    term->put_text = X11_put_text;
	    term->flags &= ~TERM_ENHANCED_TEXT;
	    c_token++;
	    break;
	case X11_SIZE:
	    c_token++;
	    if (END_OF_COMMAND) {
		int_error(c_token, "expecting X[,Y]");
	    } else {
		int x_in, y_in;
		x_in = int_expression();
		if (x_in > 0)
		    X11_SIZE_X = x_in;
		else
		    int_error(c_token, "X size must be > 0");
		if (equals(c_token, ",")) {
		    c_token++;
		    y_in = int_expression();
		    if (y_in > 0)
			X11_SIZE_Y = y_in;
		    else
			int_error(c_token, "Y size must be > 0");
		}
		set_size = yes;
	    }
	    break;
	case X11_POSITION:
	    c_token++;
	    if (END_OF_COMMAND) {
		int_error(c_token, "expecting X[,Y]");
	    } else {
		X11_POSITION_X = int_expression();
		if (equals(c_token, ",")) {
		    c_token++;
		    X11_POSITION_Y = int_expression();
		}
		set_position = yes;
	    }
	    break;
	case X11_BACKGROUND:
	    c_token++;
	    background = parse_color_name();
	    sprintf(x11_userbkg,"#%06x",background);
	    break;

#ifdef EXTERNAL_X11_WINDOW
	case X11_WINDOW:
	{
	    char *windowid;
	    c_token++;
	    if (!(windowid = try_to_get_string()))
		int_error(c_token, "expecting X window ID as string in hex");
	    sscanf(windowid,"%lx",&existing_X11_window_id);
	    free(windowid);
	    if (!existing_X11_window_id)
		int_error(c_token, "expecting X window ID as string in hex");
	    if (set_window) duplication=TRUE;
	    set_window = TRUE;
	    break;
	}
#endif
	case X11_OTHER:
	default:
	    if (set_number) duplication=TRUE;
	    /* let gnuplot_x11 check range */
	    new_term_number = int_expression();
	    if (new_term_number < 0)
		int_error(c_token, "plot number must be non-negative");
	    set_number = TRUE;
	    break;
	}

	if (duplication) {
	    int_error(c_token-1, "duplicated or contradicting arguments in X11 term options");
	}

    }


    /* Call own init routine; this might be xlib rather than x11 */
    term->init();

    if (set_reset)
	X11_atexit();	/* tell gnuplot_x11 to shut down */

    /* Leave the current window unchanged when closing an old window */
    if (X11_ipc) {
	if (set_close) {
	    if (set_number) {
		fprintf(X11_ipc, "C%d\n", new_term_number);
	    } else {
		fputs("C\n", X11_ipc);
	    }
	    fflush(X11_ipc);
	} else if (set_number) {
#ifdef EXTERNAL_X11_WINDOW
	    if (set_window)
		int_error(NO_CARET,"an existing X11 window cannot be asigned to a plot number");
#endif
	    fprintf(X11_ipc, "N%d\n", new_term_number);
	    fflush(X11_ipc);
#ifdef EXTERNAL_X11_WINDOW
	} else if (set_window) {
	    fprintf(X11_ipc, "%c%lx\n", X11_GR_SET_WINDOW_ID, existing_X11_window_id);
	    fflush(X11_ipc);
#endif
	}
    }

#ifdef EXTERNAL_X11_WINDOW
    if (set_window) {
	sprintf(term_options, "XID 0x%lX", existing_X11_window_id);
    } else
#endif
    if (set_number && new_term_number >= 0) {
	sprintf(term_options, "%d", new_term_number);
    }
    if (UNSET != do_raise) {
	strcat(term_options, (yes == do_raise ? " raise" : " noraise"));
    }
    if (UNSET != persist) {
	strcat(term_options, (yes == persist ? " persist" : " nopersist"));
    }
    if (UNSET != ctrlq) {
	strcat(term_options, (yes == ctrlq ? " ctrlq" : " noctrlq"));
    }
    if (UNSET != dashedlines) {
	strcat(term_options, (yes == dashedlines ? " dashed" : " solid"));
    }
    if (term->put_text == ENHX11_put_text) {
	strcat(term_options, " enhanced");
    }
    if (X11_linewidth_multiplier != 1.0) {
	sprintf(term_options + strlen(term_options),
		" linewidth %.2g", X11_linewidth_multiplier);
    }
    if (*X11_default_font) {
	strcat(term_options, " font \"");
	strcat(term_options, X11_default_font);
	strcat(term_options, "\"");
    }
    if (set_title) {
	char *title;
	int save_token = c_token;
	c_token = c_title_token;
	strncat(term_options, " title \"", MAX_LINE_LEN-strlen(term_options));
	title = term_options + strlen(term_options);
	if (isstringvalue(c_title_token)) {
	    char *s = try_to_get_string();
	    strncat(term_options, s, MAX_LINE_LEN-strlen(term_options));
	    free(s);
	} else
	    copy_str(term_options+strlen(term_options), c_title_token, MAX_LINE_LEN-strlen(term_options));
	if (X11_ipc) {
	    /* Send up to maximum buffer length minus three characters of
	     * title string to account for required 'n', '\0', '\n'.
	     */
	    int i;
	    fputc('n', X11_ipc);
	    for (i=0; i < X11_COMMAND_BUFFER_LENGTH-3 && title[i] != '\0'; i++)
		fputc(title[i], X11_ipc);
	    fputc('\0', X11_ipc);
	    fputc('\n', X11_ipc);
	    fflush(X11_ipc);
	}
	strncat(term_options, "\"", MAX_LINE_LEN-strlen(term_options));
	c_token = save_token;
    }
    if (set_size != UNSET)
	sprintf(term_options + strlen(term_options),
	      " size %d,%d ", X11_SIZE_X,X11_SIZE_Y);

    if (set_position != UNSET)
	sprintf(term_options + strlen(term_options),
	      " position %d,%d ", X11_POSITION_X,X11_POSITION_Y);

    X11_update_opts();
}


void
x11_raise_terminal_window(int number)
{
    /* Send the raise character and a number. */
    if (X11_ipc) {
	fprintf(X11_ipc, "^%d\n", number);
	fflush(X11_ipc);
    }
}

void
x11_raise_terminal_group(void)
{
    /* Send just the raise character. */
    if (X11_ipc) {
	fprintf(X11_ipc, "^\n");
	fflush(X11_ipc);
    }
}

void
x11_lower_terminal_window(int number)
{
    /* Send the raise character and a number. */
    if (X11_ipc) {
	fprintf(X11_ipc, "v%d\n", number);
	fflush(X11_ipc);
    }
}

void
x11_lower_terminal_group(void)
{
    /* Send just the raise character. */
    if (X11_ipc) {
	fprintf(X11_ipc, "v\n");
	fflush(X11_ipc);
    }
}


TERM_PUBLIC void
X11_update_opts()
{
    if (!X11_ipc)
	return;

    if (UNSET != do_raise || UNSET != persist || UNSET != dashedlines || UNSET != ctrlq) {
	fprintf(X11_ipc, "X %d %d %d %d\n", 
		do_raise, persist, dashedlines, ctrlq);
	fflush(X11_ipc);
    }

    /* pass size as a valid X11 geometry string WIDTHxHEIGHT[+XPOS+YPOS] */
    if (set_size != UNSET || set_position != UNSET) {
	if (set_size != UNSET && set_position == UNSET)
	    fprintf(X11_ipc, "s %dx%d\n", X11_SIZE_X, X11_SIZE_Y);
	else if (set_size == UNSET && set_position != UNSET)
	    fprintf(X11_ipc, "s %+d%+d\n", X11_POSITION_X, X11_POSITION_Y);
	else if (set_size != UNSET && set_position != UNSET)
	    fprintf(X11_ipc, "s %dx%d%+d%+d\n", X11_SIZE_X, X11_SIZE_Y,
		X11_POSITION_X, X11_POSITION_Y);
	fflush(X11_ipc);
    }
}


/*-----------------------------------------------------------------------------
 *   Three different versions of the remainder of the X11 terminal driver
 *   are provided to support three different types of IPC with the
 *   gnuplot_x11 outboard terminal driver:
 *
 *   DEFAULT_X11:      popen() pipe for most un*x platforms
 *
 *   CRIPPLED_SELECT : file IPC for un*x platforms with incomplete or faulty
 *                     implementation of BSD select()
 *
 *   VMS :             mailbox/spawn IPC
 *---------------------------------------------------------------------------*/

#define DEFAULT_X11
#if defined(VMS) || defined(CRIPPLED_SELECT)
# undef DEFAULT_X11
#endif
#if defined(VMS) && defined(CRIPPLED_SELECT)
Error.Incompatible options.
#endif
/* we do not want to have to duplicate all the code, so we
 * do most of it with macros.
 * PRINT0(format), PRINT1(format, p1), PRINT2(format, p1, p2) etc
 * also  FLUSH0(format), etc, which do an additional flush
 */
#ifdef DEFAULT_X11
/*-----------------------------------------------------------------------------
 *   DEFAULT_X11 popen() pipe IPC
 *---------------------------------------------------------------------------*/
static void
X11_atexit()
{
    if (X11_ipc) {
	fputs("R\n", X11_ipc);
	fclose(X11_ipc);
	/* dont wait(), since they might be -persist */
	X11_ipc = NULL;
#ifdef PIPE_IPC
	close(ipc_back_fd);
	ipc_back_fd = -1;
#endif
    }
}

#ifdef USE_MOUSE

TERM_PUBLIC int
X11_waitforinput()
{
#ifdef PIPE_IPC
    fd_set fds;
    static struct gp_event_t ge;
    static int l = 0;
    int n;
    int fd = fileno(stdin);
    int repeat_count = 0;

AGAIN:
    /* XXX:  if the input device it not a tty (e.g. /dev/null)
     *       mouse events are not processed. This is necessary
     *       as on some systems /dev/null is not selectable.
     * TODO: should we close the ipc_back_fd in this case ? */
    if (ipc_back_fd >= 0)
	do {
	    int ierr;
	    FD_ZERO(&fds);
	    FD_SET(fd, &fds);
	    FD_SET(ipc_back_fd, &fds);
	    ierr = select(ipc_back_fd + 1, SELECT_TYPE_ARG234 &fds, 0, 0, NULL);
	    if (ierr < 0 && errno == EINTR) {
		FD_ZERO(&fds);
		continue;
	    }
	    if (FD_ISSET(ipc_back_fd, &fds)) {
		n = read(ipc_back_fd, (void *) (l + (char *) &ge), sizeof(ge) - l);
		if (n == 0) {
		    close(ipc_back_fd);
		    ipc_back_fd = -1;
		    /* don't close X11_ipc, otherwise later writes
		     * to it will cause a segfault */
		    IPC_LOCK = FALSE;
		    break;	/* outboard driver has stopped */
		}
		l += n;
		if (l == sizeof(ge)) {
		    /* note: do_event() may not return (if an
		     * error occurs), so need to reset l first */
		    l = 0;
		    do_event(&ge);
		    if (ge.type == GE_fontprops) {
		    	if (repeat_count > 0) {
		    	    FPRINTF((stderr,
			        "X11_waitforinput: caught GE_fontprops after %d tries\n",
				repeat_count));
			}
			return(GE_fontprops);
		    }
		    if (ge.type == GE_buttonrelease && (paused_for_mouse & PAUSE_CLICK)) {
			int button = ge.par1;
			if (button == 1 && (paused_for_mouse & PAUSE_BUTTON1))
			    paused_for_mouse = 0;
			if (button == 2 && (paused_for_mouse & PAUSE_BUTTON2))
			    paused_for_mouse = 0;
			if (button == 3 && (paused_for_mouse & PAUSE_BUTTON3))
			    paused_for_mouse = 0;
			if (paused_for_mouse == 0)
			    return '\0';
		    }
		    if (ge.type == GE_keypress && (paused_for_mouse & PAUSE_KEYSTROKE)) {
			/* Ignore NULL keycode */
			if (ge.par1 > '\0') {
			    paused_for_mouse = 0;
			    return '\0';
			}
		    }
		}
	    }
	} while (!FD_ISSET(fd, &fds));

    /* If ipc_back_fd is not open, we will never see any mouse events! */
    else if (paused_for_mouse) {
	paused_for_mouse = 0;
	int_error(NO_CARET,"Mousing not active");
    }

    /* IPC_LOCK indicates that we are specifically waiting for a reply on */
    /* the mousing channel.  If stdin unblocks first, defer reading it,   */
    /* wait a few microseconds, and try again.                            */
    /* FIXME EAM - Give up after a few seconds. This will drop input chars*/
    /* but at least it won't hang forever if the X11 connection goes bad. */
    if (IPC_LOCK) {
#ifdef HAVE_USLEEP
	usleep(100);
#endif
        if (repeat_count++ < 10000)
	    goto AGAIN;
    }

    /* Same sort of thing if we are specifically waiting for mouse input. */
    if (paused_for_mouse) {
#ifdef HAVE_USLEEP
	usleep(10);
#endif
	goto AGAIN;
    }

#endif /* PIPE_IPC */

# if 0
/* HBB 20010620: switching back and forth between X11 and a non-GUI
 * terminal, while stdin is redirected, causes gnuplot to terminate
 * right after it re-enters the X11 terminal --- read() returns a '\0'
 * character once, and then EOF. Switching to <stdio.h>'s getc() fixed
 * that, for me. */
    if (read(0, &c, 1) != 1)
	return EOF;
    else
	return c;
# else
    return getc(stdin);
# endif	/* 0/1 */
}
#endif /* USE_MOUSE */


TERM_PUBLIC void
X11_init()
{
    static int been_here = 0;

    if (!X11_ipc) {
	/* first time through or after a reset */
#if defined(OS2)
      /* FIXME amai 20020219: nice try...
       * But popen() does return a non-NULL handle to almost command,
       * it's just a new session which will stop if the command does
       * not exist... We should stat() for the argument?! */
      /* X11_ipc = popen(X11_full_command_path, "w");
      if (X11_ipc==NULL) */
      {
	   X11_ipc = popen(X11_command, "w");
      }
#else /* !(OS/2) */
	int fdes[2];
# ifdef PIPE_IPC
	int fdes_back[2];

#define X11_ALLOW_EVENTS (mouse_setting.on)
	if (X11_ALLOW_EVENTS) {
	    if (pipe(fdes_back))
		perror("pipe() failed:");
	}
# endif	/* PIPE_IPC */
	if (pipe(fdes))
	    perror("pipe() failed:");

	if (fork() == 0) {
	    /* child */
# ifdef PIPE_IPC
	    char noevents[] = "-noevents";
	    if (X11_ALLOW_EVENTS) {
		dup2(fdes_back[1], 1);	/* stdout to pipe */
		close(fdes_back[0]);
	    } else {
		char **ptr;
		for (ptr = optvec; ptr && *ptr; ptr++)
		    ;		/* do nothing: skip over set arguments */
		/* tell the driver not to supply any events by
		 * appending "-noevents" to the optvec list. */
		*ptr = noevents;
		*++ptr = (char *) 0;	/* terminate */
	    }
# endif	/* PIPE_IPC */

	    /* Add user-specified background to list of command options */
	    if (strcmp(x11_userbkg,"#RRGGBB")) {
		char **ptr;
		for (ptr = optvec; ptr && *ptr; ptr++)
		    ;		/* do nothing: skip over set arguments */
		*ptr++ = "-bg";
		*ptr++ = x11_userbkg;
		*ptr = (char *) 0;	/* terminate */
	    }

	    /* close the write side of the child's forward fd */
	    close(fdes[1]);
	    dup2(fdes[0], 0);	/* stdin from pipe */
	    execvp(X11_full_command_path, optvec);
	    /* if we get here, something went wrong */
	    fprintf(stderr,"Expected X11 driver: %s\n",X11_full_command_path);
	    perror("Exec failed");
	    fprintf(stderr,"See 'help x11' for more details\n");
	    exit(EXIT_FAILURE);
	}
	/* parent */
# ifdef PIPE_IPC
	/* X11_ipc_out = fdopen(fdes[0], "r"); */
	if (ipc_back_fd > 0) {
	    fprintf(stderr, "(X11_init) warning: unclosed ipc_back_fd.\n");
	    fprintf(stderr, "           this is probably a program error.\n");
	    close(ipc_back_fd);
	}
	if (X11_ALLOW_EVENTS) {
	    ipc_back_fd = fdes_back[0];
	    close(fdes_back[1]);	/* the parent doesn't need this */
	} else {
	    /* we do not open a bidirectional communication
	     * for non-tty's by default. If this is desired,
	     * the mouse must be turned on explicitely *before*
	     * starting the x11 driver.
	     * So: if we're here, we close the ipc-back-channel
	     * which will cause a SIGPIPE in the driver. This
	     * is *ugly* but it works. (joze) */
	    /* close(fdes_back[0]); */
	    /* mark ipc_back_fd as unusable */
	    ipc_back_fd = IPC_BACK_UNUSABLE;
	}
# endif	/* PIPE_IPC */
	/* close the read side of the parent's forward fd */
	close(fdes[0]);
	X11_ipc = fdopen(fdes[1], "w");
#endif /* !OS/2 */
    }

    if (!been_here) {
	GP_ATEXIT(X11_atexit);
	been_here++;
    }
    X11_send_endianess();
#ifdef USE_MOUSE
    default_font_size_known = FALSE;
#endif
    X11_update_opts();
}

TERM_PUBLIC void
X11_reset()
{
    /* Leave the pipe alone, until exit or  set term x11 reset */
    /* but make sure that all locks are cleared.               */
#ifdef PIPE_IPC
    IPC_LOCK = FALSE;
#endif
#ifdef USE_MOUSE
    paused_for_mouse = 0;
#endif
}

#define PRINT0(fmt)          fprintf(X11_ipc, fmt)
#define PRINT1(fmt,p1)       fprintf(X11_ipc, fmt,p1)
#define PRINT2(fmt,p1,p2)    fprintf(X11_ipc, fmt,p1,p2)
#define PRINT3(fmt,p1,p2,p3) fprintf(X11_ipc, fmt,p1,p2,p3)
#define PRINT4(fmt,p1,p2,p3,p4) fprintf(X11_ipc, fmt,p1,p2,p3,p4)
#define PRINT5(fmt,p1,p2,p3,p4,p5) fprintf(X11_ipc, fmt,p1,p2,p3,p4,p5)

#define FFLUSH()             fflush(X11_ipc)

#define BEFORE_GRAPHICS		/* nowt */
#define AFTER_TEXT		/* nowt */


#elif defined(CRIPPLED_SELECT)
/* PLEASE CAN SOMEONE CHECK THAT THIS STILL WORKS !!! */
/*-----------------------------------------------------------------------------
 *   CRIPPLED_SELECT file IPC
 *---------------------------------------------------------------------------*/
static char X11_tmp[32], X11_tmp0[32], X11_shutdown[32];
static int X11_pid;

TERM_PUBLIC void
X11_init()
{
    if (!(X11_pid = fork())) {
	execvp(X11_full_command_path, optvec);
	_exit(1);
    }
    sprintf(X11_tmp, "/tmp/Gnuplot_%d", X11_pid);
    sprintf(X11_tmp0, "%s-", X11_tmp);
    sprintf(X11_shutdown, "echo R >%s", X11_tmp);
}

TERM_PUBLIC void
X11_reset()
{
    system(X11_shutdown);
}

#define BEFORE_GRAPHICS \
 if (!(X11_ipc = fopen(X11_tmp0, "w"))) { \
   perror(X11_tmp0); system(X11_shutdown); exit(1); \
 }

#define AFTER_TEXT \
 { fclose(X11_ipc); rename(X11_tmp0, X11_tmp); }

#define PRINT0(fmt)          fprintf(X11_ipc, fmt)
#define PRINT1(fmt,p1)       fprintf(X11_ipc, fmt,p1)
#define PRINT2(fmt,p1,p2)    fprintf(X11_ipc, fmt,p1,p2)
#define PRINT3(fmt,p1,p2,p3) fprintf(X11_ipc, fmt,p1,p2,p3)
#define PRINT4(fmt,p1,p2,p3,p4) fprintf(X11_ipc, fmt,p1,p2,p3,p4)
#define PRINT5(fmt,p1,p2,p3,p4,p5) fprintf(X11_ipc, fmt,p1,p2,p3,p4,p5)
#define FFLUSH()             fflush(X11_ipc)

static void
X11_atexit()
{
    /* WHAT SHOULD I DO ? */
}
#elif defined(VMS)
/*-----------------------------------------------------------------------------
 *   VMS mailbox/spawn IPC - Yehavi Bourvine - YEHAVI@VMS.HUJI.AC.IL
 *---------------------------------------------------------------------------*/
#include <iodef.h>
#include <descrip.h>
#include <dvidef.h>
#ifdef __DECC
#include <lib$routines.h>
#include <starlet.h>
#endif
#ifdef __GNUC__
#include <errno.h>
#else
int vaxc$errno;
#endif

#define SS$_NORMAL 1		/* or include <ssdef.h> for all SS$_ def's */

#define MBXMXMSG 128		/* DEFMBXMXMSG is set by SYSGEN */

static short X11_channel;

struct iosb {
    unsigned short stat;
    unsigned short count;
    unsigned long info;
};



TERM_PUBLIC void
X11_init()
{

    struct iosb iosb;

    static char devnam_string[64];
    static $DESCRIPTOR(devnam, devnam_string);

    struct {
	short int buf_len;
	short int item;
	char *buf_addr;
	unsigned short int *ret_len;
	int end;
    } item_list = {
    devnam.dsc$w_length, DVI$_DEVNAM, devnam.dsc$a_pointer, &devnam.dsc$w_length, 0};
#define CMDLEN 1024
    char cmdline[CMDLEN], *cmdp;
    int optindex;

    if (!X11_channel) {
	int one = 1;

	/* Create a descriptor for the command line that starts
	   GNUPLOT_X11. $DESCRIP doesn't work in this context... */

	/* FIXME!
	 * This does not work anymore since X11 option passing has been
	 * changed to use execvp() in the DEFAULT_X11 case
	 */
	struct dsc$descriptor_s pgmdsc = { 0, DSC$K_DTYPE_T,
	    DSC$K_CLASS_S, 0
	};
	optindex = 0;
	strcpy(cmdline, optvec[optindex]);
	cmdp = cmdline + strlen(optvec[optindex]);
	while (optvec[++optindex] != NULL) {
	    *cmdp++ = ' ';
	    *cmdp++ = '\"';
	    strcpy(cmdp, optvec[optindex]);
	    cmdp += strlen(optvec[optindex]);
	    *cmdp++ = '\"';
	}
	pgmdsc.dsc$w_length = cmdp - cmdline;
	pgmdsc.dsc$a_pointer = cmdline;

	/* Create a mailbox which will be used as a pipe for commands to the
	 * subprocess.  What we'll write to it will be read by the subprocess
	 * as its STDIN.  Use an unnamed mailbox and refer to it by its device
	 * number */

	vaxc$errno = sys$crembx(0, &X11_channel, MBXMXMSG, MBXMXMSG, 0, 0, 0, 0);
	if ((vaxc$errno & SS$_NORMAL) != SS$_NORMAL) {
	    printf("SYS$CreMbx failed with status=%d\r\n", vaxc$errno);
	    os_error(NO_CARET, "sys$crembx failed");
	}
	vaxc$errno = sys$getdviw(0, X11_channel, 0, &item_list, &iosb, 0, 0, 0);
	if ((vaxc$errno & SS$_NORMAL) == SS$_NORMAL)
	    vaxc$errno = iosb.stat;
	if ((vaxc$errno & SS$_NORMAL) != SS$_NORMAL) {
	    printf("SYS$Getdviw failed with status=%d\r\n", vaxc$errno);
	    sys$dassgn(X11_channel);
	    X11_channel = 0;
	    os_error(NO_CARET, "sys$getdviw failed");
	}
	/* Create a subprocess whose input is this mailbox. */
	vaxc$errno = lib$spawn(&pgmdsc, &devnam, 0, &one, 0, 0, 0, 0, 0, 0, 0, 0, 0);
	if ((vaxc$errno & SS$_NORMAL) != SS$_NORMAL) {
	    printf("LIB$SPAWN failed with status=%d\r\n", vaxc$errno);
	    sys$dassgn(X11_channel);
	    X11_channel = 0;
	    os_error(NO_CARET, "lib$spawn failed");
	}
    }
    {
	static int been_here = 0;
	if (!been_here) {
	    GP_ATEXIT(X11_atexit);
	    been_here = 1;
	}
    }
}


/*   We use $QIO in order to avoid buffering problems, although it might
 *   work  as well with simple Fprintf calls.
 */

#define GO(x) \
do { \
   char buffer[512]; int status; struct iosb iosb;\
   sprintf x; \
   if (strlen(buffer) >= MBXMXMSG)  { \
     printf("buffer contents (%d char) catenated to mailbox size (%d bytes)\n", \
     strlen(buffer), MBXMXMSG); \
     buffer[MBXMXMSG-1] = '\0';\
     printf("%s\n", buffer); \
   } \
   status = sys$qiow(0, X11_channel, IO$_WRITEVBLK, &iosb, 0, 0, buffer, strlen(buffer), 0, 0, 0, 0); \
   if ((status & SS$_NORMAL) == SS$_NORMAL) status = iosb.stat; \
   if((status & SS$_NORMAL) != SS$_NORMAL) exit(status); \
 } while (0)

#define PRINT0(fmt)          GO((buffer, fmt))
#define PRINT1(fmt,p1)       GO((buffer, fmt,p1))
#define PRINT2(fmt,p1,p2)    GO((buffer, fmt,p1,p2))
#define PRINT3(fmt,p1,p2,p3) GO((buffer, fmt,p1,p2,p3))
#define PRINT4(fmt,p1,p2,p3,p4) GO((buffer, fmt,p1,p2,p3,p4))
#define PRINT5(fmt,p1,p2,p3,p4,p5) GO((buffer, fmt,p1,p2,p3,p4,p5))

#define FFLUSH()		/* nowt */
#define BEFORE_GRAPHICS		/* nowt */
#define AFTER_TEXT		/* nowt */

static void
X11_atexit()
{
    if (X11_channel) {
	PRINT0("R\n");
	sleep(2);		/* Wait for subprocess to finish */
	sys$dassgn(X11_channel);
	X11_channel = 0;
    }
}

TERM_PUBLIC void
X11_reset()
{
    /* do nothing until exit */
}

#else /* !VMS */
    You lose.
#endif /* !VMS */

/* common stuff, using macros defined above */

TERM_PUBLIC void
X11_graphics()
{
#ifdef USE_MOUSE
    static unsigned long windowid = 0;
#endif
    static enum set_encoding_id last_encoding = S_ENC_DEFAULT;

    BEFORE_GRAPHICS;		/* kludge for crippled select */

#ifndef USE_MOUSE
    /* for VMS sake, keep as separate prints */
    PRINT0("G\n");
#else
#ifdef PIPE_IPC
    /* if we know the outboard driver has stopped, restart it */
    if (ipc_back_fd == IPC_BACK_CLOSED) {
	fclose(X11_ipc);
	X11_ipc = NULL;
	X11_init();
    }
#endif
    /* send also XID of gnuplot window (<space> then raises it up) */
    if (!windowid) {
	char *window_env = getenv("WINDOWID");
	if (window_env)
	    sscanf(window_env, "%lu", &windowid);
    }
#ifndef OS2
    PRINT1("G%lu\n", windowid);
#else
    PRINT2("G%lu %i\n", windowid, getpid());
#endif
#endif /* USE_MOUSE */

#ifdef ULTRIX_KLUDGE
    fflush(X11_ipc);
#endif

    if (encoding != last_encoding) {
	PRINT1("QE%d\n",encoding);
	last_encoding = encoding;
    }

#if defined(USE_MOUSE) && defined(PIPE_IPC)
    /* EAM June 2003 - Flush the set font command through the pipe */
    /* to gnuplot_x11, then wait for it to return the resulting    */
    /* font size information (v_char and h_char). The feedback is  */
    /* caught by do_event() as an event of type GE_fontprops.      */
    if (ipc_back_fd >= 0 && X11_MOUSE_FEEDBACK) {
	if (!default_font_size_known) {
	    IPC_LOCK = TRUE;
	    PRINT1("QG%s\n",X11_default_font);
	    FFLUSH();
	    X11_waitforinput();
	    default_font_size_known = TRUE;
	    IPC_LOCK = FALSE;
	}
    }
#endif
    /* Force default font at start of plot */
    *X11_last_font_used = '\01';
    X11_set_default_font();
    X11_set_font("");
}

TERM_PUBLIC void
X11_text()
{
     if (!X11_ipc)
 	return;

#ifdef USE_MOUSE
    /* EAM July 2003:  send over a snapshot of the final axis scaling
     * so that subsequent mouse events can be transformed into plot
     * coordinates even though the plot is no longer active.
     */
#ifdef PIPE_IPC
    if (ipc_back_fd >= 0)
#endif
	{
	/* Construct a mask showing which axes are active */
	int axis_mask = 0;
	int i;

	for (i = FIRST_AXES; i < 2*SECOND_AXES; i++) {
	    if (axis_array[i].ticmode != NO_TICS)
		axis_mask |= (1 << i);
	}
	PRINT2("S %2d %d\n", -2, ALMOST2D);
	PRINT2("S %2d %d\n", -1, axis_mask);
	PRINT5("S %2d %16.6g %14d %16.6g %16.6g\n", FIRST_X_AXIS,
		axis_array[FIRST_X_AXIS].min,
		axis_array[FIRST_X_AXIS].term_lower,
		axis_array[FIRST_X_AXIS].term_scale,
		axis_array[FIRST_X_AXIS].log ? axis_array[FIRST_X_AXIS].log_base : 0);
	PRINT5("S %2d %16.6g %14d %16.6g %16.6g\n", FIRST_Y_AXIS,
		axis_array[FIRST_Y_AXIS].min,
		axis_array[FIRST_Y_AXIS].term_lower,
		axis_array[FIRST_Y_AXIS].term_scale,
		axis_array[FIRST_Y_AXIS].log ? axis_array[FIRST_Y_AXIS].log_base : 0);
	PRINT5("S %2d %16.6g %14d %16.6g %16.6g\n", SECOND_X_AXIS,
		axis_array[SECOND_X_AXIS].min,
		axis_array[SECOND_X_AXIS].term_lower,
		axis_array[SECOND_X_AXIS].term_scale,
		axis_array[SECOND_X_AXIS].log ? axis_array[SECOND_X_AXIS].log_base : 0);
	PRINT5("S %2d %16.6g %14d %16.6g %16.6g\n", SECOND_Y_AXIS,
		axis_array[SECOND_Y_AXIS].min,
		axis_array[SECOND_Y_AXIS].term_lower,
		axis_array[SECOND_Y_AXIS].term_scale,
		axis_array[SECOND_Y_AXIS].log ? axis_array[SECOND_Y_AXIS].log_base : 0);
    }
#endif

    PRINT0("E\n");
    FFLUSH();
#ifdef ULTRIX_KLUDGE
    PRINT0("E\n");
    FFLUSH();
#endif

    AFTER_TEXT;			/* kludge for crippled select */
}

TERM_PUBLIC void
X11_move(unsigned int x, unsigned int y)
{
    PRINT2("M%04d%04d\n", x, y);
}

TERM_PUBLIC void
X11_vector(unsigned int x, unsigned int y)
{
    PRINT2("V%04d%04d\n", x, y);
}

TERM_PUBLIC void
X11_pointsize(double ps)
{
    if (ps < 0)
	ps = 1;
    PRINT2("P-2 %d %d\n",	/* size of point symbols */
	   (int) (term->h_tic * ps * 0.5), (int) (term->v_tic * ps * 0.5));
}

TERM_PUBLIC void
X11_linewidth(double lw)
{
    PRINT1("W%04d\n", (int) (lw * X11_linewidth_multiplier + 0.5));
}

TERM_PUBLIC void
X11_linetype(int lt)
{
    PRINT1("L%04d\n", lt);
}

TERM_PUBLIC void
X11_put_text(unsigned int x, unsigned int y, const char str[])
{
    /* Only send the font change request to X11 if it really is a change */
    if (strcmp(X11_last_font_used,X11_next_font_used)) {
	strcpy(X11_last_font_used,X11_next_font_used);
	PRINT1("QF%s\n", X11_next_font_used);
    }

    /* badly outrange labels can overflow into text field */
    if (x < 10000 && y < 10000) {
	PRINT3("T%04d%04d%s\n", x, y, str);
    }
}

TERM_PUBLIC int
X11_text_angle(int ang)
{
    PRINT1("A%d\n", ang);
    return TRUE;
}

TERM_PUBLIC int
X11_justify_text(enum JUSTIFY mode)
{
    PRINT1("J%04d\n", mode);
    X11_last_justification = mode;
    return (TRUE);
}

TERM_PUBLIC void
X11_point(unsigned int x, unsigned int y, int number)
{
    PRINT3("P%d %d %d\n", number, x, y);
}

TERM_PUBLIC int
X11_set_font(const char *fontname)
{
    PRINT1("QF%s\n", fontname?fontname:"");
    strncpy(X11_next_font_used,fontname?fontname:"",sizeof(X11_next_font_used)-1);
    return(TRUE);
}

static void
X11_set_default_font()
{
    PRINT1("QD%s\n",X11_default_font);
}

TERM_PUBLIC void
X11_fillbox(int style, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
{
    if (X11_ipc) {
	PRINT5("F%04d%04u%04u%04u%04u\n", style, x, y, w, h);
    }
}

#ifdef USE_MOUSE
TERM_PUBLIC void
X11_put_tmptext(int i, const char str[])
{
    if (X11_ipc) {
	PRINT2("t%04d%s\n", i, str);
	FFLUSH();
    }
}

TERM_PUBLIC void
X11_set_ruler(int x, int y)
{
    if (X11_ipc) {
	PRINT2("r%04d%04d\n", x < 9999 ? x : 9999, y < 9999 ? y : 9999);
	FFLUSH();
    }
}

TERM_PUBLIC void
X11_set_cursor(int c, int x, int y)
{
    if (X11_ipc) {
	PRINT3("u%04d%04d%04d\n", c, x, y);
	FFLUSH();
    }
}

TERM_PUBLIC void
X11_set_clipboard(const char s[])
{
    if (X11_ipc) {
	PRINT1("z%s\n", s);
	FFLUSH();
    }
}

#endif /* USE_MOUSE */


static void
transmit_gradient(gradient_struct *gradient, int cnt)
{
    int i = 0;

    fprintf(X11_ipc, "%d", cnt);
    for(i=0; i<cnt; i++) {
        /* this %50 *must* match the corresponding %50 in gplt_x11.c  */
        if(i%50 == 0) {
	    fputs("\n", X11_ipc);
	    fflush(X11_ipc);
	}
	/* Send gradient entry as 0.1234RRGGBB */
	fprintf(X11_ipc, "%6.4f", gradient[i].pos);
	fprintf(X11_ipc, "%02x", (unsigned int)(255.*gradient[i].col.r + 0.5));
	fprintf(X11_ipc, "%02x", (unsigned int)(255.*gradient[i].col.g + 0.5));
	fprintf(X11_ipc, "%02x", (unsigned int)(255.*gradient[i].col.b + 0.5));
    }
    fputs("\n", X11_ipc);
}


TERM_PUBLIC int
X11_make_palette(t_sm_palette *palette)
{
    if(!palette) {
        return 0;
    }

    if(!X11_ipc) {
	    fprintf(stderr, "(X11_make_palette) 0 == X11_ipc\n");
	    return -1;
	}

    fprintf(X11_ipc, "%c %c %c %c %d\n",
	     X11_GR_MAKE_PALETTE, (char)(palette->colorMode),
	     (char)(palette->positive), (char)(palette->cmodel),
	     palette->use_maxcolors);

    switch(palette->colorMode) {
    case SMPAL_COLOR_MODE_GRAY:
        fprintf(X11_ipc,"%g\n", palette->gamma);
        break;
    case SMPAL_COLOR_MODE_RGB:
        fprintf(X11_ipc, "%d %d %d\n", palette->formulaR,
		 palette->formulaG, palette->formulaB);
	break;
    case SMPAL_COLOR_MODE_GRADIENT:
        transmit_gradient(palette->gradient, palette->gradient_num);
	break;
    case SMPAL_COLOR_MODE_CUBEHELIX:
    case SMPAL_COLOR_MODE_FUNCTIONS: {
        int cnt=0;
	gradient_struct *gradient;
	gradient = approximate_palette(palette, -1, -1, &cnt);
	transmit_gradient(gradient, cnt);
	free(gradient);
	break;
    }
    default:
        fprintf(stderr, "%s:%d ooops: Unknown colorMode '%c'.\n",
		 __FILE__, __LINE__, (char)(palette->colorMode));
    }
    fflush(X11_ipc);
    return 0;
}


#if 0
/* The following are some handy little routines to keep around
 * in case one wants to do statistics on the binary data being
 * passed to a terminal function.
 */

int char_count[256];

void histogram(unsigned char c) {
    char_count[c] += 1;
}

void dump_histogram(void) {
  int i, sum;
  fprintf(stderr,"\n\n");
  for (i=0,sum=0; i<256; i++) {
    fprintf(stderr," %3.3d:%7.7d ", i, char_count[i]);
    sum += char_count[i];
  }
  fprintf(stderr,"\n\ntotal: %d\n\n",sum);
}
#endif

TERM_PUBLIC void
X11_set_color(t_colorspec *colorspec)
{
    if (colorspec->type == TC_RGB) {
	fputc(X11_GR_SET_RGBCOLOR, X11_ipc);
	PRINT1("%6.6x\n", colorspec->lt & 0xffffff);
	FFLUSH();
	return;
    }

    if (colorspec->type == TC_LT) {
	fputc(X11_GR_SET_LINECOLOR, X11_ipc);
	PRINT1("%4d\n", colorspec->lt);
	FFLUSH();
	return;
    }

    if (colorspec->type != TC_FRAC)
	return;

    {
    char *c_ptr;
    unsigned short byte_remaining;
    float fgray = colorspec->value;

    fputc(X11_GR_BINARY_COLOR, X11_ipc);
    byte_remaining = sizeof(fgray);
    c_ptr = (char *) &fgray;

    while (byte_remaining) {

	char c_tmp = *c_ptr++ - SET_COLOR_TRANSLATION_CHAR;

	byte_remaining--;

	if ( (c_tmp == '\n') || (c_tmp == SET_COLOR_CODE_CHAR) || (c_tmp == '\0') ) {
	    fputc(SET_COLOR_CODE_CHAR, X11_ipc);
	    c_tmp += 1;
	}
	fputc(c_tmp, X11_ipc);

    }

    fputc('\n', X11_ipc);
    FFLUSH();
    }

}

TERM_PUBLIC void
X11_filled_polygon(int points, gpiPoint *corners)
{
    int int_cache[2];
    int i_corner;
    unsigned short i_buffer;
    unsigned short byte_remaining;
    unsigned int point_remaining;

    /* Encode and transfer data to the pipe, one character at a time. */

    if (!points) return;

    fputc(X11_GR_BINARY_POLYGON, X11_ipc);
    i_buffer = BINARY_MAX_CHAR_PER_TRANSFER;

    /* First put number of points into the buffer.  Initialize the "cache"
     * to the number of points and the number of bytes to transfer to the
     * size of an int.  This will be the first transfer, so increase the
     * number of points by one.
     */
    int_cache[0] = points;
    int_cache[1] = corners->style;
    byte_remaining = 2*sizeof(int_cache[0]);
    point_remaining = points + 1;
    i_corner = 0;

    while (point_remaining) {

	unsigned char *uc_ptr = (unsigned char *) int_cache;

	while (byte_remaining) {

	    int sent_val;

	    unsigned char uc_tmp = *uc_ptr++ - FILLED_POLYGON_TRANSLATION_CHAR;
	    byte_remaining--;

	    if ( (uc_tmp == '\n') || (uc_tmp == FILLED_POLYGON_CODE_CHAR) || (uc_tmp == '\0') ) {
		uc_tmp += 1;
		sent_val = fputc(FILLED_POLYGON_CODE_CHAR, X11_ipc);
		if (sent_val != (int)FILLED_POLYGON_CODE_CHAR)
		    fprintf(stderr, "Bad character mapping %d -> %d\n", (int)FILLED_POLYGON_CODE_CHAR, sent_val);
		i_buffer--;
		if (!i_buffer) {
		    fputc('\n', X11_ipc);  FFLUSH();               /* End of chunk. */
		    i_buffer = BINARY_MAX_CHAR_PER_TRANSFER;
		    fputc(X11_GR_BINARY_POLYGON, X11_ipc);         /* Will be another chunk. */
		}
	    }

	    sent_val = fputc(uc_tmp, X11_ipc);
	    if (sent_val != (int)uc_tmp)
		fprintf(stderr, "Bad character mapping %d -> %d\n", (int)uc_tmp, sent_val);
	    i_buffer--;
	    if (!i_buffer) {
		fputc('\n', X11_ipc);  FFLUSH();                   /* End of chunk. */
		i_buffer = BINARY_MAX_CHAR_PER_TRANSFER;
		if (point_remaining || byte_remaining)
		    fputc(X11_GR_BINARY_POLYGON, X11_ipc);         /* Will be another chunk. */
	    }

	}

	byte_remaining = 2*sizeof(int);
	if (--point_remaining) {
	    int_cache[0] = corners[i_corner].x;
	    int_cache[1] = corners[i_corner].y;
	    i_corner++;
	}
    }

    /* Check if some characters were put in the buffer that need to be flushed. */
    if (i_buffer != BINARY_MAX_CHAR_PER_TRANSFER) {
	fputc('\n', X11_ipc);
	FFLUSH();
    }

    return;
}


/*
 * Ethan A Merritt November 2003
 *	- Support for enhanced text mode
 *
 * PROBLEMS:
 *	- The default font must be scalable
 *	- Without more feedback from the outboard driver (gnuplot_x11) it is
 *	  hard to set up proper text rotation. The current approximation is so-so.
 *	- Right- and Center- justified text is problematic for the same reason.
 *	- The default font size is not really known, and font scaling
 *	  in general could be improved
 */

static TBOOLEAN ENHx11_opened_string;
static TBOOLEAN ENHx11_sizeonly = FALSE;
static TBOOLEAN ENHx11_show = TRUE;
static int ENHx11_overprint = 0;
static TBOOLEAN ENHx11_widthflag = TRUE;
static double ENHx11_base;
static double ENHx11_fontsize;
static char  *ENHx11_font;

TERM_PUBLIC void
ENHX11_OPEN(
    char *fontname,
    double fontsize, double base,
    TBOOLEAN widthflag, TBOOLEAN showflag,
    int overprint)
{
    /* If the overprint code requests a save or request, that's all we do */
    if (overprint == 3) {
	PRINT2("Tp%04d%04d\n", 0, 0);
	return;
    } else if (overprint == 4) {
	PRINT2("Tr%04d%04d\n", 0, 0);
	return;
    }

    if (!ENHx11_opened_string) {
	ENHx11_opened_string = TRUE;
	enhanced_cur_text = &enhanced_text[0];
	ENHx11_font = fontname;
	ENHx11_fontsize = fontsize;
	ENHx11_base = base * 10;	/* FIXME - should this be v_char? v_tic? */
	ENHx11_show = showflag;
	ENHx11_overprint = overprint;
	ENHx11_widthflag = widthflag;
    }
}

/*
 * Write a string fragment and update current position.
 * We leave the real work up to gnuplot_x11!
 */
TERM_PUBLIC void
ENHX11_FLUSH()
{
    /* Send a command to print this string at current position */
    if (ENHx11_opened_string) {

	char tmpfont[128];	/* FIXME - there must be a better way! */
	*enhanced_cur_text = '\0';
	sprintf(tmpfont,"%s,%.1f", ENHx11_font, ENHx11_fontsize);
	PRINT1("QF%s\n", tmpfont);
	*X11_last_font_used = '\01';

	if (!ENHx11_show || ENHx11_sizeonly)
	    PRINT3("Ts%04d%04d%s\n", 0, (int)ENHx11_base, enhanced_text);
	else if (ENHx11_overprint == 1)
	    PRINT3("Tc%04d%04d%s\n", 0, (int)ENHx11_base, enhanced_text);
	else if (!ENHx11_widthflag && ENHx11_overprint != 0)
	    PRINT3("To%04d%04d%s\n", 0, (int)ENHx11_base, enhanced_text);
	else
	    PRINT3("Tu%04d%04d%s\n", 0, (int)ENHx11_base, enhanced_text);

	ENHx11_opened_string = FALSE;
    }
}

TERM_PUBLIC void
ENHX11_put_text(unsigned int x, unsigned int y, const char *str)
{
    char *original_string = (char *)str;
    static char *initial_font = NULL;
    double firstpass_fontsize = X11_default_fontsize;
    int pass = 1;

    if (ignore_enhanced_text) {
	X11_put_text(x,y,str);
	return;
    }

    if (!strlen(str))
	return;

    /* if there are no magic characters, we should just be able
     * punt the string to X11_put_text()
     */
    if (!strpbrk(str, "{}^_@&~")) {
	X11_put_text(x,y,str);
	return;
    }

    /* set up the global variables needed by enhanced_recursion() */
    enhanced_fontscale = 1.25;
    ENHx11_opened_string = FALSE;
    strncpy(enhanced_escape_format,"%c",sizeof(enhanced_escape_format));


    /* Tell gnuplot_x11 to set the current position to (x,y) */
	PRINT2("Tl%04d%04d\n", x, y);

    /* Text justification requires two passes. During the first pass we */
    /* don't draw anything, we just measure the space it will take.     */
    if (X11_last_justification != LEFT) {
	PRINT1("J%04d\n", LEFT);
	ENHx11_sizeonly = TRUE;
    }
PASS2:

    /* Make sure that we start out using the intended font.  */
	ENHx11_font = "DEFAULT";
	if (*X11_next_font_used) {
	    int sep = strcspn(X11_next_font_used,",");
	    free(initial_font);
	    initial_font = gp_strdup(X11_next_font_used);
	    initial_font[sep] = '\0';
	    sscanf(&(X11_next_font_used[sep+1]),"%lf",&firstpass_fontsize);
	    ENHx11_font = initial_font;
	    FPRINTF((stderr,"setting font to %s,%g\n",ENHx11_font,ENHx11_fontsize));
	}

    /* Set the recursion going. We say to keep going until a
     * closing brace, but we don't really expect to find one.
     * If the return value is not the nul-terminator of the
     * string, that can only mean that we did find an unmatched
     * closing brace in the string. We increment past it (else
     * we get stuck in an infinite loop) and try again.
     */
    while (*(str = enhanced_recursion((char *)str, TRUE,
			ENHx11_font, firstpass_fontsize,
			0.0, TRUE, TRUE, 0))) {
	(term->enhanced_flush)();

	/* I think we can only get here if *str == '}' */
	    enh_err_check(str);

	if (!*++str)
	    break; /* end of string */

	/* else carry on and process the rest of the string */
    }
    X11_set_font("");

    /* Restore text justification flag after 2nd pass */
    if (pass > 1) {
	PRINT1("J%04d\n", X11_last_justification);
	return;
    }

    /* In order to do text justification we need to do a second pass that */
    /* uses information stored by gnuplot_x11 during the first pass.      */
    if (X11_last_justification != LEFT) {
	ENHx11_sizeonly = FALSE;

	if (X11_last_justification == RIGHT) {
		PRINT2("Tj%04d%04d\n", x, y);
	} else if (X11_last_justification == CENTRE) {
		PRINT2("Tk%04d%04d\n", x, y);
	}
	str = original_string;
	pass = 2;
	goto PASS2;

    }

}


TERM_PUBLIC void
X11_send_endianess(void)
{
    /* Place an integer 1 in the pipe and see if the byte order agrees
     * with program on the other side.  Information used for routines
     * having encoded binary data.
     */
    unsigned short tmp = (unsigned short) ENDIAN_VALUE;
    fputc(X11_GR_CHECK_ENDIANESS, X11_ipc);
    fputc(((char *)&tmp)[0], X11_ipc);
    fputc(((char *)&tmp)[1], X11_ipc);
    fputc('\n', X11_ipc);
    fflush(X11_ipc);
}


TERM_PUBLIC void
X11_image(unsigned int M, unsigned int N, coordval *image, gpiPoint *corner, t_imagecolor color_mode)
{

    /* Avoid using floats or formatted I/O.  That's too slow for image data.
     *
     * To avoid using floats, we assume that the maximum resolution of the
     * color plane of the x11 device is 16 bits.  (Not an unreasonable
     * assumption.)  So we convert coordval to unsigned short and then
     * send those.  The driver then shifts these unsigned short values to
     * the right to match the size of its palette.
     *
     * The driver uses the '\n' character to mean end of command.  When the
     * core routine sees the '\n', it stops copying the remaining characters
     * that are in the buffer.  Therefore, we need to hide the '\n' character
     * from the data stream.  We also need to hide the '\0' because the core
     * routine also does an 'strcpy'.  So the scheme is as follows:
     *
     *   On the driver side, if the char CODE_WORD is found it
     *   should be ignored and replaced with the char that
     *   follows it, but subtract one from that value.
     *
     * This means that there exists the chance of the data stream enlarging
     * by a factor of two.  So the algorithm must make sure to keep the
     * number of bytes transfered less than the buffer length.
     *
     * Also note that the '\0' character is often prevalent in 16 bit image
     * data where the palette may be 8 bits or less.  For this reason, a
     * translation is first done on the character to make the '\0' occur less
     * often.  In this way, less amount of data is sent and fewer command
     * lines are used to store an image.
     */

    unsigned short i_buffer;
    unsigned int coord_remaining;
    coordval *coord_ptr;

    /* Use formatted I/O to transfer image information.  Hexadecimal uses less characters.
     *
     * Note that X11 has different frame of reference (top left origin) than does Gnuplot
     * (bottom left origin)
     */
    fputc(X11_GR_IMAGE, X11_ipc);
    fprintf(X11_ipc,"%x %x %x %x %x %x %x %x %x %x %x\n", M, N, corner[0].x, corner[0].y, corner[1].x,
      corner[1].y, corner[2].x, corner[2].y, corner[3].x, corner[3].y, color_mode);
    FFLUSH();

    /* Encode and transfer data to the pipe, one character at a time. */

    coord_remaining = M*N;
    if (color_mode == IC_RGB)
	coord_remaining *= 3;
    else if (color_mode == IC_RGBA)
	coord_remaining *= 4;

    if (!coord_remaining) return;

    fputc(X11_GR_IMAGE, X11_ipc);
    i_buffer = BINARY_MAX_CHAR_PER_TRANSFER;
    coord_ptr = image;

    while (coord_remaining) {

	unsigned short us_tmp;
	unsigned short byte_remaining;
	unsigned char *uc_ptr;

	/* Convert coordinate value to an unsigned short.
	 * Palette and RGB values are on scale [0:1] at this point,
	 * but alpha values run from [0:255].  Why? I don't know.
	 */
	if (color_mode == IC_RGBA && !((coord_remaining+3) % 4))
	    us_tmp = (*coord_ptr++);
	else
	    us_tmp = (unsigned short) ((*coord_ptr++)*IMAGE_PALETTE_VALUE_MAX + 0.5);
	coord_remaining--;

	byte_remaining = sizeof(us_tmp);
	uc_ptr = (unsigned char *) &us_tmp;

	while (byte_remaining) {

	    int sent_val;

	    unsigned char uc_tmp = *uc_ptr++ - IMAGE_TRANSLATION_CHAR;
	    byte_remaining--;

	    if ((uc_tmp == '\n') || (uc_tmp == IMAGE_CODE_CHAR) || (uc_tmp == '\0') ) {
		uc_tmp += 1;
		sent_val = fputc(IMAGE_CODE_CHAR, X11_ipc);
		if (sent_val != (int)IMAGE_CODE_CHAR)
		    fprintf(stderr, "Bad character mapping %d -> %d\n", (int)IMAGE_CODE_CHAR, sent_val);
		i_buffer--;
		if (!i_buffer) {
		    fputc('\n', X11_ipc);  FFLUSH();               /* End of chunk. */
		    i_buffer = BINARY_MAX_CHAR_PER_TRANSFER;
		    fputc(X11_GR_IMAGE, X11_ipc);                  /* Will be another chunk. */
		}
	    }

	    sent_val = fputc(uc_tmp, X11_ipc);
	    if (sent_val != (int)uc_tmp)
		fprintf(stderr, "Bad character mapping %d -> %d\n", (int)uc_tmp, sent_val);
	    i_buffer--;
	    if (!i_buffer) {
		fputc('\n', X11_ipc);  FFLUSH();                   /* End of chunk. */
		i_buffer = BINARY_MAX_CHAR_PER_TRANSFER;
		if (coord_remaining || byte_remaining)
		    fputc(X11_GR_IMAGE, X11_ipc);                  /* Will be another chunk. */
	    }

	}

    }

    /* Check if some characters were put in the buffer that need to be flushed. */
    if (i_buffer != BINARY_MAX_CHAR_PER_TRANSFER) {fputc('\n', X11_ipc);  FFLUSH();}

    return;
}

#endif /* TERM_BODY */

#ifdef TERM_TABLE

TERM_TABLE_START(x11_driver)
    "x11", "X11 Window System",
    X11_XMAX, X11_YMAX, X11_VCHAR, X11_HCHAR,
    X11_VTIC, X11_HTIC, X11_options, X11_init, X11_reset,
    X11_text, null_scale, X11_graphics, X11_move, X11_vector,
    X11_linetype, X11_put_text, X11_text_angle,
    X11_justify_text, X11_point, do_arrow, X11_set_font,
    X11_pointsize, 
    TERM_CAN_MULTIPLOT|TERM_INIT_ON_REPLOT|TERM_NO_OUTPUTFILE|TERM_CAN_DASH|TERM_ALPHA_CHANNEL|TERM_LINEWIDTH,
    X11_text /* suspend can use same routine */ , 0 /* resume */ ,
    X11_fillbox, X11_linewidth
#ifdef USE_MOUSE
    , X11_waitforinput, X11_put_tmptext, X11_set_ruler, X11_set_cursor, X11_set_clipboard
#endif
    , X11_make_palette, 0 /* X11_previous_palette */ ,
    X11_set_color, X11_filled_polygon
    , X11_image
    , ENHX11_OPEN, ENHX11_FLUSH, do_enh_writec
TERM_TABLE_END(x11_driver)

#undef LAST_TERM
#define LAST_TERM x11_driver

#endif				/* TERM_TABLE */
#endif				/* TERM_PROTO_ONLY */


#ifdef TERM_HELP
START_HELP(x11)
"1 x11",
"?commands set terminal x11",
"?set terminal x11",
"?set term x11",
"?terminal x11",
"?term x11",
"?x11",
"?X11",
"",
" Syntax:",
"    set terminal x11 {<n> | window \"<string>\"}",
"                     {title \"<string>\"}",
"                     {{no}enhanced} {font <fontspec>}",
"                     {linewidth LW} {solid|dashed}",
"                     {{no}persist} {{no}raise} {{no}ctrlq}",
"                     {close}",
"                     {size XX,YY} {position XX,YY}",
"    set terminal x11 {reset}",
"",
" Multiple plot windows are supported: `set terminal x11 <n>` directs the",
" output to plot window number n.  If n is not 0, the terminal number will be",
" appended to the window title (unless a title has been supplied manually)",
" and the icon will be labeled `Gnuplot <n>`.  The active window may be",
" distinguished by a change in cursor (from default to crosshair).",
"",
" The `x11` terminal can connect to X windows previously created by an outside",
" application via the option `window` followed by a string containing the",
" X ID for the window in hexadecimal format.  Gnuplot uses that external X",
" window as a container since X does not allow for multiple clients selecting",
" the ButtonPress event.  In this way, gnuplot's mouse features work within",
" the contained plot window.",
"",
"    set term x11 window \"220001e\"",
"",
" The x11 terminal supports enhanced text mode (see `enhanced`), subject",
" to the available fonts. In order for font size commands embedded in text",
" to have any effect, the default x11 font must be scalable. Thus the first",
" example below will work as expected, but the second will not.",
"",
"    set term x11 enhanced font \"arial,15\" ",
"    set title '{/=20 Big} Medium {/=5 Small}' ",
"",
"    set term x11 enhanced font \"terminal-14\" ",
"    set title '{/=20 Big} Medium {/=5 Small}' ",
"",
" Plot windows remain open even when the `gnuplot` driver is changed to a",
" different device.  A plot window can be closed by pressing the letter q",
" while that window has input focus, or by choosing `close` from a window",
" manager menu.  All plot windows can be closed by specifying `reset`, which",
" actually terminates the subprocess which maintains the windows (unless",
" `-persist` was specified).  The `close` command can be used to close",
" individual plot windows by number.  However, after a `reset`, those plot",
" windows left due to persist cannot be closed with the command `close`.",
" A `close` without a number closes the current active plot window.",
"",
" The gnuplot outboard driver, gnuplot_x11, is searched in a default place",
" chosen when the program is compiled.  You can override that by defining",
" the environment variable GNUPLOT_DRIVER_DIR to point to a different",
" location.",
"",
" Plot windows will automatically be closed at the end of the session",
" unless the `-persist` option was given.",
"",
" The options `persist` and `raise` are unset by default, which means that",
" the defaults (persist == no and raise == yes) or the command line options",
" -persist / -raise or the Xresources are taken.  If [no]persist or",
" [no]raise are specified, they will override command line options and",
" Xresources.  Setting one of these options takes place immediately, so",
" the behaviour of an already running driver can be modified.  If the window",
" does not get raised, see discussion in `raise`.",
"",
" The option `title \"<title name>\"` will supply the title name of the window",
" for the current plot window or plot window <n> if a number is given.",
" Where (or if) this title is shown depends on your X window manager.",
"",
" The size option can be used to set the size of the plot window.  The",
" size option will only apply to newly created windows.",
"",
" The position option can be used to set the position of the plot window.  The",
" position option will only apply to newly created windows.",
"",
" The size or aspect ratio of a plot may be changed by resizing the `gnuplot`",
" window.",
"",
" Linewidths and pointsizes may be changed from within `gnuplot` with",
" `set linestyle`.",
"",
" For terminal type `x11`, `gnuplot` accepts (when initialized) the standard",
" X Toolkit options and resources such as geometry, font, and name from the",
" command line arguments or a configuration file.  See the X(1) man page",
" (or its equivalent) for a description of such options.",
"",
"=X resources",
" A number of other `gnuplot` options are available for the `x11` terminal.",
" These may be specified either as command-line options when `gnuplot` is",
" invoked or as resources in the configuration file \".Xdefaults\".  They are",
" set upon initialization and cannot be altered during a `gnuplot` session.",
" (except `persist` and `raise`)",
"2 x11_fonts",
"?commands set terminal x11 x11_fonts",
"?set terminal x11 x11_fonts",
"?set term x11 x11_fonts",
"?x11 x11_fonts",
"?x11_fonts",
"=fonts",
" Upon initial startup, the default font is taken from the X11 resources",
" as set in the system or user .Xdefaults file or on the command line.",
"",
" Example:",
"       gnuplot*font: lucidasans-bold-12",
" A new default font may be specified to the x11 driver from inside",
" gnuplot using",
"      `set term x11 font \"<fontspec>\"`",
" The driver first queries the X-server for a font of the exact name given.",
" If this query fails, then it tries to interpret <fontspec> as",
" \"<font>,<size>,<slant>,<weight>\" and to construct a full X11 font name",
" of the form",
"       -*-<font>-<weight>-<s>-*-*-<size>-*-*-*-*-*-<encoding>",
"",
"  <font> is the base name of the font (e.g. Times or Symbol)",
"  <size> is the point size (defaults to 12 if not specified)",
"  <s> is `i` if <slant>==\"italic\" `o` if <slant>==\"oblique\" `r` otherwise",
"  <weight> is `medium` or `bold` if explicitly requested, otherwise `*`",
"  <encoding> is set based on the current character set (see `set encoding`).",
" So `set term x11 font \"arial,15,italic\"` will be translated to",
" -*-arial-*-i-*-*-15-*-*-*-*-*-iso8859-1 (assuming default encoding).",
" The <size>, <slant>, and <weight> specifications are all optional.",
" If you do not specify <slant> or <weight> then you will get whatever font ",
" variant the font server offers first.",
" You may set a default enconding via the corresponding X11 resource. E.g.",
"       gnuplot*encoding: iso8859-15",
" The driver also recognizes some common PostScript font names and",
" replaces them with possible X11 or TrueType equivalents.",
" This same sequence is used to process font requests from `set label`.",
"",
" If your gnuplot was built with configuration option --enable-x11-mbfonts,",
" you can specify multi-byte fonts by using the prefix \"mbfont:\" on the font",
" name. An additional font may be given, separated by a semicolon.",
" Since multi-byte font encodings are interpreted according to the locale",
" setting, you must make sure that the environmental variable LC_CTYPE is set",
" to some appropriate locale value such as ja_JP.eucJP, ko_KR.EUC, or zh_CN.EUC.",
"",
" Example:",
"       set term x11 font 'mbfont:kana14;k14'",
"             # 'kana14' and 'k14' are Japanese X11 font aliases, and ';'",
"             # is the separator of font names.",
"       set term x11 font 'mbfont:fixed,16,r,medium'",
"             # <font>,<size>,<slant>,<weight> form is also usable.",
"       set title '(mb strings)' font 'mbfont:*-fixed-medium-r-normal--14-*'",
"",
" The same syntax applies to the default font in Xresources settings,",
" for example,", 
"       gnuplot*font: \\",
"           mbfont:-misc-fixed-medium-r-normal--14-*-*-*-c-*-jisx0208.1983-0",
"",
" If gnuplot is built with --enable-x11-mbfonts, you can use two special",
" PostScript font names 'Ryumin-Light-*' and 'GothicBBB-Medium-*' (standard",
" Japanese PS fonts) without the prefix \"mbfont:\".",
"", 
"2 command-line_options",
"?commands set terminal x11 command-line-options",
"?set terminal x11 command-line-options",
"?set term x11 command-line-options",
"?x11 command-line-options",
"?command-line-options",
" In addition to the X Toolkit options, the following options may be specified",
" on the command line when starting `gnuplot` or as resources in your",
" \".Xdefaults\" file (note that `raise` and `persist` can be overridden",
" later by `set term x11 [no]raise [no]persist)`:",
"@start table - first is interactive cleartext form",
"  `-mono`     forces monochrome rendering on color displays.",
"  `-gray`     requests grayscale rendering on grayscale or color displays.",
"              (Grayscale displays receive monochrome rendering by default.)",
"  `-clear`    requests that the window be cleared momentarily before a",
"              new plot is displayed.",
"  `-tvtwm`    requests that geometry specifications for position of the",
"              window be made relative to the currently displayed portion",
"              of the virtual root.",
"  `-raise`    raises plot window after each plot",
"  `-noraise`  does not raise plot window after each plot",
#ifdef USE_MOUSE
"  `-noevents` does not process mouse and key events",
"  `-ctrlq   ` closes window on ctrl-q rather than q",
#endif
"  `-persist`  plot windows survive after main gnuplot program exits",
"#\\begin{tabular}{|cl|} \\hline",
"#`-mono`     & forces monochrome rendering on color displays.\\\\",
"#`-gray`     & requests grayscale rendering on grayscale or color displays.\\\\",
"#            & (Grayscale displays receive monochrome rendering by default.) \\\\",
"#`-clear`    & requests that the window be cleared momentarily before a\\\\",
"#            & new plot is displayed. \\\\",
"#`-tvtwm`    & requests that geometry specifications for position of the\\\\",
"#            & window be made relative to the currently displayed portion\\\\",
"#            & of the virtual root. \\\\",
"#`-raise`    & raises plot window after each plot. \\\\",
"#`-noraise`  & does not raise plot window after each plot. \\\\",
#ifdef USE_MOUSE
"#`-noevents` & does not process mouse and key events. \\\\",
#endif
"#`-persist`  & plot windows survive after main gnuplot program exits. \\\\",
"%c l .",
"%`-mono`@forces monochrome rendering on color displays.",
"%`-gray`@requests grayscale rendering on grayscale or color displays.",
"%       @(Grayscale displays receive monochrome rendering by default.)",
"%`-clear`@requests that the window be cleared momentarily before a",
"%        @new plot is displayed.",
"%`-tvtwm`@requests that geometry specifications for position of the",
"%        @window be made relative to the currently displayed portion",
"%        @of the virtual root.",
"%`-raise`@raises plot window after each plot",
"%`-noraise`@does not raise plot window after each plot",
#ifdef USE_MOUSE
"%`-novevents`@does not process mouse and key events",
"%`-ctrlq`@closes window on ctrl-q rather than q",
#endif
"%`-persist`@plot windows survive after main gnuplot program exits",
"@end table",
"=X resources",
" The options are shown above in their command-line syntax.  When entered as",
" resources in \".Xdefaults\", they require a different syntax.",
"",
" Example:",
"       gnuplot*gray:  on",
"       gnuplot*ctrlq: on",
"",
" `gnuplot` also provides a command line option (`-pointsize <v>`) and a",
" resource, `gnuplot*pointsize: <v>`, to control the size of points plotted",
" with the `points` plotting style.  The value `v` is a real number (greater",
" than 0 and less than or equal to ten) used as a scaling factor for point",
" sizes.  For example, `-pointsize 2` uses points twice the default size, and",
" `-pointsize 0.5` uses points half the normal size.",
"",
" The `-noevents` switch disables all mouse and key event processing (except",
" for `q` and `<space>` for closing the window). This is useful for programs",
" which use the x11 driver independent of the gnuplot main program.",
"",
" The `-ctrlq` switch changes the hot-key that closes a plot window from `q`",
" to `<ctrl>q`. This is useful is you are using the keystroke-capture feature",
" `pause mouse keystroke`, since it allows the character `q` to be captured",
" just as all other alphanumeric characters. The `-ctrlq` switch similarly",
" replaces the <space> hot-key with <ctrl><space> for the same reason.",
"",
"2 monochrome_options",
"?commands set terminal x11 monochrome_options",
"?set terminal x11 monochrome_options",
"?set term x11 monochrome_options",
"?x11 monochrome_options",
"?monochrome_options",
"=X resources",
" For monochrome displays, `gnuplot` does not honor foreground or background",
" colors.  The default is black-on-white.  `-rv` or `gnuplot*reverseVideo: on`",
" requests white-on-black.",
"",
"2 color_resources",
"?commands set terminal x11 color_resources",
"?set terminal x11 color_resources",
"?set term x11 color_resources",
"?x11 color_resources",
"?color_resources",
"=X resources",
" The X11 terminal honors the following resources (shown here with their",
" default values) or the greyscale resources.  The values may be color names",
" as listed in the X11 rgb.txt file on your system, hexadecimal RGB color",
" specifications (see X11 documentation), or a color name followed by a comma",
" and an `intensity` value from 0 to 1.  For example, `blue, 0.5` means a half",
" intensity blue.",
"@start table - first is interactive cleartext form",
"  gnuplot*background:  white",
"  gnuplot*textColor:   black",
"  gnuplot*borderColor: black",
"  gnuplot*axisColor:   black",
"  gnuplot*line1Color:  red",
"  gnuplot*line2Color:  green",
"  gnuplot*line3Color:  blue",
"  gnuplot*line4Color:  magenta",
"  gnuplot*line5Color:  cyan",
"  gnuplot*line6Color:  sienna",
"  gnuplot*line7Color:  orange",
"  gnuplot*line8Color:  coral",
"#\\begin{tabular}{|cl|} \\hline",
"#&gnuplot*background: white\\\\",
"#&gnuplot*textColor: black\\\\",
"#&gnuplot*borderColor: black\\\\",
"#&gnuplot*axisColor: black\\\\",
"#&gnuplot*line1Color: red\\\\",
"#&gnuplot*line2Color: green\\\\",
"#&gnuplot*line3Color: blue\\\\",
"#&gnuplot*line4Color: magenta\\\\",
"#&gnuplot*line5Color: cyan\\\\",
"#&gnuplot*line6Color: sienna\\\\",
"#&gnuplot*line7Color: orange\\\\",
"#&gnuplot*line8Color: coral\\\\",
"%c l .",
"%@gnuplot*background: white",
"%@gnuplot*textColor: black",
"%@gnuplot*borderColor: black",
"%@gnuplot*axisColor: black",
"%@gnuplot*line1Color: red",
"%@gnuplot*line2Color: green",
"%@gnuplot*line3Color: blue",
"%@gnuplot*line4Color: magenta",
"%@gnuplot*line5Color: cyan",
"%@gnuplot*line6Color: sienna",
"%@gnuplot*line7Color: orange",
"%@gnuplot*line8Color: coral",
"@end table",
"",
" The command-line syntax for these is simple only for background,",
" which maps directly to the usual X11 toolkit option \"-bg\".  All",
" others can only be set on the command line by use of the generic",
" \"-xrm\" resource override option",
"",
" Examples:",
"",
"       gnuplot -background coral",
" to change the background color.",
"",
"       gnuplot -xrm 'gnuplot*line1Color:blue'",
" to override the first linetype color.",
"",
"2 grayscale_resources",
"?commands set terminal x11 grayscale_resources",
"?set terminal x11 grayscale_resources",
"?set term x11 grayscale_resources",
"?x11 grayscale_resources",
"?grayscale_resources",
"=X resources",
" When `-gray` is selected, `gnuplot` honors the following resources for",
" grayscale or color displays (shown here with their default values).  Note",
" that the default background is black.",
"@start table - first is interactive cleartext form",
"  gnuplot*background: black",
"  gnuplot*textGray:   white",
"  gnuplot*borderGray: gray50",
"  gnuplot*axisGray:   gray50",
"  gnuplot*line1Gray:  gray100",
"  gnuplot*line2Gray:  gray60",
"  gnuplot*line3Gray:  gray80",
"  gnuplot*line4Gray:  gray40",
"  gnuplot*line5Gray:  gray90",
"  gnuplot*line6Gray:  gray50",
"  gnuplot*line7Gray:  gray70",
"  gnuplot*line8Gray:  gray30",
"#\\begin{tabular}{|cl|} \\hline",
"#&gnuplot*background: black\\\\",
"#&gnuplot*textGray: white\\\\",
"#&gnuplot*borderGray: gray50\\\\",
"#&gnuplot*axisGray: gray50\\\\",
"#&gnuplot*line1Gray: gray100\\\\",
"#&gnuplot*line2Gray: gray60\\\\",
"#&gnuplot*line3Gray: gray80\\\\",
"#&gnuplot*line4Gray: gray40\\\\",
"#&gnuplot*line5Gray: gray90\\\\",
"#&gnuplot*line6Gray: gray50\\\\",
"#&gnuplot*line7Gray: gray70\\\\",
"#&gnuplot*line8Gray: gray30\\\\",
"%c l .",
"%@gnuplot*background: black",
"%@gnuplot*textGray: white",
"%@gnuplot*borderGray: gray50",
"%@gnuplot*axisGray: gray50",
"%@gnuplot*line1Gray: gray100",
"%@gnuplot*line2Gray: gray60",
"%@gnuplot*line3Gray: gray80",
"%@gnuplot*line4Gray: gray40",
"%@gnuplot*line5Gray: gray90",
"%@gnuplot*line6Gray: gray50",
"%@gnuplot*line7Gray: gray70",
"%@gnuplot*line8Gray: gray30",
"@end table",
"",
"2 line_resources",
"?commands set terminal x11 line_resources",
"?set terminal x11 line_resources",
"?set term x11 line_resources",
"?x11 line_resources",
"?line_resources",
"=X resources",
" `gnuplot` honors the following resources for setting the width (in pixels) of",
" plot lines (shown here with their default values.)  0 or 1 means a minimal",
" width line of 1 pixel width.  A value of 2 or 3 may improve the appearance of",
" some plots.",
"@start table - first is interactive cleartext form",
"  gnuplot*borderWidth: 2",
"  gnuplot*axisWidth:   0",
"  gnuplot*line1Width:  0",
"  gnuplot*line2Width:  0",
"  gnuplot*line3Width:  0",
"  gnuplot*line4Width:  0",
"  gnuplot*line5Width:  0",
"  gnuplot*line6Width:  0",
"  gnuplot*line7Width:  0",
"  gnuplot*line8Width:  0",
"#\\begin{tabular}{|cl|} \\hline",
"#&gnuplot*borderWidth: 2\\\\",
"#&gnuplot*axisWidth: 0\\\\",
"#&gnuplot*line1Width: 0\\\\",
"#&gnuplot*line2Width: 0\\\\",
"#&gnuplot*line3Width: 0\\\\",
"#&gnuplot*line4Width: 0\\\\",
"#&gnuplot*line5Width: 0\\\\",
"#&gnuplot*line6Width: 0\\\\",
"#&gnuplot*line7Width: 0\\\\",
"#&gnuplot*line8Width: 0\\\\",
"%c l .",
"%@gnuplot*borderWidth: 2",
"%@gnuplot*axisWidth: 0",
"%@gnuplot*line1Width: 0",
"%@gnuplot*line2Width: 0",
"%@gnuplot*line3Width: 0",
"%@gnuplot*line4Width: 0",
"%@gnuplot*line5Width: 0",
"%@gnuplot*line6Width: 0",
"%@gnuplot*line7Width: 0",
"%@gnuplot*line8Width: 0",
"@end table",
"",
" `gnuplot` honors the following resources for setting the dash style used for",
" plotting lines.  0 means a solid line.  A two-digit number `jk` (`j` and `k`",
" are >= 1 and <= 9) means a dashed line with a repeated pattern of `j` pixels",
" on followed by `k` pixels off.  For example, '16' is a dotted line with one",
" pixel on followed by six pixels off.  More elaborate on/off patterns can be",
" specified with a four-digit value.  For example, '4441' is four on, four off,",
" four on, one off.  The default values shown below are for monochrome displays",
" or monochrome rendering on color or grayscale displays.",
" Color displays default to dashed:off ",
"@start table - first is interactive cleartext form",
"  gnuplot*dashed:       off",
"  gnuplot*borderDashes:   0",
"  gnuplot*axisDashes:    16",
"  gnuplot*line1Dashes:    0",
"  gnuplot*line2Dashes:   42",
"  gnuplot*line3Dashes:   13",
"  gnuplot*line4Dashes:   44",
"  gnuplot*line5Dashes:   15",
"  gnuplot*line6Dashes: 4441",
"  gnuplot*line7Dashes:   42",
"  gnuplot*line8Dashes:   13",
"#\\begin{tabular}{|cl|} \\hline",
"#&gnuplot*dashed: off\\\\",
"#&gnuplot*borderDashes: 0\\\\",
"#&gnuplot*axisDashes: 16\\\\",
"#&gnuplot*line1Dashes: 0\\\\",
"#&gnuplot*line2Dashes: 42\\\\",
"#&gnuplot*line3Dashes: 13\\\\",
"#&gnuplot*line4Dashes: 44\\\\",
"#&gnuplot*line5Dashes: 15\\\\",
"#&gnuplot*line6Dashes: 4441\\\\",
"#&gnuplot*line7Dashes: 42\\\\",
"#&gnuplot*line8Dashes: 13\\\\",
"%c l .",
"%@gnuplot*dashed: off",
"%@gnuplot*borderDashes: 0",
"%@gnuplot*axisDashes: 16",
"%@gnuplot*line1Dashes: 0",
"%@gnuplot*line2Dashes: 42",
"%@gnuplot*line3Dashes: 13",
"%@gnuplot*line4Dashes: 44",
"%@gnuplot*line5Dashes: 15",
"%@gnuplot*line6Dashes: 4441",
"%@gnuplot*line7Dashes: 42",
"%@gnuplot*line8Dashes: 13",
"@end table"
, "",
"2 x11 pm3d_resources",
"?commands set terminal x11 pm3d_resources",
"?set terminal x11 pm3d_resources",
"?set term x11 pm3d_resources",
"?x11 pm3d_resources",
"?pm3d_resources",
"?x11 pm3d",
"=X resources",
" Choosing the appropriate visual class and number of colors is a crucial",
" point in X11 applications and a bit awkward, since X11 supports six visual",
" types in different depths.",
"",
" By default `gnuplot` uses the default visual of the screen. The number of",
" colors which can be allocated depends on the visual class chosen. On a",
" visual class with a depth > 12bit, gnuplot starts with a maximal number",
" of 0x200 colors.  On a visual class with a depth > 8bit (but <= 12 bit)",
" the maximal number of colors is 0x100, on <= 8bit displays the maximum",
" number of colors is 240 (16 are left for line colors).",
"",
" Gnuplot first starts to allocate the maximal number of colors as stated",
" above.  If this fails, the number of colors is reduced by the factor 2",
" until gnuplot gets all colors which are requested. If dividing `maxcolors`",
" by 2 repeatedly results in a number which is smaller than `mincolors`",
" `gnuplot` tries to install a private colormap. In this case the window",
" manager is responsible for swapping colormaps when the pointer is moved",
" in and out the x11 driver's window.",
"",
" The default for `mincolors` is maxcolors / (num_colormaps > 1 ? 2 : 8),",
" where num_colormaps is the number of colormaps which are currently used",
" by gnuplot (usually 1, if only one x11 window is open).",
"",
" Some systems support multiple (different) visual classes together on one",
" screen. On these systems it might be necessary to force gnuplot to use a",
" specific visual class, e.g. the default visual might be 8bit PseudoColor",
" but the screen would also support 24bit TrueColor which would be the",
" preferred choice.",
"",
" The information about an Xserver's capabilities can be obtained with the",
" program `xdpyinfo`.  For the visual names below you can choose one of",
" StaticGray, GrayScale, StaticColor, PseudoColor, TrueColor, DirectColor.",
" If an Xserver supports a requested visual type at different depths,",
" `gnuplot` chooses the visual class with the highest depth (deepest).",
" If the requested visual class matches the default visual and multiple",
" classes of this type are supported, the default visual is preferred.",
"",
" Example: on an 8bit PseudoColor visual you can force a private color map",
" by specifying `gnuplot*maxcolors: 240` and `gnuplot*mincolors: 240`.",
"",
"@start table - first is interactive cleartext form",
"  gnuplot*maxcolors:  <integer>",
"  gnuplot*mincolors:  <integer>",
"  gnuplot*visual:     <visual name>",
"#\\begin{tabular}{|cl|} \\hline",
"#&gnuplot*maxcolors:  integer\\\\",
"#&gnuplot*mincolors:  integer\\\\",
"#&gnuplot*visual:     visual name\\\\",
"%c l .",
"%@gnuplot*maxcolors:  <integer number>",
"%@gnuplot*mincolors:  <integer number>",
"%@gnuplot*visual:     <visual name>",
"@end table"
, "",
"2 x11 other_resources",
"?commands set terminal x11 other_resources",
"?set terminal x11 other_resources",
"?set term x11 other_resources",
"?x11 other_resources",
"=X resources",
" By default the contents of the current plot window are exported to the X11",
" clipboard in response to X events in the window. Setting the resource",
" 'gnuplot*exportselection' to 'off' or 'false' will disable this.",
"",
" By default text rotation is done using a method that is fast, but can",
" corrupt nearby colors depending on the background.  If this is a problem,",
" you can set the resource 'gnuplot.fastrotate' to 'off'",
"",
"@start table - other x11 resources",
"  gnuplot*exportselection:  off",
"  gnuplot*fastrotate:  on",
"  gnuplot*ctrlq:  off",
"#\\begin{tabular}{|cl|} \\hline",
"#&gnuplot*exportselection:  off\\\\",
"#&gnuplot*fastrotate:  on\\\\",
"#&gnuplot*ctrlq:  off\\\\",
"%c l .",
"%@gnuplot*exportselection:  off",
"%@gnuplot*fastrotate:  on",
"%@gnuplot*ctrlq:  off",
"@end table"

END_HELP(x11)
#endif				/* TERM_HELP */
