comparison src/redisplay-x.c @ 4882:eab9498ecc0e

merge most of rest of redisplay-x.c and redisplay-gtk.c into redisplay-xlike-inc.c -------------------- ChangeLog entries follow: -------------------- src/ChangeLog addition: 2010-01-18 Ben Wing <ben@xemacs.org> * redisplay-gtk.c: * redisplay-gtk.c (gtk_bevel_area): * redisplay-x.c: * redisplay-x.c (THIS_IS_X): * redisplay-xlike-inc.c: * redisplay-xlike-inc.c (XLIKE_text_width_single_run): * redisplay-xlike-inc.c (XLIKE_text_width): * redisplay-xlike-inc.c (XLIKE_output_display_block): * redisplay-xlike-inc.c (XLIKE_get_gc): * redisplay-xlike-inc.c (XLIKE_output_string): * redisplay-xlike-inc.c (XLIKE_OUTPUT_XLIKE_PIXMAP): * redisplay-xlike-inc.c (XLIKE_output_pixmap): * redisplay-xlike-inc.c (XLIKE_output_vertical_divider): * redisplay-xlike-inc.c (XLIKE_output_blank): * redisplay-xlike-inc.c (XLIKE_output_horizontal_line): * redisplay-xlike-inc.c (XLIKE_clear_region): * redisplay-xlike-inc.c (XLIKE_output_eol_cursor): * redisplay-xlike-inc.c (XLIKE_clear_frame_window): * redisplay-xlike-inc.c (XLIKE_clear_frame): * redisplay-xlike-inc.c (XLIKE_flash): * redisplay-xlike-inc.c (console_type_create_redisplay_XLIKE): Move lots more code into redisplay-xlike-inc.c. Use macros to isolate the code that differs among X vs. GTK, to reduce the need for ifdefs in the middle of the code. Now, redisplay-x.c and redisplay-gtk.c only contain a few functions whose implementation is completely different from one to the other, or which are not present at all in one of them. GTK code not currently tested, but it has bitrotted somewhat any. Doing this will help keep it less bitrotty. * depend: Regenerate.
author Ben Wing <ben@xemacs.org>
date Mon, 18 Jan 2010 08:44:49 -0600
parents a4322ac49e37
children b3ce27ca7647
comparison
equal deleted inserted replaced
4881:a4322ac49e37 4882:eab9498ecc0e
25 25
26 /* Author: Chuck Thompson */ 26 /* Author: Chuck Thompson */
27 27
28 /* Lots of work done by Ben Wing for Mule */ 28 /* Lots of work done by Ben Wing for Mule */
29 29
30 #include <config.h>
31 #include "lisp.h"
32
33 #include "buffer.h"
34 #include "debug.h"
35 #include "device-impl.h"
36 #include "faces.h"
37 #include "file-coding.h"
38 #include "frame-impl.h"
39 #include "gutter.h"
40 #include "redisplay.h"
41 #include "sysdep.h"
42 #include "window.h"
43
44 #include "mule-ccl.h"
45 #include "charset.h"
46
47 #include "console-x-impl.h"
48 #include "glyphs-x.h"
49 #include "objects-x-impl.h"
50 #include "xgccache.h"
51
52 #include "EmacsFrame.h"
53 #include "EmacsFrameP.h"
54
55 #include "sysproc.h" /* for select() */
56
57 #include <X11/bitmaps/gray>
58 30
59 /* Number of pixels below each line. */ 31 /* Number of pixels below each line. */
60 int x_interline_space; /* #### this needs to be implemented, but per-font */ 32 int x_interline_space; /* #### this needs to be implemented, but per-font */
61 33
62 #define EOL_CURSOR_WIDTH 5 34 #define THIS_IS_X
63
64 static void x_output_vertical_divider (struct window *w, int clear);
65 static void x_output_blank (struct window *w, struct display_line *dl,
66 struct rune *rb, int start_pixpos,
67 int cursor_start, int cursor_width);
68 static void x_output_hline (struct window *w, struct display_line *dl,
69 struct rune *rb);
70 static void x_output_eol_cursor (struct window *w, struct display_line *dl,
71 int xpos, face_index findex);
72 static void x_clear_frame (struct frame *f);
73 static void x_clear_frame_windows (Lisp_Object window);
74
75 #ifdef USE_XFT
76 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
77 ? ((unsigned long) (x)) : ((unsigned long) (y)))
78 #endif /* USE_XFT */
79 35
80 #include "redisplay-xlike-inc.c" 36 #include "redisplay-xlike-inc.c"
81
82 /****************************************************************************/
83 /* */
84 /* X output routines */
85 /* */
86 /****************************************************************************/
87
88 static int
89 x_text_width_single_run (struct frame * USED_IF_XFT (f),
90 struct face_cachel *cachel, struct textual_run *run)
91 {
92 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset);
93 Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst);
94 if (!fi->proportional_p)
95 return fi->width * run->len;
96 #ifdef USE_XFT
97 else if (FONT_INSTANCE_X_XFTFONT(fi))
98 {
99 static XGlyphInfo glyphinfo;
100 struct device *d = XDEVICE (f->device);
101 Display *dpy = DEVICE_X_DISPLAY (d);
102
103 if (run->dimension == 2) {
104 XftTextExtents16 (dpy,
105 FONT_INSTANCE_X_XFTFONT(fi),
106 (XftChar16 *) run->ptr, run->len, &glyphinfo);
107 } else {
108 XftTextExtents8 (dpy,
109 FONT_INSTANCE_X_XFTFONT(fi),
110 run->ptr, run->len, &glyphinfo);
111 }
112
113 return glyphinfo.xOff;
114 }
115 #endif
116 else if (FONT_INSTANCE_X_FONT (fi))
117 {
118 if (run->dimension == 2)
119 return XTextWidth16 (FONT_INSTANCE_X_FONT (fi),
120 (XChar2b *) run->ptr, run->len);
121 else
122 return XTextWidth (FONT_INSTANCE_X_FONT (fi),
123 (char *) run->ptr, run->len);
124 }
125 else
126 abort();
127 return 0; /* shut up GCC */
128 }
129
130 /*
131 x_text_width
132
133 Given a string and a merged face, return the string's length in pixels
134 when displayed in the fonts associated with the face.
135 */
136
137 /* #### Break me out into a separate header */
138 int x_text_width (struct frame *f, struct face_cachel *cachel,
139 const Ichar *str, Charcount len);
140 int
141 x_text_width (struct frame *f, struct face_cachel *cachel,
142 const Ichar *str, Charcount len)
143 {
144 /* !!#### Needs review */
145 int width_so_far = 0;
146 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len);
147 struct textual_run *runs = alloca_array (struct textual_run, len);
148 int nruns;
149 int i;
150
151 nruns = separate_textual_runs (text_storage, runs, str, len,
152 cachel);
153
154 for (i = 0; i < nruns; i++)
155 width_so_far += x_text_width_single_run (f, cachel, runs + i);
156
157 return width_so_far;
158 }
159
160 /*****************************************************************************
161 x_divider_height
162
163 Return the height of the horizontal divider. This is a function because
164 divider_height is a device method.
165
166 #### If we add etched horizontal divider lines this will have to get
167 smarter.
168 ****************************************************************************/
169 static int
170 x_divider_height (void)
171 {
172 return 1;
173 }
174
175 /*****************************************************************************
176 x_eol_cursor_width
177
178 Return the width of the end-of-line cursor. This is a function
179 because eol_cursor_width is a device method.
180 ****************************************************************************/
181 static int
182 x_eol_cursor_width (void)
183 {
184 return EOL_CURSOR_WIDTH;
185 }
186 37
187 /***************************************************************************** 38 /*****************************************************************************
188 x_window_output_begin 39 x_window_output_begin
189 40
190 Perform any necessary initialization prior to an update. 41 Perform any necessary initialization prior to an update.
202 static void 53 static void
203 x_window_output_end (struct window *w) 54 x_window_output_end (struct window *w)
204 { 55 {
205 if (!(check_if_pending_expose_event (WINDOW_XDEVICE (w)))) 56 if (!(check_if_pending_expose_event (WINDOW_XDEVICE (w))))
206 XFlush (DEVICE_X_DISPLAY (WINDOW_XDEVICE (w))); 57 XFlush (DEVICE_X_DISPLAY (WINDOW_XDEVICE (w)));
207 }
208
209 /*****************************************************************************
210 x_output_display_block
211
212 Given a display line, a block number for that start line, output all
213 runes between start and end in the specified display block.
214 ****************************************************************************/
215 static void
216 x_output_display_block (struct window *w, struct display_line *dl, int block,
217 int start, int end, int start_pixpos, int cursor_start,
218 int cursor_width, int cursor_height)
219 {
220 #ifndef USE_XFT
221 struct frame *f = XFRAME (w->frame);
222 #endif
223 Ichar_dynarr *buf;
224 Lisp_Object window;
225
226 struct display_block *db = Dynarr_atp (dl->display_blocks, block);
227 rune_dynarr *rba = db->runes;
228 struct rune *rb;
229
230 int elt = start;
231 face_index findex;
232 int xpos, width = 0;
233 Lisp_Object charset = Qunbound; /* Qnil is a valid charset when
234 MULE is not defined */
235
236 window = wrap_window (w);
237 rb = Dynarr_atp (rba, start);
238
239 if (!rb)
240 /* Nothing to do so don't do anything. */
241 return;
242
243 findex = rb->findex;
244 xpos = rb->xpos;
245 if (rb->type == RUNE_CHAR)
246 charset = ichar_charset (rb->object.chr.ch);
247
248 if (end < 0)
249 end = Dynarr_length (rba);
250 buf = Dynarr_new (Ichar);
251
252 while (elt < end)
253 {
254 rb = Dynarr_atp (rba, elt);
255
256 if (rb->findex == findex && rb->type == RUNE_CHAR
257 && rb->object.chr.ch != '\n' && rb->cursor_type != CURSOR_ON
258 && EQ (charset, ichar_charset (rb->object.chr.ch)))
259 {
260 Dynarr_add (buf, rb->object.chr.ch);
261 width += rb->width;
262 elt++;
263 }
264 else
265 {
266 if (Dynarr_length (buf))
267 {
268 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width,
269 findex, 0, cursor_start, cursor_width,
270 cursor_height);
271 xpos = rb->xpos;
272 width = 0;
273 }
274 Dynarr_reset (buf);
275 width = 0;
276
277 if (rb->type == RUNE_CHAR)
278 {
279 findex = rb->findex;
280 xpos = rb->xpos;
281 charset = ichar_charset (rb->object.chr.ch);
282
283 if (rb->cursor_type == CURSOR_ON)
284 {
285 if (rb->object.chr.ch == '\n')
286 {
287 x_output_eol_cursor (w, dl, xpos, findex);
288 }
289 else
290 {
291 Dynarr_add (buf, rb->object.chr.ch);
292 x_output_string (w, dl, buf, xpos, 0, start_pixpos,
293 rb->width, findex, 1,
294 cursor_start, cursor_width,
295 cursor_height);
296 Dynarr_reset (buf);
297 }
298
299 xpos += rb->width;
300 elt++;
301 }
302 else if (rb->object.chr.ch == '\n')
303 {
304 /* Clear in case a cursor was formerly here. */
305 redisplay_clear_region (window, findex, xpos,
306 DISPLAY_LINE_YPOS (dl),
307 rb->width,
308 DISPLAY_LINE_HEIGHT (dl));
309 elt++;
310 }
311 }
312 else if (rb->type == RUNE_BLANK || rb->type == RUNE_HLINE)
313 {
314 if (rb->type == RUNE_BLANK)
315 x_output_blank (w, dl, rb, start_pixpos, cursor_start,
316 cursor_width);
317 else
318 {
319 /* #### Our flagging of when we need to redraw the
320 modeline shadows sucks. Since RUNE_HLINE is only used
321 by the modeline at the moment it is a good bet
322 that if it gets redrawn then we should also
323 redraw the shadows. This won't be true forever.
324 We borrow the shadow_thickness_changed flag for
325 now. */
326 w->shadow_thickness_changed = 1;
327 x_output_hline (w, dl, rb);
328 }
329
330 elt++;
331 if (elt < end)
332 {
333 rb = Dynarr_atp (rba, elt);
334
335 findex = rb->findex;
336 xpos = rb->xpos;
337 }
338 }
339 else if (rb->type == RUNE_DGLYPH)
340 {
341 Lisp_Object instance;
342 struct display_box dbox;
343 struct display_glyph_area dga;
344
345 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset,
346 rb->object.dglyph.yoffset, start_pixpos,
347 rb->width, &dbox, &dga);
348
349 window = wrap_window (w);
350 instance = glyph_image_instance (rb->object.dglyph.glyph,
351 window, ERROR_ME_DEBUG_WARN, 1);
352 findex = rb->findex;
353
354 if (IMAGE_INSTANCEP (instance))
355 {
356 switch (XIMAGE_INSTANCE_TYPE (instance))
357 {
358 case IMAGE_MONO_PIXMAP:
359 case IMAGE_COLOR_PIXMAP:
360 redisplay_output_pixmap (w, instance, &dbox, &dga, findex,
361 cursor_start, cursor_width,
362 cursor_height, 0);
363 break;
364
365 case IMAGE_WIDGET:
366 if (EQ (XIMAGE_INSTANCE_WIDGET_TYPE (instance),
367 Qlayout))
368 {
369 redisplay_output_layout (window, instance, &dbox, &dga, findex,
370 cursor_start, cursor_width,
371 cursor_height);
372 break;
373 }
374 case IMAGE_SUBWINDOW:
375 redisplay_output_subwindow (w, instance, &dbox, &dga, findex,
376 cursor_start, cursor_width,
377 cursor_height);
378 break;
379
380 case IMAGE_NOTHING:
381 /* nothing is as nothing does */
382 break;
383
384 case IMAGE_TEXT:
385 case IMAGE_POINTER:
386 default:
387 ABORT ();
388 }
389 IMAGE_INSTANCE_OPTIMIZE_OUTPUT
390 (XIMAGE_INSTANCE (instance)) = 0;
391 }
392
393 xpos += rb->width;
394 elt++;
395 }
396 else
397 ABORT ();
398 }
399 }
400
401 if (Dynarr_length (buf))
402 x_output_string (w, dl, buf, xpos, 0, start_pixpos, width, findex,
403 0, cursor_start, cursor_width, cursor_height);
404
405 if (dl->modeline
406 && !EQ (Qzero, w->modeline_shadow_thickness)
407 #ifndef USE_XFT
408 /* This optimization doesn't work right with some Xft fonts, which
409 leave antialiasing turds at the boundary. I don't know if this
410 is an Xft bug or not, but I think it is. See x_output_string. */
411 && (f->clear
412 || f->windows_structure_changed
413 || w->shadow_thickness_changed)
414 #endif
415 )
416 bevel_modeline (w, dl);
417
418 Dynarr_free (buf);
419 } 58 }
420 59
421 /***************************************************************************** 60 /*****************************************************************************
422 x_bevel_area 61 x_bevel_area
423 62
542 background_gc, shadow_thickness, edges); 181 background_gc, shadow_thickness, edges);
543 } 182 }
544 } 183 }
545 184
546 /***************************************************************************** 185 /*****************************************************************************
547 x_get_gc
548
549 Given a number of parameters return a GC with those properties.
550 ****************************************************************************/
551 static GC
552 x_get_gc (struct device *d, Lisp_Object font, Lisp_Object fg, Lisp_Object bg,
553 Lisp_Object bg_pmap, Lisp_Object lwidth)
554 {
555 XGCValues gcv;
556 unsigned long mask;
557
558 memset (&gcv, ~0, sizeof (XGCValues));
559 gcv.graphics_exposures = False;
560 /* Make absolutely sure that we don't pick up a clipping region in
561 the GC returned by this function. */
562 gcv.clip_mask = None;
563 gcv.clip_x_origin = 0;
564 gcv.clip_y_origin = 0;
565 gcv.fill_style = FillSolid;
566 mask = GCGraphicsExposures | GCClipMask | GCClipXOrigin | GCClipYOrigin;
567 mask |= GCFillStyle;
568
569 if (!NILP (font)
570 #ifdef USE_XFT
571 /* Only set the font if it's a core font */
572 /* the renderfont will be set elsewhere (not part of gc) */
573 && !FONT_INSTANCE_X_XFTFONT (XFONT_INSTANCE (font))
574 #endif
575 )
576 {
577 gcv.font = FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font))->fid;
578 mask |= GCFont;
579 }
580
581 /* evil kludge! */
582 if (!NILP (fg) && !COLOR_INSTANCEP (fg) && !INTP (fg))
583 {
584 /* #### I fixed one case where this was getting hit. It was a
585 bad macro expansion (compiler bug). */
586 stderr_out ("Help! x_get_gc got a bogus fg value! fg = ");
587 debug_print (fg);
588 fg = Qnil;
589 }
590
591 if (!NILP (fg))
592 {
593 if (COLOR_INSTANCEP (fg))
594 gcv.foreground = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (fg)).pixel;
595 else
596 gcv.foreground = XINT (fg);
597 mask |= GCForeground;
598 }
599
600 if (!NILP (bg))
601 {
602 if (COLOR_INSTANCEP (bg))
603 gcv.background = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (bg)).pixel;
604 else
605 gcv.background = XINT (bg);
606 mask |= GCBackground;
607 }
608
609 /* This special case comes from a request to draw text with a face which has
610 the dim property. We'll use a stippled foreground GC. */
611 if (EQ (bg_pmap, Qdim))
612 {
613 assert (DEVICE_X_GRAY_PIXMAP (d) != None);
614
615 gcv.fill_style = FillStippled;
616 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d);
617 mask |= (GCFillStyle | GCStipple);
618 }
619 else if (IMAGE_INSTANCEP (bg_pmap)
620 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
621 {
622 if (XIMAGE_INSTANCE_PIXMAP_DEPTH (bg_pmap) == 0)
623 {
624 gcv.fill_style = FillOpaqueStippled;
625 gcv.stipple = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
626 mask |= (GCStipple | GCFillStyle);
627 }
628 else
629 {
630 gcv.fill_style = FillTiled;
631 gcv.tile = XIMAGE_INSTANCE_X_PIXMAP (bg_pmap);
632 mask |= (GCTile | GCFillStyle);
633 }
634 }
635
636 if (!NILP (lwidth))
637 {
638 gcv.line_width = XINT (lwidth);
639 mask |= GCLineWidth;
640 }
641
642 #if 0
643 debug_out ("\nx_get_gc: calling gc_cache_lookup\n");
644 #endif
645 return gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
646 }
647
648 /*****************************************************************************
649 x_output_string
650
651 Given a string and a starting position, output that string in the
652 given face. If cursor is true, draw a cursor around the string.
653 Correctly handles multiple charsets in the string.
654
655 The meaning of the parameters is something like this:
656
657 W Window that the text is to be displayed in.
658 DL Display line that this text is on. The values in the
659 structure are used to determine the vertical position and
660 clipping range of the text.
661 BUF Dynamic array of Ichars specifying what is actually to be
662 drawn.
663 XPOS X position in pixels where the text should start being drawn.
664 XOFFSET Number of pixels to be chopped off the left side of the
665 text. The effect is as if the text were shifted to the
666 left this many pixels and clipped at XPOS.
667 CLIP_START Clip everything left of this X position.
668 WIDTH Clip everything right of XPOS + WIDTH.
669 FINDEX Index for the face cache element describing how to display
670 the text.
671 CURSOR #### I don't understand this. There's something
672 strange and overcomplexified with this variable.
673 Chuck, explain please?
674 CURSOR_START Starting X position of cursor.
675 CURSOR_WIDTH Width of cursor in pixels.
676 CURSOR_HEIGHT Height of cursor in pixels.
677
678 Starting Y position of cursor is the top of the text line.
679 The cursor is drawn sometimes whether or not CURSOR is set. ???
680 ****************************************************************************/
681 void
682 x_output_string (struct window *w, struct display_line *dl,
683 Ichar_dynarr *buf, int xpos, int xoffset, int clip_start,
684 int width, face_index findex, int cursor,
685 int cursor_start, int cursor_width, int cursor_height)
686 {
687 /* General variables */
688 struct frame *f = XFRAME (w->frame);
689 struct device *d = XDEVICE (f->device);
690 Lisp_Object window = wrap_window (w);
691 Display *dpy = DEVICE_X_DISPLAY (d);
692 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
693
694 int clip_end;
695
696 /* Cursor-related variables */
697 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
698 int cursor_clip;
699 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
700 WINDOW_BUFFER (w));
701 struct face_cachel *cursor_cachel = 0;
702
703 /* Text-related variables */
704 Lisp_Object bg_pmap;
705 GC bgc, gc;
706 int height = DISPLAY_LINE_HEIGHT (dl);
707 int ypos = DISPLAY_LINE_YPOS (dl);
708 int len = Dynarr_length (buf);
709 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len);
710 struct textual_run *runs = alloca_array (struct textual_run, len);
711 int nruns;
712 int i;
713 struct face_cachel *cachel = WINDOW_FACE_CACHEL (w, findex);
714
715 int use_x_font = 1; /* #### bogus!!
716 The logic of this function needs review! */
717 #ifdef USE_XFT
718 Colormap cmap = DEVICE_X_COLORMAP (d);
719 Visual *visual = DEVICE_X_VISUAL (d);
720 static XftColor fg, bg;
721 XftDraw *xftDraw;
722
723 /* Lazily initialize frame's xftDraw member. */
724 if (!FRAME_X_XFTDRAW (f)) {
725 FRAME_X_XFTDRAW (f) = XftDrawCreate (dpy, x_win, visual, cmap);
726 }
727 xftDraw = FRAME_X_XFTDRAW (f);
728
729 /* #### This will probably cause asserts when passed a Lisp integer for a
730 color. See ca. line 759 this file.
731 #### Maybe xft_convert_color should take an XColor, not a pixel. */
732 #define XFT_FROB_LISP_COLOR(color, dim) \
733 xft_convert_color (dpy, cmap, visual, \
734 COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (color)).pixel, \
735 (dim))
736 #endif
737
738 if (width < 0)
739 width = x_text_width (f, cachel, Dynarr_atp (buf, 0), Dynarr_length (buf));
740
741 /* Regularize the variables passed in. */
742
743 if (clip_start < xpos)
744 clip_start = xpos;
745 clip_end = xpos + width;
746 if (clip_start >= clip_end)
747 /* It's all clipped out. */
748 return;
749
750 xpos -= xoffset;
751
752 /* make sure the area we are about to display is subwindow free. */
753 redisplay_unmap_subwindows_maybe (f, clip_start, ypos,
754 clip_end - clip_start, height);
755
756 cursor_clip = (cursor_start >= clip_start &&
757 cursor_start < clip_end);
758
759 /* This cursor code is really a mess. */
760 if (!NILP (w->text_cursor_visible_p)
761 && (cursor
762 || cursor_clip
763 || (cursor_width
764 && (cursor_start + cursor_width >= clip_start)
765 && !NILP (bar_cursor_value))))
766 {
767 /* These have to be in separate statements in order to avoid a
768 compiler bug. */
769 face_index sucks = get_builtin_face_cache_index (w, Vtext_cursor_face);
770 cursor_cachel = WINDOW_FACE_CACHEL (w, sucks);
771
772 /* We have to reset this since any call to WINDOW_FACE_CACHEL
773 may cause the cache to resize and any pointers to it to
774 become invalid. */
775 cachel = WINDOW_FACE_CACHEL (w, findex);
776 }
777
778 #ifdef HAVE_XIM
779 if (cursor && focus && (cursor_start == clip_start) && cursor_height)
780 XIM_SetSpotLocation (f, xpos - 2, dl->ypos + dl->descent - 2);
781 #endif /* HAVE_XIM */
782
783 bg_pmap = cachel->background_pixmap;
784 if (!IMAGE_INSTANCEP (bg_pmap)
785 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
786 bg_pmap = Qnil;
787
788 if ((cursor && focus && NILP (bar_cursor_value)
789 && !NILP (w->text_cursor_visible_p)) || NILP (bg_pmap))
790 bgc = 0;
791 else
792 {
793 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background,
794 bg_pmap, Qnil);
795 }
796
797 if (bgc)
798 {
799 XFillRectangle (dpy, x_win, bgc, clip_start,
800 ypos, clip_end - clip_start,
801 height);
802 }
803
804 nruns = separate_textual_runs (text_storage, runs, Dynarr_atp (buf, 0),
805 Dynarr_length (buf), cachel);
806
807 for (i = 0; i < nruns; i++)
808 {
809 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset);
810 Lisp_Font_Instance *fi = XFONT_INSTANCE (font);
811 int this_width;
812 int need_clipping;
813
814 if (EQ (font, Vthe_null_font_instance))
815 continue;
816
817 this_width = x_text_width_single_run (f, cachel, runs + i);
818 need_clipping = (dl->clip || clip_start > xpos ||
819 clip_end < xpos + this_width);
820
821 /* XDrawImageString only clears the area equal to the height of
822 the given font. It is possible that a font is being displayed
823 on a line taller than it is, so this would cause us to fail to
824 clear some areas. */
825 if ((int) fi->height < (int) (height + dl->clip + dl->top_clip))
826 {
827 int clear_start = max (xpos, clip_start);
828 int clear_end = min (xpos + this_width, clip_end);
829
830 if (cursor)
831 {
832 int ypos1_line, ypos1_string, ypos2_line, ypos2_string;
833
834 ypos1_string = dl->ypos - fi->ascent;
835 ypos2_string = dl->ypos + fi->descent;
836 ypos1_line = ypos;
837 ypos2_line = ypos1_line + height;
838
839 /* Make sure we don't clear below the real bottom of the
840 line. */
841 if (ypos1_string > ypos2_line)
842 ypos1_string = ypos2_line;
843 if (ypos2_string > ypos2_line)
844 ypos2_string = ypos2_line;
845
846 if (ypos1_line < ypos1_string)
847 {
848 redisplay_clear_region (window, findex, clear_start, ypos1_line,
849 clear_end - clear_start,
850 ypos1_string - ypos1_line);
851 }
852
853 if (ypos2_line > ypos2_string)
854 {
855 redisplay_clear_region (window, findex, clear_start, ypos2_string,
856 clear_end - clear_start,
857 ypos2_line - ypos2_string);
858 }
859 }
860 else
861 {
862 redisplay_clear_region (window, findex, clear_start,
863 ypos, clear_end - clear_start,
864 height);
865 }
866 }
867
868 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value))
869 {
870 #ifdef USE_XFT
871 fg = XFT_FROB_LISP_COLOR (cursor_cachel->foreground, 0);
872 bg = XFT_FROB_LISP_COLOR (cursor_cachel->background, 0);
873 #endif
874 gc = x_get_gc (d, font, cursor_cachel->foreground,
875 cursor_cachel->background, Qnil, Qnil);
876 }
877 else if (cachel->dim)
878 {
879 /* Ensure the gray bitmap exists */
880 if (DEVICE_X_GRAY_PIXMAP (d) == None)
881 DEVICE_X_GRAY_PIXMAP (d) =
882 XCreateBitmapFromData (dpy, x_win, (char *)gray_bits,
883 gray_width, gray_height);
884
885 /* Request a GC with the gray stipple pixmap to draw dimmed text */
886 #ifdef USE_XFT
887 fg = XFT_FROB_LISP_COLOR (cachel->foreground, 1);
888 bg = XFT_FROB_LISP_COLOR (cachel->background, 0);
889 #endif
890 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
891 Qdim, Qnil);
892 }
893 else
894 {
895 #ifdef USE_XFT
896 fg = XFT_FROB_LISP_COLOR (cachel->foreground, 0);
897 bg = XFT_FROB_LISP_COLOR (cachel->background, 0);
898 #endif
899 gc = x_get_gc (d, font, cachel->foreground, cachel->background,
900 Qnil, Qnil);
901 }
902 #ifdef USE_XFT
903 {
904 XftFont *rf = FONT_INSTANCE_X_XFTFONT (fi);
905
906 if (rf)
907 {
908 use_x_font = 0;
909 if (need_clipping)
910 {
911 Region clip_reg = XCreateRegion();
912 XRectangle clip_box = { clip_start, ypos,
913 clip_end - clip_start, height };
914
915 XUnionRectWithRegion (&clip_box, clip_reg, clip_reg);
916 XftDrawSetClip(xftDraw, clip_reg);
917 XDestroyRegion(clip_reg);
918 }
919
920 if (!bgc)
921 {
922 /* #### Neither rect_height nor XftTextExtents as computed
923 below handles the vertical space taken up by antialiasing,
924 which for some fonts (eg, Bitstream Vera Sans Mono-16 on
925 my Mac PowerBook G4) leaves behind orphaned dots on
926 insertion or deletion earlier in the line, especially in
927 the case of the underscore character.
928 Interestingly, insertion or deletion of a single character
929 immediately after a refresh does not leave any droppings,
930 but any further insertions or deletions do.
931 While adding a pixel to rect_height (mostly) takes care of
932 this, it trashes aggressively laid-out elements like the
933 modeline (overwriting part of the bevel).
934 OK, unconditionally redraw the bevel, and increment
935 rect_height by 1. See x_output_display_block. -- sjt */
936 struct textual_run *run = &runs[i];
937 int rect_width = x_text_width_single_run (f, cachel, run);
938 #ifndef USE_XFTTEXTENTS_TO_AVOID_FONT_DROPPINGS
939 int rect_height = FONT_INSTANCE_ASCENT(fi)
940 + FONT_INSTANCE_DESCENT(fi) + 1;
941 #else
942 int rect_height = FONT_INSTANCE_ASCENT(fi)
943 + FONT_INSTANCE_DESCENT(fi);
944 XGlyphInfo gi;
945 if (run->dimension == 2) {
946 XftTextExtents16 (dpy,
947 FONT_INSTANCE_X_XFTFONT(fi),
948 (XftChar16 *) run->ptr, run->len, &gi);
949 } else {
950 XftTextExtents8 (dpy,
951 FONT_INSTANCE_X_XFTFONT(fi),
952 run->ptr, run->len, &gi);
953 }
954 rect_height = rect_height > gi.height
955 ? rect_height : gi.height;
956 #endif
957
958 XftDrawRect (xftDraw, &bg,
959 xpos, ypos, rect_width, rect_height);
960 }
961
962 if (runs[i].dimension == 1)
963 XftDrawString8 (xftDraw, &fg, rf, xpos, dl->ypos,
964 runs[i].ptr, runs[i].len);
965 else
966 XftDrawString16 (xftDraw, &fg, rf, xpos, dl->ypos,
967 (XftChar16 *) runs[i].ptr, runs[i].len);
968 }
969 }
970 #endif
971 {
972 if (use_x_font)
973 {
974 if (need_clipping)
975 {
976 XRectangle clip_box[1];
977
978 clip_box[0].x = 0;
979 clip_box[0].y = 0;
980 clip_box[0].width = clip_end - clip_start;
981 clip_box[0].height = height;
982
983 XSetClipRectangles (dpy, gc, clip_start, ypos,
984 clip_box, 1, YXBanded);
985 }
986
987 if (runs[i].dimension == 1)
988 (bgc ? XDrawString : XDrawImageString)
989 (dpy, x_win, gc, xpos, dl->ypos,
990 (char *) runs[i].ptr, runs[i].len);
991 else
992 (bgc ? XDrawString16 : XDrawImageString16)
993 (dpy, x_win, gc, xpos, dl->ypos,
994 (XChar2b *) runs[i].ptr, runs[i].len);
995 }
996 }
997
998 /* We draw underlines in the same color as the text. */
999 if (cachel->underline)
1000 {
1001 int upos, uthick;
1002 unsigned long upos_ext, uthick_ext;
1003 XFontStruct *fs =
1004 use_x_font ? FONT_INSTANCE_X_FONT (XFONT_INSTANCE (font)) : 0;
1005 /* #### the logic of the next two may be suboptimal: we may want
1006 to use the POSITION and/or THICKNESS information with Xft */
1007 if (fs && XGetFontProperty (fs, XA_UNDERLINE_POSITION, &upos_ext))
1008 upos = (int) upos_ext;
1009 else
1010 upos = dl->descent / 2;
1011 if (fs && XGetFontProperty (fs, XA_UNDERLINE_THICKNESS, &uthick_ext))
1012 uthick = (int) uthick_ext;
1013 else
1014 uthick = 1;
1015 if (dl->ypos + upos < dl->ypos + dl->descent - dl->clip)
1016 {
1017 if (dl->ypos + upos + uthick > dl->ypos + dl->descent - dl->clip)
1018 uthick = dl->descent - dl->clip - upos;
1019
1020 if (uthick == 1)
1021 {
1022 XDrawLine (dpy, x_win, gc, xpos, dl->ypos + upos,
1023 xpos + this_width, dl->ypos + upos);
1024 }
1025 else if (uthick > 1)
1026 {
1027 XFillRectangle (dpy, x_win, gc, xpos,
1028 dl->ypos + upos, this_width, uthick);
1029 }
1030 }
1031 }
1032
1033 if (cachel->strikethru)
1034 {
1035 int ascent, descent, upos, uthick;
1036 unsigned long ascent_ext, descent_ext, uthick_ext;
1037 XFontStruct *fs = FONT_INSTANCE_X_FONT (fi);
1038
1039 if (!use_x_font)
1040 {
1041 ascent = dl->ascent;
1042 descent = dl->descent;
1043 uthick = 1;
1044 }
1045 else
1046 {
1047 if (!XGetFontProperty (fs, XA_STRIKEOUT_ASCENT, &ascent_ext))
1048 ascent = fs->ascent;
1049 else
1050 ascent = (int) ascent_ext;
1051 if (!XGetFontProperty (fs, XA_STRIKEOUT_DESCENT, &descent_ext))
1052 descent = fs->descent;
1053 else
1054 descent = (int) descent_ext;
1055 if (!XGetFontProperty (fs, XA_UNDERLINE_THICKNESS, &uthick_ext))
1056 uthick = 1;
1057 else
1058 uthick = (int) uthick_ext;
1059 }
1060
1061 upos = ascent - ((ascent + descent) / 2) + 1;
1062
1063 /* Generally, upos will be positive (above the baseline),so
1064 subtract */
1065 if (dl->ypos - upos < dl->ypos + dl->descent - dl->clip)
1066 {
1067 if (dl->ypos - upos + uthick > dl->ypos + dl->descent - dl->clip)
1068 uthick = dl->descent - dl->clip + upos;
1069
1070 if (uthick == 1)
1071 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos,
1072 xpos + this_width, dl->ypos - upos);
1073 else if (uthick > 1)
1074 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos,
1075 this_width, uthick);
1076 }
1077 }
1078
1079 /* Restore the GC */
1080 if (need_clipping)
1081 {
1082 #ifdef USE_XFT
1083 if (!use_x_font)
1084 {
1085 XftDrawSetClip(xftDraw, 0);
1086 }
1087 else
1088 {
1089 #endif
1090 XSetClipMask (dpy, gc, None);
1091 XSetClipOrigin (dpy, gc, 0, 0);
1092 #ifdef USE_XFT
1093 }
1094 #endif
1095 }
1096
1097 /* If we are actually superimposing the cursor then redraw with just
1098 the appropriate section highlighted. */
1099 if (cursor_clip && !cursor && focus && cursor_cachel)
1100 {
1101 #ifdef USE_XFT
1102 if (!use_x_font) /* Xft */
1103 {
1104 XftFont *rf = FONT_INSTANCE_X_XFTFONT (fi);
1105
1106 { /* set up clipping */
1107 Region clip_reg = XCreateRegion();
1108 XRectangle clip_box = { cursor_start, ypos,
1109 cursor_width, height };
1110
1111 XUnionRectWithRegion (&clip_box, clip_reg, clip_reg);
1112 XftDrawSetClip(xftDraw, clip_reg);
1113 XDestroyRegion(clip_reg);
1114 }
1115 { /* draw background rectangle & draw text */
1116 int rect_height = FONT_INSTANCE_ASCENT(fi)
1117 + FONT_INSTANCE_DESCENT(fi);
1118 int rect_width = x_text_width_single_run(f, cachel, &runs[i]);
1119 XftColor xft_color;
1120
1121 xft_color = XFT_FROB_LISP_COLOR (cursor_cachel->background, 0);
1122 XftDrawRect (xftDraw, &xft_color,
1123 xpos, ypos, rect_width, rect_height);
1124
1125 xft_color = XFT_FROB_LISP_COLOR (cursor_cachel->foreground, 0);
1126 if (runs[i].dimension == 1)
1127 XftDrawString8 (xftDraw, &xft_color, rf, xpos, dl->ypos,
1128 runs[i].ptr, runs[i].len);
1129 else
1130 XftDrawString16 (xftDraw, &xft_color, rf, xpos, dl->ypos,
1131 (XftChar16 *) runs[i].ptr, runs[i].len);
1132 }
1133
1134 XftDrawSetClip(xftDraw, 0);
1135 }
1136 else /* core font, not Xft */
1137 {
1138 #endif
1139 GC cgc;
1140 XRectangle clip_box[1];
1141
1142 cgc = x_get_gc (d, font, cursor_cachel->foreground,
1143 cursor_cachel->background, Qnil, Qnil);
1144
1145 clip_box[0].x = 0;
1146 clip_box[0].y = 0;
1147 clip_box[0].width = cursor_width;
1148 clip_box[0].height = height;
1149
1150 XSetClipRectangles (dpy, cgc, cursor_start, ypos,
1151 clip_box, 1, YXBanded);
1152 if (runs[i].dimension == 1)
1153 XDrawImageString (dpy, x_win, cgc, xpos, dl->ypos,
1154 (char *) runs[i].ptr, runs[i].len);
1155 else
1156 XDrawImageString16 (dpy, x_win, cgc, xpos, dl->ypos,
1157 (XChar2b *) runs[i].ptr, runs[i].len);
1158
1159 XSetClipMask (dpy, cgc, None);
1160 XSetClipOrigin (dpy, cgc, 0, 0);
1161 #ifdef USE_XFT
1162 }
1163 #endif
1164 }
1165
1166 xpos += this_width;
1167 }
1168
1169 /* Draw the non-focus box or bar-cursor as needed. */
1170 /* Can't this logic be simplified? */
1171 if (cursor_cachel
1172 && ((cursor && !focus && NILP (bar_cursor_value))
1173 || (cursor_width
1174 && (cursor_start + cursor_width >= clip_start)
1175 && !NILP (bar_cursor_value))))
1176 {
1177 int tmp_height, tmp_y;
1178 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1179 int need_clipping = (cursor_start < clip_start
1180 || clip_end < cursor_start + cursor_width);
1181
1182 /* #### This value is correct (as far as I know) because
1183 all of the times we need to draw this cursor, we will
1184 be called with exactly one character, so we know we
1185 can always use runs[0].
1186
1187 This is bogus as all hell, however. The cursor handling in
1188 this function is way bogus and desperately needs to be
1189 cleaned up. (In particular, the drawing of the cursor should
1190 really really be separated out of this function. This may be
1191 a bit tricky now because this function itself does way too
1192 much stuff, a lot of which needs to be moved into
1193 redisplay.c.) This is the only way to be able to easily add
1194 new cursor types or (e.g.) make the bar cursor be able to
1195 span two characters instead of overlaying just one. */
1196 int bogusly_obtained_ascent_value =
1197 XFONT_INSTANCE (FACE_CACHEL_FONT (cachel, runs[0].charset))->ascent;
1198
1199 if (!NILP (bar_cursor_value))
1200 {
1201 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1202 make_int (bar_width));
1203 }
1204 else
1205 {
1206 gc = x_get_gc (d, Qnil, cursor_cachel->background,
1207 Qnil, Qnil, Qnil);
1208 }
1209
1210 tmp_y = dl->ypos - bogusly_obtained_ascent_value;
1211 tmp_height = cursor_height;
1212 if (tmp_y + tmp_height > (int) (ypos + height))
1213 {
1214 tmp_y = ypos + height - tmp_height;
1215 if (tmp_y < (int) ypos)
1216 tmp_y = ypos;
1217 tmp_height = ypos + height - tmp_y;
1218 }
1219
1220 if (need_clipping)
1221 {
1222 XRectangle clip_box[1];
1223 clip_box[0].x = 0;
1224 clip_box[0].y = 0;
1225 clip_box[0].width = clip_end - clip_start;
1226 clip_box[0].height = tmp_height;
1227 XSetClipRectangles (dpy, gc, clip_start, tmp_y,
1228 /* #### why not Unsorted? */
1229 clip_box, 1, YXBanded);
1230 }
1231
1232 if (!focus && NILP (bar_cursor_value))
1233 {
1234 XDrawRectangle (dpy, x_win, gc, cursor_start, tmp_y,
1235 cursor_width - 1, tmp_height - 1);
1236 }
1237 else if (focus && !NILP (bar_cursor_value))
1238 {
1239 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1, tmp_y,
1240 cursor_start + bar_width - 1, tmp_y + tmp_height - 1);
1241 }
1242
1243 /* Restore the GC */
1244 if (need_clipping)
1245 {
1246 XSetClipMask (dpy, gc, None);
1247 XSetClipOrigin (dpy, gc, 0, 0);
1248 }
1249 }
1250
1251 #ifdef USE_XFT
1252 #undef XFT_FROB_LISP_COLOR
1253 #endif
1254
1255 }
1256
1257 void
1258 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x,
1259 int y, int xoffset, int yoffset,
1260 int width, int height, unsigned long fg, unsigned long bg,
1261 GC override_gc)
1262 {
1263 struct device *d = XDEVICE (f->device);
1264 Display *dpy = DEVICE_X_DISPLAY (d);
1265 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1266
1267 GC gc;
1268 XGCValues gcv;
1269 unsigned long pixmap_mask;
1270
1271 if (!override_gc)
1272 {
1273 memset (&gcv, ~0, sizeof (XGCValues));
1274 gcv.graphics_exposures = False;
1275 gcv.foreground = fg;
1276 gcv.background = bg;
1277 pixmap_mask = GCForeground | GCBackground | GCGraphicsExposures;
1278
1279 if (IMAGE_INSTANCE_X_MASK (p))
1280 {
1281 gcv.function = GXcopy;
1282 gcv.clip_mask = IMAGE_INSTANCE_X_MASK (p);
1283 gcv.clip_x_origin = x - xoffset;
1284 gcv.clip_y_origin = y - yoffset;
1285 pixmap_mask |= (GCFunction | GCClipMask | GCClipXOrigin |
1286 GCClipYOrigin);
1287 /* Can't set a clip rectangle because we already have a mask.
1288 Is it possible to get an equivalent effect by changing the
1289 args to XCopyArea below rather than messing with a clip box?
1290 - dkindred@cs.cmu.edu
1291 Yes. We don't clip at all now - andy@xemacs.org
1292 */
1293 }
1294
1295 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, pixmap_mask);
1296 }
1297 else
1298 {
1299 gc = override_gc;
1300 /* override_gc might have a mask already--we don't want to nuke it.
1301 Maybe we can insist that override_gc have no mask, or use
1302 one of the suggestions above. */
1303 }
1304
1305 /* depth of 0 means it's a bitmap, not a pixmap, and we should use
1306 XCopyPlane (1 = current foreground color, 0 = background) instead
1307 of XCopyArea, which means that the bits in the pixmap are actual
1308 pixel values, instead of symbolic of fg/bg. */
1309 if (IMAGE_INSTANCE_PIXMAP_DEPTH (p) > 0)
1310 {
1311 XCopyArea (dpy,
1312 IMAGE_INSTANCE_X_PIXMAP_SLICE
1313 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset,
1314 yoffset, width,
1315 height, x, y);
1316 }
1317 else
1318 {
1319 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE
1320 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc,
1321 xoffset, yoffset, width, height, x, y, 1L);
1322 }
1323 }
1324
1325 static void
1326 x_output_pixmap (struct window *w, Lisp_Object image_instance,
1327 struct display_box *db, struct display_glyph_area *dga,
1328 face_index findex, int cursor_start, int cursor_width,
1329 int cursor_height, int UNUSED (bg_pixmap))
1330 {
1331 struct frame *f = XFRAME (w->frame);
1332 struct device *d = XDEVICE (f->device);
1333 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance);
1334
1335 Display *dpy = DEVICE_X_DISPLAY (d);
1336 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1337
1338 /* Output the pixmap. */
1339 {
1340 Lisp_Object tmp_pixel;
1341 XColor tmp_bcolor, tmp_fcolor;
1342
1343 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex);
1344 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1345 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex);
1346 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1347
1348 x_output_x_pixmap (f, p, db->xpos, db->ypos,
1349 dga->xoffset, dga->yoffset,
1350 dga->width, dga->height,
1351 tmp_fcolor.pixel, tmp_bcolor.pixel, 0);
1352 }
1353
1354 /* Draw a cursor over top of the pixmap. */
1355 if (cursor_width && cursor_height && (cursor_start >= db->xpos)
1356 && !NILP (w->text_cursor_visible_p)
1357 && (cursor_start < db->xpos + dga->width))
1358 {
1359 GC gc;
1360 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1361 struct face_cachel *cursor_cachel =
1362 WINDOW_FACE_CACHEL (w,
1363 get_builtin_face_cache_index
1364 (w, Vtext_cursor_face));
1365
1366 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1367
1368 if (cursor_width > db->xpos + dga->width - cursor_start)
1369 cursor_width = db->xpos + dga->width - cursor_start;
1370
1371 if (focus)
1372 {
1373 XFillRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1374 cursor_height);
1375 }
1376 else
1377 {
1378 XDrawRectangle (dpy, x_win, gc, cursor_start, db->ypos, cursor_width,
1379 cursor_height);
1380 }
1381 }
1382 }
1383
1384 /*****************************************************************************
1385 x_output_vertical_divider
1386
1387 Draw a vertical divider down the right side of the given window.
1388 ****************************************************************************/
1389 static void
1390 x_output_vertical_divider (struct window *w, int clear)
1391 {
1392 struct frame *f = XFRAME (w->frame);
1393 struct device *d = XDEVICE (f->device);
1394
1395 Display *dpy = DEVICE_X_DISPLAY (d);
1396 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1397 Lisp_Object tmp_pixel;
1398 XColor tmp_color;
1399 XGCValues gcv;
1400 GC background_gc;
1401 enum edge_style style;
1402
1403 unsigned long mask;
1404 int x, y1, y2, width, shadow_thickness, spacing, line_width;
1405 face_index div_face =
1406 get_builtin_face_cache_index (w, Vvertical_divider_face);
1407
1408 width = window_divider_width (w);
1409 shadow_thickness = XINT (w->vertical_divider_shadow_thickness);
1410 spacing = XINT (w->vertical_divider_spacing);
1411 line_width = XINT (w->vertical_divider_line_width);
1412 x = WINDOW_RIGHT (w) - width;
1413 y1 = WINDOW_TOP (w);
1414 y2 = WINDOW_BOTTOM (w);
1415
1416 memset (&gcv, ~0, sizeof (XGCValues));
1417
1418 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, div_face);
1419 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1420
1421 /* First, get the GC's. */
1422 gcv.background = tmp_color.pixel;
1423 gcv.foreground = tmp_color.pixel;
1424 gcv.graphics_exposures = False;
1425 mask = GCForeground | GCBackground | GCGraphicsExposures;
1426 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask);
1427
1428 /* Clear the divider area first. This needs to be done when a
1429 window split occurs. */
1430 if (clear)
1431 XClearArea (dpy, x_win, x, y1, width, y2 - y1, False);
1432
1433 /* Draw the divider line. */
1434 XFillRectangle (dpy, x_win, background_gc,
1435 x + spacing + shadow_thickness, y1,
1436 line_width, y2 - y1);
1437
1438 if (shadow_thickness < 0)
1439 {
1440 shadow_thickness = -shadow_thickness;
1441 style = EDGE_BEVEL_IN;
1442 }
1443 else
1444 {
1445 style = EDGE_BEVEL_OUT;
1446 }
1447
1448 /* Draw the shadows around the divider line */
1449 x_bevel_area (w, div_face, x + spacing, y1,
1450 width - 2 * spacing, y2 - y1,
1451 shadow_thickness, EDGE_ALL, style);
1452 }
1453
1454 /*****************************************************************************
1455 x_output_blank
1456
1457 Output a blank by clearing the area it covers in the foreground color
1458 of its face.
1459 ****************************************************************************/
1460 static void
1461 x_output_blank (struct window *w, struct display_line *dl, struct rune *rb,
1462 int start_pixpos, int cursor_start, int cursor_width)
1463 {
1464 struct frame *f = XFRAME (w->frame);
1465 struct device *d = XDEVICE (f->device);
1466
1467 Display *dpy = DEVICE_X_DISPLAY (d);
1468 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1469 GC gc;
1470 struct face_cachel *cursor_cachel =
1471 WINDOW_FACE_CACHEL (w,
1472 get_builtin_face_cache_index
1473 (w, Vtext_cursor_face));
1474 Lisp_Object bg_pmap;
1475 Lisp_Object buffer = WINDOW_BUFFER (w);
1476 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1477 buffer);
1478
1479 int x = rb->xpos;
1480 int y = DISPLAY_LINE_YPOS (dl);
1481 int width = rb->width;
1482 int height = DISPLAY_LINE_HEIGHT (dl);
1483
1484 /* Unmap all subwindows in the area we are going to blank. */
1485 redisplay_unmap_subwindows_maybe (f, x, y, width, height);
1486
1487 if (start_pixpos > x)
1488 {
1489 if (start_pixpos >= (x + width))
1490 return;
1491 else
1492 {
1493 width -= (start_pixpos - x);
1494 x = start_pixpos;
1495 }
1496 }
1497
1498 bg_pmap = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, rb->findex);
1499 if (!IMAGE_INSTANCEP (bg_pmap)
1500 || !IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (bg_pmap)))
1501 bg_pmap = Qnil;
1502
1503 if (NILP (bg_pmap))
1504 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1505 Qnil, Qnil, Qnil);
1506 else
1507 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1508 WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex), bg_pmap,
1509 Qnil);
1510
1511 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1512
1513 /* If this rune is marked as having the cursor, then it is actually
1514 representing a tab. */
1515 if (!NILP (w->text_cursor_visible_p)
1516 && (rb->cursor_type == CURSOR_ON
1517 || (cursor_width
1518 && (cursor_start + cursor_width > x)
1519 && cursor_start < (x + width))))
1520 {
1521 int cursor_height, cursor_y;
1522 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1523 Lisp_Font_Instance *fi;
1524
1525 fi = XFONT_INSTANCE (FACE_CACHEL_FONT
1526 (WINDOW_FACE_CACHEL (w, rb->findex),
1527 Vcharset_ascii));
1528
1529 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1530
1531 cursor_y = dl->ypos - fi->ascent;
1532 cursor_height = fi->height;
1533 if (cursor_y + cursor_height > y + height)
1534 cursor_height = y + height - cursor_y;
1535
1536 if (focus)
1537 {
1538 if (NILP (bar_cursor_value))
1539 {
1540 XFillRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1541 fi->width, cursor_height);
1542 }
1543 else
1544 {
1545 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1546
1547 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1548 make_int (bar_width));
1549 XDrawLine (dpy, x_win, gc, cursor_start + bar_width - 1,
1550 cursor_y, cursor_start + bar_width - 1,
1551 cursor_y + cursor_height - 1);
1552 }
1553 }
1554 else if (NILP (bar_cursor_value))
1555 {
1556 XDrawRectangle (dpy, x_win, gc, cursor_start, cursor_y,
1557 fi->width - 1, cursor_height - 1);
1558 }
1559 }
1560 }
1561
1562 /*****************************************************************************
1563 x_output_hline
1564
1565 Output a horizontal line in the foreground of its face.
1566 ****************************************************************************/
1567 static void
1568 x_output_hline (struct window *w, struct display_line *dl, struct rune *rb)
1569 {
1570 struct frame *f = XFRAME (w->frame);
1571 struct device *d = XDEVICE (f->device);
1572
1573 Display *dpy = DEVICE_X_DISPLAY (d);
1574 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1575 GC gc;
1576
1577 int x = rb->xpos;
1578 int width = rb->width;
1579 int height = DISPLAY_LINE_HEIGHT (dl);
1580 int ypos1, ypos2, ypos3, ypos4;
1581
1582 ypos1 = DISPLAY_LINE_YPOS (dl);
1583 ypos2 = ypos1 + rb->object.hline.yoffset;
1584 ypos3 = ypos2 + rb->object.hline.thickness;
1585 ypos4 = dl->ypos + dl->descent - dl->clip;
1586
1587 /* First clear the area not covered by the line. */
1588 if (height - rb->object.hline.thickness > 0)
1589 {
1590 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_FOREGROUND (w, rb->findex),
1591 Qnil, Qnil, Qnil);
1592
1593 if (ypos2 - ypos1 > 0)
1594 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1595 if (ypos4 - ypos3 > 0)
1596 XFillRectangle (dpy, x_win, gc, x, ypos1, width, ypos2 - ypos1);
1597 }
1598
1599 /* Now draw the line. */
1600 gc = x_get_gc (d, Qnil, WINDOW_FACE_CACHEL_BACKGROUND (w, rb->findex),
1601 Qnil, Qnil, Qnil);
1602
1603 if (ypos2 < ypos1)
1604 ypos2 = ypos1;
1605 if (ypos3 > ypos4)
1606 ypos3 = ypos4;
1607
1608 if (ypos3 - ypos2 > 0)
1609 XFillRectangle (dpy, x_win, gc, x, ypos2, width, ypos3 - ypos2);
1610 }
1611
1612 /*****************************************************************************
1613 x_output_shadows 186 x_output_shadows
1614 187
1615 Draw a shadow around the given area using the given GC's. It is the 188 Draw a shadow around the given area using the given GC's. It is the
1616 callers responsibility to set the GC's appropriately. 189 callers responsibility to set the GC's appropriately.
1617 ****************************************************************************/ 190 ****************************************************************************/
1759 *bottom_shadow = background; 332 *bottom_shadow = background;
1760 } 333 }
1761 } 334 }
1762 } 335 }
1763 336
1764 /****************************************************************************
1765 x_clear_region
1766
1767 Clear the area in the box defined by the given parameters using the
1768 given face.
1769 ****************************************************************************/
1770 static void
1771 x_clear_region (Lisp_Object UNUSED (locale), struct device* d,
1772 struct frame* f, face_index UNUSED (findex),
1773 int x, int y,
1774 int width, int height, Lisp_Object fcolor, Lisp_Object bcolor,
1775 Lisp_Object background_pixmap)
1776 {
1777 Display *dpy;
1778 Window x_win;
1779 GC gc = NULL;
1780
1781 dpy = DEVICE_X_DISPLAY (d);
1782 x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1783
1784 if (!UNBOUNDP (background_pixmap))
1785 {
1786 gc = x_get_gc (d, Qnil, fcolor, bcolor, background_pixmap, Qnil);
1787 }
1788
1789 if (gc)
1790 XFillRectangle (dpy, x_win, gc, x, y, width, height);
1791 else
1792 XClearArea (dpy, x_win, x, y, width, height, False);
1793 }
1794
1795 /*****************************************************************************
1796 x_output_eol_cursor
1797
1798 Draw a cursor at the end of a line. The end-of-line cursor is
1799 narrower than the normal cursor.
1800 ****************************************************************************/
1801 static void
1802 x_output_eol_cursor (struct window *w, struct display_line *dl, int xpos,
1803 face_index findex)
1804 {
1805 struct frame *f = XFRAME (w->frame);
1806 struct device *d = XDEVICE (f->device);
1807 Lisp_Object window;
1808
1809 Display *dpy = DEVICE_X_DISPLAY (d);
1810 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1811 GC gc;
1812 face_index elt = get_builtin_face_cache_index (w, Vtext_cursor_face);
1813 struct face_cachel *cursor_cachel = WINDOW_FACE_CACHEL (w, elt);
1814
1815 int focus = EQ (w->frame, DEVICE_FRAME_WITH_FOCUS_REAL (d));
1816 Lisp_Object bar_cursor_value = symbol_value_in_buffer (Qbar_cursor,
1817 WINDOW_BUFFER (w));
1818
1819 int x = xpos;
1820 int y = DISPLAY_LINE_YPOS (dl);
1821 int width = EOL_CURSOR_WIDTH;
1822 int height = DISPLAY_LINE_HEIGHT (dl);
1823 int cursor_height, cursor_y;
1824 int defheight, defascent;
1825
1826 window = wrap_window (w);
1827 redisplay_clear_region (window, findex, x, y, width, height);
1828
1829 if (NILP (w->text_cursor_visible_p))
1830 return;
1831
1832 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil, Qnil);
1833
1834 default_face_font_info (window, &defascent, 0, &defheight, 0, 0);
1835
1836 /* make sure the cursor is entirely contained between y and y+height */
1837 cursor_height = min (defheight, height);
1838 cursor_y = max (y, min (y + height - cursor_height,
1839 dl->ypos - defascent));
1840
1841 if (focus)
1842 {
1843 #ifdef HAVE_XIM
1844 XIM_SetSpotLocation (f, x - 2 , cursor_y + cursor_height - 2);
1845 #endif /* HAVE_XIM */
1846
1847 if (NILP (bar_cursor_value))
1848 {
1849 XFillRectangle (dpy, x_win, gc, x, cursor_y, width, cursor_height);
1850 }
1851 else
1852 {
1853 int bar_width = EQ (bar_cursor_value, Qt) ? 1 : 2;
1854
1855 gc = x_get_gc (d, Qnil, cursor_cachel->background, Qnil, Qnil,
1856 make_int (bar_width));
1857 XDrawLine (dpy, x_win, gc, x + bar_width - 1, cursor_y,
1858 x + bar_width - 1, cursor_y + cursor_height - 1);
1859 }
1860 }
1861 else if (NILP (bar_cursor_value))
1862 {
1863 XDrawRectangle (dpy, x_win, gc, x, cursor_y, width - 1,
1864 cursor_height - 1);
1865 }
1866 }
1867
1868 static void
1869 x_clear_frame_window (Lisp_Object window)
1870 {
1871 struct window *w = XWINDOW (window);
1872
1873 if (!NILP (w->vchild))
1874 {
1875 x_clear_frame_windows (w->vchild);
1876 return;
1877 }
1878
1879 if (!NILP (w->hchild))
1880 {
1881 x_clear_frame_windows (w->hchild);
1882 return;
1883 }
1884
1885 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w),
1886 WINDOW_TEXT_BOTTOM (w));
1887 }
1888
1889 static void
1890 x_clear_frame_windows (Lisp_Object window)
1891 {
1892 for (; !NILP (window); window = XWINDOW (window)->next)
1893 x_clear_frame_window (window);
1894 }
1895
1896 static void
1897 x_clear_frame (struct frame *f)
1898 {
1899 struct device *d = XDEVICE (f->device);
1900 Display *dpy = DEVICE_X_DISPLAY (d);
1901 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1902 int x, y, width, height;
1903 Lisp_Object frame;
1904
1905 x = FRAME_LEFT_BORDER_START (f);
1906 width = (FRAME_PIXWIDTH (f) - FRAME_REAL_LEFT_TOOLBAR_WIDTH (f) -
1907 FRAME_REAL_RIGHT_TOOLBAR_WIDTH (f) -
1908 2 * FRAME_REAL_LEFT_TOOLBAR_BORDER_WIDTH (f) -
1909 2 * FRAME_REAL_RIGHT_TOOLBAR_BORDER_WIDTH (f));
1910 /* #### This adjustment by 1 should be being done in the macros.
1911 There is some small differences between when the menubar is on
1912 and off that we still need to deal with. */
1913 y = FRAME_TOP_BORDER_START (f) - 1;
1914 height = (FRAME_PIXHEIGHT (f) - FRAME_REAL_TOP_TOOLBAR_HEIGHT (f) -
1915 FRAME_REAL_BOTTOM_TOOLBAR_HEIGHT (f) -
1916 2 * FRAME_REAL_TOP_TOOLBAR_BORDER_WIDTH (f) -
1917 2 * FRAME_REAL_BOTTOM_TOOLBAR_BORDER_WIDTH (f)) + 1;
1918
1919 XClearArea (dpy, x_win, x, y, width, height, False);
1920
1921 frame = wrap_frame (f);
1922
1923 if (!UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vdefault_face, frame))
1924 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vleft_margin_face, frame))
1925 || !UNBOUNDP (FACE_BACKGROUND_PIXMAP (Vright_margin_face, frame)))
1926 {
1927 x_clear_frame_windows (f->root_window);
1928 }
1929
1930 if (!(check_if_pending_expose_event (d)))
1931 XFlush (DEVICE_X_DISPLAY (d));
1932 }
1933
1934 /* briefly swap the foreground and background colors.
1935 */
1936
1937 static int
1938 x_flash (struct device *d)
1939 {
1940 Display *dpy;
1941 Window win;
1942 XGCValues gcv;
1943 GC gc;
1944 XColor tmp_fcolor, tmp_bcolor;
1945 Lisp_Object tmp_pixel, frame;
1946 struct frame *f = device_selected_frame (d);
1947 struct window *w = XWINDOW (FRAME_ROOT_WINDOW (f));
1948 Widget shell = FRAME_X_SHELL_WIDGET (f);
1949 int flash_height;
1950
1951 frame = wrap_frame (f);
1952
1953 tmp_pixel = FACE_FOREGROUND (Vdefault_face, frame);
1954 tmp_fcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1955 tmp_pixel = FACE_BACKGROUND (Vdefault_face, frame);
1956 tmp_bcolor = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel));
1957
1958 dpy = XtDisplay (shell);
1959 win = XtWindow (FRAME_X_TEXT_WIDGET (f));
1960 memset (&gcv, ~0, sizeof (XGCValues)); /* initialize all slots to ~0 */
1961 gcv.foreground = (tmp_fcolor.pixel ^ tmp_bcolor.pixel);
1962 gcv.function = GXxor;
1963 gcv.graphics_exposures = False;
1964 gc = gc_cache_lookup (DEVICE_X_GC_CACHE (XDEVICE (f->device)), &gcv,
1965 (GCForeground | GCFunction | GCGraphicsExposures));
1966 default_face_height_and_width (frame, &flash_height, 0);
1967
1968 /* If window is tall, flash top and bottom line. */
1969 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
1970 {
1971 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
1972 w->pixel_width, flash_height);
1973 XFillRectangle (dpy, win, gc, w->pixel_left,
1974 w->pixel_top + w->pixel_height - flash_height,
1975 w->pixel_width, flash_height);
1976 }
1977 else
1978 /* If it is short, flash it all. */
1979 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
1980 w->pixel_width, w->pixel_height);
1981
1982 XSync (dpy, False);
1983
1984 #ifdef HAVE_SELECT
1985 {
1986 int usecs = 100000;
1987 struct timeval tv;
1988 tv.tv_sec = usecs / 1000000L;
1989 tv.tv_usec = usecs % 1000000L;
1990 /* I'm sure someone is going to complain about this... */
1991 select (0, 0, 0, 0, &tv);
1992 }
1993 #else
1994 #ifdef HAVE_POLL
1995 poll (0, 0, 100);
1996 #else /* !HAVE_POLL */
1997 bite me
1998 #endif /* HAVE_POLL */
1999 #endif /* HAVE_SELECT */
2000
2001 /* If window is tall, flash top and bottom line. */
2002 if (EQ (Vvisible_bell, Qtop_bottom) && w->pixel_height > 3 * flash_height)
2003 {
2004 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2005 w->pixel_width, flash_height);
2006 XFillRectangle (dpy, win, gc, w->pixel_left,
2007 w->pixel_top + w->pixel_height - flash_height,
2008 w->pixel_width, flash_height);
2009 }
2010 else
2011 /* If it is short, flash it all. */
2012 XFillRectangle (dpy, win, gc, w->pixel_left, w->pixel_top,
2013 w->pixel_width, w->pixel_height);
2014
2015 XSync (dpy, False);
2016
2017 return 1;
2018 }
2019 337
2020 /* Make audible bell. */ 338 /* Make audible bell. */
2021 339
2022 static void 340 static void
2023 x_ring_bell (struct device *d, int volume, int pitch, int duration) 341 x_ring_bell (struct device *d, int volume, int pitch, int duration)
2051 369
2052 /* #### ungrab server? */ 370 /* #### ungrab server? */
2053 XSync (display, 0); 371 XSync (display, 0);
2054 } 372 }
2055 } 373 }
2056
2057
2058 /************************************************************************/
2059 /* initialization */
2060 /************************************************************************/
2061
2062 void
2063 console_type_create_redisplay_x (void)
2064 {
2065 /* redisplay methods */
2066 CONSOLE_HAS_METHOD (x, text_width);
2067 CONSOLE_HAS_METHOD (x, output_display_block);
2068 CONSOLE_HAS_METHOD (x, divider_height);
2069 CONSOLE_HAS_METHOD (x, eol_cursor_width);
2070 CONSOLE_HAS_METHOD (x, output_vertical_divider);
2071 CONSOLE_HAS_METHOD (x, clear_region);
2072 CONSOLE_HAS_METHOD (x, clear_frame);
2073 CONSOLE_HAS_METHOD (x, window_output_begin);
2074 CONSOLE_HAS_METHOD (x, window_output_end);
2075 CONSOLE_HAS_METHOD (x, flash);
2076 CONSOLE_HAS_METHOD (x, ring_bell);
2077 CONSOLE_HAS_METHOD (x, bevel_area);
2078 CONSOLE_HAS_METHOD (x, output_string);
2079 CONSOLE_HAS_METHOD (x, output_pixmap);
2080 }