1 /*
2 * A Z-Machine
3 * Copyright (C) 2000 Andrew Hunter
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /*
21 * Display for X-Windows
22 */
23
24 #include "../config.h"
25
26 #if WINDOW_SYSTEM == 1
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35
36 #include "xdisplay.h"
37 #include "xfont.h"
38
39 #include <X11/cursorfont.h>
40
41 #include "zmachine.h"
42 #include "display.h"
43 #include "v6display.h"
44 #include "rc.h"
45
46 #include "image.h"
47 #include "image_ximage.h"
48
49 #include "format.h"
50
51 #ifdef HAVE_XRENDER
52 # include <X11/extensions/Xrender.h>
53 #endif
54
55 #ifdef HAVE_XFT
56 # include <X11/Xft/Xft.h>
57 #endif
58
59 #ifdef HAVE_XDBE
60 # include <X11/extensions/Xdbe.h>
61 #endif
62
63 /* #define DEBUG */
64
65 /* Globals */
66 Display* x_display;
67 int x_screen = 0;
68
69 Window x_mainwin;
70 GC x_wingc, x_caretgc;
71 Drawable x_drawable = None;
72
73 Pixmap x_pixmap = None;
74 GC x_pixgc;
75
76 static int pix_w, pix_h;
77 static int pix_fore;
78 static int pix_back;
79
80 static int mousew_x, mousew_y, mousew_w, mousew_h = -1;
81
82 static Cursor scrollCursor;
83 static Cursor noClickHere;
84 static Cursor arrowCursor;
85 static Cursor clickCursor;
86
87 #ifdef HAVE_XRENDER
88 XRenderPictFormat* x_picformat = NULL;
89 Picture x_winpic = None;
90 Picture x_pixpic = None;
91 #endif
92
93 #ifdef HAVE_XDBE
94 XdbeBackBuffer x_backbuffer = None;
95 #endif
96
97 static Region dregion = None;
98 static int updatecount = 0;
99 static int resetregion = 0;
100
101 static int scroll_pos = 20;
102 static int scroll_range = 500;
103 static int scroll_height = 100;
104 static int scroll_top = 0;
105 int scrollpos = 0;
106
107 /* (Used by a scroll in progress) */
108 static int scroll_start = 0;
109 static int scroll_offset = 0;
110 static int scroll_state = 0;
111 static int scrolling = 0;
112
113 static int win_left, win_top;
114 static int win_width, win_height;
115 static int click_x, click_y, click_b;
116 static Time click_time;
117
118 static Atom x_prot[5];
119 static Atom wmprots;
120
121 #define SCROLLBAR_SIZE 15
122 #undef BORDER_PLAIN
123
124 #ifndef BORDER_PLAIN
125 # define BORDER_3D
126 # define BORDER_SIZE 4
127 #else
128 # define BORDER_SIZE 1
129 #endif
130
131 #define N_COLS 18
132 XColor x_colour[N_COLS] =
133 { { 0, 0xbb00,0xbb00,0xbb00, DoRed|DoGreen|DoBlue, 0 },
134 { 0, 0x6600,0x6600,0x6600, DoRed|DoGreen|DoBlue, 0 },
135 { 0, 0xff00,0xff00,0xff00, DoRed|DoGreen|DoBlue, 0 },
136 { 0, 0xee00,0xee00,0xee00, DoRed|DoGreen|DoBlue, 0 },
137
138 /* Scrollbar colours */
139 { 0, 0x0080,0x9900,0xee00, DoRed|DoGreen|DoBlue, 0 },
140 { 0, 0x00bb,0xdd00,0xff00, DoRed|DoGreen|DoBlue, 0 },
141 { 0, 0x0020,0x6600,0xaa00, DoRed|DoGreen|DoBlue, 0 },
142
143 /* ZMachine colours start here */
144 { 0, 0x0000,0x0000,0x0000, DoRed|DoGreen|DoBlue, 0 },
145 { 0, 0xff00,0x0000,0x0000, DoRed|DoGreen|DoBlue, 0 },
146 { 0, 0x0000,0xff00,0x0000, DoRed|DoGreen|DoBlue, 0 },
147 { 0, 0xff00,0xff00,0x0000, DoRed|DoGreen|DoBlue, 0 },
148 { 0, 0x0000,0x0000,0xff00, DoRed|DoGreen|DoBlue, 0 },
149 { 0, 0xff00,0x0000,0xff00, DoRed|DoGreen|DoBlue, 0 },
150 { 0, 0x0000,0xff00,0xff00, DoRed|DoGreen|DoBlue, 0 },
151 { 0, 0xff00,0xff00,0xcc00, DoRed|DoGreen|DoBlue, 0 },
152
153 { 0, 0xbb00,0xbb00,0xbb00, DoRed|DoGreen|DoBlue, 0 },
154 { 0, 0x8800,0x8800,0x8800, DoRed|DoGreen|DoBlue, 0 },
155 { 0, 0x4400,0x4400,0x4400, DoRed|DoGreen|DoBlue, 0 }};
156
157 #ifdef HAVE_XFT
158 XftColor xft_colour[N_COLS];
159 XftDraw* xft_drawable;
160 XftDraw* xft_maindraw = NULL;
161 #endif
162
163 #define DEFAULT_FORE 0
164 #define DEFAULT_BACK 7
165 #define FIRST_ZCOLOUR 7
166
167 static unsigned char terminating[256] =
168 {
169 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
170 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
171 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
172 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
173 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
174 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
175 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
176 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
177 };
178
179 /* === Misc functions === */
180
istrlen(const int * string)181 static inline int istrlen(const int* string)
182 {
183 int x = 0;
184
185 while (string[x] != 0) x++;
186 return x;
187 }
istrcpy(int * dest,const int * src)188 static inline void istrcpy(int* dest, const int* src)
189 {
190 int x;
191
192 for (x=0; src[x] != 0; x++)
193 {
194 dest[x] = src[x];
195 }
196 dest[x] = 0;
197 }
198
199 /* === Functions specific to this display style === */
200 static int ntruecols = 0;
201 static XColor* truecol = NULL;
202
xdisplay_get_pixel_value(int colour)203 long int xdisplay_get_pixel_value(int colour)
204 {
205 if (colour < 16)
206 {
207 /* Standard z-colour */
208
209 /* NOTE: colour 15 = transparent... */
210 return x_colour[colour+FIRST_ZCOLOUR].pixel;
211 }
212 else
213 {
214 XColor col;
215 int x;
216
217 /* True colour */
218 colour -= 16;
219
220 col.red = (colour&0x001f)<<11;
221 col.green = (colour&0x03e0)<<6;
222 col.blue = (colour&0x7c00)<<1;
223
224 /* Try to find this colour */
225 for (x=0; x<ntruecols; x++)
226 {
227 long int err;
228 int r,g,b;
229
230 r = truecol[x].red - col.red;
231 g = truecol[x].green - col.green;
232 b = truecol[x].blue - col.blue;
233
234 /* Sort of RMS error */
235 err = (r>>8)*(r>>8) + (g>>8)*(g>>8) + (b>>8)*(b>>8);
236
237 if (err <= 192)
238 {
239 return truecol[x].pixel;
240 }
241 }
242
243 /* Try to allocate this colour */
244 if (!XAllocColor(x_display, DefaultColormap(x_display, x_screen),
245 &col))
246 {
247 int x;
248 long int lowerror, lowerrorcol;
249
250 lowerror = 196608;
251 lowerrorcol = -1;
252
253 /* Find the closest match instead... */
254 for (x=FIRST_ZCOLOUR; x<FIRST_ZCOLOUR+8; x++)
255 {
256 long int err;
257 int r,g,b;
258
259 r = x_colour[x].red - col.red;
260 g = x_colour[x].green - col.green;
261 b = x_colour[x].blue - col.blue;
262
263 /* Sort of RMS error */
264 err = (r>>8)*(r>>8) + (g>>8)*(g>>8) + (b>>8)*(b>>8);
265
266 if (err < lowerror)
267 {
268 lowerrorcol = x;
269 lowerror = err;
270 }
271 }
272
273 if (lowerrorcol == -1)
274 zmachine_fatal("Unable to find a suitable colour for colour #%x\n", colour);
275
276 return x_colour[lowerrorcol].pixel;
277 }
278 else
279 {
280 ntruecols++;
281 truecol = realloc(truecol, sizeof(XColor)*ntruecols);
282 truecol[ntruecols-1] = col;
283
284 return col.pixel;
285 }
286 }
287 }
288
289 #ifdef HAVE_XFT
alloc_xft_colours(void)290 static void alloc_xft_colours(void)
291 {
292 int x;
293
294 for (x=0; x<N_COLS; x++)
295 {
296 XRenderColor fcolour;
297
298 fcolour.red = x_colour[x].red;
299 fcolour.green = x_colour[x].green;
300 fcolour.blue = x_colour[x].blue;
301 fcolour.alpha = 0xffff;
302
303 if (!XftColorAllocValue(x_display, DefaultVisual(x_display, x_screen),
304 DefaultColormap(x_display, x_screen),
305 &fcolour,
306 &xft_colour[x]))
307 {
308 fprintf(stderr, "Unable to allocate colour for Xft\n");
309 }
310 }
311 }
312
313 static int nxftruecols = 0;
314 static XftColor* xftruecol = NULL;
315 static XRenderColor* rendercol = NULL;
316
xdisplay_get_xft_colour(int colour)317 XftColor* xdisplay_get_xft_colour(int colour)
318 {
319 if (colour < 16)
320 {
321 /* Standard z-colour */
322
323 /* NOTE: colour 15 = transparent... */
324 return &xft_colour[colour+FIRST_ZCOLOUR];
325 }
326 else
327 {
328 XRenderColor col;
329 XftColor xft_col;
330 int x;
331
332 /* True colour */
333 colour -= 16;
334
335 col.red = (colour&0x001f)<<11;
336 col.green = (colour&0x03e0)<<6;
337 col.blue = (colour&0x7c00)<<1;
338 col.alpha = 0xffff;
339
340 /* Try to find this colour */
341 for (x=0; x<nxftruecols; x++)
342 {
343 long int err;
344 int r,g,b;
345
346 r = rendercol[x].red - col.red;
347 g = rendercol[x].green - col.green;
348 b = rendercol[x].blue - col.blue;
349
350 /* Sort of RMS error */
351 err = (r>>8)*(r>>8) + (g>>8)*(g>>8) + (b>>8)*(b>>8);
352
353 if (err <= 192)
354 {
355 return &xftruecol[x];
356 }
357 }
358
359 /* Try to allocate this colour */
360 if (!XftColorAllocValue(x_display, DefaultVisual(x_display, x_screen),
361 DefaultColormap(x_display, x_screen),
362 &col,
363 &xft_col))
364 {
365 int x;
366 long int lowerror, lowerrorcol;
367
368 lowerror = 196608;
369 lowerrorcol = -1;
370
371 /* Find the closest match instead... */
372 for (x=FIRST_ZCOLOUR; x<FIRST_ZCOLOUR+8; x++)
373 {
374 long int err;
375 int r,g,b;
376
377 r = x_colour[x].red - col.red;
378 g = x_colour[x].green - col.green;
379 b = x_colour[x].blue - col.blue;
380
381 /* Sort of RMS error */
382 err = (r>>8)*(r>>8) + (g>>8)*(g>>8) + (b>>8)*(b>>8);
383
384 if (err < lowerror)
385 {
386 lowerrorcol = x;
387 lowerror = err;
388 }
389 }
390
391 if (lowerrorcol == -1)
392 zmachine_fatal("Unable to find a suitable colour for colour #%x\n", colour);
393
394 return &xft_colour[lowerrorcol];
395 }
396 else
397 {
398 nxftruecols++;
399 xftruecol = realloc(xftruecol, sizeof(XftColor)*nxftruecols);
400 xftruecol[nxftruecols-1] = xft_col;
401 rendercol = realloc(rendercol, sizeof(XRenderColor)*nxftruecols);
402 rendercol[nxftruecols-1] = col;
403
404 return &xftruecol[nxftruecols-1];
405 }
406 }
407 }
408 #endif
409
reset_clip(void)410 static void reset_clip(void)
411 {
412 if (resetregion)
413 {
414 XRectangle clip;
415 Region rgn;
416
417 clip.x = clip.y = BORDER_SIZE;
418 clip.width = win_x; clip.height = win_y;
419
420 rgn = XCreateRegion();
421 XUnionRectWithRegion(&clip, rgn, rgn);
422 XSetRegion(x_display, x_wingc, rgn);
423 #ifdef HAVE_XFT
424 if (xft_drawable != NULL)
425 XftDrawSetClip(xft_drawable, rgn);
426 if (x_pixmap != None)
427 {
428 XftDrawSetClip(xft_drawable, None);
429 }
430 #endif
431
432 resetregion = 0;
433 XFree(rgn);
434 }
435 }
436
invalidate_scrollbar(void)437 static void invalidate_scrollbar(void)
438 {
439 XRectangle thebar;
440
441 if (dregion == None)
442 dregion = XCreateRegion();
443
444 thebar.x = win_x + BORDER_SIZE*2;
445 thebar.y = 0;
446 thebar.width = SCROLLBAR_SIZE;
447 thebar.height = total_y;
448 XUnionRectWithRegion(&thebar, dregion, dregion);
449 }
450
draw_caret(void)451 static void draw_caret(void)
452 {
453 int ison;
454
455 reset_clip();
456
457 if (insert)
458 XSetLineAttributes(x_display, x_caretgc, 2, LineSolid,
459 CapButt, JoinBevel);
460 else
461 XSetLineAttributes(x_display, x_caretgc, 4, LineSolid,
462 CapButt, JoinBevel);
463
464 if (!caret_flashing)
465 {
466 XSetLineAttributes(x_display, x_caretgc, 1, LineSolid,
467 CapButt, JoinBevel);
468 }
469
470 XSetForeground(x_display, x_caretgc,
471 xdisplay_get_pixel_value(CURWIN.back) ^
472 x_colour[4].pixel);
473
474 ison = caret_on;
475 if (more_on)
476 ison = 0;
477
478 if ((ison^caret_shown))
479 {
480 if (!caret_flashing)
481 {
482 XDrawRectangle(x_display, x_mainwin, x_caretgc,
483 caret_x + BORDER_SIZE - 2, caret_y + BORDER_SIZE,
484 4, caret_height);
485 }
486 else
487 {
488 XDrawLine(x_display, x_mainwin, x_caretgc,
489 caret_x + BORDER_SIZE, caret_y + BORDER_SIZE,
490 caret_x + BORDER_SIZE, caret_y + caret_height + BORDER_SIZE);
491 }
492
493 caret_shown = !caret_shown;
494 }
495 }
496
497 static int pix_cstyle = 0;
498 static int pix_cx = 0;
499 static int pix_cy = 0;
500 static int pix_cw = 0;
501
display_set_input_pos(int style,int x,int y,int width)502 void display_set_input_pos(int style, int x, int y, int width)
503 {
504 pix_cstyle = style;
505 pix_cx = x; pix_cy = y;
506 pix_cw = width;
507 }
508
move_caret(void)509 static void move_caret(void)
510 {
511 int last_on = caret_on;
512
513 /* Handled elsewhere for pixmap displays */
514
515 caret_on = 0;
516 draw_caret();
517
518 if (x_pixmap != None)
519 {
520 int xp, yp;
521
522 xp = win_x/2-pix_w/2;
523 yp = win_y/2-pix_h/2;
524
525 input_x = caret_x = pix_cx;
526 input_y = caret_y = pix_cy;
527 input_y += xfont_get_ascent(font[style_font[(pix_cstyle>>1)&15]]);
528 caret_height = xfont_get_height(font[style_font[(pix_cstyle>>1)&15]]);
529
530 input_x += xp; caret_x += xp;
531 input_y += yp; caret_y += yp;
532
533 if (text_buf != NULL)
534 {
535 caret_x += xfont_get_text_width(font[style_font[(pix_cstyle>>1)&15]],
536 text_buf,
537 buf_offset);
538 }
539 }
540 else
541 {
542 if (CURWIN.overlay)
543 {
544 input_x = caret_x = xfont_x*CURWIN.xpos;
545 input_y = caret_y = xfont_y*CURWIN.ypos;
546 input_y += xfont_get_ascent(font[style_font[(CURSTYLE>>1)&15]]);
547 caret_height = xfont_y;
548 }
549 else
550 {
551 if (CURWIN.lastline != NULL)
552 {
553 input_x = caret_x = CURWIN.xpos;
554 input_y = caret_y = CURWIN.lastline->baseline-scrollpos;
555 caret_y -= CURWIN.lastline->ascent;
556 caret_height = CURWIN.lastline->ascent+CURWIN.lastline->descent-1;
557 }
558 else
559 {
560 input_x = input_y = caret_x = caret_y = 0;
561 caret_height = xfont_y-1;
562 }
563 }
564
565 if (text_buf != NULL)
566 {
567 caret_x += xfont_get_text_width(font[style_font[(CURSTYLE>>1)&15]],
568 text_buf,
569 buf_offset);
570 }
571 }
572
573 caret_on = last_on;
574 draw_caret();
575 }
576
show_caret(void)577 static void show_caret(void)
578 {
579 caret_on = 1;
580 draw_caret();
581 }
582
hide_caret(void)583 static void hide_caret(void)
584 {
585 caret_on = 0;
586 draw_caret();
587 }
588
draw_input_text(void)589 static void draw_input_text(void)
590 {
591 int w;
592 int on;
593 int fg, bg;
594 int style;
595
596 reset_clip();
597
598 fg = CURWIN.fore;
599 bg = CURWIN.back;
600
601 if (CURWIN.style&1)
602 {
603 fg = CURWIN.back;
604 bg = CURWIN.fore;
605 }
606
607 on = caret_on;
608 hide_caret();
609
610 move_caret();
611 style = CURSTYLE;
612
613 if (x_pixmap != None)
614 {
615 int xp, yp;
616
617 xp = win_x/2-pix_w/2;
618 yp = win_y/2-pix_h/2;
619
620 style = pix_cstyle;
621
622 input_x = caret_x = pix_cx;
623 input_y = caret_y = pix_cy;
624 input_y += xfont_get_ascent(font[style_font[(pix_cstyle>>1)&15]]);
625 input_width = pix_cw;
626 caret_height = xfont_get_height(font[style_font[(pix_cstyle>>1)&15]])-1;
627
628 input_x += xp; input_y += yp;
629 caret_x += xp; caret_y += yp;
630
631 fg = pix_fore;
632 bg = pix_back;
633 }
634 else
635 {
636 if (CURWIN.overlay)
637 {
638 input_x = caret_x = xfont_x*CURWIN.xpos;
639 input_y = caret_y = xfont_y*CURWIN.ypos;
640 input_y += xfont_get_ascent(font[style_font[(CURSTYLE>>1)&15]]);
641 caret_height = xfont_y;
642 }
643 else
644 {
645 if (CURWIN.lastline != NULL)
646 {
647 input_x = caret_x = CURWIN.xpos;
648 input_y = caret_y = CURWIN.lastline->baseline-scrollpos;
649 caret_y -= CURWIN.lastline->ascent;
650 caret_height = CURWIN.lastline->ascent+CURWIN.lastline->descent-1;
651 }
652 else
653 {
654 input_x = input_y = caret_x = caret_y = 0;
655 caret_height = xfont_y-1;
656 }
657 }
658
659 input_width = win_x - input_x;
660 }
661
662 if (text_buf != NULL)
663 {
664 w = xfont_get_text_width(font[style_font[(style>>1)&15]],
665 text_buf,
666 istrlen(text_buf));
667
668 XSetForeground(x_display, x_wingc, xdisplay_get_pixel_value(bg));
669 XFillRectangle(x_display, x_mainwin, x_wingc,
670 input_x + BORDER_SIZE,
671 caret_y + BORDER_SIZE,
672 input_width,
673 xfont_get_height(font[style_font[(style>>1)&15]])+0.5);
674
675 caret_x += xfont_get_text_width(font[style_font[(style>>1)&15]],
676 text_buf,
677 buf_offset);
678
679 xfont_set_colours(fg, bg);
680 #ifdef HAVE_XFT
681 { XftDraw* xft_lastdraw = xft_drawable; /* Save the last drawable */
682 if (xft_drawable != NULL && xft_maindraw != NULL)
683 {
684 /*
685 * Need to draw any XFT stuff on the main window, not the hidden
686 * buffer
687 */
688 xft_lastdraw = xft_drawable;
689 xft_drawable = xft_maindraw;
690 }
691 #endif
692 xfont_plot_string(font[style_font[(style>>1)&15]],
693 x_mainwin, x_wingc,
694 input_x+BORDER_SIZE, input_y+BORDER_SIZE,
695 text_buf,
696 istrlen(text_buf));
697 #ifdef HAVE_XFT
698 if (xft_drawable != NULL && xft_maindraw != NULL)
699 {
700 xft_drawable = xft_lastdraw;
701 }
702 }
703 #endif
704 }
705
706 if (on)
707 show_caret();
708 }
709
710 static void resize_window(void);
size_window(void)711 static void size_window(void)
712 {
713 XSizeHints* hints;
714
715 win_x = size_x*xfont_x;
716 win_y = size_y*xfont_y;
717
718 hints = XAllocSizeHints();
719 hints->min_width = 200;
720 hints->min_height = 100;
721 hints->width = win_x+BORDER_SIZE*2;
722 hints->height = win_y+BORDER_SIZE*2;
723 hints->flags = PSize|PMinSize;
724 XSetWMNormalHints(x_display, x_mainwin, hints);
725 XFree(hints);
726
727 XResizeWindow(x_display, x_mainwin,
728 total_x=(win_x+BORDER_SIZE*2+SCROLLBAR_SIZE),
729 total_y=(win_y+BORDER_SIZE*2));
730 }
731
draw_scrollbar(int isselected)732 static void draw_scrollbar(int isselected)
733 {
734 int pos, height;
735 int x;
736
737 int ca, cb;
738
739 static XColor scroll_grade[8] = { { 0, 0,0,0, DoRed|DoGreen|DoBlue, 0 } };
740
741 #ifdef BORDER_3D
742 # define SG_FROM 0
743 # define SG_TO 3
744 #else
745 # define SG_FROM 2
746 # define SG_TO 0
747 #endif
748
749 reset_clip();
750
751 ca = 5; cb = 6;
752
753 if (isselected)
754 {
755 ca = 6; cb = 5;
756 }
757
758 /* Allocate colours if necessary */
759 if (scroll_grade[0].red == 0)
760 {
761 for (x=0; x<8; x++)
762 {
763 scroll_grade[x].red = x_colour[SG_FROM].red +
764 (((x_colour[SG_TO].red - x_colour[SG_FROM].red)*(x+1))/(8));
765 scroll_grade[x].green = x_colour[SG_FROM].green +
766 (((x_colour[SG_TO].green - x_colour[SG_FROM].green)*(x+1))/8);
767 scroll_grade[x].blue = x_colour[SG_FROM].blue +
768 (((x_colour[SG_TO].blue - x_colour[SG_FROM].blue)*(x+1))/8);
769
770 scroll_grade[x].flags = DoRed|DoGreen|DoBlue;
771 scroll_grade[x].pixel = 0;
772 scroll_grade[x].pad = 0;
773
774 if (!XAllocColor(x_display, DefaultColormap(x_display, x_screen),
775 &scroll_grade[x]))
776 {
777 scroll_grade[x].pixel = BlackPixel(x_display, x_screen);
778 }
779 }
780 }
781
782 #ifdef HAVE_XFT
783 alloc_xft_colours();
784 #endif
785
786 /* Draw the scrollbar well */
787 for (x=0; x<8; x++)
788 {
789 XSetForeground(x_display, x_wingc, scroll_grade[x].pixel);
790 XFillRectangle(x_display, x_drawable, x_wingc,
791 win_x+BORDER_SIZE*2 + ((x*SCROLLBAR_SIZE)/8), 0,
792 SCROLLBAR_SIZE, total_y);
793 }
794
795 if (scroll_range == 0)
796 return;
797
798 /* Calculate the position and size of the scrollbar tab */
799 pos = (scroll_pos*total_y)/scroll_range;
800 height = (scroll_height*total_y)/scroll_range;
801
802 if (height < 20)
803 height = 20;
804
805 if (pos > total_y)
806 pos = total_y-height-1;
807 if (pos + height >= total_y)
808 {
809 pos -= (pos+height)-total_y+1;
810 }
811
812 if (pos < 0 || (pos+height) >= total_y)
813 return;
814
815 /* Draw the scrollbar tab */
816 XSetForeground(x_display, x_wingc, x_colour[4].pixel);
817 XFillRectangle(x_display, x_drawable, x_wingc,
818 win_x+BORDER_SIZE*2, pos,
819 SCROLLBAR_SIZE, height);
820
821 XSetForeground(x_display, x_wingc, x_colour[ca].pixel);
822 XDrawLine(x_display, x_drawable, x_wingc,
823 win_x+BORDER_SIZE*2, pos,
824 win_x+BORDER_SIZE*2+SCROLLBAR_SIZE, pos);
825 XDrawLine(x_display, x_drawable, x_wingc,
826 win_x+BORDER_SIZE*2, pos,
827 win_x+BORDER_SIZE*2, pos+height);
828
829 XSetForeground(x_display, x_wingc, x_colour[cb].pixel);
830 XDrawLine(x_display, x_drawable, x_wingc,
831 win_x+BORDER_SIZE*2, pos+height,
832 win_x+BORDER_SIZE*2+SCROLLBAR_SIZE, pos+height);
833 XDrawLine(x_display, x_drawable, x_wingc,
834 win_x+BORDER_SIZE*2+SCROLLBAR_SIZE-1, pos,
835 win_x+BORDER_SIZE*2+SCROLLBAR_SIZE-1, pos+height);
836
837 /* Draw the ridges */
838 XSetForeground(x_display, x_wingc, x_colour[ca].pixel);
839 for (x=0; x<3; x++)
840 {
841 int ypos;
842
843 ypos = pos + (height/2) - 4 + x*4;
844 XDrawLine(x_display, x_drawable, x_wingc,
845 win_x+BORDER_SIZE*2+3, ypos,
846 win_x+BORDER_SIZE*2+SCROLLBAR_SIZE-4, ypos);
847 }
848
849 XSetForeground(x_display, x_wingc, x_colour[cb].pixel);
850 for (x=0; x<3; x++)
851 {
852 int ypos;
853
854 ypos = pos + (height/2) - 3 + x*4;
855 XDrawLine(x_display, x_drawable, x_wingc,
856 win_x+BORDER_SIZE*2+3, ypos,
857 win_x+BORDER_SIZE*2+SCROLLBAR_SIZE-4, ypos);
858 }
859 }
860
draw_window()861 static void draw_window()
862 {
863 int top, left, bottom, right;
864 int win;
865 Region newregion;
866 XRectangle clip;
867
868 int more[] = { '[', 'M', 'O', 'R', 'E', ']' };
869 int morew, moreh;
870
871 hide_caret();
872
873 resetregion = 0;
874
875 top = BORDER_SIZE;
876 left = BORDER_SIZE;
877 bottom = top + win_y;
878 right = left + win_x;
879
880 if (dregion == None)
881 {
882 XRectangle r;
883
884 r.x = 0; r.y = 0;
885 r.width = total_x; r.height = total_y;
886
887 dregion = XCreateRegion();
888 XUnionRectWithRegion(&r, dregion, dregion);
889 }
890
891 moreh = xfont_get_descent(font[style_font[2]]) + xfont_get_ascent(font[style_font[2]]);
892 morew = xfont_get_text_width(font[style_font[2]], more, 6);
893
894 clip.x = (win_x+BORDER_SIZE*2) - (morew + 2);
895 clip.y = (win_y+BORDER_SIZE*2) - (moreh + 2);
896 clip.width = morew+2; clip.height = moreh+2;
897 XUnionRectWithRegion(&clip, dregion, dregion);
898
899 XSetRegion(x_display, x_wingc, dregion);
900 #ifdef HAVE_XFT
901 if (xft_drawable != NULL && x_pixmap == None)
902 XftDrawSetClip(xft_drawable, dregion);
903 #endif
904
905 /* Draw border */
906 #ifndef BORDER_3D
907 /* Plain white border */
908 XSetForeground(x_display, x_wingc, x_colour[2].pixel);
909 XFillRectangle(x_display, x_drawable, x_wingc,
910 0, 0,
911 left, bottom);
912 XFillRectangle(x_display, x_drawable, x_wingc,
913 0, 0,
914 right, top);
915 XFillRectangle(x_display, x_drawable, x_wingc,
916 right, 0,
917 BORDER_SIZE, bottom);
918 XFillRectangle(x_display, x_drawable, x_wingc,
919 0, bottom,
920 right+BORDER_SIZE, BORDER_SIZE);
921 #else
922 /* Inset 3D border */
923 XSetForeground(x_display, x_wingc, x_colour[3].pixel);
924 XFillRectangle(x_display, x_drawable, x_wingc,
925 0, 0,
926 left, bottom);
927 XFillRectangle(x_display, x_drawable, x_wingc,
928 0, 0,
929 right, top);
930 XFillRectangle(x_display, x_drawable, x_wingc,
931 right, 0,
932 BORDER_SIZE, bottom);
933 XFillRectangle(x_display, x_drawable, x_wingc,
934 0, bottom,
935 right+BORDER_SIZE, BORDER_SIZE);
936
937 XSetForeground(x_display, x_wingc, x_colour[0].pixel);
938 XFillRectangle(x_display, x_drawable, x_wingc,
939 0, 0,
940 left-3, bottom+BORDER_SIZE);
941 XFillRectangle(x_display, x_drawable, x_wingc,
942 0, 0,
943 right+BORDER_SIZE, top-3);
944 XFillRectangle(x_display, x_drawable, x_wingc,
945 right+3, 0,
946 BORDER_SIZE-3, bottom+BORDER_SIZE);
947 XFillRectangle(x_display, x_drawable, x_wingc,
948 0, bottom+3,
949 right+BORDER_SIZE, BORDER_SIZE-3);
950
951 XSetLineAttributes(x_display, x_wingc, 1, LineSolid,
952 CapProjecting, JoinBevel);
953 XSetForeground(x_display, x_wingc, x_colour[1].pixel);
954 XDrawLine(x_display, x_drawable, x_wingc,
955 left-3, top-3, right+2, top-3);
956 XDrawLine(x_display, x_drawable, x_wingc,
957 left-3, top-3, left-3, bottom+2);
958
959 XSetForeground(x_display, x_wingc, x_colour[2].pixel);
960 XDrawLine(x_display, x_drawable, x_wingc,
961 right+2, bottom+2, right+2, top-3);
962 XDrawLine(x_display, x_drawable, x_wingc,
963 right+2, bottom+2, left-3, bottom+2);
964 #endif
965
966 /* Scrollbar */
967 draw_scrollbar(scroll_state);
968
969 /* Reduce clip region */
970 clip.x = BORDER_SIZE; clip.y = BORDER_SIZE;
971 clip.width = win_x; clip.height = win_y;
972
973 newregion = XCreateRegion();
974 XUnionRectWithRegion(&clip, newregion, newregion);
975
976 XIntersectRegion(dregion, newregion, newregion);
977
978 XSetRegion(x_display, x_wingc, newregion);
979
980 if (x_pixmap == None)
981 {
982 #ifdef HAVE_XFT
983 if (xft_drawable != NULL)
984 XftDrawSetClip(xft_drawable, newregion);
985 #endif
986
987 /* Text */
988 for (win = 0; win<3; win++)
989 {
990 if (text_win[win].overlay)
991 {
992 int x,y;
993 int fn, fg, bg;
994
995 bg = DEFAULT_BACK;
996
997 x=0; y=0;
998
999 for (y=text_win[win].winsy/xfont_y; y<size_y; y++)
1000 {
1001 for (x=0; x<size_x; x++)
1002 {
1003 if (text_win[win].cline[y].cell[x] != ' ' ||
1004 text_win[win].cline[y].bg[x] >= 0 ||
1005 y*xfont_y < text_win[win].winly)
1006 {
1007 int len;
1008
1009 len = 1;
1010 fg = text_win[win].cline[y].fg[x];
1011 bg = text_win[win].cline[y].bg[x];
1012 fn = text_win[win].cline[y].font[x];
1013
1014 while (x+len < size_x &&
1015 text_win[win].cline[y].font[x+len] == fn &&
1016 text_win[win].cline[y].fg[x+len] == fg &&
1017 text_win[win].cline[y].bg[x+len] == bg &&
1018 (bg >= 0 ||
1019 text_win[win].cline[y].cell[x+len] != ' ' ||
1020 y*xfont_y<text_win[win].winly))
1021 len++;
1022
1023 if (bg < 0)
1024 bg = -(bg+1);
1025
1026 XSetForeground(x_display, x_wingc,
1027 xdisplay_get_pixel_value(bg));
1028 XFillRectangle(x_display, x_drawable, x_wingc,
1029 x*xfont_x + BORDER_SIZE,
1030 y*xfont_y + BORDER_SIZE,
1031 len*xfont_x,
1032 xfont_y+0.5);
1033
1034 xfont_set_colours(fg, bg);
1035 xfont_plot_string(font[fn],
1036 x_drawable, x_wingc,
1037 x*xfont_x+BORDER_SIZE,
1038 y*xfont_y+BORDER_SIZE +
1039 xfont_get_ascent(font[fn]),
1040 &text_win[win].cline[y].cell[x],
1041 len);
1042
1043 x+=len-1;
1044 }
1045 }
1046
1047 /* May need to fill in to the end of the line */
1048 if (xfont_x*size_x < win_x &&
1049 y*xfont_y<text_win[win].winly)
1050 {
1051 XSetForeground(x_display, x_wingc,
1052 xdisplay_get_pixel_value(bg));
1053 XFillRectangle(x_display, x_drawable, x_wingc,
1054 xfont_x*size_x + BORDER_SIZE,
1055 y*xfont_y + BORDER_SIZE,
1056 win_x - xfont_x*size_x,
1057 xfont_y+0.5);
1058 }
1059 }
1060 }
1061 else
1062 {
1063 struct line* line;
1064 struct text* text;
1065 XFONT_MEASURE lasty, width;
1066 int offset;
1067
1068 Region r;
1069 XRectangle clip;
1070
1071 int phase;
1072
1073 r = XCreateRegion();
1074 clip.x = 0; clip.y = BORDER_SIZE + text_win[win].winsy;
1075 clip.width = total_x;
1076 clip.height = text_win[win].winly - text_win[win].winsy;
1077 XUnionRectWithRegion(&clip, r, r);
1078
1079 XIntersectRegion(newregion, r, r);
1080
1081 XSetRegion(x_display, x_wingc, r);
1082 #ifdef HAVE_XFT
1083 if (xft_drawable != NULL)
1084 XftDrawSetClip(xft_drawable, newregion);
1085 #endif
1086 XFree(r);
1087
1088 line = text_win[win].line;
1089 lasty = BORDER_SIZE;
1090
1091 /* Free any lines that scrolled off ages ago */
1092 if (line != NULL)
1093 {
1094 while (line->baseline < -32768)
1095 {
1096 struct line* n;
1097
1098 n = line->next;
1099 if (n == NULL)
1100 break;
1101
1102 if (text_win[win].topline == line)
1103 text_win[win].topline = NULL;
1104
1105 if (n->start != line->start)
1106 {
1107 struct text* nt;
1108
1109 if (line->start != text_win[win].text)
1110 zmachine_fatal("Programmer is a spoon");
1111 text_win[win].text = n->start;
1112
1113 text = line->start;
1114 while (text != n->start)
1115 {
1116 if (text == NULL)
1117 zmachine_fatal("Programmer is a spoon");
1118 nt = text->next;
1119 free(text);
1120 text = nt;
1121 }
1122 }
1123
1124
1125 free(line);
1126 text_win[win].line = n;
1127
1128 line = n;
1129 }
1130 }
1131
1132 /* Skip to the first visible line */
1133 if (line != NULL)
1134 {
1135 while (line != NULL && line->baseline + line->descent - scrollpos < text_win[win].winsy)
1136 line = line->next;
1137 }
1138
1139 /* Fill in to the start of the lines */
1140 if (line != NULL)
1141 {
1142 XSetForeground(x_display, x_wingc,
1143 xdisplay_get_pixel_value(text_win[win].winback));
1144 if (line->baseline-line->ascent-scrollpos > text_win[win].winsy)
1145 {
1146 XFillRectangle(x_display, x_drawable, x_wingc,
1147 BORDER_SIZE, text_win[win].winsy+BORDER_SIZE,
1148 win_x, line->baseline-line->ascent-scrollpos+0.5);
1149 }
1150 }
1151 else
1152 lasty = text_win[win].winsy + BORDER_SIZE;
1153
1154 /* Draw the lines */
1155 while (line != NULL &&
1156 line->baseline - line->ascent - scrollpos < text_win[win].winly)
1157 {
1158 int x;
1159
1160 for (phase=0; phase<2; phase++)
1161 {
1162 text = line->start;
1163 width = 0;
1164 offset = line->offset;
1165
1166 /*
1167 * Each line may span several text objects. We have to plot
1168 * each one in turn.
1169 */
1170 for (x=0; x<line->n_chars;)
1171 {
1172 int w;
1173 int toprint;
1174
1175 /*
1176 * Work out the amount of text to plot from the current
1177 * text object
1178 */
1179 toprint = line->n_chars-x;
1180 if (toprint > (text->len - offset))
1181 toprint = text->len - offset;
1182
1183 if (toprint > 0)
1184 {
1185 /* Plot the text */
1186 if (text->text[toprint+offset-1] == 10)
1187 {
1188 toprint--;
1189 x++;
1190 }
1191
1192 w = xfont_get_text_width(font[text->font],
1193 text->text + offset,
1194 toprint);
1195
1196 if (phase == 0)
1197 {
1198 XSetForeground(x_display, x_wingc,
1199 xdisplay_get_pixel_value(text->bg));
1200 XFillRectangle(x_display, x_drawable, x_wingc,
1201 width + BORDER_SIZE,
1202 line->baseline + BORDER_SIZE - line->ascent - scrollpos,
1203 w,
1204 line->ascent + line->descent);
1205 }
1206 else
1207 {
1208 xfont_set_colours(text->fg,
1209 text->bg);
1210 xfont_plot_string(font[text->font],
1211 x_drawable, x_wingc,
1212 width + BORDER_SIZE,
1213 line->baseline + BORDER_SIZE - scrollpos,
1214 text->text + offset,
1215 toprint);
1216 }
1217
1218 x += toprint;
1219 offset += toprint;
1220 width += w;
1221 }
1222 else
1223 {
1224 /* At the end of this object - move onto the next */
1225 offset = 0;
1226 text = text->next;
1227 }
1228 }
1229
1230 /* Fill in to the end of the line */
1231 if (phase == 0)
1232 {
1233 XSetForeground(x_display, x_wingc,
1234 xdisplay_get_pixel_value(text_win[win].winback));
1235 XFillRectangle(x_display, x_drawable, x_wingc,
1236 width + BORDER_SIZE,
1237 line->baseline - line->ascent + BORDER_SIZE - scrollpos,
1238 win_x-width,
1239 line->ascent + line->descent);
1240 }
1241
1242 lasty = line->baseline + line->descent - scrollpos + BORDER_SIZE;
1243 }
1244
1245 /* Move on */
1246 line = line->next;
1247 }
1248
1249 /* Fill in to the bottom of the window */
1250 XSetForeground(x_display, x_wingc,
1251 xdisplay_get_pixel_value(text_win[win].winback));
1252 if ((lasty-BORDER_SIZE) < win_y)
1253 {
1254 XFillRectangle(x_display, x_drawable, x_wingc,
1255 BORDER_SIZE,
1256 lasty,
1257 win_x,
1258 win_y - (lasty-BORDER_SIZE));
1259 }
1260
1261 XSetRegion(x_display, x_wingc, newregion);
1262 }
1263 }
1264 }
1265 else
1266 {
1267 int xp, yp;
1268
1269 xp = BORDER_SIZE + win_x/2-pix_w/2;
1270 yp = BORDER_SIZE + win_y/2-pix_h/2;
1271
1272 XSetForeground(x_display, x_wingc, x_colour[3].pixel);
1273 XFillRectangle(x_display, x_drawable, x_wingc,
1274 left, top,
1275 xp-left, bottom-top);
1276 XFillRectangle(x_display, x_drawable, x_wingc,
1277 left, top,
1278 right-left, yp-top);
1279 XFillRectangle(x_display, x_drawable, x_wingc,
1280 xp+pix_w, top,
1281 right-xp-pix_w, bottom-top);
1282 XFillRectangle(x_display, x_drawable, x_wingc,
1283 left, yp+pix_h,
1284 right-left, bottom-yp-pix_h);
1285
1286 XCopyArea(x_display, x_pixmap, x_drawable, x_wingc,
1287 0,0, pix_w, pix_h,
1288 xp, yp);
1289 }
1290
1291 /* Flip buffers */
1292 #ifdef HAVE_XDBE
1293 if (x_backbuffer != None)
1294 {
1295 XdbeSwapInfo i;
1296
1297 i.swap_window = x_mainwin;
1298 i.swap_action = XdbeCopied;
1299 XdbeSwapBuffers(x_display, &i, 1);
1300 }
1301 #endif
1302
1303 /* Caret */
1304 caret_shown = 0;
1305 if (!more_on)
1306 draw_input_text();
1307 draw_caret();
1308
1309 /* MORE */
1310 if (more_on)
1311 {
1312 #ifdef HAVE_XFT
1313 XftDraw* lastdraw = xft_drawable;
1314 #endif
1315
1316 clip.x = (win_x+BORDER_SIZE*2) - (morew + 2);
1317 clip.y = (win_y+BORDER_SIZE*2) - (moreh + 2);
1318 clip.width = morew+2; clip.height = moreh+2;
1319
1320 XSetRegion(x_display, x_wingc, dregion);
1321 #ifdef HAVE_XFT
1322 if (xft_drawable != NULL && xft_maindraw != NULL)
1323 {
1324 lastdraw = xft_drawable;
1325 xft_drawable = xft_maindraw;
1326 }
1327 if (xft_drawable != NULL)
1328 XftDrawSetClip(xft_drawable, dregion);
1329 #endif
1330
1331 XSetForeground(x_display, x_wingc, x_colour[4].pixel);
1332 XFillRectangle(x_display, x_mainwin, x_wingc,
1333 clip.x, clip.y, morew+1, moreh+1);
1334
1335 xfont_set_colours(0, 4);
1336 xfont_plot_string(font[style_font[2]],
1337 x_mainwin, x_wingc,
1338 win_x+BORDER_SIZE*2-(morew+1),
1339 win_y+BORDER_SIZE*2-(moreh) +
1340 xfont_get_ascent(font[style_font[2]]),
1341 more, 6);
1342
1343 XSetForeground(x_display, x_wingc, x_colour[6].pixel);
1344 XDrawLine(x_display, x_mainwin, x_wingc,
1345 clip.x+morew+1, clip.y+moreh+1, clip.x, clip.y+moreh+1);
1346 XDrawLine(x_display, x_mainwin, x_wingc,
1347 clip.x+morew+1, clip.y+moreh+1, clip.x+morew+1, clip.y);
1348
1349 XSetForeground(x_display, x_wingc, x_colour[5].pixel);
1350 XDrawLine(x_display, x_mainwin, x_wingc,
1351 clip.x, clip.y, clip.x+morew+1, clip.y);
1352 XDrawLine(x_display, x_mainwin, x_wingc,
1353 clip.x, clip.y, clip.x, clip.y+moreh+1);
1354
1355 #ifdef HAVE_XFT
1356 if (xft_drawable != NULL && xft_maindraw != NULL)
1357 {
1358 XftDrawSetClip(xft_drawable, None);
1359
1360 xft_drawable = lastdraw;
1361 }
1362 #endif
1363 }
1364
1365 /* Free regions */
1366 XFree(newregion);
1367 XFree(dregion);
1368 dregion = None;
1369
1370 updatecount = 0;
1371 resetregion = 1;
1372 }
1373
resize_window()1374 static void resize_window()
1375 {
1376 int owin;
1377 int x,y,z;
1378
1379 if (x_pixmap != None)
1380 return;
1381
1382 owin = cur_win;
1383
1384 size_x = win_x/xfont_x;
1385 size_y = win_y/xfont_y;
1386
1387 if (size_x == 0)
1388 size_x = 1;
1389 if (size_y == 0)
1390 size_y = 1;
1391
1392 /* Resize and reformat the overlay windows */
1393 for (x=1; x<=2; x++)
1394 {
1395 cur_win = x;
1396
1397 if (size_y > max_y)
1398 {
1399 CURWIN.cline = realloc(CURWIN.cline, sizeof(struct cellline)*size_y);
1400
1401 /* Allocate new rows */
1402 for (y=max_y; y<size_y; y++)
1403 {
1404 CURWIN.cline[y].cell = malloc(sizeof(int)*max_x);
1405 CURWIN.cline[y].fg = malloc(sizeof(int)*max_x);
1406 CURWIN.cline[y].bg = malloc(sizeof(int)*max_x);
1407 CURWIN.cline[y].font = malloc(sizeof(char)*max_x);
1408
1409 for (z=0; z<max_x; z++)
1410 {
1411 CURWIN.cline[y].cell[z] = ' ';
1412 CURWIN.cline[y].fg[z] = CURWIN.cline[max_y-1].fg[z];
1413 CURWIN.cline[y].bg[z] = CURWIN.cline[max_y-1].bg[z];
1414 CURWIN.cline[y].font[z] = style_font[4];
1415 }
1416 }
1417 }
1418
1419 if (size_x > max_x)
1420 {
1421 /* Allocate new columns */
1422 for (y=0; y<(max_y>size_y?max_y:size_y); y++)
1423 {
1424 CURWIN.cline[y].cell = realloc(CURWIN.cline[y].cell,
1425 sizeof(int)*size_x);
1426 CURWIN.cline[y].fg = realloc(CURWIN.cline[y].fg,
1427 sizeof(int)*size_x);
1428 CURWIN.cline[y].bg = realloc(CURWIN.cline[y].bg,
1429 sizeof(int)*size_x);
1430 CURWIN.cline[y].font = realloc(CURWIN.cline[y].font,
1431 sizeof(char)*size_x);
1432 for (z=max_x; z<size_x; z++)
1433 {
1434 CURWIN.cline[y].cell[z] = ' ';
1435 CURWIN.cline[y].fg[z] = CURWIN.cline[y].fg[max_x-1];
1436 CURWIN.cline[y].bg[z] = CURWIN.cline[y].bg[max_x-1];
1437 CURWIN.cline[y].font[z] = style_font[4];
1438 }
1439 }
1440 }
1441 }
1442
1443 if (size_x > max_x)
1444 max_x = size_x;
1445 if (size_y > max_y)
1446 max_y = size_y;
1447
1448 /* Resize and reformat the text window */
1449 cur_win = 0;
1450
1451 CURWIN.winlx = win_x;
1452 CURWIN.winly = win_y;
1453
1454 if (CURWIN.line != NULL)
1455 {
1456 struct line* line;
1457 struct line* next;
1458
1459 CURWIN.topline = NULL;
1460
1461 CURWIN.ypos = CURWIN.line->baseline - CURWIN.line->ascent;
1462 CURWIN.xpos = 0;
1463
1464 line = CURWIN.line;
1465 while (line != NULL)
1466 {
1467 next = line->next;
1468 free(line);
1469 line = next;
1470 }
1471
1472 CURWIN.line = CURWIN.lastline = NULL;
1473
1474 if (CURWIN.text != NULL)
1475 {
1476 CURWIN.lasttext = CURWIN.text;
1477 while (CURWIN.lasttext->next != NULL)
1478 {
1479 format_last_text(0);
1480 CURWIN.lasttext = CURWIN.lasttext->next;
1481 }
1482 format_last_text(0);
1483 }
1484 }
1485
1486 /* Scroll more text onto the screen if we can */
1487 cur_win = 0;
1488 if (CURWIN.lastline != NULL)
1489 {
1490 if (CURWIN.lastline->baseline+CURWIN.lastline->descent < win_y)
1491 {
1492 /* Scroll everything down */
1493 int down;
1494 struct line* l;
1495
1496 down = win_y -
1497 (CURWIN.lastline->baseline+CURWIN.lastline->descent);
1498
1499 l = CURWIN.line;
1500 while (l != NULL)
1501 {
1502 l->baseline += down;
1503
1504 l = l->next;
1505 }
1506 }
1507
1508 if (CURWIN.line->baseline-CURWIN.line->ascent > start_y)
1509 {
1510 /* Scroll everything up */
1511 int up;
1512 struct line* l;
1513
1514 up = (CURWIN.line->baseline-CURWIN.line->ascent) - start_y;
1515
1516 l = CURWIN.line;
1517 while (l != NULL)
1518 {
1519 l->baseline -= up;
1520
1521 l = l->next;
1522 }
1523 }
1524 }
1525
1526 zmachine_resize_display(display_get_info());
1527
1528 cur_win = owin;
1529 }
1530
process_events(long int to,int * buf,int buflen)1531 static int process_events(long int to, int* buf, int buflen)
1532 {
1533 struct timeval timeout, now;
1534
1535 int connection_num;
1536
1537 static int bufsize = 0;
1538 static int bufpos;
1539 static unsigned char keybuf[20];
1540
1541 int x;
1542 KeySym ks;
1543
1544 int exposing = 0;
1545
1546 if (buf != NULL)
1547 {
1548 text_buf = buf;
1549 max_buflen = buflen;
1550 buf_offset = istrlen(buf);
1551 history_pos = NULL;
1552 read_key = -1;
1553 }
1554 else
1555 {
1556 text_buf = NULL;
1557 buf_offset = 0;
1558 read_key = -1;
1559 }
1560
1561
1562 /* Work out when the timeout occurs */
1563 gettimeofday(&now, NULL);
1564 timeout = now;
1565 timeout.tv_sec += (to/1000);
1566 timeout.tv_usec += ((to%1000)*1000);
1567 timeout.tv_sec += timeout.tv_usec/1000000;
1568 timeout.tv_usec %= 1000000;
1569
1570 connection_num = ConnectionNumber(x_display);
1571
1572 if (!more_on)
1573 caret_flashing = 1;
1574 else
1575 caret_flashing = 0;
1576
1577 move_caret();
1578 show_caret();
1579
1580 while (1)
1581 {
1582 XEvent ev;
1583 fd_set readfds;
1584
1585 struct timeval tv;
1586 int isevent;
1587 int flash;
1588
1589 static struct timeval next_flash = { 0, 0 };
1590
1591 /* Get the current time */
1592 gettimeofday(&now, NULL);
1593
1594 /* Create the selection set */
1595 FD_ZERO(&readfds);
1596 FD_SET(connection_num, &readfds);
1597
1598 /* Calculate the time left to wait */
1599 tv = timeout;
1600 tv.tv_sec -= now.tv_sec;
1601 tv.tv_usec -= now.tv_usec;
1602
1603 tv.tv_sec += tv.tv_usec/1000000;
1604 tv.tv_usec %= 1000000;
1605
1606 if (tv.tv_usec < 0)
1607 {
1608 tv.tv_usec += 1000000;
1609 tv.tv_sec -= 1;
1610 }
1611
1612 if (tv.tv_sec < 0 && to != 0)
1613 return 0;
1614
1615 /* Calculate the time left til we flash */
1616 if (next_flash.tv_sec == 0 &&
1617 next_flash.tv_usec == 0)
1618 next_flash = now;
1619
1620 if (caret_flashing &&
1621 (next_flash.tv_sec < now.tv_sec ||
1622 (next_flash.tv_sec == now.tv_sec &&
1623 next_flash.tv_usec <= now.tv_usec)))
1624 {
1625 next_flash.tv_sec = now.tv_sec;
1626 next_flash.tv_usec = now.tv_usec + 400000;
1627 next_flash.tv_sec += next_flash.tv_usec/1000000;
1628 next_flash.tv_usec %= 1000000;
1629
1630 caret_on = !caret_on;
1631 draw_caret();
1632 }
1633
1634 /* Timeout on flash if that's going to occur sooner */
1635 flash = 0;
1636 if (((tv.tv_sec > next_flash.tv_sec ||
1637 (tv.tv_sec == next_flash.tv_sec &&
1638 tv.tv_usec > next_flash.tv_usec))
1639 || to == 0))
1640 {
1641 tv.tv_sec = next_flash.tv_sec - now.tv_sec;
1642 tv.tv_usec = next_flash.tv_usec - now.tv_usec;
1643
1644 tv.tv_sec += tv.tv_usec/1000000;
1645 tv.tv_usec %= 1000000;
1646
1647 if (tv.tv_usec < 0)
1648 {
1649 tv.tv_usec += 1000000;
1650 tv.tv_sec -= 1;
1651 }
1652
1653 flash = 1;
1654 }
1655
1656 /* Update the display if necessary */
1657 if (dregion != None &&
1658 exposing <= 0 &&
1659 !XPending(x_display))
1660 {
1661 draw_window();
1662 }
1663
1664 /* Wait for something to happen */
1665 isevent = 0;
1666 if (XPending(x_display))
1667 isevent = 1;
1668 else if (select(connection_num+1, &readfds, NULL, NULL,
1669 &tv))
1670 isevent = 1;
1671
1672 if (!isevent && flash)
1673 continue;
1674
1675 if (isevent)
1676 {
1677 int doubleclick;
1678
1679 XNextEvent(x_display, &ev);
1680
1681 switch (ev.type)
1682 {
1683 case KeyPress:
1684 display_set_scroll_position(0);
1685
1686 bufpos = 0;
1687 bufsize = XLookupString(&ev.xkey, keybuf, 20, NULL, NULL);
1688
1689 if (text_buf == NULL)
1690 {
1691 x = 0;
1692 for (ks=XKeycodeToKeysym(x_display, ev.xkey.keycode, x++);
1693 ks != NoSymbol;
1694 ks=XKeycodeToKeysym(x_display, ev.xkey.keycode, x++))
1695 {
1696 switch (ks)
1697 {
1698 case XK_Left:
1699 keybuf[bufsize++] = 131;
1700 goto gotkeysym;
1701
1702 case XK_Right:
1703 keybuf[bufsize++] = 132;
1704 goto gotkeysym;
1705
1706 case XK_Up:
1707 keybuf[bufsize++] = 129;
1708 goto gotkeysym;
1709
1710 case XK_Down:
1711 keybuf[bufsize++] = 130;
1712 goto gotkeysym;
1713
1714 case XK_Delete:
1715 keybuf[bufsize++] = 8;
1716 goto gotkeysym;
1717
1718 case XK_F1:
1719 keybuf[bufsize++] = 133;
1720 goto gotkeysym;
1721 case XK_F2:
1722 keybuf[bufsize++] = 134;
1723 goto gotkeysym;
1724 case XK_F3:
1725 keybuf[bufsize++] = 135;
1726 goto gotkeysym;
1727 case XK_F4:
1728 keybuf[bufsize++] = 136;
1729 goto gotkeysym;
1730 case XK_F5:
1731 keybuf[bufsize++] = 137;
1732 goto gotkeysym;
1733 case XK_F6:
1734 keybuf[bufsize++] = 138;
1735 goto gotkeysym;
1736 case XK_F7:
1737 keybuf[bufsize++] = 139;
1738 goto gotkeysym;
1739 case XK_F8:
1740 keybuf[bufsize++] = 140;
1741 goto gotkeysym;
1742 case XK_F9:
1743 keybuf[bufsize++] = 141;
1744 goto gotkeysym;
1745 case XK_F10:
1746 keybuf[bufsize++] = 142;
1747 goto gotkeysym;
1748 case XK_F11:
1749 keybuf[bufsize++] = 143;
1750 goto gotkeysym;
1751 case XK_F12:
1752 keybuf[bufsize++] = 144;
1753 goto gotkeysym;
1754 }
1755 }
1756 gotkeysym:
1757
1758 if (bufsize > 0)
1759 {
1760 hide_caret();
1761 bufsize--;
1762 return keybuf[bufpos++];
1763 }
1764 }
1765 else
1766 {
1767 int x, y;
1768
1769 x = 0;
1770 for (ks=XKeycodeToKeysym(x_display, ev.xkey.keycode, x++);
1771 ks != NoSymbol;
1772 ks=XKeycodeToKeysym(x_display, ev.xkey.keycode, x++))
1773 {
1774 switch (ks)
1775 {
1776 case XK_Left:
1777 if (terminating[131])
1778 {
1779 hide_caret();
1780 return 131;
1781 }
1782 if (buf_offset>0)
1783 buf_offset--;
1784 goto gotkeysym2;
1785
1786 case XK_Right:
1787 if (terminating[132])
1788 {
1789 hide_caret();
1790 return 132;
1791 }
1792 if (text_buf[buf_offset] != 0)
1793 buf_offset++;
1794 goto gotkeysym2;
1795
1796 case XK_Up:
1797 if (terminating[129])
1798 {
1799 hide_caret();
1800 return 129;
1801 }
1802 else
1803 {
1804 if (history_pos == NULL)
1805 history_pos = last_string;
1806 else
1807 if (history_pos->next != NULL)
1808 history_pos = history_pos->next;
1809 if (history_pos != NULL)
1810 {
1811 if (istrlen(history_pos->string) < buflen)
1812 istrcpy(text_buf, history_pos->string);
1813 buf_offset = istrlen(text_buf);
1814 }
1815 }
1816 goto gotkeysym2;
1817
1818 case XK_Down:
1819 if (terminating[130])
1820 {
1821 hide_caret();
1822 return 130;
1823 }
1824 if (history_pos != NULL)
1825 {
1826 history_pos = history_pos->last;
1827 if (history_pos != NULL)
1828 {
1829 if (istrlen(history_pos->string) < buflen)
1830 istrcpy(text_buf, history_pos->string);
1831 buf_offset = istrlen(text_buf);
1832 }
1833 else
1834 {
1835 text_buf[0] = 0;
1836 buf_offset = 0;
1837 }
1838 }
1839 goto gotkeysym2;
1840
1841 case XK_Home:
1842 buf_offset = 0;
1843 goto gotkeysym2;
1844
1845 case XK_Insert:
1846 insert = !insert;
1847 goto gotkeysym2;
1848
1849 case XK_End:
1850 buf_offset = istrlen(text_buf);
1851 goto gotkeysym2;
1852
1853 case XK_BackSpace:
1854 case XK_Delete:
1855 if (buf_offset == 0)
1856 goto gotkeysym2;
1857
1858 if (text_buf[buf_offset] == 0)
1859 text_buf[--buf_offset] = 0;
1860 else
1861 {
1862 for (y=buf_offset-1; text_buf[y] != 0; y++)
1863 text_buf[y] = text_buf[y+1];
1864 buf_offset--;
1865 }
1866 goto gotkeysym2;
1867
1868 case XK_Return:
1869 {
1870 history_item* newhist;
1871
1872 newhist = malloc(sizeof(history_item));
1873 newhist->last = NULL;
1874 newhist->next = last_string;
1875 if (last_string)
1876 last_string->last = newhist;
1877 newhist->string = malloc(sizeof(int)*(istrlen(text_buf)+1));
1878 istrcpy(newhist->string, text_buf);
1879 last_string = newhist;
1880 }
1881 bufsize = 0;
1882
1883 hide_caret();
1884
1885 return 10;
1886
1887 case XK_F1:
1888 if (terminating[133])
1889 {
1890 hide_caret();
1891 return 133;
1892 }
1893 break;
1894 case XK_F2:
1895 if (terminating[134])
1896 {
1897 hide_caret();
1898 return 134;
1899 }
1900 break;
1901 case XK_F3:
1902 if (terminating[135])
1903 {
1904 hide_caret();
1905 return 135;
1906 }
1907 break;
1908 case XK_F4:
1909 if (terminating[136])
1910 {
1911 hide_caret();
1912 return 136;
1913 }
1914 break;
1915 case XK_F5:
1916 if (terminating[137])
1917 {
1918 hide_caret();
1919 return 137;
1920 }
1921 break;
1922 case XK_F6:
1923 if (terminating[138])
1924 {
1925 hide_caret();
1926 return 138;
1927 }
1928 break;
1929 case XK_F7:
1930 if (terminating[139])
1931 {
1932 hide_caret();
1933 return 139;
1934 }
1935 break;
1936 case XK_F8:
1937 if (terminating[140])
1938 {
1939 hide_caret();
1940 return 140;
1941 }
1942 break;
1943 case XK_F9:
1944 if (terminating[141])
1945 {
1946 hide_caret();
1947 return 141;
1948 }
1949 break;
1950 case XK_F10:
1951 if (terminating[142])
1952 {
1953 hide_caret();
1954 return 142;
1955 }
1956 break;
1957 case XK_F11:
1958 if (terminating[143])
1959 {
1960 hide_caret();
1961 return 143;
1962 }
1963 break;
1964 case XK_F12:
1965 if (terminating[144])
1966 {
1967 hide_caret();
1968 return 144;
1969 }
1970 break;
1971 }
1972 }
1973 gotkeysym2:
1974
1975 for (x=0; x<bufsize; x++)
1976 {
1977 if (istrlen(text_buf) >= buflen)
1978 break;
1979
1980 if (keybuf[x]>31 && keybuf[x]<127)
1981 {
1982 if (text_buf[buf_offset] == 0)
1983 {
1984 text_buf[buf_offset+1] = 0;
1985 text_buf[buf_offset++] = keybuf[x];
1986 }
1987 else
1988 {
1989 if (insert)
1990 {
1991 for (y=istrlen(text_buf)+1; y>buf_offset; y--)
1992 {
1993 text_buf[y] = text_buf[y-1];
1994 }
1995 }
1996 text_buf[buf_offset++] = keybuf[x];
1997 }
1998 }
1999 }
2000
2001 bufsize = 0;
2002
2003 draw_input_text();
2004 }
2005 break;
2006
2007 case ConfigureNotify:
2008 #ifdef HAVE_XFT
2009 if (xft_drawable != NULL &&
2010 x_pixmap == None)
2011 {
2012 /*
2013 * Sometimes the xft_drawable breaks when the window is
2014 * resized - in particular when we're using DBE.
2015 * Recreating it fixes this... (Not necessary when
2016 * using a pixmap for rendering)
2017 */
2018 XftDrawChange(xft_drawable, x_drawable);
2019 }
2020 #endif
2021
2022 #ifdef HAVE_XRENDER
2023 if (x_winpic != None)
2024 {
2025 XRenderFreePicture(x_display, x_winpic);
2026 x_winpic = XRenderCreatePicture(x_display, x_drawable, x_picformat, 0, NULL);
2027 }
2028 #endif
2029
2030 if (ev.xconfigure.width != win_width ||
2031 ev.xconfigure.height != win_height)
2032 {
2033 win_width = total_x = ev.xconfigure.width;
2034 win_height = total_y = ev.xconfigure.height;
2035 win_x = total_x - (BORDER_SIZE*2) - SCROLLBAR_SIZE;
2036 win_y = total_y - (BORDER_SIZE*2);
2037
2038 win_left = BORDER_SIZE;
2039 win_top = BORDER_SIZE;
2040
2041 /* Reformat window here */
2042 scroll_overlays = 0;
2043 resize_window();
2044 scroll_overlays = 1;
2045 move_caret();
2046 }
2047 break;
2048
2049 case ButtonPress:
2050 /* Could be the second of a doubleclick...? */
2051 {
2052 int distx, disty, dist;
2053 distx = click_x - (ev.xbutton.x-win_left);
2054 disty = click_y - (ev.xbutton.y-win_top);
2055
2056 dist = distx*distx + disty*disty;
2057
2058 if (click_time > ev.xbutton.time - 500 &&
2059 dist < 24)
2060 {
2061 doubleclick = 253;
2062 }
2063 else
2064 {
2065 doubleclick = 254;
2066 }
2067 }
2068
2069 /* See if the click was within the scrollbar... */
2070 click_x = ev.xbutton.x-win_left;
2071 click_y = ev.xbutton.y-win_top;
2072 click_time = ev.xbutton.time;
2073
2074 if (click_x >= win_x+BORDER_SIZE)
2075 {
2076 int pos, height;
2077
2078 click_y += win_top;
2079
2080 /* Calculate the position and size of the scrollbar tab */
2081 pos = (scroll_pos*total_y)/scroll_range;
2082 height = (scroll_height*total_y)/scroll_range;
2083
2084 if (height < 20)
2085 height = 20;
2086
2087 if (pos > total_y)
2088 pos = total_y-10;
2089 if (pos + height >= total_y)
2090 {
2091 pos -= (pos+height)-total_y-1;
2092 }
2093
2094 if /* above */ (click_y < pos)
2095 {
2096 display_set_scroll_position((scroll_pos + scroll_top) - (scroll_height - xfont_y));
2097 }
2098 else if /* below */ (click_y > (pos+height))
2099 {
2100 display_set_scroll_position((scroll_pos + scroll_top) + (scroll_height - xfont_y));
2101 }
2102 else /* within - drag time */
2103 {
2104 /* Depress scrollbar */
2105 scroll_state = 1;
2106 invalidate_scrollbar();
2107
2108 /* Record some useful information */
2109 scroll_start = scroll_pos;
2110 scroll_offset = pos - click_y;
2111
2112 /* Turn on motion events */
2113 scrolling = 1;
2114
2115 /* Set the cursor */
2116 XDefineCursor(x_display, x_mainwin, scrollCursor);
2117 }
2118 }
2119 else if (terminating[doubleclick] || buf == NULL)
2120 {
2121 int xp, yp;
2122
2123 xp = win_x/2-pix_w/2;
2124 yp = win_y/2-pix_h/2;
2125
2126 if (mousew_h < 0 ||
2127 (click_x-xp > mousew_x && click_y-yp > mousew_y &&
2128 click_x-xp < mousew_x+mousew_w &&
2129 click_y-yp < mousew_y+mousew_h))
2130 {
2131 XDefineCursor(x_display, x_mainwin, clickCursor);
2132 return doubleclick;
2133 }
2134 else
2135 {
2136 XDefineCursor(x_display, x_mainwin, noClickHere);
2137 }
2138 }
2139 break;
2140
2141 case ButtonRelease:
2142 XDefineCursor(x_display, x_mainwin, arrowCursor);
2143 if (scrolling)
2144 {
2145 scroll_state = 0;
2146 scrolling = 0;
2147 invalidate_scrollbar();
2148 }
2149 break;
2150
2151 case MotionNotify:
2152 if (scrolling)
2153 {
2154 Window root, child;
2155 int cx, cy;
2156 unsigned int m;
2157
2158 XQueryPointer(x_display, x_mainwin, &root, &child,
2159 &cx, &cy,
2160 &click_x, &click_y,
2161 &m);
2162
2163 /* Only happens when we've dragged the scrollbar */
2164 click_x -= win_left;
2165 click_y -= win_top;
2166
2167 if (click_x >= win_x+BORDER_SIZE - SCROLLBAR_SIZE &&
2168 click_x <= total_x + SCROLLBAR_SIZE)
2169 {
2170 int pos, height, newpos;
2171 XFONT_MEASURE sc;
2172
2173 click_y += win_top;
2174
2175 /* Calculate the position and size of the scrollbar tab */
2176 pos = (scroll_pos*total_y)/scroll_range;
2177 height = (scroll_height*total_y)/scroll_range;
2178
2179 if (height < 20)
2180 height = 20;
2181
2182 if (pos > total_y)
2183 pos = total_y-10;
2184 if (pos + height >= total_y)
2185 {
2186 pos -= (pos+height)-total_y-1;
2187 }
2188
2189 newpos = scroll_offset + click_y;
2190 sc = scroll_top + (newpos*scroll_range)/total_y;
2191
2192 display_set_scroll_position(sc);
2193 }
2194 else
2195 {
2196 display_set_scroll_position(scroll_start);
2197 }
2198 }
2199 break;
2200
2201 case ClientMessage:
2202 if (ev.xclient.message_type == wmprots)
2203 {
2204 if (ev.xclient.data.l[0] == x_prot[0])
2205 {
2206 display_exit(0);
2207 }
2208 }
2209 break;
2210
2211 case Expose:
2212 {
2213 XRectangle r;
2214
2215 if (dregion == None)
2216 dregion = XCreateRegion();
2217 exposing = ev.xexpose.count;
2218
2219 r.x = ev.xexpose.x;
2220 r.y = ev.xexpose.y;
2221 r.width = ev.xexpose.width;
2222 r.height = ev.xexpose.height;
2223 XUnionRectWithRegion(&r, dregion, dregion);
2224 }
2225 break;
2226
2227 case FocusOut:
2228 hide_caret();
2229 caret_flashing = 0;
2230 if (!more_on)
2231 show_caret();
2232 else
2233 hide_caret();
2234 break;
2235
2236 case FocusIn:
2237 hide_caret();
2238 if (!more_on)
2239 caret_flashing = 1;
2240 break;
2241 }
2242 }
2243 }
2244
2245 hide_caret();
2246 }
2247
2248 /* === Display functions === */
2249
2250 /* Debug/error functions */
2251
printf_debug(char * format,...)2252 void printf_debug(char* format, ...)
2253 {
2254 va_list ap;
2255 char string[8192];
2256
2257 va_start(ap, format);
2258 vsprintf(string, format, ap);
2259 va_end(ap);
2260
2261 fputs(string, stderr);
2262 }
2263
printf_error(char * format,...)2264 void printf_error(char* format, ...)
2265 {
2266 va_list ap;
2267 char string[512];
2268
2269 va_start(ap, format);
2270 vsprintf(string, format, ap);
2271 va_end(ap);
2272
2273 fputs(string, stderr);
2274 }
2275
printf_info(char * format,...)2276 void printf_info(char* format, ...)
2277 {
2278 va_list ap;
2279 char string[512];
2280
2281 va_start(ap, format);
2282 vsprintf(string, format, ap);
2283 va_end(ap);
2284
2285 fputs(string, stdout);
2286 }
2287
printf_info_done(void)2288 void printf_info_done(void) { }
printf_error_done(void)2289 void printf_error_done(void) { }
2290
2291 /* Output functions */
2292
display_check_char(int chr)2293 int display_check_char(int chr)
2294 {
2295 return 1;
2296 }
2297
2298 /* Input functions */
2299
display_readline(int * buf,int buflen,long int timeout)2300 int display_readline(int* buf, int buflen, long int timeout)
2301 {
2302 int result;
2303
2304 if (x_pixmap != None)
2305 v6_set_caret();
2306
2307 displayed_text = 0;
2308 result = process_events(timeout, buf, buflen);
2309
2310 if (result == 10)
2311 {
2312 display_prints(buf);
2313 display_printc(10);
2314 }
2315
2316 return result;
2317 }
2318
display_readchar(long int timeout)2319 int display_readchar(long int timeout)
2320 {
2321 int result;
2322
2323 if (x_pixmap != None)
2324 v6_set_caret();
2325
2326 displayed_text = 0;
2327 result = process_events(timeout, NULL, 0);
2328
2329 return result;
2330 }
2331
2332 /* Display window management functions */
2333
display_update(void)2334 void display_update(void)
2335 {
2336 display_update_region(0, 0, win_x, win_y);
2337 }
2338
display_update_region(XFONT_MEASURE left,XFONT_MEASURE top,XFONT_MEASURE right,XFONT_MEASURE bottom)2339 void display_update_region(XFONT_MEASURE left,
2340 XFONT_MEASURE top,
2341 XFONT_MEASURE right,
2342 XFONT_MEASURE bottom)
2343 {
2344 XRectangle clip;
2345
2346 if (left == right ||
2347 top == bottom)
2348 return;
2349
2350 if (left > right ||
2351 top > bottom)
2352 {
2353 #ifdef DEBUG
2354 printf_debug("Bad update: %i, %i, %i, %i\n", (int)left, (int)top, (int)right, (int)bottom);
2355 #endif
2356 return;
2357 }
2358
2359 if (dregion == None)
2360 dregion = XCreateRegion();
2361
2362 updatecount++;
2363 if (updatecount == 20)
2364 {
2365 XFree(dregion);
2366 dregion = XCreateRegion();
2367
2368 clip.x = 0;
2369 clip.y = 0;
2370 clip.width = total_x;
2371 clip.height = total_y;
2372 XUnionRectWithRegion(&clip, dregion, dregion);
2373 return;
2374 }
2375 else if (updatecount > 20)
2376 return;
2377
2378 clip.x = left + BORDER_SIZE; clip.y = top + BORDER_SIZE;
2379 clip.width = right - left; clip.height = bottom - top;
2380 XUnionRectWithRegion(&clip, dregion, dregion);
2381 }
2382
display_set_scroll_range(XFONT_MEASURE top,XFONT_MEASURE bottom)2383 void display_set_scroll_range(XFONT_MEASURE top,
2384 XFONT_MEASURE bottom)
2385 {
2386 if (scroll_range == bottom-top && scroll_top == top)
2387 return;
2388
2389 scroll_range = bottom-top;
2390 if (top != scroll_top)
2391 {
2392 scroll_pos += (scroll_top - top);
2393 }
2394 scroll_top = top;
2395
2396 invalidate_scrollbar();
2397 }
2398
display_set_scroll_region(XFONT_MEASURE size)2399 void display_set_scroll_region(XFONT_MEASURE size)
2400 {
2401 if (scroll_height == size)
2402 return;
2403
2404 scroll_height = size;
2405
2406 invalidate_scrollbar();
2407 }
2408
display_set_scroll_position(XFONT_MEASURE pos)2409 void display_set_scroll_position(XFONT_MEASURE pos)
2410 {
2411 int oldpos;
2412
2413 if (scroll_height > scroll_range)
2414 return;
2415
2416 oldpos = scroll_pos;
2417 scroll_pos = pos - scroll_top;
2418
2419 if (scroll_pos+scroll_height > scroll_range)
2420 {
2421 scroll_pos = scroll_range - scroll_height;
2422 }
2423 if (scroll_pos < 0)
2424 scroll_pos = 0;
2425
2426 if (scroll_pos == oldpos)
2427 return;
2428
2429 invalidate_scrollbar();
2430
2431 scrollpos = scroll_pos + scroll_top;
2432 display_update();
2433 }
2434
display_set_title(const char * title)2435 void display_set_title(const char* title)
2436 {
2437 XTextProperty tprop;
2438 char *t;
2439
2440 t = malloc(sizeof(char)*300);
2441 sprintf(t, "Zoom " VERSION " - %s", title);
2442
2443 XStringListToTextProperty(&t, 1, &tprop);
2444 XSetWMName(x_display, x_mainwin, &tprop);
2445 XFree(tprop.value);
2446
2447 free(t);
2448 }
2449
display_terminating(unsigned char * table)2450 void display_terminating(unsigned char* table)
2451 {
2452 int x;
2453
2454 for (x=0; x<256; x++)
2455 terminating[x] = 0;
2456
2457 if (table != NULL)
2458 {
2459 for (x=0; table[x] != 0; x++)
2460 {
2461 terminating[table[x]] = 1;
2462
2463 if (table[x] == 255)
2464 {
2465 int y;
2466
2467 for (y=129; y<=154; y++)
2468 terminating[y] = 1;
2469 for (y=252; y<255; y++)
2470 terminating[y] = 1;
2471 }
2472 }
2473 }
2474 }
2475
2476 /* (Assumes a pixmap is present) */
display_read_mouse(void)2477 void display_read_mouse(void)
2478 {
2479 Window root, child;
2480 int cx, cy;
2481 unsigned int m;
2482
2483 XQueryPointer(x_display, x_mainwin, &root, &child,
2484 &cx, &cy,
2485 &click_x, &click_y,
2486 &m);
2487
2488 click_x -= win_left;
2489 click_y -= win_top;
2490
2491 click_b =
2492 ((m&Button1Mask)?1:0)|
2493 ((m&Button2Mask)?2:0)|
2494 ((m&Button3Mask)?4:0)|
2495 ((m&Button4Mask)?8:0)|
2496 ((m&Button5Mask)?16:0);
2497 }
2498
display_get_mouse_x(void)2499 int display_get_mouse_x(void)
2500 {
2501 return (click_x/xfont_x)+1;
2502 }
2503
display_get_mouse_y(void)2504 int display_get_mouse_y(void)
2505 {
2506 return (click_y/xfont_y)+1;
2507 }
2508
display_get_pix_mouse_x(void)2509 int display_get_pix_mouse_x(void)
2510 {
2511 return click_x - (win_x/2-pix_w/2);
2512 }
2513
display_get_pix_mouse_y(void)2514 int display_get_pix_mouse_y(void)
2515 {
2516 return click_y - (win_y/2-pix_h/2);
2517 }
2518
display_get_pix_mouse_b(void)2519 int display_get_pix_mouse_b(void)
2520 {
2521 return click_b;
2522 }
2523
display_beep(void)2524 void display_beep(void)
2525 {
2526 }
2527
2528 /* Initialisation */
2529
display_initialise(void)2530 void display_initialise(void)
2531 {
2532 XSetWindowAttributes win_attr;
2533 XWindowAttributes attr;
2534 rc_font* fonts;
2535 rc_colour* cols;
2536 int num;
2537
2538 int x,y;
2539
2540 x_display = XOpenDisplay(NULL);
2541 x_screen = DefaultScreen(x_display);
2542
2543 fonts = rc_get_fonts(&num);
2544 n_fonts = 0;
2545
2546 /* Load some cursors */
2547 scrollCursor = XCreateFontCursor(x_display, XC_double_arrow);
2548 noClickHere = XCreateFontCursor(x_display, XC_X_cursor);
2549 arrowCursor = XCreateFontCursor(x_display, XC_left_ptr);
2550 clickCursor = XCreateFontCursor(x_display, XC_hand2);
2551
2552 /* Start up the font system */
2553 xfont_initialise();
2554
2555 win_attr.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask|ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|FocusChangeMask;
2556 win_attr.background_pixel = None;
2557
2558 /* Create the main window */
2559 x_mainwin = XCreateWindow(x_display,
2560 RootWindow(x_display, x_screen),
2561 100,100,
2562 total_x= ((win_x=(xfont_x*rc_get_xsize())) + BORDER_SIZE*2+SCROLLBAR_SIZE),
2563 total_y=((win_y=(xfont_y*rc_get_ysize())) + BORDER_SIZE*2),
2564 1, DefaultDepth(x_display, x_screen), InputOutput,
2565 CopyFromParent,
2566 CWEventMask|CWBackPixel,
2567 &win_attr);
2568
2569 XDefineCursor(x_display, x_mainwin, arrowCursor);
2570
2571 /* Give it a back buffer, if the extension is available */
2572 x_drawable = x_mainwin;
2573
2574 #ifdef HAVE_XDBE
2575 x_backbuffer = None;
2576 if (XdbeQueryExtension(x_display, &x, &y))
2577 {
2578 if (x >= 1)
2579 {
2580 x_backbuffer = XdbeAllocateBackBufferName(x_display,
2581 x_mainwin,
2582 XdbeCopied);
2583 }
2584 if (x_backbuffer != None)
2585 x_drawable = x_backbuffer;
2586 }
2587 #endif
2588
2589 #ifdef HAVE_XRENDER
2590 if (XRenderQueryExtension(x_display, &x, &y))
2591 {
2592 x_picformat = XRenderFindVisualFormat(x_display, DefaultVisual(x_display, DefaultScreen(x_display)));
2593 if (x_picformat != NULL)
2594 {
2595 x_winpic = XRenderCreatePicture(x_display, x_drawable, x_picformat, 0, NULL);
2596 }
2597 }
2598 #endif
2599
2600 #ifdef HAVE_XFT
2601 if (XftDefaultHasRender(x_display))
2602 {
2603 xft_drawable = XftDrawCreate(x_display, x_drawable,
2604 DefaultVisual(x_display, x_screen),
2605 DefaultColormap(x_display, x_screen));
2606
2607 /*
2608 * Create a drawable on the main window (used for drawing the input
2609 * text)
2610 */
2611 xft_maindraw = XftDrawCreate(x_display, x_mainwin,
2612 DefaultVisual(x_display, x_screen),
2613 DefaultColormap(x_display, x_screen));
2614 }
2615 else
2616 {
2617 xft_drawable = NULL;
2618 }
2619 #endif
2620
2621 /* Allocate fonts */
2622 for (x=0; x<num; x++)
2623 {
2624 if (fonts[x].num <= 0)
2625 zmachine_fatal("Font numbers must be positive integers");
2626 if (fonts[x].num > n_fonts)
2627 {
2628 n_fonts = fonts[x].num;
2629 font = realloc(font, sizeof(xfont*)*n_fonts);
2630 }
2631
2632 font[fonts[x].num-1] = xfont_load_font(fonts[x].name);
2633
2634 for (y=0; y<fonts[x].n_attr; y++)
2635 {
2636 style_font[fonts[x].attributes[y]] = fonts[x].num-1;
2637 }
2638 }
2639
2640 for (y=0; y<16; y++)
2641 {
2642 if (style_font[y] == -1)
2643 {
2644 style_font[y] = style_font[8];
2645 }
2646 }
2647
2648 xfont_x = xfont_get_width(font[3]);
2649 xfont_y = xfont_get_height(font[3]);
2650
2651 cols = rc_get_colours(&num);
2652 if (num > 11)
2653 {
2654 num = 11;
2655 zmachine_warning("Maximum of 11 colours");
2656 }
2657 if (num < 8)
2658 zmachine_warning("Supplied colourmap doesn't defined all 8 'standard' colours");
2659
2660 for (x=0; x<num; x++)
2661 {
2662 x_colour[x+FIRST_ZCOLOUR].red = cols[x].r<<8;
2663 x_colour[x+FIRST_ZCOLOUR].green = cols[x].g<<8;
2664 x_colour[x+FIRST_ZCOLOUR].blue = cols[x].b<<8;
2665 }
2666
2667 /* Size the window */
2668 max_x = size_x = rc_get_xsize();
2669 max_y = size_y = rc_get_ysize();
2670 size_window();
2671
2672 /* Show the window */
2673 XMapWindow(x_display, x_mainwin);
2674
2675 /* Window properties */
2676 {
2677 XTextProperty tprop;
2678 XSizeHints* hints;
2679 XWMHints* wmhints;
2680 char* title = "Zoom " VERSION;
2681 char* icon = "Zoom";
2682
2683 XStringListToTextProperty(&title, 1, &tprop);
2684 XSetWMName(x_display, x_mainwin, &tprop);
2685 XFree(tprop.value);
2686
2687 XStringListToTextProperty(&icon, 1, &tprop);
2688 XSetWMIconName(x_display, x_mainwin, &tprop);
2689 XFree(tprop.value);
2690
2691 hints = XAllocSizeHints();
2692 hints->min_width = 200;
2693 hints->min_height = 100;
2694 hints->width = total_x;
2695 hints->height = total_y;
2696 hints->width_inc = 2;
2697 hints->height_inc = 2;
2698 hints->flags = PSize|PMinSize|PResizeInc;
2699
2700 XSetWMNormalHints(x_display, x_mainwin, hints);
2701 XFree(hints);
2702
2703 wmhints = XAllocWMHints();
2704 wmhints->input = True;
2705 wmhints->flags = InputHint;
2706
2707 XSetWMHints(x_display, x_mainwin, wmhints);
2708 XFree(wmhints);
2709
2710 x_prot[0] = XInternAtom(x_display, "WM_DELETE_WINDOW", False);
2711 XSetWMProtocols(x_display, x_mainwin, x_prot, 1);
2712 wmprots = XInternAtom(x_display, "WM_PROTOCOLS", False);
2713 }
2714
2715 /* Allocate colours */
2716 XGetWindowAttributes(x_display, x_mainwin, &attr);
2717 for (x=0; x<N_COLS; x++)
2718 {
2719 if (!XAllocColor(x_display,
2720 DefaultColormap(x_display, x_screen),
2721 &x_colour[x]))
2722 {
2723 fprintf(stderr, "Warning: couldn't allocate colour #%i\n", x);
2724 x_colour[x].pixel = BlackPixel(x_display, x_screen);
2725 }
2726 }
2727
2728 #ifdef HAVE_XFT
2729 if (XftDefaultHasRender(x_display) && xft_drawable != NULL)
2730 {
2731 alloc_xft_colours();
2732 }
2733 #endif
2734
2735 /* Create the display pixmap */
2736 x_wingc = XCreateGC(x_display, x_drawable, 0, NULL);
2737 x_caretgc = XCreateGC(x_display, x_mainwin, 0, NULL);
2738
2739 XSetForeground(x_display, x_caretgc,
2740 xdisplay_get_pixel_value(DEFAULT_FORE));
2741 XSetFunction(x_display, x_caretgc, GXxor);
2742 XSetLineAttributes(x_display, x_caretgc, 2, LineSolid, CapButt, JoinBevel);
2743
2744 display_clear();
2745 }
2746
display_reinitialise(void)2747 void display_reinitialise(void)
2748 {
2749 rc_font* fonts;
2750 rc_colour* cols;
2751 int num,x,y;
2752
2753 /* Deallocate resources */
2754 for (x=0; x<n_fonts; x++)
2755 {
2756 xfont_release_font(font[x]);
2757 }
2758 for (x=0; x<N_COLS; x++)
2759 {
2760 XFreeColors(x_display, DefaultColormap(x_display, x_screen),
2761 &x_colour[x].pixel, 1, 0);
2762 }
2763
2764 xfont_shutdown();
2765
2766 /* Reallocate fonts */
2767 xfont_initialise();
2768
2769 fonts = rc_get_fonts(&num);
2770 n_fonts = 0;
2771
2772 for (x=0; x<num; x++)
2773 {
2774 if (fonts[x].num <= 0)
2775 zmachine_fatal("Font numbers must be positive integers");
2776 if (fonts[x].num > n_fonts)
2777 {
2778 n_fonts = fonts[x].num;
2779 font = realloc(font, sizeof(xfont*)*n_fonts);
2780 }
2781
2782 font[fonts[x].num-1] = xfont_load_font(fonts[x].name);
2783
2784 for (y=0; y<fonts[x].n_attr; y++)
2785 {
2786 style_font[fonts[x].attributes[y]] = fonts[x].num-1;
2787 }
2788 }
2789
2790 for (y=0; y<16; y++)
2791 {
2792 if (style_font[y] == -1)
2793 {
2794 style_font[y] = style_font[8];
2795 }
2796 }
2797
2798 xfont_x = xfont_get_width(font[3]);
2799 xfont_y = xfont_get_height(font[3])+0.5;
2800
2801 max_x = size_x = rc_get_xsize();
2802 max_y = size_y = rc_get_ysize();
2803
2804 /* Reallocate colours */
2805 cols = rc_get_colours(&num);
2806 if (num > 11)
2807 {
2808 num = 11;
2809 zmachine_warning("Maximum of 11 colours");
2810 }
2811
2812 for (x=0; x<num; x++)
2813 {
2814 x_colour[x+FIRST_ZCOLOUR].red = cols[x].r<<8;
2815 x_colour[x+FIRST_ZCOLOUR].green = cols[x].g<<8;
2816 x_colour[x+FIRST_ZCOLOUR].blue = cols[x].b<<8;
2817 }
2818 for (x=0; x<N_COLS; x++)
2819 {
2820 if (!XAllocColor(x_display,
2821 DefaultColormap(x_display, x_screen),
2822 &x_colour[x]))
2823 {
2824 fprintf(stderr, "Warning: couldn't allocate colour #%i\n", x);
2825 x_colour[x].pixel = BlackPixel(x_display, x_screen);
2826 }
2827 }
2828
2829 size_window();
2830
2831 display_clear();
2832 }
2833
display_finalise(void)2834 void display_finalise(void)
2835 {
2836 /* Shut everything down */
2837 XDestroyWindow(x_display, x_mainwin);
2838 XCloseDisplay(x_display);
2839 }
2840
2841 extern int zoom_main(int, char**);
2842
main(int argc,char ** argv)2843 int main(int argc, char** argv)
2844 {
2845 /* Start everything rolling */
2846 return zoom_main(argc, argv);
2847 }
2848
display_exit(int code)2849 void display_exit(int code)
2850 {
2851 /* Die */
2852 exit(code);
2853 }
2854
display_get_info(void)2855 ZDisplay* display_get_info(void)
2856 {
2857 static ZDisplay dis;
2858 XColor col;
2859
2860 /* Return display capabilities */
2861
2862 dis.status_line = 1;
2863 dis.can_split = 1;
2864 dis.variable_font = 1;
2865 dis.colours = 1;
2866 dis.boldface = 1;
2867 dis.italic = 1;
2868 dis.fixed_space = 1;
2869 dis.sound_effects = 0;
2870 dis.timed_input = 1;
2871 dis.mouse = 1;
2872
2873 dis.lines = size_y;
2874 dis.columns = size_x;
2875 dis.width = size_x;
2876 dis.height = size_y;
2877 dis.font_width = 1;
2878 dis.font_height = 1;
2879 dis.pictures = 1;
2880 dis.fore = DEFAULT_FORE;
2881 dis.back = DEFAULT_BACK;
2882
2883 col = x_colour[FIRST_ZCOLOUR+DEFAULT_FORE];
2884 dis.fore_true = (col.red>>11)|((col.green>>11)<<5)|((col.blue>>11)<<10);
2885 col = x_colour[FIRST_ZCOLOUR+DEFAULT_BACK];
2886 dis.back_true = (col.red>>11)|((col.green>>11)<<5)|((col.blue>>11)<<10);
2887
2888 if (x_pixmap != None)
2889 {
2890 dis.width = pix_w;
2891 dis.height = pix_h;
2892
2893 dis.font_width = xfont_get_width(font[style_font[4]])+0.5;
2894 dis.font_height = xfont_get_height(font[style_font[4]])+0.5;
2895 }
2896
2897 return &dis;
2898 }
2899
2900 /*** ----// 888 \\---- ***/
2901 /* Pixmap display */
2902
pixmap_update(int left,int top,int right,int bottom)2903 static void pixmap_update(int left, int top, int right, int bottom)
2904 {
2905 int xp, yp;
2906
2907 xp = win_x/2 - pix_w/2;
2908 yp = win_y/2 - pix_h/2;
2909
2910 display_update_region(xp+left, yp+top, xp+right, yp+bottom);
2911 }
2912
display_init_pixmap(int width,int height)2913 int display_init_pixmap(int width, int height)
2914 {
2915 if (x_pixmap != None)
2916 {
2917 zmachine_fatal("Can't initialise a pixmap display twice in succession");
2918 return 0;
2919 }
2920
2921 if (width < 0)
2922 {
2923 width = win_x; height = win_y;
2924 }
2925 pix_w = width; pix_h = height;
2926 x_pixmap = XCreatePixmap(x_display, x_drawable,
2927 width, height,
2928 DefaultDepth(x_display, x_screen));
2929 if (x_pixmap == None)
2930 return 0;
2931
2932 x_pixgc = XCreateGC(x_display, x_pixmap, 0, NULL);
2933
2934 XSetForeground(x_display, x_pixgc, xdisplay_get_pixel_value(1));
2935 XFillRectangle(x_display, x_pixmap, x_pixgc, 0,0, width, height);
2936
2937 XResizeWindow(x_display, x_mainwin,
2938 width+BORDER_SIZE*2+SCROLLBAR_SIZE,
2939 height+BORDER_SIZE*2);
2940
2941 #ifdef HAVE_XRENDER
2942 if (x_picformat != NULL)
2943 x_pixpic = XRenderCreatePicture(x_display, x_pixmap, x_picformat, 0, NULL);
2944 #endif
2945
2946 #ifdef HAVE_XFT
2947 if (xft_drawable != NULL)
2948 {
2949 XftDrawChange(xft_drawable, x_pixmap);
2950 }
2951 #endif
2952
2953 return 1;
2954 }
2955
display_pixmap_cols(int fore,int back)2956 void display_pixmap_cols(int fore, int back)
2957 {
2958 pix_fore = fore;
2959 pix_back = back;
2960 if (back == -1)
2961 pix_back = -1;
2962 if (fore < 0)
2963 pix_fore = DEFAULT_FORE;
2964 }
2965
display_get_pix_colour(int x,int y)2966 int display_get_pix_colour(int x, int y)
2967 {
2968 /* Blecherous, but there you go */
2969 XImage* teeny;
2970 unsigned long px;
2971 XColor out;
2972
2973 int res;
2974
2975 teeny = XGetImage(x_display, x_pixmap, x, y, 1, 1, AllPlanes, XYPixmap);
2976 px = XGetPixel(teeny, 0, 0);
2977 XDestroyImage(teeny);
2978
2979 out.pixel = px;
2980 XQueryColor(x_display, DefaultColormap(x_display, x_screen),
2981 &out);
2982
2983 /* See if we have a standard colour */
2984 for (x=FIRST_ZCOLOUR; x<FIRST_ZCOLOUR+8; x++)
2985 {
2986 long int err;
2987 int r,g,b;
2988
2989 r = x_colour[x].red - out.red;
2990 g = x_colour[x].green - out.green;
2991 b = x_colour[x].blue - out.blue;
2992
2993 /* Sort of RMS error */
2994 err = (r>>8)*(r>>8) + (g>>8)*(g>>8) + (b>>8)*(b>>8);
2995
2996 if (err <= 192)
2997 {
2998 return x-FIRST_ZCOLOUR;
2999 }
3000 }
3001
3002 res = (out.red>>11)|((out.green>>11)<<5)|((out.blue>>11)<<10);
3003
3004 return res+16;
3005 }
3006
display_plot_gtext(const int * text,int len,int style,int x,int y)3007 void display_plot_gtext(const int* text,
3008 int len,
3009 int style,
3010 int x,
3011 int y)
3012 {
3013 int fg, bg;
3014 int ft;
3015
3016 float width, height;
3017
3018 if (len <= 0)
3019 return;
3020
3021 if (x<0 || y<0)
3022 return;
3023
3024 fg = pix_fore; bg = pix_back;
3025 if ((style&1))
3026 { fg = pix_back; bg = pix_fore; }
3027 if (fg < 0)
3028 fg = 7;
3029
3030 ft = style_font[(style>>1)&15];
3031
3032 xfont_set_colours(fg, bg);
3033
3034 width = xfont_get_text_width(font[ft],
3035 text, len);
3036 height = xfont_get_height(font[ft])+0.5;
3037
3038 if (bg >= 0)
3039 {
3040 XSetForeground(x_display, x_pixgc,
3041 xdisplay_get_pixel_value(bg));
3042 XFillRectangle(x_display, x_pixmap, x_pixgc,
3043 x, y-xfont_get_ascent(font[ft]),
3044 width,
3045 height);
3046 }
3047 xfont_plot_string(font[ft], x_pixmap, x_pixgc,
3048 x, y,
3049 text, len);
3050
3051 y -= xfont_get_ascent(font[ft]);
3052 pixmap_update(x, y, x+width, y+height);
3053 }
3054
display_plot_rect(int x,int y,int width,int height)3055 void display_plot_rect(int x, int y,
3056 int width, int height)
3057 {
3058 XSetForeground(x_display, x_pixgc,
3059 xdisplay_get_pixel_value(pix_fore));
3060 XFillRectangle(x_display, x_pixmap, x_pixgc,
3061 x, y,
3062 width, height);
3063
3064 pixmap_update(x, y, x+width, y+height);
3065 }
3066
display_scroll_region(int x,int y,int width,int height,int xoff,int yoff)3067 void display_scroll_region(int x, int y,
3068 int width, int height,
3069 int xoff, int yoff)
3070 {
3071 int rx, ry, rw, rh;
3072
3073 XCopyArea(x_display, x_pixmap, x_pixmap, x_pixgc,
3074 x, y,
3075 width, height,
3076 x+xoff, y+yoff);
3077
3078 rx = x; ry = y;
3079 rw = width; rh = height;
3080
3081 if (xoff < 0)
3082 rx += xoff;
3083 else
3084 rw += xoff;
3085 if (yoff < 0)
3086 ry += yoff;
3087 else
3088 rh += yoff;
3089
3090 pixmap_update(rx, ry, rx+rw, ry+rh);
3091 }
3092
display_measure_text(const int * text,int len,int style)3093 float display_measure_text(const int* text, int len, int style)
3094 {
3095 int ft;
3096 float res;
3097
3098 if (len <= 0)
3099 return 0;
3100
3101 ft = style_font[(style>>1)&15];
3102
3103 res = xfont_get_text_width(font[ft], text, len);
3104
3105 return res;
3106 }
3107
display_get_font_width(int style)3108 float display_get_font_width(int style)
3109 {
3110 int ft;
3111
3112 ft = style_font[(style>>1)&15];
3113
3114 return xfont_get_width(font[ft]);
3115 }
3116
display_get_font_height(int style)3117 float display_get_font_height(int style)
3118 {
3119 int ft;
3120
3121 ft = style_font[(style>>1)&15];
3122
3123 return xfont_get_height(font[ft]);
3124 }
3125
display_get_font_ascent(int style)3126 float display_get_font_ascent(int style)
3127 {
3128 int ft;
3129
3130 ft = style_font[(style>>1)&15];
3131
3132 return xfont_get_ascent(font[ft]);
3133 }
3134
display_get_font_descent(int style)3135 float display_get_font_descent(int style)
3136 {
3137 int ft;
3138
3139 ft = style_font[(style>>1)&15];
3140
3141 return xfont_get_descent(font[ft]);
3142 }
3143
display_plot_image(BlorbImage * img,int x,int y)3144 void display_plot_image(BlorbImage* img, int x, int y)
3145 {
3146 int sc_n, sc_d;
3147
3148 if (img == NULL)
3149 return;
3150
3151 v6_scale_image(img, &sc_n, &sc_d);
3152
3153 reset_clip();
3154
3155 if (img->loaded == NULL)
3156 {
3157 return;
3158 }
3159
3160 #ifdef HAVE_XRENDER
3161 if (x_pixpic != None)
3162 {
3163 image_plot_Xrender(img->loaded, x_display, x_pixpic,
3164 x, y, sc_n, sc_d);
3165 }
3166 else
3167 #endif
3168 {
3169 image_plot_X(img->loaded, x_display, x_pixmap, x_pixgc,
3170 x, y, sc_n, sc_d);
3171 }
3172
3173 pixmap_update(x, y, x+image_width(img->loaded), y+image_height(img->loaded));
3174 }
3175
display_wait_for_more(void)3176 void display_wait_for_more(void)
3177 {
3178 more_on = 1;
3179 display_readchar(0);
3180 more_on = 0;
3181
3182 draw_window();
3183 }
3184
display_set_mouse_win(int x,int y,int w,int h)3185 void display_set_mouse_win(int x, int y, int w, int h)
3186 {
3187 mousew_x = x;
3188 mousew_y = y;
3189 mousew_w = w;
3190 mousew_h = h;
3191 }
3192
3193 #endif
3194