Index: src/extents.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/extents.c,v retrieving revision 1.27.2.20 diff -u -r1.27.2.20 extents.c --- src/extents.c 2000/02/29 21:05:52 1.27.2.20 +++ src/extents.c 2000/03/04 15:58:57 @@ -227,6 +227,7 @@ #include "opaque.h" #include "process.h" #include "redisplay.h" +#include "gutter.h" /* ------------------------------- */ /* gap array */ @@ -461,7 +462,6 @@ /* FSFmacs bogosity */ Lisp_Object Vdefault_text_properties; - EXFUN (Fextent_properties, 1); EXFUN (Fset_extent_property, 3); @@ -1589,33 +1589,46 @@ object = extent_object (extent); - if (!BUFFERP (object) || extent_detached_p (extent)) - /* #### Can changes to string extents affect redisplay? - I will have to think about this. What about string glyphs? - Things in the modeline? etc. */ - /* #### changes to string extents can certainly affect redisplay - if the extent is in some generated-modeline-string: when - we change an extent in generated-modeline-string, this changes - its parent, which is in `modeline-format', so we should - force the modeline to be updated. But how to determine whether - a string is a `generated-modeline-string'? Looping through - all buffers is not very efficient. Should we add all - `generated-modeline-string' strings to a hash table? - Maybe efficiency is not the greatest concern here and there's - no big loss in looping over the buffers. */ + if (extent_detached_p (extent)) return; - { - struct buffer *b; - b = XBUFFER (object); - BUF_FACECHANGE (b)++; - MARK_EXTENTS_CHANGED; - if (invisibility_change) - MARK_CLIP_CHANGED; - buffer_extent_signal_changed_region (b, - extent_endpoint_bufpos (extent, 0), - extent_endpoint_bufpos (extent, 1)); - } + else if (STRINGP (object)) + { + /* #### Changes to string extents can affect redisplay if they are + in the modeline or in the gutters. + + If the extent is in some generated-modeline-string: when we + change an extent in generated-modeline-string, this changes its + parent, which is in `modeline-format', so we should force the + modeline to be updated. But how to determine whether a string + is a `generated-modeline-string'? Looping through all buffers + is not very efficient. Should we add all + `generated-modeline-string' strings to a hash table? Maybe + efficiency is not the greatest concern here and there's no big + loss in looping over the buffers. + + If the extent is in a gutter we mark the gutter as + changed. This means (a) we can update extents in the gutters + when we need it. (b) we don't have to update the gutters when + only extents attached to buffers have changed. */ + + MARK_EXTENTS_CHANGED; + gutter_extent_signal_changed_region_maybe (object, + extent_endpoint_bufpos (extent, 0), + extent_endpoint_bufpos (extent, 1)); + } + else if (BUFFERP (object)) + { + struct buffer *b; + b = XBUFFER (object); + BUF_FACECHANGE (b)++; + MARK_EXTENTS_CHANGED; + if (invisibility_change) + MARK_CLIP_CHANGED; + buffer_extent_signal_changed_region (b, + extent_endpoint_bufpos (extent, 0), + extent_endpoint_bufpos (extent, 1)); + } } /* A change to an extent occurred that might affect redisplay. Index: src/frame.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/frame.h,v retrieving revision 1.18.2.13 diff -u -r1.18.2.13 frame.h --- src/frame.h 2000/03/01 17:47:07 1.18.2.13 +++ src/frame.h 2000/03/04 15:59:00 @@ -115,11 +115,15 @@ in redisplay_frame. */ unsigned int current_toolbar_size[4]; #endif + + /* Size of gutters as seen by redisplay. This is used to determine + whether to re-layout windows by a call to change_frame_size early + in redisplay_frame. */ unsigned int current_gutter_bounds[4]; - /* Dynamic array of display lines for gutters */ - display_line_dynarr *current_display_lines; - display_line_dynarr *desired_display_lines; + /* Dynamic arrays of display lines for gutters */ + display_line_dynarr *current_display_lines[4]; + display_line_dynarr *desired_display_lines[4]; /* A structure of auxiliary data specific to the device type. struct x_frame is used for X window frames; defined in console-x.h */ Index: src/gutter.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/Attic/gutter.c,v retrieving revision 1.1.2.23 diff -u -r1.1.2.23 gutter.c --- src/gutter.c 2000/03/02 13:20:42 1.1.2.23 +++ src/gutter.c 2000/03/04 15:59:19 @@ -244,7 +244,7 @@ } static void -output_gutter (struct frame *f, enum gutter_pos pos) +output_gutter (struct frame *f, enum gutter_pos pos, int force) { Lisp_Object frame; Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW (f); @@ -263,13 +263,13 @@ border_width = FRAME_GUTTER_BORDER_WIDTH (f, pos); findex = get_builtin_face_cache_index (w, Vgui_element_face); - if (!f->current_display_lines) - f->current_display_lines = Dynarr_new (display_line); - if (!f->desired_display_lines) - f->desired_display_lines = Dynarr_new (display_line); + if (!f->current_display_lines[pos]) + f->current_display_lines[pos] = Dynarr_new (display_line); + if (!f->desired_display_lines[pos]) + f->desired_display_lines[pos] = Dynarr_new (display_line); - ddla = f->desired_display_lines; - cdla = f->current_display_lines; + ddla = f->desired_display_lines[pos]; + cdla = f->current_display_lines[pos]; cdla_len = Dynarr_length (cdla); XSETFRAME (frame, f); @@ -280,30 +280,54 @@ x + border_width, y + border_width, width - 2 * border_width, height - 2 * border_width, ddla, 0, findex); - /* Output each line. */ - for (line = 0; line < Dynarr_length (ddla); line++) - { - output_display_line (w, cdla, ddla, line, -1, -1); - } - /* If the number of display lines has shrunk, adjust. */ - if (cdla_len > Dynarr_length (ddla)) + /* We only output the gutter if we think something of significance + has changed. This is, for example, because redisplay can cause + new face cache elements to get added causing compare_runes to + fail because the findex for a particular face has changed. */ + if (force || f->faces_changed || f->frame_changed || + f->gutter_changed || f->glyphs_changed || + f->size_changed || f->subwindows_changed || + w->windows_changed || f->windows_structure_changed || + cdla_len != Dynarr_length (ddla) || + (f->extents_changed && w->gutter_extent_modiff[pos])) { - Dynarr_length (cdla) = Dynarr_length (ddla); + /* Output each line. */ + for (line = 0; line < Dynarr_length (ddla); line++) + { + output_display_line (w, cdla, ddla, line, -1, -1); + } + + /* If the number of display lines has shrunk, adjust. */ + if (cdla_len > Dynarr_length (ddla)) + { + Dynarr_length (cdla) = Dynarr_length (ddla); + } + + /* grab coordinates of last line and blank after it. */ + dl = Dynarr_atp (ddla, Dynarr_length (ddla) - 1); + ypos = dl->ypos + dl->descent - dl->clip; + redisplay_clear_region (window, findex, x + border_width , ypos, + width - 2 * border_width, height - (ypos - y) - border_width); + /* bevel the gutter area if so desired */ + if (border_width != 0) + { + MAYBE_DEVMETH (d, bevel_area, + (w, findex, x, y, width, height, border_width, + EDGE_ALL, EDGE_BEVEL_OUT)); + } } - - /* grab coordinates of last line and blank after it. */ - dl = Dynarr_atp (ddla, Dynarr_length (ddla) - 1); - ypos = dl->ypos + dl->descent - dl->clip; - redisplay_clear_region (window, findex, x + border_width , ypos, - width - 2 * border_width, height - (ypos - y) - border_width); - /* bevel the gutter area if so desired */ - if (border_width != 0) + else { - MAYBE_DEVMETH (d, bevel_area, - (w, findex, x, y, width, height, border_width, - EDGE_ALL, EDGE_BEVEL_OUT)); + /* Nothing of significance happened so sync the display line + structs. */ + for (line = 0; line < Dynarr_length (ddla); line++) + { + sync_display_line_structs (w, line, 1, cdla, ddla); + } } + + w->gutter_extent_modiff [pos] = 0; } /* sizing gutters is a pain so we try and help the user by detemining @@ -375,20 +399,54 @@ the glyph will also mark the image_instance. */ void mark_gutters (struct frame* f) +{ + enum gutter_pos pos; + GUTTER_POS_LOOP (pos) + { + if (f->current_display_lines[pos]) + mark_redisplay_structs (f->current_display_lines[pos]); + /* #### Do we really need to mark the desired lines? */ + if (f->desired_display_lines[pos]) + mark_redisplay_structs (f->desired_display_lines[pos]); + } +} + +/* This is called by extent_changed_for_redisplay, so that redisplay + knows exactly what extents have changed. */ +void +gutter_extent_signal_changed_region_maybe (Lisp_Object obj, + Bufpos start, Bufpos end) { - if (f->current_display_lines) - mark_redisplay_structs (f->current_display_lines); - if (f->desired_display_lines) - mark_redisplay_structs (f->desired_display_lines); + /* #### Start and end are currently ignored but could be used by a + more optimal gutter redisplay. We currently loop over all frames + here, this could be optimized. */ + Lisp_Object frmcons, devcons, concons; + + FRAME_LOOP_NO_BREAK (frmcons, devcons, concons) + { + struct frame *f = XFRAME (XCAR (frmcons)); + enum gutter_pos pos; + Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW (f); + struct window* w = XWINDOW (window); + + GUTTER_POS_LOOP (pos) + { + if (EQ (WINDOW_GUTTER (w, pos), obj)) + { + w->gutter_extent_modiff[pos]++; + } + } + } } void update_frame_gutters (struct frame *f) { - if (f->gutter_changed || f->clear || - f->glyphs_changed || f->subwindows_changed || - f->windows_changed || f->windows_structure_changed || - f->extents_changed || f->faces_changed) + if (f->faces_changed || f->frame_changed || + f->gutter_changed || f->glyphs_changed || + f->size_changed || f->subwindows_changed || + f->windows_changed || f->windows_structure_changed || + f->extents_changed) { enum gutter_pos pos; @@ -396,6 +454,8 @@ so locally disable them. */ int local_clip_changed = f->clip_changed; int local_buffers_changed = f->buffers_changed; + f->clip_changed = 0; + f->buffers_changed = 0; /* If the gutter geometry has changed then re-layout the frame. */ @@ -409,24 +469,21 @@ change_frame_size (f, height, width, 0); break; } - } - - GUTTER_POS_LOOP (pos) - { - f->current_gutter_bounds[pos] = FRAME_GUTTER_BOUNDS (f, pos); } - - f->clip_changed = 0; - f->buffers_changed = 0; - + /* and output */ GUTTER_POS_LOOP (pos) { if (FRAME_GUTTER_VISIBLE (f, pos)) - output_gutter (f, pos); + output_gutter (f, pos, 0); + else if (gutter_was_visible (f, pos)) - clear_gutter (f, pos); + clear_gutter (f, pos); + + /* Mark sizes as up-to-date. */ + f->current_gutter_bounds[pos] = FRAME_GUTTER_BOUNDS (f, pos); } + f->clip_changed = local_clip_changed; f->buffers_changed = local_buffers_changed; f->gutter_changed = 0; @@ -436,8 +493,12 @@ void reset_gutter_display_lines (struct frame* f) { - if (f->current_display_lines) - Dynarr_reset (f->current_display_lines); + enum gutter_pos pos; + GUTTER_POS_LOOP (pos) + { + if (f->current_display_lines[pos]) + Dynarr_reset (f->current_display_lines[pos]); + } } static void @@ -461,7 +522,7 @@ /* Even if none of the gutter is in the area, the blank region at the very least must be because the first thing we did is verify that some portion of the gutter is in the exposed region. */ - output_gutter (f, pos); + output_gutter (f, pos, 1); } void @@ -479,15 +540,19 @@ void free_frame_gutters (struct frame *f) { - if (f->current_display_lines) - { - free_display_lines (f->current_display_lines); - f->current_display_lines = 0; - } - if (f->desired_display_lines) + enum gutter_pos pos; + GUTTER_POS_LOOP (pos) { - free_display_lines (f->desired_display_lines); - f->desired_display_lines = 0; + if (f->current_display_lines[pos]) + { + free_display_lines (f->current_display_lines[pos]); + f->current_display_lines[pos] = 0; + } + if (f->desired_display_lines[pos]) + { + free_display_lines (f->desired_display_lines[pos]); + f->desired_display_lines[pos] = 0; + } } } Index: src/gutter.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/Attic/gutter.h,v retrieving revision 1.1.2.10 diff -u -r1.1.2.10 gutter.h --- src/gutter.h 2000/03/01 17:47:08 1.1.2.10 +++ src/gutter.h 2000/03/04 15:59:20 @@ -62,6 +62,8 @@ void redraw_exposed_gutters (struct frame *f, int x, int y, int width, int height); void reset_gutter_display_lines (struct frame* f); +void gutter_extent_signal_changed_region_maybe (Lisp_Object obj, + Bufpos start, Bufpos end); #define WINDOW_GUTTER_BORDER_WIDTH(w, pos) \ (INTP ((w)->gutter_border_width[pos]) ? XINT ((w)->gutter_border_width[pos]) : 0) Index: src/redisplay-output.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/redisplay-output.c,v retrieving revision 1.11.2.28 diff -u -r1.11.2.28 redisplay-output.c --- src/redisplay-output.c 2000/02/13 20:22:27 1.11.2.28 +++ src/redisplay-output.c 2000/03/04 15:59:27 @@ -101,7 +101,7 @@ For the given LINE in window W, make the current display line equal the desired display line. ****************************************************************************/ -static void +void sync_display_line_structs (struct window *w, int line, int do_blocks, display_line_dynarr *cdla, display_line_dynarr *ddla) @@ -236,17 +236,9 @@ return 0; /* Only check dirtiness if we know something has changed. */ else if (crb->type == RUNE_DGLYPH && - XFRAME (w->frame)->glyphs_changed) - { - glyph_index gindex = get_glyph_cachel_index (w, drb->object.dglyph.glyph); - /* Although doing the cachel lookup for every comparison is - very expensive.we have to do it to make sure the cache is - up-to-date. */ - if (GLYPH_CACHEL_DIRTYP (w, gindex)) - return 0; - else - return 1; - } + XFRAME (w->frame)->glyphs_changed && + XGLYPH_DIRTYP (crb->object.dglyph.glyph)) + return 0; else return 1; } Index: src/redisplay.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/redisplay.c,v retrieving revision 1.55.2.42 diff -u -r1.55.2.42 redisplay.c --- src/redisplay.c 2000/03/01 17:47:10 1.55.2.42 +++ src/redisplay.c 2000/03/04 15:59:55 @@ -1528,10 +1528,10 @@ glyph sizes might have changed too */ invalidate_glyph_geometry_maybe (gb->glyph, w); - /* This makes sure the glyph is in the cachels. - - #### We need to change this so that we hold onto the glyph_index - here, not the glyph itself. */ + /* #### We do this to make sure the glyph is in the glyph cachels, + so that the dirty flag can be reset after redisplay has + finished. We should do this some other way, maybe by iterating + over the window cache of subwindows. */ get_glyph_cachel_index (w, gb->glyph); /* A nil extent indicates a special glyph (ex. truncator). */ Index: src/redisplay.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/redisplay.h,v retrieving revision 1.7.2.21 diff -u -r1.7.2.21 redisplay.h --- src/redisplay.h 2000/02/23 22:29:42 1.7.2.21 +++ src/redisplay.h 2000/03/04 15:59:59 @@ -783,5 +783,8 @@ void output_display_line (struct window *w, display_line_dynarr *cdla, display_line_dynarr *ddla, int line, int force_start, int force_end); +void sync_display_line_structs (struct window *w, int line, int do_blocks, + display_line_dynarr *cdla, + display_line_dynarr *ddla); #endif /* INCLUDED_redisplay_h_ */ Index: src/window.c =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/window.c,v retrieving revision 1.41.2.41 diff -u -r1.41.2.41 window.c --- src/window.c 2000/03/01 17:47:11 1.41.2.41 +++ src/window.c 2000/03/04 16:00:17 @@ -290,6 +290,11 @@ INIT_DISP_VARIABLE (window_end_pos, 0); p->redisplay_end_trigger = Qnil; + p->gutter_extent_modiff[0] = 0; + p->gutter_extent_modiff[1] = 0; + p->gutter_extent_modiff[2] = 0; + p->gutter_extent_modiff[3] = 0; + #define WINDOW_SLOT(slot, compare) p->slot = Qnil #include "winslots.h" Index: src/window.h =================================================================== RCS file: /usr/CVSroot/XEmacs/xemacs/src/window.h,v retrieving revision 1.13.2.11 diff -u -r1.13.2.11 window.h --- src/window.h 2000/02/03 21:17:57 1.13.2.11 +++ src/window.h 2000/03/04 16:00:19 @@ -184,6 +184,9 @@ must run the redisplay-end-trigger-functions. */ Lisp_Object redisplay_end_trigger; + /* Set by the extent code when extents in the gutter are changed. */ + int gutter_extent_modiff[4]; + /* Set by redisplay to the last position seen. This is used to implement the redisplay-end-trigger-functions. */ Bufpos last_redisplay_pos;