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