Mercurial > hg > xemacs-beta
annotate src/redisplay-output.c @ 4844:91b3d00e717f
Various cleanups for Dynarr code, from Unicode-internal ws
dynarr.c: Add comment explaining Dynarr_largest() use.
dynarr.c: In Dynarr_insert_many(), don't call Dynarr_resize() unless we
actually need to resize, and note that an assert() that we are
inserting at or below the current end could be wrong if code
wants to access stuff between `len' and `largest'.
dynarr.c: Don't just Dynarr_resize() to the right size; instead use
Dynarr_reset() then Dynarr_add_many(), so that the 'len' and
'largest' and such get set properly.
dynarr.c, faces.c, gutter.c, lisp.h, lread.c, lrecord.h, redisplay-output.c, redisplay.c: Rename Dynarr member 'cur' to 'len' since it's the length of
the dynarr, not really a pointer to a "current insertion point".
Use type_checking_assert() instead of just assert() in some places.
Add additional assertions (Dynarr_verify*()) to check that we're
being given positions within range. Use them in Dynarr_at,
Dynarr_atp, etc. New Dynarr_atp_allow_end() for retrieving a
pointer to a position that might be the element past the last one.
New Dynarr_past_lastp() to retrieve a pointer to the position
past the last one, using Dynarr_atp_allow_end(). Change code
appropriately to use it.
Rename Dynarr_end() to Dynarr_lastp() (pointer to the last
element) for clarity, and change code appropriately to use it.
Change code appropriately to use Dynarr_begin().
Rewrite Dynarr_add_many(). New version can accept a NULL pointer
to mean "reserve space but don't put anything in it". Used by
stack_like_malloc().
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Wed, 13 Jan 2010 04:07:42 -0600 |
parents | 62d532188a28 |
children | 8b63e21b0436 |
rev | line source |
---|---|
428 | 1 /* Synchronize redisplay structures and output changes. |
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois. | |
1318 | 3 Copyright (C) 1995, 1996, 2002, 2003 Ben Wing. |
428 | 4 Copyright (C) 1996 Chuck Thompson. |
863 | 5 Copyright (C) 1999, 2002 Andy Piper. |
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 /* This file has been Mule-ized. */ | |
27 | |
28 /* Author: Chuck Thompson */ | |
29 | |
30 /* Heavily hacked for modularity, gutter and subwindow support by Andy | |
31 Piper. */ | |
32 | |
33 #include <config.h> | |
34 #include "lisp.h" | |
35 | |
36 #include "buffer.h" | |
37 #include "window.h" | |
872 | 38 #include "frame-impl.h" |
39 #include "device-impl.h" | |
428 | 40 #include "glyphs.h" |
41 #include "redisplay.h" | |
42 #include "faces.h" | |
446 | 43 #include "gutter.h" |
428 | 44 |
45 static int compare_runes (struct window *w, struct rune *crb, | |
46 struct rune *drb); | |
47 static void redraw_cursor_in_window (struct window *w, | |
48 int run_end_begin_glyphs); | |
49 static void redisplay_output_display_block (struct window *w, struct display_line *dl, | |
50 int block, int start, int end, int start_pixpos, | |
434 | 51 int cursor_start, int cursor_width, |
428 | 52 int cursor_height); |
434 | 53 static void redisplay_normalize_display_box (struct display_box* dest, |
428 | 54 struct display_glyph_area* src); |
55 static int redisplay_display_boxes_in_window_p (struct window* w, | |
56 struct display_box* db, | |
57 struct display_glyph_area* dga); | |
434 | 58 static void redisplay_clear_clipped_region (Lisp_Object locale, face_index findex, |
59 struct display_box* dest, | |
60 struct display_glyph_area* glyphsrc, | |
428 | 61 int fullheight_p, Lisp_Object); |
1318 | 62 static void redisplay_redraw_exposed_windows (Lisp_Object window, int x, |
63 int y, int width, int height); | |
428 | 64 |
65 /***************************************************************************** | |
66 sync_rune_structs | |
67 | |
68 Synchronize the given rune blocks. | |
69 ****************************************************************************/ | |
70 static void | |
2286 | 71 sync_rune_structs (struct window *UNUSED (w), rune_dynarr *cra, |
72 rune_dynarr *dra) | |
428 | 73 { |
74 int rune_elt; | |
75 int max_move = ((Dynarr_length (dra) > Dynarr_largest (cra)) | |
76 ? Dynarr_largest (cra) | |
77 : Dynarr_length (dra)); | |
78 | |
79 if (max_move) | |
80 { | |
81 /* #### Doing this directly breaks the encapsulation. But, the | |
4187 | 82 running time of this function has a measurable impact on |
83 redisplay performance so avoiding all excess overhead is a | |
84 good thing. Is all of this true? */ | |
428 | 85 memcpy (cra->base, dra->base, sizeof (struct rune) * max_move); |
86 Dynarr_set_size (cra, max_move); | |
87 } | |
88 else | |
89 Dynarr_reset (cra); | |
90 | |
91 for (rune_elt = max_move; rune_elt < Dynarr_length (dra); rune_elt++) | |
92 { | |
93 struct rune rb, *crb; | |
94 struct rune *drb = Dynarr_atp (dra, rune_elt); | |
95 | |
96 crb = &rb; | |
97 memcpy (crb, drb, sizeof (struct rune)); | |
98 Dynarr_add (cra, *crb); | |
99 } | |
100 } | |
101 | |
102 /***************************************************************************** | |
103 sync_display_line_structs | |
104 | |
105 For the given LINE in window W, make the current display line equal | |
106 the desired display line. | |
107 ****************************************************************************/ | |
442 | 108 void |
428 | 109 sync_display_line_structs (struct window *w, int line, int do_blocks, |
110 display_line_dynarr *cdla, | |
111 display_line_dynarr *ddla) | |
112 { | |
113 struct display_line dl, *clp, *dlp; | |
114 int db_elt; | |
800 | 115 int local = 0; |
428 | 116 |
4207 | 117 /* #### NOTE: practically, this is not needed because of the memcpy below. |
118 #### However, it's cleaner and bugs-in-the-future proof. -- dvl */ | |
119 DISPLAY_LINE_INIT (dl); | |
428 | 120 dlp = Dynarr_atp (ddla, line); |
121 if (line >= Dynarr_largest (cdla)) | |
122 { | |
123 clp = &dl; | |
124 clp->display_blocks = Dynarr_new (display_block); | |
800 | 125 local = 1; |
428 | 126 } |
127 else | |
128 { | |
129 clp = Dynarr_atp (cdla, line); | |
130 if (clp->display_blocks) | |
131 Dynarr_reset (clp->display_blocks); | |
132 if (clp->left_glyphs) | |
133 { | |
134 Dynarr_free (clp->left_glyphs); | |
135 clp->left_glyphs = 0; | |
136 } | |
137 if (clp->right_glyphs) | |
138 { | |
139 Dynarr_free (clp->right_glyphs); | |
140 clp->right_glyphs = 0; | |
141 } | |
142 } | |
143 { | |
144 display_block_dynarr *tdb = clp->display_blocks; | |
145 | |
146 memcpy (clp, dlp, sizeof (struct display_line)); | |
147 clp->display_blocks = tdb; | |
148 clp->left_glyphs = 0; | |
149 clp->right_glyphs = 0; | |
150 } | |
151 | |
800 | 152 if (do_blocks || line < Dynarr_length (cdla)) |
428 | 153 { |
800 | 154 for (db_elt = 0; db_elt < Dynarr_length (dlp->display_blocks); db_elt++) |
155 { | |
156 struct display_block db, *cdb; | |
157 struct display_block *ddb = Dynarr_atp (dlp->display_blocks, db_elt); | |
158 | |
159 if (db_elt >= Dynarr_largest (clp->display_blocks)) | |
160 { | |
161 cdb = &db; | |
162 memcpy (cdb, ddb, sizeof (struct display_block)); | |
163 cdb->runes = Dynarr_new (rune); | |
164 Dynarr_add (clp->display_blocks, *cdb); | |
165 } | |
166 else | |
167 { | |
168 rune_dynarr *tr; | |
169 | |
170 cdb = Dynarr_atp (clp->display_blocks, db_elt); | |
171 tr = cdb->runes; | |
172 memcpy (cdb, ddb, sizeof (struct display_block)); | |
173 cdb->runes = tr; | |
174 Dynarr_increment (clp->display_blocks); | |
175 } | |
176 | |
177 sync_rune_structs (w, cdb->runes, ddb->runes); | |
178 } | |
428 | 179 } |
180 | |
800 | 181 if (local) |
182 Dynarr_add (cdla, *clp); | |
183 else if (line >= Dynarr_length (cdla)) | |
428 | 184 { |
800 | 185 assert (line == Dynarr_length (cdla)); |
186 Dynarr_increment (cdla); | |
428 | 187 } |
188 } | |
189 | |
190 /***************************************************************************** | |
191 compare_runes | |
192 | |
448 | 193 Compare two runes to see if each of their fields is equal. If so, |
428 | 194 return true otherwise return false. |
195 ****************************************************************************/ | |
196 static int | |
197 compare_runes (struct window *w, struct rune *crb, struct rune *drb) | |
198 { | |
665 | 199 /* Do not compare the values of charbpos and endpos. They do not |
428 | 200 affect the display characteristics. */ |
201 | |
202 /* Note: (hanoi 6) spends 95% of its time in redisplay, and about | |
203 30% here. Not using bitfields for rune.type alone gives a redisplay | |
204 speed up of 10%. | |
205 | |
206 #### In profile arcs run of a normal Gnus session this function | |
207 is run 6.76 million times, only to return 1 in 6.73 million of | |
208 those. | |
209 | |
210 In addition a quick look GCC sparc assembly shows that GCC is not | |
211 doing a good job here. | |
212 1. The function is not inlined (too complicated?) | |
213 2. It seems to be reloading the crb and drb variables all the | |
214 time. | |
215 3. It doesn't seem to notice that the second half of these if's | |
216 are really a switch statement. | |
217 | |
218 So I (JV) conjecture | |
219 | |
220 #### It would really be worth it to arrange for this function to | |
221 be (almost) a single call to memcmp. */ | |
434 | 222 |
442 | 223 if (crb->xpos != drb->xpos) |
428 | 224 return 0; |
225 else if (crb->width != drb->width) | |
226 return 0; | |
227 else if (crb->cursor_type != drb->cursor_type) | |
228 return 0; | |
229 else if (crb->type != drb->type) | |
230 return 0; | |
231 else if (crb->type == RUNE_CHAR && | |
232 (crb->object.chr.ch != drb->object.chr.ch)) | |
233 return 0; | |
234 else if (crb->type == RUNE_HLINE && | |
235 (crb->object.hline.thickness != drb->object.hline.thickness || | |
236 crb->object.hline.yoffset != drb->object.hline.yoffset)) | |
237 return 0; | |
434 | 238 else if (crb->type == RUNE_DGLYPH && |
428 | 239 (!EQ (crb->object.dglyph.glyph, drb->object.dglyph.glyph) || |
240 !EQ (crb->object.dglyph.extent, drb->object.dglyph.extent) || | |
819 | 241 crb->object.dglyph.xoffset != drb->object.dglyph.xoffset || |
242 crb->object.dglyph.yoffset != drb->object.dglyph.yoffset || | |
4187 | 243 crb->object.dglyph.ascent != drb->object.dglyph.ascent || |
244 crb->object.dglyph.descent != drb->object.dglyph.descent)) | |
428 | 245 return 0; |
246 /* Only check dirtiness if we know something has changed. */ | |
247 else if (crb->type == RUNE_DGLYPH && | |
442 | 248 (XGLYPH_DIRTYP (crb->object.dglyph.glyph) || |
249 crb->findex != drb->findex)) | |
428 | 250 { |
442 | 251 /* We need some way of telling redisplay_output_layout () that the |
4187 | 252 only reason we are outputting it is because something has |
253 changed internally. That way we can optimize whether we need | |
254 to clear the layout first and also only output the components | |
255 that have changed. The image_instance dirty flag and | |
256 display_hash are no good to us because these will invariably | |
257 have been set anyway if the layout has changed. So it looks | |
258 like we need yet another change flag that we can set here and | |
259 then clear in redisplay_output_layout (). */ | |
442 | 260 Lisp_Object window, image; |
261 Lisp_Image_Instance* ii; | |
793 | 262 window = wrap_window (w); |
442 | 263 image = glyph_image_instance (crb->object.dglyph.glyph, |
793 | 264 window, ERROR_ME_DEBUG_WARN, 1); |
442 | 265 |
266 if (!IMAGE_INSTANCEP (image)) | |
267 return 0; | |
268 ii = XIMAGE_INSTANCE (image); | |
269 | |
270 if (TEXT_IMAGE_INSTANCEP (image) && | |
271 (crb->findex != drb->findex || | |
272 WINDOW_FACE_CACHEL_DIRTY (w, drb->findex))) | |
428 | 273 return 0; |
442 | 274 |
275 /* It is quite common for the two glyphs to be EQ since in many | |
276 cases they will actually be the same object. This does not | |
277 mean, however, that nothing has changed. We therefore need to | |
278 check the current hash of the glyph against the last recorded | |
279 display hash and the pending display items. See | |
280 update_subwindow (). */ | |
281 if (image_instance_changed (image) || | |
282 crb->findex != drb->findex || | |
283 WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)) | |
284 { | |
638 | 285 /* Now we are going to re-output the glyph, but since |
442 | 286 this is for some internal reason not related to geometry |
287 changes, send a hint to the output routines that they can | |
288 take some short cuts. This is most useful for | |
289 layouts. This flag should get reset by the output | |
290 routines. | |
291 | |
292 #### It is possible for us to get here when the | |
293 face_cachel is dirty. I do not know what the implications | |
294 of this are.*/ | |
295 IMAGE_INSTANCE_OPTIMIZE_OUTPUT (ii) = 1; | |
296 return 0; | |
297 } | |
434 | 298 else |
428 | 299 return 1; |
300 } | |
442 | 301 /* We now do this last so that glyph checks can do their own thing |
302 for face changes. Face changes quite often happen when we are | |
303 trying to output something in the gutter, this would normally | |
304 lead to a lot of flashing. The indices can quite often be | |
305 different and yet the faces are the same, we do not want to | |
306 re-output in this instance. */ | |
307 else if (crb->findex != drb->findex || | |
308 WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)) | |
309 return 0; | |
428 | 310 else |
311 return 1; | |
312 } | |
313 | |
851 | 314 #if 0 |
315 void | |
316 compare_runes_2 (struct window *w, struct rune *crb, struct rune *drb) | |
317 { | |
318 if (crb->type == DGLYPH) | |
319 { | |
320 if (!EQ (crb->object.dglyph.glyph, drb->object.dglyph.glyph) || | |
321 !EQ (crb->object.dglyph.extent, drb->object.dglyph.extent) || | |
322 crb->object.dglyph.xoffset != drb->object.dglyph.xoffset || | |
323 crb->object.dglyph.yoffset != drb->object.dglyph.yoffset || | |
324 crb->object.dglyph.ascent != drb->object.dglyph.ascent || | |
325 crb->object.dglyph.descent != drb->object.dglyph.descent) | |
326 return 0; | |
327 /* Only check dirtiness if we know something has changed. */ | |
328 else if (XGLYPH_DIRTYP (crb->object.dglyph.glyph) || | |
329 crb->findex != drb->findex) | |
330 { | |
331 /* We need some way of telling redisplay_output_layout () that the | |
332 only reason we are outputting it is because something has | |
333 changed internally. That way we can optimize whether we need | |
334 to clear the layout first and also only output the components | |
335 that have changed. The image_instance dirty flag and | |
336 display_hash are no good to us because these will invariably | |
337 have been set anyway if the layout has changed. So it looks | |
338 like we need yet another change flag that we can set here and | |
339 then clear in redisplay_output_layout (). */ | |
340 Lisp_Object window, image; | |
341 Lisp_Image_Instance* ii; | |
342 window = wrap_window (w); | |
343 image = glyph_image_instance (crb->object.dglyph.glyph, | |
344 window, crb->object.dglyph.matchspec, | |
345 ERROR_ME_DEBUG_WARN, 1); | |
4187 | 346 |
851 | 347 if (!IMAGE_INSTANCEP (image)) |
348 return 0; | |
349 ii = XIMAGE_INSTANCE (image); | |
4187 | 350 |
851 | 351 if (TEXT_IMAGE_INSTANCEP (image) && |
352 (crb->findex != drb->findex || | |
353 WINDOW_FACE_CACHEL_DIRTY (w, drb->findex))) | |
354 return 0; | |
4187 | 355 |
851 | 356 /* It is quite common for the two glyphs to be EQ since in many |
357 cases they will actually be the same object. This does not | |
358 mean, however, that nothing has changed. We therefore need to | |
359 check the current hash of the glyph against the last recorded | |
360 display hash and the pending display items. See | |
361 update_widget () ^^#### which function?. */ | |
362 if (image_instance_changed (image) || | |
363 crb->findex != drb->findex || | |
364 WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)) | |
365 { | |
366 /* Now we are going to re-output the glyph, but since | |
367 this is for some internal reason not related to geometry | |
368 changes, send a hint to the output routines that they can | |
369 take some short cuts. This is most useful for | |
370 layouts. This flag should get reset by the output | |
371 routines. | |
4187 | 372 |
851 | 373 #### It is possible for us to get here when the |
374 face_cachel is dirty. I do not know what the implications | |
375 of this are.*/ | |
376 IMAGE_INSTANCE_OPTIMIZE_OUTPUT (ii) = 1; | |
377 return 0; | |
378 } | |
379 else | |
380 return 1; | |
381 } | |
382 else if (crb->findex != drb->findex || | |
383 WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)) | |
384 return 0; | |
385 else | |
386 return 1; | |
387 } | |
388 else return !(memcmp (crb, drb, sizeof (*crb)) || | |
389 WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)); | |
390 } | |
391 #endif | |
392 | |
393 | |
428 | 394 /***************************************************************************** |
395 get_next_display_block | |
396 | |
397 Return the next display starting at or overlapping START_POS. Return | |
398 the start of the next region in NEXT_START. | |
399 ****************************************************************************/ | |
400 int | |
401 get_next_display_block (layout_bounds bounds, display_block_dynarr *dba, | |
402 int start_pos, int *next_start) | |
403 { | |
404 int next_display_block = NO_BLOCK; | |
405 int priority = -1; | |
406 int block; | |
407 | |
408 /* If we don't find a display block covering or starting at | |
409 start_pos, then we return the starting point of the next display | |
410 block or the next division boundary, whichever is closer to | |
411 start_pos. */ | |
412 if (next_start) | |
413 { | |
414 if (start_pos >= bounds.left_out && start_pos < bounds.left_in) | |
415 *next_start = bounds.left_in; | |
416 else if (start_pos < bounds.left_white) | |
417 *next_start = bounds.left_white; | |
418 else if (start_pos < bounds.right_white) | |
419 *next_start = bounds.right_white; | |
420 else if (start_pos < bounds.right_in) | |
421 *next_start = bounds.right_in; | |
422 else if (start_pos <= bounds.right_out) | |
423 *next_start = bounds.right_out; | |
424 else | |
2500 | 425 ABORT (); |
428 | 426 } |
427 | |
428 for (block = 0; block < Dynarr_length (dba); block++) | |
429 { | |
430 struct display_block *db = Dynarr_atp (dba, block); | |
431 | |
432 if (db->start_pos <= start_pos && db->end_pos > start_pos) | |
433 { | |
434 if ((int) db->type > priority) | |
435 { | |
436 priority = db->type; | |
437 next_display_block = block; | |
438 if (next_start) | |
439 *next_start = db->end_pos; | |
440 } | |
441 } | |
442 else if (next_start && db->start_pos > start_pos) | |
443 { | |
444 if (db->start_pos < *next_start) | |
445 *next_start = db->start_pos; | |
446 } | |
447 } | |
448 | |
449 return next_display_block; | |
450 } | |
451 | |
452 /***************************************************************************** | |
453 get_cursor_size_and_location | |
454 | |
455 Return the information defining the pixel location of the cursor. | |
456 ****************************************************************************/ | |
457 static void | |
458 get_cursor_size_and_location (struct window *w, struct display_block *db, | |
459 int cursor_location, | |
460 int *cursor_start, int *cursor_width, | |
461 int *cursor_height) | |
462 { | |
463 struct rune *rb; | |
464 Lisp_Object window; | |
465 int defheight, defwidth; | |
466 | |
467 if (Dynarr_length (db->runes) <= cursor_location) | |
2500 | 468 ABORT (); |
428 | 469 |
793 | 470 window = wrap_window (w); |
428 | 471 |
472 rb = Dynarr_atp (db->runes, cursor_location); | |
473 *cursor_start = rb->xpos; | |
474 | |
475 default_face_height_and_width (window, &defheight, &defwidth); | |
476 *cursor_height = defheight; | |
477 | |
478 if (rb->type == RUNE_BLANK) | |
479 *cursor_width = defwidth; | |
480 else | |
481 *cursor_width = rb->width; | |
482 } | |
483 | |
484 /***************************************************************************** | |
485 compare_display_blocks | |
486 | |
487 Given two display blocks, output only those areas where they differ. | |
488 ****************************************************************************/ | |
489 static int | |
490 compare_display_blocks (struct window *w, struct display_line *cdl, | |
491 struct display_line *ddl, int c_block, int d_block, | |
492 int start_pixpos, int cursor_start, int cursor_width, | |
493 int cursor_height) | |
494 { | |
495 struct frame *f = XFRAME (w->frame); | |
496 struct display_block *cdb, *ddb; | |
497 int start_pos; | |
498 int stop_pos; | |
499 int force = 0; | |
2286 | 500 #if 0 |
428 | 501 int block_end; |
2286 | 502 #endif |
428 | 503 |
504 cdb = Dynarr_atp (cdl->display_blocks, c_block); | |
505 ddb = Dynarr_atp (ddl->display_blocks, d_block); | |
506 | |
507 assert (cdb->type == ddb->type); | |
508 | |
509 start_pos = -1; | |
510 stop_pos = min (Dynarr_length (cdb->runes), Dynarr_length (ddb->runes)); | |
511 | |
2286 | 512 #if 0 |
428 | 513 block_end = |
514 (!Dynarr_length (ddb->runes) | |
515 ? 0 | |
4844
91b3d00e717f
Various cleanups for Dynarr code, from Unicode-internal ws
Ben Wing <ben@xemacs.org>
parents:
4207
diff
changeset
|
516 : (Dynarr_lastp (ddb->runes)->xpos + |
91b3d00e717f
Various cleanups for Dynarr code, from Unicode-internal ws
Ben Wing <ben@xemacs.org>
parents:
4207
diff
changeset
|
517 Dynarr_lastp (ddb->runes)->width)); |
2286 | 518 #endif |
428 | 519 |
520 /* If the new block type is not text and the cursor status is | |
521 changing and it overlaps the position of this block then force a | |
522 full redraw of the block in order to make sure that the cursor is | |
523 updated properly. */ | |
524 if (ddb->type != TEXT | |
525 #if 0 | |
526 /* I'm not sure exactly what this code wants to do, but it's | |
527 * not right--it doesn't update when cursor_elt changes from, e.g., | |
528 * 0 to 8, and the new or old cursor loc overlaps this block. | |
529 * I've replaced it with the more conservative test below. | |
530 * -dkindred@cs.cmu.edu 23-Mar-1997 */ | |
531 && ((cdl->cursor_elt == -1 && ddl->cursor_elt != -1) | |
532 || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1)) | |
533 && (ddl->cursor_elt == -1 || | |
534 (cursor_start | |
535 && cursor_width | |
536 && (cursor_start + cursor_width) >= start_pixpos | |
537 && cursor_start <= block_end)) | |
538 #else | |
539 && (cdl->cursor_elt != ddl->cursor_elt) | |
540 #endif | |
541 ) | |
542 force = 1; | |
543 | |
544 if (f->windows_structure_changed || | |
545 /* #### Why is this so? We have face cachels so that we don't | |
4187 | 546 have to recalculate all the display blocks when faces |
547 change. I have fixed this for glyphs and am inclined to think | |
548 that faces should "Just Work", but I'm not feeling brave | |
549 today. Maybe its because the face cachels represent merged | |
550 faces rather than simply instantiations in a particular | |
551 domain. */ | |
428 | 552 f->faces_changed || |
553 cdl->ypos != ddl->ypos || | |
554 cdl->ascent != ddl->ascent || | |
555 cdl->descent != ddl->descent || | |
556 cdl->clip != ddl->clip || | |
557 force) | |
558 { | |
559 start_pos = 0; | |
560 force = 1; | |
561 } | |
562 else | |
563 { | |
564 int elt = 0; | |
565 | |
566 while (start_pos < 0 && elt < stop_pos) | |
567 { | |
568 if (!compare_runes (w, Dynarr_atp (cdb->runes, elt), | |
569 Dynarr_atp (ddb->runes, elt))) | |
570 { | |
571 start_pos = elt; | |
572 } | |
573 else | |
574 { | |
575 elt++; | |
576 } | |
577 } | |
578 | |
579 /* If nothing has changed in the area where the blocks overlap, but | |
580 there are new blocks in the desired block, then adjust the start | |
581 point accordingly. */ | |
582 if (elt == stop_pos && stop_pos < Dynarr_length (ddb->runes)) | |
583 start_pos = stop_pos; | |
584 } | |
585 | |
586 if (start_pos >= 0) | |
587 { | |
588 if ((Dynarr_length (ddb->runes) != Dynarr_length (cdb->runes)) | |
589 || force) | |
590 { | |
591 stop_pos = Dynarr_length (ddb->runes); | |
592 } | |
593 else | |
594 { | |
595 /* If the lines have the same number of runes and we are not | |
596 forcing a full redraw because the display line has | |
597 changed position then we try and optimize how much of the | |
598 line we actually redraw by scanning backwards from the | |
599 end for the first changed rune. This optimization is | |
600 almost always triggered by face changes. */ | |
601 | |
602 int elt = Dynarr_length (ddb->runes) - 1; | |
603 | |
604 while (elt > start_pos) | |
605 { | |
606 if (!compare_runes (w, Dynarr_atp (cdb->runes, elt), | |
607 Dynarr_atp (ddb->runes, elt))) | |
608 break; | |
609 else | |
610 elt--; | |
611 } | |
612 stop_pos = elt + 1; | |
613 } | |
614 | |
615 redisplay_output_display_block (w, ddl, d_block, start_pos, | |
616 stop_pos, start_pixpos, | |
617 cursor_start, cursor_width, | |
618 cursor_height); | |
619 return 1; | |
620 } | |
621 | |
622 return 0; | |
623 } | |
624 | |
625 /***************************************************************************** | |
626 clear_left_border | |
627 | |
628 Clear the lefthand outside border. | |
629 ****************************************************************************/ | |
630 static void | |
631 clear_left_border (struct window *w, int y, int height) | |
632 { | |
633 struct frame *f = XFRAME (w->frame); | |
793 | 634 Lisp_Object window = wrap_window (w); |
428 | 635 |
636 redisplay_clear_region (window, DEFAULT_INDEX, | |
637 FRAME_LEFT_BORDER_START (f), y, | |
638 FRAME_BORDER_WIDTH (f), height); | |
639 } | |
640 | |
641 /***************************************************************************** | |
642 clear_right_border | |
643 | |
644 Clear the righthand outside border. | |
645 ****************************************************************************/ | |
646 static void | |
647 clear_right_border (struct window *w, int y, int height) | |
648 { | |
649 struct frame *f = XFRAME (w->frame); | |
793 | 650 Lisp_Object window = wrap_window (w); |
428 | 651 |
652 redisplay_clear_region (window, DEFAULT_INDEX, | |
653 FRAME_RIGHT_BORDER_START (f), | |
654 y, FRAME_BORDER_WIDTH (f), height); | |
655 } | |
656 | |
657 /***************************************************************************** | |
658 output_display_line | |
659 | |
660 Ensure that the contents of the given display line is correct | |
661 on-screen. The force_ parameters are used by redisplay_move_cursor | |
662 to correctly update cursor locations and only cursor locations. | |
663 ****************************************************************************/ | |
664 void | |
665 output_display_line (struct window *w, display_line_dynarr *cdla, | |
666 display_line_dynarr *ddla, int line, int force_start, | |
667 int force_end) | |
668 | |
669 { | |
670 struct frame *f = XFRAME (w->frame); | |
671 struct buffer *b = XBUFFER (w->buffer); | |
672 struct buffer *old_b = window_display_buffer (w); | |
673 struct display_line *cdl, *ddl; | |
674 display_block_dynarr *cdba, *ddba; | |
675 int start_pixpos, end_pixpos; | |
676 int cursor_start, cursor_width, cursor_height; | |
677 | |
678 int force = (force_start >= 0 || force_end >= 0); | |
679 int clear_border = 0; | |
680 int must_sync = 0; | |
681 | |
682 if (cdla && line < Dynarr_length (cdla)) | |
683 { | |
684 cdl = Dynarr_atp (cdla, line); | |
685 cdba = cdl->display_blocks; | |
686 } | |
687 else | |
688 { | |
689 cdl = NULL; | |
690 cdba = NULL; | |
691 } | |
692 | |
4844
91b3d00e717f
Various cleanups for Dynarr code, from Unicode-internal ws
Ben Wing <ben@xemacs.org>
parents:
4207
diff
changeset
|
693 /* The following will assert line < Dynarr_length (ddla) */ |
91b3d00e717f
Various cleanups for Dynarr code, from Unicode-internal ws
Ben Wing <ben@xemacs.org>
parents:
4207
diff
changeset
|
694 ddl = Dynarr_atp (ddla, line); |
428 | 695 ddba = ddl->display_blocks; |
696 | |
697 if (force_start >= 0 && force_start >= ddl->bounds.left_out) | |
698 start_pixpos = force_start; | |
699 else | |
700 start_pixpos = ddl->bounds.left_out; | |
701 | |
702 if (force_end >= 0 && force_end < ddl->bounds.right_out) | |
703 end_pixpos = force_end; | |
704 else | |
705 end_pixpos = ddl->bounds.right_out; | |
706 | |
707 /* Get the cursor parameters. */ | |
708 if (ddl->cursor_elt != -1) | |
709 { | |
710 struct display_block *db; | |
711 | |
712 /* If the lines cursor parameter is not -1 then it indicates | |
4187 | 713 which rune in the TEXT block contains the cursor. This means |
714 that there must be at least one display block. The TEXT | |
715 block, if present, must always be the first display block. */ | |
428 | 716 assert (Dynarr_length (ddba) != 0); |
717 | |
718 db = Dynarr_atp (ddba, 0); | |
719 assert (db->type == TEXT); | |
720 | |
721 get_cursor_size_and_location (w, db, ddl->cursor_elt, &cursor_start, | |
722 &cursor_width, &cursor_height); | |
723 } | |
724 else | |
725 { | |
726 cursor_start = cursor_width = cursor_height = 0; | |
727 } | |
728 | |
729 /* The modeline should only have a single block and it had better be | |
730 a TEXT block. */ | |
731 if (ddl->modeline) | |
732 { | |
733 /* The shadow thickness check is necessary if only the sign of | |
4187 | 734 the size changed. */ |
428 | 735 if (cdba && !w->shadow_thickness_changed) |
736 { | |
737 must_sync |= compare_display_blocks (w, cdl, ddl, 0, 0, | |
738 start_pixpos, 0, 0, 0); | |
739 } | |
740 else | |
741 { | |
742 redisplay_output_display_block (w, ddl, 0, 0, -1, start_pixpos, | |
743 0, 0, 0); | |
744 must_sync = 1; | |
745 } | |
746 | |
747 if (must_sync) | |
748 clear_border = 1; | |
749 } | |
750 | |
751 while (!ddl->modeline && start_pixpos < end_pixpos) | |
752 { | |
753 int block; | |
754 int next_start_pixpos; | |
755 | |
756 block = get_next_display_block (ddl->bounds, ddba, start_pixpos, | |
757 &next_start_pixpos); | |
758 | |
759 /* If we didn't find a block then we should blank the area | |
4187 | 760 between start_pos and next_start if necessary. */ |
428 | 761 if (block == NO_BLOCK) |
762 { | |
763 /* We only erase those areas which were actually previously | |
4187 | 764 covered by a display block unless the window structure |
765 changed. In that case we clear all areas since the current | |
766 structures may actually represent a different buffer. */ | |
428 | 767 while (start_pixpos < next_start_pixpos) |
768 { | |
769 int block_end; | |
770 int old_block; | |
771 | |
772 if (cdba) | |
773 old_block = get_next_display_block (ddl->bounds, cdba, | |
774 start_pixpos, &block_end); | |
775 else | |
776 { | |
777 old_block = NO_BLOCK; | |
778 block_end = next_start_pixpos; | |
779 } | |
780 | |
781 if (!cdba || old_block != NO_BLOCK || b != old_b || | |
782 f->windows_structure_changed || | |
783 f->faces_changed || | |
784 force || | |
785 (cdl && (cdl->ypos != ddl->ypos || | |
786 cdl->ascent != ddl->ascent || | |
787 cdl->descent != ddl->descent || | |
788 cdl->top_clip != ddl->top_clip || | |
789 cdl->clip != ddl->clip))) | |
790 { | |
791 int x, y, width, height; | |
792 face_index findex; | |
793 | |
794 must_sync = 1; | |
795 x = start_pixpos; | |
796 y = DISPLAY_LINE_YPOS (ddl); | |
797 width = min (next_start_pixpos, block_end) - x; | |
798 height = DISPLAY_LINE_HEIGHT (ddl); | |
799 | |
800 if (x < ddl->bounds.left_in) | |
801 { | |
4187 | 802 findex = (ddl->left_margin_findex > DEFAULT_INDEX) ? |
434 | 803 ddl->left_margin_findex |
428 | 804 : get_builtin_face_cache_index (w, Vleft_margin_face); |
805 } | |
806 else if (x < ddl->bounds.right_in) | |
807 { | |
4187 | 808 findex = (ddl->default_findex >= DEFAULT_INDEX) ? |
809 ddl->default_findex | |
810 : DEFAULT_INDEX; | |
428 | 811 } |
812 else if (x < ddl->bounds.right_out) | |
813 { | |
4187 | 814 findex = (ddl->right_margin_findex > DEFAULT_INDEX) ? |
434 | 815 ddl->right_margin_findex |
428 | 816 : get_builtin_face_cache_index (w, Vright_margin_face); |
817 } | |
818 else | |
819 findex = (face_index) -1; | |
820 | |
821 if (findex != (face_index) -1) | |
822 { | |
793 | 823 Lisp_Object window = wrap_window (w); |
428 | 824 |
825 | |
826 /* Clear the empty area. */ | |
827 redisplay_clear_region (window, findex, x, y, width, height); | |
828 | |
829 /* Mark that we should clear the border. This is | |
830 necessary because italic fonts may leave | |
831 droppings in the border. */ | |
832 clear_border = 1; | |
833 } | |
834 } | |
835 | |
836 start_pixpos = min (next_start_pixpos, block_end); | |
837 } | |
838 } | |
839 else | |
840 { | |
841 struct display_block *cdb, *ddb; | |
842 int block_end; | |
843 int old_block; | |
844 | |
845 if (cdba) | |
846 old_block = get_next_display_block (ddl->bounds, cdba, | |
847 start_pixpos, &block_end); | |
848 else | |
849 old_block = NO_BLOCK; | |
850 | |
851 ddb = Dynarr_atp (ddba, block); | |
852 cdb = (old_block != NO_BLOCK ? Dynarr_atp (cdba, old_block) : 0); | |
853 | |
854 /* If there was formerly no block over the current | |
855 region or if it was a block of a different type, then | |
856 output the entire ddb. Otherwise, compare cdb and | |
857 ddb and output only the changed region. */ | |
434 | 858 if (!force && cdb && ddb->type == cdb->type |
428 | 859 /* If there was no buffer being display before the |
4187 | 860 compare anyway as we might be outputting a gutter. */ |
434 | 861 && |
428 | 862 (b == old_b || !old_b)) |
863 { | |
864 must_sync |= compare_display_blocks (w, cdl, ddl, old_block, | |
865 block, start_pixpos, | |
866 cursor_start, cursor_width, | |
867 cursor_height); | |
868 } | |
869 else | |
870 { | |
871 int elt; | |
872 int first_elt = 0; | |
873 int last_elt = -1; | |
874 | |
875 for (elt = 0; elt < Dynarr_length (ddb->runes); elt++) | |
876 { | |
877 struct rune *rb = Dynarr_atp (ddb->runes, elt); | |
878 | |
879 if (start_pixpos >= rb->xpos | |
880 && start_pixpos < rb->xpos + rb->width) | |
881 first_elt = elt; | |
882 | |
883 if (end_pixpos > rb->xpos | |
884 && end_pixpos <= rb->xpos + rb->width) | |
885 { | |
886 last_elt = elt + 1; | |
887 if (last_elt > Dynarr_length (ddb->runes)) | |
888 last_elt = Dynarr_length (ddb->runes); | |
889 break; | |
890 } | |
891 } | |
892 | |
893 must_sync = 1; | |
894 redisplay_output_display_block (w, ddl, block, first_elt, | |
895 last_elt, | |
896 start_pixpos, | |
897 cursor_start, cursor_width, | |
898 cursor_height); | |
899 } | |
434 | 900 |
428 | 901 start_pixpos = next_start_pixpos; |
902 } | |
903 } | |
904 | |
905 /* Clear the internal border if we are next to it and the window | |
906 structure or frame size has changed or if something caused | |
907 clear_border to be tripped. */ | |
908 /* #### Doing this on f->clear sucks but is necessary because of | |
909 window-local background values. */ | |
910 if (f->windows_structure_changed || f->faces_changed || clear_border | |
911 || f->clear) | |
912 { | |
913 int y = DISPLAY_LINE_YPOS (ddl); | |
914 int height = DISPLAY_LINE_HEIGHT (ddl); | |
915 | |
916 /* If we are in the gutter then we musn't clear the borders. */ | |
917 if (y >= WINDOW_TEXT_TOP (w) && (y + height) <= WINDOW_TEXT_BOTTOM (w)) | |
918 { | |
919 if (ddl->modeline) | |
920 { | |
921 y -= MODELINE_SHADOW_THICKNESS (w); | |
922 height += (2 * MODELINE_SHADOW_THICKNESS (w)); | |
923 } | |
434 | 924 |
428 | 925 if (window_is_leftmost (w)) |
926 clear_left_border (w, y, height); | |
927 if (window_is_rightmost (w)) | |
928 clear_right_border (w, y, height); | |
929 } | |
930 } | |
931 | |
932 if (cdla) | |
933 sync_display_line_structs (w, line, must_sync, cdla, ddla); | |
934 } | |
935 | |
936 /***************************************************************************** | |
937 redisplay_move_cursor | |
938 | |
939 For the given window W, move the cursor to NEW_POINT. Returns a | |
940 boolean indicating success or failure. | |
941 ****************************************************************************/ | |
942 | |
826 | 943 #define ADJ_CHARPOS (rb->charpos + dl->offset) |
428 | 944 #define ADJ_ENDPOS (rb->endpos + dl->offset) |
945 | |
946 int | |
665 | 947 redisplay_move_cursor (struct window *w, Charbpos new_point, int no_output_end) |
428 | 948 { |
949 struct frame *f = XFRAME (w->frame); | |
950 struct device *d = XDEVICE (f->device); | |
951 | |
952 display_line_dynarr *cla = window_display_lines (w, CURRENT_DISP); | |
953 struct display_line *dl; | |
954 struct display_block *db; | |
955 struct rune *rb; | |
956 int x = w->last_point_x[CURRENT_DISP]; | |
957 int y = w->last_point_y[CURRENT_DISP]; | |
958 | |
959 /* | |
960 * Bail if cursor_in_echo_area is non-zero and we're fiddling with | |
961 * the cursor in a non-active minibuffer window, since that is a | |
962 * special case that is handled elsewhere and this function need | |
963 * not handle it. Return 1 so the caller will assume we | |
964 * succeeded. | |
965 */ | |
966 if (cursor_in_echo_area && MINI_WINDOW_P (w) && | |
967 w != XWINDOW (FRAME_SELECTED_WINDOW (f))) | |
968 return 1; | |
969 | |
970 if (y < 0 || y >= Dynarr_length (cla)) | |
971 return 0; | |
972 | |
973 dl = Dynarr_atp (cla, y); | |
974 db = get_display_block_from_line (dl, TEXT); | |
975 | |
976 if (x < 0 || x >= Dynarr_length (db->runes)) | |
977 return 0; | |
978 | |
979 rb = Dynarr_atp (db->runes, x); | |
980 | |
981 if (rb->cursor_type == CURSOR_OFF) | |
982 return 0; | |
826 | 983 else if (ADJ_CHARPOS == new_point |
984 || (ADJ_ENDPOS && (new_point >= ADJ_CHARPOS) | |
428 | 985 && (new_point <= ADJ_ENDPOS))) |
986 { | |
987 w->last_point_x[CURRENT_DISP] = x; | |
988 w->last_point_y[CURRENT_DISP] = y; | |
826 | 989 Fset_marker (w->last_point[CURRENT_DISP], make_int (ADJ_CHARPOS), |
428 | 990 w->buffer); |
991 dl->cursor_elt = x; | |
992 return 1; | |
993 } | |
994 else | |
995 { | |
442 | 996 { |
997 MAYBE_DEVMETH (d, frame_output_begin, (f)); | |
998 MAYBE_DEVMETH (d, window_output_begin, (w)); | |
999 } | |
1000 rb->cursor_type = CURSOR_OFF; | |
428 | 1001 dl->cursor_elt = -1; |
1002 output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width); | |
1003 } | |
1004 | |
1005 w->last_point_x[CURRENT_DISP] = -1; | |
1006 w->last_point_y[CURRENT_DISP] = -1; | |
1007 Fset_marker (w->last_point[CURRENT_DISP], Qnil, w->buffer); | |
1008 | |
1009 /* If this isn't the selected frame, then erasing the old cursor is | |
1010 all we actually had to do. */ | |
1011 if (w != XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d)))) | |
1012 { | |
1013 if (!no_output_end) | |
442 | 1014 { |
1015 MAYBE_DEVMETH (d, window_output_end, (w)); | |
1016 MAYBE_DEVMETH (d, frame_output_end, (f)); | |
1017 } | |
428 | 1018 |
1019 return 1; | |
1020 } | |
1021 | |
1022 /* This should only occur in the minibuffer. */ | |
1023 if (new_point == 0) | |
1024 { | |
1025 w->last_point_x[CURRENT_DISP] = 0; | |
1026 w->last_point_y[CURRENT_DISP] = y; | |
1027 Fset_marker (w->last_point[CURRENT_DISP], Qzero, w->buffer); | |
1028 | |
1029 rb = Dynarr_atp (db->runes, 0); | |
1030 rb->cursor_type = CURSOR_ON; | |
1031 dl->cursor_elt = 0; | |
1032 | |
1033 output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width); | |
1034 | |
1035 if (!no_output_end) | |
442 | 1036 { |
1037 MAYBE_DEVMETH (d, window_output_end, (w)); | |
1038 MAYBE_DEVMETH (d, frame_output_end, (f)); | |
1039 } | |
428 | 1040 return 1; |
1041 } | |
1042 else | |
1043 { | |
1044 int cur_rb = 0; | |
1045 int first = 0; | |
1046 int cur_dl, up; | |
1047 | |
826 | 1048 if (ADJ_CHARPOS < new_point) |
428 | 1049 { |
1050 up = 1; | |
1051 cur_rb = x + 1; | |
1052 cur_dl = y; | |
1053 } | |
665 | 1054 else /* (rb->charbpos + dl->offset) > new_point */ |
428 | 1055 { |
1056 up = 0; | |
1057 | |
1058 if (!x) | |
1059 { | |
1060 cur_dl = y - 1; | |
1061 first = 0; | |
1062 } | |
1063 else | |
1064 { | |
1065 cur_rb = x - 1; | |
1066 cur_dl = y; | |
1067 first = 1; | |
1068 } | |
1069 } | |
1070 | |
434 | 1071 while (up ? (cur_dl < Dynarr_length (cla)) : (cur_dl >= 0)) |
428 | 1072 { |
1073 dl = Dynarr_atp (cla, cur_dl); | |
1074 db = get_display_block_from_line (dl, TEXT); | |
1075 | |
1076 if (!up && !first) | |
1077 cur_rb = Dynarr_length (db->runes) - 1; | |
1078 | |
1079 while ((!scroll_on_clipped_lines || !dl->clip) && | |
1080 (up ? (cur_rb < Dynarr_length (db->runes)) : (cur_rb >= 0))) | |
1081 { | |
1082 rb = Dynarr_atp (db->runes, cur_rb); | |
1083 | |
1084 if (rb->cursor_type != IGNORE_CURSOR | |
1085 && rb->cursor_type != NO_CURSOR && | |
826 | 1086 (ADJ_CHARPOS == new_point |
1087 || (ADJ_ENDPOS && (new_point >= ADJ_CHARPOS) | |
1088 && (new_point <= ADJ_CHARPOS)))) | |
428 | 1089 { |
1090 rb->cursor_type = CURSOR_ON; | |
1091 dl->cursor_elt = cur_rb; | |
1092 | |
1093 | |
1094 output_display_line (w, 0, cla, cur_dl, rb->xpos, | |
1095 rb->xpos + rb->width); | |
1096 | |
1097 w->last_point_x[CURRENT_DISP] = cur_rb; | |
1098 w->last_point_y[CURRENT_DISP] = cur_dl; | |
1099 Fset_marker (w->last_point[CURRENT_DISP], | |
826 | 1100 make_int (ADJ_CHARPOS), w->buffer); |
428 | 1101 |
1102 if (!no_output_end) | |
442 | 1103 { |
1104 MAYBE_DEVMETH (d, window_output_end, (w)); | |
1105 MAYBE_DEVMETH (d, frame_output_end, (f)); | |
1106 } | |
428 | 1107 return 1; |
1108 } | |
1109 | |
1110 (up ? cur_rb++ : cur_rb--); | |
1111 } | |
1112 | |
1113 (up ? (cur_rb = 0) : (first = 0)); | |
1114 (up ? cur_dl++ : cur_dl--); | |
1115 } | |
1116 } | |
1117 | |
1118 if (!no_output_end) | |
442 | 1119 { |
1120 MAYBE_DEVMETH (d, window_output_end, (w)); | |
1121 MAYBE_DEVMETH (d, frame_output_end, (f)); | |
1122 } | |
428 | 1123 return 0; |
1124 } | |
826 | 1125 #undef ADJ_CHARPOS |
428 | 1126 #undef ADJ_ENDPOS |
1127 | |
1128 /***************************************************************************** | |
1129 redraw_cursor_in_window | |
1130 | |
1131 For the given window W, redraw the cursor if it is contained within | |
1132 the window. | |
1133 ****************************************************************************/ | |
1134 static void | |
1135 redraw_cursor_in_window (struct window *w, int run_end_begin_meths) | |
1136 { | |
1137 struct frame *f = XFRAME (w->frame); | |
1138 struct device *d = XDEVICE (f->device); | |
1139 | |
1140 display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP); | |
1141 struct display_line *dl; | |
1142 struct display_block *db; | |
1143 struct rune *rb; | |
1144 | |
1145 int x = w->last_point_x[CURRENT_DISP]; | |
1146 int y = w->last_point_y[CURRENT_DISP]; | |
1147 | |
1148 if (cursor_in_echo_area && MINI_WINDOW_P (w) && | |
1149 !echo_area_active (f) && minibuf_level == 0) | |
1150 { | |
1151 MAYBE_DEVMETH (d, set_final_cursor_coords, (f, w->pixel_top, 0)); | |
1152 } | |
1153 | |
1154 if (y < 0 || y >= Dynarr_length (dla)) | |
1155 return; | |
1156 | |
1157 if (MINI_WINDOW_P (w) && f != device_selected_frame (d) && | |
1158 !is_surrogate_for_selected_frame (f)) | |
1159 return; | |
1160 | |
1161 dl = Dynarr_atp (dla, y); | |
1162 db = get_display_block_from_line (dl, TEXT); | |
1163 | |
1164 if (x < 0 || x >= Dynarr_length (db->runes)) | |
1165 return; | |
1166 | |
1167 rb = Dynarr_atp (db->runes, x); | |
1168 | |
1169 /* Don't call the output routine if the block isn't actually the | |
1170 cursor. */ | |
1171 if (rb->cursor_type == CURSOR_ON) | |
1172 { | |
1173 MAYBE_DEVMETH (d, set_final_cursor_coords, | |
1174 (f, dl->ypos - 1, rb->xpos)); | |
1175 | |
1176 if (run_end_begin_meths) | |
442 | 1177 { |
1178 MAYBE_DEVMETH (d, frame_output_begin, (f)); | |
1179 MAYBE_DEVMETH (d, window_output_begin, (w)); | |
1180 } | |
428 | 1181 |
1182 output_display_line (w, 0, dla, y, rb->xpos, rb->xpos + rb->width); | |
1183 | |
1184 if (run_end_begin_meths) | |
442 | 1185 { |
1186 MAYBE_DEVMETH (d, window_output_end, (w)); | |
1187 MAYBE_DEVMETH (d, frame_output_end, (f)); | |
1188 } | |
428 | 1189 } |
1190 } | |
1191 | |
1192 /***************************************************************************** | |
1193 redisplay_redraw_cursor | |
1194 | |
1195 For the given frame F, redraw the cursor on the selected window. | |
1196 This is used to update the cursor after focus changes. | |
1197 ****************************************************************************/ | |
1198 void | |
1199 redisplay_redraw_cursor (struct frame *f, int run_end_begin_meths) | |
1200 { | |
1201 Lisp_Object window; | |
1202 | |
1203 if (!cursor_in_echo_area) | |
1204 window = FRAME_SELECTED_WINDOW (f); | |
1205 else if (FRAME_HAS_MINIBUF_P (f)) | |
1206 window = FRAME_MINIBUF_WINDOW (f); | |
1207 else | |
1208 return; | |
1209 | |
1210 redraw_cursor_in_window (XWINDOW (window), run_end_begin_meths); | |
1211 } | |
1212 | |
1213 /**************************************************************************** | |
1214 redisplay_output_display_block | |
1215 | |
1216 Given a display line, a block number for that start line, output all | |
1217 runes between start and end in the specified display block. | |
1218 ****************************************************************************/ | |
1219 static void | |
1220 redisplay_output_display_block (struct window *w, struct display_line *dl, int block, | |
1221 int start, int end, int start_pixpos, int cursor_start, | |
1222 int cursor_width, int cursor_height) | |
1223 { | |
1224 struct frame *f = XFRAME (w->frame); | |
1225 struct device *d = XDEVICE (f->device); | |
442 | 1226 /* Temporarily disabled until generalization is done. */ |
1227 #if 0 | |
428 | 1228 struct display_block *db = Dynarr_atp (dl->display_blocks, block); |
1229 rune_dynarr *rba = db->runes; | |
1230 struct rune *rb; | |
1231 int xpos, width; | |
1232 rb = Dynarr_atp (rba, start); | |
1233 | |
1234 if (!rb) | |
1235 /* Nothing to do so don't do anything. */ | |
1236 return; | |
1237 | |
1238 xpos = max (start_pixpos, rb->xpos); | |
1239 | |
1240 if (end < 0) | |
1241 end = Dynarr_length (rba); | |
1242 | |
1243 rb = Dynarr_atp (rba, end - 1); | |
1244 width = rb->xpos + rb->width - xpos; | |
442 | 1245 #endif |
428 | 1246 /* now actually output the block. */ |
1247 DEVMETH (d, output_display_block, (w, dl, block, start, | |
1248 end, start_pixpos, | |
1249 cursor_start, cursor_width, | |
1250 cursor_height)); | |
1251 } | |
1252 | |
1253 /**************************************************************************** | |
1254 redisplay_unmap_subwindows | |
1255 | |
1256 Remove subwindows from the area in the box defined by the given | |
1257 parameters. | |
1258 ****************************************************************************/ | |
448 | 1259 static void |
1260 redisplay_unmap_subwindows (struct frame* f, int x, int y, int width, int height, | |
1261 Lisp_Object ignored_window) | |
428 | 1262 { |
442 | 1263 Lisp_Object rest; |
428 | 1264 |
442 | 1265 LIST_LOOP (rest, XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f))) |
1266 { | |
1267 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (XCAR (rest)); | |
1268 if (IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii) | |
428 | 1269 && |
442 | 1270 IMAGE_INSTANCE_DISPLAY_X (ii) |
1271 + IMAGE_INSTANCE_DISPLAY_WIDTH (ii) > x | |
428 | 1272 && |
442 | 1273 IMAGE_INSTANCE_DISPLAY_X (ii) < x + width |
1274 && | |
1275 IMAGE_INSTANCE_DISPLAY_Y (ii) | |
1276 + IMAGE_INSTANCE_DISPLAY_HEIGHT (ii) > y | |
434 | 1277 && |
442 | 1278 IMAGE_INSTANCE_DISPLAY_Y (ii) < y + height |
1279 && | |
1280 !EQ (XCAR (rest), ignored_window)) | |
428 | 1281 { |
442 | 1282 unmap_subwindow (XCAR (rest)); |
428 | 1283 } |
1284 } | |
1285 } | |
1286 | |
1287 /**************************************************************************** | |
1288 redisplay_unmap_subwindows_maybe | |
1289 | |
1290 Potentially subwindows from the area in the box defined by the given | |
1291 parameters. | |
1292 ****************************************************************************/ | |
1279 | 1293 void |
1294 redisplay_unmap_subwindows_maybe (struct frame *f, int x, int y, int width, | |
1295 int height) | |
428 | 1296 { |
442 | 1297 if (!NILP (XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f)))) |
428 | 1298 { |
1299 redisplay_unmap_subwindows (f, x, y, width, height, Qnil); | |
1300 } | |
1301 } | |
1302 | |
1279 | 1303 static void |
1304 redisplay_unmap_subwindows_except_us (struct frame *f, int x, int y, int width, | |
1305 int height, Lisp_Object subwindow) | |
428 | 1306 { |
442 | 1307 if (!NILP (XWEAK_LIST_LIST (FRAME_SUBWINDOW_CACHE (f)))) |
428 | 1308 { |
1309 redisplay_unmap_subwindows (f, x, y, width, height, subwindow); | |
1310 } | |
1311 } | |
1312 | |
1313 /**************************************************************************** | |
1314 redisplay_output_subwindow | |
1315 | |
1316 output a subwindow. This code borrows heavily from the pixmap stuff, | |
1317 although is much simpler not needing to account for partial | |
1318 pixmaps, backgrounds etc. | |
1319 ****************************************************************************/ | |
1320 void | |
434 | 1321 redisplay_output_subwindow (struct window *w, |
428 | 1322 Lisp_Object image_instance, |
1323 struct display_box* db, struct display_glyph_area* dga, | |
2286 | 1324 face_index findex, int UNUSED (cursor_start), |
1325 int UNUSED (cursor_width), | |
1326 int UNUSED (cursor_height)) | |
428 | 1327 { |
440 | 1328 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance); |
428 | 1329 Lisp_Object window; |
1330 struct display_glyph_area sdga; | |
1331 | |
442 | 1332 dga->height = IMAGE_INSTANCE_HEIGHT (p); |
1333 dga->width = IMAGE_INSTANCE_WIDTH (p); | |
1334 | |
1335 /* The first thing we are going to do is update the display | |
1336 characteristics of the subwindow. This also clears the dirty | |
1337 flags as a side effect. */ | |
1338 redisplay_subwindow (image_instance); | |
428 | 1339 |
1340 /* This makes the glyph area fit into the display area. */ | |
1341 if (!redisplay_normalize_glyph_area (db, dga)) | |
1342 return; | |
1343 | |
793 | 1344 window = wrap_window (w); |
428 | 1345 |
1346 /* Clear the area the subwindow is going into. */ | |
1347 redisplay_clear_clipped_region (window, findex, | |
1348 db, dga, 0, image_instance); | |
1349 | |
1350 /* This shrinks the display box to exactly enclose the glyph | |
1351 area. */ | |
1352 redisplay_normalize_display_box (db, dga); | |
1353 | |
1354 /* if we can't view the whole window we can't view any of it. We | |
1355 have to be careful here since we may be being asked to display | |
1356 part of a subwindow, the rest of which is on-screen as well. We | |
1357 need to allow this case and map the entire subwindow. We also | |
1358 need to be careful since the subwindow could be outside the | |
1359 window in the gutter or modeline - we also need to allow these | |
1360 cases.*/ | |
1361 sdga.xoffset = -dga->xoffset; | |
1362 sdga.yoffset = -dga->yoffset; | |
442 | 1363 sdga.height = IMAGE_INSTANCE_HEIGHT (p); |
1364 sdga.width = IMAGE_INSTANCE_WIDTH (p); | |
434 | 1365 |
446 | 1366 if (redisplay_display_boxes_in_window_p (w, db, &sdga) == 0 |
1367 || | |
1368 /* We only want to do full subwindow display for windows that | |
1369 are completely in the gutter, otherwise we must clip to be | |
1370 safe. */ | |
1371 display_boxes_in_gutter_p (XFRAME (w->frame), db, &sdga) <= 0) | |
428 | 1372 { |
1373 map_subwindow (image_instance, db->xpos, db->ypos, dga); | |
1374 } | |
1375 else | |
1376 { | |
1377 sdga.xoffset = sdga.yoffset = 0; | |
434 | 1378 map_subwindow (image_instance, db->xpos - dga->xoffset, |
428 | 1379 db->ypos - dga->yoffset, &sdga); |
1380 } | |
1381 } | |
1382 | |
1383 /**************************************************************************** | |
1384 redisplay_output_layout | |
1385 | |
1386 Output a widget hierarchy. This can safely call itself recursively. | |
442 | 1387 |
1388 The complexity of outputting layouts is deciding whether to do it or | |
1389 not. Consider a layout enclosing some text, the text changes and is | |
1390 marked as dirty, but the enclosing layout has not been marked as | |
1391 dirty so no updates occur and the text will potentially be truncated. | |
1392 Alternatively we hold a back pointer in the image instance to the | |
1393 parent and mark the parent as dirty. But the layout code assumes that | |
1394 if the layout is dirty then the whole layout should be redisplayed, | |
1395 so we then get lots of flashing even though only the text has changed | |
1396 size. Of course if the text shrinks in size then we do actually need | |
1397 to redisplay the layout to repaint the exposed area. So what happens | |
1398 if we make a non-structural change like changing color? Either we | |
1399 redisplay everything, or we redisplay nothing. These are exactly the | |
1400 issues lwlib has to grapple with. We really need to know what has | |
1401 actually changed and make a layout decision based on that. We also | |
1402 really need to know what has changed so that we can only make the | |
1403 necessary changes in update_subwindow. This has all now been | |
1404 implemented, Viva la revolution! | |
428 | 1405 ****************************************************************************/ |
1406 void | |
442 | 1407 redisplay_output_layout (Lisp_Object domain, |
428 | 1408 Lisp_Object image_instance, |
1409 struct display_box* db, struct display_glyph_area* dga, | |
2286 | 1410 face_index findex, int UNUSED (cursor_start), |
1411 int UNUSED (cursor_width), int UNUSED (cursor_height)) | |
428 | 1412 { |
440 | 1413 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance); |
442 | 1414 Lisp_Object rest, window = DOMAIN_WINDOW (domain); |
3479 | 1415 Ichar_dynarr *buf; |
442 | 1416 struct window *w = XWINDOW (window); |
1417 struct device *d = DOMAIN_XDEVICE (domain); | |
428 | 1418 int layout_height, layout_width; |
1419 | |
442 | 1420 layout_height = glyph_height (image_instance, domain); |
1421 layout_width = glyph_width (image_instance, domain); | |
428 | 1422 |
1423 dga->height = layout_height; | |
1424 dga->width = layout_width; | |
442 | 1425 #ifdef DEBUG_WIDGET_OUTPUT |
1426 printf ("outputing layout glyph %p\n", p); | |
1427 #endif | |
428 | 1428 /* This makes the glyph area fit into the display area. */ |
1429 if (!redisplay_normalize_glyph_area (db, dga)) | |
1430 return; | |
1431 | |
3479 | 1432 buf = Dynarr_new (Ichar); |
1433 | |
428 | 1434 /* Highly dodgy optimization. We want to only output the whole |
1435 layout if we really have to. */ | |
442 | 1436 if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (p) |
1437 || IMAGE_INSTANCE_LAYOUT_CHANGED (p) | |
1438 || IMAGE_INSTANCE_WIDGET_FACE_CHANGED (p) | |
1439 || IMAGE_INSTANCE_SIZE_CHANGED (p) | |
1440 || IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (p)) | |
428 | 1441 { |
1442 /* First clear the area we are drawing into. This is the easiest | |
1443 thing to do since we have many gaps that we have to make sure are | |
1444 filled in. */ | |
1445 redisplay_clear_clipped_region (window, findex, db, dga, 1, Qnil); | |
434 | 1446 |
428 | 1447 /* Output a border if required */ |
1448 if (!NILP (IMAGE_INSTANCE_LAYOUT_BORDER (p))) | |
1449 { | |
1450 int edges = 0; | |
1451 enum edge_style style; | |
1452 int ypos = db->ypos; | |
863 | 1453 int xpos = db->xpos; |
428 | 1454 int height = dga->height; |
863 | 1455 int width = dga->width; |
434 | 1456 |
863 | 1457 /* The bevel_area routines always draw in from the specified |
1458 area so there is no need to adjust the displayed area to | |
1459 make sure that the lines are visible. */ | |
4187 | 1460 if (dga->xoffset >= 0) |
428 | 1461 edges |= EDGE_LEFT; |
4187 | 1462 if (dga->width - dga->xoffset == layout_width) |
428 | 1463 edges |= EDGE_RIGHT; |
4187 | 1464 if (dga->yoffset >= 0) |
428 | 1465 edges |= EDGE_TOP; |
1466 if (dga->height - dga->yoffset == layout_height) | |
1467 edges |= EDGE_BOTTOM; | |
4187 | 1468 |
428 | 1469 if (EQ (IMAGE_INSTANCE_LAYOUT_BORDER (p), Qetched_in)) |
1470 style = EDGE_ETCHED_IN; | |
1471 else if (EQ (IMAGE_INSTANCE_LAYOUT_BORDER (p), Qetched_out)) | |
1472 style = EDGE_ETCHED_OUT; | |
1473 else if (EQ (IMAGE_INSTANCE_LAYOUT_BORDER (p), Qbevel_in)) | |
1474 style = EDGE_BEVEL_IN; | |
1475 else if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (p))) | |
1476 { | |
1477 style = EDGE_ETCHED_IN; | |
1478 if (edges & EDGE_TOP) | |
1479 { | |
1480 ypos += XINT (IMAGE_INSTANCE_LAYOUT_BORDER (p)); | |
1481 height -= XINT (IMAGE_INSTANCE_LAYOUT_BORDER (p)); | |
1482 } | |
1483 } | |
1484 else | |
1485 style = EDGE_BEVEL_OUT; | |
1486 | |
434 | 1487 MAYBE_DEVMETH (d, bevel_area, |
863 | 1488 (w, findex, xpos, ypos, width, height, |
1489 DEFAULT_WIDGET_SHADOW_WIDTH, edges, style)); | |
428 | 1490 } |
1491 } | |
434 | 1492 |
428 | 1493 /* This shrinks the display box to exactly enclose the glyph |
1494 area. */ | |
1495 redisplay_normalize_display_box (db, dga); | |
1496 | |
1497 /* Flip through the widgets in the layout displaying as necessary */ | |
1498 LIST_LOOP (rest, IMAGE_INSTANCE_LAYOUT_CHILDREN (p)) | |
1499 { | |
442 | 1500 Lisp_Object child = glyph_image_instance (XCAR (rest), image_instance, |
793 | 1501 ERROR_ME_DEBUG_WARN, 1); |
428 | 1502 |
1503 struct display_box cdb; | |
1504 /* For losing HP-UX */ | |
1505 cdb.xpos = db->xpos; | |
1506 cdb.ypos = db->ypos; | |
1507 cdb.width = db->width; | |
1508 cdb.height = db->height; | |
1509 | |
1510 /* First determine if the image is visible at all */ | |
1511 if (IMAGE_INSTANCEP (child)) | |
1512 { | |
440 | 1513 Lisp_Image_Instance* childii = XIMAGE_INSTANCE (child); |
442 | 1514 |
428 | 1515 /* The enclosing layout offsets are +ve at this point */ |
1516 struct display_glyph_area cdga; | |
1517 cdga.xoffset = IMAGE_INSTANCE_XOFFSET (childii) - dga->xoffset; | |
1518 cdga.yoffset = IMAGE_INSTANCE_YOFFSET (childii) - dga->yoffset; | |
442 | 1519 cdga.width = glyph_width (child, image_instance); |
1520 cdga.height = glyph_height (child, image_instance); | |
1521 | |
1522 IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) = | |
1523 IMAGE_INSTANCE_OPTIMIZE_OUTPUT (p); | |
428 | 1524 |
4207 | 1525 /* Although normalization is done by the output routines we have to |
1526 do it here so that they don't try and clear all of db. This is | |
1527 true below also. */ | |
428 | 1528 if (redisplay_normalize_glyph_area (&cdb, &cdga)) |
1529 { | |
1530 redisplay_normalize_display_box (&cdb, &cdga); | |
4207 | 1531 /* Since the display boxes will now be totally in the window if |
1532 they are visible at all we can now check this easily. */ | |
428 | 1533 if (cdb.xpos < db->xpos || cdb.ypos < db->ypos |
1534 || cdb.xpos + cdb.width > db->xpos + db->width | |
1535 || cdb.ypos + cdb.height > db->ypos + db->height) | |
1536 continue; | |
4207 | 1537 /* We have to invert the offset here as normalization will have |
1538 made them positive which the output routines will treat as a | |
1539 truly +ve offset. */ | |
428 | 1540 cdga.xoffset = -cdga.xoffset; |
1541 cdga.yoffset = -cdga.yoffset; | |
1542 | |
1543 switch (IMAGE_INSTANCE_TYPE (childii)) | |
1544 { | |
1545 case IMAGE_TEXT: | |
1546 { | |
1547 /* #### This is well hacked and could use some | |
1548 generalisation.*/ | |
434 | 1549 if (redisplay_normalize_glyph_area (&cdb, &cdga) |
1550 && | |
442 | 1551 (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) || |
1552 IMAGE_INSTANCE_DIRTYP (childii))) | |
428 | 1553 { |
1554 struct display_line dl; /* this is fake */ | |
1555 Lisp_Object string = | |
1556 IMAGE_INSTANCE_TEXT_STRING (childii); | |
442 | 1557 unsigned char charsets[NUM_LEADING_BYTES]; |
4207 | 1558 struct face_cachel *cachel |
1559 = WINDOW_FACE_CACHEL (w, findex); | |
1560 | |
1561 DISPLAY_LINE_INIT (dl); | |
442 | 1562 |
867 | 1563 find_charsets_in_ibyte_string (charsets, |
4207 | 1564 XSTRING_DATA (string), |
1565 XSTRING_LENGTH (string)); | |
442 | 1566 ensure_face_cachel_complete (cachel, window, charsets); |
1567 | |
867 | 1568 convert_ibyte_string_into_ichar_dynarr |
4207 | 1569 (XSTRING_DATA (string), XSTRING_LENGTH (string), |
1570 buf); | |
434 | 1571 |
428 | 1572 redisplay_normalize_display_box (&cdb, &cdga); |
1573 /* Offsets are now +ve again so be careful | |
1574 when fixing up the display line. */ | |
1575 /* Munge boxes into display lines. */ | |
1576 dl.ypos = (cdb.ypos - cdga.yoffset) | |
442 | 1577 + glyph_ascent (child, image_instance); |
1578 dl.ascent = glyph_ascent (child, image_instance); | |
1579 dl.descent = glyph_descent (child, image_instance); | |
428 | 1580 dl.top_clip = cdga.yoffset; |
4207 | 1581 dl.clip = (dl.ypos + dl.descent) |
1582 - (cdb.ypos + cdb.height); | |
428 | 1583 /* output_string doesn't understand offsets in |
1584 the same way as other routines - we have to | |
1585 add the offset to the width so that we | |
1586 output the full string. */ | |
4207 | 1587 MAYBE_DEVMETH (d, output_string, |
1588 (w, &dl, buf, cdb.xpos, | |
1589 cdga.xoffset, cdb.xpos, | |
1590 cdga.width + cdga.xoffset, | |
1591 findex, 0, 0, 0, 0)); | |
428 | 1592 Dynarr_reset (buf); |
1593 } | |
1594 } | |
1595 break; | |
434 | 1596 |
428 | 1597 case IMAGE_MONO_PIXMAP: |
1598 case IMAGE_COLOR_PIXMAP: | |
442 | 1599 if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) |
1600 || IMAGE_INSTANCE_DIRTYP (childii)) | |
428 | 1601 redisplay_output_pixmap (w, child, &cdb, &cdga, findex, |
1602 0, 0, 0, 0); | |
1603 break; | |
434 | 1604 |
428 | 1605 case IMAGE_WIDGET: |
442 | 1606 if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (childii), Qlayout)) |
1607 { | |
1608 redisplay_output_layout (image_instance, child, &cdb, &cdga, findex, | |
1609 0, 0, 0); | |
1610 break; | |
1611 } | |
428 | 1612 case IMAGE_SUBWINDOW: |
442 | 1613 if (!IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) || |
1614 IMAGE_INSTANCE_DIRTYP (childii)) | |
428 | 1615 redisplay_output_subwindow (w, child, &cdb, &cdga, findex, |
1616 0, 0, 0); | |
1617 break; | |
434 | 1618 |
428 | 1619 case IMAGE_NOTHING: |
1620 /* nothing is as nothing does */ | |
1621 break; | |
434 | 1622 |
428 | 1623 case IMAGE_POINTER: |
1624 default: | |
2500 | 1625 ABORT (); |
428 | 1626 } |
1627 } | |
442 | 1628 IMAGE_INSTANCE_OPTIMIZE_OUTPUT (childii) = 0; |
428 | 1629 } |
1630 } | |
442 | 1631 |
1632 /* Update any display properties. I'm not sure whether this actually | |
1633 does anything for layouts except clear the changed flags. */ | |
1634 redisplay_subwindow (image_instance); | |
1635 | |
428 | 1636 Dynarr_free (buf); |
1637 } | |
1638 | |
1639 /**************************************************************************** | |
1640 redisplay_output_pixmap | |
1641 | |
1642 | |
1643 output a pixmap. | |
1644 ****************************************************************************/ | |
1645 void | |
434 | 1646 redisplay_output_pixmap (struct window *w, |
428 | 1647 Lisp_Object image_instance, |
1648 struct display_box* db, struct display_glyph_area* dga, | |
1649 face_index findex, int cursor_start, int cursor_width, | |
1650 int cursor_height, int offset_bitmap) | |
1651 { | |
1652 struct frame *f = XFRAME (w->frame); | |
1653 struct device *d = XDEVICE (f->device); | |
440 | 1654 Lisp_Image_Instance *p = XIMAGE_INSTANCE (image_instance); |
793 | 1655 Lisp_Object window = wrap_window (w); |
1656 | |
428 | 1657 |
1658 dga->height = IMAGE_INSTANCE_PIXMAP_HEIGHT (p); | |
1659 dga->width = IMAGE_INSTANCE_PIXMAP_WIDTH (p); | |
1660 | |
819 | 1661 #ifdef DEBUG_REDISPLAY |
1662 printf ("redisplay_output_pixmap(request) \ | |
4187 | 1663 [%dx%d@%d+%d] in [%dx%d@%d+%d]\n", |
819 | 1664 db->width, db->height, db->xpos, db->ypos, |
1665 dga->width, dga->height, dga->xoffset, dga->yoffset); | |
1666 #endif | |
1667 | |
428 | 1668 /* This makes the glyph area fit into the display area. */ |
1669 if (!redisplay_normalize_glyph_area (db, dga)) | |
1670 return; | |
1671 | |
819 | 1672 #ifdef DEBUG_REDISPLAY |
1673 printf ("redisplay_output_pixmap(normalized) \ | |
1674 [%dx%d@%d+%d] in [%dx%d@%d+%d]\n", | |
1675 db->width, db->height, db->xpos, db->ypos, | |
1676 dga->width, dga->height, dga->xoffset, dga->yoffset); | |
1677 #endif | |
1678 | |
428 | 1679 /* Clear the area the pixmap is going into. The pixmap itself will |
1680 always take care of the full width. We don't want to clear where | |
1681 it is going to go in order to avoid flicker. So, all we have to | |
1682 take care of is any area above or below the pixmap. If the pixmap | |
1683 has a mask in which case we have to clear the whole damn thing | |
1684 since we can't yet clear just the area not included in the | |
1685 mask. */ | |
1686 if (!offset_bitmap) | |
1687 { | |
1688 redisplay_clear_clipped_region (window, findex, | |
434 | 1689 db, dga, |
442 | 1690 (IMAGE_INSTANCE_PIXMAP_MASK (p) != 0), |
428 | 1691 Qnil); |
1692 | |
1693 /* This shrinks the display box to exactly enclose the glyph | |
1694 area. */ | |
1695 redisplay_normalize_display_box (db, dga); | |
1696 } | |
1697 assert (db->xpos >= 0 && db->ypos >= 0); | |
1698 | |
1699 MAYBE_DEVMETH (d, output_pixmap, (w, image_instance, | |
1700 db, dga, | |
1701 findex, cursor_start, | |
1702 cursor_width, cursor_height, | |
1703 offset_bitmap)); | |
1704 } | |
1705 | |
1706 /**************************************************************************** | |
1707 redisplay_clear_region | |
1708 | |
1709 Clear the area in the box defined by the given parameters using the | |
1710 given face. This has been generalised so that subwindows can be | |
1711 coped with effectively. | |
1712 ****************************************************************************/ | |
1713 void | |
1714 redisplay_clear_region (Lisp_Object locale, face_index findex, int x, int y, | |
1715 int width, int height) | |
1716 { | |
1717 struct window *w = NULL; | |
1718 struct frame *f = NULL; | |
1719 struct device *d; | |
1720 Lisp_Object background_pixmap = Qunbound; | |
1721 Lisp_Object fcolor = Qnil, bcolor = Qnil; | |
1722 | |
1723 if (!width || !height) | |
1724 return; | |
1725 | |
1726 if (WINDOWP (locale)) | |
1727 { | |
1728 w = XWINDOW (locale); | |
1729 f = XFRAME (w->frame); | |
1730 } | |
1731 else if (FRAMEP (locale)) | |
1732 { | |
1733 w = NULL; | |
1734 f = XFRAME (locale); | |
1735 } | |
1736 else | |
2500 | 1737 ABORT (); |
428 | 1738 |
1739 d = XDEVICE (f->device); | |
1740 | |
1741 /* if we have subwindows in the region we have to unmap them */ | |
1742 redisplay_unmap_subwindows_maybe (f, x, y, width, height); | |
1743 | |
1744 /* #### This isn't quite right for when this function is called | |
1745 from the toolbar code. */ | |
434 | 1746 |
428 | 1747 /* Don't use a backing pixmap in the border area */ |
1748 if (x >= FRAME_LEFT_BORDER_END (f) | |
1749 && x < FRAME_RIGHT_BORDER_START (f) | |
1750 && y >= FRAME_TOP_BORDER_END (f) | |
1751 && y < FRAME_BOTTOM_BORDER_START (f)) | |
1752 { | |
1753 Lisp_Object temp; | |
434 | 1754 |
428 | 1755 if (w) |
1756 { | |
1757 temp = WINDOW_FACE_CACHEL_BACKGROUND_PIXMAP (w, findex); | |
434 | 1758 |
428 | 1759 if (IMAGE_INSTANCEP (temp) |
1760 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp))) | |
1761 { | |
1762 /* #### maybe we could implement such that a string | |
1763 can be a background pixmap? */ | |
1764 background_pixmap = temp; | |
1765 } | |
1766 } | |
1767 else | |
1768 { | |
1769 temp = FACE_BACKGROUND_PIXMAP (Vdefault_face, locale); | |
434 | 1770 |
428 | 1771 if (IMAGE_INSTANCEP (temp) |
1772 && IMAGE_INSTANCE_PIXMAP_TYPE_P (XIMAGE_INSTANCE (temp))) | |
1773 { | |
1774 background_pixmap = temp; | |
1775 } | |
1776 } | |
434 | 1777 } |
428 | 1778 |
1779 if (!UNBOUNDP (background_pixmap) && | |
1780 XIMAGE_INSTANCE_PIXMAP_DEPTH (background_pixmap) == 0) | |
1781 { | |
1782 if (w) | |
1783 { | |
1784 fcolor = WINDOW_FACE_CACHEL_FOREGROUND (w, findex); | |
1785 bcolor = WINDOW_FACE_CACHEL_BACKGROUND (w, findex); | |
1786 } | |
1787 else | |
1788 { | |
1789 fcolor = FACE_FOREGROUND (Vdefault_face, locale); | |
1790 bcolor = FACE_BACKGROUND (Vdefault_face, locale); | |
1791 } | |
1792 } | |
1793 else | |
1794 { | |
1795 fcolor = (w ? | |
1796 WINDOW_FACE_CACHEL_BACKGROUND (w, findex) : | |
1797 FACE_BACKGROUND (Vdefault_face, locale)); | |
434 | 1798 |
428 | 1799 } |
434 | 1800 |
428 | 1801 if (UNBOUNDP (background_pixmap)) |
1802 background_pixmap = Qnil; | |
434 | 1803 |
1804 DEVMETH (d, clear_region, | |
428 | 1805 (locale, d, f, findex, x, y, width, height, fcolor, bcolor, background_pixmap)); |
1806 } | |
1807 | |
1808 /**************************************************************************** | |
1809 redisplay_clear_clipped_region | |
1810 | |
1811 Clear the area in the dest display_box not covered by the src | |
442 | 1812 display_glyph_area using the given face. This is a common occurrence |
428 | 1813 for images shorter than the display line. Clipping can be played |
1814 around with by altering these. glyphsrc should be normalized. | |
1815 ****************************************************************************/ | |
1816 static void | |
434 | 1817 redisplay_clear_clipped_region (Lisp_Object window, face_index findex, |
1818 struct display_box* dest, struct display_glyph_area* glyphsrc, | |
428 | 1819 int fullheight_p, Lisp_Object ignored_subwindow) |
1820 { | |
1821 /* assume dest->xpos >= 0 */ | |
1822 int clear_x; | |
1823 struct frame* f = XFRAME (XWINDOW (window)->frame); | |
1824 | |
1825 if (glyphsrc->xoffset > 0) | |
1826 { | |
1827 clear_x = dest->xpos + glyphsrc->xoffset; | |
1828 } | |
1829 else | |
1830 { | |
1831 clear_x = dest->xpos; | |
1832 } | |
1833 | |
1834 /* If we need the whole height cleared then just do it. */ | |
1835 if (fullheight_p) | |
1836 { | |
1837 redisplay_clear_region (window, findex, clear_x, dest->ypos, | |
1838 glyphsrc->width, dest->height); | |
1839 } | |
1840 else | |
1841 { | |
434 | 1842 int yoffset = (glyphsrc->yoffset > 0 ? glyphsrc->yoffset : 0); |
1843 | |
428 | 1844 /* We need to make sure that subwindows are unmapped from the |
4187 | 1845 whole area. */ |
428 | 1846 redisplay_unmap_subwindows_except_us (f, clear_x, dest->ypos, |
1847 glyphsrc->width, dest->height, | |
1848 ignored_subwindow); | |
1849 /* first the top box */ | |
1850 if (yoffset > 0) | |
1851 { | |
1852 redisplay_clear_region (window, findex, clear_x, dest->ypos, | |
1853 glyphsrc->width, yoffset); | |
434 | 1854 |
428 | 1855 } |
1856 /* Then the bottom box */ | |
1857 if (yoffset + glyphsrc->height < dest->height) | |
1858 { | |
1859 redisplay_clear_region (window, findex, clear_x, | |
1860 dest->ypos + yoffset + glyphsrc->height, | |
434 | 1861 glyphsrc->width, |
428 | 1862 dest->height - (yoffset + glyphsrc->height)); |
1863 | |
1864 } | |
1865 } | |
1866 } | |
1867 | |
1868 /***************************************************************************** | |
1869 redisplay_normalize_glyph_area | |
1870 redisplay_normalize_display_box | |
1871 | |
819 | 1872 Calculate the visible box for displaying glyphsrc in dest. |
1873 | |
1874 display_box and display_glyph_area are used to represent an area to | |
1875 displayed and where to display it. Using these two structures all | |
1876 combinations of clipping and position can be accommodated. | |
1877 | |
1878 dest - display_box | |
1879 | |
1880 xpos - absolute horizontal position of area. | |
1881 | |
4187 | 1882 ypos - absolute vertical position of area. |
819 | 1883 |
1884 glyphsrc - display_glyph_area | |
1885 | |
1886 xoffset - horizontal offset of the glyph, +ve means display | |
1887 the glyph with the x position offset by xoffset, -ve means | |
1888 display starting xoffset into the glyph. | |
1889 | |
1890 yoffset - vertical offset of the glyph, +ve means display the | |
1891 glyph with y position offset by yoffset, -ve means display | |
1892 starting xoffset into the glyph. | |
1893 | |
428 | 1894 ****************************************************************************/ |
1895 int | |
434 | 1896 redisplay_normalize_glyph_area (struct display_box* dest, |
428 | 1897 struct display_glyph_area* glyphsrc) |
1898 { | |
1899 if (dest->xpos + glyphsrc->xoffset > dest->xpos + dest->width | |
1900 || | |
1901 dest->ypos + glyphsrc->yoffset > dest->ypos + dest->height | |
1902 || | |
1903 -glyphsrc->xoffset >= glyphsrc->width | |
1904 || | |
448 | 1905 -glyphsrc->yoffset >= glyphsrc->height |
1906 || | |
1907 /* #### Not sure why this wasn't coped with before but normalizing | |
1908 to zero width or height is definitely wrong. */ | |
1909 (dest->xpos + glyphsrc->xoffset + glyphsrc->width > dest->xpos + dest->width | |
1910 && | |
1911 dest->width - glyphsrc->xoffset <= 0) | |
1912 || | |
1913 (dest->ypos + glyphsrc->yoffset + glyphsrc->height > dest->ypos + dest->height | |
1914 && | |
1915 dest->height - glyphsrc->yoffset <= 0)) | |
428 | 1916 { |
1917 /* It's all clipped out */ | |
1918 return 0; | |
1919 } | |
1920 | |
819 | 1921 /* Horizontal offsets. This works because xoffset can be -ve as well |
1922 as +ve. When we enter this function the glyphsrc width and | |
1923 height are set to the actual glyph width and height irrespective | |
1924 of how much can be displayed. We are trying to clip both the | |
1925 offset into the image and the rightmost bounding box. Its | |
1926 possible for the glyph width to be much larger than the area we | |
1927 are displaying into (e.g. a large glyph in a small frame). */ | |
428 | 1928 if (dest->xpos + glyphsrc->xoffset + glyphsrc->width > dest->xpos + dest->width) |
1929 { | |
819 | 1930 /* glyphsrc offset is +ve we are trying to display offset from the |
1931 origin (the bounding box contains some space and then the | |
1932 glyph). At most the width we want to display is dest->width - | |
1933 glyphsrc->xoffset. */ | |
428 | 1934 if (glyphsrc->xoffset > 0) |
1935 glyphsrc->width = dest->width - glyphsrc->xoffset; | |
819 | 1936 /* glyphsrc offset is -ve we are trying to display hard up |
1937 against the dest corner inset into the glyphsrc by | |
1938 xoffset.*/ | |
4187 | 1939 else if (glyphsrc->xoffset < 0) |
819 | 1940 { |
1941 glyphsrc->width += glyphsrc->xoffset; | |
1942 glyphsrc->width = min (glyphsrc->width, dest->width); | |
1943 } | |
428 | 1944 else |
1945 glyphsrc->width = dest->width; | |
1946 } | |
1947 | |
4187 | 1948 else if (glyphsrc->xoffset < 0) |
428 | 1949 glyphsrc->width += glyphsrc->xoffset; |
1950 | |
1951 /* Vertical offsets. This works because yoffset can be -ve as well as +ve */ | |
1952 if (dest->ypos + glyphsrc->yoffset + glyphsrc->height > dest->ypos + dest->height) | |
1953 { | |
819 | 1954 if ((glyphsrc->yoffset > 0) && (dest->height > glyphsrc->yoffset)) |
428 | 1955 glyphsrc->height = dest->height - glyphsrc->yoffset; |
4187 | 1956 else if (glyphsrc->yoffset < 0) |
819 | 1957 { |
1958 glyphsrc->height += glyphsrc->yoffset; | |
1959 glyphsrc->height = min (glyphsrc->height, dest->height); | |
1960 } | |
428 | 1961 else |
1962 glyphsrc->height = dest->height; | |
1963 } | |
1964 | |
819 | 1965 else if (glyphsrc->yoffset < 0) |
428 | 1966 glyphsrc->height += glyphsrc->yoffset; |
1967 | |
1968 return 1; | |
1969 } | |
1970 | |
1971 static void | |
434 | 1972 redisplay_normalize_display_box (struct display_box* dest, |
428 | 1973 struct display_glyph_area* glyphsrc) |
1974 { | |
1975 /* Adjust the destination area. At the end of this the destination | |
1976 area will exactly enclose the glyph area. The only remaining | |
1977 adjustment will be offsets into the glyph area. */ | |
1978 | |
1979 /* Horizontal adjustment. */ | |
1980 if (glyphsrc->xoffset > 0) | |
1981 { | |
1982 dest->xpos += glyphsrc->xoffset; | |
1983 dest->width -= glyphsrc->xoffset; | |
1984 glyphsrc->xoffset = 0; | |
1985 } | |
1986 else | |
1987 glyphsrc->xoffset = -glyphsrc->xoffset; | |
1988 | |
1989 if (glyphsrc->width < dest->width) | |
1990 dest->width = glyphsrc->width; | |
1991 | |
1992 /* Vertical adjustment. */ | |
1993 if (glyphsrc->yoffset > 0) | |
1994 { | |
1995 dest->ypos += glyphsrc->yoffset; | |
1996 dest->height -= glyphsrc->yoffset; | |
1997 glyphsrc->yoffset = 0; | |
1998 } | |
1999 else | |
2000 glyphsrc->yoffset = -glyphsrc->yoffset; | |
2001 | |
2002 if (glyphsrc->height < dest->height) | |
2003 dest->height = glyphsrc->height; | |
2004 } | |
2005 | |
2006 /***************************************************************************** | |
2007 redisplay_display_boxes_in_window_p | |
2008 | |
446 | 2009 Determine whether the required display_glyph_area is completely inside |
2010 the window. -1 means the display_box is not in the window. 1 means the | |
2011 display_box and the display_glyph_area are in the window. 0 means | |
428 | 2012 the display_box is in the window but the display_glyph_area is not. |
2013 ****************************************************************************/ | |
2014 static int | |
2015 redisplay_display_boxes_in_window_p (struct window* w, | |
2016 struct display_box* db, | |
2017 struct display_glyph_area* dga) | |
2018 { | |
2019 int left = WINDOW_TEXT_LEFT (w); | |
2020 int right = WINDOW_TEXT_RIGHT (w); | |
2021 int top = WINDOW_TEXT_TOP (w); | |
2022 int bottom = WINDOW_TEXT_BOTTOM (w); | |
2023 | |
2024 if (db->xpos < left || db->ypos < top | |
2025 || db->xpos + db->width > right | |
2026 || db->ypos + db->height > bottom) | |
446 | 2027 /* We are not displaying in a window at all */ |
2028 return -1; | |
434 | 2029 |
428 | 2030 if (db->xpos + dga->xoffset >= left |
2031 && | |
2032 db->ypos + dga->yoffset >= top | |
2033 && | |
2034 db->xpos + dga->xoffset + dga->width <= right | |
2035 && | |
2036 db->ypos + dga->yoffset + dga->height <= bottom) | |
2037 return 1; | |
2038 | |
446 | 2039 return 0; |
428 | 2040 } |
2041 | |
2042 /***************************************************************************** | |
2043 redisplay_calculate_display_boxes | |
2044 | |
2045 Convert from rune/display_line co-ordinates to display_box | |
2046 co-ordinates. | |
2047 ****************************************************************************/ | |
2048 int | |
2049 redisplay_calculate_display_boxes (struct display_line *dl, int xpos, | |
819 | 2050 int xoffset, int yoffset, int start_pixpos, |
4187 | 2051 int width, struct display_box* dest, |
428 | 2052 struct display_glyph_area* src) |
2053 { | |
2054 dest->xpos = xpos; | |
2055 dest->ypos = DISPLAY_LINE_YPOS (dl); | |
2056 dest->width = width; | |
2057 dest->height = DISPLAY_LINE_HEIGHT (dl); | |
2058 | |
2059 src->xoffset = -xoffset; | |
2060 src->width = 0; | |
2061 src->height = 0; | |
2062 | |
819 | 2063 src->yoffset = -dl->top_clip + yoffset; |
2064 | |
428 | 2065 if (start_pixpos >=0 && start_pixpos > xpos) |
2066 { | |
2067 /* Oops, we're asking for a start outside of the displayable | |
4187 | 2068 area. */ |
428 | 2069 if (start_pixpos > xpos + width) |
2070 return 0; | |
2071 dest->xpos = start_pixpos; | |
2072 dest->width -= (start_pixpos - xpos); | |
2073 /* Offsets are -ve when we want to clip pixels off the displayed | |
4187 | 2074 glyph. */ |
428 | 2075 src->xoffset -= (start_pixpos - xpos); |
2076 } | |
2077 | |
2078 return 1; | |
2079 } | |
2080 | |
2081 /***************************************************************************** | |
2082 redisplay_clear_top_of_window | |
2083 | |
2084 If window is topmost, clear the internal border above it. | |
2085 ****************************************************************************/ | |
448 | 2086 void |
428 | 2087 redisplay_clear_top_of_window (struct window *w) |
2088 { | |
793 | 2089 Lisp_Object window = wrap_window (w); |
2090 | |
428 | 2091 |
2092 if (!NILP (Fwindow_highest_p (window))) | |
2093 { | |
2094 struct frame *f = XFRAME (w->frame); | |
2095 int x, y, width, height; | |
2096 | |
2097 x = w->pixel_left; | |
2098 width = w->pixel_width; | |
2099 | |
2100 if (window_is_leftmost (w)) | |
2101 { | |
2102 x -= FRAME_BORDER_WIDTH (f); | |
2103 width += FRAME_BORDER_WIDTH (f); | |
2104 } | |
2105 if (window_is_rightmost (w)) | |
2106 width += FRAME_BORDER_WIDTH (f); | |
2107 | |
2108 y = FRAME_TOP_BORDER_START (f) - 1; | |
2109 height = FRAME_BORDER_HEIGHT (f) + 1; | |
2110 | |
2111 redisplay_clear_region (window, DEFAULT_INDEX, x, y, width, height); | |
2112 } | |
2113 } | |
2114 | |
2115 /***************************************************************************** | |
2116 redisplay_clear_to_window_end | |
2117 | |
2118 Clear the area between ypos1 and ypos2. Each margin area and the | |
2119 text area is handled separately since they may each have their own | |
2120 background color. | |
2121 ****************************************************************************/ | |
2122 void | |
2123 redisplay_clear_to_window_end (struct window *w, int ypos1, int ypos2) | |
2124 { | |
2125 struct frame *f = XFRAME (w->frame); | |
2126 struct device *d = XDEVICE (f->device); | |
2127 | |
2128 if (HAS_DEVMETH_P (d, clear_to_window_end)) | |
2129 DEVMETH (d, clear_to_window_end, (w, ypos1, ypos2)); | |
2130 else | |
2131 { | |
2132 int height = ypos2 - ypos1; | |
434 | 2133 |
428 | 2134 if (height) |
2135 { | |
2136 Lisp_Object window; | |
2137 int bflag = 0 ; /* (window_needs_vertical_divider (w) ? 0 : 1);*/ | |
2138 layout_bounds bounds; | |
434 | 2139 |
428 | 2140 bounds = calculate_display_line_boundaries (w, bflag); |
793 | 2141 window = wrap_window (w); |
428 | 2142 |
2143 if (window_is_leftmost (w)) | |
2144 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_LEFT_BORDER_START (f), | |
2145 ypos1, FRAME_BORDER_WIDTH (f), height); | |
434 | 2146 |
428 | 2147 if (bounds.left_in - bounds.left_out > 0) |
2148 redisplay_clear_region (window, | |
2149 get_builtin_face_cache_index (w, Vleft_margin_face), | |
2150 bounds.left_out, ypos1, | |
2151 bounds.left_in - bounds.left_out, height); | |
434 | 2152 |
428 | 2153 if (bounds.right_in - bounds.left_in > 0) |
434 | 2154 redisplay_clear_region (window, |
428 | 2155 DEFAULT_INDEX, |
2156 bounds.left_in, ypos1, | |
2157 bounds.right_in - bounds.left_in, height); | |
434 | 2158 |
428 | 2159 if (bounds.right_out - bounds.right_in > 0) |
2160 redisplay_clear_region (window, | |
2161 get_builtin_face_cache_index (w, Vright_margin_face), | |
2162 bounds.right_in, ypos1, | |
2163 bounds.right_out - bounds.right_in, height); | |
434 | 2164 |
428 | 2165 if (window_is_rightmost (w)) |
2166 redisplay_clear_region (window, DEFAULT_INDEX, FRAME_RIGHT_BORDER_START (f), | |
2167 ypos1, FRAME_BORDER_WIDTH (f), height); | |
2168 } | |
2169 } | |
2170 } | |
2171 | |
2172 /***************************************************************************** | |
2173 redisplay_clear_bottom_of_window | |
2174 | |
2175 Clear window from right below the last display line to right above | |
2176 the modeline. The calling function can limit the area actually | |
2177 erased by setting min_start and/or max_end to positive values. | |
2178 ****************************************************************************/ | |
2179 void | |
2180 redisplay_clear_bottom_of_window (struct window *w, display_line_dynarr *ddla, | |
2181 int min_start, int max_end) | |
2182 { | |
2183 struct frame *f = XFRAME (w->frame); | |
2184 int ypos1, ypos2; | |
2185 int ddla_len = Dynarr_length (ddla); | |
2186 | |
2187 ypos2 = WINDOW_TEXT_BOTTOM (w); | |
2188 #ifdef HAVE_SCROLLBARS | |
2189 /* This adjustment is to catch the intersection of any scrollbars. */ | |
2190 if (f->windows_structure_changed && NILP (w->scrollbar_on_top_p)) | |
2191 ypos2 += window_scrollbar_height (w); | |
2192 #endif | |
2193 | |
2194 if (ddla_len) | |
2195 { | |
2196 if (ddla_len == 1 && Dynarr_atp (ddla, 0)->modeline) | |
2197 { | |
2198 ypos1 = WINDOW_TEXT_TOP (w); | |
2199 #ifdef HAVE_SCROLLBARS | |
2200 /* This adjustment is to catch the intersection of any scrollbars. */ | |
2201 if (f->windows_structure_changed && !NILP (w->scrollbar_on_top_p)) | |
2202 ypos1 -= window_scrollbar_height (w); | |
2203 #endif | |
2204 } | |
2205 else | |
2206 { | |
2207 struct display_line *dl = Dynarr_atp (ddla, ddla_len - 1); | |
2208 ypos1 = dl->ypos + dl->descent - dl->clip; | |
2209 } | |
2210 } | |
2211 else | |
2212 ypos1 = WINDOW_TEXT_TOP (w); | |
2213 | |
2214 /* #### See if this can be made conditional on the frame | |
2215 changing size. */ | |
2216 if (MINI_WINDOW_P (w)) | |
2217 ypos2 += FRAME_BORDER_HEIGHT (f); | |
2218 | |
2219 if (min_start >= 0 && ypos1 < min_start) | |
2220 ypos1 = min_start; | |
2221 if (max_end >= 0 && ypos2 > max_end) | |
2222 ypos2 = max_end; | |
2223 | |
2224 if (ypos2 <= ypos1) | |
2225 return; | |
2226 | |
2227 redisplay_clear_to_window_end (w, ypos1, ypos2); | |
2228 } | |
2229 | |
2230 /***************************************************************************** | |
2231 redisplay_update_line | |
2232 | |
2233 This is used during incremental updates to update a single line and | |
2234 correct the offsets on all lines below it. At the moment | |
2235 update_values is false if we are only updating the modeline. | |
2236 ****************************************************************************/ | |
2237 void | |
2238 redisplay_update_line (struct window *w, int first_line, int last_line, | |
2239 int update_values) | |
2240 { | |
2241 struct frame *f = XFRAME (w->frame); | |
2242 struct device *d = XDEVICE (f->device); | |
2243 | |
2244 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP); | |
2245 display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP); | |
2246 | |
442 | 2247 MAYBE_DEVMETH (d, window_output_begin, (w)); |
428 | 2248 |
2249 while (first_line <= last_line) | |
2250 { | |
826 | 2251 Charcount old_len = (Dynarr_atp (cdla, first_line)->end_charpos - |
2252 Dynarr_atp (cdla, first_line)->charpos); | |
2253 Charcount new_len = (Dynarr_atp (ddla, first_line)->end_charpos - | |
2254 Dynarr_atp (ddla, first_line)->charpos); | |
428 | 2255 |
2256 assert (Dynarr_length (cdla) == Dynarr_length (ddla)); | |
2257 | |
2258 /* Output the changes. */ | |
2259 output_display_line (w, cdla, ddla, first_line, -1, -1); | |
2260 | |
2261 /* Update the offsets. */ | |
2262 if (update_values) | |
2263 { | |
2264 int cur_line = first_line + 1; | |
2265 while (cur_line < Dynarr_length (cdla)) | |
2266 { | |
2267 Dynarr_atp (cdla, cur_line)->offset += (new_len - old_len); | |
2268 Dynarr_atp (ddla, cur_line)->offset += (new_len - old_len); | |
2269 cur_line++; | |
2270 } | |
2271 } | |
2272 | |
2273 /* Update the window_end_pos and other settings. */ | |
2274 if (update_values) | |
2275 { | |
2276 w->window_end_pos[CURRENT_DISP] -= (new_len - old_len); | |
2277 | |
2278 if (Dynarr_atp (ddla, first_line)->cursor_elt != -1) | |
2279 { | |
2280 w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP]; | |
2281 w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP]; | |
2282 } | |
2283 } | |
2284 | |
2285 first_line++; | |
2286 } | |
2287 | |
2288 /* Update the window max line length. We have to scan the entire | |
2289 set of display lines otherwise we might not detect if the max is | |
2290 supposed to shrink. */ | |
2291 if (update_values) | |
2292 { | |
2293 int line = 0; | |
2294 | |
2295 w->max_line_len = 0; | |
2296 while (line < Dynarr_length (ddla)) | |
2297 { | |
2298 struct display_line *dl = Dynarr_atp (ddla, line); | |
2299 | |
2300 if (!dl->modeline) | |
2301 w->max_line_len = max (dl->num_chars, w->max_line_len); | |
2302 | |
2303 line++; | |
2304 } | |
2305 } | |
2306 | |
2307 w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP]; | |
2308 w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP]; | |
2309 Fset_marker (w->last_point[CURRENT_DISP], | |
2310 Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer); | |
2311 Fset_marker (w->last_start[CURRENT_DISP], | |
2312 Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer); | |
2313 | |
2314 /* We don't bother updating the vertical scrollbars here. This | |
2315 gives us a performance increase while having minimal loss of | |
2316 quality to the scrollbar slider size and position since when this | |
2317 function is called we know that the changes to the buffer were | |
2318 very localized. We have to update the horizontal scrollbars, | |
2319 though, because this routine could cause a change which has a | |
2320 larger impact on their sizing. */ | |
2321 /* #### See if we can get away with only calling this if | |
2322 max_line_len is greater than the window_char_width. */ | |
462 | 2323 /* #### BILL!!! Should we do this for GTK as well? */ |
428 | 2324 #if defined(HAVE_SCROLLBARS) && defined(HAVE_X_WINDOWS) |
2325 { | |
2326 extern int stupid_vertical_scrollbar_drag_hack; | |
2327 | |
2328 update_window_scrollbars (w, NULL, 1, stupid_vertical_scrollbar_drag_hack); | |
2329 stupid_vertical_scrollbar_drag_hack = 1; | |
2330 } | |
2331 #endif | |
2332 | |
442 | 2333 redisplay_redraw_cursor (f, 0); |
2334 MAYBE_DEVMETH (d, window_output_end, (w)); | |
428 | 2335 } |
2336 | |
2337 /***************************************************************************** | |
2338 redisplay_output_window | |
2339 | |
2340 For the given window W, ensure that the current display lines are | |
2341 equal to the desired display lines, outputing changes as necessary. | |
2342 | |
2343 #### Fuck me. This just isn't going to cut it for tty's. The output | |
2344 decisions for them must be based on the contents of the entire frame | |
2345 because that is how the available output capabilities think. The | |
2346 solution is relatively simple. Create redisplay_output_frame. This | |
2347 will basically merge all of the separate window display structs into | |
2348 a single one for the frame. This combination structure will be able | |
2349 to be passed to the same output_display_line which works for windows | |
2350 on X frames and the right things will happen. It just takes time to | |
2351 do. | |
2352 ****************************************************************************/ | |
2353 void | |
2354 redisplay_output_window (struct window *w) | |
2355 { | |
2356 struct frame *f = XFRAME (w->frame); | |
2357 struct device *d = XDEVICE (f->device); | |
2358 | |
2359 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP); | |
2360 display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP); | |
2361 | |
2362 int cdla_len = Dynarr_length (cdla); | |
2363 int ddla_len = Dynarr_length (ddla); | |
2364 | |
2365 int line; | |
2366 int need_to_clear_bottom = 0; | |
2367 int need_to_clear_start = -1; | |
2368 int need_to_clear_end = -1; | |
2369 | |
2370 /* Backgrounds may have changed or windows may have gone away | |
2371 leaving dividers lying around. */ | |
2372 if (f->faces_changed | |
2373 || f->windows_structure_changed | |
2374 || w->shadow_thickness_changed) | |
2375 need_to_clear_bottom = 1; | |
2376 | |
2377 /* The first thing we do is determine if we are going to need to | |
2378 clear the bottom of the window. We only need to do this if the | |
2379 bottom of the current display lines is below the bottom of the | |
2380 desired display lines. Note that the number of lines is | |
2381 irrelevant. Only the position matters. We also clear to the | |
2382 bottom of the window if the modeline has shifted position. */ | |
2383 /* #### We can't blindly not clear the bottom if f->clear is true | |
2384 since there might be a window-local background. However, for | |
2385 those cases where there isn't, clearing the end of the window in | |
2386 this case sucks. */ | |
2387 if (!need_to_clear_bottom) | |
2388 { | |
2389 struct display_line *cdl, *ddl; | |
2390 | |
2391 /* If the modeline has changed position or size, clear the bottom | |
2392 of the window. */ | |
2393 if (!need_to_clear_bottom) | |
2394 { | |
2395 cdl = ddl = 0; | |
2396 | |
2397 if (cdla_len) | |
2398 cdl = Dynarr_atp (cdla, 0); | |
2399 if (ddla_len) | |
2400 ddl = Dynarr_atp (ddla, 0); | |
2401 | |
2402 if (!cdl || !ddl) | |
2403 need_to_clear_bottom = 1; | |
2404 else if ((!cdl->modeline && ddl->modeline) | |
2405 || (cdl->modeline && !ddl->modeline)) | |
2406 need_to_clear_bottom = 1; | |
2407 else if (cdl->ypos != ddl->ypos || | |
2408 cdl->ascent != ddl->ascent || | |
2409 cdl->descent != ddl->descent || | |
2410 cdl->clip != ddl->clip) | |
2411 need_to_clear_bottom = 1; | |
2412 | |
2413 /* #### This kludge is to make sure the modeline shadows get | |
2414 redrawn if the modeline position shifts. */ | |
2415 if (need_to_clear_bottom) | |
2416 w->shadow_thickness_changed = 1; | |
2417 } | |
2418 | |
2419 if (!need_to_clear_bottom) | |
2420 { | |
2421 cdl = ddl = 0; | |
2422 | |
2423 if (cdla_len) | |
2424 cdl = Dynarr_atp (cdla, cdla_len - 1); | |
2425 if (ddla_len) | |
2426 ddl = Dynarr_atp (ddla, ddla_len - 1); | |
2427 | |
2428 if (!cdl || !ddl) | |
2429 need_to_clear_bottom = 1; | |
2430 else | |
2431 { | |
2432 int cdl_bottom, ddl_bottom; | |
2433 | |
2434 cdl_bottom = cdl->ypos + cdl->descent; | |
2435 ddl_bottom = ddl->ypos + ddl->descent; | |
2436 | |
2437 if (cdl_bottom > ddl_bottom) | |
2438 { | |
2439 need_to_clear_bottom = 1; | |
2440 need_to_clear_start = ddl_bottom; | |
2441 need_to_clear_end = cdl_bottom; | |
2442 } | |
2443 } | |
2444 } | |
2445 } | |
2446 | |
2447 /* Perform any output initialization. */ | |
442 | 2448 MAYBE_DEVMETH (d, window_output_begin, (w)); |
428 | 2449 |
2450 /* If the window's structure has changed clear the internal border | |
2451 above it if it is topmost (the function will check). */ | |
448 | 2452 if (f->windows_structure_changed || f->faces_changed) |
428 | 2453 redisplay_clear_top_of_window (w); |
2454 | |
2455 /* Output each line. */ | |
2456 for (line = 0; line < Dynarr_length (ddla); line++) | |
2457 { | |
2458 output_display_line (w, cdla, ddla, line, -1, -1); | |
2459 } | |
2460 | |
2461 /* If the number of display lines has shrunk, adjust. */ | |
2462 if (cdla_len > ddla_len) | |
2463 { | |
2464 Dynarr_length (cdla) = ddla_len; | |
2465 } | |
2466 | |
2467 /* Output a vertical divider between windows, if necessary. */ | |
2468 if (window_needs_vertical_divider (w) | |
2469 && (f->windows_structure_changed || f->clear)) | |
2470 { | |
442 | 2471 MAYBE_DEVMETH (d, output_vertical_divider, (w, f->windows_structure_changed)); |
428 | 2472 } |
2473 | |
2474 /* Clear the rest of the window, if necessary. */ | |
2475 if (need_to_clear_bottom) | |
2476 { | |
2477 redisplay_clear_bottom_of_window (w, ddla, need_to_clear_start, | |
2478 need_to_clear_end); | |
2479 } | |
2480 | |
2481 w->window_end_pos[CURRENT_DISP] = w->window_end_pos[DESIRED_DISP]; | |
2482 Fset_marker (w->start[CURRENT_DISP], | |
2483 make_int (marker_position (w->start[DESIRED_DISP])), | |
2484 w->buffer); | |
2485 Fset_marker (w->pointm[CURRENT_DISP], | |
2486 make_int (marker_position (w->pointm[DESIRED_DISP])), | |
2487 w->buffer); | |
2488 w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP]; | |
2489 w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP]; | |
2490 Fset_marker (w->last_start[CURRENT_DISP], | |
2491 Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer); | |
2492 Fset_marker (w->last_point[CURRENT_DISP], | |
2493 Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer); | |
2494 w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP]; | |
2495 w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP]; | |
2496 w->shadow_thickness_changed = 0; | |
2497 | |
2498 set_window_display_buffer (w, XBUFFER (w->buffer)); | |
2499 find_window_mirror (w)->truncate_win = window_truncation_on (w); | |
2500 | |
2501 /* Overkill on invalidating the cache. It is very bad for it to not | |
2502 get invalidated when it should be. */ | |
2503 INVALIDATE_DEVICE_PIXEL_TO_GLYPH_CACHE (d); | |
2504 | |
442 | 2505 redisplay_redraw_cursor (f, 0); |
2506 MAYBE_DEVMETH (d, window_output_end, (w)); | |
428 | 2507 |
2508 #ifdef HAVE_SCROLLBARS | |
2509 update_window_scrollbars (w, NULL, !MINI_WINDOW_P (w), 0); | |
2510 #endif | |
2511 } | |
2512 | |
2513 /***************************************************************************** | |
1318 | 2514 redisplay_redraw_exposed_window |
2515 | |
2516 Given a bounding box for an area that needs to be redrawn, determine | |
2517 what parts of what lines are contained within and re-output their | |
2518 contents. | |
2519 ****************************************************************************/ | |
2520 static void | |
2521 redisplay_redraw_exposed_window (struct window *w, int x, int y, int width, | |
2522 int height) | |
2523 { | |
2524 struct frame *f = XFRAME (w->frame); | |
2525 int line; | |
2526 int start_x, start_y, end_x, end_y; | |
2527 int orig_windows_structure_changed; | |
2528 | |
2529 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP); | |
2530 | |
2531 if (!NILP (w->vchild)) | |
2532 { | |
2533 redisplay_redraw_exposed_windows (w->vchild, x, y, width, height); | |
2534 return; | |
2535 } | |
2536 else if (!NILP (w->hchild)) | |
2537 { | |
2538 redisplay_redraw_exposed_windows (w->hchild, x, y, width, height); | |
2539 return; | |
2540 } | |
2541 | |
2542 /* If the window doesn't intersect the exposed region, we're done here. */ | |
2543 if (x >= WINDOW_RIGHT (w) || (x + width) <= WINDOW_LEFT (w) | |
2544 || y >= WINDOW_BOTTOM (w) || (y + height) <= WINDOW_TOP (w)) | |
2545 { | |
2546 return; | |
2547 } | |
2548 else | |
2549 { | |
2550 start_x = max (WINDOW_LEFT (w), x); | |
2551 end_x = min (WINDOW_RIGHT (w), (x + width)); | |
2552 start_y = max (WINDOW_TOP (w), y); | |
2553 end_y = min (WINDOW_BOTTOM (w), y + height); | |
2554 | |
2555 /* We do this to make sure that the 3D modelines get redrawn if | |
4187 | 2556 they are in the exposed region. */ |
1318 | 2557 orig_windows_structure_changed = f->windows_structure_changed; |
2558 f->windows_structure_changed = 1; | |
2559 } | |
2560 | |
2561 /* #### Not in GTK or MS Windows. I think is because of toolbars, which | |
2562 are handled as widgets in GTK and MS Windows, but drawn ourselves in | |
2563 X. For the moment I'm leaving this in, if it causes problems we have | |
2564 some device method indicating whether we're drawing our own | |
2565 toolbars. */ | |
2566 redisplay_clear_top_of_window (w); | |
2567 if (window_needs_vertical_divider (w)) | |
2568 { | |
2569 FRAMEMETH (f, output_vertical_divider, (w, 0)); | |
2570 } | |
2571 | |
2572 for (line = 0; line < Dynarr_length (cdla); line++) | |
2573 { | |
2574 struct display_line *cdl = Dynarr_atp (cdla, line); | |
2575 int top_y = DISPLAY_LINE_YPOS (cdl); | |
2576 int bottom_y = DISPLAY_LINE_YPOS (cdl) + DISPLAY_LINE_HEIGHT (cdl); | |
2577 | |
2578 if (bottom_y >= start_y) | |
2579 { | |
2580 if (top_y > end_y) | |
2581 { | |
2582 if (line == 0) | |
2583 continue; | |
2584 else | |
2585 break; | |
2586 } | |
2587 else | |
2588 { | |
2589 output_display_line (w, 0, cdla, line, start_x, end_x); | |
2590 } | |
2591 } | |
2592 } | |
2593 | |
2594 f->windows_structure_changed = orig_windows_structure_changed; | |
2595 | |
2596 /* If there have never been any face cache_elements created, then this | |
2597 expose event doesn't actually have anything to do. */ | |
2598 if (Dynarr_largest (w->face_cachels)) | |
2599 redisplay_clear_bottom_of_window (w, cdla, start_y, end_y); | |
2600 | |
2601 #ifdef HAVE_SCROLLBARS | |
2602 MAYBE_FRAMEMETH (f, redisplay_deadbox, (w, x, y, width, height)); | |
2603 #endif | |
2604 } | |
2605 | |
2606 | |
2607 /***************************************************************************** | |
2608 redisplay_redraw_exposed_windows | |
2609 | |
2610 For each window beneath the given window in the window hierarchy, | |
2611 ensure that it is redrawn if necessary after an Expose event. | |
2612 ****************************************************************************/ | |
2613 static void | |
2614 redisplay_redraw_exposed_windows (Lisp_Object window, int x, int y, int width, | |
2615 int height) | |
2616 { | |
2617 for (; !NILP (window); window = XWINDOW (window)->next) | |
2618 redisplay_redraw_exposed_window (XWINDOW (window), x, y, width, height); | |
2619 } | |
2620 | |
2621 static void | |
2622 redisplay_redraw_exposed_area_1 (Lisp_Object arg) | |
2623 { | |
2624 assert (!in_display); | |
2625 redisplay_redraw_exposed_area (XFRAME (X1ST (arg)), | |
2626 XINT (X2ND (arg)), | |
2627 XINT (X3RD (arg)), | |
2628 XINT (X4TH (arg)), | |
2629 XINT (X5TH (arg))); | |
2630 free_list (arg); | |
2631 } | |
2632 | |
2633 /***************************************************************************** | |
2634 redisplay_redraw_exposed_area | |
2635 | |
2636 For each window on the given frame, ensure that any area in the | |
2637 Exposed area is redrawn. | |
2638 ****************************************************************************/ | |
2639 void | |
2640 redisplay_redraw_exposed_area (struct frame *f, int x, int y, int width, | |
2641 int height) | |
2642 { | |
2643 int depth; | |
2644 | |
2645 if (in_display) | |
2646 { | |
2647 /* Not safe to do it now, so delay it */ | |
2648 register_post_redisplay_action (redisplay_redraw_exposed_area_1, | |
2649 list5 (wrap_frame (f), make_int (x), | |
2650 make_int (y), make_int (width), | |
2651 make_int (height))); | |
2652 return; | |
2653 } | |
2654 | |
2655 depth = enter_redisplay_critical_section (); | |
2656 | |
2657 MAYBE_FRAMEMETH (f, frame_output_begin, (f)); | |
2658 | |
2659 /* If any window on the frame has had its face cache reset then the | |
2660 redisplay structures are effectively invalid. If we attempt to | |
2661 use them we'll blow up. We mark the frame as changed to ensure | |
2662 that redisplay will do a full update. This probably isn't | |
2663 necessary but it can't hurt. */ | |
2664 #ifdef HAVE_TOOLBARS | |
2665 /* #### We would rather put these off as well but there is currently | |
2666 no combination of flags which will force an unchanged toolbar to | |
2667 redraw anyhow. */ | |
2668 MAYBE_FRAMEMETH (f, redraw_exposed_toolbars, (f, x, y, width, height)); | |
2669 #endif | |
2670 redraw_exposed_gutters (f, x, y, width, height); | |
2671 | |
2672 if (!f->window_face_cache_reset) | |
2673 { | |
2674 redisplay_redraw_exposed_windows (f->root_window, x, y, width, height); | |
2675 /* #### Why not call this always? */ | |
2676 MAYBE_FRAMEMETH (f, frame_output_end, (f)); | |
2677 } | |
2678 else | |
2679 MARK_FRAME_CHANGED (f); | |
2680 | |
2681 exit_redisplay_critical_section (depth); | |
2682 } | |
2683 | |
2684 /***************************************************************************** | |
428 | 2685 bevel_modeline |
2686 | |
2687 Draw a 3d border around the modeline on window W. | |
2688 ****************************************************************************/ | |
2689 void | |
2690 bevel_modeline (struct window *w, struct display_line *dl) | |
2691 { | |
2692 struct frame *f = XFRAME (w->frame); | |
2693 struct device *d = XDEVICE (f->device); | |
2694 int x, y, width, height; | |
2695 int shadow_thickness = MODELINE_SHADOW_THICKNESS (w); | |
2696 enum edge_style style; | |
2697 | |
2698 x = WINDOW_MODELINE_LEFT (w); | |
2699 width = WINDOW_MODELINE_RIGHT (w) - x; | |
2700 y = dl->ypos - dl->ascent - shadow_thickness; | |
2701 height = dl->ascent + dl->descent + 2 * shadow_thickness; | |
2702 | |
2703 if (XINT (w->modeline_shadow_thickness) < 0) | |
2704 { | |
2705 style = EDGE_BEVEL_IN; | |
2706 } | |
2707 else | |
2708 { | |
2709 style = EDGE_BEVEL_OUT; | |
2710 } | |
2711 | |
434 | 2712 MAYBE_DEVMETH (d, bevel_area, |
428 | 2713 (w, MODELINE_INDEX, x, y, width, height, shadow_thickness, |
2714 EDGE_ALL, style)); | |
2715 } |