XEmacs 21.2.33 "Melpomene".
[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 Gutter specifiers are used to specify the format of a gutter.
793 The values of the variables `default-gutter', `top-gutter',
794 `left-gutter', `right-gutter', and `bottom-gutter' are always
795 gutter specifiers.
796
797 Valid gutter instantiators are called "gutter descriptors" and are
798 either strings or property-lists of strings.  See `default-gutter' for
799 a description of the exact format.
800 */
801        (object))
802 {
803   return GUTTER_SPECIFIERP (object) ? Qt : Qnil;
804 }
805
806 \f
807 /*
808   Helper for invalidating the real specifier when default
809   specifier caching changes
810 */
811 static void
812 recompute_overlaying_specifier (Lisp_Object real_one[4])
813 {
814   enum gutter_pos pos = decode_gutter_position (Vdefault_gutter_position);
815   Fset_specifier_dirty_flag (real_one[pos]);
816 }
817
818 static void
819 gutter_specs_changed (Lisp_Object specifier, struct window *w,
820                        Lisp_Object oldval, enum gutter_pos pos)
821 {
822   w->real_gutter[pos] = construct_window_gutter_spec (w, pos);
823   w->real_gutter_size[pos] = w->gutter_size[pos];
824   
825   if (EQ (w->real_gutter_size[pos], Qautodetect)
826       && !NILP (w->gutter_visible_p[pos]))
827     {
828       w->real_gutter_size [pos] = calculate_gutter_size (w, pos);
829     }
830   MARK_GUTTER_CHANGED;
831   MARK_MODELINE_CHANGED;
832   MARK_WINDOWS_CHANGED (w);
833 }
834
835 /* We define all of these so we can access which actual gutter changed. */
836 static void
837 top_gutter_specs_changed (Lisp_Object specifier, struct window *w,
838                           Lisp_Object oldval)
839 {
840   gutter_specs_changed (specifier, w, oldval, TOP_GUTTER);
841 }
842
843 static void
844 bottom_gutter_specs_changed (Lisp_Object specifier, struct window *w,
845                              Lisp_Object oldval)
846 {
847   gutter_specs_changed (specifier, w, oldval, BOTTOM_GUTTER);
848 }
849
850 static void
851 left_gutter_specs_changed (Lisp_Object specifier, struct window *w,
852                            Lisp_Object oldval)
853 {
854   gutter_specs_changed (specifier, w, oldval, LEFT_GUTTER);
855 }
856
857 static void
858 right_gutter_specs_changed (Lisp_Object specifier, struct window *w,
859                             Lisp_Object oldval)
860 {
861   gutter_specs_changed (specifier, w, oldval, RIGHT_GUTTER);
862 }
863
864 static void
865 default_gutter_specs_changed (Lisp_Object specifier, struct window *w,
866                                Lisp_Object oldval)
867 {
868   recompute_overlaying_specifier (Vgutter);
869 }
870
871 static void
872 gutter_geometry_changed_in_window (Lisp_Object specifier, struct window *w,
873                                     Lisp_Object oldval)
874 {
875   enum gutter_pos pos;
876   GUTTER_POS_LOOP (pos)
877     {
878       w->real_gutter_size[pos] = w->gutter_size[pos];
879       if (EQ (w->real_gutter_size[pos], Qautodetect)
880           && !NILP (w->gutter_visible_p[pos]))
881         {
882           w->real_gutter_size [pos] = calculate_gutter_size (w, pos);
883         }
884     }
885   
886   MARK_GUTTER_CHANGED;
887   MARK_MODELINE_CHANGED;
888   MARK_WINDOWS_CHANGED (w);
889 }
890
891 static void
892 default_gutter_size_changed_in_window (Lisp_Object specifier, struct window *w,
893                                         Lisp_Object oldval)
894 {
895   recompute_overlaying_specifier (Vgutter_size);
896 }
897
898 static void
899 default_gutter_border_width_changed_in_window (Lisp_Object specifier,
900                                                 struct window *w,
901                                                 Lisp_Object oldval)
902 {
903   recompute_overlaying_specifier (Vgutter_border_width);
904 }
905
906 static void
907 default_gutter_visible_p_changed_in_window (Lisp_Object specifier,
908                                              struct window *w,
909                                              Lisp_Object oldval)
910 {
911   recompute_overlaying_specifier (Vgutter_visible_p);
912   /* Need to reconstruct the gutter specifier as it is affected by the
913      visibility. */
914   recompute_overlaying_specifier (Vgutter);
915 }
916
917
918 DECLARE_SPECIFIER_TYPE (gutter_size);
919 #define GUTTER_SIZE_SPECIFIERP(x) SPECIFIER_TYPEP (x, gutter_size)
920 DEFINE_SPECIFIER_TYPE (gutter_size);
921
922 static void
923 gutter_size_validate (Lisp_Object instantiator)
924 {
925   if (NILP (instantiator))
926     return;
927
928   if (!INTP (instantiator) && !EQ (instantiator, Qautodetect))
929     signal_simple_error ("Gutter size must be an integer or 'autodetect", instantiator);
930 }
931
932 DEFUN ("gutter-size-specifier-p", Fgutter_size_specifier_p, 1, 1, 0, /*
933 Return non-nil if OBJECT is a gutter-size specifier.
934
935 Gutter-size specifiers are used to specify the size of a gutter.  The
936 values of the variables `default-gutter-size', `top-gutter-size',
937 `left-gutter-size', `right-gutter-size', and `bottom-gutter-size' are
938 always gutter-size specifiers.
939
940 Valid gutter-size instantiators are either integers or the special
941 symbol 'autodetect. If a gutter-size is set to 'autodetect them the
942 size of the gutter will be adjusted to just accomodate the gutters
943 contents. 'autodetect only works for top and bottom gutters.
944 */
945        (object))
946 {
947   return GUTTER_SIZE_SPECIFIERP (object) ? Qt : Qnil;
948 }
949
950 DECLARE_SPECIFIER_TYPE (gutter_visible);
951 #define GUTTER_VISIBLE_SPECIFIERP(x) SPECIFIER_TYPEP (x, gutter_visible)
952 DEFINE_SPECIFIER_TYPE (gutter_visible);
953
954 static void
955 gutter_visible_validate (Lisp_Object instantiator)
956 {
957   if (NILP (instantiator))
958     return;
959
960   if (!NILP (instantiator) && !EQ (instantiator, Qt) && !CONSP (instantiator))
961     signal_simple_error ("Gutter visibility must be a boolean or list of symbols", 
962                          instantiator);
963
964   if (CONSP (instantiator))
965     {
966       Lisp_Object rest;
967
968       EXTERNAL_LIST_LOOP (rest, instantiator)
969         {
970           if (!SYMBOLP (XCAR (rest)))
971               signal_simple_error ("Gutter visibility must be a boolean or list of symbols", 
972                                    instantiator);
973         }
974     }
975 }
976
977 DEFUN ("gutter-visible-specifier-p", Fgutter_visible_specifier_p, 1, 1, 0, /*
978 Return non-nil if OBJECT is a gutter-visible specifier.
979
980 Gutter-visible specifiers are used to specify the visibility of a
981 gutter.  The values of the variables `default-gutter-visible-p',
982 `top-gutter-visible-p', `left-gutter-visible-p',
983 `right-gutter-visible-p', and `bottom-gutter-visible-p' are always
984 gutter-visible specifiers.
985
986 Valid gutter-visible instantiators are t, nil or a list of symbols.
987 If a gutter-visible instantiator is set to a list of symbols, and the
988 correspondong gutter specification is a property-list strings, then
989 elements of the gutter specification will only be visible if the
990 corresponding symbol occurs in the gutter-visible instantiator.
991 */
992        (object))
993 {
994   return GUTTER_VISIBLE_SPECIFIERP (object) ? Qt : Qnil;
995 }
996
997 DEFUN ("redisplay-gutter-area", Fredisplay_gutter_area, 0, 0, 0, /*
998 Ensure that all gutters are correctly showing their gutter specifier.
999 */
1000        ())
1001 {
1002   Lisp_Object devcons, concons;
1003
1004   DEVICE_LOOP_NO_BREAK (devcons, concons)
1005     {
1006       struct device *d = XDEVICE (XCAR (devcons));
1007       Lisp_Object frmcons;
1008
1009       DEVICE_FRAME_LOOP (frmcons, d)
1010         {
1011           struct frame *f = XFRAME (XCAR (frmcons));
1012           
1013           /* Sequence is quite important here. We not only want to
1014            redisplay the gutter area but we also want to flush any
1015            frame size changes out so that the gutter redisplay happens
1016            in a kosha environment. 
1017
1018            This is not only so that things look right but so that
1019            glyph redisplay optimization kicks in, by default display
1020            lines will be completely re-output if
1021            f->windows_structure_changed is 1, and this is true if
1022            frame size changes haven't been flushed out. Once frame
1023            size changes have been flushed out we then need to
1024            redisplay the frame in order to flush out pending window
1025            size changes. */
1026           update_frame_gutter_geometry (f);
1027
1028           if (f->windows_structure_changed)
1029             redisplay_frame (f, 1);
1030           else if (FRAME_REPAINT_P (f))
1031             {
1032               /* We have to be "in display" when we output the gutter
1033                  - make it so. */
1034               hold_frame_size_changes ();
1035               update_frame_gutters (f);
1036               unhold_one_frame_size_changes (f);
1037             }
1038         }
1039       /* We now call the output_end routine for tty frames.  We delay
1040          doing so in order to avoid cursor flicker.  So much for 100%
1041          encapsulation. */
1042       if (DEVICE_TTY_P (d))
1043         DEVMETH (d, output_end, (d));
1044       
1045       d->gutter_changed = 0;
1046     }
1047
1048   /* This is so that further changes to the gutters will trigger redisplay. */
1049   gutter_changed_set = 0;
1050   gutter_changed = 0;
1051
1052   return Qnil;
1053 }
1054
1055 void
1056 init_frame_gutters (struct frame *f)
1057 {
1058   enum gutter_pos pos;
1059   struct window* w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
1060   /* We are here as far in frame creation so cached specifiers are
1061      already recomputed, and possibly modified by resource
1062      initialization. We need to recalculate autodetected gutters. */
1063   GUTTER_POS_LOOP (pos)
1064     {
1065       w->real_gutter[pos] = construct_window_gutter_spec (w, pos);
1066       w->real_gutter_size[pos] = w->gutter_size[pos];
1067       if (EQ (w->gutter_size[pos], Qautodetect)
1068           && !NILP (w->gutter_visible_p[pos]))
1069         {
1070           w->real_gutter_size [pos] = calculate_gutter_size (w, pos);
1071           MARK_GUTTER_CHANGED;
1072           MARK_WINDOWS_CHANGED (w);
1073         }
1074     }
1075
1076   /* Keep a record of the current sizes of things. */
1077   GUTTER_POS_LOOP (pos)
1078     {
1079       f->current_gutter_bounds[pos] = FRAME_GUTTER_BOUNDS (f, pos);
1080     }
1081 }
1082
1083 void
1084 syms_of_gutter (void)
1085 {
1086   DEFSUBR (Fgutter_specifier_p);
1087   DEFSUBR (Fgutter_size_specifier_p);
1088   DEFSUBR (Fgutter_visible_specifier_p);
1089   DEFSUBR (Fset_default_gutter_position);
1090   DEFSUBR (Fdefault_gutter_position);
1091   DEFSUBR (Fgutter_pixel_height);
1092   DEFSUBR (Fgutter_pixel_width);
1093   DEFSUBR (Fredisplay_gutter_area);
1094
1095   defsymbol (&Qgutter_size, "gutter-size");
1096   defsymbol (&Qgutter_visible, "gutter-visible");
1097   defsymbol (&Qdefault_gutter_position_changed_hook,
1098              "default-gutter-position-changed-hook");
1099 }
1100
1101 void
1102 vars_of_gutter (void)
1103 {
1104   staticpro (&Vdefault_gutter_position);
1105   Vdefault_gutter_position = Qtop;
1106
1107   Fprovide (Qgutter);
1108 }
1109
1110 void
1111 specifier_type_create_gutter (void)
1112 {
1113   INITIALIZE_SPECIFIER_TYPE (gutter, "gutter", "gutter-specifier-p");
1114   SPECIFIER_HAS_METHOD (gutter, validate);
1115   SPECIFIER_HAS_METHOD (gutter, after_change);
1116
1117   INITIALIZE_SPECIFIER_TYPE (gutter_size, "gutter-size", "gutter-size-specifier-p");
1118   SPECIFIER_HAS_METHOD (gutter_size, validate);
1119
1120   INITIALIZE_SPECIFIER_TYPE (gutter_visible, "gutter-visible", "gutter-visible-specifier-p");
1121   SPECIFIER_HAS_METHOD (gutter_visible, validate);
1122 }
1123
1124 void
1125 reinit_specifier_type_create_gutter (void)
1126 {
1127   REINITIALIZE_SPECIFIER_TYPE (gutter);
1128   REINITIALIZE_SPECIFIER_TYPE (gutter_size);
1129   REINITIALIZE_SPECIFIER_TYPE (gutter_visible);
1130 }
1131
1132 void
1133 specifier_vars_of_gutter (void)
1134 {
1135   Lisp_Object fb;
1136
1137   DEFVAR_SPECIFIER ("default-gutter", &Vdefault_gutter /*
1138 Specifier for a fallback gutter.
1139 Use `set-specifier' to change this.
1140
1141 The position of this gutter is specified in the function
1142 `default-gutter-position'.  If the corresponding position-specific
1143 gutter (e.g. `top-gutter' if `default-gutter-position' is 'top)
1144 does not specify a gutter in a particular domain (usually a window),
1145 then the value of `default-gutter' in that domain, if any, will be
1146 used instead.
1147
1148 Note that the gutter at any particular position will not be
1149 displayed unless its visibility flag is true and its thickness
1150 \(width or height, depending on orientation) is non-zero.  The
1151 visibility is controlled by the specifiers `top-gutter-visible-p',
1152 `bottom-gutter-visible-p', `left-gutter-visible-p', and
1153 `right-gutter-visible-p', and the thickness is controlled by the
1154 specifiers `top-gutter-height', `bottom-gutter-height',
1155 `left-gutter-width', and `right-gutter-width'.
1156
1157 Note that one of the four visibility specifiers inherits from
1158 `default-gutter-visibility' and one of the four thickness
1159 specifiers inherits from either `default-gutter-width' or
1160 `default-gutter-height' (depending on orientation), just
1161 like for the gutter description specifiers (e.g. `top-gutter')
1162 mentioned above.
1163
1164 Therefore, if you are setting `default-gutter', you should control
1165 the visibility and thickness using `default-gutter-visible-p',
1166 `default-gutter-width', and `default-gutter-height', rather than
1167 using position-specific specifiers.  That way, you will get sane
1168 behavior if the user changes the default gutter position.
1169
1170 The gutter value should be a string, a property list of strings or
1171 nil. You can attach extents and glyphs to the string and hence display
1172 glyphs and text in other fonts in the gutter area. If the gutter value
1173 is a property list then the strings will be concatenated together
1174 before being displayed.  */ );
1175
1176   Vdefault_gutter = Fmake_specifier (Qgutter);
1177   /* #### It would be even nicer if the specifier caching
1178      automatically knew about specifier fallbacks, so we didn't
1179      have to do it ourselves. */
1180   set_specifier_caching (Vdefault_gutter,
1181                          offsetof (struct window, default_gutter),
1182                          default_gutter_specs_changed,
1183                          0, 0);
1184
1185   DEFVAR_SPECIFIER ("top-gutter",
1186                     &Vgutter[TOP_GUTTER] /*
1187 Specifier for the gutter at the top of the frame.
1188 Use `set-specifier' to change this.
1189 See `default-gutter' for a description of a valid gutter instantiator.
1190 */ );
1191   Vgutter[TOP_GUTTER] = Fmake_specifier (Qgutter);
1192   set_specifier_caching (Vgutter[TOP_GUTTER],
1193                          offsetof (struct window, gutter[TOP_GUTTER]),
1194                          top_gutter_specs_changed,
1195                          0, 0);
1196
1197   DEFVAR_SPECIFIER ("bottom-gutter",
1198                     &Vgutter[BOTTOM_GUTTER] /*
1199 Specifier for the gutter at the bottom of the frame.
1200 Use `set-specifier' to change this.
1201 See `default-gutter' for a description of a valid gutter instantiator.
1202
1203 Note that, unless the `default-gutter-position' is `bottom', by
1204 default the height of the bottom gutter (controlled by
1205 `bottom-gutter-height') is 0; thus, a bottom gutter will not be
1206 displayed even if you provide a value for `bottom-gutter'.
1207 */ );
1208   Vgutter[BOTTOM_GUTTER] = Fmake_specifier (Qgutter);
1209   set_specifier_caching (Vgutter[BOTTOM_GUTTER],
1210                          offsetof (struct window, gutter[BOTTOM_GUTTER]),
1211                          bottom_gutter_specs_changed,
1212                          0, 0);
1213
1214   DEFVAR_SPECIFIER ("left-gutter",
1215                     &Vgutter[LEFT_GUTTER] /*
1216 Specifier for the gutter at the left edge of the frame.
1217 Use `set-specifier' to change this.
1218 See `default-gutter' for a description of a valid gutter instantiator.
1219
1220 Note that, unless the `default-gutter-position' is `left', by
1221 default the height of the left gutter (controlled by
1222 `left-gutter-width') is 0; thus, a left gutter will not be
1223 displayed even if you provide a value for `left-gutter'.
1224 */ );
1225   Vgutter[LEFT_GUTTER] = Fmake_specifier (Qgutter);
1226   set_specifier_caching (Vgutter[LEFT_GUTTER],
1227                          offsetof (struct window, gutter[LEFT_GUTTER]),
1228                          left_gutter_specs_changed,
1229                          0, 0);
1230
1231   DEFVAR_SPECIFIER ("right-gutter",
1232                     &Vgutter[RIGHT_GUTTER] /*
1233 Specifier for the gutter at the right edge of the frame.
1234 Use `set-specifier' to change this.
1235 See `default-gutter' for a description of a valid gutter instantiator.
1236
1237 Note that, unless the `default-gutter-position' is `right', by
1238 default the height of the right gutter (controlled by
1239 `right-gutter-width') is 0; thus, a right gutter will not be
1240 displayed even if you provide a value for `right-gutter'.
1241 */ );
1242   Vgutter[RIGHT_GUTTER] = Fmake_specifier (Qgutter);
1243   set_specifier_caching (Vgutter[RIGHT_GUTTER],
1244                          offsetof (struct window, gutter[RIGHT_GUTTER]),
1245                          right_gutter_specs_changed,
1246                          0, 0);
1247
1248   /* initially, top inherits from default; this can be
1249      changed with `set-default-gutter-position'. */
1250   fb = list1 (Fcons (Qnil, Qnil));
1251   set_specifier_fallback (Vdefault_gutter, fb);
1252   set_specifier_fallback (Vgutter[TOP_GUTTER], Vdefault_gutter);
1253   set_specifier_fallback (Vgutter[BOTTOM_GUTTER], fb);
1254   set_specifier_fallback (Vgutter[LEFT_GUTTER],   fb);
1255   set_specifier_fallback (Vgutter[RIGHT_GUTTER],  fb);
1256
1257   DEFVAR_SPECIFIER ("default-gutter-height", &Vdefault_gutter_height /*
1258 *Height of the default gutter, if it's oriented horizontally.
1259 This is a specifier; use `set-specifier' to change it.
1260
1261 The position of the default gutter is specified by the function
1262 `set-default-gutter-position'.  If the corresponding position-specific
1263 gutter thickness specifier (e.g. `top-gutter-height' if
1264 `default-gutter-position' is 'top) does not specify a thickness in a
1265 particular domain (a window or a frame), then the value of
1266 `default-gutter-height' or `default-gutter-width' (depending on the
1267 gutter orientation) in that domain, if any, will be used instead.
1268
1269 Note that `default-gutter-height' is only used when
1270 `default-gutter-position' is 'top or 'bottom, and `default-gutter-width'
1271 is only used when `default-gutter-position' is 'left or 'right.
1272
1273 Note that all of the position-specific gutter thickness specifiers
1274 have a fallback value of zero when they do not correspond to the
1275 default gutter.  Therefore, you will have to set a non-zero thickness
1276 value if you want a position-specific gutter to be displayed.
1277
1278 If you set the height to 'autodetect the size of the gutter will be
1279 calculated to be large enough to hold the contents of the gutter. This
1280 is the default.
1281 */ );
1282   Vdefault_gutter_height = Fmake_specifier (Qgutter_size);
1283   set_specifier_caching (Vdefault_gutter_height,
1284                          offsetof (struct window, default_gutter_height),
1285                          default_gutter_size_changed_in_window,
1286                          0, 0);
1287
1288   DEFVAR_SPECIFIER ("default-gutter-width", &Vdefault_gutter_width /*
1289 *Width of the default gutter, if it's oriented vertically.
1290 This is a specifier; use `set-specifier' to change it.
1291
1292 See `default-gutter-height' for more information.
1293 */ );
1294   Vdefault_gutter_width = Fmake_specifier (Qnatnum);
1295   set_specifier_caching (Vdefault_gutter_width,
1296                          offsetof (struct window, default_gutter_width),
1297                          default_gutter_size_changed_in_window,
1298                          0, 0);
1299
1300   DEFVAR_SPECIFIER ("top-gutter-height",
1301                     &Vgutter_size[TOP_GUTTER] /*
1302 *Height of the top gutter.
1303 This is a specifier; use `set-specifier' to change it.
1304
1305 See `default-gutter-height' for more information.
1306 */ );
1307   Vgutter_size[TOP_GUTTER] = Fmake_specifier (Qgutter_size);
1308   set_specifier_caching (Vgutter_size[TOP_GUTTER],
1309                          offsetof (struct window, gutter_size[TOP_GUTTER]),
1310                          gutter_geometry_changed_in_window, 0, 0);
1311
1312   DEFVAR_SPECIFIER ("bottom-gutter-height",
1313                     &Vgutter_size[BOTTOM_GUTTER] /*
1314 *Height of the bottom gutter.
1315 This is a specifier; use `set-specifier' to change it.
1316
1317 See `default-gutter-height' for more information.
1318 */ );
1319   Vgutter_size[BOTTOM_GUTTER] = Fmake_specifier (Qgutter_size);
1320   set_specifier_caching (Vgutter_size[BOTTOM_GUTTER],
1321                          offsetof (struct window, gutter_size[BOTTOM_GUTTER]),
1322                          gutter_geometry_changed_in_window, 0, 0);
1323
1324   DEFVAR_SPECIFIER ("left-gutter-width",
1325                     &Vgutter_size[LEFT_GUTTER] /*
1326 *Width of left gutter.
1327 This is a specifier; use `set-specifier' to change it.
1328
1329 See `default-gutter-height' for more information.
1330 */ );
1331   Vgutter_size[LEFT_GUTTER] = Fmake_specifier (Qnatnum);
1332   set_specifier_caching (Vgutter_size[LEFT_GUTTER],
1333                          offsetof (struct window, gutter_size[LEFT_GUTTER]),
1334                          gutter_geometry_changed_in_window, 0, 0);
1335
1336   DEFVAR_SPECIFIER ("right-gutter-width",
1337                     &Vgutter_size[RIGHT_GUTTER] /*
1338 *Width of right gutter.
1339 This is a specifier; use `set-specifier' to change it.
1340
1341 See `default-gutter-height' for more information.
1342 */ );
1343   Vgutter_size[RIGHT_GUTTER] = Fmake_specifier (Qnatnum);
1344   set_specifier_caching (Vgutter_size[RIGHT_GUTTER],
1345                          offsetof (struct window, gutter_size[RIGHT_GUTTER]),
1346                          gutter_geometry_changed_in_window, 0, 0);
1347
1348   fb = Qnil;
1349 #ifdef HAVE_TTY
1350   fb = Fcons (Fcons (list1 (Qtty), Qautodetect), fb);
1351 #endif
1352 #ifdef HAVE_X_WINDOWS
1353   fb = Fcons (Fcons (list1 (Qx), Qautodetect), fb);
1354 #endif
1355 #ifdef HAVE_MS_WINDOWS
1356   fb = Fcons (Fcons (list1 (Qmsprinter), Qautodetect), fb);
1357   fb = Fcons (Fcons (list1 (Qmswindows), Qautodetect), fb);
1358 #endif
1359   if (!NILP (fb))
1360     set_specifier_fallback (Vdefault_gutter_height, fb);
1361
1362   fb = Qnil;
1363 #ifdef HAVE_TTY
1364   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1365 #endif
1366 #ifdef HAVE_X_WINDOWS
1367   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_GUTTER_WIDTH)), fb);
1368 #endif
1369 #ifdef HAVE_MS_WINDOWS
1370   fb = Fcons (Fcons (list1 (Qmsprinter), Qzero), fb);
1371   fb = Fcons (Fcons (list1 (Qmswindows), 
1372                      make_int (DEFAULT_GUTTER_WIDTH)), fb);
1373 #endif
1374   if (!NILP (fb))
1375     set_specifier_fallback (Vdefault_gutter_width, fb);
1376
1377   set_specifier_fallback (Vgutter_size[TOP_GUTTER], Vdefault_gutter_height);
1378   fb = list1 (Fcons (Qnil, Qzero));
1379   set_specifier_fallback (Vgutter_size[BOTTOM_GUTTER], fb);
1380   set_specifier_fallback (Vgutter_size[LEFT_GUTTER],   fb);
1381   set_specifier_fallback (Vgutter_size[RIGHT_GUTTER],  fb);
1382
1383   DEFVAR_SPECIFIER ("default-gutter-border-width",
1384                     &Vdefault_gutter_border_width /*
1385 *Width of the border around the default gutter.
1386 This is a specifier; use `set-specifier' to change it.
1387
1388 The position of the default gutter is specified by the function
1389 `set-default-gutter-position'.  If the corresponding position-specific
1390 gutter border width specifier (e.g. `top-gutter-border-width' if
1391 `default-gutter-position' is 'top) does not specify a border width in a
1392 particular domain (a window or a frame), then the value of
1393 `default-gutter-border-width' in that domain, if any, will be used
1394 instead.
1395
1396 */ );
1397   Vdefault_gutter_border_width = Fmake_specifier (Qnatnum);
1398   set_specifier_caching (Vdefault_gutter_border_width,
1399                          offsetof (struct window, default_gutter_border_width),
1400                          default_gutter_border_width_changed_in_window,
1401                          0, 0);
1402
1403   DEFVAR_SPECIFIER ("top-gutter-border-width",
1404                     &Vgutter_border_width[TOP_GUTTER] /*
1405 *Border width of the top 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[TOP_GUTTER] = Fmake_specifier (Qnatnum);
1411   set_specifier_caching (Vgutter_border_width[TOP_GUTTER],
1412                          offsetof (struct window,
1413                                    gutter_border_width[TOP_GUTTER]),
1414                          gutter_geometry_changed_in_window, 0, 0);
1415
1416   DEFVAR_SPECIFIER ("bottom-gutter-border-width",
1417                     &Vgutter_border_width[BOTTOM_GUTTER] /*
1418 *Border width of the bottom gutter.
1419 This is a specifier; use `set-specifier' to change it.
1420
1421 See `default-gutter-height' for more information.
1422 */ );
1423   Vgutter_border_width[BOTTOM_GUTTER] = Fmake_specifier (Qnatnum);
1424   set_specifier_caching (Vgutter_border_width[BOTTOM_GUTTER],
1425                          offsetof (struct window,
1426                                    gutter_border_width[BOTTOM_GUTTER]),
1427                          gutter_geometry_changed_in_window, 0, 0);
1428
1429   DEFVAR_SPECIFIER ("left-gutter-border-width",
1430                     &Vgutter_border_width[LEFT_GUTTER] /*
1431 *Border width of left gutter.
1432 This is a specifier; use `set-specifier' to change it.
1433
1434 See `default-gutter-height' for more information.
1435 */ );
1436   Vgutter_border_width[LEFT_GUTTER] = Fmake_specifier (Qnatnum);
1437   set_specifier_caching (Vgutter_border_width[LEFT_GUTTER],
1438                          offsetof (struct window,
1439                                    gutter_border_width[LEFT_GUTTER]),
1440                          gutter_geometry_changed_in_window, 0, 0);
1441
1442   DEFVAR_SPECIFIER ("right-gutter-border-width",
1443                     &Vgutter_border_width[RIGHT_GUTTER] /*
1444 *Border width of right gutter.
1445 This is a specifier; use `set-specifier' to change it.
1446
1447 See `default-gutter-height' for more information.
1448 */ );
1449   Vgutter_border_width[RIGHT_GUTTER] = Fmake_specifier (Qnatnum);
1450   set_specifier_caching (Vgutter_border_width[RIGHT_GUTTER],
1451                          offsetof (struct window,
1452                                    gutter_border_width[RIGHT_GUTTER]),
1453                          gutter_geometry_changed_in_window, 0, 0);
1454
1455   fb = Qnil;
1456 #ifdef HAVE_TTY
1457   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1458 #endif
1459 #ifdef HAVE_X_WINDOWS
1460   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_GUTTER_BORDER_WIDTH)), fb);
1461 #endif
1462 #ifdef HAVE_MS_WINDOWS
1463   fb = Fcons (Fcons (list1 (Qmsprinter), Qzero), fb);
1464   fb = Fcons (Fcons (list1 (Qmswindows), make_int (DEFAULT_GUTTER_BORDER_WIDTH)), fb);
1465 #endif
1466   if (!NILP (fb))
1467     set_specifier_fallback (Vdefault_gutter_border_width, fb);
1468
1469   set_specifier_fallback (Vgutter_border_width[TOP_GUTTER], Vdefault_gutter_border_width);
1470   fb = list1 (Fcons (Qnil, Qzero));
1471   set_specifier_fallback (Vgutter_border_width[BOTTOM_GUTTER], fb);
1472   set_specifier_fallback (Vgutter_border_width[LEFT_GUTTER],   fb);
1473   set_specifier_fallback (Vgutter_border_width[RIGHT_GUTTER],  fb);
1474
1475   DEFVAR_SPECIFIER ("default-gutter-visible-p", &Vdefault_gutter_visible_p /*
1476 *Whether the default gutter is visible.
1477 This is a specifier; use `set-specifier' to change it.
1478
1479 The position of the default gutter is specified by the function
1480 `set-default-gutter-position'.  If the corresponding position-specific
1481 gutter visibility specifier (e.g. `top-gutter-visible-p' if
1482 `default-gutter-position' is 'top) does not specify a visible-p value
1483 in a particular domain (a window or a frame), then the value of
1484 `default-gutter-visible-p' in that domain, if any, will be used
1485 instead.
1486
1487 `default-gutter-visible-p' and all of the position-specific gutter
1488 visibility specifiers have a fallback value of true.
1489 */ );
1490   Vdefault_gutter_visible_p = Fmake_specifier (Qgutter_visible);
1491   set_specifier_caching (Vdefault_gutter_visible_p,
1492                          offsetof (struct window,
1493                                    default_gutter_visible_p),
1494                          default_gutter_visible_p_changed_in_window,
1495                          0, 0);
1496
1497   DEFVAR_SPECIFIER ("top-gutter-visible-p",
1498                     &Vgutter_visible_p[TOP_GUTTER] /*
1499 *Whether the top gutter is visible.
1500 This is a specifier; use `set-specifier' to change it.
1501
1502 See `default-gutter-visible-p' for more information.
1503 */ );
1504   Vgutter_visible_p[TOP_GUTTER] = Fmake_specifier (Qgutter_visible);
1505   set_specifier_caching (Vgutter_visible_p[TOP_GUTTER],
1506                          offsetof (struct window,
1507                                    gutter_visible_p[TOP_GUTTER]),
1508                          top_gutter_specs_changed, 0, 0);
1509
1510   DEFVAR_SPECIFIER ("bottom-gutter-visible-p",
1511                     &Vgutter_visible_p[BOTTOM_GUTTER] /*
1512 *Whether the bottom gutter is visible.
1513 This is a specifier; use `set-specifier' to change it.
1514
1515 See `default-gutter-visible-p' for more information.
1516 */ );
1517   Vgutter_visible_p[BOTTOM_GUTTER] = Fmake_specifier (Qgutter_visible);
1518   set_specifier_caching (Vgutter_visible_p[BOTTOM_GUTTER],
1519                          offsetof (struct window,
1520                                    gutter_visible_p[BOTTOM_GUTTER]),
1521                          bottom_gutter_specs_changed, 0, 0);
1522
1523   DEFVAR_SPECIFIER ("left-gutter-visible-p",
1524                     &Vgutter_visible_p[LEFT_GUTTER] /*
1525 *Whether the left gutter is visible.
1526 This is a specifier; use `set-specifier' to change it.
1527
1528 See `default-gutter-visible-p' for more information.
1529 */ );
1530   Vgutter_visible_p[LEFT_GUTTER] = Fmake_specifier (Qgutter_visible);
1531   set_specifier_caching (Vgutter_visible_p[LEFT_GUTTER],
1532                          offsetof (struct window,
1533                                    gutter_visible_p[LEFT_GUTTER]),
1534                          left_gutter_specs_changed, 0, 0);
1535
1536   DEFVAR_SPECIFIER ("right-gutter-visible-p",
1537                     &Vgutter_visible_p[RIGHT_GUTTER] /*
1538 *Whether the right gutter is visible.
1539 This is a specifier; use `set-specifier' to change it.
1540
1541 See `default-gutter-visible-p' for more information.
1542 */ );
1543   Vgutter_visible_p[RIGHT_GUTTER] = Fmake_specifier (Qgutter_visible);
1544   set_specifier_caching (Vgutter_visible_p[RIGHT_GUTTER],
1545                          offsetof (struct window,
1546                                    gutter_visible_p[RIGHT_GUTTER]),
1547                          right_gutter_specs_changed, 0, 0);
1548
1549   /* initially, top inherits from default; this can be
1550      changed with `set-default-gutter-position'. */
1551   fb = list1 (Fcons (Qnil, Qt));
1552   set_specifier_fallback (Vdefault_gutter_visible_p, fb);
1553   set_specifier_fallback (Vgutter_visible_p[TOP_GUTTER],
1554                           Vdefault_gutter_visible_p);
1555   set_specifier_fallback (Vgutter_visible_p[BOTTOM_GUTTER], fb);
1556   set_specifier_fallback (Vgutter_visible_p[LEFT_GUTTER],   fb);
1557   set_specifier_fallback (Vgutter_visible_p[RIGHT_GUTTER],  fb);
1558 }