/*
* $Id: ggi.trm,v 1.15 2002/07/10 19:46:16 mikulik Exp $
*/
/* GNUPLOT - ggi.trm */
/*[
* Copyright 2000
*
* 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.
]*/
/*
* AUTHOR:
* Cesar Crusius <crusius@leland.stanford.edu>
* event / mouse processing & double-buffering
* by Johannes Zellner <johannes@zellner.org>
* pm3d support by Johannes Zellner <johannes@zellner.org> (Oct. 2000)
*
* TODO:
*
* - reimplement wmh (if it's available)
* - implement window title using wmh (if it's available)
* - check for availability of two frames, and if not
* do it with one frame. (will eventually not do
* with mouse/event reporting)
* - check if libxmi is available and if so, use
* it to draw filled polygons.
* - enable cursors using blits.
*/
#include "driver.h"
#ifdef TERM_REGISTER
register_term(ggi)
#endif
#ifdef TERM_PROTO
#include <ggi/ggi.h>
#ifdef USE_MOUSE
# include <ggi/ggi-unix.h>
#endif
#ifdef HAVE_GGI_WMH_H
# include <ggi/wmh.h>
static TBOOLEAN GGI_use_whm = 0;
#endif
#if 1
#if defined(PM3D) && defined(HAVE_GGI_XMI_H)
# define ENABLE_XMI 1
#endif
#endif
#ifdef ENABLE_XMI
# include <ggi/xmi.h>
#endif
static void GGI_line_colors __PROTO((void));
TERM_PUBLIC void GGI_graphics __PROTO((void));
TERM_PUBLIC void GGI_set_size __PROTO((void));
TERM_PUBLIC void GGI_init __PROTO((void));
TERM_PUBLIC void GGI_linetype __PROTO((int));
TERM_PUBLIC void GGI_move __PROTO((unsigned int,unsigned int));
TERM_PUBLIC void GGI_options __PROTO((void));
TERM_PUBLIC void GGI_put_text __PROTO((unsigned int,unsigned int, const char*));
TERM_PUBLIC void GGI_suspend __PROTO((void));
TERM_PUBLIC void GGI_resume __PROTO((void));
TERM_PUBLIC void GGI_fillbox __PROTO((int style, unsigned int x, unsigned int y,
unsigned int w, unsigned int h));
TERM_PUBLIC void GGI_close __PROTO((void));
TERM_PUBLIC void GGI_reset __PROTO((void));
TERM_PUBLIC void GGI_text __PROTO((void));
TERM_PUBLIC void GGI_vector __PROTO((unsigned int,unsigned int));
#ifdef USE_MOUSE
/* zoom box information */
typedef struct {
int x;
int y;
} GGI_point_t;
typedef struct {
int x;
int y;
int width;
int height;
char str[0xff];
} GGI_vertex_t;
TERM_PUBLIC long int GGI_SetTime(const struct timeval* current);
TERM_PUBLIC int GGI_from_keysym __PROTO((uint32 keysym));
TERM_PUBLIC int GGI_from_button __PROTO((uint32 button));
TERM_PUBLIC int GGI_y __PROTO((sint32 y));
TERM_PUBLIC int GGI_dispatch_event __PROTO((const ggi_event* event));
TERM_PUBLIC int GGI_eventually_update_modifiers __PROTO((const ggi_event* event, const int add));
TERM_PUBLIC int GGI_waitforinput __PROTO((void));
TERM_PUBLIC void GGI_draw_ruler __PROTO((void));
TERM_PUBLIC void GGI_clear_zoombox __PROTO((void));
TERM_PUBLIC void GGI_draw_zoombox __PROTO((void));
TERM_PUBLIC void GGI_set_ruler __PROTO((int, int));
TERM_PUBLIC void GGI_set_cursor __PROTO((int, int, int));
TERM_PUBLIC void GGI_save_frame_canvas __PROTO((void));
TERM_PUBLIC void GGI_save_frame_stl __PROTO((void));
TERM_PUBLIC void GGI_replot __PROTO((void));
TERM_PUBLIC void GGI_clear __PROTO((const GGI_vertex_t* v, const int tag));
TERM_PUBLIC void GGI_save_puts __PROTO((GGI_vertex_t* v, const int tag));
TERM_PUBLIC void GGI_set_vertex __PROTO((GGI_vertex_t* v, const int x, const int y, const char* str, const int tag));
TERM_PUBLIC void GGI_abort_zooming __PROTO((void));
TERM_PUBLIC void GGI_put_tmptext __PROTO((int, const char str[]));
TERM_PUBLIC void GGI_relative __PROTO((int r[2]));
TERM_PUBLIC void GGI_clear_hline __PROTO((int x1, int x2, int y));
TERM_PUBLIC void GGI_clear_vline __PROTO((int y1, int y2, int x));
TERM_PUBLIC void GGI_draw_hline __PROTO((int x1, int x2, int y));
TERM_PUBLIC void GGI_draw_vline __PROTO((int y1, int y2, int x));
TERM_PUBLIC void GGI_set_clipboard __PROTO((const char[]));
#endif /* USE_MOUSE */
#ifdef PM3D
TERM_PUBLIC int GGI_make_palette __PROTO((t_sm_palette*));
TERM_PUBLIC void GGI_previous_palette __PROTO((void));
TERM_PUBLIC void GGI_set_color __PROTO((double));
#ifdef ENABLE_XMI
TERM_PUBLIC void GGI_filled_polygon __PROTO((int, gpiPoint*));
#endif
#endif
#define GOT_GGI_PROTO
#endif
#ifndef TERM_PROTO_ONLY
#ifdef TERM_BODY
#define GGI_XMAX 800
#define GGI_YMAX 600
#define GGI_VCHAR 8
#define GGI_HCHAR 8
#define GGI_VTIC 8
#define GGI_HTIC 8
#ifdef USE_MOUSE
static GGI_vertex_t GGI_zoom[2][2];
static GGI_vertex_t GGI_stl_vertex;
static GGI_point_t GGI_ruler = {-1, -1};
static GGI_point_t GGI_zoombox[2] = {{-1, -1}, {-1, -1}};
static struct timeval GGI_timestamp;
static int GGI_mouse_x = 0;
static int GGI_mouse_y = 0;
static int GGI_modifiers = 0;
static int GGI_use_mouse = 1; /* mouse is on by default */
static unsigned int GGIcanvas_height = 0;
static int GGI_font_width = 0;
static int GGI_font_height = 0;
static int GGI_saved_canvas = 0;
static int GGI_saved_stl = 0;
static int GGI_needs_update = 1;
#endif
#ifdef PM3D
static t_sm_palette GGI_save_pal = {
-1, -1, -1, -1, -1, -1, -1, -1,
(rgb_color*) 0, -1, -1
};
#endif
/* First to some global variables
*
* GGIvisual is our 'piece of paper.'
* GGIborderColor and axixColor have the obvious meanings.
* GGIcolors are the colors for linestyles 0 and up.
* GGImap is for initializing colors.
* GGIx,GGIy are the current coordinates.
* GGIwidth, GGIheight are the extensions in the visual.
* GGIymax = term->ymax
*/
static ggi_visual_t GGIvisual = (ggi_visual_t)0;
static ggi_pixel GGIborderColor;
static ggi_pixel GGIaxisColor;
static ggi_pixel GGIblack;
static ggi_pixel GGIcolors[7];
#ifdef PM3D
#define GGI_PM3D_COLORS 240
static const int ggi_pm3d_colors = GGI_PM3D_COLORS;
static ggi_pixel GGI_smooth_colors[GGI_PM3D_COLORS];
#endif
static unsigned int GGIx,GGIy;
static unsigned int GGIwidth, GGIheight, GGIymax;
#if 0
static unsigned int Xenv;
#endif
static int GGI_frames =
#ifdef USE_MOUSE
2
#else
1
#endif
;
#ifdef ENABLE_XMI
static miGC* GGI_miGC = (miGC*)0;
static miPaintedSet* GGI_miPaintedSet = (miPaintedSet*)0;
static miPixel GGI_miPixels[2]; /* only GGI_miPixels[1] is used */
static int GGI_numblendstages = 0;
static miBlendStage GGI_blendstages[4];
#endif
static TBOOLEAN GGI_mode_changed = 1;
static char GGI_mode_spec[0xff] = "";
static int GGI_acceleration = 7; /* arbitrary */
enum GGI_id {
GGI_MODE,
GGI_ACCELERATION,
GGI_OTHER
};
static struct gen_table GGI_opts[] =
{
{ "mo$de", GGI_MODE },
{ "ac$celeration", GGI_ACCELERATION },
{ NULL, GGI_OTHER }
};
static void
GGI_line_colors()
{
ggi_pixel GGIwhite,GGIred,GGIgreen,GGIblue,GGIcyan,GGImagenta,GGIgray;
ggi_pixel GGIyellow;
ggi_color color;
color.r = 0xFFFF; color.g = 0xFFFF; color.b = 0xFFFF; GGIwhite = ggiMapColor(GGIvisual,&color);
color.r = 0x0000; color.g = 0x0000; color.b = 0x0000; GGIblack = ggiMapColor(GGIvisual,&color);
color.r = 0xFFFF; color.g = 0x0000; color.b = 0x0000; GGIred = ggiMapColor(GGIvisual,&color);
color.r = 0x0000; color.g = 0xFFFF; color.b = 0x0000; GGIgreen = ggiMapColor(GGIvisual,&color);
color.r = 0x0000; color.g = 0x0000; color.b = 0xFFFF; GGIblue = ggiMapColor(GGIvisual,&color);
color.r = 0x0000; color.g = 0xFFFF; color.b = 0xFFFF; GGIcyan = ggiMapColor(GGIvisual,&color);
color.r = 0xFFFF; color.g = 0x0000; color.b = 0xFFFF; GGImagenta = ggiMapColor(GGIvisual,&color);
color.r = 0xFFFF; color.g = 0xFFFF; color.b = 0x0000; GGIyellow = ggiMapColor(GGIvisual,&color);
color.r = 0x8888; color.g = 0x8888; color.b = 0x8888; GGIgray = ggiMapColor(GGIvisual,&color);
GGIborderColor = GGIwhite;
GGIaxisColor = GGIgray;
GGIcolors[0] = GGIred;
GGIcolors[1] = GGIgreen;
GGIcolors[2] = GGIblue;
GGIcolors[3] = GGImagenta;
GGIcolors[4] = GGIcyan;
GGIcolors[5] = GGIyellow;
GGIcolors[6] = GGIgray;
}
/* Called bevore a graphic is displayed */
TERM_PUBLIC void GGI_graphics()
{
#ifdef USE_MOUSE
int i, j;
int display_frame = ggiGetDisplayFrame(GGIvisual);
#endif
#if 0
if(!Xenv)
{
GGI_line_colors();
return;
}
#endif
ggiSetGCForeground(GGIvisual,GGIblack);
#ifdef USE_MOUSE
/* write to the currently not displayed buffer */
ggiSetWriteFrame(GGIvisual, !display_frame);
/* mark the contents of the alternate frame as invalid */
GGI_saved_canvas = 0;
GGI_saved_stl = 0;
GGI_needs_update = 1;
/* reset the stl vertex */
GGI_stl_vertex.width = 0;
/* reset the zoom box coordinates */
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
GGI_zoom[i][j].width = 0;
}
GGI_zoombox[i].x = -1;
GGI_zoombox[i].y = -1;
}
#endif /* USE_MOUSE */
/* clear *write* buffer. */
ggiDrawBox(GGIvisual, 0, 0, GGIwidth, GGIheight);
#ifdef USE_MOUSE
if (GGI_use_mouse) {
/* copy the contents of the currently
* displayed stl to the write frame.
* This way the stl won't jitter. */
ggiSetReadFrame(GGIvisual, display_frame);
ggiCopyBox(GGIvisual, 0, GGIcanvas_height,
GGIwidth, GGI_font_height, 0, GGIcanvas_height);
}
#endif
}
TERM_PUBLIC void
GGI_set_size(void)
{
ggi_mode mode;
ggiGetMode(GGIvisual,&mode);
GGIwidth = mode.virt.x;
GGIheight = mode.virt.y;
term->xmax = mode.virt.x - 1;
#ifdef USE_MOUSE
GGIcanvas_height = mode.virt.y - (GGI_use_mouse ? GGI_font_height : 0);
term->ymax = GGIcanvas_height - 1;
#else
term->ymax = mode.virt.y - 1;
#endif
GGIymax = term->ymax;
}
/*
* init
* -----------------------
* Called only once, when the terminal is initialized. We have to open the visual here because it
* is during 'init' that we have to change the terminal dimensions (xmax, ymax).
*/
TERM_PUBLIC void GGI_init()
{
int success = 0;
ggi_mode mode;
#if 0
if (0 != giiInit()) {
ggiPanic("*** giiInit() failed *** \n");
}
#endif
if (0 != ggiInit()) {
ggiPanic("*** ggiInit() failed *** \n");
}
if (NULL == (GGIvisual = ggiOpen(NULL))) {
/* TODO: abort a bit more gracefully */
ggiPanic("(GGI_init() unable to open default\n");
}
if (strlen(GGI_mode_spec)) {
/* user specified mode */
if (!ggiParseMode(GGI_mode_spec, &mode)) {
mode.frames = GGI_frames;
if (!ggiSetMode(GGIvisual, &mode)) {
success = 1;
}
}
}
if (!success) {
/* try the default mode */
if(ggiSetSimpleMode(GGIvisual,GGI_AUTO,GGI_AUTO,GGI_frames,GT_AUTO)) {
ggiPanic("(GGI_init() unable to set default mode\n");
GGIvisual = (ggi_visual_t)0;
}
}
ggiGetMode(GGIvisual, &mode);
/* print the mode only once if it has changed */
if (GGI_mode_changed) {
GGI_mode_changed = 0;
ggiFPrintMode(stderr, &mode);
fprintf(stderr, "\n");
}
#ifdef USE_MOUSE
/* must come before GGI_set_size() */
ggiGetCharSize(GGIvisual, &GGI_font_width, &GGI_font_height);
#endif
GGI_set_size();
#ifdef USE_MOUSE
ggiSetReadFrame(GGIvisual, 0);
ggiSetWriteFrame(GGIvisual, 0);
ggiSetDisplayFrame(GGIvisual, 0);
#endif
#ifdef HAVE_GGI_WMH_H
/* Initialize WMH extension */
if (ggiWmhInit() != 0 || ggiWmhAttach(GGIvisual) < 0) {
GGI_use_whm = 0;
} else {
GGI_use_whm = 1;
ggiWmhAllowResize(GGIvisual, 100, 50, 2000, 2000, 10, 10);
ggiWmhSetTitle(GGIvisual, "GGI Gnuplot Driver");
ggiWmhSetIconTitle(GGIvisual, "Gnuplot");
}
#endif
/*
* if(!(Xenv=!ggiWmhAttach(GGIvisual))) ggiWmhDetach(GGIvisual);
* else Xenv=!ggiWmhSetTitle(GGIvisual,"GGI Gnuplot Driver");
*/
#if 0
if(!Xenv)
{
/*
* ggiWmhDetach(GGIvisual);
* ggiWmhExit();
*/
ggiClose(GGIvisual);
ggiExit();
GGIvisual=NULL;
}
#endif
GGI_line_colors();
ggiSetFlags(GGIvisual, GGIFLAG_ASYNC);
#ifdef USE_MOUSE
GGI_mouse_x = 0;
GGI_mouse_y = 0;
GGI_modifiers = 0;
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
GGI_SetTime(&tv); /* initialize time */
}
#endif
#ifdef ENABLE_XMI
if (0 != xmiInit()) {
/* TODO: abort a bit more gracefully */
ggiPanic("(GGI_init() unable to initialize xmi\n");
}
if (xmiAttach(GGIvisual) < 0) {
ggiPanic("(GGI_init) Unable to attach XMI extension to visual\n");
}
/* miPaintedSet */
if (GGI_miPaintedSet) {
miDeletePaintedSet(GGIvisual, GGI_miPaintedSet);
GGI_miPaintedSet = (miPaintedSet*)0;
}
GGI_miPaintedSet = miNewPaintedSet(GGIvisual);
miClearPaintedSet(GGIvisual, GGI_miPaintedSet);
/* miGC */
if (GGI_miGC) {
miDeleteGC(GGIvisual, GGI_miGC);
GGI_miGC = (miGC*)0;
}
GGI_miGC = miNewGC(GGIvisual, 2,
GGI_miPixels, GGI_numblendstages, GGI_blendstages);
#endif
setvbuf(stdin, (char*)0, _IONBF, 0);
}
TERM_PUBLIC void GGI_linetype(linetype)
int linetype;
{
if(linetype==-2) ggiSetGCForeground(GGIvisual,GGIborderColor);
if(linetype==-1) ggiSetGCForeground(GGIvisual,GGIaxisColor);
if(linetype<0) return;
if(linetype>=6) linetype%=6;
ggiSetGCForeground(GGIvisual,GGIcolors[linetype]);
}
TERM_PUBLIC void GGI_move(x,y)
unsigned int x,y;
{
GGIx=x;
GGIy=GGI_y(y);
}
TERM_PUBLIC void
GGI_options()
{
while (!END_OF_COMMAND) {
switch(lookup_table(&GGI_opts[0], c_token)) {
case GGI_ACCELERATION:
{
int itmp;
struct value a;
c_token++;
itmp = (int) real(const_express(&a));
if (itmp < 1) {
fprintf(stderr, "acceleration must be strictly positive!\n");
} else {
GGI_acceleration = itmp;
}
}
break;
case GGI_MODE:
/* fallthru */
c_token++;
default:
if (!END_OF_COMMAND) {
copy_str(GGI_mode_spec, c_token, 0xfe);
GGI_mode_changed = 1;
}
break;
}
c_token++;
}
if (*GGI_mode_spec) {
sprintf(term_options, "mode %s acceleration %d",
GGI_mode_spec, GGI_acceleration);
} else {
sprintf(term_options, "acceleration %d", GGI_acceleration);
}
}
TERM_PUBLIC void
GGI_close()
{
ggiFlush(GGIvisual);
/* DETACH EXTENSIONS */
#if HAVE_WMH_H
if(GGI_use_whm) {
ggiWmhDetach(GGIvisual);
}
#endif
#ifdef ENABLE_XMI
xmiDetach(GGIvisual);
#endif
ggiClose(GGIvisual);
GGIvisual = (ggi_visual_t)0;
/* EXIT EXTENSIONS */
#if HAVE_WMH_H
if(GGI_use_whm) {
ggiWmhExit();
GGI_use_whm = 0;
}
#endif
#ifdef ENABLE_XMI
xmiExit();
#endif
}
/* Called when terminal is terminated i.e.
* when switching to another terminal. */
TERM_PUBLIC void
GGI_reset()
{
if(GGIvisual!=NULL) {
GGI_close();
}
#ifdef PM3D
/* not needed */
#if 0
GGI_save_pal.colorFormulae = -1; /* force later reallocation of palette */
#endif
#endif
}
TERM_PUBLIC void GGI_put_text(x,y,str)
unsigned int x,y;
const char *str;
{
ggi_pixel current_foreground;
ggiGetGCForeground(GGIvisual,¤t_foreground);
ggiSetGCForeground(GGIvisual,GGIborderColor);
ggiPuts(GGIvisual,x,GGI_y(y) - 4 /* ? (joze ? */,str);
ggiSetGCForeground(GGIvisual,current_foreground);
}
TERM_PUBLIC void
GGI_suspend()
{
/* this fails on the console */
GGI_text();
}
TERM_PUBLIC void
GGI_resume()
{
/* do nothing */
}
TERM_PUBLIC void
GGI_fillbox(style, x, y, w, h)
int style;
unsigned int x, y, w, h;
{
/* when is this called ? */
/* ULIG: the style parameter is now used for the fillboxes style
* (not implemented here), see the documentation */
#if 0
fprintf(stderr, "(GGI_fillbox) style, x, y, w, y = %d, %d, %d, %d, %d\n",
style, x, y, w, h);
#endif
}
TERM_PUBLIC void
GGI_text()
{
ggiFlush(GGIvisual);
#ifdef USE_MOUSE
/* now display the buffer which was just written */
ggiSetDisplayFrame(GGIvisual, ggiGetWriteFrame(GGIvisual));
return;
#else
/* Wait for a key to be pressed and exit graphics mode if
* running in console mode. */
/* TODO: return immediately, if in X */
ggiGetc(GGIvisual);
GGI_close();
#endif
}
TERM_PUBLIC void GGI_vector(x,y)
unsigned int x,y;
{
y = GGI_y(y);
ggiDrawLine(GGIvisual,GGIx,GGIy,x,y);
GGIx=x;
GGIy=y;
}
#ifdef USE_MOUSE
/* tranlate ggi keysym to gnuplot keysym */
TERM_PUBLIC int
GGI_from_keysym(keysym)
uint32 keysym;
{
switch (keysym) {
case GIIUC_BackSpace:
return GP_BackSpace;
case GIIUC_Tab:
return GP_Tab;
case GIIUC_Linefeed:
return GP_Linefeed;
case GIIK_Clear:
return GP_Clear;
case GIIUC_Return:
return GP_Return;
case GIIK_Pause:
return GP_Pause;
case GIIK_ScrollLock:
return GP_Scroll_Lock;
case GIIK_SysRq:
return GP_Sys_Req;
case GIIUC_Escape:
return GP_Escape;
case GIIK_Insert:
return GP_Insert;
case GIIUC_Delete:
return GP_Delete;
case GIIK_Home:
return GP_Home;
case GIIK_Left:
return GP_Left;
case GIIK_Up:
return GP_Up;
case GIIK_Right:
return GP_Right;
case GIIK_Down:
return GP_Down;
case GIIK_PageUp:
return GP_PageUp;
case GIIK_PageDown:
return GP_PageDown;
case GIIK_End:
return GP_End;
case GIIK_Begin:
return GP_Begin;
case GIIK_PSpace:
return GP_KP_Space;
case GIIK_PTab:
return GP_KP_Tab;
case GIIK_PEnter:
return GP_KP_Enter;
case GIIK_PF1:
return GP_KP_F1;
case GIIK_PF2:
return GP_KP_F2;
case GIIK_PF3:
return GP_KP_F3;
case GIIK_PF4:
return GP_KP_F4;
#if 0
case 1:
return GP_KP_Insert; /* ~ KP_0 */
case 1:
return GP_KP_End; /* ~ KP_1 */
case 1:
return GP_KP_Down; /* ~ KP_2 */
case 1:
return GP_KP_Page_Down; /* ~ KP_3 */
case 1:
return GP_KP_Left; /* ~ KP_4 */
case 1:
return GP_KP_Begin; /* ~ KP_5 */
case 1:
return GP_KP_Right; /* ~ KP_6 */
case 1:
return GP_KP_Home; /* ~ KP_7 */
case 1:
return GP_KP_Up; /* ~ KP_8 */
case 1:
return GP_KP_Page_Up; /* ~ KP_9 */
#endif
#if 0
case GIIK_PDelete:
return GP_KP_Delete;
#endif
case GIIK_PEqual:
return GP_KP_Equal;
case GIIK_PAsterisk:
return GP_KP_Multiply;
case GIIK_PPlus:
return GP_KP_Add;
case GIIK_PSeparator:
return GP_KP_Separator;
case GIIK_PMinus:
return GP_KP_Subtract;
case GIIK_PDecimal:
return GP_KP_Decimal;
case GIIK_PSlash:
return GP_KP_Divide;
case GIIK_P0:
return GP_KP_0;
case GIIK_P1:
return GP_KP_1;
case GIIK_P2:
return GP_KP_2;
case GIIK_P3:
return GP_KP_3;
case GIIK_P4:
return GP_KP_4;
case GIIK_P5:
return GP_KP_5;
case GIIK_P6:
return GP_KP_6;
case GIIK_P7:
return GP_KP_7;
case GIIK_P8:
return GP_KP_8;
case GIIK_P9:
return GP_KP_9;
case GIIK_F1:
return GP_F1;
case GIIK_F2:
return GP_F2;
case GIIK_F3:
return GP_F3;
case GIIK_F4:
return GP_F4;
case GIIK_F5:
return GP_F5;
case GIIK_F6:
return GP_F6;
case GIIK_F7:
return GP_F7;
case GIIK_F8:
return GP_F8;
case GIIK_F9:
return GP_F9;
case GIIK_F10:
return GP_F10;
case GIIK_F11:
return GP_F11;
case GIIK_F12:
return GP_F12;
default:
/* return it untranslated */
return keysym;
}
}
TERM_PUBLIC long int
GGI_SetTime(current)
const struct timeval* current;
{
/* --> dsec in musec */
int dsec = (current->tv_sec - GGI_timestamp.tv_sec) * 1000000;
/* --> dmu in millisec */
int dmu = (current->tv_usec - GGI_timestamp.tv_usec + dsec) / 1000;
GGI_timestamp = *current;
return dmu;
}
TERM_PUBLIC int
GGI_from_button(button)
uint32 button;
{
switch (button) {
case GII_PBUTTON_LEFT:
return 1;
case GII_PBUTTON_MIDDLE:
return 2;
case GII_PBUTTON_RIGHT:
return 3;
default:
/* should not happen */
return 0;
}
}
TERM_PUBLIC int
GGI_y(y)
sint32 y;
{
return GGIymax - y;
}
TERM_PUBLIC int
GGI_eventually_update_modifiers(event, add)
const ggi_event* event;
const int add;
{
int mod = 0;
int old_modifiers = GGI_modifiers;
switch (event->key.sym) {
case GIIK_Shift:
mod = Mod_Shift;
break;
case GIIK_Ctrl:
mod = Mod_Ctrl;
break;
case GIIK_Alt:
case GIIK_Meta:
mod = Mod_Alt;
break;
default:
return 0;
}
if (add) {
GGI_modifiers |= mod;
} else {
GGI_modifiers &= ~mod;
}
if (GGI_modifiers != old_modifiers) {
struct gp_event_t gp_ev;
gp_ev.type = GE_modifier;
gp_ev.mx = GGI_mouse_x;
gp_ev.my = GGI_y(GGI_mouse_y);
gp_ev.par1 = 0;
gp_ev.par2 = 0;
gp_ev.par1 = GGI_modifiers;
do_event(&gp_ev);
}
return 1;
}
TERM_PUBLIC int
GGI_dispatch_event(event)
const ggi_event* event;
{
struct gp_event_t gp_ev;
gp_ev.type = 0;
gp_ev.mx = GGI_mouse_x;
gp_ev.my = GGI_y(GGI_mouse_y);
gp_ev.par1 = 0;
gp_ev.par2 = 0;
switch (event->any.type) {
/* [-- KEY EVENTS --] */
case evKeyPress:
case evKeyRepeat:
if (GGI_eventually_update_modifiers(event, 1)) {
/* was just a modifier pressed */
return 0;
}
gp_ev.type = GE_keypress;
gp_ev.par1 = GGI_from_keysym(event->key.sym);
if ('q' == gp_ev.par1) {
return 'q';
}
break;
case evKeyRelease:
if (GGI_eventually_update_modifiers(event, 0)) {
/* was just a modifier pressed */
return 0;
}
break;
/* [-- POINTER EVENTS --] */
case evPtrRelative:
/* relative motion is not implemented. Should it ? */
/*
* fprintf(stderr, "%s:%d report this to <johannes@zellner.org> %d %d\n",
* __FILE__, __LINE__, event->pmove.x, event->pmove.y);
*/
gp_ev.type = GE_motion;
GGI_mouse_x += GGI_acceleration * event->pmove.x;
GGI_mouse_y += GGI_acceleration * event->pmove.y;
break;
case evPtrAbsolute:
gp_ev.type = GE_motion;
GGI_mouse_x = event->pmove.x;
GGI_mouse_y = event->pmove.y;
break;
case evPtrButtonPress:
gp_ev.type = GE_buttonpress;
gp_ev.par1 = GGI_from_button(event->pbutton.button);
break;
case evPtrButtonRelease:
gp_ev.type = GE_buttonrelease;
gp_ev.par1 = GGI_from_button(event->pbutton.button);
gp_ev.par2 = GGI_SetTime(&(event->pbutton.time));
break;
#ifdef HAVE_GGI_WMH_H
case evCommand:
/* [-- resizing --] */
if (GGI_use_whm) {
/* fprintf(stderr, "(GGI_dispatch_event) \n"); */
if (event->cmd.code==GGICMD_REQUEST_SWITCH) {
/*
* ggi_cmddata_switchrequest *req;
* req = &(event->cmd.data);
* ggi_resize(GGIvisual, &(req->mode));
*/
/*
* while( ggiEventPoll(GGIvisual, emAll, &tv) ) {
* ggiEventRead(GGIvisual, event, emAll);
* }
*/
}
}
break;
#endif
default:
/* fprintf(stderr, "(GGI_dispatch_event) unhandled event\n"); */
break;
}
do_event(&gp_ev);
gp_ev.type = GE_plotdone;
do_event(&gp_ev);
return 0;
}
/* save currently displayed frame to alternate buffer */
TERM_PUBLIC void
GGI_save_frame_canvas()
{
if (!GGI_saved_canvas && GGIvisual) {
int display_frame = ggiGetDisplayFrame(GGIvisual);
/* save the currently displayed frame to alternate frame */
ggiSetReadFrame(GGIvisual, display_frame);
ggiSetWriteFrame(GGIvisual, !display_frame);
ggiCopyBox(GGIvisual, 0, 0, GGIwidth, GGIcanvas_height, 0, 0);
/* write again directly to the display frame */
ggiSetWriteFrame(GGIvisual, display_frame);
/* remember that the alternate frame is valid */
GGI_saved_canvas = 1;
}
}
TERM_PUBLIC void
GGI_save_frame_stl()
{
if (!GGI_saved_stl) {
int display_frame = ggiGetDisplayFrame(GGIvisual);
/* clear the stl part of the alternate buffer */
ggiSetGCForeground(GGIvisual, GGIblack);
ggiSetWriteFrame(GGIvisual, !display_frame);
ggiDrawBox(GGIvisual, 0, GGIcanvas_height, GGIwidth, GGI_font_height);
ggiSetWriteFrame(GGIvisual, display_frame);
/* clear the currently displayed area, which is left
* from a previous plot (see above, where the stl of
* the previous plot is copied to the current frame) */
ggiSetReadFrame(GGIvisual, !display_frame);
ggiCopyBox(GGIvisual, 0, GGIcanvas_height,
GGIwidth, GGI_font_height, 0, GGIcanvas_height);
GGI_saved_stl = 1;
}
}
TERM_PUBLIC void
GGI_replot()
{
struct gp_event_t ev = {
GE_cmd,
0, 0, 0, 0,
"replot"
};
do_event(&ev);
}
TERM_PUBLIC void
GGI_clear(v, tag)
const GGI_vertex_t* v;
const int tag;
{
if (tag && v->width) {
/* turn off current */
ggiSetReadFrame(GGIvisual, !ggiGetDisplayFrame(GGIvisual));
ggiCopyBox(GGIvisual, v->x, v->y, v->width, v->height, v->x, v->y);
}
}
TERM_PUBLIC void
GGI_save_puts(v, tag)
GGI_vertex_t* v;
const int tag;
{
GGI_clear(v, tag);
if (v->width) {
/* draw the text in the axis color (gray) */
ggiSetGCForeground(GGIvisual, GGIaxisColor);
/* write the string directly to the display */
ggiPuts(GGIvisual, v->x, v->y, v->str);
}
}
TERM_PUBLIC void
GGI_set_vertex(v, x, y, str, tag)
GGI_vertex_t* v;
const int x;
const int y;
const char* str;
const int tag;
{
GGI_clear(v, tag);
v->x = x;
v->y = y;
v->height = GGI_font_height;
if (str && *str) {
v->width = strlen(str) * GGI_font_width;
strcpy(v->str, str);
} else {
/* turn string off */
v->width = 0;
*(v->str) = '\0';
}
}
TERM_PUBLIC void
GGI_relative(r)
int r[2];
{
int diff = r[1] - r[0];
if (diff < 0) {
r[0] = r[1];
r[1] = -diff;
} else {
r[1] = diff;
}
}
TERM_PUBLIC void
GGI_clear_hline(x1, x2, y)
int x1;
int x2;
int y;
{
if (GGI_saved_canvas && x1 >= 0 && x2 >= 0 && y >= 0) {
int r[2];
ggiSetReadFrame(GGIvisual, !ggiGetDisplayFrame(GGIvisual));
r[0] = x1;
r[1] = x2;
GGI_relative(r);
/* horizontal line */
ggiCopyBox(GGIvisual, r[0], y, r[1], 1, r[0], y);
}
}
TERM_PUBLIC void
GGI_clear_vline(y1, y2, x)
int y1;
int y2;
int x;
{
if (GGI_saved_canvas && y1 >= 0 && y2 >= 0 && x >= 0) {
int r[2];
ggiSetReadFrame(GGIvisual, !ggiGetDisplayFrame(GGIvisual));
r[0] = y1;
r[1] = y2;
GGI_relative(r);
/* vertical line */
ggiCopyBox(GGIvisual, x, r[0], 1, r[1], x, r[0]);
}
}
TERM_PUBLIC void
GGI_draw_hline(x1, x2, y)
int x1;
int x2;
int y;
{
if (x1 >= 0 && x2 >= 0 && y >= 0) {
int r[2];
r[0] = x1;
r[1] = x2;
GGI_relative(r);
/* horizontal line */
ggiDrawHLine(GGIvisual, r[0], y, r[1]);
}
}
TERM_PUBLIC void
GGI_draw_vline(y1, y2, x)
int y1;
int y2;
int x;
{
if (y1 >= 0 && y2 >= 0 && x >= 0) {
int r[2];
r[0] = y1;
r[1] = y2;
GGI_relative(r);
/* vertical line */
ggiDrawVLine(GGIvisual, x, r[0], r[1]);
}
}
TERM_PUBLIC void
GGI_draw_ruler()
{
if (GGI_ruler.x >= 0 && GGI_ruler.y >= 0) {
ggi_pixel current_foreground;
GGI_save_frame_canvas();
/* TODO: we could choose a nicer color here */
ggiGetGCForeground(GGIvisual, ¤t_foreground);
ggiSetGCForeground(GGIvisual, GGIaxisColor);
ggiDrawHLine(GGIvisual, 0, GGI_ruler.y, GGIwidth);
ggiDrawVLine(GGIvisual, GGI_ruler.x, 0, GGIcanvas_height);
/* restore old foreground color */
/* XXX need this ? */
ggiSetGCForeground(GGIvisual, current_foreground);
}
}
TERM_PUBLIC void
GGI_clear_zoombox()
{
GGI_clear_hline(GGI_zoombox[0].x, GGI_zoombox[1].x, GGI_zoombox[0].y);
GGI_clear_hline(GGI_zoombox[0].x, GGI_zoombox[1].x, GGI_zoombox[1].y);
GGI_clear_vline(GGI_zoombox[0].y, GGI_zoombox[1].y, GGI_zoombox[0].x);
GGI_clear_vline(GGI_zoombox[0].y, GGI_zoombox[1].y, GGI_zoombox[1].x);
}
TERM_PUBLIC void
GGI_draw_zoombox()
{
if (GGI_zoombox[0].x >= 0 && GGI_zoombox[0].y >= 0
&& GGI_zoombox[0].x >= 0 && GGI_zoombox[0].y >= 0) {
ggi_pixel current_foreground;
GGI_save_frame_canvas();
/* TODO: we could choose a nicer color here */
ggiGetGCForeground(GGIvisual, ¤t_foreground);
ggiSetGCForeground(GGIvisual, GGIaxisColor);
GGI_draw_hline(GGI_zoombox[0].x, GGI_zoombox[1].x, GGI_zoombox[0].y);
GGI_draw_hline(GGI_zoombox[0].x, GGI_zoombox[1].x, GGI_zoombox[1].y);
GGI_draw_vline(GGI_zoombox[0].y, GGI_zoombox[1].y, GGI_zoombox[0].x);
GGI_draw_vline(GGI_zoombox[0].y, GGI_zoombox[1].y, GGI_zoombox[1].x);
/* restore old foreground color */
/* XXX need this ? */
ggiSetGCForeground(GGIvisual, current_foreground);
}
}
TERM_PUBLIC void
GGI_abort_zooming()
{
/* empty string: finish zooming */
int i, j;
GGI_clear_zoombox();
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
GGI_set_vertex(&(GGI_zoom[i][j]), 0, 0, (char*)0, GGI_saved_canvas);
}
GGI_zoombox[i].x = -1;
}
}
TERM_PUBLIC int
GGI_waitforinput()
{
char c;
/* 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.
*/
if (GGIvisual) {
fd_set fds;
int fd = fileno(stdin);
int i, j;
do {
int n;
ggi_event_mask mask = emAll; /* TODO: choose a more selective mask */
ggiSetEventMask(GGIvisual, mask);
FD_ZERO(&fds);
FD_SET(fd, &fds); /* listen to stdin */
if (GGI_needs_update) {
/* draw the ruler below the other items */
GGI_draw_ruler();
/* update the zoombox */
GGI_draw_zoombox();
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
GGI_save_puts(&(GGI_zoom[i][j]), GGI_saved_canvas);
}
}
/* update the status line */
GGI_save_puts(&GGI_stl_vertex, GGI_saved_stl);
ggiFlush(GGIvisual);
GGI_needs_update = 0;
}
n = ggiEventSelect(GGIvisual, &mask, fd + 1,
SELECT_FD_SET_CAST &fds, 0, 0, (struct timeval*)0);
if (mask) {
ggi_event event;
/* mask pointer motions and key repeat events,
* to they don't pile up */
ggiEventRead(GGIvisual, &event, mask);
ggiRemoveEventMask(GGIvisual, emPtrMove | emKeyRepeat);
if ('q' == GGI_dispatch_event(&event)) {
term_reset();
break;
} else {
ggiAddEventMask(GGIvisual, emPtrMove | emKeyRepeat);
}
}
} while (!FD_ISSET(fd, &fds) && GGIvisual);
}
if (read(0, &c, 1)!=1) return EOF;
else return c;
}
TERM_PUBLIC void
GGI_put_tmptext(i, str)
int i;
const char str[];
{
char* second;
switch (i) {
case 0: /* statusline text */
if (!str || !(*str)) {
/* statusline is empty. This is the case,
* if the mouse was just turned off. */
if (GGI_use_mouse) {
/* The user just toggled of the mouse. */
GGI_use_mouse = 0;
GGI_set_size();
GGI_replot();
}
} else {
/* statusline is non-empty */
if (!GGI_use_mouse) {
/* The mouse was off before and was just turned on. */
GGI_use_mouse = 1;
GGI_set_size();
GGI_replot();
}
GGI_save_frame_stl();
GGI_set_vertex(&GGI_stl_vertex, 0, GGIcanvas_height, str, GGI_saved_stl);
}
break;
case 1: /* coordinate text for first corner of zoombox */
case 2: /* coordinate text for second corner of zoombox */
GGI_save_frame_canvas();
second = (char*) strchr(str, '\r');
--i; /* transform to [0, 1] */
GGI_clear_zoombox();
if (second == NULL) {
/* remove box and / or coordinates */
GGI_set_vertex(&(GGI_zoom[i][0]), 0, 0, (char*)0, GGI_saved_canvas);
GGI_set_vertex(&(GGI_zoom[i][1]), 0, 0, (char*)0, GGI_saved_canvas);
break;
} else {
*second = '\0'; /* XXX this assumes that str is writable XXX */
second++;
GGI_set_vertex(&(GGI_zoom[i][0]), GGI_mouse_x, GGI_mouse_y - GGI_font_height - 1, str, GGI_saved_canvas);
GGI_set_vertex(&(GGI_zoom[i][1]), GGI_mouse_x, GGI_mouse_y + 1, second, GGI_saved_canvas);
GGI_zoombox[i].x = GGI_mouse_x;
GGI_zoombox[i].y = GGI_mouse_y;
}
break;
}
GGI_needs_update++;
}
TERM_PUBLIC void
GGI_set_ruler(x, y)
int x, y;
{
if (x < 0) {
/* turn ruler off */
GGI_clear_hline(0, GGIwidth, GGI_ruler.y);
GGI_clear_vline(0, GGIcanvas_height, GGI_ruler.x);
GGI_ruler.x = -1;
GGI_ruler.y = -1;
} else {
GGI_ruler.x = x;
GGI_ruler.y = GGI_y(y);
}
GGI_needs_update++;
}
TERM_PUBLIC void
GGI_set_cursor(c, x, y)
int c, x, y;
{
/* TODO */
switch (c) {
case 0:
GGI_abort_zooming();
break;
case 1:
case 2:
case 3:
default:
/* XXX not implemented */
break;
}
GGI_needs_update++;
}
TERM_PUBLIC void
GGI_set_clipboard(s)
const char s[];
{
/* XXX: not implemented */
}
#endif
#ifdef PM3D
TERM_PUBLIC int
GGI_make_palette(palette)
t_sm_palette *palette;
{
/* reallocate only, if it has changed */
if (palette && (GGI_save_pal.colorFormulae < 0
|| palette->colorFormulae != GGI_save_pal.colorFormulae
|| palette->colorMode != GGI_save_pal.colorMode
|| palette->formulaR != GGI_save_pal.formulaR
|| palette->formulaG != GGI_save_pal.formulaG
|| palette->formulaB != GGI_save_pal.formulaB
|| palette->positive != GGI_save_pal.positive)) {
int i;
ggi_color color;
for (i = 0; i < ggi_pm3d_colors; i++) {
color.r = (short)floor(palette->color[i].r * 0xffff),
color.g = (short)floor(palette->color[i].g * 0xffff),
color.b = (short)floor(palette->color[i].b * 0xffff),
GGI_smooth_colors[i] = ggiMapColor(GGIvisual, &color);
}
GGI_save_pal = *palette;
} else {
return ggi_pm3d_colors;
}
return 0;
}
TERM_PUBLIC void
GGI_previous_palette()
{
#if 0
#ifdef ENABLE_XMI
fprintf(stderr, "(GGI_previous_palette) \n");
if (GGI_miPaintedSet) {
miPoint offset;
offset.x = 0; offset.y = 0;
miCopyPaintedSetToVisual(GGIvisual, GGI_miGC, GGI_miPaintedSet, offset);
miClearPaintedSet(GGIvisual, GGI_miPaintedSet);
}
#endif
#endif
}
TERM_PUBLIC void
GGI_set_color(gray)
double gray;
{
if (GGIvisual) {
int idx = (gray <= 0) ? 0 : (int)(gray * ggi_pm3d_colors);
if (idx >= ggi_pm3d_colors)
idx = ggi_pm3d_colors - 1;
ggiSetGCForeground(GGIvisual, GGI_smooth_colors[idx]);
#ifdef ENABLE_XMI
GGI_miGC->pixels[1] = GGI_smooth_colors[idx];
#endif
}
}
#ifdef ENABLE_XMI
TERM_PUBLIC void
GGI_filled_polygon(points, corners)
int points;
gpiPoint *corners;
{
static miPoint offset = {0, 0};
if (GGI_miPaintedSet) {
#define MI_POINTS 4
miPoint mi_corners[MI_POINTS];
unsigned int i;
if (MI_POINTS != points) {
fprintf(stderr, "(GGI_filled_polygon) internal error %s:%d\n", __FILE__, __LINE__);
return;
}
for (i = 0; i < MI_POINTS; i++) {
mi_corners[i].x = corners[i].x;
mi_corners[i].y = GGI_y(corners[i].y);
}
miFillPolygon(GGIvisual, GGI_miPaintedSet, GGI_miGC,
MI_SHAPE_GENERAL, MI_COORD_MODE_ORIGIN, MI_POINTS, mi_corners);
miCopyPaintedSetToVisual(GGIvisual, GGI_miGC, GGI_miPaintedSet, offset);
miClearPaintedSet(GGIvisual, GGI_miPaintedSet);
}
}
#endif
#endif /* PM3D */
#endif /* TERM_BODY */
#ifdef TERM_TABLE
TERM_TABLE_START(ggi_driver)
"ggi", "GGI target",
GGI_XMAX, GGI_YMAX, GGI_VCHAR, GGI_HCHAR, GGI_VTIC, GGI_HTIC,
GGI_options, GGI_init, GGI_reset, GGI_text,
null_scale, GGI_graphics, GGI_move, GGI_vector,
GGI_linetype, GGI_put_text,
0, /* angle */
0, /* justify text */
0, /* point */
0, /* arrow */
0, /* set_font */
0, /* set_pointsize */
TERM_CAN_MULTIPLOT,
GGI_suspend,
GGI_resume,
GGI_fillbox,
0 /* linewidth */
#ifdef USE_MOUSE
, GGI_waitforinput, GGI_put_tmptext, GGI_set_ruler, GGI_set_cursor, GGI_set_clipboard
#endif
#ifdef PM3D
, GGI_make_palette,
GGI_previous_palette,
GGI_set_color,
#ifdef ENABLE_XMI
GGI_filled_polygon
#else
0 /* GGI_filled_polygon */
#endif
#endif
TERM_TABLE_END(ggi_driver)
#endif /* TERM_TABLE */
#endif /* TERM_PROTO_ONLY */
#ifdef TERM_HELP
START_HELP(ggi)
"1 ggi",
"?commands set terminal ggi",
"?set terminal ggi",
"?set term ggi",
"?terminal ggi",
"?term ggi",
"?ggi",
" The `ggi` driver can run on different targets as X or svgalib.",
"",
" Syntax:",
" set terminal ggi [acceleration <integer>] [[mode] {mode}]",
"",
" In X the window cannot be resized using window manager handles, but the",
" mode can be given with the mode option, e.g.:",
" - V1024x768",
" - V800x600",
" - V640x480",
" - V320x200",
" Please refer to the ggi documentation for other modes. The 'mode' keyword",
" is optional. It is recommended to select the target by environment variables",
" as explained in the libggi manual page. To get DGA on X, you should for",
" example",
" bash> export GGI_DISPLAY=DGA",
" csh> setenv GGI_DISPLAY DGA",
"",
" 'acceleration' is only used for targets which report relative pointer",
" motion events (e.g. DGA) and is a strictly positive integer multiplication",
" factor for the relative distances. The default for acceleration is 7.",
"",
" Examples:",
" set term ggi acc 10",
" set term ggi acc 1 mode V1024x768",
" set term ggi V1024x768"
END_HELP(ggi)
#endif