Build Fix -- compatibility issue with newer autoconf
[sxemacs] / src / ui / gutter.c
1 /* Gutter implementation.
2    Copyright (C) 1999, 2000 Andy Piper.
3
4 This file is part of SXEmacs
5
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
18
19
20 /* Synched up with: Not in FSF. */
21
22 /* written by Andy Piper <andy@xemacs.org> with specifiers partially
23    ripped-off from toolbar.c */
24
25 #include <config.h>
26 #include "lisp.h"
27
28 #include "buffer.h"
29 #include "frame.h"
30 #include "device.h"
31 #include "faces.h"
32 #include "glyphs.h"
33 #include "redisplay.h"
34 #include "window.h"
35 #include "gutter.h"
36
37 Lisp_Object Vgutter[4];
38 Lisp_Object Vgutter_size[4];
39 Lisp_Object Vgutter_visible_p[4];
40 Lisp_Object Vgutter_border_width[4];
41
42 Lisp_Object Vdefault_gutter, Vdefault_gutter_visible_p;
43 Lisp_Object Vdefault_gutter_width, Vdefault_gutter_height;
44 Lisp_Object Vdefault_gutter_border_width;
45
46 Lisp_Object Vdefault_gutter_position;
47
48 Lisp_Object Qgutter_size;
49 Lisp_Object Qgutter_visible;
50 Lisp_Object Qdefault_gutter_position_changed_hook;
51
52 static void update_gutter_geometry(struct frame *f, enum gutter_pos pos);
53
54 #define SET_GUTTER_WAS_VISIBLE_FLAG(frame, pos, flag)   \
55   do {                                                  \
56     switch (pos)                                        \
57       {                                                 \
58       case TOP_GUTTER:                                  \
59         (frame)->top_gutter_was_visible = flag;         \
60         break;                                          \
61       case BOTTOM_GUTTER:                               \
62         (frame)->bottom_gutter_was_visible = flag;      \
63         break;                                          \
64       case LEFT_GUTTER:                                 \
65         (frame)->left_gutter_was_visible = flag;        \
66         break;                                          \
67       case RIGHT_GUTTER:                                \
68         (frame)->right_gutter_was_visible = flag;       \
69         break;                                          \
70       default:                                          \
71         abort ();                                       \
72       }                                                 \
73   } while (0)
74
75 static int gutter_was_visible(struct frame *frame, enum gutter_pos pos)
76 {
77         switch (pos) {
78         case TOP_GUTTER:
79                 return frame->top_gutter_was_visible;
80         case BOTTOM_GUTTER:
81                 return frame->bottom_gutter_was_visible;
82         case LEFT_GUTTER:
83                 return frame->left_gutter_was_visible;
84         case RIGHT_GUTTER:
85                 return frame->right_gutter_was_visible;
86         default:
87                 abort();
88                 return 0;       /* To keep the compiler happy */
89         }
90 }
91
92 #if 0
93 static Lisp_Object frame_topmost_window(struct frame *f)
94 {
95         Lisp_Object w = FRAME_ROOT_WINDOW(f);
96
97         do {
98                 while (!NILP(XWINDOW(w)->vchild)) {
99                         w = XWINDOW(w)->vchild;
100                 }
101         } while (!NILP(XWINDOW(w)->hchild) && !NILP(w = XWINDOW(w)->hchild));
102
103         return w;
104 }
105 #endif
106
107 static Lisp_Object frame_bottommost_window(struct frame *f)
108 {
109         Lisp_Object w = FRAME_ROOT_WINDOW(f);
110
111         do {
112                 while (!NILP(XWINDOW(w)->vchild)) {
113                         w = XWINDOW(w)->vchild;
114                         while (!NILP(XWINDOW(w)->next)) {
115                                 w = XWINDOW(w)->next;
116                         }
117                 }
118         } while (!NILP(XWINDOW(w)->hchild) && !NILP(w = XWINDOW(w)->hchild));
119
120         return w;
121 }
122
123 #if 0
124 static Lisp_Object frame_leftmost_window(struct frame *f)
125 {
126         Lisp_Object w = FRAME_ROOT_WINDOW(f);
127
128         do {
129                 while (!NILP(XWINDOW(w)->hchild)) {
130                         w = XWINDOW(w)->hchild;
131                 }
132         } while (!NILP(XWINDOW(w)->vchild) && !NILP(w = XWINDOW(w)->vchild));
133
134         return w;
135 }
136
137 static Lisp_Object frame_rightmost_window(struct frame *f)
138 {
139         Lisp_Object w = FRAME_ROOT_WINDOW(f);
140
141         do {
142                 while (!NILP(XWINDOW(w)->hchild)) {
143                         w = XWINDOW(w)->hchild;
144                         while (!NILP(XWINDOW(w)->next)) {
145                                 w = XWINDOW(w)->next;
146                         }
147                 }
148         } while (!NILP(XWINDOW(w)->vchild) && !NILP(w = XWINDOW(w)->vchild));
149         return w;
150 }
151 #endif
152
153 /* calculate the coordinates of a gutter for the current frame and
154    selected window. we have to be careful in calculating this as we
155    need to use *two* windows, the currently selected window will give
156    us the actual height, width and contents of the gutter, but if we
157    use this for calculating the gutter positions we run into trouble
158    if it is not the window nearest the gutter. Instead we predetermine
159    the nearest window and then use that.*/
160 static void
161 get_gutter_coords(struct frame *f, enum gutter_pos pos, int *x, int *y,
162                   int *width, int *height)
163 {
164         Lisp_Object tmp = frame_bottommost_window(f);
165         struct window *bot = XWINDOW(tmp);
166         /* The top and bottom gutters take precedence over the left and
167            right. */
168         switch (pos) {
169         case TOP_GUTTER:
170                 *x = FRAME_LEFT_BORDER_END(f);
171                 *y = FRAME_TOP_BORDER_END(f);
172                 *width = FRAME_RIGHT_BORDER_START(f)
173                     - FRAME_LEFT_BORDER_END(f);
174                 *height = FRAME_TOP_GUTTER_BOUNDS(f);
175                 break;
176
177         case BOTTOM_GUTTER:
178                 *x = FRAME_LEFT_BORDER_END(f);
179                 *y = WINDOW_BOTTOM(bot);
180                 *width = FRAME_RIGHT_BORDER_START(f)
181                     - FRAME_LEFT_BORDER_END(f);
182                 *height = FRAME_BOTTOM_GUTTER_BOUNDS(f);
183                 break;
184
185         case LEFT_GUTTER:
186                 *x = FRAME_LEFT_BORDER_END(f);
187                 *y = FRAME_TOP_BORDER_END(f) + FRAME_TOP_GUTTER_BOUNDS(f);
188                 *width = FRAME_LEFT_GUTTER_BOUNDS(f);
189                 *height = WINDOW_BOTTOM(bot)
190                     - (FRAME_TOP_BORDER_END(f) + FRAME_TOP_GUTTER_BOUNDS(f));
191                 break;
192
193         case RIGHT_GUTTER:
194                 *x = FRAME_RIGHT_BORDER_START(f)
195                     - FRAME_RIGHT_GUTTER_BOUNDS(f);
196                 *y = FRAME_TOP_BORDER_END(f) + FRAME_TOP_GUTTER_BOUNDS(f);
197                 *width = FRAME_RIGHT_GUTTER_BOUNDS(f);
198                 *height = WINDOW_BOTTOM(bot)
199                     - (FRAME_TOP_BORDER_END(f) + FRAME_TOP_GUTTER_BOUNDS(f));
200                 break;
201
202         default:
203                 abort();
204         }
205 }
206
207 /*
208  display_boxes_in_gutter_p
209
210  Determine whether the required display_glyph_area is completely
211  inside the gutter. -1 means the display_box is not in the gutter. 1
212  means the display_box and the display_glyph_area are in the
213  window. 0 means the display_box is in the gutter but the
214  display_glyph_area is not. */
215 int display_boxes_in_gutter_p(struct frame *f, struct display_box *db,
216                               struct display_glyph_area *dga)
217 {
218         enum gutter_pos pos;
219         GUTTER_POS_LOOP(pos) {
220                 if (FRAME_GUTTER_VISIBLE(f, pos)) {
221                         int x, y, width, height;
222                         get_gutter_coords(f, pos, &x, &y, &width, &height);
223                         if (db->xpos + dga->xoffset >= x
224                             &&
225                             db->ypos + dga->yoffset >= y
226                             &&
227                             db->xpos + dga->xoffset + dga->width <= x + width
228                             &&
229                             db->ypos + dga->yoffset + dga->height <= y + height)
230                                 return 1;
231                         else if (db->xpos >= x && db->ypos >= y
232                                  && db->xpos + db->width <= x + width
233                                  && db->ypos + db->height <= y + height)
234                                 return 0;
235                 }
236         }
237         return -1;
238 }
239
240 /* Convert the gutter specifier into something we can actually
241    display. */
242 static Lisp_Object construct_window_gutter_spec(struct window *w,
243                                                 enum gutter_pos pos)
244 {
245         Lisp_Object rest, *args;
246         int nargs = 0;
247         Lisp_Object gutter = RAW_WINDOW_GUTTER(w, pos);
248
249         if (STRINGP(gutter) || NILP(gutter))
250                 return gutter;
251
252         GET_LIST_LENGTH(gutter, nargs);
253         args = alloca_array(Lisp_Object, nargs >> 1);
254         nargs = 0;
255
256         for (rest = gutter; !NILP(rest); rest = XCDR(XCDR(rest))) {
257                 /* We only put things in the real gutter that are declared to be
258                    visible. */
259                 if (!CONSP(WINDOW_GUTTER_VISIBLE(w, pos))
260                     || !NILP(Fmemq(XCAR(rest), WINDOW_GUTTER_VISIBLE(w, pos)))) {
261                         args[nargs++] = XCAR(XCDR(rest));
262                 }
263         }
264
265         return Fconcat(nargs, args);
266 }
267
268 /* Sizing gutters is a pain so we try and help the user by determining
269    what height will accommodate all lines. This is useless on left and
270    right gutters as we always have a maximal number of lines. */
271 static int
272 calculate_gutter_size_from_display_lines(enum gutter_pos pos,
273                                          display_line_dynarr * ddla)
274 {
275         int size = 0;
276         struct display_line *dl;
277
278         /* For top and bottom the calculation is easy. */
279         if (pos == TOP_GUTTER || pos == BOTTOM_GUTTER) {
280                 /* grab coordinates of last line  */
281                 if (Dynarr_length(ddla)) {
282                         dl = Dynarr_atp(ddla, Dynarr_length(ddla) - 1);
283                         size = (dl->ypos + dl->descent - dl->clip)
284                             - (Dynarr_atp(ddla, 0)->ypos -
285                                Dynarr_atp(ddla, 0)->ascent);
286                 }
287         }
288         /* For left and right we have to do some maths. */
289         else {
290                 int start_pos = 0, end_pos = 0, line;
291                 for (line = 0; line < Dynarr_length(ddla); line++) {
292                         int block;
293                         dl = Dynarr_atp(ddla, line);
294
295                         for (block = 0;
296                              block < Dynarr_largest(dl->display_blocks);
297                              block++) {
298                                 struct display_block *db =
299                                     Dynarr_atp(dl->display_blocks, block);
300
301                                 if (db->type == TEXT) {
302                                         start_pos =
303                                             min(db->start_pos, start_pos);
304                                         end_pos = max(db->end_pos, end_pos);
305                                 }
306                         }
307                 }
308                 size = end_pos - start_pos;
309         }
310
311         return size;
312 }
313
314 static Lisp_Object calculate_gutter_size(struct window *w, enum gutter_pos pos)
315 {
316         struct frame *f = XFRAME(WINDOW_FRAME(w));
317         int count;
318         display_line_dynarr *ddla;
319         Lisp_Object ret = Qnil;
320
321         /* degenerate case */
322         if (NILP(RAW_WINDOW_GUTTER(w, pos))
323             || !FRAME_VISIBLE_P(f)
324             || NILP(w->buffer))
325                 return Qnil;
326
327         /* Redisplay code that we use relies on GC not happening. Make it
328            so. */
329         count = specpdl_depth();
330         record_unwind_protect(restore_gc_inhibit,
331                               make_int(gc_currently_forbidden));
332         gc_currently_forbidden = 1;
333
334         ddla = Dynarr_new(display_line);
335         /* generate some display lines */
336         generate_displayable_area(w, WINDOW_GUTTER(w, pos),
337                                   FRAME_LEFT_BORDER_END(f),
338                                   FRAME_TOP_BORDER_END(f),
339                                   FRAME_RIGHT_BORDER_START(f)
340                                   - FRAME_LEFT_BORDER_END(f),
341                                   FRAME_BOTTOM_BORDER_START(f)
342                                   - FRAME_TOP_BORDER_END(f), ddla, 0, 0);
343
344         /* Let GC happen again. */
345         unbind_to(count, Qnil);
346
347         ret = make_int(calculate_gutter_size_from_display_lines(pos, ddla));
348         free_display_lines(ddla);
349
350         return ret;
351 }
352
353 static void output_gutter(struct frame *f, enum gutter_pos pos, int force)
354 {
355         Lisp_Object frame;
356         Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW(f);
357         struct device *d = XDEVICE(f->device);
358         struct window *w = XWINDOW(window);
359         int x, y, width, height, ypos;
360         int line, border_width;
361         face_index findex;
362         display_line_dynarr *ddla, *cdla;
363         struct display_line *dl = 0;
364         int cdla_len;
365
366         if (!WINDOW_LIVE_P(w))
367                 return;
368
369         border_width = FRAME_GUTTER_BORDER_WIDTH(f, pos);
370         findex = get_builtin_face_cache_index(w, Vwidget_face);
371
372         if (!f->current_display_lines[pos])
373                 f->current_display_lines[pos] = Dynarr_new(display_line);
374         if (!f->desired_display_lines[pos])
375                 f->desired_display_lines[pos] = Dynarr_new(display_line);
376
377         ddla = f->desired_display_lines[pos];
378         cdla = f->current_display_lines[pos];
379         cdla_len = Dynarr_length(cdla);
380
381         XSETFRAME(frame, f);
382
383         get_gutter_coords(f, pos, &x, &y, &width, &height);
384         /* generate some display lines */
385         generate_displayable_area(w, WINDOW_GUTTER(w, pos),
386                                   x + border_width, y + border_width,
387                                   width - 2 * border_width,
388                                   height - 2 * border_width, ddla, 0, findex);
389
390         /* We only output the gutter if we think something of significance
391            has changed.  This is, for example, because redisplay can cause
392            new face cache elements to get added causing compare_runes to
393            fail because the findex for a particular face has changed.  */
394         if (force || f->faces_changed || f->frame_changed ||
395             f->gutter_changed || f->glyphs_changed ||
396             f->size_changed || f->subwindows_changed ||
397             w->windows_changed || f->windows_structure_changed ||
398             cdla_len != Dynarr_length(ddla) ||
399             (f->extents_changed && w->gutter_extent_modiff[pos])) {
400 #ifdef DEBUG_GUTTERS
401                 printf("gutter redisplay [%dx%d@%d+%d] triggered by %s,\n",
402                        width, height, x, y, force ? "force" :
403                        f->faces_changed ? "f->faces_changed" :
404                        f->frame_changed ? "f->frame_changed" :
405                        f->gutter_changed ? "f->gutter_changed" :
406                        f->glyphs_changed ? "f->glyphs_changed" :
407                        f->size_changed ? "f->size_changed" :
408                        f->subwindows_changed ? "f->subwindows_changed" :
409                        w->windows_changed ? "w->windows_changed" :
410                        f->
411                        windows_structure_changed ?
412                        "f->windows_structure_changed" : cdla_len !=
413                        Dynarr_length(ddla) ? "different display structures" :
414                        f->extents_changed
415                        && w->
416                        gutter_extent_modiff[pos] ?
417                        "f->extents_changed && w->gutter_extent_modiff[pos]" :
418                        "<null>");
419 #endif
420                 /* Output each line. */
421                 for (line = 0; line < Dynarr_length(ddla); line++) {
422                         output_display_line(w, cdla, ddla, line, -1, -1);
423                 }
424
425                 /* If the number of display lines has shrunk, adjust. */
426                 if (cdla_len > Dynarr_length(ddla)) {
427                         Dynarr_length(cdla) = Dynarr_length(ddla);
428                 }
429
430                 /* grab coordinates of last line and blank after it. */
431                 if (Dynarr_length(ddla) > 0) {
432                         dl = Dynarr_atp(ddla, Dynarr_length(ddla) - 1);
433                         ypos = dl->ypos + dl->descent - dl->clip;
434                 } else
435                         ypos = y;
436
437                 redisplay_clear_region(window, findex, x + border_width, ypos,
438                                        width - 2 * border_width,
439                                        height - (ypos - y) - border_width);
440                 /* If, for some reason, we have more to display than we have
441                    room for, and we are allowed to resize the gutter, then make
442                    sure this happens before the next time we try and
443                    output. This can happen when face font sizes change. */
444                 if (dl && EQ(w->gutter_size[pos], Qautodetect)
445                     && (dl->clip > 0 ||
446                         calculate_gutter_size_from_display_lines(pos, ddla) >
447                         WINDOW_GUTTER_SIZE_INTERNAL(w, pos))) {
448                         /* #### Ideally we would just mark the specifier as dirty
449                            and everything else would "just work". Unfortunately we have
450                            two problems with this. One is that the specifier cache
451                            won't be recalculated unless the specifier code thinks the
452                            cached value has actually changed, even though we have
453                            marked the specifier as dirty. Additionally, although doing
454                            this results in a gutter size change, we never seem to get
455                            back into redisplay so that the frame size can be updated. I
456                            think this is because we are already in redisplay and later
457                            on the frame will be marked as clean. Thus we also have to
458                            force a pending recalculation of the frame size.  */
459                         w->gutter_size[pos] = Qnil;
460                         Fset_specifier_dirty_flag(Vgutter_size[pos]);
461                         update_gutter_geometry(f, pos);
462                 }
463
464                 /* bevel the gutter area if so desired */
465                 if (border_width != 0) {
466                         MAYBE_DEVMETH(d, bevel_area,
467                                       (w, findex, x, y, width, height,
468                                        border_width, EDGE_ALL, EDGE_BEVEL_OUT));
469                 }
470         } else {
471                 /* Nothing of significance happened so sync the display line
472                    structs. */
473                 for (line = 0; line < Dynarr_length(ddla); line++) {
474                         sync_display_line_structs(w, line, 1, cdla, ddla);
475                 }
476         }
477
478         w->gutter_extent_modiff[pos] = 0;
479 }
480
481 static void clear_gutter(struct frame *f, enum gutter_pos pos)
482 {
483         int x, y, width, height;
484         Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW(f);
485         face_index findex = get_builtin_face_cache_index(XWINDOW(window),
486                                                          Vwidget_face);
487         get_gutter_coords(f, pos, &x, &y, &width, &height);
488
489         SET_GUTTER_WAS_VISIBLE_FLAG(f, pos, 0);
490
491         redisplay_clear_region(window, findex, x, y, width, height);
492 }
493
494 /* #### I don't currently believe that redisplay needs to mark the
495    glyphs in its structures since these will always be referenced from
496    somewhere else. However, I'm not sure enough to stake my life on it
497    at this point, so we do the safe thing. */
498
499 /* See the comment in image_instantiate_cache_result as to why marking
500    the glyph will also mark the image_instance. */
501 void mark_gutters(struct frame *f)
502 {
503         enum gutter_pos pos;
504         GUTTER_POS_LOOP(pos) {
505                 if (f->current_display_lines[pos])
506                         mark_redisplay_structs(f->current_display_lines[pos]);
507                 /* #### Do we really need to mark the desired lines? */
508                 if (f->desired_display_lines[pos])
509                         mark_redisplay_structs(f->desired_display_lines[pos]);
510         }
511 }
512
513 /* This is called by extent_changed_for_redisplay, so that redisplay
514    knows exactly what extents have changed. */
515 void
516 gutter_extent_signal_changed_region_maybe(Lisp_Object obj,
517                                           Bufpos start, Bufpos end)
518 {
519         /* #### Start and end are currently ignored but could be used by a
520            more optimal gutter redisplay. We currently loop over all frames
521            here, this could be optimized. */
522         Lisp_Object frmcons, devcons, concons;
523
524         FRAME_LOOP_NO_BREAK(frmcons, devcons, concons) {
525                 struct frame *f = XFRAME(XCAR(frmcons));
526                 enum gutter_pos pos;
527                 Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW(f);
528                 struct window *w = XWINDOW(window);
529
530                 GUTTER_POS_LOOP(pos) {
531                         if (EQ(WINDOW_GUTTER(w, pos), obj)) {
532                                 w->gutter_extent_modiff[pos]++;
533                         }
534                 }
535         }
536 }
537
538 /* We have to change the gutter geometry separately to the gutter
539    update since it needs to occur outside of redisplay proper. */
540 static void update_gutter_geometry(struct frame *f, enum gutter_pos pos)
541 {
542         /* If the gutter geometry has changed then re-layout the
543            frame. If we are in display there is almost no point in doing
544            anything else since the frame size changes will be delayed
545            until we are out of redisplay proper. */
546         if (FRAME_GUTTER_BOUNDS(f, pos) != f->current_gutter_bounds[pos]) {
547                 int width, height;
548                 pixel_to_char_size(f, FRAME_PIXWIDTH(f), FRAME_PIXHEIGHT(f),
549                                    &width, &height);
550                 change_frame_size(f, height, width, 0);
551                 MARK_FRAME_LAYOUT_CHANGED(f);
552         }
553
554         /* Mark sizes as up-to-date. */
555         f->current_gutter_bounds[pos] = FRAME_GUTTER_BOUNDS(f, pos);
556 }
557
558 void update_frame_gutter_geometry(struct frame *f)
559 {
560         if (f->gutter_changed
561             || f->frame_layout_changed || f->windows_structure_changed) {
562                 enum gutter_pos pos;
563
564                 /* If the gutter geometry has changed then re-layout the
565                    frame. If we are in display there is almost no point in doing
566                    anything else since the frame size changes will be delayed
567                    until we are out of redisplay proper. */
568                 GUTTER_POS_LOOP(pos) {
569                         update_gutter_geometry(f, pos);
570                 }
571         }
572 }
573
574 void update_frame_gutters(struct frame *f)
575 {
576         if (f->faces_changed || f->frame_changed ||
577             f->gutter_changed || f->glyphs_changed ||
578             f->size_changed || f->subwindows_changed ||
579             f->windows_changed || f->windows_structure_changed ||
580             f->extents_changed || f->frame_layout_changed) {
581                 enum gutter_pos pos;
582
583                 /* We don't actually care about these when outputting the gutter
584                    so locally disable them. */
585                 int local_clip_changed = f->clip_changed;
586                 int local_buffers_changed = f->buffers_changed;
587                 f->clip_changed = 0;
588                 f->buffers_changed = 0;
589
590                 /* and output */
591                 GUTTER_POS_LOOP(pos) {
592                         if (FRAME_GUTTER_VISIBLE(f, pos))
593                                 output_gutter(f, pos, 0);
594
595                         else if (gutter_was_visible(f, pos))
596                                 clear_gutter(f, pos);
597                 }
598
599                 f->clip_changed = local_clip_changed;
600                 f->buffers_changed = local_buffers_changed;
601                 f->gutter_changed = 0;
602         }
603 }
604
605 void reset_gutter_display_lines(struct frame *f)
606 {
607         enum gutter_pos pos;
608         GUTTER_POS_LOOP(pos) {
609                 if (f->current_display_lines[pos])
610                         Dynarr_reset(f->current_display_lines[pos]);
611         }
612 }
613
614 static void
615 redraw_exposed_gutter(struct frame *f, enum gutter_pos pos, int x, int y,
616                       int width, int height)
617 {
618         int g_x, g_y, g_width, g_height;
619
620         get_gutter_coords(f, pos, &g_x, &g_y, &g_width, &g_height);
621
622         if (((y + height) < g_y) || (y > (g_y + g_height)) || !height || !width
623             || !g_height || !g_width)
624                 return;
625         if (((x + width) < g_x) || (x > (g_x + g_width)))
626                 return;
627
628 #ifdef DEBUG_WIDGETS
629         printf("redrawing gutter after expose %d+%d, %dx%d\n",
630                x, y, width, height);
631 #endif
632         /* #### optimize this - redrawing the whole gutter for every expose
633            is very expensive. We reset the current display lines because if
634            they're being exposed they are no longer current. */
635         reset_gutter_display_lines(f);
636
637         /* Even if none of the gutter is in the area, the blank region at
638            the very least must be because the first thing we did is verify
639            that some portion of the gutter is in the exposed region. */
640         output_gutter(f, pos, 1);
641 }
642
643 void
644 redraw_exposed_gutters(struct frame *f, int x, int y, int width, int height)
645 {
646         enum gutter_pos pos;
647
648         /* We have to be "in display" when we output the gutter - make it
649            so. */
650         hold_frame_size_changes();
651         GUTTER_POS_LOOP(pos) {
652                 if (FRAME_GUTTER_VISIBLE(f, pos))
653                         redraw_exposed_gutter(f, pos, x, y, width, height);
654         }
655         unhold_one_frame_size_changes(f);
656 }
657
658 void free_frame_gutters(struct frame *f)
659 {
660         enum gutter_pos pos;
661         GUTTER_POS_LOOP(pos) {
662                 if (f->current_display_lines[pos]) {
663                         free_display_lines(f->current_display_lines[pos]);
664                         f->current_display_lines[pos] = 0;
665                 }
666                 if (f->desired_display_lines[pos]) {
667                         free_display_lines(f->desired_display_lines[pos]);
668                         f->desired_display_lines[pos] = 0;
669                 }
670         }
671 }
672
673 static enum gutter_pos decode_gutter_position(Lisp_Object position)
674 {
675         if (EQ(position, Qtop))
676                 return TOP_GUTTER;
677         if (EQ(position, Qbottom))
678                 return BOTTOM_GUTTER;
679         if (EQ(position, Qleft))
680                 return LEFT_GUTTER;
681         if (EQ(position, Qright))
682                 return RIGHT_GUTTER;
683         signal_simple_error("Invalid gutter position", position);
684
685         return TOP_GUTTER;      /* not reached */
686 }
687
688 DEFUN("set-default-gutter-position", Fset_default_gutter_position, 1, 1, 0,     /*
689 Set the position that the `default-gutter' will be displayed at.
690 Valid positions are 'top, 'bottom, 'left and 'right.
691 See `default-gutter-position'.
692 */
693       (position))
694 {
695         enum gutter_pos cur = decode_gutter_position(Vdefault_gutter_position);
696         enum gutter_pos new = decode_gutter_position(position);
697
698         if (cur != new) {
699                 /* The following calls will automatically cause the dirty
700                    flags to be set; we delay frame size changes to avoid
701                    lots of frame flickering. */
702                 /* #### I think this should be GC protected. -sb */
703                 hold_frame_size_changes();
704                 set_specifier_fallback(Vgutter[cur], list1(Fcons(Qnil, Qnil)));
705                 set_specifier_fallback(Vgutter[new], Vdefault_gutter);
706                 set_specifier_fallback(Vgutter_size[cur],
707                                        list1(Fcons(Qnil, Qzero)));
708                 set_specifier_fallback(Vgutter_size[new], new == TOP_GUTTER
709                                        || new ==
710                                        BOTTOM_GUTTER ? Vdefault_gutter_height :
711                                        Vdefault_gutter_width);
712                 set_specifier_fallback(Vgutter_border_width[cur],
713                                        list1(Fcons(Qnil, Qzero)));
714                 set_specifier_fallback(Vgutter_border_width[new],
715                                        Vdefault_gutter_border_width);
716                 set_specifier_fallback(Vgutter_visible_p[cur],
717                                        list1(Fcons(Qnil, Qt)));
718                 set_specifier_fallback(Vgutter_visible_p[new],
719                                        Vdefault_gutter_visible_p);
720
721                 Vdefault_gutter_position = position;
722                 unhold_frame_size_changes();
723         }
724
725         run_hook(Qdefault_gutter_position_changed_hook);
726
727         return position;
728 }
729
730 DEFUN("default-gutter-position", Fdefault_gutter_position, 0, 0, 0,     /*
731 Return the position that the `default-gutter' will be displayed at.
732 The `default-gutter' will only be displayed here if the corresponding
733 position-specific gutter specifier does not provide a value.
734 */
735       ())
736 {
737         return Vdefault_gutter_position;
738 }
739
740 DEFUN("gutter-pixel-width", Fgutter_pixel_width, 0, 2, 0,       /*
741 Return the pixel width of the gutter at POS in LOCALE.
742 POS defaults to the default gutter position. LOCALE defaults to
743 the current window.
744 */
745       (pos, locale))
746 {
747         int x, y, width, height;
748         enum gutter_pos p = TOP_GUTTER;
749         struct frame *f = decode_frame(FW_FRAME(locale));
750
751         if (NILP(pos))
752                 pos = Vdefault_gutter_position;
753         p = decode_gutter_position(pos);
754
755         get_gutter_coords(f, p, &x, &y, &width, &height);
756         width -= (FRAME_GUTTER_BORDER_WIDTH(f, p) * 2);
757
758         return make_int(width);
759 }
760
761 DEFUN("gutter-pixel-height", Fgutter_pixel_height, 0, 2, 0,     /*
762 Return the pixel height of the gutter at POS in LOCALE.
763 POS defaults to the default gutter position. LOCALE defaults to
764 the current window.
765 */
766       (pos, locale))
767 {
768         int x, y, width, height;
769         enum gutter_pos p = TOP_GUTTER;
770         struct frame *f = decode_frame(FW_FRAME(locale));
771
772         if (NILP(pos))
773                 pos = Vdefault_gutter_position;
774         p = decode_gutter_position(pos);
775
776         get_gutter_coords(f, p, &x, &y, &width, &height);
777         height -= (FRAME_GUTTER_BORDER_WIDTH(f, p) * 2);
778
779         return make_int(height);
780 }
781
782 DEFINE_SPECIFIER_TYPE(gutter);
783
784 static void gutter_after_change(Lisp_Object specifier, Lisp_Object locale)
785 {
786         MARK_GUTTER_CHANGED;
787 }
788
789 static void gutter_validate(Lisp_Object instantiator)
790 {
791         if (NILP(instantiator))
792                 return;
793
794         /* Must be a string or a plist. */
795         if (!STRINGP(instantiator) && NILP(Fvalid_plist_p(instantiator)))
796                 signal_simple_error("Gutter spec must be string, plist or nil",
797                                     instantiator);
798
799         if (!STRINGP(instantiator)) {
800                 Lisp_Object rest;
801
802                 for (rest = instantiator; !NILP(rest); rest = XCDR(XCDR(rest))) {
803                         if (!SYMBOLP(XCAR(rest))
804                             || !STRINGP(XCAR(XCDR(rest))))
805                                 signal_simple_error
806                                     ("Gutter plist spec must contain strings",
807                                      instantiator);
808                 }
809         }
810 }
811
812 DEFUN("gutter-specifier-p", Fgutter_specifier_p, 1, 1, 0,       /*
813 Return non-nil if OBJECT is a gutter specifier.
814
815 See `make-gutter-specifier' for a description of possible gutter
816 instantiators.
817 */
818       (object))
819 {
820         return GUTTER_SPECIFIERP(object) ? Qt : Qnil;
821 }
822 \f
823 /*
824   Helper for invalidating the real specifier when default
825   specifier caching changes
826 */
827 static void recompute_overlaying_specifier(Lisp_Object real_one[4])
828 {
829         enum gutter_pos pos = decode_gutter_position(Vdefault_gutter_position);
830         Fset_specifier_dirty_flag(real_one[pos]);
831 }
832
833 static void
834 gutter_specs_changed(Lisp_Object specifier, struct window *w,
835                      Lisp_Object oldval, enum gutter_pos pos)
836 {
837         w->real_gutter[pos] = construct_window_gutter_spec(w, pos);
838         w->real_gutter_size[pos] = w->gutter_size[pos];
839
840         if (EQ(w->real_gutter_size[pos], Qautodetect)
841             && !NILP(w->gutter_visible_p[pos])) {
842                 w->real_gutter_size[pos] = calculate_gutter_size(w, pos);
843         }
844         MARK_GUTTER_CHANGED;
845         MARK_MODELINE_CHANGED;
846         MARK_WINDOWS_CHANGED(w);
847 }
848
849 /* We define all of these so we can access which actual gutter changed. */
850 static void
851 top_gutter_specs_changed(Lisp_Object specifier, struct window *w,
852                          Lisp_Object oldval)
853 {
854         gutter_specs_changed(specifier, w, oldval, TOP_GUTTER);
855 }
856
857 static void
858 bottom_gutter_specs_changed(Lisp_Object specifier, struct window *w,
859                             Lisp_Object oldval)
860 {
861         gutter_specs_changed(specifier, w, oldval, BOTTOM_GUTTER);
862 }
863
864 static void
865 left_gutter_specs_changed(Lisp_Object specifier, struct window *w,
866                           Lisp_Object oldval)
867 {
868         gutter_specs_changed(specifier, w, oldval, LEFT_GUTTER);
869 }
870
871 static void
872 right_gutter_specs_changed(Lisp_Object specifier, struct window *w,
873                            Lisp_Object oldval)
874 {
875         gutter_specs_changed(specifier, w, oldval, RIGHT_GUTTER);
876 }
877
878 static void
879 default_gutter_specs_changed(Lisp_Object specifier, struct window *w,
880                              Lisp_Object oldval)
881 {
882         recompute_overlaying_specifier(Vgutter);
883 }
884
885 static void
886 gutter_geometry_changed_in_window(Lisp_Object specifier, struct window *w,
887                                   Lisp_Object oldval)
888 {
889         enum gutter_pos pos;
890         GUTTER_POS_LOOP(pos) {
891                 w->real_gutter_size[pos] = w->gutter_size[pos];
892                 if (EQ(w->real_gutter_size[pos], Qautodetect)
893                     && !NILP(w->gutter_visible_p[pos])) {
894                         w->real_gutter_size[pos] =
895                             calculate_gutter_size(w, pos);
896                 }
897         }
898
899         MARK_GUTTER_CHANGED;
900         MARK_MODELINE_CHANGED;
901         MARK_WINDOWS_CHANGED(w);
902 }
903
904 static void
905 default_gutter_size_changed_in_window(Lisp_Object specifier, struct window *w,
906                                       Lisp_Object oldval)
907 {
908         recompute_overlaying_specifier(Vgutter_size);
909 }
910
911 static void
912 default_gutter_border_width_changed_in_window(Lisp_Object specifier,
913                                               struct window *w,
914                                               Lisp_Object oldval)
915 {
916         recompute_overlaying_specifier(Vgutter_border_width);
917 }
918
919 static void
920 default_gutter_visible_p_changed_in_window(Lisp_Object specifier,
921                                            struct window *w, Lisp_Object oldval)
922 {
923         recompute_overlaying_specifier(Vgutter_visible_p);
924         /* Need to reconstruct the gutter specifier as it is affected by the
925            visibility. */
926         recompute_overlaying_specifier(Vgutter);
927 }
928
929 DECLARE_SPECIFIER_TYPE(gutter_size);
930 #define GUTTER_SIZE_SPECIFIERP(x) SPECIFIER_TYPEP (x, gutter_size)
931 DEFINE_SPECIFIER_TYPE(gutter_size);
932
933 static void gutter_size_validate(Lisp_Object instantiator)
934 {
935         if (NILP(instantiator))
936                 return;
937
938         if (!INTP(instantiator) && !EQ(instantiator, Qautodetect))
939                 signal_simple_error
940                     ("Gutter size must be an integer or 'autodetect",
941                      instantiator);
942 }
943
944 DEFUN("gutter-size-specifier-p", Fgutter_size_specifier_p, 1, 1, 0,     /*
945 Return non-nil if OBJECT is a gutter-size specifier.
946
947 See `make-gutter-size-specifier' for a description of possible gutter-size
948 instantiators.
949 */
950       (object))
951 {
952         return GUTTER_SIZE_SPECIFIERP(object) ? Qt : Qnil;
953 }
954
955 DECLARE_SPECIFIER_TYPE(gutter_visible);
956 #define GUTTER_VISIBLE_SPECIFIERP(x) SPECIFIER_TYPEP (x, gutter_visible)
957 DEFINE_SPECIFIER_TYPE(gutter_visible);
958
959 static void gutter_visible_validate(Lisp_Object instantiator)
960 {
961         if (NILP(instantiator))
962                 return;
963
964         if (!NILP(instantiator) && !EQ(instantiator, Qt)
965             && !CONSP(instantiator))
966                 signal_simple_error
967                     ("Gutter visibility must be a boolean or list of symbols",
968                      instantiator);
969
970         if (CONSP(instantiator)) {
971                 Lisp_Object rest;
972
973                 EXTERNAL_LIST_LOOP(rest, instantiator) {
974                         if (!SYMBOLP(XCAR(rest)))
975                                 signal_simple_error
976                                     ("Gutter visibility must be a boolean or list of symbols",
977                                      instantiator);
978                 }
979         }
980 }
981
982 DEFUN("gutter-visible-specifier-p", Fgutter_visible_specifier_p, 1, 1, 0,       /*
983 Return non-nil if OBJECT is a gutter-visible specifier.
984
985 See `make-gutter-visible-specifier' for a description of possible
986 gutter-visible instantiators.
987 */
988       (object))
989 {
990         return GUTTER_VISIBLE_SPECIFIERP(object) ? Qt : Qnil;
991 }
992
993 DEFUN("redisplay-gutter-area", Fredisplay_gutter_area, 0, 0, 0, /*
994 Ensure that all gutters are correctly showing their gutter specifier.
995 */
996       ())
997 {
998         Lisp_Object devcons, concons;
999
1000         DEVICE_LOOP_NO_BREAK(devcons, concons) {
1001                 struct device *d = XDEVICE(XCAR(devcons));
1002                 Lisp_Object frmcons;
1003
1004                 DEVICE_FRAME_LOOP(frmcons, d) {
1005                         struct frame *f = XFRAME(XCAR(frmcons));
1006
1007                         MAYBE_DEVMETH(d, frame_output_begin, (f));
1008
1009                         /* Sequence is quite important here. We not only want to
1010                            redisplay the gutter area but we also want to flush any
1011                            frame size changes out so that the gutter redisplay happens
1012                            in a kosha environment.
1013
1014                            This is not only so that things look right but so that
1015                            glyph redisplay optimization kicks in, by default display
1016                            lines will be completely re-output if
1017                            f->windows_structure_changed is 1, and this is true if
1018                            frame size changes haven't been flushed out. Once frame
1019                            size changes have been flushed out we then need to
1020                            redisplay the frame in order to flush out pending window
1021                            size changes. */
1022                         update_frame_gutter_geometry(f);
1023
1024                         if (f->windows_structure_changed)
1025                                 redisplay_frame(f, 1);
1026                         else if (FRAME_REPAINT_P(f)) {
1027                                 /* We have to be "in display" when we output the gutter
1028                                    - make it so. */
1029                                 hold_frame_size_changes();
1030                                 update_frame_gutters(f);
1031                                 unhold_one_frame_size_changes(f);
1032                         }
1033
1034                         MAYBE_DEVMETH(d, frame_output_end, (f));
1035                 }
1036
1037                 d->gutter_changed = 0;
1038         }
1039
1040         /* This is so that further changes to the gutters will trigger redisplay. */
1041         gutter_changed_set = 0;
1042         gutter_changed = 0;
1043
1044         return Qnil;
1045 }
1046
1047 void init_frame_gutters(struct frame *f)
1048 {
1049         enum gutter_pos pos;
1050         struct window *w = XWINDOW(FRAME_LAST_NONMINIBUF_WINDOW(f));
1051         /* We are here as far in frame creation so cached specifiers are
1052            already recomputed, and possibly modified by resource
1053            initialization. We need to recalculate autodetected gutters. */
1054         GUTTER_POS_LOOP(pos) {
1055                 w->real_gutter[pos] = construct_window_gutter_spec(w, pos);
1056                 w->real_gutter_size[pos] = w->gutter_size[pos];
1057                 if (EQ(w->gutter_size[pos], Qautodetect)
1058                     && !NILP(w->gutter_visible_p[pos])) {
1059                         w->real_gutter_size[pos] =
1060                             calculate_gutter_size(w, pos);
1061                         MARK_GUTTER_CHANGED;
1062                         MARK_WINDOWS_CHANGED(w);
1063                 }
1064         }
1065
1066         /* Keep a record of the current sizes of things. */
1067         GUTTER_POS_LOOP(pos) {
1068                 f->current_gutter_bounds[pos] = FRAME_GUTTER_BOUNDS(f, pos);
1069         }
1070 }
1071
1072 void syms_of_gutter(void)
1073 {
1074         DEFSUBR(Fgutter_specifier_p);
1075         DEFSUBR(Fgutter_size_specifier_p);
1076         DEFSUBR(Fgutter_visible_specifier_p);
1077         DEFSUBR(Fset_default_gutter_position);
1078         DEFSUBR(Fdefault_gutter_position);
1079         DEFSUBR(Fgutter_pixel_height);
1080         DEFSUBR(Fgutter_pixel_width);
1081         DEFSUBR(Fredisplay_gutter_area);
1082
1083         defsymbol(&Qgutter_size, "gutter-size");
1084         defsymbol(&Qgutter_visible, "gutter-visible");
1085         defsymbol(&Qdefault_gutter_position_changed_hook,
1086                   "default-gutter-position-changed-hook");
1087 }
1088
1089 void vars_of_gutter(void)
1090 {
1091         staticpro(&Vdefault_gutter_position);
1092         Vdefault_gutter_position = Qtop;
1093
1094         Fprovide(Qgutter);
1095 }
1096
1097 void specifier_type_create_gutter(void)
1098 {
1099         INITIALIZE_SPECIFIER_TYPE(gutter, "gutter", "gutter-specifier-p");
1100         SPECIFIER_HAS_METHOD(gutter, validate);
1101         SPECIFIER_HAS_METHOD(gutter, after_change);
1102
1103         INITIALIZE_SPECIFIER_TYPE(gutter_size, "gutter-size",
1104                                   "gutter-size-specifier-p");
1105         SPECIFIER_HAS_METHOD(gutter_size, validate);
1106
1107         INITIALIZE_SPECIFIER_TYPE(gutter_visible, "gutter-visible",
1108                                   "gutter-visible-specifier-p");
1109         SPECIFIER_HAS_METHOD(gutter_visible, validate);
1110 }
1111
1112 void reinit_specifier_type_create_gutter(void)
1113 {
1114         REINITIALIZE_SPECIFIER_TYPE(gutter);
1115         REINITIALIZE_SPECIFIER_TYPE(gutter_size);
1116         REINITIALIZE_SPECIFIER_TYPE(gutter_visible);
1117 }
1118
1119 void specifier_vars_of_gutter(void)
1120 {
1121         Lisp_Object fb;
1122
1123         DEFVAR_SPECIFIER("default-gutter", &Vdefault_gutter     /*
1124 Specifier for a fallback gutter.
1125 Use `set-specifier' to change this.
1126
1127 The position of this gutter is specified in the function
1128 `default-gutter-position'.  If the corresponding position-specific
1129 gutter (e.g. `top-gutter' if `default-gutter-position' is 'top)
1130 does not specify a gutter in a particular domain (usually a window),
1131 then the value of `default-gutter' in that domain, if any, will be
1132 used instead.
1133
1134 Note that the gutter at any particular position will not be
1135 displayed unless its visibility flag is true and its thickness
1136 \(width or height, depending on orientation) is non-zero.  The
1137 visibility is controlled by the specifiers `top-gutter-visible-p',
1138 `bottom-gutter-visible-p', `left-gutter-visible-p', and
1139 `right-gutter-visible-p', and the thickness is controlled by the
1140 specifiers `top-gutter-height', `bottom-gutter-height',
1141 `left-gutter-width', and `right-gutter-width'.
1142
1143 Note that one of the four visibility specifiers inherits from
1144 `default-gutter-visibility' and one of the four thickness
1145 specifiers inherits from either `default-gutter-width' or
1146 `default-gutter-height' (depending on orientation), just
1147 like for the gutter description specifiers (e.g. `top-gutter')
1148 mentioned above.
1149
1150 Therefore, if you are setting `default-gutter', you should control
1151 the visibility and thickness using `default-gutter-visible-p',
1152 `default-gutter-width', and `default-gutter-height', rather than
1153 using position-specific specifiers.  That way, you will get sane
1154 behavior if the user changes the default gutter position.
1155
1156 The gutter value should be a string, a property list of strings or
1157 nil. You can attach extents and glyphs to the string and hence display
1158 glyphs and text in other fonts in the gutter area. If the gutter value
1159 is a property list then the strings will be concatenated together
1160                                                                    before being displayed.  */ );
1161
1162         Vdefault_gutter = Fmake_specifier(Qgutter);
1163         /* #### It would be even nicer if the specifier caching
1164            automatically knew about specifier fallbacks, so we didn't
1165            have to do it ourselves. */
1166         set_specifier_caching(Vdefault_gutter,
1167                               offsetof(struct window, default_gutter),
1168                               default_gutter_specs_changed, 0, 0, 1);
1169
1170         DEFVAR_SPECIFIER("top-gutter", &Vgutter[TOP_GUTTER]     /*
1171 Specifier for the gutter at the top of the frame.
1172 Use `set-specifier' to change this.
1173 See `default-gutter' for a description of a valid gutter instantiator.
1174                                                                  */ );
1175         Vgutter[TOP_GUTTER] = Fmake_specifier(Qgutter);
1176         set_specifier_caching(Vgutter[TOP_GUTTER],
1177                               offsetof(struct window, gutter[TOP_GUTTER]),
1178                               top_gutter_specs_changed, 0, 0, 1);
1179
1180         DEFVAR_SPECIFIER("bottom-gutter", &Vgutter[BOTTOM_GUTTER]       /*
1181 Specifier for the gutter at the bottom of the frame.
1182 Use `set-specifier' to change this.
1183 See `default-gutter' for a description of a valid gutter instantiator.
1184
1185 Note that, unless the `default-gutter-position' is `bottom', by
1186 default the height of the bottom gutter (controlled by
1187 `bottom-gutter-height') is 0; thus, a bottom gutter will not be
1188 displayed even if you provide a value for `bottom-gutter'.
1189                                                                          */ );
1190         Vgutter[BOTTOM_GUTTER] = Fmake_specifier(Qgutter);
1191         set_specifier_caching(Vgutter[BOTTOM_GUTTER],
1192                               offsetof(struct window, gutter[BOTTOM_GUTTER]),
1193                               bottom_gutter_specs_changed, 0, 0, 1);
1194
1195         DEFVAR_SPECIFIER("left-gutter", &Vgutter[LEFT_GUTTER]   /*
1196 Specifier for the gutter at the left edge of the frame.
1197 Use `set-specifier' to change this.
1198 See `default-gutter' for a description of a valid gutter instantiator.
1199
1200 Note that, unless the `default-gutter-position' is `left', by
1201 default the height of the left gutter (controlled by
1202 `left-gutter-width') is 0; thus, a left gutter will not be
1203 displayed even if you provide a value for `left-gutter'.
1204                                                                  */ );
1205         Vgutter[LEFT_GUTTER] = Fmake_specifier(Qgutter);
1206         set_specifier_caching(Vgutter[LEFT_GUTTER],
1207                               offsetof(struct window, gutter[LEFT_GUTTER]),
1208                               left_gutter_specs_changed, 0, 0, 1);
1209
1210         DEFVAR_SPECIFIER("right-gutter", &Vgutter[RIGHT_GUTTER] /*
1211 Specifier for the gutter at the right edge of the frame.
1212 Use `set-specifier' to change this.
1213 See `default-gutter' for a description of a valid gutter instantiator.
1214
1215 Note that, unless the `default-gutter-position' is `right', by
1216 default the height of the right gutter (controlled by
1217 `right-gutter-width') is 0; thus, a right gutter will not be
1218 displayed even if you provide a value for `right-gutter'.
1219                                                                  */ );
1220         Vgutter[RIGHT_GUTTER] = Fmake_specifier(Qgutter);
1221         set_specifier_caching(Vgutter[RIGHT_GUTTER],
1222                               offsetof(struct window, gutter[RIGHT_GUTTER]),
1223                               right_gutter_specs_changed, 0, 0, 1);
1224
1225         /* initially, top inherits from default; this can be
1226            changed with `set-default-gutter-position'. */
1227         fb = list1(Fcons(Qnil, Qnil));
1228         set_specifier_fallback(Vdefault_gutter, fb);
1229         set_specifier_fallback(Vgutter[TOP_GUTTER], Vdefault_gutter);
1230         set_specifier_fallback(Vgutter[BOTTOM_GUTTER], fb);
1231         set_specifier_fallback(Vgutter[LEFT_GUTTER], fb);
1232         set_specifier_fallback(Vgutter[RIGHT_GUTTER], fb);
1233
1234         DEFVAR_SPECIFIER("default-gutter-height", &Vdefault_gutter_height       /*
1235 *Height of the default gutter, if it's oriented horizontally.
1236 This is a specifier; use `set-specifier' to change it.
1237
1238 The position of the default gutter is specified by the function
1239 `set-default-gutter-position'.  If the corresponding position-specific
1240 gutter thickness specifier (e.g. `top-gutter-height' if
1241 `default-gutter-position' is 'top) does not specify a thickness in a
1242 particular domain (a window or a frame), then the value of
1243 `default-gutter-height' or `default-gutter-width' (depending on the
1244 gutter orientation) in that domain, if any, will be used instead.
1245
1246 Note that `default-gutter-height' is only used when
1247 `default-gutter-position' is 'top or 'bottom, and `default-gutter-width'
1248 is only used when `default-gutter-position' is 'left or 'right.
1249
1250 Note that all of the position-specific gutter thickness specifiers
1251 have a fallback value of zero when they do not correspond to the
1252 default gutter.  Therefore, you will have to set a non-zero thickness
1253 value if you want a position-specific gutter to be displayed.
1254
1255 If you set the height to 'autodetect the size of the gutter will be
1256 calculated to be large enough to hold the contents of the gutter. This
1257 is the default.
1258                                                                                  */ );
1259         Vdefault_gutter_height = Fmake_specifier(Qgutter_size);
1260         set_specifier_caching(Vdefault_gutter_height,
1261                               offsetof(struct window, default_gutter_height),
1262                               default_gutter_size_changed_in_window, 0, 0, 1);
1263
1264         DEFVAR_SPECIFIER("default-gutter-width", &Vdefault_gutter_width /*
1265 *Width of the default gutter, if it's oriented vertically.
1266 This is a specifier; use `set-specifier' to change it.
1267
1268 See `default-gutter-height' for more information.
1269                                                                          */ );
1270         Vdefault_gutter_width = Fmake_specifier(Qgutter_size);
1271         set_specifier_caching(Vdefault_gutter_width,
1272                               offsetof(struct window, default_gutter_width),
1273                               default_gutter_size_changed_in_window, 0, 0, 1);
1274
1275         DEFVAR_SPECIFIER("top-gutter-height", &Vgutter_size[TOP_GUTTER] /*
1276 *Height of the top gutter.
1277 This is a specifier; use `set-specifier' to change it.
1278
1279 See `default-gutter-height' for more information.
1280                                                                          */ );
1281         Vgutter_size[TOP_GUTTER] = Fmake_specifier(Qgutter_size);
1282         set_specifier_caching(Vgutter_size[TOP_GUTTER],
1283                               offsetof(struct window, gutter_size[TOP_GUTTER]),
1284                               gutter_geometry_changed_in_window, 0, 0, 1);
1285
1286         DEFVAR_SPECIFIER("bottom-gutter-height", &Vgutter_size[BOTTOM_GUTTER]   /*
1287 *Height of the bottom gutter.
1288 This is a specifier; use `set-specifier' to change it.
1289
1290 See `default-gutter-height' for more information.
1291                                                                                  */ );
1292         Vgutter_size[BOTTOM_GUTTER] = Fmake_specifier(Qgutter_size);
1293         set_specifier_caching(Vgutter_size[BOTTOM_GUTTER],
1294                               offsetof(struct window,
1295                                        gutter_size[BOTTOM_GUTTER]),
1296                               gutter_geometry_changed_in_window, 0, 0, 1);
1297
1298         DEFVAR_SPECIFIER("left-gutter-width", &Vgutter_size[LEFT_GUTTER]        /*
1299 *Width of left gutter.
1300 This is a specifier; use `set-specifier' to change it.
1301
1302 See `default-gutter-height' for more information.
1303                                                                                  */ );
1304         Vgutter_size[LEFT_GUTTER] = Fmake_specifier(Qgutter_size);
1305         set_specifier_caching(Vgutter_size[LEFT_GUTTER],
1306                               offsetof(struct window, gutter_size[LEFT_GUTTER]),
1307                               gutter_geometry_changed_in_window, 0, 0, 1);
1308
1309         DEFVAR_SPECIFIER("right-gutter-width", &Vgutter_size[RIGHT_GUTTER]      /*
1310 *Width of right gutter.
1311 This is a specifier; use `set-specifier' to change it.
1312
1313 See `default-gutter-height' for more information.
1314                                                                                  */ );
1315         Vgutter_size[RIGHT_GUTTER] = Fmake_specifier(Qgutter_size);
1316         set_specifier_caching(Vgutter_size[RIGHT_GUTTER],
1317                               offsetof(struct window,
1318                                        gutter_size[RIGHT_GUTTER]),
1319                               gutter_geometry_changed_in_window, 0, 0, 1);
1320
1321         fb = Qnil;
1322 #ifdef HAVE_TTY
1323         fb = Fcons(Fcons(list1(Qtty), Qautodetect), fb);
1324 #endif
1325 #ifdef HAVE_X_WINDOWS
1326         fb = Fcons(Fcons(list1(Qx), Qautodetect), fb);
1327 #endif
1328         if (!NILP(fb))
1329                 set_specifier_fallback(Vdefault_gutter_height, fb);
1330
1331         fb = Qnil;
1332 #ifdef HAVE_TTY
1333         fb = Fcons(Fcons(list1(Qtty), Qautodetect), fb);
1334 #endif
1335 #ifdef HAVE_X_WINDOWS
1336         fb = Fcons(Fcons(list1(Qx), Qautodetect), fb);
1337 #endif
1338         if (!NILP(fb))
1339                 set_specifier_fallback(Vdefault_gutter_width, fb);
1340
1341         set_specifier_fallback(Vgutter_size[TOP_GUTTER],
1342                                Vdefault_gutter_height);
1343         fb = list1(Fcons(Qnil, Qzero));
1344         set_specifier_fallback(Vgutter_size[BOTTOM_GUTTER], fb);
1345         set_specifier_fallback(Vgutter_size[LEFT_GUTTER], fb);
1346         set_specifier_fallback(Vgutter_size[RIGHT_GUTTER], fb);
1347
1348         DEFVAR_SPECIFIER("default-gutter-border-width", &Vdefault_gutter_border_width   /*
1349 *Width of the border around the default gutter.
1350 This is a specifier; use `set-specifier' to change it.
1351
1352 The position of the default gutter is specified by the function
1353 `set-default-gutter-position'.  If the corresponding position-specific
1354 gutter border width specifier (e.g. `top-gutter-border-width' if
1355 `default-gutter-position' is 'top) does not specify a border width in a
1356 particular domain (a window or a frame), then the value of
1357 `default-gutter-border-width' in that domain, if any, will be used
1358 instead.
1359
1360                                                                                          */ );
1361         Vdefault_gutter_border_width = Fmake_specifier(Qnatnum);
1362         set_specifier_caching(Vdefault_gutter_border_width,
1363                               offsetof(struct window,
1364                                        default_gutter_border_width),
1365                               default_gutter_border_width_changed_in_window, 0,
1366                               0, 0);
1367
1368         DEFVAR_SPECIFIER("top-gutter-border-width", &Vgutter_border_width[TOP_GUTTER]   /*
1369 *Border width of the top gutter.
1370 This is a specifier; use `set-specifier' to change it.
1371
1372 See `default-gutter-height' for more information.
1373                                                                                          */ );
1374         Vgutter_border_width[TOP_GUTTER] = Fmake_specifier(Qnatnum);
1375         set_specifier_caching(Vgutter_border_width[TOP_GUTTER],
1376                               offsetof(struct window,
1377                                        gutter_border_width[TOP_GUTTER]),
1378                               gutter_geometry_changed_in_window, 0, 0, 0);
1379
1380         DEFVAR_SPECIFIER("bottom-gutter-border-width", &Vgutter_border_width[BOTTOM_GUTTER]     /*
1381 *Border width of the bottom gutter.
1382 This is a specifier; use `set-specifier' to change it.
1383
1384 See `default-gutter-height' for more information.
1385                                                                                                  */ );
1386         Vgutter_border_width[BOTTOM_GUTTER] = Fmake_specifier(Qnatnum);
1387         set_specifier_caching(Vgutter_border_width[BOTTOM_GUTTER],
1388                               offsetof(struct window,
1389                                        gutter_border_width[BOTTOM_GUTTER]),
1390                               gutter_geometry_changed_in_window, 0, 0, 0);
1391
1392         DEFVAR_SPECIFIER("left-gutter-border-width", &Vgutter_border_width[LEFT_GUTTER] /*
1393 *Border width of left gutter.
1394 This is a specifier; use `set-specifier' to change it.
1395
1396 See `default-gutter-height' for more information.
1397                                                                                          */ );
1398         Vgutter_border_width[LEFT_GUTTER] = Fmake_specifier(Qnatnum);
1399         set_specifier_caching(Vgutter_border_width[LEFT_GUTTER],
1400                               offsetof(struct window,
1401                                        gutter_border_width[LEFT_GUTTER]),
1402                               gutter_geometry_changed_in_window, 0, 0, 0);
1403
1404         DEFVAR_SPECIFIER("right-gutter-border-width", &Vgutter_border_width[RIGHT_GUTTER]       /*
1405 *Border width of right gutter.
1406 This is a specifier; use `set-specifier' to change it.
1407
1408 See `default-gutter-height' for more information.
1409                                                                                                  */ );
1410         Vgutter_border_width[RIGHT_GUTTER] = Fmake_specifier(Qnatnum);
1411         set_specifier_caching(Vgutter_border_width[RIGHT_GUTTER],
1412                               offsetof(struct window,
1413                                        gutter_border_width[RIGHT_GUTTER]),
1414                               gutter_geometry_changed_in_window, 0, 0, 0);
1415
1416         fb = Qnil;
1417 #ifdef HAVE_TTY
1418         fb = Fcons(Fcons(list1(Qtty), Qzero), fb);
1419 #endif
1420 #ifdef HAVE_X_WINDOWS
1421         fb = Fcons(Fcons(list1(Qx), make_int(DEFAULT_GUTTER_BORDER_WIDTH)), fb);
1422 #endif
1423         if (!NILP(fb))
1424                 set_specifier_fallback(Vdefault_gutter_border_width, fb);
1425
1426         set_specifier_fallback(Vgutter_border_width[TOP_GUTTER],
1427                                Vdefault_gutter_border_width);
1428         fb = list1(Fcons(Qnil, Qzero));
1429         set_specifier_fallback(Vgutter_border_width[BOTTOM_GUTTER], fb);
1430         set_specifier_fallback(Vgutter_border_width[LEFT_GUTTER], fb);
1431         set_specifier_fallback(Vgutter_border_width[RIGHT_GUTTER], fb);
1432
1433         DEFVAR_SPECIFIER("default-gutter-visible-p", &Vdefault_gutter_visible_p /*
1434 *Whether the default gutter is visible.
1435 This is a specifier; use `set-specifier' to change it.
1436
1437 The position of the default gutter is specified by the function
1438 `set-default-gutter-position'.  If the corresponding position-specific
1439 gutter visibility specifier (e.g. `top-gutter-visible-p' if
1440 `default-gutter-position' is 'top) does not specify a visible-p value
1441 in a particular domain (a window or a frame), then the value of
1442 `default-gutter-visible-p' in that domain, if any, will be used
1443 instead.
1444
1445 `default-gutter-visible-p' and all of the position-specific gutter
1446 visibility specifiers have a fallback value of true.
1447                                                                                  */ );
1448         Vdefault_gutter_visible_p = Fmake_specifier(Qgutter_visible);
1449         set_specifier_caching(Vdefault_gutter_visible_p,
1450                               offsetof(struct window,
1451                                        default_gutter_visible_p),
1452                               default_gutter_visible_p_changed_in_window,
1453                               0, 0, 0);
1454
1455         DEFVAR_SPECIFIER("top-gutter-visible-p", &Vgutter_visible_p[TOP_GUTTER] /*
1456 *Whether the top gutter is visible.
1457 This is a specifier; use `set-specifier' to change it.
1458
1459 See `default-gutter-visible-p' for more information.
1460                                                                                  */ );
1461         Vgutter_visible_p[TOP_GUTTER] = Fmake_specifier(Qgutter_visible);
1462         set_specifier_caching(Vgutter_visible_p[TOP_GUTTER],
1463                               offsetof(struct window,
1464                                        gutter_visible_p[TOP_GUTTER]),
1465                               top_gutter_specs_changed, 0, 0, 0);
1466
1467         DEFVAR_SPECIFIER("bottom-gutter-visible-p", &Vgutter_visible_p[BOTTOM_GUTTER]   /*
1468 *Whether the bottom gutter is visible.
1469 This is a specifier; use `set-specifier' to change it.
1470
1471 See `default-gutter-visible-p' for more information.
1472                                                                                          */ );
1473         Vgutter_visible_p[BOTTOM_GUTTER] = Fmake_specifier(Qgutter_visible);
1474         set_specifier_caching(Vgutter_visible_p[BOTTOM_GUTTER],
1475                               offsetof(struct window,
1476                                        gutter_visible_p[BOTTOM_GUTTER]),
1477                               bottom_gutter_specs_changed, 0, 0, 0);
1478
1479         DEFVAR_SPECIFIER("left-gutter-visible-p", &Vgutter_visible_p[LEFT_GUTTER]       /*
1480 *Whether the left gutter is visible.
1481 This is a specifier; use `set-specifier' to change it.
1482
1483 See `default-gutter-visible-p' for more information.
1484                                                                                          */ );
1485         Vgutter_visible_p[LEFT_GUTTER] = Fmake_specifier(Qgutter_visible);
1486         set_specifier_caching(Vgutter_visible_p[LEFT_GUTTER],
1487                               offsetof(struct window,
1488                                        gutter_visible_p[LEFT_GUTTER]),
1489                               left_gutter_specs_changed, 0, 0, 0);
1490
1491         DEFVAR_SPECIFIER("right-gutter-visible-p", &Vgutter_visible_p[RIGHT_GUTTER]     /*
1492 *Whether the right gutter is visible.
1493 This is a specifier; use `set-specifier' to change it.
1494
1495 See `default-gutter-visible-p' for more information.
1496                                                                                          */ );
1497         Vgutter_visible_p[RIGHT_GUTTER] = Fmake_specifier(Qgutter_visible);
1498         set_specifier_caching(Vgutter_visible_p[RIGHT_GUTTER],
1499                               offsetof(struct window,
1500                                        gutter_visible_p[RIGHT_GUTTER]),
1501                               right_gutter_specs_changed, 0, 0, 0);
1502
1503         /* initially, top inherits from default; this can be
1504            changed with `set-default-gutter-position'. */
1505         fb = list1(Fcons(Qnil, Qt));
1506         set_specifier_fallback(Vdefault_gutter_visible_p, fb);
1507         set_specifier_fallback(Vgutter_visible_p[TOP_GUTTER],
1508                                Vdefault_gutter_visible_p);
1509         set_specifier_fallback(Vgutter_visible_p[BOTTOM_GUTTER], fb);
1510         set_specifier_fallback(Vgutter_visible_p[LEFT_GUTTER], fb);
1511         set_specifier_fallback(Vgutter_visible_p[RIGHT_GUTTER], fb);
1512 }