Mercurial > hg > xemacs-beta
annotate src/redisplay-x.c @ 4881:a4322ac49e37
break out common separate-into-runs routines into redisplay-xlike-inc.c
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-01-18 Ben Wing <ben@xemacs.org>
* redisplay-xlike-inc.c:
* redisplay-xlike-inc.c (separate_textual_runs_nomule):
* redisplay-xlike-inc.c (separate_textual_runs_xft_nomule):
* redisplay-xlike-inc.c (separate_textual_runs_xft_mule):
* redisplay-xlike-inc.c (separate_textual_runs_mule):
Break separate_textual_runs_* functions from redisplay-x.c.
(Code in redisplay-gtk.c should have been identical but was
bit-rotted.)
* redisplay-gtk.c:
* redisplay-x.c:
Delete code, replace with include statement.
* depend: Regenerate.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Mon, 18 Jan 2010 06:21:05 -0600 |
parents | 11daf37dae4d |
children | eab9498ecc0e |
rev | line source |
---|---|
428 | 1 /* X output and frame manipulation routines. |
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois. | |
3 Copyright (C) 1994 Lucid, Inc. | |
4 Copyright (C) 1995 Sun Microsystems, Inc. | |
1318 | 5 Copyright (C) 2002, 2003 Ben Wing. |
428 | 6 |
7 This file is part of XEmacs. | |
8 | |
9 XEmacs is free software; you can redistribute it and/or modify it | |
10 under the terms of the GNU General Public License as published by the | |
11 Free Software Foundation; either version 2, or (at your option) any | |
12 later version. | |
13 | |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with XEmacs; see the file COPYING. If not, write to | |
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
22 Boston, MA 02111-1307, USA. */ | |
23 | |
24 /* Synched up with: Not in FSF. */ | |
25 | |
26 /* Author: Chuck Thompson */ | |
27 | |
28 /* Lots of work done by Ben Wing for Mule */ | |
29 | |
30 #include <config.h> | |
31 #include "lisp.h" | |
32 | |
33 #include "buffer.h" | |
34 #include "debug.h" | |
872 | 35 #include "device-impl.h" |
428 | 36 #include "faces.h" |
800 | 37 #include "file-coding.h" |
872 | 38 #include "frame-impl.h" |
428 | 39 #include "gutter.h" |
40 #include "redisplay.h" | |
41 #include "sysdep.h" | |
42 #include "window.h" | |
800 | 43 |
44 #include "mule-ccl.h" | |
3659 | 45 #include "charset.h" |
800 | 46 |
872 | 47 #include "console-x-impl.h" |
800 | 48 #include "glyphs-x.h" |
872 | 49 #include "objects-x-impl.h" |
800 | 50 #include "xgccache.h" |
51 | |
52 #include "EmacsFrame.h" | |
53 #include "EmacsFrameP.h" | |
428 | 54 |
55 #include "sysproc.h" /* for select() */ | |
56 | |
800 | 57 #include <X11/bitmaps/gray> |
428 | 58 |
59 /* Number of pixels below each line. */ | |
3094 | 60 int x_interline_space; /* #### this needs to be implemented, but per-font */ |
428 | 61 |
62 #define EOL_CURSOR_WIDTH 5 | |
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 | |
3094 | 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 | |
4881
a4322ac49e37
break out common separate-into-runs routines into redisplay-xlike-inc.c
Ben Wing <ben@xemacs.org>
parents:
4827
diff
changeset
|
80 #include "redisplay-xlike-inc.c" |
428 | 81 |
82 /****************************************************************************/ | |
83 /* */ | |
84 /* X output routines */ | |
85 /* */ | |
86 /****************************************************************************/ | |
87 | |
88 static int | |
3094 | 89 x_text_width_single_run (struct frame * USED_IF_XFT (f), |
90 struct face_cachel *cachel, struct textual_run *run) | |
428 | 91 { |
92 Lisp_Object font_inst = FACE_CACHEL_FONT (cachel, run->charset); | |
440 | 93 Lisp_Font_Instance *fi = XFONT_INSTANCE (font_inst); |
428 | 94 if (!fi->proportional_p) |
95 return fi->width * run->len; | |
3094 | 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)) | |
428 | 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 } | |
3094 | 125 else |
126 abort(); | |
127 return 0; /* shut up GCC */ | |
428 | 128 } |
129 | |
130 /* | |
131 x_text_width | |
132 | |
3094 | 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. | |
428 | 135 */ |
136 | |
3094 | 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, | |
2286 | 142 const Ichar *str, Charcount len) |
428 | 143 { |
2367 | 144 /* !!#### Needs review */ |
428 | 145 int width_so_far = 0; |
851 | 146 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len); |
428 | 147 struct textual_run *runs = alloca_array (struct textual_run, len); |
148 int nruns; | |
149 int i; | |
150 | |
3659 | 151 nruns = separate_textual_runs (text_storage, runs, str, len, |
152 cachel); | |
428 | 153 |
154 for (i = 0; i < nruns; i++) | |
3094 | 155 width_so_far += x_text_width_single_run (f, cachel, runs + i); |
428 | 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 | |
187 /***************************************************************************** | |
442 | 188 x_window_output_begin |
428 | 189 |
190 Perform any necessary initialization prior to an update. | |
191 ****************************************************************************/ | |
192 static void | |
2286 | 193 x_window_output_begin (struct window *UNUSED (w)) |
428 | 194 { |
195 } | |
196 | |
197 /***************************************************************************** | |
442 | 198 x_window_output_end |
428 | 199 |
200 Perform any necessary flushing of queues when an update has completed. | |
201 ****************************************************************************/ | |
202 static void | |
442 | 203 x_window_output_end (struct window *w) |
428 | 204 { |
1204 | 205 if (!(check_if_pending_expose_event (WINDOW_XDEVICE (w)))) |
206 XFlush (DEVICE_X_DISPLAY (WINDOW_XDEVICE (w))); | |
428 | 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 { | |
3094 | 220 #ifndef USE_XFT |
428 | 221 struct frame *f = XFRAME (w->frame); |
3094 | 222 #endif |
3479 | 223 Ichar_dynarr *buf; |
428 | 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 | |
793 | 236 window = wrap_window (w); |
428 | 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) | |
867 | 246 charset = ichar_charset (rb->object.chr.ch); |
428 | 247 |
248 if (end < 0) | |
249 end = Dynarr_length (rba); | |
3479 | 250 buf = Dynarr_new (Ichar); |
428 | 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 | |
867 | 258 && EQ (charset, ichar_charset (rb->object.chr.ch))) |
428 | 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; | |
867 | 281 charset = ichar_charset (rb->object.chr.ch); |
428 | 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. */ | |
440 | 305 redisplay_clear_region (window, findex, xpos, |
428 | 306 DISPLAY_LINE_YPOS (dl), |
440 | 307 rb->width, |
428 | 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; | |
819 | 344 |
428 | 345 redisplay_calculate_display_boxes (dl, rb->xpos, rb->object.dglyph.xoffset, |
819 | 346 rb->object.dglyph.yoffset, start_pixpos, |
347 rb->width, &dbox, &dga); | |
428 | 348 |
793 | 349 window = wrap_window (w); |
428 | 350 instance = glyph_image_instance (rb->object.dglyph.glyph, |
793 | 351 window, ERROR_ME_DEBUG_WARN, 1); |
428 | 352 findex = rb->findex; |
353 | |
354 if (IMAGE_INSTANCEP (instance)) | |
442 | 355 { |
356 switch (XIMAGE_INSTANCE_TYPE (instance)) | |
428 | 357 { |
442 | 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; | |
428 | 364 |
442 | 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; | |
428 | 379 |
442 | 380 case IMAGE_NOTHING: |
381 /* nothing is as nothing does */ | |
382 break; | |
428 | 383 |
442 | 384 case IMAGE_TEXT: |
385 case IMAGE_POINTER: | |
386 default: | |
2500 | 387 ABORT (); |
442 | 388 } |
389 IMAGE_INSTANCE_OPTIMIZE_OUTPUT | |
390 (XIMAGE_INSTANCE (instance)) = 0; | |
391 } | |
428 | 392 |
393 xpos += rb->width; | |
394 elt++; | |
395 } | |
396 else | |
2500 | 397 ABORT (); |
428 | 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) | |
3094 | 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. */ | |
428 | 411 && (f->clear |
412 || f->windows_structure_changed | |
3094 | 413 || w->shadow_thickness_changed) |
414 #endif | |
415 ) | |
428 | 416 bevel_modeline (w, dl); |
417 | |
418 Dynarr_free (buf); | |
419 } | |
420 | |
421 /***************************************************************************** | |
422 x_bevel_area | |
423 | |
450 | 424 Draw shadows for the given area in the given face. |
428 | 425 ****************************************************************************/ |
426 static void | |
427 x_bevel_area (struct window *w, face_index findex, | |
428 int x, int y, int width, int height, | |
429 int shadow_thickness, int edges, enum edge_style style) | |
430 { | |
431 struct frame *f = XFRAME (w->frame); | |
432 struct device *d = XDEVICE (f->device); | |
433 | |
434 EmacsFrame ef = (EmacsFrame) FRAME_X_TEXT_WIDGET (f); | |
435 Display *dpy = DEVICE_X_DISPLAY (d); | |
436 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f)); | |
437 Pixel top_shadow_pixel, bottom_shadow_pixel, background_pixel; | |
438 Lisp_Object tmp_pixel; | |
439 XColor tmp_color; | |
440 XGCValues gcv; | |
441 GC top_shadow_gc, bottom_shadow_gc, background_gc; | |
442 | |
443 int use_pixmap = 0; | |
444 int flip_gcs = 0; | |
445 unsigned long mask; | |
446 | |
447 assert (shadow_thickness >=0); | |
448 memset (&gcv, ~0, sizeof (XGCValues)); | |
449 | |
450 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex); | |
451 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel)); | |
452 | |
453 /* First, get the GC's. */ | |
454 top_shadow_pixel = tmp_color.pixel; | |
455 bottom_shadow_pixel = tmp_color.pixel; | |
456 background_pixel = tmp_color.pixel; | |
457 | |
458 x_generate_shadow_pixels (f, &top_shadow_pixel, &bottom_shadow_pixel, | |
459 background_pixel, ef->core.background_pixel); | |
460 | |
461 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex); | |
462 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel)); | |
463 gcv.background = tmp_color.pixel; | |
464 gcv.graphics_exposures = False; | |
465 mask = GCForeground | GCBackground | GCGraphicsExposures; | |
466 | |
467 /* If we can't distinguish one of the shadows (the color is the same as the | |
468 background), it's better to use a pixmap to generate a dithered gray. */ | |
469 if (top_shadow_pixel == background_pixel || | |
470 bottom_shadow_pixel == background_pixel) | |
471 use_pixmap = 1; | |
472 | |
473 if (use_pixmap) | |
474 { | |
475 if (DEVICE_X_GRAY_PIXMAP (d) == None) | |
476 { | |
477 DEVICE_X_GRAY_PIXMAP (d) = | |
478 XCreatePixmapFromBitmapData (dpy, x_win, (char *) gray_bits, | |
479 gray_width, gray_height, 1, 0, 1); | |
480 } | |
481 | |
482 tmp_pixel = WINDOW_FACE_CACHEL_BACKGROUND (w, findex); | |
483 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel)); | |
484 gcv.foreground = tmp_color.pixel; | |
485 /* this is needed because the GC draws with a pixmap here */ | |
486 gcv.fill_style = FillOpaqueStippled; | |
487 gcv.stipple = DEVICE_X_GRAY_PIXMAP (d); | |
488 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, | |
489 (mask | GCStipple | GCFillStyle)); | |
490 | |
491 tmp_pixel = WINDOW_FACE_CACHEL_FOREGROUND (w, findex); | |
492 tmp_color = COLOR_INSTANCE_X_COLOR (XCOLOR_INSTANCE (tmp_pixel)); | |
493 bottom_shadow_pixel = tmp_color.pixel; | |
494 | |
495 flip_gcs = (bottom_shadow_pixel == | |
496 WhitePixelOfScreen (DefaultScreenOfDisplay (dpy))); | |
497 } | |
498 else | |
499 { | |
500 gcv.foreground = top_shadow_pixel; | |
501 top_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask); | |
502 } | |
503 | |
504 gcv.foreground = bottom_shadow_pixel; | |
505 bottom_shadow_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask); | |
506 | |
507 if (use_pixmap && flip_gcs) | |
508 { | |
509 GC tmp_gc = bottom_shadow_gc; | |
510 bottom_shadow_gc = top_shadow_gc; | |
511 top_shadow_gc = tmp_gc; | |
512 } | |
513 | |
514 gcv.foreground = background_pixel; | |
515 background_gc = gc_cache_lookup (DEVICE_X_GC_CACHE (d), &gcv, mask); | |
516 | |
517 /* possibly revert the GC's This will give a depressed look to the | |
518 divider */ | |
519 if (style == EDGE_ETCHED_IN || style == EDGE_BEVEL_IN) | |
520 { | |
521 GC temp; | |
522 | |
523 temp = top_shadow_gc; | |
524 top_shadow_gc = bottom_shadow_gc; | |
525 bottom_shadow_gc = temp; | |
526 } | |
527 | |
528 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT) | |
529 shadow_thickness /= 2; | |
530 | |
531 /* Draw the shadows around the divider line */ | |
532 x_output_shadows (f, x, y, width, height, | |
533 top_shadow_gc, bottom_shadow_gc, | |
534 background_gc, shadow_thickness, edges); | |
535 | |
536 if (style == EDGE_ETCHED_IN || style == EDGE_ETCHED_OUT) | |
537 { | |
538 /* Draw the shadows around the divider line */ | |
539 x_output_shadows (f, x + shadow_thickness, y + shadow_thickness, | |
540 width - 2*shadow_thickness, height - 2*shadow_thickness, | |
541 bottom_shadow_gc, top_shadow_gc, | |
542 background_gc, shadow_thickness, edges); | |
543 } | |
544 } | |
545 | |
546 /***************************************************************************** | |
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 | |
3094 | 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 ) | |
428 | 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 { | |
3094 | 584 /* #### I fixed one case where this was getting hit. It was a |
428 | 585 bad macro expansion (compiler bug). */ |
442 | 586 stderr_out ("Help! x_get_gc got a bogus fg value! fg = "); |
428 | 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 | |
3094 | 642 #if 0 |
643 debug_out ("\nx_get_gc: calling gc_cache_lookup\n"); | |
644 #endif | |
428 | 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. | |
867 | 661 BUF Dynamic array of Ichars specifying what is actually to be |
428 | 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, | |
867 | 683 Ichar_dynarr *buf, int xpos, int xoffset, int clip_start, |
428 | 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); | |
3094 | 690 Lisp_Object window = wrap_window (w); |
428 | 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; | |
3094 | 706 int height = DISPLAY_LINE_HEIGHT (dl); |
707 int ypos = DISPLAY_LINE_YPOS (dl); | |
428 | 708 int len = Dynarr_length (buf); |
851 | 709 unsigned char *text_storage = (unsigned char *) ALLOCA (2 * len); |
428 | 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 | |
3094 | 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 | |
428 | 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. */ | |
3094 | 753 redisplay_unmap_subwindows_maybe (f, clip_start, ypos, |
754 clip_end - clip_start, height); | |
428 | 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 | |
3094 | 792 { |
793 bgc = x_get_gc (d, Qnil, cachel->foreground, cachel->background, | |
794 bg_pmap, Qnil); | |
795 } | |
428 | 796 |
797 if (bgc) | |
3094 | 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), | |
3659 | 805 Dynarr_length (buf), cachel); |
428 | 806 |
807 for (i = 0; i < nruns; i++) | |
808 { | |
809 Lisp_Object font = FACE_CACHEL_FONT (cachel, runs[i].charset); | |
440 | 810 Lisp_Font_Instance *fi = XFONT_INSTANCE (font); |
428 | 811 int this_width; |
812 int need_clipping; | |
813 | |
814 if (EQ (font, Vthe_null_font_instance)) | |
815 continue; | |
816 | |
3094 | 817 this_width = x_text_width_single_run (f, cachel, runs + i); |
428 | 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; | |
3094 | 836 ypos1_line = ypos; |
837 ypos2_line = ypos1_line + height; | |
428 | 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, | |
3094 | 863 ypos, clear_end - clear_start, |
428 | 864 height); |
865 } | |
866 } | |
867 | |
868 if (cursor && cursor_cachel && focus && NILP (bar_cursor_value)) | |
3094 | 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 } | |
428 | 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 */ | |
3094 | 886 #ifdef USE_XFT |
887 fg = XFT_FROB_LISP_COLOR (cachel->foreground, 1); | |
888 bg = XFT_FROB_LISP_COLOR (cachel->background, 0); | |
889 #endif | |
428 | 890 gc = x_get_gc (d, font, cachel->foreground, cachel->background, |
891 Qdim, Qnil); | |
892 } | |
893 else | |
3094 | 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); | |
428 | 905 |
3094 | 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 }; | |
428 | 914 |
3094 | 915 XUnionRectWithRegion (&clip_box, clip_reg, clip_reg); |
916 XftDrawSetClip(xftDraw, clip_reg); | |
917 XDestroyRegion(clip_reg); | |
918 } | |
428 | 919 |
3094 | 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 | |
428 | 957 |
3094 | 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 } | |
428 | 997 |
998 /* We draw underlines in the same color as the text. */ | |
999 if (cachel->underline) | |
1000 { | |
647 | 1001 int upos, uthick; |
1002 unsigned long upos_ext, uthick_ext; | |
3094 | 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; | |
647 | 1009 else |
3094 | 1010 upos = dl->descent / 2; |
1011 if (fs && XGetFontProperty (fs, XA_UNDERLINE_THICKNESS, &uthick_ext)) | |
1012 uthick = (int) uthick_ext; | |
1013 else | |
428 | 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 | |
647 | 1033 if (cachel->strikethru) |
1034 { | |
1035 int ascent, descent, upos, uthick; | |
1036 unsigned long ascent_ext, descent_ext, uthick_ext; | |
3094 | 1037 XFontStruct *fs = FONT_INSTANCE_X_FONT (fi); |
647 | 1038 |
3094 | 1039 if (!use_x_font) |
1040 { | |
1041 ascent = dl->ascent; | |
1042 descent = dl->descent; | |
1043 uthick = 1; | |
1044 } | |
647 | 1045 else |
3094 | 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 } | |
428 | 1060 |
647 | 1061 upos = ascent - ((ascent + descent) / 2) + 1; |
428 | 1062 |
647 | 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) | |
428 | 1071 XDrawLine (dpy, x_win, gc, xpos, dl->ypos - upos, |
1072 xpos + this_width, dl->ypos - upos); | |
647 | 1073 else if (uthick > 1) |
428 | 1074 XFillRectangle (dpy, x_win, gc, xpos, dl->ypos + upos, |
1075 this_width, uthick); | |
647 | 1076 } |
1077 } | |
428 | 1078 |
1079 /* Restore the GC */ | |
1080 if (need_clipping) | |
1081 { | |
3094 | 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 | |
428 | 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 { | |
3094 | 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; | |
428 | 1120 |
3094 | 1121 xft_color = XFT_FROB_LISP_COLOR (cursor_cachel->background, 0); |
1122 XftDrawRect (xftDraw, &xft_color, | |
1123 xpos, ypos, rect_width, rect_height); | |
428 | 1124 |
3094 | 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); | |
428 | 1144 |
3094 | 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 | |
428 | 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 | |
3094 | 1189 cleaned up. (In particular, the drawing of the cursor should |
428 | 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 | |
3094 | 1193 redisplay.c.) This is the only way to be able to easily add |
428 | 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; | |
3094 | 1212 if (tmp_y + tmp_height > (int) (ypos + height)) |
428 | 1213 { |
3094 | 1214 tmp_y = ypos + height - tmp_height; |
1215 if (tmp_y < (int) ypos) | |
1216 tmp_y = ypos; | |
1217 tmp_height = ypos + height - tmp_y; | |
428 | 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, | |
3094 | 1228 /* #### why not Unsorted? */ |
1229 clip_box, 1, YXBanded); | |
428 | 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 } | |
3094 | 1250 |
1251 #ifdef USE_XFT | |
1252 #undef XFT_FROB_LISP_COLOR | |
1253 #endif | |
1254 | |
428 | 1255 } |
1256 | |
1257 void | |
440 | 1258 x_output_x_pixmap (struct frame *f, Lisp_Image_Instance *p, int x, |
428 | 1259 int y, int xoffset, int yoffset, |
440 | 1260 int width, int height, unsigned long fg, unsigned long bg, |
428 | 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 { | |
440 | 1311 XCopyArea (dpy, |
1312 IMAGE_INSTANCE_X_PIXMAP_SLICE | |
428 | 1313 (p, IMAGE_INSTANCE_PIXMAP_SLICE (p)), x_win, gc, xoffset, |
1314 yoffset, width, | |
1315 height, x, y); | |
1316 } | |
1317 else | |
1318 { | |
440 | 1319 XCopyPlane (dpy, IMAGE_INSTANCE_X_PIXMAP_SLICE |
428 | 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, | |
2286 | 1329 int cursor_height, int UNUSED (bg_pixmap)) |
428 | 1330 { |
1331 struct frame *f = XFRAME (w->frame); | |
1332 struct device *d = XDEVICE (f->device); | |
440 | 1333 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance); |
428 | 1334 |
1335 Display *dpy = DEVICE_X_DISPLAY (d); | |
1336 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f)); | |
440 | 1337 |
428 | 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; | |
647 | 1405 face_index div_face = |
1406 get_builtin_face_cache_index (w, Vvertical_divider_face); | |
428 | 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; | |
442 | 1413 y1 = WINDOW_TOP (w); |
1414 y2 = WINDOW_BOTTOM (w); | |
428 | 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)); | |
440 | 1523 Lisp_Font_Instance *fi; |
428 | 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 | |
1614 | |
1615 Draw a shadow around the given area using the given GC's. It is the | |
1616 callers responsibility to set the GC's appropriately. | |
1617 ****************************************************************************/ | |
1618 void | |
1619 x_output_shadows (struct frame *f, int x, int y, int width, int height, | |
2286 | 1620 GC top_shadow_gc, GC bottom_shadow_gc, |
1621 GC UNUSED (background_gc), int shadow_thickness, int edges) | |
428 | 1622 { |
1623 struct device *d = XDEVICE (f->device); | |
1624 | |
1625 Display *dpy = DEVICE_X_DISPLAY (d); | |
1626 Window x_win = XtWindow (FRAME_X_TEXT_WIDGET (f)); | |
1627 | |
1628 XSegment top_shadow[20], bottom_shadow[20]; | |
1629 int elt; | |
1630 | |
1631 if (shadow_thickness > 10) | |
1632 shadow_thickness = 10; | |
1633 else if (shadow_thickness < 0) | |
1634 shadow_thickness = 0; | |
1635 if (shadow_thickness > (width / 2)) | |
1636 shadow_thickness = width / 2; | |
1637 if (shadow_thickness > (height / 2)) | |
1638 shadow_thickness = height / 2; | |
1639 | |
1640 for (elt = 0; elt < shadow_thickness; elt++) | |
1641 { | |
1642 int seg1 = elt; | |
1643 int seg2 = (edges & EDGE_TOP) ? elt + shadow_thickness : elt; | |
1644 int bot_seg2 = (edges & EDGE_BOTTOM) ? elt + shadow_thickness : elt; | |
1645 | |
1646 if (edges & EDGE_TOP) | |
1647 { | |
1648 top_shadow[seg1].x1 = x + elt; | |
1649 top_shadow[seg1].x2 = x + width - elt - 1; | |
1650 top_shadow[seg1].y1 = top_shadow[seg1].y2 = y + elt; | |
1651 } | |
1652 if (edges & EDGE_LEFT) | |
1653 { | |
1654 top_shadow[seg2].x1 = top_shadow[seg2].x2 = x + elt; | |
1655 top_shadow[seg2].y1 = y + elt; | |
1656 top_shadow[seg2].y2 = y + height - elt - 1; | |
1657 } | |
1658 if (edges & EDGE_BOTTOM) | |
1659 { | |
1660 bottom_shadow[seg1].x1 = x + elt; | |
1661 bottom_shadow[seg1].x2 = x + width - elt - 1; | |
1662 bottom_shadow[seg1].y1 = bottom_shadow[seg1].y2 = y + height - elt - 1; | |
1663 } | |
1664 if (edges & EDGE_RIGHT) | |
1665 { | |
1666 bottom_shadow[bot_seg2].x1 = bottom_shadow[bot_seg2].x2 = x + width - elt - 1; | |
1667 bottom_shadow[bot_seg2].y1 = y + elt; | |
1668 bottom_shadow[bot_seg2].y2 = y + height - elt - 1; | |
1669 } | |
1670 } | |
1671 | |
1672 XDrawSegments (dpy, x_win, top_shadow_gc, top_shadow, | |
1673 ((edges & EDGE_TOP) ? shadow_thickness : 0) | |
1674 + ((edges & EDGE_LEFT) ? shadow_thickness : 0)); | |
1675 XDrawSegments (dpy, x_win, bottom_shadow_gc, bottom_shadow, | |
1676 ((edges & EDGE_BOTTOM) ? shadow_thickness : 0) | |
1677 + ((edges & EDGE_RIGHT) ? shadow_thickness : 0)); | |
1678 } | |
1679 | |
1680 /***************************************************************************** | |
1681 x_generate_shadow_pixels | |
1682 | |
1683 Given three pixels (top shadow, bottom shadow, background) massage | |
1684 the top and bottom shadow colors to guarantee that they differ. The | |
1685 background pixels are not allowed to be modified. | |
1686 | |
1687 This function modifies its parameters. | |
1688 | |
1689 This code is modified from code blatantly stolen from lwlib/xlwmenu.c | |
1690 ****************************************************************************/ | |
1691 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \ | |
1692 ? ((unsigned long) (x)) : ((unsigned long) (y))) | |
1693 | |
1694 void | |
1695 x_generate_shadow_pixels (struct frame *f, unsigned long *top_shadow, | |
1696 unsigned long *bottom_shadow, | |
1697 unsigned long background, | |
1698 unsigned long core_background) | |
1699 { | |
1700 struct device *d = XDEVICE (f->device); | |
1701 Display *dpy = DEVICE_X_DISPLAY (d); | |
1702 Colormap cmap = DEVICE_X_COLORMAP (d); | |
1703 Visual *visual = DEVICE_X_VISUAL (d); | |
1704 | |
1705 XColor topc, botc; | |
1706 int top_frobbed = 0, bottom_frobbed = 0; | |
1707 | |
1708 /* If the top shadow is the same color as the background, try to | |
1709 adjust it. */ | |
1710 if (*top_shadow == background) | |
1711 { | |
1712 topc.pixel = background; | |
1713 XQueryColor (dpy, cmap, &topc); | |
1714 /* don't overflow/wrap! */ | |
1715 topc.red = MINL (65535, (unsigned long) topc.red * 6 / 5); | |
1716 topc.green = MINL (65535, (unsigned long) topc.green * 6 / 5); | |
1717 topc.blue = MINL (65535, (unsigned long) topc.blue * 6 / 5); | |
3094 | 1718 if (x_allocate_nearest_color (dpy, cmap, visual, &topc)) |
428 | 1719 { |
1720 *top_shadow = topc.pixel; | |
1721 top_frobbed = 1; | |
1722 } | |
1723 } | |
1724 | |
1725 /* If the bottom shadow is the same color as the background, try to | |
1726 adjust it. */ | |
1727 if (*bottom_shadow == background) | |
1728 { | |
1729 botc.pixel = background; | |
1730 XQueryColor (dpy, cmap, &botc); | |
1731 botc.red = (unsigned short) ((unsigned long) botc.red * 3 / 5); | |
1732 botc.green = (unsigned short) ((unsigned long) botc.green * 3 / 5); | |
1733 botc.blue = (unsigned short) ((unsigned long) botc.blue * 3 / 5); | |
3094 | 1734 if (x_allocate_nearest_color (dpy, cmap, visual, &botc)) |
428 | 1735 { |
1736 *bottom_shadow = botc.pixel; | |
1737 bottom_frobbed = 1; | |
1738 } | |
1739 } | |
1740 | |
1741 /* If we had to adjust both shadows, then we have to do some | |
1742 additional work. */ | |
1743 if (top_frobbed && bottom_frobbed) | |
1744 { | |
1745 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3)); | |
1746 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3)); | |
1747 if (bot_avg > top_avg) | |
1748 { | |
1749 Pixel tmp = *top_shadow; | |
1750 | |
1751 *top_shadow = *bottom_shadow; | |
1752 *bottom_shadow = tmp; | |
1753 } | |
1754 else if (topc.pixel == botc.pixel) | |
1755 { | |
1756 if (botc.pixel == background) | |
1757 *top_shadow = core_background; | |
1758 else | |
1759 *bottom_shadow = background; | |
1760 } | |
1761 } | |
1762 } | |
1763 | |
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 | |
2286 | 1771 x_clear_region (Lisp_Object UNUSED (locale), struct device* d, |
1772 struct frame* f, face_index UNUSED (findex), | |
428 | 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 | |
793 | 1826 window = wrap_window (w); |
428 | 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 | |
440 | 1885 redisplay_clear_to_window_end (w, WINDOW_TEXT_TOP (w), |
428 | 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 | |
793 | 1921 frame = wrap_frame (f); |
428 | 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 | |
1204 | 1930 if (!(check_if_pending_expose_event (d))) |
1931 XFlush (DEVICE_X_DISPLAY (d)); | |
428 | 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); | |
442 | 1949 int flash_height; |
428 | 1950 |
793 | 1951 frame = wrap_frame (f); |
428 | 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)); | |
442 | 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 | |
428 | 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 | |
442 | 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 | |
428 | 2015 XSync (dpy, False); |
2016 | |
2017 return 1; | |
2018 } | |
2019 | |
2020 /* Make audible bell. */ | |
2021 | |
2022 static void | |
2023 x_ring_bell (struct device *d, int volume, int pitch, int duration) | |
2024 { | |
2025 Display *display = DEVICE_X_DISPLAY (d); | |
2026 | |
2027 if (volume < 0) volume = 0; | |
2028 else if (volume > 100) volume = 100; | |
2029 if (pitch < 0 && duration < 0) | |
2030 { | |
2031 XBell (display, (volume * 2) - 100); | |
2032 XFlush (display); | |
2033 } | |
2034 else | |
2035 { | |
2036 XKeyboardState state; | |
2037 XKeyboardControl ctl; | |
2038 XSync (display, 0); | |
2039 /* #### grab server? */ | |
2040 XGetKeyboardControl (display, &state); | |
2041 | |
664 | 2042 ctl.bell_pitch = (pitch >= 0 ? pitch : (int) state.bell_pitch); |
2043 ctl.bell_duration = (duration >= 0 ? duration : (int) state.bell_duration); | |
428 | 2044 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl); |
2045 | |
2046 XBell (display, (volume * 2) - 100); | |
2047 | |
2048 ctl.bell_pitch = state.bell_pitch; | |
2049 ctl.bell_duration = state.bell_duration; | |
2050 XChangeKeyboardControl (display, KBBellPitch|KBBellDuration, &ctl); | |
2051 | |
2052 /* #### ungrab server? */ | |
2053 XSync (display, 0); | |
2054 } | |
2055 } | |
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); | |
442 | 2073 CONSOLE_HAS_METHOD (x, window_output_begin); |
2074 CONSOLE_HAS_METHOD (x, window_output_end); | |
428 | 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 } |