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