1 /*
2    Copyright (c) 1991 - 1994 Michael Schoene & Heinz W. Werntges.
3    Parts Copyright (c) 1999  Martin Kroeker.
4 
5    All rights reserved. Distributed by Free Software Foundation, Inc.
6 
7 This file is part of HP2xx.
8 
9 HP2xx is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
11 to anyone for the consequences of using it or for whether it serves any
12 particular purpose or works at all, unless he says so in writing.  Refer
13 to the GNU General Public License, Version 2 or later, for full details.
14 
15 Everyone is granted permission to copy, modify and redistribute
16 HP2xx, but only under the conditions described in the GNU General Public
17 License.  A copy of this license is supposed to have been
18 given to you along with HP2xx so you can know your rights and
19 responsibilities.  It should be in a file named COPYING.  Among other
20 things, the copyright notice and this notice must be preserved on all
21 copies.
22 
23 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24 */
25 
26 /** to_x11.c: X11 preview part of project "hp2xx" (UNIX only)
27  **
28  ** 92/01/15  V 1.00  HWW  Derived from to_vga.c (V1.01b)
29  **			  X11 essentials due to M. Schoene
30  ** 92/01/28  V 1.01  HWW  Window offset user-defined via -o -O
31  ** 92/02/03  V 1.02  HWW  bug fixes, error handling
32  ** 92/05/19  V 1.02b HWW  Abort if color mode
33  ** 92/05/25  V 1.10  HWW  8 Colors supported
34  ** 93/01/06  V 1.10b HWW  Improved selection of foreground color
35  ** 94/02/14  V 1.20a HWW  Adapted to changes in hp2xx.h
36  ** 01/04/22          YuS  Exit on button and key events
37  **
38  **	      NOTE: Color assignment leaves something to be desired
39  **		    with some X11 servers.
40  **/
41 
42 
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <sys/time.h>
47 #include <X11/Xlib.h>
48 #include <X11/Xutil.h>
49 
50 #include "bresnham.h"
51 #include "pendef.h"
52 #include "hp2xx.h"
53 #include "x11.h"
54 
55 
56 
57 #define WIN_NAME	"x11"	/* Window name          */
58 #define PROG_NAME	"hp2xx"	/* Program name                 */
59 
60 
61 
62 /**
63  ** Global variables for X11
64  **/
65 
66 static Display *XDisplay = NULL;	/* Workstation id       */
67 static int XScreen;
68 static Window XRoot;		/* Number of root window        */
69 static Visual *XVisual = NULL;
70 
71 static GC XGcWin;
72 static Window XWin;		/* Window id            */
73 
74 static unsigned long col_table[CMS_SIZE];
75 static XColor Xcol;
76 static Colormap def_clut;
77 
78 /**
79  ** Screen sizes
80  **/
81 
82 static int scr_width;
83 static int scr_height;
84 
85 /**
86  ** Window sizes
87  **/
88 
89 static int width;
90 static int bytes;
91 static int height;
92 
93 /* Added by YuS 22 April 2001 */
94 XEvent WaitEvent;
95 
96 static int row_start = 0;
97 static int col_start = 0;
98 static int oversized = 0;
99 static int zoomed = 0;
100 /**
101  ** Initialize X11 and open window
102  **/
103 
104 static int
win_open(const GEN_PAR * pg,char * title,int x,int y,int w,int h)105 win_open (const GEN_PAR * pg, char *title, int x, int y, int w, int h)
106 {
107   char *DisplayName = NULL;
108   char **argv;
109   XSizeHints Hints;
110   unsigned long ValueMask;
111   XSetWindowAttributes WinAttr;
112   XEvent Event;
113   char colorname[13];
114   int i;
115 
116 	/**
117 	 ** Simulate command line arguments
118 	 **/
119 
120   argv = (char **) malloc (3 * sizeof (char *));
121   argv[0] = PROG_NAME;
122   argv[1] = title;
123   argv[2] = NULL;
124 
125 	/**
126 	 ** X11 server reachable ?
127 	 **/
128 
129   if ((XDisplay = (Display *) XOpenDisplay (DisplayName)) == NULL)
130     {
131       Eprintf ("No X11 server found !\n");
132       return NO_SERVER;
133     }
134 
135 
136 
137   XScreen = DefaultScreen (XDisplay);
138   XRoot = RootWindow (XDisplay, XScreen);
139   XVisual = DefaultVisual (XDisplay, XScreen);
140   XGcWin = DefaultGC (XDisplay, XScreen);
141 
142   scr_width = WidthOfScreen (ScreenOfDisplay (XDisplay, XScreen));
143   scr_height = HeightOfScreen (ScreenOfDisplay (XDisplay, XScreen));
144   if (x + w > scr_width || y + h > scr_height)
145     {
146   if (!pg->quiet)
147       Eprintf ("Window exceeds screen limits, use mouse button 1 to pan\n");
148       w = MIN (w, scr_width);
149       h = MIN (h, scr_height);
150       oversized = 1;
151 /*		return SIZE;*/
152     }
153 
154 	/**
155 	 ** Set window attributes
156 	 **/
157 
158   WinAttr.background_pixel = WhitePixel (XDisplay, XScreen);
159   WinAttr.border_pixel = WhitePixel (XDisplay, XScreen);
160   WinAttr.backing_store = Always;
161   ValueMask = CWBackPixel | CWBorderPixel | CWBackingStore;
162 
163 	/**
164 	 ** Create Window
165 	 **/
166 
167   XWin = XCreateWindow (XDisplay, XRoot,
168 			x, y, w, h,
169 			1, 0,
170 			CopyFromParent, CopyFromParent, ValueMask, &WinAttr);
171 
172 	/**
173 	 ** Define window properties
174 	 **/
175 
176   Hints.flags = PSize | PMinSize | PMaxSize | USPosition;
177   Hints.x = x;
178   Hints.y = y;
179   Hints.width = Hints.min_width = Hints.max_width = w;
180   Hints.height = Hints.min_height = Hints.max_height = h;
181 
182   XSetStandardProperties (XDisplay, XWin,
183 			  title, title, 0, argv, 2, &Hints);
184 
185 /**
186  ** Define color table (compatible to SunView and Turbo-C usage)
187  **/
188 
189   def_clut = DefaultColormap (XDisplay, XScreen);
190   if (DefaultDepth (XDisplay, XScreen) < 4)
191     {
192       col_table[BLACK] = WhitePixel (XDisplay, XScreen);
193       col_table[WHITE] = BlackPixel (XDisplay, XScreen);
194       col_table[GRAY] = col_table[WHITE];
195       col_table[RED] = col_table[WHITE];
196       col_table[GREEN] = col_table[WHITE];
197       col_table[BLUE] = col_table[WHITE];
198       col_table[CYAN] = col_table[WHITE];
199       col_table[MAGENTA] = col_table[WHITE];
200       col_table[YELLOW] = col_table[WHITE];
201       col_table[LIGHTGRAY] = col_table[WHITE];
202       col_table[LIGHTRED] = col_table[WHITE];
203       col_table[LIGHTGREEN] = col_table[WHITE];
204       col_table[LIGHTBLUE] = col_table[WHITE];
205       col_table[LIGHTCYAN] = col_table[WHITE];
206       col_table[LIGHTMAGENTA] = col_table[WHITE];
207     }
208   else
209     {
210       XParseColor (XDisplay, def_clut, "gray10", &Xcol);
211       XAllocColor (XDisplay, def_clut, &Xcol);
212       col_table[GRAY] = Xcol.pixel;
213 
214       for (i = 1; i <= pg->maxpens; i++)
215 	{
216 
217 	  sprintf (colorname, "#%2.2X%2.2X%2.2X",
218 		   pt.clut[i][0], pt.clut[i][1], pt.clut[i][2]);
219 	  XParseColor (XDisplay, def_clut, colorname, &Xcol);
220 	  XAllocColor (XDisplay, def_clut, &Xcol);
221 	  col_table[i] = Xcol.pixel;
222 	}
223     }
224 
225 
226 	/**
227 	 **  Set foreground and background colors
228 	 **/
229 
230   XSetState (XDisplay, XGcWin,
231 	     col_table[BLACK], col_table[WHITE], GXcopy, AllPlanes);
232 
233 	/**
234 	 ** Define permitted events for this window
235 	 **/
236 
237   XSelectInput (XDisplay, XWin,
238 		ExposureMask | VisibilityChangeMask | KeyPressMask |
239 		ButtonPressMask | ButtonReleaseMask);
240 
241 	/**
242 	 ** Display window
243 	 **/
244   XMapWindow (XDisplay, XWin);
245   do
246     {
247       XNextEvent (XDisplay, &Event);
248     }
249   while (Event.type != Expose && Event.type != VisibilityNotify);
250 
251   width = w;
252   height = h;
253   bytes = (w + 7) / 8;
254 
255 
256   free ((char *) argv);
257   return (0);
258 }
259 
260 
261 
262 void
win_close()263 win_close ()
264 {
265   XDestroyWindow (XDisplay, XWin);
266   XCloseDisplay (XDisplay);
267 }
268 
269 
270 
271 
272 #define	setXcolor(col) XSetForeground (XDisplay, XGcWin, col_table[col])
273 
274 
275 
276 
277 int
PicBuf_to_X11(const GEN_PAR * pg,OUT_PAR * po)278 PicBuf_to_X11 ( const GEN_PAR * pg,  OUT_PAR * po)
279 /**
280  ** Interface to higher-level routines,
281  **   similar in structure to other previewers
282  **/
283 {
284   int row_c, x, y;
285   int saved_col=0,saved_row=0;
286   int xref = 0, yref = 0;
287   const RowBuf *row;
288   const PicBuf *pb;
289   struct timeval tv;
290   tv.tv_usec = 10;
291 
292   if (pg == NULL || po == NULL)
293     return ERROR;
294   pb = po->picbuf;
295   if (pb == NULL)
296     return ERROR;
297 
298   if (!pg->quiet)
299     {
300       Eprintf ("\nX11 preview follows.\n");
301       Eprintf ("Press any key to end graphics mode\n");
302     }
303 
304   if (win_open (pg, po->outfile, (int) (po->xoff * po->dpi_x / 25.4),
305 		(int) (po->yoff * po->dpi_y / 25.4), pb->nb << 3, pb->nr))
306     return ERROR;
307 REDRAW:
308   /* Backward since highest index is lowest line on screen! */
309   for (row_c = row_start, y = MIN (height-row_start, pb->nr - 1);
310        row_c < pb->nr; row_c++, y--)
311     {
312       row = get_RowBuf (pb, row_c);
313       if (row == NULL)
314 	return 0;
315       for (x = col_start; x < pb->nc; x++)
316 	{
317 	  switch (index_from_RowBuf (row, x, pb))
318 	    {
319 
320 	    case xxBackground:
321 	      continue;
322 	    case xxForeground:
323 	      setXcolor (WHITE);
324 	      break;
325 /*
326 		case xxRed:	setXcolor (RED);	break;
327 		case xxGreen:	setXcolor (GREEN);	break;
328 		case xxBlue:	setXcolor (BLUE);	break;
329 		case xxCyan:	setXcolor (CYAN);	break;
330 		case xxMagenta:	setXcolor (MAGENTA);	break;
331 		case xxYellow:	setXcolor (YELLOW);	break;
332 */
333 	    default:
334 	      setXcolor (index_from_RowBuf (row, x, pb));
335 	      break;
336 	    }
337 	  XDrawPoint (XDisplay, XWin, XGcWin, x - col_start, y + row_start);
338 	}
339     }
340 
341 /* Wait KeyPress of any mouse ButtonPress to exit */
342   do
343     {
344       XNextEvent (XDisplay, &WaitEvent);
345       if (WaitEvent.type == ButtonPress)
346 	{
347 	  if (WaitEvent.xbutton.button == Button1)
348 	    {
349 	      xref = WaitEvent.xbutton.x;
350 	      yref = WaitEvent.xbutton.y;
351 	    }
352 	  if (WaitEvent.xbutton.button == Button2)
353 	    {
354 	    if (!zoomed){
355 	      zoomed=1;
356 	      po->dpi_x *=2;
357 	      po->dpi_y *=2;
358 	       po->HP_to_xdots *=2;
359 	       po->HP_to_ydots *=2;
360 		saved_row=row_start;
361 		saved_col=col_start;
362 		  row_start = height-WaitEvent.xbutton.y+2*saved_row;
363 		  if (height <scr_height) row_start = (height-WaitEvent.xbutton.y);
364 		  col_start =  WaitEvent.xbutton.x+col_start;
365 	    } else {
366 	      zoomed=0;
367 	      po->dpi_x = po->dpi_x/2;
368 	      po->dpi_y = po->dpi_y/2;
369 	       po->HP_to_xdots = po->HP_to_xdots/2;
370 	       po->HP_to_ydots = po->HP_to_ydots/2;
371 		row_start=saved_row;
372 		col_start=saved_col;
373 		}
374 		free(po->picbuf);
375 		po->picbuf=NULL;
376 	      TMP_to_BUF(pg, po);
377 		pb=po->picbuf;
378 	    }
379 	}
380       else if (WaitEvent.type == ButtonRelease)
381 	{
382 	  if (WaitEvent.xbutton.button == Button1)
383 	    {
384 	      if (oversized)
385 		{
386 		  row_start += WaitEvent.xbutton.y - yref;
387 		  col_start += xref - WaitEvent.xbutton.x;
388 		  if (row_start > pb->nr)
389 		    row_start = pb->nr - scr_height;
390 		  if (row_start < 0)
391 		    row_start = 0;
392 		  if (scr_width + col_start > pb->nc)
393 		    col_start = pb->nc - scr_width;
394 		  if (col_start < 0)
395 		    col_start = 0;
396 		}
397 	      XSetForeground (XDisplay, XGcWin,
398 			      WhitePixel (XDisplay, XScreen));
399 	      XFillRectangle (XDisplay, XWin, XGcWin, 0, 0, scr_width,
400 			      scr_height);
401 	      goto REDRAW;	/* yes, goto in C is ugly */
402 	    }
403 	  if (WaitEvent.xbutton.button == Button2){
404 	      XSetForeground (XDisplay, XGcWin,
405 			      WhitePixel (XDisplay, XScreen));
406 	      XFillRectangle (XDisplay, XWin, XGcWin, 0, 0, scr_width,
407 			      scr_height);
408 	      goto REDRAW;	/* yes, goto in C is ugly */
409 		}
410 	  break;
411 	  select (0, NULL, NULL, NULL, &tv);
412 	}
413     }
414   while (WaitEvent.type != KeyPress);
415 
416   win_close ();
417   return 0;
418 }
419