- Optification is done by auto builder now
[gnuplot] / term / ggi.trm
1 /* Hello, Emacs, this is -*-C-*-
2  * $Id: ggi.trm,v 1.26.2.1 2008/06/26 23:16:55 sfeam Exp $
3  */
4
5 /* GNUPLOT - ggi.trm */
6
7 /*[
8  * Copyright 2000, 2004
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35  ]*/
36
37 /*
38  * AUTHOR:
39  *   Cesar Crusius <crusius@leland.stanford.edu>
40  *   event / mouse processing & double-buffering
41  *   by Johannes Zellner <johannes@zellner.org>
42  *   pm3d support by Johannes Zellner <johannes@zellner.org> (Oct. 2000)
43  *
44  *   TODO:
45  *
46  *      - reimplement wmh (if it's available)
47  *      - implement window title using wmh (if it's available)
48  *      - check for availability of two frames, and if not
49  *        do it with one frame. (will eventually not do
50  *        with mouse/event reporting)
51  *      - check if libxmi is available and if so, use
52  *        it to draw filled polygons.
53  *      - enable cursors using blits.
54  */
55
56 #include "driver.h"
57
58 #ifdef TERM_REGISTER
59 register_term(ggi)
60 #endif
61
62 #ifdef TERM_PROTO
63
64 #include <ggi/ggi.h>
65 #ifdef USE_MOUSE
66 #  include <ggi/ggi-unix.h>
67 #endif
68
69 #ifdef HAVE_GGI_WMH_H
70 #   include <ggi/wmh.h>
71 static TBOOLEAN GGI_use_whm = 0;
72 #endif
73
74 #if 1
75 #if defined(HAVE_GGI_XMI_H)
76 #   define ENABLE_XMI 1
77 #endif
78 #endif
79
80 #ifdef ENABLE_XMI
81 #   include <ggi/xmi.h>
82 #endif
83
84 static void GGI_line_colors __PROTO((void));
85 TERM_PUBLIC void GGI_graphics __PROTO((void));
86 TERM_PUBLIC void GGI_set_size __PROTO((void));
87 TERM_PUBLIC void GGI_init __PROTO((void));
88 TERM_PUBLIC void GGI_linetype __PROTO((int));
89 TERM_PUBLIC void GGI_move __PROTO((unsigned int,unsigned int));
90 TERM_PUBLIC void GGI_options __PROTO((void));
91 TERM_PUBLIC void GGI_put_text __PROTO((unsigned int,unsigned int, const char*));
92 TERM_PUBLIC void GGI_suspend __PROTO((void));
93 TERM_PUBLIC void GGI_resume __PROTO((void));
94 TERM_PUBLIC void GGI_fillbox __PROTO((int style, unsigned int x, unsigned int y,
95         unsigned int w, unsigned int h));
96 TERM_PUBLIC void GGI_close __PROTO((void));
97 TERM_PUBLIC void GGI_reset __PROTO((void));
98 TERM_PUBLIC void GGI_text __PROTO((void));
99 TERM_PUBLIC void GGI_vector __PROTO((unsigned int,unsigned int));
100
101 #ifdef USE_MOUSE
102
103 /* zoom box information */
104
105 typedef struct  {
106     int x;
107     int y;
108 } GGI_point_t;
109
110 typedef struct {
111     int x;
112     int y;
113     int width;
114     int height;
115     char str[0xff];
116 } GGI_vertex_t;
117
118 TERM_PUBLIC long int GGI_SetTime(const struct timeval* current);
119 TERM_PUBLIC int GGI_from_keysym __PROTO((uint32_t keysym));
120 TERM_PUBLIC int GGI_from_button __PROTO((uint32_t button));
121 TERM_PUBLIC int GGI_y __PROTO((int32_t y));
122 TERM_PUBLIC int GGI_dispatch_event __PROTO((const ggi_event* event));
123 TERM_PUBLIC int GGI_eventually_update_modifiers __PROTO((const ggi_event* event, const int add));
124 TERM_PUBLIC int GGI_waitforinput __PROTO((void));
125 TERM_PUBLIC void GGI_draw_ruler __PROTO((void));
126 TERM_PUBLIC void GGI_clear_zoombox __PROTO((void));
127 TERM_PUBLIC void GGI_draw_zoombox __PROTO((void));
128 TERM_PUBLIC void GGI_set_ruler __PROTO((int, int));
129 TERM_PUBLIC void GGI_set_cursor __PROTO((int, int, int));
130 TERM_PUBLIC void GGI_save_frame_canvas __PROTO((void));
131 TERM_PUBLIC void GGI_save_frame_stl __PROTO((void));
132 TERM_PUBLIC void GGI_replot __PROTO((void));
133 TERM_PUBLIC void GGI_clear __PROTO((const GGI_vertex_t* v, const int tag));
134 TERM_PUBLIC void GGI_save_puts __PROTO((GGI_vertex_t* v, const int tag));
135 TERM_PUBLIC void GGI_set_vertex __PROTO((GGI_vertex_t* v, const int x, const int y, const char* str, const int tag));
136 TERM_PUBLIC void GGI_abort_zooming __PROTO((void));
137 TERM_PUBLIC void GGI_put_tmptext __PROTO((int, const char str[]));
138 TERM_PUBLIC void GGI_relative __PROTO((int r[2]));
139 TERM_PUBLIC void GGI_clear_hline __PROTO((int x1, int x2, int y));
140 TERM_PUBLIC void GGI_clear_vline __PROTO((int y1, int y2, int x));
141 TERM_PUBLIC void GGI_draw_hline __PROTO((int x1, int x2, int y));
142 TERM_PUBLIC void GGI_draw_vline __PROTO((int y1, int y2, int x));
143 TERM_PUBLIC void GGI_set_clipboard __PROTO((const char[]));
144 #endif /* USE_MOUSE */
145
146 TERM_PUBLIC int GGI_make_palette __PROTO((t_sm_palette*));
147 TERM_PUBLIC void GGI_previous_palette __PROTO((void));
148 TERM_PUBLIC void GGI_set_color __PROTO((struct t_colorspec *colorspec));
149 #ifdef ENABLE_XMI
150 TERM_PUBLIC void GGI_filled_polygon __PROTO((int, gpiPoint*));
151 #endif
152
153 #define GOT_GGI_PROTO
154 #endif
155
156 #ifndef TERM_PROTO_ONLY
157 #ifdef TERM_BODY
158
159 #define GGI_XMAX 800
160 #define GGI_YMAX 600
161 #define GGI_VCHAR 8
162 #define GGI_HCHAR 8
163 #define GGI_VTIC 8
164 #define GGI_HTIC 8
165
166
167 #ifdef USE_MOUSE
168 static GGI_vertex_t GGI_zoom[2][2];
169 static GGI_vertex_t GGI_stl_vertex;
170 static GGI_point_t GGI_ruler = {-1, -1};
171 static GGI_point_t GGI_zoombox[2] = {{-1, -1}, {-1, -1}};
172
173 static struct timeval GGI_timestamp;
174 static int GGI_mouse_x = 0;
175 static int GGI_mouse_y = 0;
176 static int GGI_modifiers = 0;
177 static int GGI_use_mouse = 1; /* mouse is on by default */
178 static unsigned int GGIcanvas_height = 0;
179 static int GGI_font_width = 0;
180 static int GGI_font_height = 0;
181 static int GGI_saved_canvas = 0;
182 static int GGI_saved_stl = 0;
183 static int GGI_needs_update = 1;
184 #endif
185
186 static t_sm_palette GGI_save_pal = {
187     -1, -1, -1, -1, -1, -1, -1, -1,
188     (rgb_color*) 0, -1, -1
189 };
190
191 /* First to some global variables
192  *
193  * GGIvisual is our 'piece of paper.'
194  * GGIborderColor and axixColor have the obvious meanings.
195  * GGIcolors are the colors for linestyles 0 and up.
196  * GGImap is for initializing colors.
197  * GGIx,GGIy are the current coordinates.
198  * GGIwidth, GGIheight are the extensions in the visual.
199  * GGIymax = term->ymax
200  */
201 static ggi_visual_t GGIvisual = (ggi_visual_t)0;
202 static ggi_pixel GGIborderColor;
203 static ggi_pixel GGIaxisColor;
204 static ggi_pixel GGIblack;
205 static ggi_pixel GGIcolors[7];
206 #define GGI_PM3D_COLORS 240
207 static const int ggi_pm3d_colors = GGI_PM3D_COLORS;
208 static ggi_pixel GGI_smooth_colors[GGI_PM3D_COLORS];
209 static unsigned int GGIx,GGIy;
210 static unsigned int GGIwidth, GGIheight, GGIymax;
211 #if 0
212 static unsigned int Xenv;
213 #endif
214 static int GGI_frames =
215 #ifdef USE_MOUSE
216 2
217 #else
218 1
219 #endif
220 ;
221
222 #ifdef ENABLE_XMI
223 static miGC* GGI_miGC = (miGC*)0;
224 static miPaintedSet* GGI_miPaintedSet = (miPaintedSet*)0;
225 static miPixel GGI_miPixels[2]; /* only GGI_miPixels[1] is used */
226 static int GGI_numblendstages = 0;
227 static miBlendStage GGI_blendstages[4];
228 #endif
229
230 static TBOOLEAN GGI_mode_changed = 1;
231 static char GGI_mode_spec[0xff] = "";
232 static int GGI_acceleration = 7; /* arbitrary */
233
234 enum GGI_id {
235     GGI_MODE,
236     GGI_ACCELERATION,
237     GGI_OTHER
238 };
239
240 static struct gen_table GGI_opts[] =
241 {
242     { "mo$de", GGI_MODE },
243     { "ac$celeration", GGI_ACCELERATION },
244     { NULL, GGI_OTHER }
245 };
246
247 static void
248 GGI_line_colors()
249 {
250     ggi_pixel GGIwhite,GGIred,GGIgreen,GGIblue,GGIcyan,GGImagenta,GGIgray;
251     ggi_pixel GGIyellow;
252     ggi_color color;
253
254     color.r = 0xFFFF; color.g = 0xFFFF; color.b = 0xFFFF; GGIwhite   = ggiMapColor(GGIvisual,&color);
255     color.r = 0x0000; color.g = 0x0000; color.b = 0x0000; GGIblack   = ggiMapColor(GGIvisual,&color);
256     color.r = 0xFFFF; color.g = 0x0000; color.b = 0x0000; GGIred     = ggiMapColor(GGIvisual,&color);
257     color.r = 0x0000; color.g = 0xFFFF; color.b = 0x0000; GGIgreen   = ggiMapColor(GGIvisual,&color);
258     color.r = 0x0000; color.g = 0x0000; color.b = 0xFFFF; GGIblue    = ggiMapColor(GGIvisual,&color);
259     color.r = 0x0000; color.g = 0xFFFF; color.b = 0xFFFF; GGIcyan    = ggiMapColor(GGIvisual,&color);
260     color.r = 0xFFFF; color.g = 0x0000; color.b = 0xFFFF; GGImagenta = ggiMapColor(GGIvisual,&color);
261     color.r = 0xFFFF; color.g = 0xFFFF; color.b = 0x0000; GGIyellow  = ggiMapColor(GGIvisual,&color);
262     color.r = 0x8888; color.g = 0x8888; color.b = 0x8888; GGIgray    = ggiMapColor(GGIvisual,&color);
263
264     GGIborderColor = GGIwhite;
265     GGIaxisColor   = GGIgray;
266     GGIcolors[0]   = GGIred;
267     GGIcolors[1]   = GGIgreen;
268     GGIcolors[2]   = GGIblue;
269     GGIcolors[3]   = GGImagenta;
270     GGIcolors[4]   = GGIcyan;
271     GGIcolors[5]   = GGIyellow;
272     GGIcolors[6]   = GGIgray;
273 }
274
275 /* Called bevore a graphic is displayed */
276 TERM_PUBLIC void GGI_graphics()
277 {
278 #ifdef USE_MOUSE
279     int i, j;
280     int display_frame = ggiGetDisplayFrame(GGIvisual);
281 #endif
282 #if 0
283     if(!Xenv)
284     {
285         GGI_line_colors();
286         return;
287     }
288 #endif
289     ggiSetGCForeground(GGIvisual,GGIblack);
290 #ifdef USE_MOUSE
291     /* write to the currently not displayed buffer */
292     ggiSetWriteFrame(GGIvisual, !display_frame);
293
294     /* mark the contents of the alternate frame as invalid */
295     GGI_saved_canvas = 0;
296     GGI_saved_stl = 0;
297     GGI_needs_update = 1;
298
299     /* reset the stl vertex */
300     GGI_stl_vertex.width = 0;
301
302     /* reset the zoom box coordinates */
303     for (i = 0; i < 2; i++) {
304         for (j = 0; j < 2; j++) {
305             GGI_zoom[i][j].width = 0;
306         }
307         GGI_zoombox[i].x = -1;
308         GGI_zoombox[i].y = -1;
309     }
310 #endif /* USE_MOUSE */
311
312     /* clear *write* buffer. */
313     ggiDrawBox(GGIvisual, 0, 0, GGIwidth, GGIheight);
314
315 #ifdef USE_MOUSE
316     if (GGI_use_mouse) {
317         /* copy the contents of the currently
318          * displayed stl to the write frame.
319          * This way the stl won't jitter. */
320         ggiSetReadFrame(GGIvisual, display_frame);
321         ggiCopyBox(GGIvisual, 0, GGIcanvas_height,
322             GGIwidth, GGI_font_height, 0, GGIcanvas_height);
323     }
324 #endif
325 }
326
327 TERM_PUBLIC void
328 GGI_set_size()
329 {
330     ggi_mode mode;
331     ggiGetMode(GGIvisual,&mode);
332
333     GGIwidth  = mode.virt.x;
334     GGIheight = mode.virt.y;
335
336     term->xmax = mode.virt.x - 1;
337
338 #ifdef USE_MOUSE
339     GGIcanvas_height = mode.virt.y - (GGI_use_mouse ? GGI_font_height : 0);
340     term->ymax = GGIcanvas_height - 1;
341 #else
342     term->ymax = mode.virt.y - 1;
343 #endif
344     GGIymax = term->ymax;
345 }
346
347 /*
348  * init
349  * -----------------------
350  * Called only once, when the terminal is initialized. We have to open the visual here because it
351  * is during 'init' that we have to change the terminal dimensions (xmax, ymax).
352  */
353 TERM_PUBLIC void GGI_init()
354 {
355     int success = 0;
356     ggi_mode mode;
357
358 #if 0
359     if (0 != giiInit()) {
360         ggiPanic("*** giiInit() failed *** \n");
361     }
362 #endif
363
364     if (0 != ggiInit()) {
365         ggiPanic("*** ggiInit() failed *** \n");
366     }
367
368     if (NULL == (GGIvisual = ggiOpen(NULL))) {
369         /* TODO: abort a bit more gracefully */
370         ggiPanic("(GGI_init() unable to open default\n");
371     }
372
373     if (strlen(GGI_mode_spec)) {
374         /* user specified mode */
375         if (!ggiParseMode(GGI_mode_spec, &mode)) {
376             mode.frames = GGI_frames;
377             if (!ggiSetMode(GGIvisual, &mode)) {
378                 success = 1;
379             }
380         }
381     }
382
383     if (!success) {
384         /* try the default mode */
385         if(ggiSetSimpleMode(GGIvisual,GGI_AUTO,GGI_AUTO,GGI_frames,GT_AUTO)) {
386             ggiPanic("(GGI_init() unable to set default mode\n");
387             GGIvisual = (ggi_visual_t)0;
388         }
389     }
390
391     ggiGetMode(GGIvisual, &mode);
392
393     /* print the mode only once if it has changed */
394     if (GGI_mode_changed) {
395         GGI_mode_changed = 0;
396         ggiFPrintMode(stderr, &mode);
397         fprintf(stderr, "\n");
398     }
399
400 #ifdef USE_MOUSE
401     /* must come before GGI_set_size() */
402     ggiGetCharSize(GGIvisual, &GGI_font_width, &GGI_font_height);
403 #endif
404
405     GGI_set_size();
406
407
408 #ifdef USE_MOUSE
409     ggiSetReadFrame(GGIvisual, 0);
410     ggiSetWriteFrame(GGIvisual, 0);
411     ggiSetDisplayFrame(GGIvisual, 0);
412 #endif
413
414 #ifdef HAVE_GGI_WMH_H
415     /* Initialize WMH extension */
416     if (ggiWmhInit() != 0 || ggiWmhAttach(GGIvisual) < 0) {
417         GGI_use_whm = 0;
418     } else {
419         GGI_use_whm = 1;
420         ggiWmhAllowResize(GGIvisual, 100, 50, 2000, 2000, 10, 10);
421         ggiWmhSetTitle(GGIvisual, "GGI Gnuplot Driver");
422         ggiWmhSetIconTitle(GGIvisual, "Gnuplot");
423     }
424 #endif
425
426     /*
427      * if(!(Xenv=!ggiWmhAttach(GGIvisual))) ggiWmhDetach(GGIvisual);
428      * else Xenv=!ggiWmhSetTitle(GGIvisual,"GGI Gnuplot Driver");
429      */
430 #if 0
431     if(!Xenv)
432     {
433         /*
434          * ggiWmhDetach(GGIvisual);
435          * ggiWmhExit();
436          */
437         ggiClose(GGIvisual);
438         ggiExit();
439         GGIvisual=NULL;
440     }
441 #endif
442     GGI_line_colors();
443     ggiSetFlags(GGIvisual, GGIFLAG_ASYNC);
444 #ifdef USE_MOUSE
445     GGI_mouse_x = 0;
446     GGI_mouse_y = 0;
447     GGI_modifiers = 0;
448     {
449         struct timeval tv;
450         struct timezone tz;
451         gettimeofday(&tv, &tz);
452         GGI_SetTime(&tv); /* initialize time */
453     }
454 #endif
455
456 #ifdef ENABLE_XMI
457     if (0 != xmiInit()) {
458         /* TODO: abort a bit more gracefully */
459         ggiPanic("(GGI_init() unable to initialize xmi\n");
460     }
461
462     if (xmiAttach(GGIvisual) < 0) {
463         ggiPanic("(GGI_init) Unable to attach XMI extension to visual\n");
464     }
465
466     /* miPaintedSet */
467     if (GGI_miPaintedSet) {
468         miDeletePaintedSet(GGIvisual, GGI_miPaintedSet);
469         GGI_miPaintedSet = (miPaintedSet*)0;
470     }
471     GGI_miPaintedSet = miNewPaintedSet(GGIvisual);
472     miClearPaintedSet(GGIvisual, GGI_miPaintedSet);
473
474     /* miGC */
475     if (GGI_miGC) {
476         miDeleteGC(GGIvisual, GGI_miGC);
477         GGI_miGC = (miGC*)0;
478     }
479     GGI_miGC = miNewGC(GGIvisual, 2,
480         GGI_miPixels, GGI_numblendstages, GGI_blendstages);
481 #endif
482     setvbuf(stdin, (char*)0, _IONBF, 0);
483 }
484
485 TERM_PUBLIC void GGI_linetype(int linetype)
486 {
487     if(linetype == LT_BLACK)
488         ggiSetGCForeground(GGIvisual,GGIborderColor);
489     if(linetype == LT_AXIS)
490         ggiSetGCForeground(GGIvisual,GGIaxisColor);
491     if(linetype < 0)
492         return;
493     if(linetype >= 6)
494         linetype%=6;
495     ggiSetGCForeground(GGIvisual,GGIcolors[linetype]);
496 }
497
498 TERM_PUBLIC void GGI_move(unsigned int x, unsigned int y)
499 {
500     GGIx=x;
501     GGIy=GGI_y(y);
502 }
503
504 TERM_PUBLIC void
505 GGI_options()
506 {
507     while (!END_OF_COMMAND) {
508         switch(lookup_table(&GGI_opts[0], c_token)) {
509         case GGI_ACCELERATION:
510         {
511             int itmp;
512             struct value a;
513
514             c_token++;
515             itmp = (int) real(const_express(&a));
516             if (itmp < 1) {
517                 fprintf(stderr, "acceleration must be strictly positive!\n");
518             } else {
519                 GGI_acceleration = itmp;
520             }
521             break;
522         }
523         case GGI_MODE:
524             c_token++;
525             /* fallthru */
526         default:
527             if (!END_OF_COMMAND) {
528                 copy_str(GGI_mode_spec, c_token, 0xfe);
529                 GGI_mode_changed = 1;
530             }
531             break;
532         }
533         c_token++;
534     } /* while(command) */
535
536     if (*GGI_mode_spec) {
537         sprintf(term_options, "mode %s acceleration %d",
538                 GGI_mode_spec, GGI_acceleration);
539     } else {
540         sprintf(term_options, "acceleration %d", GGI_acceleration);
541     }
542 }
543
544 TERM_PUBLIC void
545 GGI_close()
546 {
547     ggiFlush(GGIvisual);
548     /* DETACH EXTENSIONS */
549 #if HAVE_WMH_H
550     if(GGI_use_whm) {
551         ggiWmhDetach(GGIvisual);
552     }
553 #endif
554 #ifdef ENABLE_XMI
555     xmiDetach(GGIvisual);
556 #endif
557
558     ggiClose(GGIvisual);
559     GGIvisual = (ggi_visual_t)0;
560
561     /* EXIT EXTENSIONS */
562 #if HAVE_WMH_H
563     if(GGI_use_whm) {
564         ggiWmhExit();
565         GGI_use_whm = 0;
566     }
567 #endif
568 #ifdef ENABLE_XMI
569     xmiExit();
570 #endif
571 }
572
573 /* Called when terminal is terminated i.e.
574  * when switching to another terminal. */
575 TERM_PUBLIC void
576 GGI_reset()
577 {
578     if(GGIvisual!=NULL) {
579         GGI_close();
580     }
581 # if 0 /* not needed */
582     GGI_save_pal.colorFormulae = -1; /* force later reallocation of palette */
583 # endif
584 }
585
586 TERM_PUBLIC void
587 GGI_put_text(unsigned int x, unsigned int y, const char *str)
588 {
589     ggi_pixel current_foreground;
590     ggiGetGCForeground(GGIvisual,&current_foreground);
591     ggiSetGCForeground(GGIvisual,GGIborderColor);
592     ggiPuts(GGIvisual,x,GGI_y(y) - 4 /* ? (joze ? */,str);
593     ggiSetGCForeground(GGIvisual,current_foreground);
594 }
595
596 TERM_PUBLIC void
597 GGI_suspend()
598 {
599     /* this fails on the console */
600     GGI_text();
601 }
602
603 TERM_PUBLIC void
604 GGI_resume()
605 {
606     /* do nothing */
607 }
608
609 TERM_PUBLIC void
610 GGI_fillbox(
611     int style,
612     unsigned int x, unsigned int y,
613     unsigned int w, unsigned int h)
614 {
615     ggiDrawBox(GGIvisual, x, GGI_y((int)(y+h)), w, h);
616 }
617
618 TERM_PUBLIC void
619 GGI_text()
620 {
621     ggiFlush(GGIvisual);
622 #ifdef USE_MOUSE
623     /* now display the buffer which was just written */
624     ggiSetDisplayFrame(GGIvisual, ggiGetWriteFrame(GGIvisual));
625     return;
626 #else
627     /* Wait for a key to be pressed and exit graphics mode if
628      * running in console mode. */
629     /* TODO: return immediately, if in X */
630     ggiGetc(GGIvisual);
631     GGI_close();
632 #endif
633 }
634
635 TERM_PUBLIC void
636 GGI_vector(unsigned int x, unsigned int y)
637 {
638     y = GGI_y(y);
639     ggiDrawLine(GGIvisual,GGIx,GGIy,x,y);
640     GGIx=x;
641     GGIy=y;
642 }
643
644 #ifdef USE_MOUSE
645
646 /* translate ggi keysym to gnuplot keysym */
647 TERM_PUBLIC int
648 GGI_from_keysym(uint32_t keysym)
649 {
650     switch (keysym) {
651         case GIIUC_BackSpace:
652             return GP_BackSpace;
653         case GIIUC_Tab:
654             return GP_Tab;
655         case GIIUC_Linefeed:
656             return GP_Linefeed;
657         case GIIK_Clear:
658             return GP_Clear;
659         case GIIUC_Return:
660             return GP_Return;
661         case GIIK_Pause:
662             return GP_Pause;
663         case GIIK_ScrollLock:
664             return GP_Scroll_Lock;
665         case GIIK_SysRq:
666             return GP_Sys_Req;
667         case GIIUC_Escape:
668             return GP_Escape;
669         case GIIK_Insert:
670             return GP_Insert;
671         case GIIUC_Delete:
672             return GP_Delete;
673         case GIIK_Home:
674             return GP_Home;
675         case GIIK_Left:
676             return GP_Left;
677         case GIIK_Up:
678             return GP_Up;
679         case GIIK_Right:
680             return GP_Right;
681         case GIIK_Down:
682             return GP_Down;
683         case GIIK_PageUp:
684             return GP_PageUp;
685         case GIIK_PageDown:
686             return GP_PageDown;
687         case GIIK_End:
688             return GP_End;
689         case GIIK_Begin:
690             return GP_Begin;
691         case GIIK_PSpace:
692             return GP_KP_Space;
693         case GIIK_PTab:
694             return GP_KP_Tab;
695         case GIIK_PEnter:
696             return GP_KP_Enter;
697
698         case GIIK_PF1:
699             return GP_KP_F1;
700         case GIIK_PF2:
701             return GP_KP_F2;
702         case GIIK_PF3:
703             return GP_KP_F3;
704         case GIIK_PF4:
705             return GP_KP_F4;
706
707 #if 0
708         case 1:
709             return GP_KP_Insert;    /* ~ KP_0 */
710         case 1:
711             return GP_KP_End;       /* ~ KP_1 */
712         case 1:
713             return GP_KP_Down;      /* ~ KP_2 */
714         case 1:
715             return GP_KP_Page_Down; /* ~ KP_3 */
716         case 1:
717             return GP_KP_Left;      /* ~ KP_4 */
718         case 1:
719             return GP_KP_Begin;     /* ~ KP_5 */
720         case 1:
721             return GP_KP_Right;     /* ~ KP_6 */
722         case 1:
723             return GP_KP_Home;      /* ~ KP_7 */
724         case 1:
725             return GP_KP_Up;        /* ~ KP_8 */
726         case 1:
727             return GP_KP_Page_Up;   /* ~ KP_9 */
728 #endif
729
730 #if 0
731         case GIIK_PDelete:
732             return GP_KP_Delete;
733 #endif
734         case GIIK_PEqual:
735             return GP_KP_Equal;
736         case GIIK_PAsterisk:
737             return GP_KP_Multiply;
738         case GIIK_PPlus:
739             return GP_KP_Add;
740         case GIIK_PSeparator:
741             return GP_KP_Separator;
742         case GIIK_PMinus:
743             return GP_KP_Subtract;
744         case GIIK_PDecimal:
745             return GP_KP_Decimal;
746         case GIIK_PSlash:
747             return GP_KP_Divide;
748
749         case GIIK_P0:
750             return GP_KP_0;
751         case GIIK_P1:
752             return GP_KP_1;
753         case GIIK_P2:
754             return GP_KP_2;
755         case GIIK_P3:
756             return GP_KP_3;
757         case GIIK_P4:
758             return GP_KP_4;
759         case GIIK_P5:
760             return GP_KP_5;
761         case GIIK_P6:
762             return GP_KP_6;
763         case GIIK_P7:
764             return GP_KP_7;
765         case GIIK_P8:
766             return GP_KP_8;
767         case GIIK_P9:
768             return GP_KP_9;
769
770         case GIIK_F1:
771             return GP_F1;
772         case GIIK_F2:
773             return GP_F2;
774         case GIIK_F3:
775             return GP_F3;
776         case GIIK_F4:
777             return GP_F4;
778         case GIIK_F5:
779             return GP_F5;
780         case GIIK_F6:
781             return GP_F6;
782         case GIIK_F7:
783             return GP_F7;
784         case GIIK_F8:
785             return GP_F8;
786         case GIIK_F9:
787             return GP_F9;
788         case GIIK_F10:
789             return GP_F10;
790         case GIIK_F11:
791             return GP_F11;
792         case GIIK_F12:
793             return GP_F12;
794
795         default:
796             /* return it untranslated */
797             return keysym;
798     }
799 }
800
801 TERM_PUBLIC long int
802 GGI_SetTime(const struct timeval* current)
803 {
804     /* --> dsec in musec */
805     int dsec = (current->tv_sec - GGI_timestamp.tv_sec) * 1000000;
806     /* --> dmu in millisec */
807     int dmu = (current->tv_usec - GGI_timestamp.tv_usec + dsec) / 1000;
808
809     GGI_timestamp = *current;
810     return dmu;
811 }
812
813 TERM_PUBLIC int
814 GGI_from_button(uint32_t button)
815 {
816     switch (button) {
817     case GII_PBUTTON_LEFT:
818         return 1;
819     case GII_PBUTTON_MIDDLE:
820         return 2;
821     case GII_PBUTTON_RIGHT:
822         return 3;
823     default:
824         /* should not happen */
825         return 0;
826     }
827 }
828
829 TERM_PUBLIC int
830 GGI_y(int32_t y)
831 {
832     return GGIymax - y;
833 }
834
835 TERM_PUBLIC int
836 GGI_eventually_update_modifiers(const ggi_event* event, const int add)
837 {
838     int mod = 0;
839     int old_modifiers = GGI_modifiers;
840
841     switch (event->key.sym) {
842     case GIIK_Shift:
843         mod = Mod_Shift;
844         break;
845     case GIIK_Ctrl:
846         mod = Mod_Ctrl;
847         break;
848     case GIIK_Alt:
849     case GIIK_Meta:
850         mod = Mod_Alt;
851         break;
852     default:
853         return 0;
854     }
855
856     if (add) {
857         GGI_modifiers |= mod;
858     } else {
859         GGI_modifiers &= ~mod;
860     }
861
862     if (GGI_modifiers != old_modifiers) {
863
864         struct gp_event_t gp_ev;
865
866         gp_ev.type = GE_modifier;
867         gp_ev.mx   = GGI_mouse_x;
868         gp_ev.my   = GGI_y(GGI_mouse_y);
869         gp_ev.par1 = 0;
870         gp_ev.par2 = 0;
871         gp_ev.par1 = GGI_modifiers;
872
873         do_event(&gp_ev);
874     }
875
876     return 1;
877 }
878
879 TERM_PUBLIC int
880 GGI_dispatch_event(const ggi_event* event)
881 {
882     struct gp_event_t gp_ev;
883
884     gp_ev.type = 0;
885     gp_ev.mx   = GGI_mouse_x;
886     gp_ev.my   = GGI_y(GGI_mouse_y);
887     gp_ev.par1 = 0;
888     gp_ev.par2 = 0;
889
890     switch (event->any.type) {
891
892         /* [-- KEY EVENTS --] */
893     case evKeyPress:
894     case evKeyRepeat:
895         if (GGI_eventually_update_modifiers(event, 1)) {
896             /* was just a modifier pressed */
897             return 0;
898         }
899         gp_ev.type = GE_keypress;
900         gp_ev.par1 = GGI_from_keysym(event->key.sym);
901         if ('q' == gp_ev.par1) {
902             return 'q';
903         }
904         break;
905     case evKeyRelease:
906         if (GGI_eventually_update_modifiers(event, 0)) {
907             /* was just a modifier pressed */
908             return 0;
909         }
910         break;
911
912         /* [-- POINTER EVENTS --] */
913     case evPtrRelative:
914         /* relative motion is not implemented. Should it ? */
915         /*
916          * fprintf(stderr, "%s:%d report this to <johannes@zellner.org> %d %d\n",
917          *     __FILE__, __LINE__, event->pmove.x, event->pmove.y);
918          */
919         gp_ev.type  = GE_motion;
920         GGI_mouse_x += GGI_acceleration * event->pmove.x;
921         GGI_mouse_y += GGI_acceleration * event->pmove.y;
922         break;
923     case evPtrAbsolute:
924         gp_ev.type  = GE_motion;
925         GGI_mouse_x = event->pmove.x;
926         GGI_mouse_y = event->pmove.y;
927         break;
928     case evPtrButtonPress:
929         gp_ev.type = GE_buttonpress;
930         gp_ev.par1 = GGI_from_button(event->pbutton.button);
931         break;
932     case evPtrButtonRelease:
933         gp_ev.type = GE_buttonrelease;
934         gp_ev.par1 = GGI_from_button(event->pbutton.button);
935         gp_ev.par2 = GGI_SetTime(&(event->pbutton.time));
936         break;
937 #ifdef HAVE_GGI_WMH_H
938     case evCommand:
939         /* [-- resizing --] */
940         if (GGI_use_whm) {
941             /* fprintf(stderr, "(GGI_dispatch_event) \n"); */
942             if (event->cmd.code==GGICMD_REQUEST_SWITCH) {
943                 /*
944                  * ggi_cmddata_switchrequest *req;
945                  * req = &(event->cmd.data);
946                  * ggi_resize(GGIvisual, &(req->mode));
947                  */
948                 /*
949                  * while( ggiEventPoll(GGIvisual, emAll, &tv) ) {
950                  *     ggiEventRead(GGIvisual, event, emAll);
951                  * }
952                  */
953             }
954         }
955         break;
956 #endif
957     default:
958         /* fprintf(stderr, "(GGI_dispatch_event) unhandled event\n"); */
959         break;
960     }
961     do_event(&gp_ev);
962     gp_ev.type = GE_plotdone;
963     do_event(&gp_ev);
964     return 0;
965 }
966
967 /* save currently displayed frame to alternate buffer */
968 TERM_PUBLIC void
969 GGI_save_frame_canvas()
970 {
971     if (!GGI_saved_canvas && GGIvisual) {
972         int display_frame = ggiGetDisplayFrame(GGIvisual);
973
974         /* save the currently displayed frame to alternate frame */
975         ggiSetReadFrame(GGIvisual, display_frame);
976         ggiSetWriteFrame(GGIvisual, !display_frame);
977         ggiCopyBox(GGIvisual, 0, 0, GGIwidth, GGIcanvas_height, 0, 0);
978
979         /* write again directly to the display frame */
980         ggiSetWriteFrame(GGIvisual, display_frame);
981
982         /* remember that the alternate frame is valid */
983         GGI_saved_canvas = 1;
984     }
985 }
986
987 TERM_PUBLIC void
988 GGI_save_frame_stl()
989 {
990     if (!GGI_saved_stl) {
991         int display_frame = ggiGetDisplayFrame(GGIvisual);
992
993         /* clear the stl part of the alternate buffer */
994         ggiSetGCForeground(GGIvisual, GGIblack);
995         ggiSetWriteFrame(GGIvisual, !display_frame);
996         ggiDrawBox(GGIvisual, 0, GGIcanvas_height, GGIwidth, GGI_font_height);
997         ggiSetWriteFrame(GGIvisual, display_frame);
998
999         /* clear the currently displayed area, which is left
1000          * from a previous plot (see above, where the stl of
1001          * the previous plot is copied to the current frame) */
1002         ggiSetReadFrame(GGIvisual, !display_frame);
1003         ggiCopyBox(GGIvisual, 0, GGIcanvas_height,
1004                    GGIwidth, GGI_font_height, 0, GGIcanvas_height);
1005
1006         GGI_saved_stl = 1;
1007     }
1008 }
1009
1010 TERM_PUBLIC void
1011 GGI_replot()
1012 {
1013     struct gp_event_t ev = {
1014         GE_replot,
1015         0, 0, 0, 0
1016     };
1017
1018     do_event(&ev);
1019 }
1020
1021 TERM_PUBLIC void
1022 GGI_clear(const GGI_vertex_t* v, const int tag)
1023 {
1024     if (tag && v->width) {
1025         /* turn off current */
1026         ggiSetReadFrame(GGIvisual, !ggiGetDisplayFrame(GGIvisual));
1027         ggiCopyBox(GGIvisual, v->x, v->y, v->width, v->height, v->x, v->y);
1028     }
1029 }
1030
1031 TERM_PUBLIC void
1032 GGI_save_puts(GGI_vertex_t* v, const int tag)
1033 {
1034     GGI_clear(v, tag);
1035
1036     if (v->width) {
1037
1038         /* draw the text in the axis color (gray) */
1039         ggiSetGCForeground(GGIvisual, GGIaxisColor);
1040
1041         /* write the string directly to the display */
1042         ggiPuts(GGIvisual, v->x, v->y, v->str);
1043
1044     }
1045 }
1046
1047 TERM_PUBLIC void
1048 GGI_set_vertex(
1049     GGI_vertex_t* v,
1050     const int x,
1051     const int y,
1052     const char* str,
1053     const int tag)
1054 {
1055     GGI_clear(v, tag);
1056
1057     v->x = x;
1058     v->y = y;
1059     v->height = GGI_font_height;
1060
1061     if (str && *str) {
1062         v->width = strlen(str) * GGI_font_width;
1063         strcpy(v->str, str);
1064     } else {
1065         /* turn string off */
1066         v->width = 0;
1067         *(v->str) = '\0';
1068     }
1069 }
1070
1071 TERM_PUBLIC void
1072 GGI_relative(int r[2])
1073 {
1074     int diff = r[1] - r[0];
1075     if (diff < 0) {
1076         r[0] = r[1];
1077         r[1] = -diff;
1078     } else {
1079         r[1] = diff;
1080     }
1081 }
1082
1083 TERM_PUBLIC void
1084 GGI_clear_hline(int x1, int x2, int y)
1085 {
1086     if (GGI_saved_canvas && x1 >= 0 && x2 >= 0 && y >= 0) {
1087         int r[2];
1088         ggiSetReadFrame(GGIvisual, !ggiGetDisplayFrame(GGIvisual));
1089
1090         r[0] = x1;
1091         r[1] = x2;
1092         GGI_relative(r);
1093         /* horizontal line */
1094         ggiCopyBox(GGIvisual, r[0], y, r[1], 1, r[0], y);
1095     }
1096 }
1097
1098 TERM_PUBLIC void
1099 GGI_clear_vline(int y1, int y2, int x)
1100 {
1101     if (GGI_saved_canvas && y1 >= 0 && y2 >= 0 && x >= 0) {
1102         int r[2];
1103         ggiSetReadFrame(GGIvisual, !ggiGetDisplayFrame(GGIvisual));
1104
1105         r[0] = y1;
1106         r[1] = y2;
1107         GGI_relative(r);
1108         /* vertical line */
1109         ggiCopyBox(GGIvisual, x, r[0], 1, r[1], x, r[0]);
1110     }
1111 }
1112
1113 TERM_PUBLIC void
1114 GGI_draw_hline(int x1, int x2, int y)
1115 {
1116     if (x1 >= 0 && x2 >= 0 && y >= 0) {
1117         int r[2];
1118
1119         r[0] = x1;
1120         r[1] = x2;
1121         GGI_relative(r);
1122         /* horizontal line */
1123         ggiDrawHLine(GGIvisual, r[0], y, r[1]);
1124     }
1125 }
1126
1127 TERM_PUBLIC void
1128 GGI_draw_vline(int y1, int y2, int x)
1129 {
1130     if (y1 >= 0 && y2 >= 0 && x >= 0) {
1131         int r[2];
1132
1133         r[0] = y1;
1134         r[1] = y2;
1135         GGI_relative(r);
1136         /* vertical line */
1137         ggiDrawVLine(GGIvisual, x, r[0], r[1]);
1138     }
1139 }
1140
1141 TERM_PUBLIC void
1142 GGI_draw_ruler()
1143 {
1144     if (GGI_ruler.x >= 0 && GGI_ruler.y >= 0) {
1145         ggi_pixel current_foreground;
1146
1147         GGI_save_frame_canvas();
1148
1149         /* TODO: we could choose a nicer color here */
1150         ggiGetGCForeground(GGIvisual, &current_foreground);
1151         ggiSetGCForeground(GGIvisual, GGIaxisColor);
1152
1153         ggiDrawHLine(GGIvisual, 0, GGI_ruler.y, GGIwidth);
1154         ggiDrawVLine(GGIvisual, GGI_ruler.x, 0, GGIcanvas_height);
1155
1156         /* restore old foreground color */
1157         /* XXX need this ? */
1158         ggiSetGCForeground(GGIvisual, current_foreground);
1159     }
1160 }
1161
1162 TERM_PUBLIC void
1163 GGI_clear_zoombox()
1164 {
1165     GGI_clear_hline(GGI_zoombox[0].x, GGI_zoombox[1].x, GGI_zoombox[0].y);
1166     GGI_clear_hline(GGI_zoombox[0].x, GGI_zoombox[1].x, GGI_zoombox[1].y);
1167     GGI_clear_vline(GGI_zoombox[0].y, GGI_zoombox[1].y, GGI_zoombox[0].x);
1168     GGI_clear_vline(GGI_zoombox[0].y, GGI_zoombox[1].y, GGI_zoombox[1].x);
1169 }
1170
1171 TERM_PUBLIC void
1172 GGI_draw_zoombox()
1173 {
1174     if (GGI_zoombox[0].x >= 0 && GGI_zoombox[0].y >= 0
1175         && GGI_zoombox[0].x >= 0 && GGI_zoombox[0].y >= 0) {
1176         ggi_pixel current_foreground;
1177
1178         GGI_save_frame_canvas();
1179
1180         /* TODO: we could choose a nicer color here */
1181         ggiGetGCForeground(GGIvisual, &current_foreground);
1182         ggiSetGCForeground(GGIvisual, GGIaxisColor);
1183
1184         GGI_draw_hline(GGI_zoombox[0].x, GGI_zoombox[1].x, GGI_zoombox[0].y);
1185         GGI_draw_hline(GGI_zoombox[0].x, GGI_zoombox[1].x, GGI_zoombox[1].y);
1186         GGI_draw_vline(GGI_zoombox[0].y, GGI_zoombox[1].y, GGI_zoombox[0].x);
1187         GGI_draw_vline(GGI_zoombox[0].y, GGI_zoombox[1].y, GGI_zoombox[1].x);
1188
1189         /* restore old foreground color */
1190         /* XXX need this ? */
1191         ggiSetGCForeground(GGIvisual, current_foreground);
1192     }
1193 }
1194
1195 TERM_PUBLIC void
1196 GGI_abort_zooming()
1197 {
1198     /* empty string: finish zooming */
1199     int i, j;
1200     GGI_clear_zoombox();
1201     for (i = 0; i < 2; i++) {
1202         for (j = 0; j < 2; j++) {
1203             GGI_set_vertex(&(GGI_zoom[i][j]), 0, 0, (char*)0, GGI_saved_canvas);
1204         }
1205         GGI_zoombox[i].x = -1;
1206     }
1207 }
1208
1209 TERM_PUBLIC int
1210 GGI_waitforinput()
1211 {
1212     char c;
1213
1214     /* XXX:  if the input device it not a tty (e.g. /dev/null)
1215      *       mouse events are not processed. This is necessary
1216      *       as on some systems /dev/null is not selectable.
1217      */
1218     if (GGIvisual) {
1219         fd_set fds;
1220         int fd = fileno(stdin);
1221         int i, j;
1222         do {
1223             int n;
1224
1225             ggi_event_mask mask = emAll; /* TODO: choose a more selective mask */
1226             ggiSetEventMask(GGIvisual, mask);
1227
1228             FD_ZERO(&fds);
1229             FD_SET(fd, &fds); /* listen to stdin */
1230
1231             if (GGI_needs_update) {
1232                 /* draw the ruler below the other items */
1233                 GGI_draw_ruler();
1234
1235                 /* update the zoombox */
1236                 GGI_draw_zoombox();
1237                 for (i = 0; i < 2; i++) {
1238                     for (j = 0; j < 2; j++) {
1239                         GGI_save_puts(&(GGI_zoom[i][j]), GGI_saved_canvas);
1240                     }
1241                 }
1242
1243                 /* update the status line */
1244                 GGI_save_puts(&GGI_stl_vertex, GGI_saved_stl);
1245
1246                 ggiFlush(GGIvisual);
1247
1248                 GGI_needs_update = 0;
1249             }
1250
1251             n = ggiEventSelect(GGIvisual, &mask, fd + 1,
1252                 SELECT_TYPE_ARG234 &fds, 0, 0, (struct timeval*)0);
1253
1254             if (mask) {
1255                 ggi_event event;
1256                 /* mask pointer motions and key repeat events,
1257                  * to they don't pile up */
1258                 ggiEventRead(GGIvisual, &event, mask);
1259                 ggiRemoveEventMask(GGIvisual, emPtrMove | emKeyRepeat);
1260                 if ('q' == GGI_dispatch_event(&event)) {
1261                     term_reset();
1262                     break;
1263                 } else {
1264                     ggiAddEventMask(GGIvisual, emPtrMove | emKeyRepeat);
1265                 }
1266             }
1267
1268         } while (!FD_ISSET(fd, &fds) && GGIvisual);
1269     }
1270
1271     if (read(0, &c, 1)!=1) return EOF;
1272     else return c;
1273 }
1274
1275 TERM_PUBLIC void
1276 GGI_put_tmptext(int i, const char str[])
1277 {
1278     char* second;
1279
1280     switch (i) {
1281         case 0: /* statusline text */
1282
1283             if (!str || !(*str)) {
1284                 /* statusline is empty. This is the case,
1285                  * if the mouse was just turned off. */
1286                 if (GGI_use_mouse) {
1287                     /* The user just toggled of the mouse. */
1288                     GGI_use_mouse = 0;
1289                     GGI_set_size();
1290                     GGI_replot();
1291                 }
1292             } else {
1293                 /* statusline is non-empty */
1294                 if (!GGI_use_mouse) {
1295                     /* The mouse was off before and was just turned on. */
1296                     GGI_use_mouse = 1;
1297                     GGI_set_size();
1298                     GGI_replot();
1299                 }
1300                 GGI_save_frame_stl();
1301                 GGI_set_vertex(&GGI_stl_vertex, 0, GGIcanvas_height, str, GGI_saved_stl);
1302             }
1303             break;
1304
1305         case 1: /* coordinate text for first  corner of zoombox */
1306         case 2: /* coordinate text for second corner of zoombox */
1307             GGI_save_frame_canvas();
1308             second = (char*) strchr(str, '\r');
1309             --i; /* transform to [0, 1] */
1310             GGI_clear_zoombox();
1311             if (second == NULL) {
1312                 /* remove box and / or coordinates */
1313                 GGI_set_vertex(&(GGI_zoom[i][0]), 0, 0, (char*)0, GGI_saved_canvas);
1314                 GGI_set_vertex(&(GGI_zoom[i][1]), 0, 0, (char*)0, GGI_saved_canvas);
1315                 break;
1316             } else {
1317                 *second = '\0'; /* XXX this assumes that str is writable XXX */
1318                 second++;
1319                 GGI_set_vertex(&(GGI_zoom[i][0]), GGI_mouse_x, GGI_mouse_y - GGI_font_height - 1, str, GGI_saved_canvas);
1320                 GGI_set_vertex(&(GGI_zoom[i][1]), GGI_mouse_x, GGI_mouse_y + 1, second, GGI_saved_canvas);
1321                 GGI_zoombox[i].x = GGI_mouse_x;
1322                 GGI_zoombox[i].y = GGI_mouse_y;
1323             }
1324             break;
1325     }
1326     GGI_needs_update++;
1327 }
1328
1329 TERM_PUBLIC void
1330 GGI_set_ruler(int x, int y)
1331 {
1332     if (x < 0) {
1333
1334         /* turn ruler off */
1335         GGI_clear_hline(0, GGIwidth, GGI_ruler.y);
1336         GGI_clear_vline(0, GGIcanvas_height, GGI_ruler.x);
1337         GGI_ruler.x = -1;
1338         GGI_ruler.y = -1;
1339
1340     } else {
1341         GGI_ruler.x = x;
1342         GGI_ruler.y = GGI_y(y);
1343     }
1344     GGI_needs_update++;
1345 }
1346
1347 TERM_PUBLIC void
1348 GGI_set_cursor(int c, int x, int y)
1349 {
1350     /* TODO */
1351     switch (c) {
1352         case 0:
1353             GGI_abort_zooming();
1354             break;
1355         case 1:
1356         case 2:
1357         case 3:
1358         default:
1359             /* XXX not implemented */
1360             break;
1361     }
1362     GGI_needs_update++;
1363 }
1364
1365 TERM_PUBLIC void
1366 GGI_set_clipboard(const char s[])
1367 {
1368     /* XXX: not implemented */
1369     (void) s;                   /* avoid -Wunused */
1370 }
1371
1372 #endif
1373
1374 TERM_PUBLIC int
1375 GGI_make_palette(t_sm_palette *palette)
1376 {
1377     /* reallocate only, if it has changed */
1378     if (palette && (GGI_save_pal.colorFormulae < 0
1379             || palette->colorFormulae != GGI_save_pal.colorFormulae
1380             || palette->colorMode != GGI_save_pal.colorMode
1381             || palette->formulaR != GGI_save_pal.formulaR
1382             || palette->formulaG != GGI_save_pal.formulaG
1383             || palette->formulaB != GGI_save_pal.formulaB
1384             || palette->positive != GGI_save_pal.positive)) {
1385         int i;
1386         ggi_color color;
1387         for (i = 0; i < ggi_pm3d_colors; i++) {
1388             color.r = (short)floor(palette->color[i].r * 0xffff),
1389             color.g = (short)floor(palette->color[i].g * 0xffff),
1390             color.b = (short)floor(palette->color[i].b * 0xffff),
1391             GGI_smooth_colors[i] = ggiMapColor(GGIvisual, &color);
1392         }
1393         GGI_save_pal = *palette;
1394     } else {
1395         return ggi_pm3d_colors;
1396     }
1397     return 0;
1398 }
1399
1400 TERM_PUBLIC void
1401 GGI_previous_palette()
1402 {
1403 #if 0
1404 #ifdef ENABLE_XMI
1405     fprintf(stderr, "(GGI_previous_palette) \n");
1406     if (GGI_miPaintedSet) {
1407         miPoint offset;
1408         offset.x = 0; offset.y = 0;
1409         miCopyPaintedSetToVisual(GGIvisual, GGI_miGC, GGI_miPaintedSet, offset);
1410         miClearPaintedSet(GGIvisual, GGI_miPaintedSet);
1411     }
1412 #endif
1413 #endif
1414 }
1415
1416 TERM_PUBLIC void
1417 GGI_set_color(struct t_colorspec *colorspec)
1418 {
1419     ggi_color rgb;
1420     double gray = colorspec->value;
1421
1422     if (colorspec->type == TC_RGB) {
1423         rgb.r = ((colorspec->lt >> 16) & 0xff) * (65535./255.);
1424         rgb.g = ((colorspec->lt >> 8) & 0xff) * (65535./255.);
1425         rgb.b = ((colorspec->lt) & 0xff) * (65535./255.);
1426         ggiSetGCForeground(GGIvisual, ggiMapColor(GGIvisual,&rgb));
1427     }
1428     
1429     if (colorspec->type != TC_FRAC)
1430         return;
1431
1432     if (GGIvisual) {
1433         int idx = (gray <= 0) ? 0 : (int)(gray * ggi_pm3d_colors);
1434         if (idx >= ggi_pm3d_colors)
1435             idx = ggi_pm3d_colors - 1;
1436         ggiSetGCForeground(GGIvisual, GGI_smooth_colors[idx]);
1437 #ifdef ENABLE_XMI
1438         GGI_miGC->pixels[1] = GGI_smooth_colors[idx];
1439 #endif
1440     }
1441 }
1442
1443 #ifdef ENABLE_XMI
1444 TERM_PUBLIC void
1445 GGI_filled_polygon(int points, gpiPoint *corners)
1446 {
1447     static miPoint offset = {0, 0};
1448     if (GGI_miPaintedSet) {
1449 #define MI_POINTS 4
1450         miPoint mi_corners[MI_POINTS];
1451         unsigned int i;
1452         if (MI_POINTS != points) {
1453             fprintf(stderr, "(GGI_filled_polygon) internal error %s:%d\n", __FILE__, __LINE__);
1454             return;
1455         }
1456         for (i = 0; i < MI_POINTS; i++) {
1457             mi_corners[i].x = corners[i].x;
1458             mi_corners[i].y = GGI_y(corners[i].y);
1459         }
1460         miFillPolygon(GGIvisual, GGI_miPaintedSet, GGI_miGC,
1461             MI_SHAPE_GENERAL, MI_COORD_MODE_ORIGIN, MI_POINTS, mi_corners);
1462         miCopyPaintedSetToVisual(GGIvisual, GGI_miGC, GGI_miPaintedSet, offset);
1463         miClearPaintedSet(GGIvisual, GGI_miPaintedSet);
1464     }
1465 }
1466 #endif
1467
1468 #endif /* TERM_BODY */
1469
1470 #ifdef TERM_TABLE
1471
1472 TERM_TABLE_START(ggi_driver)
1473     "ggi", "GGI target",
1474     GGI_XMAX, GGI_YMAX, GGI_VCHAR, GGI_HCHAR, GGI_VTIC, GGI_HTIC,
1475     GGI_options, GGI_init, GGI_reset, GGI_text,
1476     null_scale, GGI_graphics, GGI_move, GGI_vector,
1477     GGI_linetype, GGI_put_text,
1478     0, /* angle */
1479     0, /* justify text */
1480     0, /* point */
1481     0, /* arrow */
1482     0, /* set_font */
1483     0, /* set_pointsize */
1484     TERM_CAN_MULTIPLOT,
1485     GGI_suspend,
1486     GGI_resume,
1487     GGI_fillbox,
1488     0 /* linewidth */
1489 #ifdef USE_MOUSE
1490     , GGI_waitforinput, GGI_put_tmptext, GGI_set_ruler, GGI_set_cursor, GGI_set_clipboard
1491 #endif
1492     , GGI_make_palette,
1493     GGI_previous_palette,
1494     GGI_set_color,
1495 #ifdef ENABLE_XMI
1496     GGI_filled_polygon
1497 #else
1498     0 /* GGI_filled_polygon */
1499 #endif
1500 TERM_TABLE_END(ggi_driver)
1501
1502 #endif /* TERM_TABLE */
1503 #endif /* TERM_PROTO_ONLY */
1504
1505 #ifdef TERM_HELP
1506 START_HELP(ggi)
1507 "1 ggi",
1508 "?commands set terminal ggi",
1509 "?set terminal ggi",
1510 "?set term ggi",
1511 "?terminal ggi",
1512 "?term ggi",
1513 "?ggi",
1514 " The `ggi` driver can run on different targets as X or svgalib.",
1515 "",
1516 " Syntax:",
1517 "    set terminal ggi [acceleration <integer>] [[mode] {mode}]",
1518 "",
1519 " In X the window cannot be resized using window manager handles, but the",
1520 " mode can be given with the mode option, e.g.:",
1521 "  - V1024x768",
1522 "  - V800x600",
1523 "  - V640x480",
1524 "  - V320x200",
1525 " Please refer to the ggi documentation for other modes. The 'mode' keyword",
1526 " is optional. It is recommended to select the target by environment variables",
1527 " as explained in the libggi manual page. To get DGA on X, you should for",
1528 " example",
1529 "    bash> export GGI_DISPLAY=DGA",
1530 "    csh>  setenv GGI_DISPLAY DGA",
1531 "",
1532 " 'acceleration' is only used for targets which report relative pointer",
1533 " motion events (e.g. DGA) and is a strictly positive integer multiplication",
1534 " factor for the relative distances.  The default for acceleration is 7.",
1535 "",
1536 " Examples:",
1537 "    set term ggi acc 10",
1538 "    set term ggi acc 1 mode V1024x768",
1539 "    set term ggi V1024x768"
1540 END_HELP(ggi)
1541 #endif