1 /*--------------------------------*-C-*---------------------------------*
2  * File:	graphics.c
3  *----------------------------------------------------------------------*
4  * Copyright (C) 1997,1998 mj olesen <olesen@me.queensu.ca>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *----------------------------------------------------------------------*/
20 /*----------------------------------------------------------------------*
21  * Originally written:
22  *     1994      Rob Nation <nation@rocket.sanders.lockheed.com>
23  * Modifications:
24  *     1997      Raul Garcia Garcia <rgg@tid.es>
25  *     1997,1998 mj olesen <olesen@me.QueensU.CA>
26  *----------------------------------------------------------------------*/
27 
28 #ifndef lint
29 static const char rcsid[] = "$Id: graphics.c,v 1.2 2004/11/16 19:47:58 sasha Exp $";
30 #endif
31 
32 #include "rxvt.h"		/* NECESSARY */
33 #include <X11/cursorfont.h>
34 
35 /* commands:
36  * 'C' = Clear
37  * 'F' = Fill
38  * 'G' = Geometry
39  * 'L' = Line
40  * 'P' = Points
41  * 'T' = Text
42  * 'W' = Window
43  */
44 
45 #ifndef GRX_SCALE
46 # define GRX_SCALE	10000
47 #endif
48 
49 #ifdef RXVT_GRAPHICS
50 static int      graphics_up = 0;
51 static grwin_t *gr_root = NULL;
52 #endif
53 
54 /*----------------------------------------------------------------------*
55  * local functions
56  */
57 /* ARGSUSED */
58 /* PROTO */
59 void
Gr_NewWindow(int nargs,int args[])60 Gr_NewWindow(int nargs, int args[])
61 {
62 #ifdef RXVT_GRAPHICS
63     int             x, y;
64     unsigned int    w, h;
65     Window          win;
66     grwin_t        *grwin;
67     Cursor          cursor;
68 
69     if (nargs != 4) {
70 	print_error("NewWindow: 4 args needed, got %d\n", nargs);
71 	return;
72     }
73     x = args[0] * TermWin.width / GRX_SCALE + TermWin_internalBorder;
74     y = args[1] * TermWin.height / GRX_SCALE + TermWin_internalBorder;
75     w = args[2] * TermWin.width / GRX_SCALE;
76     h = args[3] * TermWin.height / GRX_SCALE;
77     win = XCreateSimpleWindow(Xdisplay, TermWin.vt,
78 			      x, y, w, h,
79 			      0,
80 			      PixColors[Color_fg],
81 			      PixColors[Color_bg]);
82 
83     cursor = XCreateFontCursor(Xdisplay, XC_crosshair);
84     XDefineCursor(Xdisplay, win, cursor);
85     XMapWindow(Xdisplay, win);
86     XSelectInput(Xdisplay, win, ExposureMask);
87 
88     grwin = (grwin_t *) MALLOC(sizeof(grwin_t));
89     grwin->win = win;
90     grwin->x = x;
91     grwin->y = y;
92     grwin->w = w;
93     grwin->h = h;
94     grwin->screen = 0;
95     grwin->prev = NULL;
96     grwin->next = gr_root;
97     if (grwin->next)
98 	grwin->next->prev = grwin;
99     gr_root = grwin;
100     grwin->graphics = NULL;
101     graphics_up++;
102 
103     tt_printf("\033W%ld\n", (long)grwin->win);
104 #endif
105 }
106 
107 /* ARGSUSED */
108 /* PROTO */
109 void
Gr_ClearWindow(grwin_t * grwin)110 Gr_ClearWindow(grwin_t * grwin)
111 {
112 #ifdef RXVT_GRAPHICS
113     grcmd_t        *cmd, *next;
114 
115     for (cmd = grwin->graphics; cmd != NULL; cmd = next) {
116 	next = cmd->next;
117 	free(cmd->coords);
118 	if (cmd->text != NULL)
119 	    free(cmd->text);
120 	free(cmd);
121     }
122     grwin->graphics = NULL;
123     XClearWindow(Xdisplay, grwin->win);
124 #endif
125 }
126 
127 /*
128  * arg [0] = x
129  * arg [1] = y
130  * arg [2] = alignment
131  * arg [3] = strlen (text)
132  */
133 /* ARGSUSED */
134 /* PROTO */
135 void
Gr_Text(grwin_t * grwin,grcmd_t * data)136 Gr_Text(grwin_t * grwin, grcmd_t * data)
137 {
138 #ifdef RXVT_GRAPHICS
139     int             x, y, align;
140 
141     if (data->ncoords < 4 || data->text == NULL || *(data->text) == '\0')
142 	return;
143 
144     x = data->coords[0] * grwin->w / GRX_SCALE;
145     y = data->coords[1] * grwin->h / GRX_SCALE;
146     align = data->coords[2];
147 
148     if (align & RIGHT_TEXT)
149 	x -= XTextWidth(TermWin.font, data->text, data->coords[3]);
150     else if (align & HCENTER_TEXT)
151 	x -= (XTextWidth(TermWin.font, data->text, data->coords[3]) >> 1);
152 
153     if (align & TOP_TEXT)
154 	y += TermWin.font->ascent;
155     else if (align & BOTTOM_TEXT)
156 	y -= TermWin.font->descent;
157 
158     if (align & VCENTER_TEXT)
159 	y -= TermWin.font->descent
160 	     + ((TermWin.font->ascent + TermWin.font->descent) >> 1);
161     if (align & VCAPS_CENTER_TEXT)
162 	y += (TermWin.font->ascent >> 1);
163 
164     XPMClearArea(Xdisplay, grwin->win, x, y, Width2Pixel(data->coords[3]),
165 		 Height2Pixel(1), 0);
166     XDrawString(Xdisplay, grwin->win, TermWin.gc, x, y,
167 		data->text, data->coords[3]);
168 #endif
169 }
170 
171 /* ARGSUSED */
172 /* PROTO */
173 void
Gr_Geometry(grwin_t * grwin,grcmd_t * data)174 Gr_Geometry(grwin_t * grwin, grcmd_t * data)
175 {
176 #ifdef RXVT_GRAPHICS
177     if (grwin)
178 	tt_printf("\033G%ld %d %d %u %u %d %d %ld %ld %d\n",
179 		  (long)grwin->win,
180 		  grwin->x, grwin->y, grwin->w, grwin->h,
181 		  TermWin.fwidth,
182 		  TermWin.fheight,
183 		  (long)GRX_SCALE * TermWin.fwidth / grwin->w,
184 		  (long)GRX_SCALE * TermWin.fheight / grwin->h,
185 		  Xdepth);
186     else			/* rxvt terminal window size */
187 	tt_printf("\033G0 0 0 %d %d %d %d %ld %ld %d\n",
188 		  TermWin.width - 2 * TermWin_internalBorder,
189 		  TermWin.height - 2 * TermWin_internalBorder,
190 		  TermWin.fwidth,
191 		  TermWin.fheight,
192 		  (long)GRX_SCALE * TermWin.fwidth
193 		        / (TermWin.width - 2 * TermWin_internalBorder),
194 		  (long)GRX_SCALE * TermWin.fheight
195 		        / (TermWin.height - 2 * TermWin_internalBorder),
196 		  Xdepth);
197 #endif
198 }
199 
200 /* ARGSUSED */
201 /* PROTO */
202 void
Gr_DestroyWindow(grwin_t * grwin)203 Gr_DestroyWindow(grwin_t * grwin)
204 {
205 #ifdef RXVT_GRAPHICS
206     grcmd_t        *cmd, *next;
207 
208     if (grwin == NULL)
209 	return;
210 
211     for (cmd = grwin->graphics; cmd; cmd = next) {
212 	next = cmd->next;
213 	free(cmd->coords);
214 	if (cmd->text != NULL)
215 	    free(cmd->text);
216 	free(cmd);
217     }
218 
219     XDestroyWindow(Xdisplay, grwin->win);
220     if (grwin->next != NULL)
221 	grwin->next->prev = grwin->prev;
222     if (grwin->prev != NULL)
223 	grwin->prev->next = grwin->next;
224     else
225 	gr_root = grwin->next;
226     free(grwin);
227 
228     graphics_up--;
229 #endif
230 }
231 
232 /* ARGSUSED */
233 /* PROTO */
234 void
Gr_Dispatch(grwin_t * grwin,grcmd_t * data)235 Gr_Dispatch(grwin_t * grwin, grcmd_t * data)
236 {
237 #ifdef RXVT_GRAPHICS
238     int             i, n;
239     union {
240 	XPoint          pt[NGRX_PTS / 2];
241 	XRectangle      rect[NGRX_PTS / 4];
242     } xdata;
243 
244     if (data->color != Color_fg) {
245 	XGCValues       gcv;
246 
247 	gcv.foreground = PixColors[data->color];
248 	XChangeGC(Xdisplay, TermWin.gc, GCForeground, &gcv);
249     }
250     if (grwin)
251 	switch (data->cmd) {
252 	case 'L':
253 	    if (data->ncoords > 3) {
254 		for (n = i = 0; i < data->ncoords; i += 2, n++) {
255 		    xdata.pt[n].x = data->coords[i] * grwin->w / GRX_SCALE;
256 		    xdata.pt[n].y = data->coords[i + 1] * grwin->h / GRX_SCALE;
257 		}
258 		XDrawLines(Xdisplay,
259 		       grwin->win, TermWin.gc, xdata.pt, n, CoordModeOrigin);
260 	    }
261 	    break;
262 
263 	case 'P':
264 	    if (data->ncoords > 3) {
265 		for (n = i = 0; i < data->ncoords; i += 2, n++) {
266 		    xdata.pt[n].x = data->coords[i] * grwin->w / GRX_SCALE;
267 		    xdata.pt[n].y = data->coords[i + 1] * grwin->h / GRX_SCALE;
268 		}
269 		XDrawPoints(Xdisplay,
270 		       grwin->win, TermWin.gc, xdata.pt, n, CoordModeOrigin);
271 	    }
272 	    break;
273 
274 	case 'F':
275 	    if (data->ncoords > 0) {
276 		for (n = i = 0; i < data->ncoords; i += 4, n++) {
277 		    xdata.rect[n].x = data->coords[i] * grwin->w / GRX_SCALE;
278 		    xdata.rect[n].y = data->coords[i + 1] * grwin->h
279 				      / GRX_SCALE;
280 		    xdata.rect[n].width = ((data->coords[i + 2]
281 					    - data->coords[i] + 1) *
282 					   grwin->w / GRX_SCALE);
283 		    xdata.rect[n].height = ((data->coords[i + 3]
284 					     - data->coords[i + 1] + 1) *
285 					    grwin->h / GRX_SCALE);
286 		    XPMClearArea(Xdisplay, grwin->win,
287 				 xdata.rect[n].x, xdata.rect[n].y,
288 				 xdata.rect[n].width, xdata.rect[n].height,
289 				 0);
290 		}
291 		XFillRectangles(Xdisplay, grwin->win, TermWin.gc, xdata.rect,
292 				n);
293 	    }
294 	    break;
295 	case 'T':
296 	    Gr_Text(grwin, data);
297 	    break;
298 	case 'C':
299 	    Gr_ClearWindow(grwin);
300 	    break;
301 	}
302     if (data->color != Color_fg) {
303 	XGCValues       gcv;
304 
305 	gcv.foreground = PixColors[Color_fg];
306 	XChangeGC(Xdisplay, TermWin.gc, GCForeground, &gcv);
307     }
308 #endif
309 }
310 
311 /* ARGSUSED */
312 /* PROTO */
313 void
Gr_Redraw(grwin_t * grwin)314 Gr_Redraw(grwin_t * grwin)
315 {
316 #ifdef RXVT_GRAPHICS
317     grcmd_t        *cmd;
318 
319     for (cmd = grwin->graphics; cmd != NULL; cmd = cmd->next)
320 	Gr_Dispatch(grwin, cmd);
321 #endif
322 }
323 
324 /*----------------------------------------------------------------------*
325  * end of static functions
326  */
327 /* ARGSUSED */
328 /* PROTO */
329 void
Gr_ButtonReport(int but,int x,int y)330 Gr_ButtonReport(int but, int x, int y)
331 {
332 #ifdef RXVT_GRAPHICS
333     grwin_t        *grwin;
334 
335     for (grwin = gr_root; grwin != NULL; grwin = grwin->next)
336 	if ((x > grwin->x) &&
337 	    (y > grwin->y) &&
338 	    (x < grwin->x + grwin->w) &&
339 	    (y < grwin->y + grwin->h))
340 	    break;
341 
342     if (grwin == NULL)
343 	return;
344 
345     x = GRX_SCALE * (x - grwin->x) / grwin->w;
346     y = GRX_SCALE * (y - grwin->y) / grwin->h;
347     tt_printf("\033%c%ld;%d;%d;\n", but, (long)grwin->win, x, y);
348 #endif
349 }
350 
351 /* ARGSUSED */
352 /* PROTO */
353 void
Gr_do_graphics(int cmd,int nargs,int args[],unsigned char * text)354 Gr_do_graphics(int cmd, int nargs, int args[], unsigned char *text)
355 {
356 #ifdef RXVT_GRAPHICS
357     static Window   last_id = None;
358     long            win_id;
359     grwin_t        *grwin;
360     grcmd_t        *newcmd, *oldcmd;
361     int             i;
362 
363     if (cmd == 'W') {
364 	Gr_NewWindow(nargs, args);
365 	return;
366     }
367     win_id = (nargs > 0) ? (Window) args[0] : None;
368 
369     if ((cmd == 'G') && (win_id == None)) {
370 	Gr_Geometry(NULL, NULL);
371 	return;
372     }
373     if ((win_id == None) && (last_id != None))
374 	win_id = last_id;
375 
376     if (win_id == None)
377 	return;
378 
379     grwin = gr_root;
380     while ((grwin != NULL) && (grwin->win != win_id))
381 	grwin = grwin->next;
382 
383     if (grwin == NULL)
384 	return;
385 
386     if (cmd == 'G') {
387 	Gr_Geometry(grwin, NULL);
388 	return;
389     }
390     nargs--;
391     args++;			/* skip over window id */
392 
393 /* record this new command */
394     newcmd = (grcmd_t *) MALLOC(sizeof(grcmd_t));
395     newcmd->ncoords = nargs;
396     newcmd->coords = (int *)MALLOC((newcmd->ncoords * sizeof(int)));
397 
398     newcmd->next = NULL;
399     newcmd->cmd = cmd;
400     newcmd->color = scr_get_fgcolor();
401     newcmd->text = text;
402 
403     for (i = 0; i < newcmd->ncoords; i++)
404 	newcmd->coords[i] = args[i];
405 
406 /*
407  * If newcmd == fill, and rectangle is full window, drop all prior
408  * commands.
409  */
410     if ((newcmd->cmd == 'F') && (grwin) && (grwin->graphics)) {
411 	for (i = 0; i < newcmd->ncoords; i += 4) {
412 	    if ((newcmd->coords[i] == 0) &&
413 		(newcmd->coords[i + 1] == 0) &&
414 		(newcmd->coords[i + 2] == GRX_SCALE) &&
415 		(newcmd->coords[i + 3] == GRX_SCALE)) {
416 	    /* drop previous commands */
417 		oldcmd = grwin->graphics;
418 		while (oldcmd->next != NULL) {
419 		    grcmd_t        *tmp = oldcmd;
420 
421 		    oldcmd = oldcmd->next;
422 		    free(tmp);
423 		}
424 		grwin->graphics = NULL;
425 	    }
426 	}
427     }
428 /* insert new command into command list */
429     oldcmd = grwin->graphics;
430     if (oldcmd == NULL)
431 	grwin->graphics = newcmd;
432     else {
433 	while (oldcmd->next != NULL)
434 	    oldcmd = oldcmd->next;
435 	oldcmd->next = newcmd;
436     }
437     Gr_Dispatch(grwin, newcmd);
438 #endif
439 }
440 
441 /* ARGSUSED */
442 /* PROTO */
443 void
Gr_scroll(int count)444 Gr_scroll(int count)
445 {
446 #ifdef RXVT_GRAPHICS
447     static short    prev_start = 0;
448     grwin_t        *grwin, *next;
449 
450     if ((count == 0) && (prev_start == TermWin.view_start))
451 	return;
452 
453     prev_start = TermWin.view_start;
454 
455     for (grwin = gr_root; grwin != NULL; grwin = next) {
456 	next = grwin->next;
457 	grwin->y -= (count * TermWin.fheight);
458 	if ((grwin->y + grwin->h) < -(TermWin.saveLines * TermWin.fheight))
459 	    Gr_DestroyWindow(grwin);
460 	else
461 	    XMoveWindow(Xdisplay, grwin->win,
462 			grwin->x,
463 			grwin->y + (TermWin.view_start * TermWin.fheight));
464     }
465 #endif
466 }
467 
468 /* PROTO */
469 void
Gr_ClearScreen(void)470 Gr_ClearScreen(void)
471 {
472 #ifdef RXVT_GRAPHICS
473     grwin_t        *grwin, *next;
474 
475     for (grwin = gr_root; grwin != NULL; grwin = next) {
476 	next = grwin->next;
477 	if ((grwin->screen == 0) && (grwin->y + grwin->h > 0)) {
478 	    if (grwin->y >= 0)
479 		Gr_DestroyWindow(grwin);
480 	    else
481 		XResizeWindow(Xdisplay, grwin->win,
482 			      grwin->w, -grwin->y);
483 	}
484     }
485 #endif
486 }
487 
488 /* PROTO */
489 void
Gr_ChangeScreen(void)490 Gr_ChangeScreen(void)
491 {
492 #ifdef RXVT_GRAPHICS
493     grwin_t        *grwin, *next;
494 
495     for (grwin = gr_root; grwin != NULL; grwin = next) {
496 	next = grwin->next;
497 	if (grwin->y + grwin->h > 0) {
498 	    if (grwin->screen == 1) {
499 		XMapWindow(Xdisplay, grwin->win);
500 		grwin->screen = 0;
501 	    } else {
502 		XUnmapWindow(Xdisplay, grwin->win);
503 		grwin->screen = 1;
504 	    }
505 	}
506     }
507 #endif
508 }
509 
510 /* ARGSUSED */
511 /* PROTO */
512 void
Gr_expose(Window win)513 Gr_expose(Window win)
514 {
515 #ifdef RXVT_GRAPHICS
516     grwin_t        *grwin;
517 
518     for (grwin = gr_root; grwin != NULL; grwin = grwin->next) {
519 	if (grwin->win == win) {
520 	    Gr_Redraw(grwin);
521 	    break;
522 	}
523     }
524 #endif
525 }
526 
527 /* ARGSUSED */
528 /* PROTO */
529 void
Gr_Resize(int w,int h)530 Gr_Resize(int w, int h)
531 {
532 #ifdef RXVT_GRAPHICS
533     grwin_t        *grwin;
534 
535     for (grwin = gr_root; grwin != NULL; grwin = grwin->next) {
536 	if (TermWin.height != h) {
537 	    grwin->y += (TermWin.height - h);
538 	    XMoveWindow(Xdisplay, grwin->win,
539 			grwin->x,
540 			grwin->y + (TermWin.view_start * TermWin.fheight));
541 	}
542 	Gr_Redraw(grwin);
543     }
544 #endif
545 }
546 
547 /* PROTO */
548 void
Gr_reset(void)549 Gr_reset(void)
550 {
551 #ifdef RXVT_GRAPHICS
552     grwin_t        *grwin, *next;
553 
554     for (grwin = gr_root; grwin != NULL; grwin = next) {
555 	next = grwin->next;
556 	Gr_DestroyWindow(grwin);
557     }
558 
559     graphics_up = 0;
560 #endif
561 }
562 
563 /* PROTO */
564 int
Gr_Displayed(void)565 Gr_Displayed(void)
566 {
567 #ifdef RXVT_GRAPHICS
568     return graphics_up;
569 #else
570     return 0;
571 #endif
572 }
573 /*----------------------- end-of-file (C source) -----------------------*/
574