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