Initial release of Maemo 5 port of gnuplot
[gnuplot] / term / pm.trm
1 /* Hello, Emacs, this is -*-C-*-
2  * $Id: pm.trm,v 1.53 2006/07/21 02:35:47 sfeam Exp $
3  */
4
5 /* GNUPLOT - pm.trm */
6
7 /*[
8  * Copyright 1992, 1993, 1998, 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  *    pm.trm  --- inboard terminal driver for Presentation Manager
39  *            --- after X-11 driver, by R.W.Fearick 31/1/92.
40  *    v1.1 11/8/92 -- speed things up
41  *
42  *    since March 1998: additions for mouse support implemented by Petr Mikulik
43  *       last change: January 2000
44  *       for mouse support, pm.trm has to be compiled with USE_MOUSE, e.g.
45  *       gcc ... -DUSE_MOUSE ...
46  *    January 1999: terminal entries for PM3D functionality by Petr Mikulik
47  */
48
49 #include "driver.h"
50
51 #ifdef TERM_REGISTER
52 register_term(pm)
53 #endif
54
55 #ifdef TERM_PROTO
56 TERM_PUBLIC void PM_init __PROTO((void));
57 TERM_PUBLIC void PM_options __PROTO((void));
58 TERM_PUBLIC void PM_reset __PROTO((void));
59 TERM_PUBLIC void PM_text __PROTO((void));
60 TERM_PUBLIC void PM_graphics __PROTO((void));
61 TERM_PUBLIC void PM_linetype __PROTO((int lt));
62 TERM_PUBLIC void PM_move __PROTO((unsigned int x, unsigned int y));
63 TERM_PUBLIC void PM_vector __PROTO((unsigned int x, unsigned int y));
64 TERM_PUBLIC int PM_text_angle __PROTO((int ang));
65 TERM_PUBLIC void PM_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
66 TERM_PUBLIC int PM_justify_text __PROTO((enum JUSTIFY mode));
67 TERM_PUBLIC void PM_point __PROTO((unsigned int x, unsigned int y, int number));
68 TERM_PUBLIC void PM_suspend __PROTO((void));
69 TERM_PUBLIC void PM_resume __PROTO((void));
70 TERM_PUBLIC void PM_fillbox __PROTO((int style, unsigned int x, unsigned int y, unsigned int w, unsigned int h));
71 TERM_PUBLIC void PM_linewidth __PROTO((double linewidth));
72 #ifdef USE_MOUSE
73 TERM_PUBLIC void PM_set_ruler __PROTO((int, int));
74 TERM_PUBLIC void PM_set_cursor __PROTO((int, int, int));
75 TERM_PUBLIC void PM_put_tmptext __PROTO((int, const char str[]));
76 TERM_PUBLIC void PM_set_clipboard __PROTO((const char[]));
77 #endif
78 TERM_PUBLIC int PM_make_palette (t_sm_palette *);
79 #if 0
80 TERM_PUBLIC void PM_previous_palette (void);
81 #endif
82 TERM_PUBLIC void PM_set_color (t_colorspec *);
83 TERM_PUBLIC void PM_filled_polygon (int, gpiPoint *);
84 #ifdef WITH_IMAGE
85 TERM_PUBLIC void PM_image __PROTO((unsigned int, unsigned int, coordval *, gpiPoint *, t_imagecolor));
86 #endif
87 #ifndef PM_OLD_ENHANCED_TEXT
88 /* To support "set term pm enhanced" */
89 TERM_PUBLIC void PM_enhanced_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
90 TERM_PUBLIC void PM_enhanced_open __PROTO((char * fontname, double fontsize,
91                         double base, TBOOLEAN widthflag, TBOOLEAN showflag,
92                         int overprint));
93 TERM_PUBLIC void PM_enhanced_flush __PROTO((void));
94 #endif
95
96 /* define PM world coordinate limits */
97
98 #define PM_XMAX 19500
99 #define PM_YMAX 12500
100
101 /* approximations for typical font/screen sizes */
102 #define PM_VCHAR (550)
103 #define PM_HCHAR (220)
104 /* Note: VCHAR AND HCHAR sizes in gnuplot 3.5 were 415 and 242,
105    in X11 are 500 and 195, respectively.
106 */
107 #if 0 /* Sizes of gnuplot 3.6 and 3.7: */
108 #  define PM_VTIC (200)
109 #  define PM_HTIC (200)
110 #else /* Sizes as X11: */
111 #  define PM_VTIC (125)
112 #  define PM_HTIC (130)
113 /* Note: sizes for VTIC and HTIC in gnuplot 3.5 were 122 and 128, respectively.
114 */
115 #endif
116
117 #endif
118
119 #ifdef TERM_BODY
120
121 #include <stdio.h>
122 #include <process.h>
123 #include <io.h>
124 #define INCL_DOSPROCESS
125 #define INCL_DOSSEMAPHORES
126 #define INCL_DOSMISC
127 #define INCL_DOSMODULEMGR
128 #include <os2.h>
129 #include "os2/pm_msgs.h"
130         
131 #define PM_nopts 1
132
133 /* path for pm program */
134 static char PM_path[256] = "";
135 /* track mode to avoid redraw after hitting break */
136 static int PM_mode = 0;
137 static HEV hev;
138 static int PM_termmode = 0;
139 static int PM_must_reset_opts = FALSE;
140 static int PM_must_abort = 0;
141
142 static char PM_opts[256] = "";
143 static int PM_optargs = 0;
144 static int PM_plot_number = 0;
145 static char PM_term_title[128] = "";
146
147 static int mouseGnupmdrv = 0; /* PM set to 1 if we are connected to a mouseable gnupmdrv */
148
149 static FILE *PM_pipe = NULL;
150 static FILE *PM_savepipe = NULL;
151
152
153 #ifndef PM_OLD_ENHANCED_TEXT
154
155 /* track current state of pm terminal */
156 /* this is only needed for enhanced text */
157 static char * PM_font = NULL; 
158 static double PM_fontsize = 12.0;
159 static unsigned int PM_x = 0;
160 static unsigned int PM_y = 0;
161 static enum JUSTIFY PM_justification = LEFT;
162 static double PM_angle = 0.;  /* unit is radian */
163
164 /* state variables for enhanced text processing */
165 static TBOOLEAN ENHpm_opened_string;
166 static TBOOLEAN ENHpm_show = TRUE;
167 static int ENHpm_overprint = 0;
168 static TBOOLEAN ENHpm_widthflag = TRUE;
169 static TBOOLEAN ENHpm_sizeonly = FALSE;
170 static double ENHpm_base;
171
172 #endif
173
174 static void PM_reset_opts(void);
175 static void PM_query(void);
176 static void PM_make_servername(char *);
177 static void PM_abortplot();
178 static void PM_query_font(void);
179
180
181 TERM_PUBLIC void
182 PM_init()
183 {
184     static char buffer[1024];
185     int pid;
186     int rc;
187     int spawnmode;
188     PPIB pib;
189     PTIB tib;
190     char semname[32];
191     char pipename[32];
192     char tempname[32];
193
194     term_force_init = TRUE;
195     if (PM_savepipe != NULL && PM_termmode == 0) {
196         PM_pipe = PM_savepipe;
197     }
198     if ((PM_pipe == NULL) && (PM_termmode & 2)) {
199         /* check if term is running */
200         PM_make_servername(tempname);
201         strcpy(pipename, "\\pipe\\");
202         strcat(pipename, tempname);
203 /*        sprintf( pipename, "\\pipe\\gpServ%d", PM_plot_number ) ; */
204         DosGetInfoBlocks(&tib, &pib);
205         PM_pipe = fopen(pipename, "r+b");
206         if (PM_pipe != NULL) {
207             setvbuf(PM_pipe, buffer, _IOFBF, 1024);
208             pid = pib->pib_ulpid;
209             fwrite(&pid, 1, 4, PM_pipe);
210             fflush(PM_pipe);
211             /* set new options */
212 /*            PM_reset_opts() ; */
213         }
214     }
215     /* else we start up term here */
216     if (PM_pipe == NULL) {
217         if (PM_termmode & 2) {
218             PM_make_servername(tempname);
219 /*            sprintf( tempname, "gpServ%d", PM_plot_number ) ; */
220         } else {
221             static int gpid = 0;
222             gpid++;
223             sprintf(tempname, "gp%X%d", getpid(), gpid);
224         }
225         strcpy(semname, "\\sem32\\");
226         strcpy(pipename, "\\pipe\\");
227         strcat(semname, tempname);
228         strcat(pipename, tempname);
229         strcat(PM_path, "\\gnupmdrv.exe");
230         rc = access(PM_path, 0);
231         /* find exe file */
232         if (rc != 0)
233             rc = DosSearchPath(0x0002,  /* search GNUPLOT environment */
234                                "GNUPLOT",
235                                "gnupmdrv.exe",
236                                PM_path,
237                                256);
238
239         if (rc != 0)
240             rc = DosSearchPath(0x0003,  /* then try current directory & path */
241                                "PATH",
242                                "gnupmdrv.exe",
243                                PM_path,
244                                256);
245         if (rc != 0) {
246             fputs("Cannot find gnupmdrv.exe !\n", stderr);
247             exit(3);
248         }
249         rc = DosCreateEventSem(semname, &hev, 1, 0);
250         if (rc != 0) {
251             fputs("Cannot create semaphore !\n", stderr);
252             exit(3);
253         }
254         spawnmode = P_SESSION | P_DEFAULT;
255         if (PM_optargs != 0)
256             spawnmode |= P_UNRELATED;
257         pid = spawnl(spawnmode, PM_path, PM_path, tempname, PM_opts, NULL);
258         if (pid == -1) {
259             fputs("Cannot spawn gnupmdrv.exe !\n", stderr);
260             exit(3);
261         }
262         DosGetInfoBlocks(&tib, &pib);
263         DosWaitEventSem(hev, 10000);
264         DosCloseEventSem(hev);
265         PM_pipe = fopen(pipename, "r+b");
266         if (PM_pipe == NULL) {
267             fputs("Cannot open pipe to gnupmdrv.exe !\n", stderr);
268             exit(3);
269         } else if (PM_termmode == 0)
270             PM_savepipe = PM_pipe;
271         setvbuf(PM_pipe, buffer, _IOFBF, 1024);
272         pid = pib->pib_ulpid;
273         fwrite(&pid, 1, 4, PM_pipe);
274         fflush(PM_pipe);
275     } else {
276         if (PM_must_reset_opts)
277             PM_reset_opts();
278     }
279 #ifdef USE_MOUSE
280     /* PM: notify gnupmdrv that this is mouse-enhanced terminal */
281     putc( GR_MOUSECAPABLE, PM_pipe ) ;
282     fflush( PM_pipe ) ;
283     /* we catch mouseable gnupmdrv's answer in PM_query by 0xABCD */
284 #endif
285     PM_query();
286 }
287
288
289 static void
290 PM_make_servername(char *str)
291 {
292     if (PM_term_title[0]) {
293         int hash = 0;
294         char *p = PM_term_title + 1;
295         int match = PM_term_title[0];
296         while (*p != match) {
297             hash = (hash << 1) + hash + *p++;
298         }
299         hash %= (256 * 256 * 256 - 1);
300         sprintf(str, "gp%x", hash);
301     } else
302         sprintf(str, "gpServ%d", PM_plot_number);
303 }
304
305
306 TERM_PUBLIC void
307 PM_options()
308 {
309     int old_termmode = PM_termmode;
310     PM_termmode = 0;
311     term_options[0] = NUL;
312     PM_term_title[0] = NUL;
313     PM_opts[0] = NUL;
314     PM_optargs = 0;
315     while (!END_OF_COMMAND) {
316         if (almost_equals(c_token, "pe$rsist")) {
317             strcat(PM_opts, "-p ");
318             strcat(term_options, "persist ");
319             PM_termmode |= 1;
320             PM_optargs = 1;
321             if (!(old_termmode & 1))
322                 PM_pipe = NULL;
323         } else if (almost_equals(c_token, "s$erver")) {
324             strcat(PM_opts, "-s ");
325             strcat(term_options, "server ");
326             PM_termmode |= 2;
327             PM_optargs = 1;
328             if (!(old_termmode & 2))
329                 PM_pipe = NULL;
330             if (isanumber(c_token + 1)) {
331                 struct value t;
332                 char *p = PM_opts + strlen(PM_opts);
333                 c_token++;
334                 PM_plot_number = (int) real(const_express(&t));
335                 sprintf(p, "%d", PM_plot_number);
336                 sprintf(term_options + strlen(term_options), "%d", PM_plot_number);
337             }
338         } else if (almost_equals(c_token, "w$idelines")) {
339             strcat(PM_opts, "-w ");
340             strcat(term_options, "widelines ");
341             PM_optargs = 1;
342         } else if (almost_equals(c_token, "e$nhanced")) {
343             strcat(term_options, "enhanced ");
344 #ifdef PM_OLD_ENHANCED_TEXT
345             PM_optargs = 1;
346             strcat(PM_opts, "-e ");
347             term->put_text = PM_put_text;
348 #else
349             term->put_text = PM_enhanced_put_text;
350 #endif
351             term->flags |= TERM_ENHANCED_TEXT;
352         } else if (almost_equals(c_token, "noe$nhanced")) {
353             strcat(term_options, "noenhanced ");
354             term->put_text = PM_put_text;
355             term->flags &= ~TERM_ENHANCED_TEXT;
356         } else if (isstring(c_token)) {
357             copy_str(PM_term_title, c_token, 127);
358         }
359 #if 0
360         else if (almost_equals(c_token, "po$rtrait")) {
361             strcat(PM_opts, "-l ");
362             strcat(term_options, "portrait ");
363             PM_optargs = 1;
364         }
365 #endif
366         c_token++;
367     }
368     if (PM_term_title[0]) {
369         strcat(PM_opts, " ");
370         strcat(term_options, " ");
371         strcat(PM_opts, PM_term_title);
372         strcat(term_options, PM_term_title);
373     }
374     PM_must_reset_opts = TRUE;
375 }
376
377
378 static void
379 PM_reset_opts()
380 {
381     int len;
382     putc(SET_OPTIONS, PM_pipe);
383     len = strlen(PM_opts) + 1;
384     fwrite(&len, sizeof(int), 1, PM_pipe);
385     fwrite(PM_opts, 1, len, PM_pipe);
386     for (len = sizeof(int) - len % sizeof(int); len > 0; len--) {
387         /* pad rest of int with zeros */
388         putc(NUL, PM_pipe);
389     }
390     fflush(PM_pipe);
391     PM_must_reset_opts = FALSE;
392 }
393
394
395 static void
396 PM_query()
397 {
398     int rc;
399     ULONG cbR;
400     putc(GR_QUERY, PM_pipe);
401     fflush(PM_pipe);
402     rc = DosRead(fileno(PM_pipe), &term->h_char, sizeof(int), &cbR);
403     if (term->h_char == 0xABCD) {
404       /* PM we have got greetings from mouseable gnupmdrv */
405       mouseGnupmdrv = 1; /*  thus set mouseGnupmdrv on and reread h_char */
406       rc = DosRead( fileno(PM_pipe), &term->h_char, sizeof(int), &cbR ) ;
407       }
408     rc = DosRead(fileno(PM_pipe), &term->v_char, sizeof(int), &cbR);
409 }
410
411
412 # ifdef USE_MOUSE
413 /* update menu items in PM terminal */
414 void
415 PM_update_menu_items()
416 {
417     /* connected to a mouseable gnupmdrv */
418     if ((PM_pipe != NULL) && (mouseGnupmdrv)) {
419         struct t_gpPMmenu gpPMmenu;
420
421         PM_set_gpPMmenu(&gpPMmenu);
422         putc(SET_MENU, PM_pipe);
423         fwrite(&gpPMmenu, sizeof(gpPMmenu), 1, PM_pipe);
424     }
425 }
426 #endif
427
428
429 TERM_PUBLIC void
430 PM_reset()
431 {
432     putc(GR_RESET, PM_pipe);
433     fflush(PM_pipe);
434     term_force_init = FALSE;
435     if (PM_termmode > 0) {
436         fclose(PM_pipe);
437         PM_pipe = NULL;
438     }
439 }
440
441
442 TERM_PUBLIC void
443 PM_suspend()
444 {
445     putc(GR_SUSPEND, PM_pipe);
446     fflush(PM_pipe);
447 }
448
449
450 TERM_PUBLIC void
451 PM_resume()
452 {
453     putc(GR_RESUME, PM_pipe);
454     fflush(PM_pipe);
455 }
456
457
458 TERM_PUBLIC void
459 PM_text()
460 {
461     fflush(PM_pipe);
462     if (PM_mode != SET_TEXT) {
463         putc(SET_TEXT, PM_pipe);
464         fflush(PM_pipe);
465 #if 0
466         keep_term_initialised = term_initialised ;
467         term_initialised = FALSE ; /* need to force init */
468 #endif
469     }
470
471     PM_mode = SET_TEXT;
472 #ifdef USE_MOUSE
473     {
474         /* FIXME 20040712: 'extern' in a source file is always wrong. */
475         extern TBOOLEAN allowmotion;
476         allowmotion = TRUE;
477     }
478 #endif
479 }
480
481
482 TERM_PUBLIC void
483 PM_graphics()
484 {
485     static int last_encoding = -999;
486     putc(SET_GRAPHICS, PM_pipe);
487     fflush(PM_pipe);
488 #ifdef USE_MOUSE
489     PM_update_menu_items();
490 #endif
491     if (encoding != last_encoding) {
492         int cp;
493         switch (encoding) {
494             case S_ENC_ISO8859_2: cp = 912; break;
495             case S_ENC_CP437: cp = 437; break;
496             case S_ENC_CP850: cp = 850; break;
497             default: /*  S_ENC_DEFAULT, S_ENC_ISO8859_1 */
498                      cp = 0; break;
499         };
500         putc(SET_SPECIAL, PM_pipe);
501         putc('c', PM_pipe); /*  set codepage */
502         fwrite(&cp, sizeof(int), 1, PM_pipe);
503         fflush(PM_pipe);
504         last_encoding = encoding;
505     }
506     PM_mode = SET_GRAPHICS;
507 }
508
509
510 TERM_PUBLIC void
511 PM_move(unsigned int x, unsigned int y)
512 {
513     if (PM_must_abort)
514         PM_abortplot();
515
516     putc(GR_MOVE, PM_pipe);
517     fwrite(&x, sizeof(int), 1, PM_pipe);
518     fwrite(&y, sizeof(int), 1, PM_pipe);
519
520 #ifndef PM_OLD_ENHANCED_TEXT
521     /* save current position, only needed for enhanced text */
522     PM_x = x; 
523     PM_y = y;
524 #endif
525 }
526
527
528 TERM_PUBLIC void
529 PM_vector(unsigned int x, unsigned int y)
530 {
531     if (PM_must_abort)
532         PM_abortplot();
533     putc(GR_DRAW, PM_pipe);
534     fwrite(&x, sizeof(int), 1, PM_pipe);
535     fwrite(&y, sizeof(int), 1, PM_pipe);
536 }
537
538
539 TERM_PUBLIC void
540 PM_linetype(int lt)
541 {
542     putc(SET_LINE, PM_pipe);
543     fwrite(&lt, sizeof(int), 1, PM_pipe);
544 }
545
546
547 TERM_PUBLIC int
548 PM_text_angle(int ang)
549 {
550     putc(SET_ANGLE, PM_pipe);
551     fwrite(&ang, sizeof(int), 1, PM_pipe);
552 #ifndef PM_OLD_ENHANCED_TEXT
553     /* store text angle, only needed for enhanced text */
554     PM_angle = (double)ang * M_PI / 180.;
555 #endif
556     return TRUE;
557 }
558
559
560 TERM_PUBLIC void
561 PM_put_text(unsigned int x, unsigned int y, const char *str)
562 {
563     int len;
564
565     if (PM_must_abort)
566         PM_abortplot();
567
568 #ifdef PM_OLD_ENHANCED_TEXT
569     if (ignore_enhanced_text) {
570         putc(SET_SPECIAL, PM_pipe);
571         putc('e', PM_pipe); /* switch the enhanced mode off */
572         putc('0', PM_pipe);
573     }
574 #endif
575
576     putc(GR_TEXT, PM_pipe);
577     fwrite(&x, sizeof(int), 1, PM_pipe);
578     fwrite(&y, sizeof(int), 1, PM_pipe);
579     len = strlen(str) + 1;
580     fwrite(&len, sizeof(int), 1, PM_pipe);
581     fwrite(str, 1, len, PM_pipe);
582     for (len = sizeof(int) - len % sizeof(int); len > 0; len--) {
583         /* pad rest of int with zeros */
584         putc(NUL, PM_pipe);
585     }
586
587 #ifdef PM_OLD_ENHANCED_TEXT
588     if (ignore_enhanced_text) {
589         putc(SET_SPECIAL, PM_pipe);
590         putc('e', PM_pipe); /* restore the enhanced mode */
591         putc('2', PM_pipe);
592     }
593 #endif
594 }
595
596
597 TERM_PUBLIC int
598 PM_justify_text(enum JUSTIFY mode)
599 {
600 #ifdef PM_OLD_ENHANCED_TEXT
601     if (ignore_enhanced_text) {
602         putc(SET_SPECIAL, PM_pipe);
603         putc('e', PM_pipe); /* switch the enhanced mode off */
604         putc('0', PM_pipe);
605     }
606 #endif
607         
608     putc(SET_JUSTIFY, PM_pipe);
609     fwrite(&mode, sizeof(int), 1, PM_pipe);
610
611 #ifndef PM_OLD_ENHANCED_TEXT
612     /* store text justification, only needed for enhanced text */
613     PM_justification = mode;
614 #else
615     if (ignore_enhanced_text) {
616         putc(SET_SPECIAL, PM_pipe);
617         putc('e', PM_pipe); /* restore the enhanced mode */
618         putc('2', PM_pipe);
619     }
620 #endif
621     return TRUE;
622 }
623
624
625 TERM_PUBLIC int
626 PM_set_font(const char *font)
627 {
628     unsigned int len;
629
630     putc(SET_FONT, PM_pipe);
631     if (font == NULL)
632         len = 0;
633     else
634         len = strlen(font);
635
636     if (len==0) {
637         fwrite(&len, sizeof(int), 1, PM_pipe);
638     } else {
639         len += 1;
640         fwrite(&len, sizeof(int), 1, PM_pipe);
641         fwrite(font, 1, len, PM_pipe);
642         for (len = sizeof(int) - len % sizeof(int); len > 0; len--) {
643             /* pad rest of int with zeros */
644             putc(NUL, PM_pipe);
645         }
646     }
647
648     return TRUE;
649 }
650
651
652 #ifndef PM_OLD_ENHANCED_TEXT
653
654 /* PM_query_font:
655         get current font name and size from gnupmdrv and
656         save them to PM_font and PM_fontsize
657 */
658 static void PM_query_font(void)
659 {
660     unsigned int len, fontsize;
661     char *newfont;
662     ULONG cbR, rc;
663
664     putc(GR_QUERY_FONT, PM_pipe);
665     fflush(PM_pipe);  
666
667     free( PM_font );
668     rc = DosRead(fileno(PM_pipe), &len, sizeof(int), &cbR);
669     newfont = (char *)malloc( len + 1 ); 
670     rc = DosRead(fileno(PM_pipe), newfont, len*sizeof(char), &cbR);
671     newfont[len] = '\0';
672     
673     PM_font = (char *)malloc( len + 1 ); 
674     sscanf( newfont, "%i.%s", &fontsize, PM_font );
675     PM_fontsize = (double)fontsize;
676     free(newfont);
677 }
678
679 #endif
680
681
682 TERM_PUBLIC void
683 PM_point(unsigned int x, unsigned int y, int number)
684 /*
685 ** tell the driver we are plotting a point so it can decide whether to
686 ** use colour or not
687 */
688 {
689     int mode;
690     mode = 1;
691     putc(SET_POINTMODE, PM_pipe);
692     fwrite(&mode, sizeof(int), 1, PM_pipe);
693     do_point(x, y, number);
694     mode = 0;
695     putc(SET_POINTMODE, PM_pipe);
696     fwrite(&mode, sizeof(int), 1, PM_pipe);
697 }
698
699
700 void
701 PM_abortplot(void)
702 {
703     PM_must_abort = 0;
704     term_reset();
705     (void) putc('\n', stderr);
706     bail_to_command_line();
707 }
708
709
710 void
711 PM_intc_cleanup(void)
712 {
713     if (PM_pipe == NULL || PM_mode == SET_TEXT)
714         PM_abortplot();
715     PM_must_abort = 1;
716 }
717
718
719 int
720 PM_pause(char *str)
721 /*
722 ** pause - using message box on PM screen
723 */
724 {
725     int len, rc;
726     ULONG cbR;
727     char buf[256];
728     char *bp;
729
730     if (PM_pipe == NULL)
731         return 2;
732     bp = buf;
733     putc(GR_PAUSE, PM_pipe);
734     len = strlen(str) + 1;
735     fwrite(&len, sizeof(int), 1, PM_pipe);
736     fwrite(str, 1, len, PM_pipe);
737     for (rc = sizeof(int) - len % sizeof(int); rc > 0; rc--) {
738         /* pad rest of int with zeros */
739         putc(NUL, PM_pipe);
740     }
741     fflush(PM_pipe);
742     rc = DosRead(fileno(PM_pipe), &len, sizeof(int), &cbR);
743     return len;
744 }
745
746
747 TERM_PUBLIC void
748 PM_fillbox(int style, unsigned int x, unsigned int y, unsigned int w, unsigned int h)
749 {
750     putc(SET_FILLBOX, PM_pipe);
751     fwrite(&style, sizeof(style), 1, PM_pipe);
752     fwrite(&x, sizeof(x), 1, PM_pipe);
753     fwrite(&y, sizeof(y), 1, PM_pipe);
754     fwrite(&w, sizeof(w), 1, PM_pipe);
755     fwrite(&h, sizeof(h), 1, PM_pipe);
756 }
757
758
759 TERM_PUBLIC void
760 PM_linewidth(double linewidth)
761 {
762     int lw;
763     lw = linewidth * 100;
764     putc(SET_LINEWIDTH, PM_pipe);
765     fwrite(&lw, sizeof(int), 1, PM_pipe);
766 }
767
768
769 TERM_PUBLIC int
770 PM_make_palette(t_sm_palette * palette)
771 {
772     if (palette == NULL) {
773         ULONG rc, cbR;
774         int PM_nColors;
775
776         /* query maximum number of colours in palette */
777         putc(GR_MAKE_PALETTE, PM_pipe);
778         putc(0, PM_pipe);
779         fflush(PM_pipe);
780         rc = DosRead(fileno(PM_pipe), &PM_nColors, sizeof(int), &cbR);
781         return PM_nColors;
782     }
783
784     if (sm_palette.colors > 0) {
785         ULONG *rgbTable;
786         unsigned int i;
787
788         /* Note: gvpm sources have also limit 256, is it limit of PM palette?
789            I suppose yes, thus let colours passed as unsigned char through the pipe.
790            Gray interval [0;1] will be mapped to interval [0;255] whose r,g,b
791            components are mapped by the array below.
792          */
793         putc(GR_MAKE_PALETTE, PM_pipe);
794         putc(1, PM_pipe);
795         rgbTable = (ULONG *) malloc(sizeof(ULONG) * sm_palette.colors);
796         for (i = 0; i < sm_palette.colors; i++) {
797             ULONG r, g, b;
798
799             r = (ULONG) (palette->color[i].r * 255 + 0.5);
800             g = (ULONG) (palette->color[i].g * 255 + 0.5);
801             b = (ULONG) (palette->color[i].b * 255 + 0.5);
802             rgbTable[i] = (r << 16) + (g << 8) + b;     /*  PM API likes this form */
803         }
804         fwrite(&sm_palette.colors, sizeof(int), 1, PM_pipe);
805         fwrite(rgbTable, sizeof(ULONG) * sm_palette.colors, 1, PM_pipe);
806         free(rgbTable);
807     }
808     return 0;
809 }
810
811
812 #if 0
813 /* switch back to the palette used before calling make_palette */
814 TERM_PUBLIC void
815 PM_previous_palette()
816 {
817     putc(GR_RELEASE_PALETTE, PM_pipe);
818 }
819 #endif
820
821
822 TERM_PUBLIC void
823 PM_set_color(t_colorspec *colorspec)
824 {
825     switch (colorspec->type) {
826     case TC_FRAC:
827         if (sm_palette.colors == 0) {
828             rgb255_color rgb255;
829             unsigned int rgb;
830
831             rgb255maxcolors_from_gray(colorspec->value, &rgb255);
832             rgb = (rgb255.r << 16) + (rgb255.g << 8) + rgb255.b;
833             putc(GR_SET_RGBCOLOR, PM_pipe);
834             fwrite(&rgb, sizeof(int), 1, PM_pipe);
835         } else {
836             unsigned char colorindex;
837
838             /* map [0;1] to interval [0;sm_palette.colors-1] */
839             colorindex = ((colorspec->value * (sm_palette.colors - 1.)) + 0.5);
840             putc(GR_SET_COLOR, PM_pipe);
841             fwrite(&colorindex, sizeof(colorindex), 1, PM_pipe);
842         }
843         break;
844     case TC_LT:
845         PM_linetype(colorspec->lt);
846         break;
847     case TC_RGB:
848         putc(GR_SET_RGBCOLOR, PM_pipe);
849         fwrite(&(colorspec->lt), sizeof(int), 1, PM_pipe);
850         /* fflush(PM_pipe); */ /* FIXME: why should that be necessary? */
851         break;
852     }
853 }
854
855
856 TERM_PUBLIC void PM_filled_polygon ( int points, gpiPoint *corners )
857 {
858     int i;
859     putc(GR_FILLED_POLYGON, PM_pipe);
860     fwrite(&points, sizeof(int), 1, PM_pipe); /*  tell him number of corners */
861     for (i = 0; i < points; i++) {
862         fwrite(&corners[i].x, sizeof(int), 1, PM_pipe);
863         fwrite(&corners[i].y, sizeof(int), 1, PM_pipe);
864     }
865 }
866
867
868 #ifdef USE_MOUSE
869
870 TERM_PUBLIC void
871 PM_put_tmptext(int i, const char str[])
872 {
873     if (PM_pipe) {
874         putc(PUT_TMPTEXT, PM_pipe);
875         fwrite(&i, sizeof(int), 1, PM_pipe);
876         i = strlen(str) + 1;
877         fwrite(&i, sizeof(int), 1, PM_pipe);
878         fwrite(&str[0], i, 1, PM_pipe);
879         fflush(PM_pipe);
880     }
881 }
882
883
884 TERM_PUBLIC void
885 PM_set_ruler(int x, int y)
886 {
887     if (PM_pipe) {
888         putc(SET_RULER, PM_pipe);
889         fwrite(&x, sizeof(int), 1, PM_pipe);
890         fwrite(&y, sizeof(int), 1, PM_pipe);
891         fflush(PM_pipe);
892     }
893 }
894
895
896 TERM_PUBLIC void
897 PM_set_cursor(int c, int x, int y)
898 {
899     if (PM_pipe) {
900         putc(SET_CURSOR, PM_pipe);
901         fwrite(&c, sizeof(int), 1, PM_pipe);
902         fwrite(&x, sizeof(int), 1, PM_pipe);
903         fwrite(&y, sizeof(int), 1, PM_pipe);
904         fflush(PM_pipe);
905     }
906 }
907
908
909 TERM_PUBLIC void
910 PM_set_clipboard(const char s[])
911 {
912     if (PM_pipe) {
913         int i = strlen(s);
914         putc(SET_CLIPBOARD, PM_pipe);
915         fwrite(&i, sizeof(int), 1, PM_pipe);
916         fwrite(s, i+1, 1, PM_pipe);
917         fflush(PM_pipe);
918     }
919 }
920
921 #endif /* USE_MOUSE */
922
923
924 #ifdef WITH_IMAGE
925
926 TERM_PUBLIC void
927 PM_image(unsigned int M, unsigned int N, coordval *image, gpiPoint *corner, t_imagecolor color_mode)
928 {
929     PBYTE rgb_image;
930     unsigned int image_size;
931     unsigned int pad_bytes;
932
933     /* IC_PALETTE and IC_RGB images are converted to a 24bit RGB format
934        suitable for OS/2's presentation manager:
935         - sequence of lines is reversed 
936         - each line starts at a 4 byte boundary
937     */
938
939     /* fprintf(stderr, "PM_image: %i x %i, mode=%s\n", M, N, color_mode==IC_RGB?"IC_RGB":"IC_PALETTE" ); */
940     pad_bytes = (4 - (3 * M) % 4) % 4; /* scan lines start on ULONG boundaries */
941     image_size = (M + pad_bytes ) * N * 3;
942     rgb_image = (PBYTE) gp_alloc(image_size, "PM RGB image");
943
944     if (color_mode == IC_PALETTE) {
945         unsigned int x, y;
946
947         rgb_image += N * (3 * M + pad_bytes);
948         for (y=0; y<N; y++) {
949             rgb_image -= 3 * M + pad_bytes;
950             for(x=0; x<M; x++) {
951                 rgb255_color rgb255;
952                 rgb255maxcolors_from_gray(*image++, &rgb255);
953                 *(rgb_image++) = rgb255.b;
954                 *(rgb_image++) = rgb255.g;
955                 *(rgb_image++) = rgb255.r;
956             }
957             rgb_image -= 3 * M;
958         }
959     } else if (color_mode == IC_RGB) {
960         unsigned int x, y;
961
962         rgb_image += N * (3 * M + pad_bytes);
963         for (y=0; y<N; y++) {
964             rgb_image -= 3 * M + pad_bytes;
965             for(x=0; x<M; x++) {
966                 rgb255_color rgb255;
967                 rgb255.r = (BYTE) (*image++ * 255 + 0.5);
968                 rgb255.g = (BYTE) (*image++ * 255 + 0.5);
969                 rgb255.b = (BYTE) (*image++ * 255 + 0.5);
970                 *(rgb_image++) = rgb255.b;
971                 *(rgb_image++) = rgb255.g;
972                 *(rgb_image++) = rgb255.r;
973             }
974             rgb_image -= 3 * M;
975         }
976     }
977
978     if ((color_mode == IC_PALETTE) || (color_mode == IC_RGB)) {
979         unsigned int i;
980
981         /* transfer data to gnupmdrv */
982         putc(GR_RGB_IMAGE, PM_pipe);
983         fwrite(&M, sizeof(M), 1, PM_pipe);
984         fwrite(&N, sizeof(N), 1, PM_pipe);
985         for (i=0; i<4; i++) {
986             fwrite(&(corner[i].x), sizeof(int), 1, PM_pipe);
987             fwrite(&(corner[i].y), sizeof(int), 1, PM_pipe);
988         }
989         fwrite(&image_size, sizeof(image_size), 1, PM_pipe);
990         fwrite(rgb_image, image_size, 1, PM_pipe);
991         fflush(PM_pipe);
992     }
993
994     free(rgb_image);
995 }
996
997 #endif /* WITH_IMAGE */
998
999
1000 #ifndef PM_OLD_ENHANCED_TEXT
1001
1002 TERM_PUBLIC void
1003 PM_enhanced_open(
1004     char *fontname,
1005     double fontsize, double base,
1006     TBOOLEAN widthflag, TBOOLEAN showflag,
1007     int overprint)
1008 {
1009     static const int pm_scale = 35; /* scaling of base offset */  
1010     static unsigned int ENHpm_xsave, ENHpm_ysave;
1011     char *fontstring;
1012
1013     /* There are two special cases:
1014      * overprint = 3 means save current position
1015      * overprint = 4 means restore saved position
1016      */
1017     if (overprint == 3) {
1018         ENHpm_xsave = PM_x;
1019         ENHpm_ysave = PM_y;
1020         return;
1021     } else if (overprint == 4) {
1022         PM_x = ENHpm_xsave;
1023         PM_y = ENHpm_ysave;
1024         return;
1025     }
1026
1027     if (!ENHpm_opened_string) {
1028         ENHpm_opened_string = TRUE;
1029
1030         /* Start new text fragment */
1031         enhanced_cur_text = &enhanced_text[0];
1032
1033         /* Keep track of whether we are supposed to show this string */
1034         ENHpm_show = showflag;
1035
1036         /* 0/1/2  no overprint / 1st pass / 2nd pass */
1037         ENHpm_overprint = overprint;
1038
1039         /* widthflag FALSE means do not update text position after printing */
1040         ENHpm_widthflag = widthflag;
1041
1042         /* Select font */
1043         /* FIXME: It would be nice to have fractional font sizes 
1044                   for super- and subscripts. */
1045         /* FIXME: sometimes fontname has zero length */
1046         if ((fontname != NULL) && strlen(fontname) > 0) {
1047             fontstring = malloc( strlen(fontname) + 16 );
1048             sprintf( fontstring, "%s,%i", fontname, (int)fontsize );
1049         }
1050         else {
1051             fontstring = malloc( strlen(PM_font) + 16 );
1052             sprintf( fontstring, "%s,%i", PM_font, (int)fontsize );
1053         }
1054         PM_set_font( fontstring );
1055         free( fontstring );
1056         PM_query_font();
1057
1058         /* Scale fractional font height to vertical units of display */
1059         /* FIXME:       
1060                 Font scaling is not done properly (yet) and will lead to
1061                 non-optimal results for most font and size selections.
1062                 The old gnupmdrv code used FONTINFO information for super-
1063                 and subscripts.
1064         */
1065         ENHpm_base = pm_scale * base;
1066     }
1067 }
1068
1069
1070 TERM_PUBLIC void
1071 PM_enhanced_flush()
1072 {
1073     static unsigned int ENHpm_xsave, ENHpm_ysave;
1074
1075     if (ENHpm_opened_string) {
1076         int width, height;
1077         unsigned int mode;
1078         unsigned int x, y, len;
1079         ULONG rc, cbR;
1080
1081         *enhanced_cur_text = '\0';
1082         
1083         if (PM_must_abort)
1084             PM_abortplot();
1085
1086         /* print the string fragment, perhaps invisibly */
1087         /* NB: base expresses offset from current y pos */
1088         x = PM_x - ENHpm_base * sin(PM_angle);
1089         y = PM_y + ENHpm_base * cos(PM_angle);
1090         mode = ((ENHpm_show && !ENHpm_sizeonly) ? 0x01 : 0x00 );
1091         len = strlen(enhanced_text) + 1;
1092
1093         /* send message to gnupmdrv */
1094         putc(GR_ENH_TEXT, PM_pipe);
1095         fwrite(&x, sizeof(int), 1, PM_pipe);
1096         fwrite(&y, sizeof(int), 1, PM_pipe);
1097         /* write 'mode indicator' (currently show switch only) */
1098         fwrite(&mode, sizeof(int), 1, PM_pipe); 
1099         fwrite(&len, sizeof(int), 1, PM_pipe);
1100         fwrite(enhanced_text, 1, len, PM_pipe);
1101         for (len = sizeof(int) - len % sizeof(int); len > 0; len--) {
1102             /* pad rest of int with zeros */
1103             putc(NUL, PM_pipe);
1104         }
1105
1106         /* answer from gnupmdrv is length of text */
1107         fflush(PM_pipe);
1108         rc = DosRead(fileno(PM_pipe), &width, sizeof(int), &cbR);
1109         rc = DosRead(fileno(PM_pipe), &height, sizeof(int), &cbR);
1110
1111         /* update drawing position according to len */
1112         if (!ENHpm_widthflag) {
1113             width = 0; 
1114             height = 0;
1115         }
1116         if (ENHpm_sizeonly) {
1117             /* This is the first pass for justified printing.        */
1118             /* We just adjust the starting position for second pass. */
1119             if (PM_justification == RIGHT) {
1120                 PM_x -= width;
1121                 PM_y -= height;
1122             }
1123             else if (PM_justification == CENTRE) {
1124                 PM_x -= width / 2;
1125                 PM_y -= height / 2;
1126             }
1127             /* nothing to do for LEFT justified text */
1128         }
1129         else if (ENHpm_overprint == 1) {
1130             /* Save current position */
1131             ENHpm_xsave = PM_x + width;
1132             ENHpm_ysave = PM_y + height;
1133             /* First pass of overprint, leave position in center of fragment */
1134             PM_x += width / 2;
1135             PM_y += height / 2;
1136         }
1137         else if (ENHpm_overprint == 2) {
1138             /* Restore current position,                          */
1139             /* this sets the position behind the overprinted text */
1140             PM_x = ENHpm_xsave;
1141             PM_y = ENHpm_ysave;
1142         }
1143         else {
1144             /* Normal case is to update position to end of fragment */
1145             PM_x += width;
1146             PM_y += height;
1147         }
1148
1149         ENHpm_opened_string = FALSE;
1150     }
1151 }
1152
1153
1154 TERM_PUBLIC void
1155 PM_enhanced_put_text(unsigned int x, unsigned int y, const char *str)
1156 {
1157     char *original_string = (char *)str;
1158     unsigned int pass, num_passes;
1159
1160     /* If no enhanced text processing is needed, we can use the plain  */
1161     /* vanilla put_text() routine instead of this fancy recursive one. */
1162     if (ignore_enhanced_text || !strpbrk(str, "{}^_@&~")) {
1163         PM_put_text(x,y,str);
1164         return;
1165     }
1166
1167     /* Set up global variables needed by enhanced_recursion() */
1168     ENHpm_opened_string = FALSE;
1169     enhanced_fontscale = 1.0;
1170     strncpy(enhanced_escape_format,"%c",sizeof(enhanced_escape_format));
1171
1172     /* Tell the terminal to move the drawing position */
1173     /* we store the current position to PM_x and PM_y */
1174     PM_x = x; 
1175     PM_y = y;
1176
1177     /* Text justification requires two passes. During the first pass we */
1178     /* don't draw anything, we just measure the space it will take.     */
1179     /* Without justification one pass is enough                         */
1180     if (PM_justification == LEFT) {
1181         num_passes = 1;
1182     }
1183     else {
1184         num_passes = 2;
1185         ENHpm_sizeonly = TRUE; 
1186     }
1187
1188     for( pass=1; pass <= num_passes; pass++ ) {
1189
1190         /* This will restore the default font 
1191            and update PM_font and PM_fontsize */
1192         PM_set_font(NULL); 
1193         PM_query_font(); 
1194
1195         /* Set the recursion going. We say to keep going until a
1196         * closing brace, but we don't really expect to find one.
1197         * If the return value is not the nul-terminator of the
1198         * string, that can only mean that we did find an unmatched
1199         * closing brace in the string. We increment past it (else
1200         * we get stuck in an infinite loop) and try again.
1201         */
1202         while (*(str = enhanced_recursion((char *)str, TRUE,
1203                         NULL, PM_fontsize,
1204                         0.0, TRUE, TRUE, 0))) {
1205             (term->enhanced_flush)();
1206
1207             /* I think we can only get here if *str == '}' */
1208             enh_err_check(str);
1209
1210             if (!*++str)
1211                 break; /* end of string */
1212
1213             /* else carry on and process the rest of the string */
1214         }
1215
1216         /* In order to do text justification we need to do a second pass that */
1217         /* uses information stored during the first pass.                     */
1218         /* see PM_enhanced_flush()                                            */
1219         if (pass == 1) {
1220             /* do the actual printing in the next pass */
1221             ENHpm_sizeonly = FALSE;
1222             str = original_string;
1223         }
1224     }
1225
1226     /* restore default font */
1227     PM_set_font(NULL); 
1228 }
1229
1230 #endif /* PM_OLD_ENHANCED_TEXT */
1231
1232
1233 /* helper function */
1234 void
1235 pm_raise_terminal_window()
1236 {
1237     putc(SET_SPECIAL, PM_pipe);
1238     putc('^', PM_pipe); /* raise window */
1239     fflush(PM_pipe);
1240 }
1241
1242 void
1243 pm_lower_terminal_window()
1244 {
1245     putc(SET_SPECIAL, PM_pipe);
1246     putc('_', PM_pipe); /* lower window */
1247     fflush(PM_pipe);
1248 }
1249
1250
1251 #endif /* TERM_BODY */
1252
1253 #ifdef TERM_TABLE
1254 TERM_TABLE_START(PM_driver)
1255     "pm", "OS/2 Presentation Manager",
1256     PM_XMAX, PM_YMAX, PM_VCHAR, PM_HCHAR,
1257     PM_VTIC, PM_HTIC, PM_options, PM_init, PM_reset,
1258     PM_text, null_scale, PM_graphics, PM_move, PM_vector,
1259     PM_linetype, PM_put_text, PM_text_angle,
1260     PM_justify_text, PM_point, do_arrow, PM_set_font,
1261     0 /*pointsize */ , TERM_CAN_MULTIPLOT|TERM_NO_OUTPUTFILE, 
1262     PM_suspend, PM_resume,
1263     PM_fillbox, PM_linewidth
1264 #ifdef USE_MOUSE
1265     , 0 /* PM_waitforinput */,
1266     PM_put_tmptext, PM_set_ruler, PM_set_cursor, PM_set_clipboard
1267 #endif
1268     , PM_make_palette,
1269     0, /* PM_previous_palette */
1270     PM_set_color,
1271     PM_filled_polygon
1272 #ifdef WITH_IMAGE
1273     , PM_image
1274 #endif
1275 #ifndef PM_OLD_ENHANCED_TEXT
1276     , PM_enhanced_open, PM_enhanced_flush, do_enh_writec
1277 #endif
1278 TERM_TABLE_END(PM_driver)
1279
1280 #undef LAST_TERM
1281 #define LAST_TERM PM_driver
1282
1283 #endif /* TERM_TABLE */
1284
1285 #ifdef TERM_HELP
1286 START_HELP(pm)
1287 "1 pm",
1288 "?commands set terminal pm",
1289 "?set terminal pm",
1290 "?set term pm",
1291 "?terminal pm",
1292 "?term pm",
1293 "?pm",
1294 " The `pm` terminal driver provides an OS/2 Presentation Manager window in",
1295 " which the graph is plotted.  The window is opened when the first graph is",
1296 " plotted.  This window has its own online help as well as facilities for",
1297 " printing, copying to the clipboard and some line type and color adjustments.",
1298 " The `multiplot` option is supported.",
1299 "",
1300 " Syntax:",
1301 "       set terminal pm {server {n}} {persist} {widelines} {enhanced} {\"title\"}",
1302 "",
1303 " If `persist` is specified, each graph appears in its own window and all",
1304 " windows remain open after `gnuplot` exits.  If `server` is specified, all",
1305 " graphs appear in the same window, which remains open when `gnuplot` exits.",
1306 " This option takes an optional numerical argument which specifies an instance",
1307 " of the server process.  Thus multiple server windows can be in use at the",
1308 " same time.",
1309 "",
1310 " If `widelines` is specified, all plots will be drawn with wide lines.  If",
1311 " `enhanced` is specified, sub- and superscripts and multiple fonts are",
1312 " enabled using the same syntax as the `enhanced postscript` option (see",
1313 " `set terminal postscript enhanced` for details).  Font names for the basic",
1314 " PostScript fonts may be abbreviated to single letters.",
1315 "",
1316 " If `title` is specified, it will be used as the title of the plot window.",
1317 " It will also be used as the name of the server instance, and will override",
1318 " the optional numerical argument.",
1319 "",
1320 " Linewidths may be changed with `set linestyle`."
1321 END_HELP(pm)
1322 #endif /* TERM_HELP */