1 /* Hello, Emacs, this is -*-C-*-
2 * $Id: ggi.trm,v 1.26.2.1 2008/06/26 23:16:55 sfeam Exp $
5 /* GNUPLOT - ggi.trm */
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.
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,
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
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.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
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)
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.
66 # include <ggi/ggi-unix.h>
71 static TBOOLEAN GGI_use_whm = 0;
75 #if defined(HAVE_GGI_XMI_H)
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));
103 /* zoom box information */
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 */
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));
150 TERM_PUBLIC void GGI_filled_polygon __PROTO((int, gpiPoint*));
153 #define GOT_GGI_PROTO
156 #ifndef TERM_PROTO_ONLY
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}};
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;
186 static t_sm_palette GGI_save_pal = {
187 -1, -1, -1, -1, -1, -1, -1, -1,
188 (rgb_color*) 0, -1, -1
191 /* First to some global variables
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
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;
212 static unsigned int Xenv;
214 static int GGI_frames =
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];
230 static TBOOLEAN GGI_mode_changed = 1;
231 static char GGI_mode_spec[0xff] = "";
232 static int GGI_acceleration = 7; /* arbitrary */
240 static struct gen_table GGI_opts[] =
242 { "mo$de", GGI_MODE },
243 { "ac$celeration", GGI_ACCELERATION },
250 ggi_pixel GGIwhite,GGIred,GGIgreen,GGIblue,GGIcyan,GGImagenta,GGIgray;
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);
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;
275 /* Called bevore a graphic is displayed */
276 TERM_PUBLIC void GGI_graphics()
280 int display_frame = ggiGetDisplayFrame(GGIvisual);
289 ggiSetGCForeground(GGIvisual,GGIblack);
291 /* write to the currently not displayed buffer */
292 ggiSetWriteFrame(GGIvisual, !display_frame);
294 /* mark the contents of the alternate frame as invalid */
295 GGI_saved_canvas = 0;
297 GGI_needs_update = 1;
299 /* reset the stl vertex */
300 GGI_stl_vertex.width = 0;
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;
307 GGI_zoombox[i].x = -1;
308 GGI_zoombox[i].y = -1;
310 #endif /* USE_MOUSE */
312 /* clear *write* buffer. */
313 ggiDrawBox(GGIvisual, 0, 0, GGIwidth, GGIheight);
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);
331 ggiGetMode(GGIvisual,&mode);
333 GGIwidth = mode.virt.x;
334 GGIheight = mode.virt.y;
336 term->xmax = mode.virt.x - 1;
339 GGIcanvas_height = mode.virt.y - (GGI_use_mouse ? GGI_font_height : 0);
340 term->ymax = GGIcanvas_height - 1;
342 term->ymax = mode.virt.y - 1;
344 GGIymax = term->ymax;
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).
353 TERM_PUBLIC void GGI_init()
359 if (0 != giiInit()) {
360 ggiPanic("*** giiInit() failed *** \n");
364 if (0 != ggiInit()) {
365 ggiPanic("*** ggiInit() failed *** \n");
368 if (NULL == (GGIvisual = ggiOpen(NULL))) {
369 /* TODO: abort a bit more gracefully */
370 ggiPanic("(GGI_init() unable to open default\n");
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)) {
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;
391 ggiGetMode(GGIvisual, &mode);
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");
401 /* must come before GGI_set_size() */
402 ggiGetCharSize(GGIvisual, &GGI_font_width, &GGI_font_height);
409 ggiSetReadFrame(GGIvisual, 0);
410 ggiSetWriteFrame(GGIvisual, 0);
411 ggiSetDisplayFrame(GGIvisual, 0);
414 #ifdef HAVE_GGI_WMH_H
415 /* Initialize WMH extension */
416 if (ggiWmhInit() != 0 || ggiWmhAttach(GGIvisual) < 0) {
420 ggiWmhAllowResize(GGIvisual, 100, 50, 2000, 2000, 10, 10);
421 ggiWmhSetTitle(GGIvisual, "GGI Gnuplot Driver");
422 ggiWmhSetIconTitle(GGIvisual, "Gnuplot");
427 * if(!(Xenv=!ggiWmhAttach(GGIvisual))) ggiWmhDetach(GGIvisual);
428 * else Xenv=!ggiWmhSetTitle(GGIvisual,"GGI Gnuplot Driver");
434 * ggiWmhDetach(GGIvisual);
443 ggiSetFlags(GGIvisual, GGIFLAG_ASYNC);
451 gettimeofday(&tv, &tz);
452 GGI_SetTime(&tv); /* initialize time */
457 if (0 != xmiInit()) {
458 /* TODO: abort a bit more gracefully */
459 ggiPanic("(GGI_init() unable to initialize xmi\n");
462 if (xmiAttach(GGIvisual) < 0) {
463 ggiPanic("(GGI_init) Unable to attach XMI extension to visual\n");
467 if (GGI_miPaintedSet) {
468 miDeletePaintedSet(GGIvisual, GGI_miPaintedSet);
469 GGI_miPaintedSet = (miPaintedSet*)0;
471 GGI_miPaintedSet = miNewPaintedSet(GGIvisual);
472 miClearPaintedSet(GGIvisual, GGI_miPaintedSet);
476 miDeleteGC(GGIvisual, GGI_miGC);
479 GGI_miGC = miNewGC(GGIvisual, 2,
480 GGI_miPixels, GGI_numblendstages, GGI_blendstages);
482 setvbuf(stdin, (char*)0, _IONBF, 0);
485 TERM_PUBLIC void GGI_linetype(int linetype)
487 if(linetype == LT_BLACK)
488 ggiSetGCForeground(GGIvisual,GGIborderColor);
489 if(linetype == LT_AXIS)
490 ggiSetGCForeground(GGIvisual,GGIaxisColor);
495 ggiSetGCForeground(GGIvisual,GGIcolors[linetype]);
498 TERM_PUBLIC void GGI_move(unsigned int x, unsigned int y)
507 while (!END_OF_COMMAND) {
508 switch(lookup_table(&GGI_opts[0], c_token)) {
509 case GGI_ACCELERATION:
515 itmp = (int) real(const_express(&a));
517 fprintf(stderr, "acceleration must be strictly positive!\n");
519 GGI_acceleration = itmp;
527 if (!END_OF_COMMAND) {
528 copy_str(GGI_mode_spec, c_token, 0xfe);
529 GGI_mode_changed = 1;
534 } /* while(command) */
536 if (*GGI_mode_spec) {
537 sprintf(term_options, "mode %s acceleration %d",
538 GGI_mode_spec, GGI_acceleration);
540 sprintf(term_options, "acceleration %d", GGI_acceleration);
548 /* DETACH EXTENSIONS */
551 ggiWmhDetach(GGIvisual);
555 xmiDetach(GGIvisual);
559 GGIvisual = (ggi_visual_t)0;
561 /* EXIT EXTENSIONS */
573 /* Called when terminal is terminated i.e.
574 * when switching to another terminal. */
578 if(GGIvisual!=NULL) {
581 # if 0 /* not needed */
582 GGI_save_pal.colorFormulae = -1; /* force later reallocation of palette */
587 GGI_put_text(unsigned int x, unsigned int y, const char *str)
589 ggi_pixel current_foreground;
590 ggiGetGCForeground(GGIvisual,¤t_foreground);
591 ggiSetGCForeground(GGIvisual,GGIborderColor);
592 ggiPuts(GGIvisual,x,GGI_y(y) - 4 /* ? (joze ? */,str);
593 ggiSetGCForeground(GGIvisual,current_foreground);
599 /* this fails on the console */
612 unsigned int x, unsigned int y,
613 unsigned int w, unsigned int h)
615 ggiDrawBox(GGIvisual, x, GGI_y((int)(y+h)), w, h);
623 /* now display the buffer which was just written */
624 ggiSetDisplayFrame(GGIvisual, ggiGetWriteFrame(GGIvisual));
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 */
636 GGI_vector(unsigned int x, unsigned int y)
639 ggiDrawLine(GGIvisual,GGIx,GGIy,x,y);
646 /* translate ggi keysym to gnuplot keysym */
648 GGI_from_keysym(uint32_t keysym)
651 case GIIUC_BackSpace:
663 case GIIK_ScrollLock:
664 return GP_Scroll_Lock;
709 return GP_KP_Insert; /* ~ KP_0 */
711 return GP_KP_End; /* ~ KP_1 */
713 return GP_KP_Down; /* ~ KP_2 */
715 return GP_KP_Page_Down; /* ~ KP_3 */
717 return GP_KP_Left; /* ~ KP_4 */
719 return GP_KP_Begin; /* ~ KP_5 */
721 return GP_KP_Right; /* ~ KP_6 */
723 return GP_KP_Home; /* ~ KP_7 */
725 return GP_KP_Up; /* ~ KP_8 */
727 return GP_KP_Page_Up; /* ~ KP_9 */
737 return GP_KP_Multiply;
740 case GIIK_PSeparator:
741 return GP_KP_Separator;
743 return GP_KP_Subtract;
745 return GP_KP_Decimal;
796 /* return it untranslated */
802 GGI_SetTime(const struct timeval* current)
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;
809 GGI_timestamp = *current;
814 GGI_from_button(uint32_t button)
817 case GII_PBUTTON_LEFT:
819 case GII_PBUTTON_MIDDLE:
821 case GII_PBUTTON_RIGHT:
824 /* should not happen */
836 GGI_eventually_update_modifiers(const ggi_event* event, const int add)
839 int old_modifiers = GGI_modifiers;
841 switch (event->key.sym) {
857 GGI_modifiers |= mod;
859 GGI_modifiers &= ~mod;
862 if (GGI_modifiers != old_modifiers) {
864 struct gp_event_t gp_ev;
866 gp_ev.type = GE_modifier;
867 gp_ev.mx = GGI_mouse_x;
868 gp_ev.my = GGI_y(GGI_mouse_y);
871 gp_ev.par1 = GGI_modifiers;
880 GGI_dispatch_event(const ggi_event* event)
882 struct gp_event_t gp_ev;
885 gp_ev.mx = GGI_mouse_x;
886 gp_ev.my = GGI_y(GGI_mouse_y);
890 switch (event->any.type) {
892 /* [-- KEY EVENTS --] */
895 if (GGI_eventually_update_modifiers(event, 1)) {
896 /* was just a modifier pressed */
899 gp_ev.type = GE_keypress;
900 gp_ev.par1 = GGI_from_keysym(event->key.sym);
901 if ('q' == gp_ev.par1) {
906 if (GGI_eventually_update_modifiers(event, 0)) {
907 /* was just a modifier pressed */
912 /* [-- POINTER EVENTS --] */
914 /* relative motion is not implemented. Should it ? */
916 * fprintf(stderr, "%s:%d report this to <johannes@zellner.org> %d %d\n",
917 * __FILE__, __LINE__, event->pmove.x, event->pmove.y);
919 gp_ev.type = GE_motion;
920 GGI_mouse_x += GGI_acceleration * event->pmove.x;
921 GGI_mouse_y += GGI_acceleration * event->pmove.y;
924 gp_ev.type = GE_motion;
925 GGI_mouse_x = event->pmove.x;
926 GGI_mouse_y = event->pmove.y;
928 case evPtrButtonPress:
929 gp_ev.type = GE_buttonpress;
930 gp_ev.par1 = GGI_from_button(event->pbutton.button);
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));
937 #ifdef HAVE_GGI_WMH_H
939 /* [-- resizing --] */
941 /* fprintf(stderr, "(GGI_dispatch_event) \n"); */
942 if (event->cmd.code==GGICMD_REQUEST_SWITCH) {
944 * ggi_cmddata_switchrequest *req;
945 * req = &(event->cmd.data);
946 * ggi_resize(GGIvisual, &(req->mode));
949 * while( ggiEventPoll(GGIvisual, emAll, &tv) ) {
950 * ggiEventRead(GGIvisual, event, emAll);
958 /* fprintf(stderr, "(GGI_dispatch_event) unhandled event\n"); */
962 gp_ev.type = GE_plotdone;
967 /* save currently displayed frame to alternate buffer */
969 GGI_save_frame_canvas()
971 if (!GGI_saved_canvas && GGIvisual) {
972 int display_frame = ggiGetDisplayFrame(GGIvisual);
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);
979 /* write again directly to the display frame */
980 ggiSetWriteFrame(GGIvisual, display_frame);
982 /* remember that the alternate frame is valid */
983 GGI_saved_canvas = 1;
990 if (!GGI_saved_stl) {
991 int display_frame = ggiGetDisplayFrame(GGIvisual);
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);
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);
1013 struct gp_event_t ev = {
1022 GGI_clear(const GGI_vertex_t* v, const int tag)
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);
1032 GGI_save_puts(GGI_vertex_t* v, const int tag)
1038 /* draw the text in the axis color (gray) */
1039 ggiSetGCForeground(GGIvisual, GGIaxisColor);
1041 /* write the string directly to the display */
1042 ggiPuts(GGIvisual, v->x, v->y, v->str);
1059 v->height = GGI_font_height;
1062 v->width = strlen(str) * GGI_font_width;
1063 strcpy(v->str, str);
1065 /* turn string off */
1072 GGI_relative(int r[2])
1074 int diff = r[1] - r[0];
1084 GGI_clear_hline(int x1, int x2, int y)
1086 if (GGI_saved_canvas && x1 >= 0 && x2 >= 0 && y >= 0) {
1088 ggiSetReadFrame(GGIvisual, !ggiGetDisplayFrame(GGIvisual));
1093 /* horizontal line */
1094 ggiCopyBox(GGIvisual, r[0], y, r[1], 1, r[0], y);
1099 GGI_clear_vline(int y1, int y2, int x)
1101 if (GGI_saved_canvas && y1 >= 0 && y2 >= 0 && x >= 0) {
1103 ggiSetReadFrame(GGIvisual, !ggiGetDisplayFrame(GGIvisual));
1109 ggiCopyBox(GGIvisual, x, r[0], 1, r[1], x, r[0]);
1114 GGI_draw_hline(int x1, int x2, int y)
1116 if (x1 >= 0 && x2 >= 0 && y >= 0) {
1122 /* horizontal line */
1123 ggiDrawHLine(GGIvisual, r[0], y, r[1]);
1128 GGI_draw_vline(int y1, int y2, int x)
1130 if (y1 >= 0 && y2 >= 0 && x >= 0) {
1137 ggiDrawVLine(GGIvisual, x, r[0], r[1]);
1144 if (GGI_ruler.x >= 0 && GGI_ruler.y >= 0) {
1145 ggi_pixel current_foreground;
1147 GGI_save_frame_canvas();
1149 /* TODO: we could choose a nicer color here */
1150 ggiGetGCForeground(GGIvisual, ¤t_foreground);
1151 ggiSetGCForeground(GGIvisual, GGIaxisColor);
1153 ggiDrawHLine(GGIvisual, 0, GGI_ruler.y, GGIwidth);
1154 ggiDrawVLine(GGIvisual, GGI_ruler.x, 0, GGIcanvas_height);
1156 /* restore old foreground color */
1157 /* XXX need this ? */
1158 ggiSetGCForeground(GGIvisual, current_foreground);
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);
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;
1178 GGI_save_frame_canvas();
1180 /* TODO: we could choose a nicer color here */
1181 ggiGetGCForeground(GGIvisual, ¤t_foreground);
1182 ggiSetGCForeground(GGIvisual, GGIaxisColor);
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);
1189 /* restore old foreground color */
1190 /* XXX need this ? */
1191 ggiSetGCForeground(GGIvisual, current_foreground);
1198 /* empty string: finish zooming */
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);
1205 GGI_zoombox[i].x = -1;
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.
1220 int fd = fileno(stdin);
1225 ggi_event_mask mask = emAll; /* TODO: choose a more selective mask */
1226 ggiSetEventMask(GGIvisual, mask);
1229 FD_SET(fd, &fds); /* listen to stdin */
1231 if (GGI_needs_update) {
1232 /* draw the ruler below the other items */
1235 /* update the 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);
1243 /* update the status line */
1244 GGI_save_puts(&GGI_stl_vertex, GGI_saved_stl);
1246 ggiFlush(GGIvisual);
1248 GGI_needs_update = 0;
1251 n = ggiEventSelect(GGIvisual, &mask, fd + 1,
1252 SELECT_TYPE_ARG234 &fds, 0, 0, (struct timeval*)0);
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)) {
1264 ggiAddEventMask(GGIvisual, emPtrMove | emKeyRepeat);
1268 } while (!FD_ISSET(fd, &fds) && GGIvisual);
1271 if (read(0, &c, 1)!=1) return EOF;
1276 GGI_put_tmptext(int i, const char str[])
1281 case 0: /* statusline text */
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. */
1293 /* statusline is non-empty */
1294 if (!GGI_use_mouse) {
1295 /* The mouse was off before and was just turned on. */
1300 GGI_save_frame_stl();
1301 GGI_set_vertex(&GGI_stl_vertex, 0, GGIcanvas_height, str, GGI_saved_stl);
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);
1317 *second = '\0'; /* XXX this assumes that str is writable XXX */
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;
1330 GGI_set_ruler(int x, int y)
1334 /* turn ruler off */
1335 GGI_clear_hline(0, GGIwidth, GGI_ruler.y);
1336 GGI_clear_vline(0, GGIcanvas_height, GGI_ruler.x);
1342 GGI_ruler.y = GGI_y(y);
1348 GGI_set_cursor(int c, int x, int y)
1353 GGI_abort_zooming();
1359 /* XXX not implemented */
1366 GGI_set_clipboard(const char s[])
1368 /* XXX: not implemented */
1369 (void) s; /* avoid -Wunused */
1375 GGI_make_palette(t_sm_palette *palette)
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)) {
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);
1393 GGI_save_pal = *palette;
1395 return ggi_pm3d_colors;
1401 GGI_previous_palette()
1405 fprintf(stderr, "(GGI_previous_palette) \n");
1406 if (GGI_miPaintedSet) {
1408 offset.x = 0; offset.y = 0;
1409 miCopyPaintedSetToVisual(GGIvisual, GGI_miGC, GGI_miPaintedSet, offset);
1410 miClearPaintedSet(GGIvisual, GGI_miPaintedSet);
1417 GGI_set_color(struct t_colorspec *colorspec)
1420 double gray = colorspec->value;
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));
1429 if (colorspec->type != TC_FRAC)
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]);
1438 GGI_miGC->pixels[1] = GGI_smooth_colors[idx];
1445 GGI_filled_polygon(int points, gpiPoint *corners)
1447 static miPoint offset = {0, 0};
1448 if (GGI_miPaintedSet) {
1450 miPoint mi_corners[MI_POINTS];
1452 if (MI_POINTS != points) {
1453 fprintf(stderr, "(GGI_filled_polygon) internal error %s:%d\n", __FILE__, __LINE__);
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);
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);
1468 #endif /* TERM_BODY */
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,
1479 0, /* justify text */
1483 0, /* set_pointsize */
1490 , GGI_waitforinput, GGI_put_tmptext, GGI_set_ruler, GGI_set_cursor, GGI_set_clipboard
1493 GGI_previous_palette,
1498 0 /* GGI_filled_polygon */
1500 TERM_TABLE_END(ggi_driver)
1502 #endif /* TERM_TABLE */
1503 #endif /* TERM_PROTO_ONLY */
1508 "?commands set terminal ggi",
1509 "?set terminal ggi",
1514 " The `ggi` driver can run on different targets as X or svgalib.",
1517 " set terminal ggi [acceleration <integer>] [[mode] {mode}]",
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.:",
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",
1529 " bash> export GGI_DISPLAY=DGA",
1530 " csh> setenv GGI_DISPLAY DGA",
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.",
1537 " set term ggi acc 10",
1538 " set term ggi acc 1 mode V1024x768",
1539 " set term ggi V1024x768"