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