comparison src/redisplay-x.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 9ee227acff29
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* X output and frame manipulation routines.
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1994 Lucid, Inc.
4 Copyright (C) 1995 Sun Microsystems, Inc.
5
6 This file is part of XEmacs.
7
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
22
23 /* Synched up with: Not in FSF. */
24
25 /* Author: Chuck Thompson */
26
27 /* Lots of work done by Ben Wing for Mule */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "console-x.h"
33 #include "EmacsFrame.h"
34 #include "EmacsFrameP.h"
35 #include "xgccache.h"
36 #include "glyphs-x.h"
37 #include "objects-x.h"
38
39 #include "buffer.h"
40 #include "debug.h"
41 #include "faces.h"
42 #include "frame.h"
43 #include "redisplay.h"
44 #include "sysdep.h"
45 #include "window.h"
46 #include <X11/bitmaps/gray>
47
48 #include "sysproc.h" /* for select() */
49
50 /* X_DIVIDER_LINE_WIDTH is the width of the line drawn in the gutter.
51 X_DIVIDER_SPACING is the amount of blank space on each side of the line.
52 X_DIVIDER_WIDTH = X_DIVIDER_LINE_WIDTH + 2*X_DIVIDER_SPACING
53 */
54
55 /* Number of pixels below each line. */
56 /* #### implement me */
57 int x_interline_space;
58
59 #define X_DIVIDER_LINE_WIDTH 3
60 #define X_DIVIDER_SPACING 2
61 #define X_DIVIDER_WIDTH (X_DIVIDER_LINE_WIDTH + 2 * X_DIVIDER_SPACING)
62
63 #define EOL_CURSOR_WIDTH 5
64
65 static void x_output_pixmap (struct window *w, struct display_line *dl,
66 Lisp_Object image_instance, int xpos,
67 int xoffset,
68 int start_pixpos, int width, face_index findex,
69 int cursor_start, int cursor_width,
70 int cursor_height);
71 static void x_output_vertical_divider (struct window *w, int clear);
72 static void x_output_blank (struct window *w, struct display_line *dl,
73 struct rune *rb, int start_pixpos,
74 int cursor_start, int cursor_width);
75 static void x_output_hline (struct window *w, struct display_line *dl,
76 struct rune *rb);
77 static void x_redraw_exposed_window (struct window *w, int x, int y,
78 int width, int height);
79 static void x_redraw_exposed_windows (Lisp_Object window, int x, int y,
80 int width, int height);
81 static void x_clear_region (Lisp_Object window, face_index findex, int x,
82 int y, int width, int height);
83 static void x_output_eol_cursor (struct window *w, struct display_line *dl,
84 int xpos);
85 static void x_clear_frame (struct frame *f);
86 static void x_clear_frame_windows (Lisp_Object window);
87 static void x_bevel_modeline (struct window *w, struct display_line *dl);
88
89
90 /* Note: We do not use the Xmb*() functions and XFontSets.
91 Those functions are generally losing for a number of reasons:
92
93 1) They only support one locale (e.g. you could display
94 Japanese and ASCII text, but not mixed Japanese/Chinese
95 text). You could maybe call setlocale() frequently
96 to try to deal with this, but that would generally
97 fail because an XFontSet is tied to one locale and
98 won't have the other character sets in it.
99 2) Not all (or even very many) OS's support the useful
100 locales. For example, as far as I know SunOS and
101 Solaris only support the Japanese locale if you get the
102 special Asian-language version of the OS. Yuck yuck
103 yuck. Linux doesn't support the Japanese locale at
104 all.
105 3) The locale support in X only exists in R5, not in R4.
106 (Not sure how big of a problem this is: how many
107 people are using R4?)
108 4) Who knows if the multi-byte text format (which is locale-
109 specific) is even the same for the same locale on
110 different OS's? It's not even documented anywhere that
111 I can find what the multi-byte text format for the
112 Japanese locale under SunOS and Solaris is, but I assume
113 it's EUC.
114 */
115
116 struct textual_run
117 {
118 Lisp_Object charset;
119 unsigned char *ptr;
120 int len;
121 int dimension;
122 };
123
124 /* Separate out the text in DYN into a series of textual runs of a
125 particular charset. Also convert the characters as necessary into
126 the format needed by XDrawImageString(), XDrawImageString16(), et
127 al. (This means converting to one or two byte format, possibly
128 tweaking the high bits, and possibly running a CCL program.) You
129 must pre-allocate the space used and pass it in. (This is done so
130 you can alloca() the space.) You need to allocate (2 * len) bytes
131 of TEXT_STORAGE and (len * sizeof (struct textual_run)) bytes of
132 RUN_STORAGE, where LEN is the length of the dynarr.
133
134 Returns the number of runs actually used. */
135
136 static int
137 separate_textual_runs (unsigned char *text_storage,
138 struct textual_run *run_storage,
139 CONST Emchar *str, Charcount len)
140 {
141 Lisp_Object prev_charset = Qunbound; /* not Qnil because that is a
142 possible valid charset when
143 MULE is not defined */
144 int runs_so_far = 0;
145 int i;
146
147 for (i = 0; i < len; i++)
148 {
149 Emchar ch = str[i];
150 Lisp_Object charset;
151 int byte1, byte2;
152 int dimension;
153 int graphic;
154
155 BREAKUP_CHAR (ch, charset, byte1, byte2);
156 dimension = XCHARSET_DIMENSION (charset);
157 graphic = XCHARSET_GRAPHIC (charset);
158
159 if (!EQ (charset, prev_charset))
160 {
161 run_storage[runs_so_far].ptr = text_storage;
162 run_storage[runs_so_far].charset = charset;
163 run_storage[runs_so_far].dimension = dimension;
164
165 if (runs_so_far)
166 {
167 run_storage[runs_so_far - 1].len =
168 text_storage - run_storage[runs_so_far - 1].ptr;
169 if (run_storage[runs_so_far - 1].dimension == 2)
170 run_storage[runs_so_far - 1].len >>= 1;
171 }
172 runs_so_far++;
173 prev_charset = charset;
174 }
175
176 if (graphic == 0)
177 {
178 byte1 &= 0x7F;
179 byte2 &= 0x7F;
180 }
181 else if (graphic == 1)
182 {
183 byte1 |= 0x80;
184 byte2 |= 0x80;
185 }
186 *text_storage++ = (unsigned char) byte1;
187 if (dimension == 2)
188 *text_storage++ = (unsigned char) byte2;
189 }
190
191 if (runs_so_far)
192 {
193 run_storage[runs_so_far - 1].len =
194 text_storage - run_storage[runs_so_far - 1].ptr;
195 if (run_storage[runs_so_far - 1].dimension == 2)
196 run_storage[runs_so_far - 1].len >>= 1;
197 }
198
199 return runs_so_far;
200 }
201
202 /****************************************************************************/
203 /* */
204 /* X output routines */
205 /* */
206 /****************************************************************************/
207
208 static int
209 x_text_width_single_run (struct face_cachel *cachel, struct textual_run *run)
210 {
211 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
212 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
213 if (!fi->proportional_p)
214 return fi->width * run->len;
215 else
216 {
217 if (run->dimension == 2)
218 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
219 (XChar2b *) run->ptr, run->len);
220 else
221 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
222 (char *) run->ptr, run->len);
223 }
224 }
225
226 /*
227 x_text_width
228
229 Given a string and a face, return the string's length in pixels when
230 displayed in the font associated with the face.
231 */
232
233 static int
234 x_text_width (struct face_cachel *cachel, CONST Emchar *str,
235 Charcount len)
236 {
237 int width_so_far = 0;
238 unsigned char *text_storage = (unsigned char *) alloca (2 * len);
239 struct textual_run *runs =
240 (struct textual_run *) alloca (len * sizeof (struct textual_run));
241 int nruns;
242 int i;
243
244 nruns = separate_textual_runs (text_storage, runs, str, len);
245
246 for (i = 0; i < nruns; i++)
247 width_so_far += x_text_width_single_run (cachel, runs + i);
248
249 return width_so_far;
250 }
251
252
253 /*****************************************************************************
254 x_divider_width
255
256 Return the width of the vertical divider. This is a function because
257 divider_width is a device method.
258 ****************************************************************************/
259 static int
260 x_divider_width (void)
261 {
262 return X_DIVIDER_WIDTH;
263 }
264
265 /*****************************************************************************
266 x_divider_height
267
268 Return the height of the horizontal divider. This is a function because
269 divider_height is a device method.
270
271 #### If we add etched horizontal divider lines this will have to get
272 smarter.
273 ****************************************************************************/
274 static int
275 x_divider_height (void)
276 {
277 return 1;
278 }
279
280 /*****************************************************************************
281 x_eol_cursor_width
282
283 Return the width of the end-of-line cursor. This is a function
284 because eol_cursor_width is a device method.
285 ****************************************************************************/
286 static int
287 x_eol_cursor_width (void)
288 {
289 return EOL_CURSOR_WIDTH;
290 }
291
292 /*****************************************************************************
293 x_output_begin
294
295 Perform any necessary initialization prior to an update.
296 ****************************************************************************/
297 static void
298 x_output_begin (struct device *d)
299 {
300 }
301
302 /*****************************************************************************
303 x_output_end
304
305 Perform any necessary flushing of queues when an update has completed.
306 ****************************************************************************/
307 static void
308 x_output_end (struct device *d)
309 {
310 XFlush (DEVICE_X_DISPLAY (d));
311 }
312
313 /*****************************************************************************
314 x_output_display_block
315
316 Given a display line, a block number for that start line, output all
317 runes between start and end in the specified display block.
318 ****************************************************************************/
319 static void
320 x_output_display_block (struct window *w, struct display_line *dl, int block,
321 int start, int end, int start_pixpos, int cursor_start,
322 int cursor_width, int cursor_height)
323 {
324 struct frame *f = XFRAME (w->frame);
325 emchar_dynarr *buf = Dynarr_new (Emchar);
326 Lisp_Object window;
327
328 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
329 rune_dynarr *rba = db->runes;
330 struct rune *rb;
331
332 int elt = start;
333 face_index findex;
334 int xpos, width;
335 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
336 MULE is not defined */
337
338 XSETWINDOW (window, w);
339 rb = Dynarr_atp (rba, start);
340
341 if (!rb)
342 {
343 /* Nothing to do so don't do anything. */
344 return;
345 }
346 else
347 {
348 findex = rb->findex;
349 xpos = rb->xpos;
350 width = 0;
351 if (rb->type == RUNE_CHAR)
352 charset = CHAR_CHARSET (rb->object.chr.ch);
353 }
354
355 if (end < 0)
356 end = Dynarr_length (rba);
357 Dynarr_reset (buf);
358
359 while (elt < end)
360 {
361 rb = Dynarr_atp (rba, elt);
362
363 if (rb->findex == findex && rb->type == RUNE_CHAR
364 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
365 && EQ (charset, CHAR_CHARSET (rb->object.chr.ch)))
366 {
367 Dynarr_add (buf, rb->object.chr.ch);
368 width += rb->width;
369 elt++;
370 }
371 else
372 {
373 if (Dynarr_length (buf))
374 {
375 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
376 findex, 0, cursor_start, cursor_width,
377 cursor_height);
378 xpos = rb->xpos;
379 width = 0;
380 }
381 Dynarr_reset (buf);
382 width = 0;
383
384 if (rb->type == RUNE_CHAR)
385 {
386 findex = rb->findex;
387 xpos = rb->xpos;
388 charset = CHAR_CHARSET (rb->object.chr.ch);
389
390 if (rb->cursor_type == CURSOR_ON)
391 {
392 if (rb->object.chr.ch == '\n')
393 {
394 x_output_eol_cursor (w, dl, xpos);
395 }
396 else
397 {
398 Dynarr_add (buf, rb->object.chr.ch);
399 x_output_string (w, dl, buf, xpos, 0, start_pixpos,
400 rb->width, findex, 1,
401 cursor_start, cursor_width,
402 cursor_height);
403 Dynarr_reset (buf);
404 }
405
406 xpos += rb->width;
407 elt++;
408 }
409 else if (rb->object.chr.ch == '\n')
410 {
411 /* Clear in case a cursor was formerly here. */
412 int height = dl->ascent + dl->descent - dl->clip;
413
414 x_clear_region (window, findex, xpos, dl->ypos - dl->ascent,
415 rb->width, height);
416 elt++;
417 }
418 }
419 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
420 {
421 if (rb->type == RUNE_BLANK)
422 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
423 cursor_width);
424 else
425 {
426 /* #### Our flagging of when we need to redraw the
427 modeline shadows sucks. Since RUNE_HLINE is only used
428 by the modeline at the moment it is a good bet
429 that if it gets redrawn then we should also
430 redraw the shadows. This won't be true forever.
431 We borrow the shadow_thickness_changed flag for
432 now. */
433 w->shadow_thickness_changed = 1;
434 x_output_hline (w, dl, rb);
435 }
436
437 elt++;
438 if (elt < end)
439 {
440 rb = Dynarr_atp (rba, elt);
441
442 findex = rb->findex;
443 xpos = rb->xpos;
444 }
445 }
446 else if (rb->type == RUNE_DGLYPH)
447 {
448 Lisp_Object instance;
449
450 XSETWINDOW (window, w);
451 instance = glyph_image_instance (rb->object.dglyph.glyph,
452 window, ERROR_ME_NOT, 1);
453 findex = rb->findex;
454
455 if (IMAGE_INSTANCEP (instance))
456 switch (XIMAGE_INSTANCE_TYPE (instance))
457 {
458 case IMAGE_TEXT:
459 {
460 /* #### This is way losing. See the comment in
461 add_glyph_rune(). */
462 Lisp_Object string =
463 XIMAGE_INSTANCE_TEXT_STRING (instance);
464 convert_bufbyte_string_into_emchar_dynarr
465 (string_data (XSTRING (string)),
466 string_length (XSTRING (string)),
467 buf);
468
469 x_output_string (w, dl, buf, xpos,
470 rb->object.dglyph.xoffset,
471 start_pixpos, -1, findex,
472 (rb->cursor_type == CURSOR_ON),
473 cursor_start, cursor_width,
474 cursor_height);
475 Dynarr_reset (buf);
476 }
477 break;
478
479 case IMAGE_MONO_PIXMAP:
480 case IMAGE_COLOR_PIXMAP:
481 x_output_pixmap (w, dl, instance, xpos,
482 rb->object.dglyph.xoffset, start_pixpos,
483 rb->width, findex, cursor_start,
484 cursor_width, cursor_height);
485 break;
486
487 case IMAGE_POINTER:
488 abort ();
489
490 case IMAGE_SUBWINDOW:
491 /* #### implement me */
492 break;
493
494 case IMAGE_NOTHING:
495 /* nothing is as nothing does */
496 break;
497
498 default:
499 abort ();
500 }
501
502 xpos += rb->width;
503 elt++;
504 }
505 else
506 abort ();
507 }
508 }
509
510 if (Dynarr_length (buf))
511 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
512 0, cursor_start, cursor_width, cursor_height);
513
514 /* #### This is really conditionalized well for optimized
515 performance. */
516 if (dl->modeline
517 && !EQ (Qzero, w->modeline_shadow_thickness)
518 && (f->clear
519 || f->windows_structure_changed
520 || w->shadow_thickness_changed))
521 x_bevel_modeline (w, dl);
522
523 Dynarr_free (buf);
524 }
525
526 /*****************************************************************************
527 x_bevel_modeline
528
529 Draw a 3d border around the modeline on window W.
530 ****************************************************************************/
531 static void
532 x_bevel_modeline (struct window *w, struct display_line *dl)
533 {
534 struct frame *f = XFRAME (w->frame);
535 struct device *d = XDEVICE (f->device);
536 Display *dpy = DEVICE_X_DISPLAY (d);
537 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
538 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f);
539 GC top_shadow_gc, bottom_shadow_gc, background_gc;
540 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel;
541 XColor tmp_color;
542 Lisp_Object tmp_pixel;
543 int x, y, width, height;
544 XGCValues gcv;
545 unsigned long mask;
546 int use_pixmap = 0;
547 int flip_gcs = 0;
548 int shadow_thickness;
549
550 memset (&gcv, ~0, sizeof (XGCValues));
551
552 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
553 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
554
555 /* First, get the GC's. */
556 top_shadow_pixel = tmp_color.pixel;
557 bottom_shadow_pixel = tmp_color.pixel;
558 background_pixel = tmp_color.pixel;
559
560 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel,
561 background_pixel, ef->core.background_pixel);
562
563 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, MODELINE_INDEX);
564 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
565 gcv.background = tmp_color.pixel;
566 gcv.graphics_exposures = False;
567 mask = GCForeground | GCBackground | GCGraphicsExposures;
568
569 if (top_shadow_pixel == background_pixel ||
570 bottom_shadow_pixel == background_pixel)
571 use_pixmap = 1;
572
573 if (use_pixmap)
574 {
575 if (DEVICE_X_GRAY_PIXMAP (d) == None)
576 {
577 DEVICE_X_GRAY_PIXMAP (d) =
578 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits,
579 gray_width, gray_height, 1, 0, 1);
580 }
581
582 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX);
583 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
584 gcv.foreground = tmp_color.pixel;
585 gcv.fill_style = FillOpaqueStippled;
586 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
587 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv,
588 (mask | GCStipple | GCFillStyle));
589
590 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, MODELINE_INDEX);
591 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
592 bottom_shadow_pixel = tmp_color.pixel;
593
594 flip_gcs = (bottom_shadow_pixel ==
595 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy)));
596 }
597 else
598 {
599 gcv.foreground = top_shadow_pixel;
600 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
601 }
602
603 gcv.foreground = bottom_shadow_pixel;
604 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
605
606 if (use_pixmap && flip_gcs)
607 {
608 GC tmp_gc = bottom_shadow_gc;
609 bottom_shadow_gc = top_shadow_gc;
610 top_shadow_gc = tmp_gc;
611 }
612
613 gcv.foreground = background_pixel;
614 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
615
616 if (XINT (w->modeline_shadow_thickness) < 0)
617 {
618 GC temp;
619
620 temp = top_shadow_gc;
621 top_shadow_gc = bottom_shadow_gc;
622 bottom_shadow_gc = temp;
623 }
624
625 shadow_thickness = MODELINE_SHADOW_THICKNESS (w);
626
627 x = WINDOW_MODELINE_LEFT (w);
628 width = WINDOW_MODELINE_RIGHT (w) - x;
629 y = dl->ypos - dl->ascent - shadow_thickness;
630 height = dl->ascent + dl->descent + 2 * shadow_thickness;
631
632 x_output_shadows (f, x, y, width, height, top_shadow_gc, bottom_shadow_gc,
633 background_gc, shadow_thickness);
634 }
635
636 void debug_print (Lisp_Object); /* kludge! */
637
638 /*****************************************************************************
639 x_get_gc
640
641 Given a number of parameters return a GC with those properties.
642 ****************************************************************************/
643 static GC
644 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
645 Lisp_Object bg_pmap, Lisp_Object lwidth)
646 {
647 XGCValues gcv;
648 unsigned long mask;
649
650 memset (&gcv, ~0, sizeof (XGCValues));
651 gcv.graphics_exposures = False;
652 /* Make absolutely sure that we don't pick up a clipping region in
653 the GC returned by this function. */
654 gcv.clip_mask = None;
655 gcv.clip_x_origin = 0;
656 gcv.clip_y_origin = 0;
657 gcv.fill_style = FillSolid;
658 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
659 mask |= GCFillStyle;
660
661 if (!NILP (font))
662 {
663 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
664 mask |= GCFont;
665 }
666
667 /* evil kludge! */
668 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
669 {
670 /* #### I fixed once case where this was getting it. It was a
671 bad macro expansion (compiler bug). */
672 fprintf (stderr, "Help! x_get_gc got a bogus fg value! fg = ");
673 debug_print (fg);
674 fg = Qnil;
675 }
676
677 if (!NILP (fg))
678 {
679 if (COLOR_INSTANCEP (fg))
680 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
681 else
682 gcv.foreground = XINT (fg);
683 mask |= GCForeground;
684 }
685
686 if (!NILP (bg))
687 {
688 if (COLOR_INSTANCEP (bg))
689 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
690 else
691 gcv.background = XINT (bg);
692 mask |= GCBackground;
693 }
694
695 if (IMAGE_INSTANCEP (bg_pmap)
696 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
697 {
698 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
699 {
700 gcv.fill_style = FillOpaqueStippled;
701 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
702 mask |= (GCStipple | GCFillStyle);
703 }
704 else
705 {
706 gcv.fill_style = FillTiled;
707 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
708 mask |= (GCTile | GCFillStyle);
709 }
710 }
711
712 if (!NILP (lwidth))
713 {
714 gcv.line_width = XINT (lwidth);
715 mask |= GCLineWidth;
716 }
717
718 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
719 }
720
721 /*****************************************************************************
722 x_output_string
723
724 Given a string and a starting position, output that string in the
725 given face. If cursor is true, draw a cursor around the string.
726 Correctly handles multiple charsets in the string.
727
728 The meaning of the parameters is something like this:
729
730 W Window that the text is to be displayed in.
731 DL Display line that this text is on. The values in the
732 structure are used to determine the vertical position and
733 clipping range of the text.
734 BUF Dynamic array of Emchars specifying what is actually to be
735 drawn.
736 XPOS X position in pixels where the text should start being drawn.
737 XOFFSET Number of pixels to be chopped off the left side of the
738 text. The effect is as if the text were shifted to the
739 left this many pixels and clipped at XPOS.
740 CLIP_START Clip everything left of this X position.
741 WIDTH Clip everything right of XPOS + WIDTH.
742 FINDEX Index for the face cache element describing how to display
743 the text.
744 CURSOR #### I don't understand this. There's something
745 strange and overcomplexified with this variable.
746 Chuck, explain please?
747 CURSOR_START Starting X position of cursor.
748 CURSOR_WIDTH Width of cursor in pixels.
749 CURSOR_HEIGHT Height of cursor in pixels.
750
751 Starting Y position of cursor is the top of the text line.
752 The cursor is drawn sometimes whether or not CURSOR is set. ???
753 ****************************************************************************/
754 void
755 x_output_string (struct window *w, struct display_line *dl,
756 emchar_dynarr *buf, int xpos, int xoffset, int clip_start,
757 int width, face_index findex, int cursor,
758 int cursor_start, int cursor_width, int cursor_height)
759 {
760 /* General variables */
761 struct frame *f = XFRAME (w->frame);
762 struct device *d = XDEVICE (f->device);
763 Lisp_Object device = Qnil;
764 Lisp_Object window = Qnil;
765 Display *dpy = DEVICE_X_DISPLAY (d);
766 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
767
768 int clip_end;
769
770 /* Cursor-related variables */
771 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
772 int cursor_clip;
773 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
774 WINDOW_BUFFER (w));
775 struct face_cachel *cursor_cachel = 0;
776
777 /* Text-related variables */
778 Lisp_Object bg_pmap;
779 GC bgc, gc;
780 int height;
781 int len = Dynarr_length (buf);
782 unsigned char *text_storage = alloca (2 * len);
783 struct textual_run *runs = alloca (len * sizeof (struct textual_run));
784 int nruns;
785 int i;
786 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
787
788 XSETDEVICE (device, d);
789 XSETWINDOW (window, w);
790
791 if (width < 0)
792 width = x_text_width (cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
793 height = dl->ascent + dl->descent - dl->clip;
794
795 /* Regularize the variables passed in. */
796
797 if (clip_start < xpos)
798 clip_start = xpos;
799 clip_end = xpos + width;
800 if (clip_start >= clip_end)
801 /* It's all clipped out. */
802 return;
803
804 xpos -= xoffset;
805
806 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
807 Dynarr_length (buf));
808
809 cursor_clip = (cursor_start >= clip_start &&
810 cursor_start < clip_end);
811
812 /* This cursor code is really a mess. */
813 if (!NILP (w->text_cursor_visible_p)
814 && (cursor
815 || cursor_clip
816 || (cursor_width
817 && (cursor_start + cursor_width >= clip_start)
818 && !NILP (bar_cursor_value))))
819 {
820 /* These have to be in separate statements in order to avoid a
821 compiler bug. */
822 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
823 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
824
825 /* We have to reset this since any call to WINDOW_FACE_CACHEL
826 may cause the cache to resize and any pointers to it to
827 become invalid. */
828 cachel = WINDOW_FACE_CACHEL (w, findex);
829 }
830
831 bg_pmap = cachel->background_pixmap;
832 if (!IMAGE_INSTANCEP (bg_pmap)
833 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
834 bg_pmap = Qnil;
835
836 if ((cursor && focus && NILP (bar_cursor_value)
837 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
838 bgc = 0;
839 else
840 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
841 bg_pmap, Qnil);
842
843 if (bgc)
844 XFillRectangle (dpy, x_win, bgc, clip_start,
845 dl->ypos - dl->ascent, clip_end - clip_start,
846 height);
847
848 for (i = 0; i < nruns; i++)
849 {
850 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
851 struct Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
852 int this_width;
853 int need_clipping;
854
855 if (EQ (font, Vthe_null_font_instance))
856 continue;
857
858 this_width = x_text_width_single_run (cachel, runs + i);
859 need_clipping = (dl->clip || clip_start > xpos ||
860 clip_end < xpos + this_width);
861
862 /* XDrawImageString only clears the area equal to the height of
863 the given font. It is possible that a font is being displayed
864 on a line taller than it is, so this would cause us to fail to
865 clear some areas. */
866 if ((int) fi->height < (int) (height + dl->clip))
867 {
868 int clear_start = max (xpos, clip_start);
869 int clear_end = min (xpos + this_width, clip_end);
870
871 if (cursor)
872 {
873 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
874
875 ypos1_string = dl->ypos - fi->ascent;
876 ypos2_string = dl->ypos + fi->descent;
877 ypos1_line = dl->ypos - dl->ascent;
878 ypos2_line = dl->ypos + dl->descent - dl->clip;
879
880 /* Make sure we don't clear below the real bottom of the
881 line. */
882 if (ypos1_string > ypos2_line)
883 ypos1_string = ypos2_line;
884 if (ypos2_string > ypos2_line)
885 ypos2_string = ypos2_line;
886
887 if (ypos1_line < ypos1_string)
888 {
889 x_clear_region (window, findex, clear_start, ypos1_line,
890 clear_end - clear_start,
891 ypos1_string - ypos1_line);
892 }
893
894 if (ypos2_line > ypos2_string)
895 {
896 x_clear_region (window, findex, clear_start, ypos2_string,
897 clear_end - clear_start,
898 ypos2_line - ypos2_string);
899 }
900 }
901 else
902 {
903 x_clear_region (window, findex, clear_start,
904 dl->ypos - dl->ascent, clear_end - clear_start,
905 height);
906 }
907 }
908
909 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
910 gc = x_get_gc (d, font, cursor_cachel->foreground,
911 cursor_cachel->background, Qnil, Qnil);
912 else
913 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
914 Qnil, Qnil);
915
916 if (need_clipping)
917 {
918 XRectangle clip_box[1];
919
920 clip_box[0].x = 0;
921 clip_box[0].y = 0;
922 clip_box[0].width = clip_end - clip_start;
923 clip_box[0].height = height;
924
925 XSetClipRectangles (dpy, gc, clip_start, dl->ypos - dl->ascent,
926 clip_box, 1, Unsorted);
927 }
928
929 if (runs[i].dimension == 1)
930 (bgc ? XDrawString : XDrawImageString) (dpy, x_win, gc, xpos,
931 dl->ypos, (char *) runs[i].ptr,
932 runs[i].len);
933 else
934 (bgc ? XDrawString16 : XDrawImageString16) (dpy, x_win, gc, xpos,
935 dl->ypos,
936 (XChar2b *) runs[i].ptr,
937 runs[i].len);
938
939 /* We draw underlines in the same color as the text. */
940 if (cachel->underline)
941 {
942 unsigned long upos, uthick;
943 XFontStruct *xfont;
944
945 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
946 if (!XGetFontProperty (xfont, XA_UNDERLINE_POSITION, &upos))
947 upos = 0;
948 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
949 uthick = 1;
950
951 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
952 {
953 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
954 uthick = dl->descent - dl->clip - upos;
955
956 if (uthick == 1)
957 {
958 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
959 xpos + this_width, dl->ypos + upos);
960 }
961 else if (uthick > 1)
962 {
963 XFillRectangle (dpy, x_win, gc, xpos,
964 dl->ypos + upos, this_width, uthick);
965 }
966 }
967 }
968
969 if (cachel->strikethru) {
970 unsigned long ascent,descent,upos, uthick;
971 XFontStruct *xfont;
972
973 xfont = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font));
974
975 if (!XGetFontProperty (xfont, XA_STRIKEOUT_ASCENT, &ascent))
976 ascent = xfont->ascent;
977 if (!XGetFontProperty (xfont, XA_STRIKEOUT_DESCENT, &descent))
978 descent = xfont->descent;
979 if (!XGetFontProperty (xfont, XA_UNDERLINE_THICKNESS, &uthick))
980 uthick = 1;
981
982 upos = ascent - ((ascent + descent) / 2) + 1;
983
984 /* Generally, upos will be positive (above the baseline),so subtract */
985 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
986 {
987 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
988 uthick = dl->descent - dl->clip + upos;
989
990 if (uthick == 1)
991 {
992 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
993 xpos + this_width, dl->ypos - upos);
994 }
995 else if (uthick > 1)
996 {
997 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
998 this_width, uthick);
999 }
1000 }
1001 }
1002
1003 /* Restore the GC */
1004 if (need_clipping)
1005 {
1006 XSetClipMask (dpy, gc, None);
1007 XSetClipOrigin (dpy, gc, 0, 0);
1008 }
1009
1010 /* If we are actually superimposing the cursor then redraw with just
1011 the appropriate section highlighted. */
1012 if (cursor_clip && !cursor && focus && cursor_cachel)
1013 {
1014 GC cgc;
1015 XRectangle clip_box[1];
1016
1017 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1018 cursor_cachel->background, Qnil, Qnil);
1019
1020 clip_box[0].x = 0;
1021 clip_box[0].y = 0;
1022 clip_box[0].width = cursor_width;
1023 clip_box[0].height = height;
1024
1025 XSetClipRectangles (dpy, cgc, cursor_start, dl->ypos - dl->ascent,
1026 clip_box, 1, Unsorted);
1027
1028 if (runs[i].dimension == 1)
1029 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1030 (char *) runs[i].ptr, runs[i].len);
1031 else
1032 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1033 (XChar2b *) runs[i].ptr, runs[i].len);
1034
1035 XSetClipMask (dpy, cgc, None);
1036 XSetClipOrigin (dpy, cgc, 0, 0);
1037 }
1038
1039 xpos += this_width;
1040 }
1041
1042 /* Draw the non-focus box or bar-cursor as needed. */
1043 /* Can't this logic be simplified? */
1044 if (cursor_cachel
1045 && ((cursor && !focus && NILP (bar_cursor_value))
1046 || (cursor_width
1047 && (cursor_start + cursor_width >= clip_start)
1048 && !NILP (bar_cursor_value))))
1049 {
1050 int tmp_height, tmp_y;
1051 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1052 int cursor_x;
1053
1054 /* #### This value is correct (as far as I know) because
1055 all of the times we need to draw this cursor, we will
1056 be called with exactly one character, so we know we
1057 can always use runs[0].
1058
1059 This is bogus as all hell, however. The cursor handling in
1060 this function is way bogus and desperately needs to be
1061 cleaned up. (In particular, the drawing of the cursor should
1062 really really be separated out of this function. This may be
1063 a bit tricky now because this function itself does way too
1064 much stuff, a lot of which needs to be moved into
1065 redisplay.c) This is the only way to be able to easily add
1066 new cursor types or (e.g.) make the bar cursor be able to
1067 span two characters instead of overlaying just one. */
1068 int bogusly_obtained_ascent_value =
1069 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1070
1071 if (!NILP (bar_cursor_value))
1072 {
1073 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1074 make_int (bar_width));
1075 }
1076 else
1077 {
1078 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1079 Qnil, Qnil, Qnil);
1080 }
1081
1082 if (cursor)
1083 cursor_x = clip_start;
1084 else
1085 cursor_x = cursor_start;
1086
1087 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1088 tmp_height = cursor_height;
1089 if (tmp_y + tmp_height > (int) (dl->ypos - dl->ascent + height))
1090 {
1091 tmp_y = dl->ypos - dl->ascent + height - tmp_height;
1092 if (tmp_y < (int) (dl->ypos - dl->ascent))
1093 tmp_y = dl->ypos - dl->ascent;
1094 tmp_height = dl->ypos - dl->ascent + height - tmp_y;
1095 }
1096
1097 if (!focus && NILP (bar_cursor_value))
1098 {
1099 XDrawRectangle (dpy, x_win, gc, cursor_x, tmp_y,
1100 cursor_width - 1, tmp_height - 1);
1101 }
1102 else if (focus && !NILP (bar_cursor_value))
1103 {
1104 XDrawLine (dpy, x_win, gc, cursor_x + bar_width - 1, tmp_y,
1105 cursor_x + bar_width - 1, tmp_y + tmp_height - 1);
1106 }
1107 }
1108 }
1109
1110 void
1111 x_output_x_pixmap (struct frame *f, struct Lisp_Image_Instance *p, int x,
1112 int y, int clip_x, int clip_y, int clip_width,
1113 int clip_height, int width, int height, int pixmap_offset,
1114 unsigned long fg, unsigned long bg, GC override_gc)
1115 {
1116 struct device *d = XDEVICE (f->device);
1117 Display *dpy = DEVICE_X_DISPLAY (d);
1118 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1119
1120 GC gc;
1121 XGCValues gcv;
1122 unsigned long pixmap_mask;
1123
1124 if (!override_gc)
1125 {
1126 memset (&gcv, ~0, sizeof (XGCValues));
1127 gcv.graphics_exposures = False;
1128 gcv.foreground = fg;
1129 gcv.background = bg;
1130 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1131
1132 if (IMAGE_INSTANCE_X_MASK (p))
1133 {
1134 gcv.function = GXcopy;
1135 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1136 gcv.clip_x_origin = x;
1137 gcv.clip_y_origin = y - pixmap_offset;
1138 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1139 GCClipYOrigin);
1140 }
1141
1142 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1143 }
1144 else
1145 gc = override_gc;
1146
1147 if (clip_x || clip_y)
1148 {
1149 XRectangle clip_box[1];
1150
1151 clip_box[0].x = clip_x;
1152 clip_box[0].y = clip_y;
1153 clip_box[0].width = clip_width;
1154 clip_box[0].height = clip_height;
1155
1156 XSetClipRectangles (dpy, gc, x, y, clip_box, 1, Unsorted);
1157 }
1158
1159 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1160 XCopyPlane (1 = current foreground color, 0 = background) instead
1161 of XCopyArea, which means that the bits in the pixmap are actual
1162 pixel values, instead of symbolic of fg/bg. */
1163 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1164 {
1165 XCopyArea (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1166 pixmap_offset, width,
1167 height, x, y);
1168 }
1169 else
1170 {
1171 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP (p), x_win, gc, 0,
1172 (pixmap_offset < 0
1173 ? 0
1174 : pixmap_offset),
1175 width, height, x,
1176 (pixmap_offset < 0
1177 ? y - pixmap_offset
1178 : y),
1179 1L);
1180 }
1181
1182 if (clip_x || clip_y)
1183 {
1184 XSetClipMask (dpy, gc, None);
1185 XSetClipOrigin (dpy, gc, 0, 0);
1186 }
1187 }
1188
1189 static void
1190 x_output_pixmap (struct window *w, struct display_line *dl,
1191 Lisp_Object image_instance, int xpos, int xoffset,
1192 int start_pixpos, int width, face_index findex,
1193 int cursor_start, int cursor_width, int cursor_height)
1194 {
1195 struct frame *f = XFRAME (w->frame);
1196 struct device *d = XDEVICE (f->device);
1197 struct Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1198 Lisp_Object window;
1199
1200 Display *dpy = DEVICE_X_DISPLAY (d);
1201 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1202 int lheight = dl->ascent + dl->descent - dl->clip;
1203 int pheight = ((int) IMAGE_INSTANCE_PIXMAP_HEIGHT (p) > lheight ? lheight :
1204 IMAGE_INSTANCE_PIXMAP_HEIGHT (p));
1205 int pwidth = min (width + xoffset, (int) IMAGE_INSTANCE_PIXMAP_WIDTH (p));
1206 int clip_x, clip_y, clip_width, clip_height;
1207
1208 /* The pixmap_offset is used to center the pixmap on lines which are
1209 shorter than it is. This results in odd effects when scrolling
1210 pixmaps off of the bottom. Let's try not using it. */
1211 #if 0
1212 int pixmap_offset = (int) (IMAGE_INSTANCE_PIXMAP_HEIGHT (p) - lheight) / 2;
1213 #else
1214 int pixmap_offset = 0;
1215 #endif
1216
1217 XSETWINDOW (window, w);
1218
1219 if ((start_pixpos >= 0 && start_pixpos > xpos) || xoffset)
1220 {
1221 if (start_pixpos > xpos && start_pixpos > xpos + width)
1222 return;
1223
1224 clip_x = xoffset;
1225 clip_width = width;
1226 if (start_pixpos > xpos)
1227 {
1228 clip_x += (start_pixpos - xpos);
1229 clip_width -= (start_pixpos - xpos);
1230 }
1231 }
1232 else
1233 {
1234 clip_x = 0;
1235 clip_width = 0;
1236 }
1237
1238 /* Place markers for possible future functionality (clipping the top
1239 half instead of the bottom half; think pixel scrolling). */
1240 clip_y = 0;
1241 clip_height = pheight;
1242
1243 /* Clear the area the pixmap is going into. The pixmap itself will
1244 always take care of the full width. We don't want to clear where
1245 it is going to go in order to avoid flicker. So, all we have to
1246 take care of is any area above or below the pixmap. */
1247 /* #### We take a shortcut for now. We know that since we have
1248 pixmap_offset hardwired to 0 that the pixmap is against the top
1249 edge so all we have to worry about is below it. */
1250 /* #### Unless the pixmap has a mask in which case we have to clear
1251 the whole damn thing since we can't yet clear just the area not
1252 included in the mask. */
1253 if (((int) (dl->ypos - dl->ascent + pheight) <
1254 (int) (dl->ypos + dl->descent - dl->clip))
1255 || IMAGE_INSTANCE_X_MASK (p))
1256 {
1257 int clear_x, clear_y, clear_width, clear_height;
1258
1259 if (IMAGE_INSTANCE_X_MASK (p))
1260 {
1261 clear_y = dl->ypos - dl->ascent;
1262 clear_height = lheight;
1263 }
1264 else
1265 {
1266 clear_y = dl->ypos - dl->ascent + pheight;
1267 clear_height = lheight - pheight;
1268 }
1269
1270 if (start_pixpos >= 0 && start_pixpos > xpos)
1271 {
1272 clear_x = start_pixpos;
1273 clear_width = xpos + width - start_pixpos;
1274 }
1275 else
1276 {
1277 clear_x = xpos;
1278 clear_width = width;
1279 }
1280
1281 x_clear_region (window, findex, clear_x, clear_y,
1282 clear_width, clear_height);
1283 }
1284
1285 /* Output the pixmap. */
1286 {
1287 Lisp_Object tmp_pixel;
1288 XColor tmp_bcolor, tmp_fcolor;
1289
1290 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1291 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1292 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1293 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1294
1295 x_output_x_pixmap (f, p, xpos - xoffset, dl->ypos - dl->ascent, clip_x,
1296 clip_y, clip_width, clip_height,
1297 pwidth, pheight, pixmap_offset,
1298 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1299 }
1300
1301 /* Draw a cursor over top of the pixmap. */
1302 if (cursor_width && cursor_height && (cursor_start >= xpos)
1303 && !NILP (w->text_cursor_visible_p)
1304 && (cursor_start < xpos + pwidth))
1305 {
1306 GC gc;
1307 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1308 int y = dl->ypos - dl->ascent;
1309 struct face_cachel *cursor_cachel =
1310 WINDOW_FACE_CACHEL (w,
1311 get_builtin_face_cache_index
1312 (w, Vtext_cursor_face));
1313
1314 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1315
1316 if (cursor_width > xpos + pwidth - cursor_start)
1317 cursor_width = xpos + pwidth - cursor_start;
1318
1319 if (focus)
1320 {
1321 XFillRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1322 cursor_height);
1323 }
1324 else
1325 {
1326 XDrawRectangle (dpy, x_win, gc, cursor_start, y, cursor_width,
1327 cursor_height);
1328 }
1329 }
1330 }
1331
1332 /*****************************************************************************
1333 x_output_vertical_divider
1334
1335 Draw a vertical divider down the left side of the given window.
1336 ****************************************************************************/
1337 static void
1338 x_output_vertical_divider (struct window *w, int clear)
1339 {
1340 struct frame *f = XFRAME (w->frame);
1341 struct device *d = XDEVICE (f->device);
1342
1343 Display *dpy = DEVICE_X_DISPLAY (d);
1344 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1345 GC gc;
1346
1347 /* We don't use the normal gutter measurements here because the
1348 horizontal scrollbars and toolbars do not stretch completely over
1349 to the right edge of the window. Only the modeline does. */
1350 int modeline_height = window_modeline_height (w);
1351 int x1, x2;
1352 int y1, y2;
1353
1354 #ifdef HAVE_SCROLLBARS
1355 if (f->scrollbar_on_left)
1356 #endif
1357 x1 = WINDOW_LEFT (w);
1358 #ifdef HAVE_SCROLLBARS
1359 else
1360 x1 = WINDOW_RIGHT (w) - X_DIVIDER_WIDTH;
1361 x2 = x1 + X_DIVIDER_SPACING;
1362 #endif
1363
1364 #ifdef HAVE_SCROLLBARS
1365 if (f->scrollbar_on_top)
1366 y1 = WINDOW_TOP (w);
1367 else
1368 #endif
1369 y1 = WINDOW_TEXT_TOP (w);
1370 y2 = WINDOW_BOTTOM (w) - modeline_height;
1371
1372 /* Draw the divider in the window. */
1373 {
1374 /* Clear the divider area first. This needs to be done when a
1375 window split occurs. */
1376 if (clear)
1377 XClearArea (dpy, x_win, x1, y1, X_DIVIDER_WIDTH, y2 - y1, False);
1378
1379 /* #### There needs to be some checks to make sure that whatever
1380 colors we choose, the line will be visible (not same color as
1381 default background.
1382
1383 #### No there don't. If I want the vertical divider to be
1384 invisible, I should be able to make it so. */
1385 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX),
1386 WINDOW_FACE_CACHEL_FOREGROUND (w, MODELINE_INDEX),
1387 Qnil, Qnil);
1388
1389 /* Draw the divider line. */
1390 XFillRectangle (dpy, x_win, gc, x2, y1, X_DIVIDER_LINE_WIDTH, y2 - y1);
1391 }
1392
1393 /* Draw the divider in the modeline but only if we are using 2D
1394 modelines. */
1395 if (EQ (Qzero, w->modeline_shadow_thickness))
1396 {
1397 XFillRectangle (dpy, x_win, gc, x1, y2, X_DIVIDER_WIDTH,
1398 modeline_height);
1399
1400 /* #### There needs to be some checks to make sure that whatever
1401 colors we choose, the line will be visible (not same color as
1402 default background. */
1403 gc = x_get_gc (d, Qnil,
1404 WINDOW_FACE_CACHEL_FOREGROUND (w, MODELINE_INDEX),
1405 WINDOW_FACE_CACHEL_BACKGROUND (w, MODELINE_INDEX),
1406 Qnil, Qnil);
1407
1408 /* Draw the divider line. */
1409 XFillRectangle (dpy, x_win, gc, x2, y2, X_DIVIDER_LINE_WIDTH,
1410 modeline_height);
1411 }
1412 }
1413
1414 /*****************************************************************************
1415 x_output_blank
1416
1417 Output a blank by clearing the area it covers in the foreground color
1418 of its face.
1419 ****************************************************************************/
1420 static void
1421 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1422 int start_pixpos, int cursor_start, int cursor_width)
1423 {
1424 struct frame *f = XFRAME (w->frame);
1425 struct device *d = XDEVICE (f->device);
1426
1427 Display *dpy = DEVICE_X_DISPLAY (d);
1428 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1429 GC gc;
1430 struct face_cachel *cursor_cachel =
1431 WINDOW_FACE_CACHEL (w,
1432 get_builtin_face_cache_index
1433 (w, Vtext_cursor_face));
1434 Lisp_Object bg_pmap;
1435 Lisp_Object buffer = WINDOW_BUFFER (w);
1436 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1437 buffer);
1438
1439 int x = rb->xpos;
1440 int y = dl->ypos - dl->ascent;
1441 int width = rb->width;
1442 int height = dl->ascent + dl->descent - dl->clip;
1443
1444 if (start_pixpos > x)
1445 {
1446 if (start_pixpos >= (x + width))
1447 return;
1448 else
1449 {
1450 width -= (start_pixpos - x);
1451 x = start_pixpos;
1452 }
1453 }
1454
1455 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1456 if (!IMAGE_INSTANCEP (bg_pmap)
1457 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1458 bg_pmap = Qnil;
1459
1460 if (NILP (bg_pmap))
1461 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1462 Qnil, Qnil, Qnil);
1463 else
1464 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1465 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1466 Qnil);
1467
1468 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1469
1470 /* If this rune is marked as having the cursor, then it is actually
1471 representing a tab. */
1472 if (!NILP (w->text_cursor_visible_p)
1473 && (rb->cursor_type == CURSOR_ON
1474 || (cursor_width
1475 && (cursor_start + cursor_width > x)
1476 && cursor_start < (x + width))))
1477 {
1478 int cursor_height, cursor_y;
1479 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1480 struct Lisp_Font_Instance *fi;
1481
1482 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1483 (WINDOW_FACE_CACHEL (w, rb->findex),
1484 Vcharset_ascii));
1485
1486 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1487
1488 cursor_y = dl->ypos - fi->ascent;
1489 cursor_height = fi->height;
1490 if (cursor_y + cursor_height > y + height)
1491 cursor_height = y + height - cursor_y;
1492
1493 if (focus)
1494 {
1495 if (NILP (bar_cursor_value))
1496 {
1497 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1498 fi->width, cursor_height);
1499 }
1500 else
1501 {
1502 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1503
1504 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1505 make_int (bar_width));
1506 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1507 cursor_y, cursor_start + bar_width - 1,
1508 cursor_y + cursor_height - 1);
1509 }
1510 }
1511 else if (NILP (bar_cursor_value))
1512 {
1513 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1514 fi->width - 1, cursor_height - 1);
1515 }
1516 }
1517 }
1518
1519 /*****************************************************************************
1520 x_output_hline
1521
1522 Output a horizontal line in the foreground of its face.
1523 ****************************************************************************/
1524 static void
1525 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1526 {
1527 struct frame *f = XFRAME (w->frame);
1528 struct device *d = XDEVICE (f->device);
1529
1530 Display *dpy = DEVICE_X_DISPLAY (d);
1531 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1532 GC gc;
1533
1534 int x = rb->xpos;
1535 int width = rb->width;
1536 int height = dl->ascent + dl->descent - dl->clip;
1537 int ypos1, ypos2, ypos3, ypos4;
1538
1539 ypos1 = dl->ypos - dl->ascent;
1540 ypos2 = ypos1 + rb->object.hline.yoffset;
1541 ypos3 = ypos2 + rb->object.hline.thickness;
1542 ypos4 = dl->ypos + dl->descent - dl->clip;
1543
1544 /* First clear the area not covered by the line. */
1545 if (height - rb->object.hline.thickness > 0)
1546 {
1547 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1548 Qnil, Qnil, Qnil);
1549
1550 if (ypos2 - ypos1 > 0)
1551 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1552 if (ypos4 - ypos3 > 0)
1553 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1554 }
1555
1556 /* Now draw the line. */
1557 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1558 Qnil, Qnil, Qnil);
1559
1560 if (ypos2 < ypos1)
1561 ypos2 = ypos1;
1562 if (ypos3 > ypos4)
1563 ypos3 = ypos4;
1564
1565 if (ypos3 - ypos2 > 0)
1566 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1567 }
1568
1569 /*****************************************************************************
1570 x_output_shadows
1571
1572 Draw a shadow around the given area using the given GC's. It is the
1573 callers responsibility to ste the GC's appropriately.
1574 ****************************************************************************/
1575 void
1576 x_output_shadows (struct frame *f, int x, int y, int width, int height,
1577 GC top_shadow_gc, GC bottom_shadow_gc, GC background_gc,
1578 int shadow_thickness)
1579 {
1580 struct device *d = XDEVICE (f->device);
1581
1582 Display *dpy = DEVICE_X_DISPLAY (d);
1583 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1584
1585 XSegment top_shadow[20], bottom_shadow[20];
1586 int elt;
1587
1588 if (shadow_thickness > 10)
1589 shadow_thickness = 10;
1590 else if (shadow_thickness < 0)
1591 shadow_thickness = 0;
1592 if (shadow_thickness > (width / 2))
1593 shadow_thickness = width / 2;
1594 if (shadow_thickness > (height / 2))
1595 shadow_thickness = height / 2;
1596
1597 for (elt = 0; elt < shadow_thickness; elt++)
1598 {
1599 int seg1 = elt;
1600 int seg2 = elt + shadow_thickness;
1601
1602 top_shadow[seg1].x1 = x;
1603 top_shadow[seg1].x2 = x + width - elt - 1;
1604 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt;
1605
1606 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt;
1607 top_shadow[seg2].y1 = y + shadow_thickness;
1608 top_shadow[seg2].y2 = y + height - elt - 1;
1609
1610 bottom_shadow[seg1].x1 = x + elt + 1;
1611 bottom_shadow[seg1].x2 = x + width - 1;
1612 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1;
1613
1614 bottom_shadow[seg2].x1 = bottom_shadow[seg2].x2 = x + width - elt - 1;
1615 bottom_shadow[seg2].y1 = y + elt + 1;
1616 bottom_shadow[seg2].y2 = y + height - shadow_thickness;
1617 }
1618
1619 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow, shadow_thickness * 2);
1620 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow,
1621 shadow_thickness * 2);
1622 }
1623
1624 /*****************************************************************************
1625 x_generate_shadow_pixels
1626
1627 Given three pixels (top shadow, bottom shadow, background) massage
1628 the top and bottom shadow colors to guarantee that they differ. The
1629 background pixels are not allowed to be modified.
1630
1631 This function modifies its parameters.
1632
1633 This code is modified from code blatantly stolen from lwlib/xlwmenu.c
1634 ****************************************************************************/
1635 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
1636 ? ((unsigned long) (x)) : ((unsigned long) (y)))
1637
1638 void
1639 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow,
1640 unsigned long *bottom_shadow,
1641 unsigned long background,
1642 unsigned long core_background)
1643 {
1644 struct device *d = XDEVICE (f->device);
1645 Display *dpy = DEVICE_X_DISPLAY (d);
1646 Colormap cmap =
1647 DefaultColormapOfScreen (XtScreen ((Widget) FRAME_X_TEXT_WIDGET (f)));
1648
1649 XColor topc, botc;
1650 int top_frobbed = 0, bottom_frobbed = 0;
1651
1652 /* If the top shadow is the same color as the background, try and
1653 adjust it. */
1654 if (*top_shadow == background)
1655 {
1656 topc.pixel = background;
1657 XQueryColor (dpy, cmap, &topc);
1658 /* don't overflow/wrap! */
1659 topc.red = MINL (65535, topc.red * 1.2);
1660 topc.green = MINL (65535, topc.green * 1.2);
1661 topc.blue = MINL (65535, topc.blue * 1.2);
1662 if (allocate_nearest_color (dpy, cmap, &topc))
1663 {
1664 *top_shadow = topc.pixel;
1665 top_frobbed = 1;
1666 }
1667 }
1668
1669 /* If the bottom shadow is the same color as the background, try and
1670 adjust it. */
1671 if (*bottom_shadow == background)
1672 {
1673 botc.pixel = background;
1674 XQueryColor (dpy, cmap, &botc);
1675 botc.red *= 0.6;
1676 botc.green *= 0.6;
1677 botc.blue *= 0.6;
1678 if (allocate_nearest_color (dpy, cmap, &botc))
1679 {
1680 *bottom_shadow = botc.pixel;
1681 bottom_frobbed = 1;
1682 }
1683 }
1684
1685 /* If we had to adjust both shadows, then we have to do some
1686 additional work. */
1687 if (top_frobbed && bottom_frobbed)
1688 {
1689 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
1690 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
1691 if (bot_avg > top_avg)
1692 {
1693 Pixel tmp = *top_shadow;
1694
1695 *top_shadow = *bottom_shadow;
1696 *bottom_shadow = tmp;
1697 }
1698 else if (topc.pixel == botc.pixel)
1699 {
1700 if (botc.pixel == background)
1701 *top_shadow = core_background;
1702 else
1703 *bottom_shadow = background;
1704 }
1705 }
1706 }
1707
1708 /*****************************************************************************
1709 x_clear_to_window_end
1710
1711 Clear the area between ypos1 and ypos2. Each margin area and the
1712 text area is handled separately since they may each have their own
1713 background color.
1714 ****************************************************************************/
1715 static void
1716 x_clear_to_window_end (struct window *w, int ypos1, int ypos2)
1717 {
1718 int height = ypos2 - ypos1;
1719
1720 if (height)
1721 {
1722 struct frame *f = XFRAME (w->frame);
1723 Lisp_Object window;
1724 int bflag = (window_needs_vertical_divider (w) ? 0 : 1);
1725 layout_bounds bounds;
1726
1727 bounds = calculate_display_line_boundaries (w, bflag);
1728 XSETWINDOW (window, w);
1729
1730 if (window_is_leftmost (w))
1731 x_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f),
1732 ypos1, FRAME_BORDER_WIDTH (f), height);
1733
1734 if (bounds.left_in - bounds.left_out > 0)
1735 x_clear_region (window,
1736 get_builtin_face_cache_index (w, Vleft_margin_face),
1737 bounds.left_out, ypos1,
1738 bounds.left_in - bounds.left_out, height);
1739
1740 if (bounds.right_in - bounds.left_in > 0)
1741 x_clear_region (window, DEFAULT_INDEX, bounds.left_in, ypos1,
1742 bounds.right_in - bounds.left_in, height);
1743
1744 if (bounds.right_out - bounds.right_in > 0)
1745 x_clear_region (window,
1746 get_builtin_face_cache_index (w, Vright_margin_face),
1747 bounds.right_in, ypos1,
1748 bounds.right_out - bounds.right_in, height);
1749
1750 if (window_is_rightmost (w))
1751 x_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f),
1752 ypos1, FRAME_BORDER_WIDTH (f), height);
1753 }
1754 }
1755
1756 /*****************************************************************************
1757 x_redraw_exposed_window
1758
1759 Given a bounding box for an area that needs to be redrawn, determine
1760 what parts of what lines are contained within and re-output their
1761 contents.
1762 ****************************************************************************/
1763 static void
1764 x_redraw_exposed_window (struct window *w, int x, int y, int width, int height)
1765 {
1766 struct frame *f = XFRAME (w->frame);
1767 int line;
1768 int start_x, start_y, end_x, end_y;
1769 int orig_windows_structure_changed;
1770
1771 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1772
1773 if (!NILP (w->vchild))
1774 {
1775 x_redraw_exposed_windows (w->vchild, x, y, width, height);
1776 return;
1777 }
1778 else if (!NILP (w->hchild))
1779 {
1780 x_redraw_exposed_windows (w->hchild, x, y, width, height);
1781 return;
1782 }
1783
1784 /* If the window doesn't intersect the exposed region, we're done here. */
1785 if (x > WINDOW_RIGHT (w) || (x + width) < WINDOW_LEFT (w)
1786 || y > WINDOW_BOTTOM (w) || (y + height) < WINDOW_TOP (w))
1787 {
1788 return;
1789 }
1790 else
1791 {
1792 start_x = max (WINDOW_LEFT (w), x);
1793 end_x = min (WINDOW_RIGHT (w), (x + width));
1794 start_y = max (WINDOW_TOP (w), y);
1795 end_y = min (WINDOW_BOTTOM (w), y + height);
1796
1797 /* We do this to make sure that the 3D modelines get redrawn if
1798 they are in the exposed region. */
1799 orig_windows_structure_changed = f->windows_structure_changed;
1800 f->windows_structure_changed = 1;
1801 }
1802
1803 if (window_needs_vertical_divider (w))
1804 {
1805 x_output_vertical_divider (w, 0);
1806 }
1807
1808 for (line = 0; line < Dynarr_length (cdla); line++)
1809 {
1810 struct display_line *cdl = Dynarr_atp (cdla, line);
1811 int top_y = cdl->ypos - cdl->ascent;
1812 int bottom_y = cdl->ypos + cdl->descent;
1813
1814 if (bottom_y >= start_y)
1815 {
1816 if (top_y > end_y)
1817 {
1818 if (line == 0)
1819 continue;
1820 else
1821 break;
1822 }
1823 else
1824 {
1825 output_display_line (w, 0, cdla, line, start_x, end_x);
1826 }
1827 }
1828 }
1829
1830 f->windows_structure_changed = orig_windows_structure_changed;
1831
1832 /* If there have never been any face cache_elements created, then this
1833 expose event doesn't actually have anything to do. */
1834 if (Dynarr_largest (w->face_cachels))
1835 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y);
1836 }
1837
1838 /*****************************************************************************
1839 x_redraw_exposed_windows
1840
1841 For each window beneath the given window in the window hierarchy,
1842 ensure that it is redrawn if necessary after an Expose event.
1843 ****************************************************************************/
1844 static void
1845 x_redraw_exposed_windows (Lisp_Object window, int x, int y, int width,
1846 int height)
1847 {
1848 for (; !NILP (window); window = XWINDOW (window)->next)
1849 x_redraw_exposed_window (XWINDOW (window), x, y, width, height);
1850 }
1851
1852 /*****************************************************************************
1853 x_redraw_exposed_area
1854
1855 For each window on the given frame, ensure that any area in the
1856 Exposed area is redrawn.
1857 ****************************************************************************/
1858 void
1859 x_redraw_exposed_area (struct frame *f, int x, int y, int width, int height)
1860 {
1861 /* If any window on the frame has had its face cache reset then the
1862 redisplay structures are effectively invalid. If we attempt to
1863 use them we'll blow up. We mark the frame as changed to ensure
1864 that redisplay will do a full update. This probably isn't
1865 necessary but it can't hurt. */
1866
1867 #ifdef HAVE_TOOLBARS
1868 /* #### We would rather put these off as well but there is currently
1869 no combination of flags which will force an unchanged toolbar to
1870 redraw anyhow. */
1871 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height));
1872 #endif
1873
1874 if (!f->window_face_cache_reset)
1875 {
1876 x_redraw_exposed_windows (f->root_window, x, y, width, height);
1877
1878 XFlush (DEVICE_X_DISPLAY (XDEVICE (f->device)));
1879 }
1880 else
1881 MARK_FRAME_CHANGED (f);
1882 }
1883
1884 /****************************************************************************
1885 x_clear_region
1886
1887 Clear the area in the box defined by the given parameters using the
1888 given face.
1889 ****************************************************************************/
1890 static void
1891 x_clear_region (Lisp_Object locale, face_index findex, int x, int y,
1892 int width, int height)
1893 {
1894 struct window *w = 0;
1895 struct frame *f = 0;
1896 struct device *d;
1897 Lisp_Object background_pixmap;
1898
1899 Display *dpy;
1900 Window x_win;
1901
1902 if (WINDOWP (locale))
1903 {
1904 w = XWINDOW (locale);
1905 f = XFRAME (w->frame);
1906 }
1907 else if (FRAMEP (locale))
1908 {
1909 w = 0;
1910 f = XFRAME (locale);
1911 }
1912 else
1913 abort ();
1914
1915 d = XDEVICE (f->device);
1916 dpy = DEVICE_X_DISPLAY (d);
1917 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1918
1919 /* #### This function is going to have to be made cursor aware. */
1920 if (width && height)
1921 {
1922 int values_set = 0;
1923 GC gc;
1924
1925 /* #### This isn't quite right for when this function is called
1926 from the toolbar code. */
1927 background_pixmap = Qunbound;
1928
1929 /* Don't use a backing pixmap in the border area */
1930 if (x >= FRAME_LEFT_BORDER_END (f)
1931 && x < FRAME_RIGHT_BORDER_START (f)
1932 && y >= FRAME_TOP_BORDER_END (f)
1933 && y < FRAME_BOTTOM_BORDER_START (f))
1934 {
1935 Lisp_Object temp;
1936
1937 if (w)
1938 {
1939 temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, findex);
1940
1941 if (IMAGE_INSTANCEP (temp)
1942 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1943 {
1944 /* #### maybe we could implement such that a string
1945 can be a background pixmap? */
1946 background_pixmap = temp;
1947 }
1948 }
1949 else
1950 {
1951 temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale);
1952
1953 if (IMAGE_INSTANCEP (temp)
1954 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp)))
1955 {
1956 background_pixmap = temp;
1957 }
1958 }
1959
1960 if (!UNBOUNDP (background_pixmap) &&
1961 XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0)
1962 {
1963 Lisp_Object fcolor, bcolor;
1964
1965 if (w)
1966 {
1967 fcolor = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1968 bcolor = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1969 }
1970 else
1971 {
1972 fcolor = FACE_FOREGROUND (Vdefault_face, locale);
1973 bcolor = FACE_BACKGROUND (Vdefault_face, locale);
1974 }
1975
1976 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap,
1977 Qnil);
1978 values_set = 1;
1979 }
1980 else
1981 {
1982 Lisp_Object color;
1983
1984 if (UNBOUNDP (background_pixmap))
1985 background_pixmap = Qnil;
1986
1987 if (w)
1988 color = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1989 else
1990 color = FACE_BACKGROUND (Vdefault_face, locale);
1991
1992 gc = x_get_gc (d, Qnil, color, Qnil, background_pixmap,
1993 Qnil);
1994 values_set = 1;
1995 }
1996 }
1997
1998 if (values_set)
1999 {
2000 XFillRectangle (dpy, x_win, gc, x, y, width, height);
2001 }
2002 else
2003 {
2004 XClearArea (dpy, x_win, x, y, width, height, False);
2005 }
2006 }
2007 }
2008
2009 /*****************************************************************************
2010 x_output_eol_cursor
2011
2012 Draw a cursor at the end of a line. The end-of-line cursor is
2013 narrower than the normal cursor.
2014 ****************************************************************************/
2015 static void
2016 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos)
2017 {
2018 struct frame *f = XFRAME (w->frame);
2019 struct device *d = XDEVICE (f->device);
2020
2021 Display *dpy = DEVICE_X_DISPLAY (d);
2022 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2023 GC gc;
2024 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
2025 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
2026
2027 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
2028 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
2029 WINDOW_BUFFER (w));
2030
2031 int x = xpos;
2032 int y = dl->ypos - dl->ascent;
2033 int width = EOL_CURSOR_WIDTH;
2034 int height = dl->ascent + dl->descent - dl->clip;
2035 int cursor_height, cursor_y;
2036 int defheight, defascent;
2037
2038 XClearArea (dpy, x_win, x, y, width, height, False);
2039
2040 if (NILP (w->text_cursor_visible_p))
2041 return;
2042
2043 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
2044
2045 {
2046 Lisp_Object window = Qnil;
2047
2048 XSETWINDOW (window, w);
2049 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
2050 }
2051
2052 cursor_y = dl->ypos - defascent;
2053 if (cursor_y < y)
2054 cursor_y = y;
2055 cursor_height = defheight;
2056 if (cursor_y + cursor_height > y + height)
2057 cursor_height = y + height - cursor_y;
2058
2059 if (focus)
2060 {
2061 if (NILP (bar_cursor_value))
2062 {
2063 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
2064 }
2065 else
2066 {
2067 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
2068
2069 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
2070 make_int (bar_width));
2071 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
2072 x + bar_width - 1, cursor_y + cursor_height - 1);
2073 }
2074 }
2075 else if (NILP (bar_cursor_value))
2076 {
2077 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
2078 cursor_height - 1);
2079 }
2080 }
2081
2082 static void
2083 x_clear_frame_window (Lisp_Object window)
2084 {
2085 struct window *w = XWINDOW (window);
2086
2087 if (!NILP (w->vchild))
2088 {
2089 x_clear_frame_windows (w->vchild);
2090 return;
2091 }
2092
2093 if (!NILP (w->hchild))
2094 {
2095 x_clear_frame_windows (w->hchild);
2096 return;
2097 }
2098
2099 x_clear_to_window_end (w, WINDOW_TEXT_TOP (w), WINDOW_TEXT_BOTTOM (w));
2100 }
2101
2102 static void
2103 x_clear_frame_windows (Lisp_Object window)
2104 {
2105 for (; !NILP (window); window = XWINDOW (window)->next)
2106 x_clear_frame_window (window);
2107 }
2108
2109 static void
2110 x_clear_frame (struct frame *f)
2111 {
2112 struct device *d = XDEVICE (f->device);
2113 Display *dpy = DEVICE_X_DISPLAY (d);
2114 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
2115 int x, y, width, height;
2116 Lisp_Object frame;
2117
2118 x = FRAME_LEFT_BORDER_START (f);
2119 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
2120 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f));
2121 /* #### This adjustment by 1 should be being done in the macros.
2122 There is some small differences between when the menubar is on
2123 and off that we still need to deal with. */
2124 y = FRAME_TOP_BORDER_START (f) - 1;
2125 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
2126 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f)) + 1;
2127
2128 XClearArea (dpy, x_win, x, y, width, height, False);
2129
2130 XSETFRAME (frame, f);
2131
2132 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
2133 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
2134 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
2135 {
2136 x_clear_frame_windows (f->root_window);
2137 }
2138
2139 XFlush (DEVICE_X_DISPLAY (d));
2140 }
2141
2142 /* briefly swap the foreground and background colors.
2143 */
2144
2145 static int
2146 x_flash (struct device *d)
2147 {
2148 Display *dpy;
2149 Window w;
2150 XGCValues gcv;
2151 GC gc;
2152 XColor tmp_fcolor, tmp_bcolor;
2153 Lisp_Object tmp_pixel, frame;
2154 struct frame *f = device_selected_frame (d);
2155 Widget shell = FRAME_X_SHELL_WIDGET (f);
2156 Dimension width, height;
2157
2158 XtVaGetValues (shell, XtNwidth, &width, XtNheight, &height, 0);
2159 XSETFRAME (frame, f);
2160
2161 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
2162 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2163 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
2164 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
2165
2166 dpy = XtDisplay (shell);
2167 w = XtWindow (FRAME_X_TEXT_WIDGET (f));
2168 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
2169 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
2170 gcv.function = GXxor;
2171 gcv.graphics_exposures = False;
2172 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
2173 (GCForeground | GCFunction | GCGraphicsExposures));
2174 XFillRectangle (dpy, w, gc, 0, 0, width, height);
2175 XSync (dpy, False);
2176
2177 #ifdef HAVE_POLL
2178 poll (0, 0, 100);
2179 #else /* !HAVE_POLL */
2180 {
2181 int usecs = 100000;
2182 struct timeval tv;
2183 tv.tv_sec = usecs / 1000000L;
2184 tv.tv_usec = usecs % 1000000L;
2185 /* I'm sure someone is going to complain about this... */
2186 (void) select (0, 0, 0, 0, &tv);
2187 }
2188 #endif /* !HAVE_POLL */
2189
2190 XFillRectangle (dpy, w, gc, 0, 0, width, height);
2191 XSync (dpy, False);
2192
2193 return 1;
2194 }
2195
2196 /* Make audible bell. */
2197
2198 static void
2199 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2200 {
2201 Display *display = DEVICE_X_DISPLAY (d);
2202
2203 if (volume < 0) volume = 0;
2204 else if (volume > 100) volume = 100;
2205 if (pitch < 0 && duration < 0)
2206 {
2207 XBell (display, (volume * 2) - 100);
2208 XFlush (display);
2209 }
2210 else
2211 {
2212 XKeyboardState state;
2213 XKeyboardControl ctl;
2214 XSync (display, 0);
2215 /* #### grab server? */
2216 XGetKeyboardControl (display, &state);
2217
2218 ctl.bell_pitch = (pitch >= 0 ? pitch : state.bell_pitch);
2219 ctl.bell_duration = (duration >= 0 ? duration : state.bell_duration);
2220 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2221
2222 XBell (display, (volume * 2) - 100);
2223
2224 ctl.bell_pitch = state.bell_pitch;
2225 ctl.bell_duration = state.bell_duration;
2226 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl);
2227
2228 /* #### ungrab server? */
2229 XSync (display, 0);
2230 }
2231 }
2232
2233
2234 /************************************************************************/
2235 /* initialization */
2236 /************************************************************************/
2237
2238 void
2239 console_type_create_redisplay_x (void)
2240 {
2241 /* redisplay methods */
2242 CONSOLE_HAS_METHOD (x, text_width);
2243 CONSOLE_HAS_METHOD (x, output_display_block);
2244 CONSOLE_HAS_METHOD (x, divider_width);
2245 CONSOLE_HAS_METHOD (x, divider_height);
2246 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2247 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2248 CONSOLE_HAS_METHOD (x, clear_to_window_end);
2249 CONSOLE_HAS_METHOD (x, clear_region);
2250 CONSOLE_HAS_METHOD (x, clear_frame);
2251 CONSOLE_HAS_METHOD (x, output_begin);
2252 CONSOLE_HAS_METHOD (x, output_end);
2253 CONSOLE_HAS_METHOD (x, flash);
2254 CONSOLE_HAS_METHOD (x, ring_bell);
2255 }