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