Mercurial > hg > xemacs-beta
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 } |