This commit was generated by cvs2svn to compensate for changes in r5670,
[chise/xemacs-chise.git.1] / src / gutter.c
1 /* Gutter implementation.
2    Copyright (C) 1999 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 /* Specifers ripped-off from toolbar.c */
24
25 #include <config.h>
26 #include "lisp.h"
27
28 #include "buffer.h"
29 #include "frame.h"
30 #include "device.h"
31 #include "faces.h"
32 #include "glyphs.h"
33 #include "redisplay.h"
34 #include "window.h"
35 #include "gutter.h"
36
37 Lisp_Object Vgutter[4];
38 Lisp_Object Vgutter_size[4];
39 Lisp_Object Vgutter_visible_p[4];
40 Lisp_Object Vgutter_border_width[4];
41
42 Lisp_Object Vdefault_gutter, Vdefault_gutter_visible_p;
43 Lisp_Object Vdefault_gutter_width, Vdefault_gutter_height;
44 Lisp_Object Vdefault_gutter_border_width;
45
46 Lisp_Object Vdefault_gutter_position;
47
48 #define SET_GUTTER_WAS_VISIBLE_FLAG(frame, pos, flag)                   \
49   do {                                                                  \
50     switch (pos)                                                        \
51       {                                                                 \
52       case TOP_GUTTER:                                                  \
53         (frame)->top_gutter_was_visible = flag;                 \
54         break;                                                          \
55       case BOTTOM_GUTTER:                                               \
56         (frame)->bottom_gutter_was_visible = flag;                      \
57         break;                                                          \
58       case LEFT_GUTTER:                                         \
59         (frame)->left_gutter_was_visible = flag;                        \
60         break;                                                          \
61       case RIGHT_GUTTER:                                                \
62         (frame)->right_gutter_was_visible = flag;                       \
63         break;                                                          \
64       default:                                                          \
65         abort ();                                                       \
66       }                                                                 \
67   } while (0)
68
69 static int gutter_was_visible (struct frame* frame, enum gutter_pos pos)
70 {
71   switch (pos)
72     {
73     case TOP_GUTTER:
74       return (frame)->top_gutter_was_visible;
75     case BOTTOM_GUTTER:
76       return (frame)->bottom_gutter_was_visible;
77     case LEFT_GUTTER:
78       return (frame)->left_gutter_was_visible;
79     case RIGHT_GUTTER:
80       return (frame)->right_gutter_was_visible;
81     default:
82       abort ();
83     }
84 }
85
86 static Lisp_Object
87 frame_topmost_window (struct frame *f)
88 {
89   Lisp_Object w = FRAME_ROOT_WINDOW (f);
90
91   do {
92     while (!NILP (XWINDOW (w)->vchild))
93       {
94         w = XWINDOW (w)->vchild;
95       }
96   } while (!NILP (XWINDOW (w)->hchild) && !NILP (w = XWINDOW (w)->hchild));
97
98   return w;
99 }
100
101 static Lisp_Object
102 frame_bottommost_window (struct frame *f)
103 {
104   Lisp_Object w = FRAME_ROOT_WINDOW (f);
105
106   do {
107     while (!NILP (XWINDOW (w)->vchild))
108       {
109         w = XWINDOW (w)->vchild;
110         while (!NILP (XWINDOW (w)->next))
111           {
112             w = XWINDOW (w)->next;
113           }
114       }
115   } while (!NILP (XWINDOW (w)->hchild) && !NILP (w = XWINDOW (w)->hchild));
116
117   return w;
118 }
119
120 #if 0
121 static Lisp_Object
122 frame_leftmost_window (struct frame *f)
123 {
124   Lisp_Object w = FRAME_ROOT_WINDOW (f);
125
126   do {
127     while (!NILP (XWINDOW (w)->hchild))
128       {
129         w = XWINDOW (w)->hchild;
130       }
131   } while (!NILP (XWINDOW (w)->vchild) && !NILP (w = XWINDOW (w)->vchild));
132
133   return w;
134 }
135
136 static Lisp_Object
137 frame_rightmost_window (struct frame *f)
138 {
139   Lisp_Object w = FRAME_ROOT_WINDOW (f);
140
141   do {
142     while (!NILP (XWINDOW (w)->hchild))
143       {
144         w = XWINDOW (w)->hchild;
145         while (!NILP (XWINDOW (w)->next))
146           {
147             w = XWINDOW (w)->next;
148           }
149       }
150   } while (!NILP (XWINDOW (w)->vchild) && !NILP (w = XWINDOW (w)->vchild));
151   return w;
152 }
153 #endif
154
155 /* calculate the coordinates of a gutter for the current frame and
156    selected window. we have to be careful in calculating this as we
157    need to use *two* windows, the currently selected window will give
158    us the actual height, width and contents of the gutter, but if we
159    use this for calculating the gutter positions we run into trouble
160    if it is not the window nearest the gutter. Instead we predetermine
161    the nearest window and then use that.*/
162 void
163 get_gutter_coords (struct frame *f, enum gutter_pos pos, int *x, int *y,
164                    int *width, int *height)
165 {
166   struct window
167     * top = XWINDOW (frame_topmost_window (f)),
168     * bot = XWINDOW (frame_bottommost_window (f));
169   /* The top and bottom gutters take precedence over the left and
170      right. */
171   switch (pos)
172     {
173     case TOP_GUTTER:
174       *x = FRAME_LEFT_BORDER_END (f);
175       *y = FRAME_TOP_BORDER_END (f);
176       *width = FRAME_RIGHT_BORDER_START (f) 
177         - FRAME_LEFT_BORDER_END (f);
178       *height = FRAME_TOP_GUTTER_BOUNDS (f);
179       break;
180
181     case BOTTOM_GUTTER:
182       *x = FRAME_LEFT_BORDER_END (f);
183       *y = WINDOW_BOTTOM (bot)
184         - FRAME_BOTTOM_GUTTER_BOUNDS (f);
185       *width = FRAME_RIGHT_BORDER_START (f) 
186         - FRAME_LEFT_BORDER_END (f);
187       *height = FRAME_BOTTOM_GUTTER_BOUNDS (f);
188       break;
189
190     case LEFT_GUTTER:
191       *x = FRAME_LEFT_BORDER_END (f);
192       *y = WINDOW_TEXT_TOP (top);
193       *width = FRAME_LEFT_GUTTER_BOUNDS (f);
194       *height = WINDOW_BOTTOM (bot)
195         - (WINDOW_TEXT_TOP (top)
196            + FRAME_BOTTOM_GUTTER_BOUNDS (f));
197       break;
198       
199     case RIGHT_GUTTER:
200       *x = FRAME_RIGHT_BORDER_START (f)
201         - FRAME_RIGHT_GUTTER_BOUNDS (f);
202       *y = WINDOW_TEXT_TOP (top);
203       *width = FRAME_RIGHT_GUTTER_BOUNDS (f);
204       *height = WINDOW_BOTTOM (bot)
205         - (WINDOW_TEXT_TOP (top) 
206            + FRAME_BOTTOM_GUTTER_BOUNDS (f));
207       break;
208
209     default:
210       abort ();
211     }
212 }
213
214 static void
215 output_gutter (struct frame *f, enum gutter_pos pos)
216 {
217   Lisp_Object frame;
218   Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW (f);
219   struct device *d = XDEVICE (f->device);
220   struct window* w = XWINDOW (window);
221   int x, y, width, height, ypos;
222   int line;
223   int border_width = FRAME_GUTTER_BORDER_WIDTH (f, pos);
224   face_index findex = get_builtin_face_cache_index (w, Vgui_element_face);
225   display_line_dynarr* ddla, *cdla;
226   struct display_line *dl;
227
228   if (!f->current_display_lines)
229     f->current_display_lines = Dynarr_new (display_line);
230   if (!f->desired_display_lines)
231     f->desired_display_lines = Dynarr_new (display_line);
232   
233   ddla = f->desired_display_lines;
234   cdla = f->current_display_lines;
235
236   XSETFRAME (frame, f);
237
238   get_gutter_coords (f, pos, &x, &y, &width, &height);
239   /* clear out what we want to cover */
240   /* generate some display lines */
241   generate_displayable_area (w, WINDOW_GUTTER (w, pos),
242                              x + border_width, y + border_width,
243                              width - 2 * border_width, 
244                              height - 2 * border_width, ddla, 0, findex);
245   /* Output each line. */
246   for (line = 0; line < Dynarr_length (ddla); line++)
247     {
248       output_display_line (w, cdla, ddla, line, -1, -1);
249     }
250
251   /* grab coordinates of last line and blank after it. */
252   dl = Dynarr_atp (ddla, Dynarr_length (ddla) - 1);
253   ypos = dl->ypos + dl->descent - dl->clip;
254   redisplay_clear_region (window, findex, x + border_width , ypos,
255                           width - 2 * border_width, height - (ypos - y));
256
257   /* bevel the gutter area if so desired */
258   if (border_width != 0)
259     {
260       MAYBE_DEVMETH (d, bevel_area, 
261                      (w, findex, x, y, width, height, border_width));
262     }
263 }
264
265 /* sizing gutters is a pain so we try and help the user by detemining
266    what height will accomodate all lines. This is useless on left and
267    right gutters as we always have a maximal number of lines. */
268 static Lisp_Object
269 calculate_gutter_size (struct window *w, enum gutter_pos pos)
270 {
271   struct frame* f = XFRAME (WINDOW_FRAME (w));
272   int ypos;
273   display_line_dynarr* ddla;
274   struct display_line *dl;
275
276   /* we cannot autodetect gutter sizes for the left and right as there
277      is no reasonable metric to use */
278   assert (pos == TOP_GUTTER || pos == BOTTOM_GUTTER);
279   /* degenerate case */
280   if (NILP (WINDOW_GUTTER (w, pos))
281       ||
282       !FRAME_VISIBLE_P (f))
283     return Qnil;
284
285   ddla = Dynarr_new (display_line);
286   /* generate some display lines */
287   generate_displayable_area (w, WINDOW_GUTTER (w, pos),
288                              FRAME_LEFT_BORDER_END (f),
289                              0,
290                              FRAME_RIGHT_BORDER_START (f)
291                              - FRAME_LEFT_BORDER_END (f),
292                              200,
293                              ddla, 0, 0);
294   /* grab coordinates of last line  */
295   if (Dynarr_length (ddla))
296     {
297       dl = Dynarr_atp (ddla, Dynarr_length (ddla) - 1);
298       ypos = dl->ypos + dl->descent - dl->clip;
299       Dynarr_free (ddla);
300       return make_int (ypos);
301     }
302   else
303     {
304       Dynarr_free (ddla);
305       return Qnil;
306     }
307 }
308
309 static void
310 clear_gutter (struct frame *f, enum gutter_pos pos)
311 {
312   int x, y, width, height;
313   Lisp_Object window = FRAME_LAST_NONMINIBUF_WINDOW (f);
314   face_index findex = get_builtin_face_cache_index (XWINDOW (window),
315                                                     Vgui_element_face);
316   get_gutter_coords (f, pos, &x, &y, &width, &height);
317
318   SET_GUTTER_WAS_VISIBLE_FLAG (f, pos, 0);
319
320   redisplay_clear_region (window, findex, x, y, width, height);
321 }
322
323 void
324 update_frame_gutters (struct frame *f)
325 {
326   if (f->gutter_changed || f->frame_changed || f->clear)
327     {
328       int pos;
329       /* and output */
330
331       for (pos = 0; pos < 4; pos++)
332         {
333           if (FRAME_GUTTER_VISIBLE (f, pos))
334             output_gutter (f, pos);
335           else if (gutter_was_visible (f, pos))
336             clear_gutter (f, pos);
337         }
338
339     }
340   f->gutter_changed = 0;
341 }
342
343 static void
344 redraw_exposed_gutter (struct frame *f, enum gutter_pos pos, int x, int y,
345                        int width, int height)
346 {
347   int g_x, g_y, g_width, g_height;
348   int newx, newy;
349
350   get_gutter_coords (f, pos, &g_x, &g_y, &g_width, &g_height);
351
352   if (((y + height) < g_y) || (y > (g_y + g_height)))
353     return;
354   if (((x + width) < g_x) || (x > (g_x + g_width)))
355     return;
356
357   /* #### optimize this - redrawing the whole gutter for every expose
358      is very expensive. We reset the current display lines because if
359      they're being exposed they are no longer current. */
360   if (f->current_display_lines)
361     Dynarr_reset (f->current_display_lines);
362   /* we have to do this in-case there were subwindows where we are
363      redrawing, unfortunately sometimes this also generates expose
364      events resulting in an endless cycle of redsplay. */
365   newx = max (x, g_x);
366   newy = max (y, g_y);
367   width = min (x + width - newx, g_x + g_width - newx);
368   height = min (y + height - newy, g_y + g_height - newy);
369   redisplay_unmap_subwindows_maybe (f, newx, newy, width, height);
370
371   /* Even if none of the gutter is in the area, the blank region at
372      the very least must be because the first thing we did is verify
373      that some portion of the gutter is in the exposed region. */
374   output_gutter (f, pos);
375 }
376
377 void
378 redraw_exposed_gutters (struct frame *f, int x, int y, int width,
379                         int height)
380 {
381       int pos;
382       for (pos = 0; pos < 4; pos++)
383         {
384           if (FRAME_GUTTER_VISIBLE (f, pos))
385             redraw_exposed_gutter (f, pos, x, y, width, height);
386         }
387 }
388
389 void
390 free_frame_gutters (struct frame *f)
391 {
392   if (f->current_display_lines)
393     Dynarr_free (f->current_display_lines);
394   if (f->desired_display_lines)
395     Dynarr_free (f->desired_display_lines);
396 }
397
398 static enum gutter_pos
399 decode_gutter_position (Lisp_Object position)
400 {
401   if (EQ (position, Qtop))    return TOP_GUTTER;
402   if (EQ (position, Qbottom)) return BOTTOM_GUTTER;
403   if (EQ (position, Qleft))   return LEFT_GUTTER;
404   if (EQ (position, Qright))  return RIGHT_GUTTER;
405   signal_simple_error ("Invalid gutter position", position);
406
407   return TOP_GUTTER; /* not reached */
408 }
409
410 DEFUN ("set-default-gutter-position", Fset_default_gutter_position, 1, 1, 0, /*
411 Set the position that the `default-gutter' will be displayed at.
412 Valid positions are 'top, 'bottom, 'left and 'right.
413 See `default-gutter-position'.
414 */
415        (position))
416 {
417   enum gutter_pos cur = decode_gutter_position (Vdefault_gutter_position);
418   enum gutter_pos new = decode_gutter_position (position);
419
420   if (cur != new)
421     {
422       /* The following calls will automatically cause the dirty
423          flags to be set; we delay frame size changes to avoid
424          lots of frame flickering. */
425       /* #### I think this should be GC protected. -sb */
426       hold_frame_size_changes ();
427       set_specifier_fallback (Vgutter[cur], list1 (Fcons (Qnil, Qnil)));
428       set_specifier_fallback (Vgutter[new], Vdefault_gutter);
429       set_specifier_fallback (Vgutter_size[cur], list1 (Fcons (Qnil, Qzero)));
430       set_specifier_fallback (Vgutter_size[new],
431                               new == TOP_GUTTER || new == BOTTOM_GUTTER
432                               ? Vdefault_gutter_height
433                               : Vdefault_gutter_width);
434       set_specifier_fallback (Vgutter_border_width[cur],
435                               list1 (Fcons (Qnil, Qzero)));
436       set_specifier_fallback (Vgutter_border_width[new],
437                               Vdefault_gutter_border_width);
438       set_specifier_fallback (Vgutter_visible_p[cur],
439                               list1 (Fcons (Qnil, Qt)));
440       set_specifier_fallback (Vgutter_visible_p[new],
441                               Vdefault_gutter_visible_p);
442       Vdefault_gutter_position = position;
443       unhold_frame_size_changes ();
444     }
445
446   return position;
447 }
448
449 DEFUN ("default-gutter-position", Fdefault_gutter_position, 0, 0, 0, /*
450 Return the position that the `default-gutter' will be displayed at.
451 The `default-gutter' will only be displayed here if the corresponding
452 position-specific gutter specifier does not provide a value.
453 */
454        ())
455 {
456   return Vdefault_gutter_position;
457 }
458
459 DEFUN ("gutter-pixel-width", Fgutter_pixel_width, 0, 2, 0, /*
460 Return the pixel width of the gutter at POS in LOCALE.
461 POS defaults to the default gutter position. LOCALE defaults to
462 the current window.
463 */
464        (pos, locale))
465 {
466   int x, y, width, height;
467   enum gutter_pos p = TOP_GUTTER;
468   struct frame *f = decode_frame (FW_FRAME (locale));
469
470   if (NILP (pos))
471     pos = Vdefault_gutter_position;
472   p = decode_gutter_position (pos);
473
474   get_gutter_coords (f, p, &x, &y, &width, &height);
475   width -= (FRAME_GUTTER_BORDER_WIDTH (f, p) * 2);
476
477   return make_int (width);
478 }
479
480 DEFUN ("gutter-pixel-height", Fgutter_pixel_height, 0, 2, 0, /*
481 Return the pixel height of the gutter at POS in LOCALE.
482 POS defaults to the default gutter position. LOCALE defaults to
483 the current window.
484 */
485        (pos, locale))
486 {
487   int x, y, width, height;
488   enum gutter_pos p = TOP_GUTTER;
489   struct frame *f = decode_frame (FW_FRAME (locale));
490
491   if (NILP (pos))
492     pos = Vdefault_gutter_position;
493   p = decode_gutter_position (pos);
494
495   get_gutter_coords (f, p, &x, &y, &width, &height);
496   height -= (FRAME_GUTTER_BORDER_WIDTH (f, p) * 2);
497
498   return make_int (height);
499 }
500
501 DEFINE_SPECIFIER_TYPE (gutter);
502
503 static void
504 gutter_after_change (Lisp_Object specifier, Lisp_Object locale)
505 {
506   MARK_GUTTER_CHANGED;
507 }
508
509 static void
510 gutter_validate (Lisp_Object instantiator)
511 {
512   if (NILP (instantiator))
513     return;
514
515   if (!STRINGP (instantiator))
516     signal_simple_error ("Gutter spec must be string or nil", instantiator);
517 }
518
519 DEFUN ("gutter-specifier-p", Fgutter_specifier_p, 1, 1, 0, /*
520 Return non-nil if OBJECT is a gutter specifier.
521 Gutter specifiers are used to specify the format of a gutter.
522 The values of the variables `default-gutter', `top-gutter',
523 `left-gutter', `right-gutter', and `bottom-gutter' are always
524 gutter specifiers.
525
526 Valid gutter instantiators are called "gutter descriptors"
527 and are lists of vectors.  See `default-gutter' for a description
528 of the exact format.
529 */
530        (object))
531 {
532   return GUTTER_SPECIFIERP (object) ? Qt : Qnil;
533 }
534
535 \f
536 /*
537   Helper for invalidating the real specifier when default
538   specifier caching changes
539 */
540 static void
541 recompute_overlaying_specifier (Lisp_Object real_one[4])
542 {
543   enum gutter_pos pos = decode_gutter_position (Vdefault_gutter_position);
544   Fset_specifier_dirty_flag (real_one[pos]);
545 }
546
547 static void
548 gutter_specs_changed (Lisp_Object specifier, struct window *w,
549                        Lisp_Object oldval)
550 {
551   int pos;
552   for (pos = 0; pos< 4; pos++)
553     {
554       w->real_gutter_size[pos] = w->gutter_size[pos];
555       if (EQ (w->real_gutter_size[pos], Qautodetect)
556           && !NILP (w->gutter_visible_p[pos]))
557         {
558           w->real_gutter_size [pos] = calculate_gutter_size (w, pos);
559         }
560     }
561   MARK_GUTTER_CHANGED;
562   MARK_WINDOWS_CHANGED (w);
563 }
564
565 static void
566 default_gutter_specs_changed (Lisp_Object specifier, struct window *w,
567                                Lisp_Object oldval)
568 {
569   recompute_overlaying_specifier (Vgutter);
570 }
571
572 static void
573 gutter_geometry_changed_in_window (Lisp_Object specifier, struct window *w,
574                                     Lisp_Object oldval)
575 {
576   int pos;
577   for (pos = 0; pos< 4; pos++)
578     {
579       w->real_gutter_size[pos] = w->gutter_size[pos];
580       if (EQ (w->real_gutter_size[pos], Qautodetect)
581           && !NILP (w->gutter_visible_p[pos]))
582         {
583           w->real_gutter_size [pos] = calculate_gutter_size (w, pos);
584         }
585     }
586   
587   MARK_GUTTER_CHANGED;
588   MARK_WINDOWS_CHANGED (w);
589 }
590
591 static void
592 default_gutter_size_changed_in_window (Lisp_Object specifier, struct window *w,
593                                         Lisp_Object oldval)
594 {
595   recompute_overlaying_specifier (Vgutter_size);
596 }
597
598 static void
599 default_gutter_border_width_changed_in_window (Lisp_Object specifier,
600                                                 struct window *w,
601                                                 Lisp_Object oldval)
602 {
603   recompute_overlaying_specifier (Vgutter_border_width);
604 }
605
606 static void
607 default_gutter_visible_p_changed_in_window (Lisp_Object specifier,
608                                              struct window *w,
609                                              Lisp_Object oldval)
610 {
611   recompute_overlaying_specifier (Vgutter_visible_p);
612 }
613
614 void
615 init_frame_gutters (struct frame *f)
616 {
617   int pos;
618   struct window* w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
619   /* We are here as far in frame creation so cached specifiers are
620      already recomputed, and possibly modified by resource
621      initialization. We need to recalculate autodetected gutters. */
622   for (pos = 0; pos< 4; pos++)
623     {
624       w->real_gutter_size[pos] = w->gutter_size[pos];
625       if (EQ (w->gutter_size[pos], Qautodetect)
626           && !NILP (w->gutter_visible_p[pos]))
627         {
628           w->real_gutter_size [pos] = calculate_gutter_size (w, pos);
629           MARK_GUTTER_CHANGED;
630           MARK_WINDOWS_CHANGED (w);
631         }
632     }
633 }
634
635 void
636 syms_of_gutter (void)
637 {
638   DEFSUBR (Fgutter_specifier_p);
639   DEFSUBR (Fset_default_gutter_position);
640   DEFSUBR (Fdefault_gutter_position);
641   DEFSUBR (Fgutter_pixel_height);
642   DEFSUBR (Fgutter_pixel_width);
643 }
644
645 void
646 vars_of_gutter (void)
647 {
648   staticpro (&Vdefault_gutter_position);
649   Vdefault_gutter_position = Qtop;
650
651   Fprovide (Qgutter);
652 }
653
654 void
655 specifier_type_create_gutter (void)
656 {
657   INITIALIZE_SPECIFIER_TYPE (gutter, "gutter", "gutter-specifier-p");
658
659   SPECIFIER_HAS_METHOD (gutter, validate);
660   SPECIFIER_HAS_METHOD (gutter, after_change);
661 }
662
663 void
664 specifier_vars_of_gutter (void)
665 {
666   Lisp_Object fb;
667
668   DEFVAR_SPECIFIER ("default-gutter", &Vdefault_gutter /*
669 Specifier for a fallback gutter.
670 Use `set-specifier' to change this.
671
672 The position of this gutter is specified in the function
673 `default-gutter-position'.  If the corresponding position-specific
674 gutter (e.g. `top-gutter' if `default-gutter-position' is 'top)
675 does not specify a gutter in a particular domain (usually a window),
676 then the value of `default-gutter' in that domain, if any, will be
677 used instead.
678
679 Note that the gutter at any particular position will not be
680 displayed unless its visibility flag is true and its thickness
681 \(width or height, depending on orientation) is non-zero.  The
682 visibility is controlled by the specifiers `top-gutter-visible-p',
683 `bottom-gutter-visible-p', `left-gutter-visible-p', and
684 `right-gutter-visible-p', and the thickness is controlled by the
685 specifiers `top-gutter-height', `bottom-gutter-height',
686 `left-gutter-width', and `right-gutter-width'.
687
688 Note that one of the four visibility specifiers inherits from
689 `default-gutter-visibility' and one of the four thickness
690 specifiers inherits from either `default-gutter-width' or
691 `default-gutter-height' (depending on orientation), just
692 like for the gutter description specifiers (e.g. `top-gutter')
693 mentioned above.
694
695 Therefore, if you are setting `default-gutter', you should control
696 the visibility and thickness using `default-gutter-visible-p',
697 `default-gutter-width', and `default-gutter-height', rather than
698 using position-specific specifiers.  That way, you will get sane
699 behavior if the user changes the default gutter position.
700
701 The gutter value should be a string or nil. You can attach extents and
702 glyphs to the string and hence display glyphs and text in other fonts
703 in the gutter area.
704
705 */ );
706
707   Vdefault_gutter = Fmake_specifier (Qgutter);
708   /* #### It would be even nicer if the specifier caching
709      automatically knew about specifier fallbacks, so we didn't
710      have to do it ourselves. */
711   set_specifier_caching (Vdefault_gutter,
712                          slot_offset (struct window,
713                                       default_gutter),
714                          default_gutter_specs_changed,
715                          0, 0);
716
717   DEFVAR_SPECIFIER ("top-gutter",
718                     &Vgutter[TOP_GUTTER] /*
719 Specifier for the gutter at the top of the frame.
720 Use `set-specifier' to change this.
721 See `default-gutter' for a description of a valid gutter instantiator.
722 */ );
723   Vgutter[TOP_GUTTER] = Fmake_specifier (Qgutter);
724   set_specifier_caching (Vgutter[TOP_GUTTER],
725                          slot_offset (struct window,
726                                       gutter[TOP_GUTTER]),
727                          gutter_specs_changed,
728                          0, 0);
729
730   DEFVAR_SPECIFIER ("bottom-gutter",
731                     &Vgutter[BOTTOM_GUTTER] /*
732 Specifier for the gutter at the bottom of the frame.
733 Use `set-specifier' to change this.
734 See `default-gutter' for a description of a valid gutter instantiator.
735
736 Note that, unless the `default-gutter-position' is `bottom', by
737 default the height of the bottom gutter (controlled by
738 `bottom-gutter-height') is 0; thus, a bottom gutter will not be
739 displayed even if you provide a value for `bottom-gutter'.
740 */ );
741   Vgutter[BOTTOM_GUTTER] = Fmake_specifier (Qgutter);
742   set_specifier_caching (Vgutter[BOTTOM_GUTTER],
743                          slot_offset (struct window,
744                                       gutter[BOTTOM_GUTTER]),
745                          gutter_specs_changed,
746                          0, 0);
747
748   DEFVAR_SPECIFIER ("left-gutter",
749                     &Vgutter[LEFT_GUTTER] /*
750 Specifier for the gutter at the left edge of the frame.
751 Use `set-specifier' to change this.
752 See `default-gutter' for a description of a valid gutter instantiator.
753
754 Note that, unless the `default-gutter-position' is `left', by
755 default the height of the left gutter (controlled by
756 `left-gutter-width') is 0; thus, a left gutter will not be
757 displayed even if you provide a value for `left-gutter'.
758 */ );
759   Vgutter[LEFT_GUTTER] = Fmake_specifier (Qgutter);
760   set_specifier_caching (Vgutter[LEFT_GUTTER],
761                          slot_offset (struct window,
762                                       gutter[LEFT_GUTTER]),
763                          gutter_specs_changed,
764                          0, 0);
765
766   DEFVAR_SPECIFIER ("right-gutter",
767                     &Vgutter[RIGHT_GUTTER] /*
768 Specifier for the gutter at the right edge of the frame.
769 Use `set-specifier' to change this.
770 See `default-gutter' for a description of a valid gutter instantiator.
771
772 Note that, unless the `default-gutter-position' is `right', by
773 default the height of the right gutter (controlled by
774 `right-gutter-width') is 0; thus, a right gutter will not be
775 displayed even if you provide a value for `right-gutter'.
776 */ );
777   Vgutter[RIGHT_GUTTER] = Fmake_specifier (Qgutter);
778   set_specifier_caching (Vgutter[RIGHT_GUTTER],
779                          slot_offset (struct window,
780                                       gutter[RIGHT_GUTTER]),
781                          gutter_specs_changed,
782                          0, 0);
783
784   /* initially, top inherits from default; this can be
785      changed with `set-default-gutter-position'. */
786   fb = list1 (Fcons (Qnil, Qnil));
787   set_specifier_fallback (Vdefault_gutter, fb);
788   set_specifier_fallback (Vgutter[TOP_GUTTER], Vdefault_gutter);
789   set_specifier_fallback (Vgutter[BOTTOM_GUTTER], fb);
790   set_specifier_fallback (Vgutter[LEFT_GUTTER],   fb);
791   set_specifier_fallback (Vgutter[RIGHT_GUTTER],  fb);
792
793   DEFVAR_SPECIFIER ("default-gutter-height", &Vdefault_gutter_height /*
794 *Height of the default gutter, if it's oriented horizontally.
795 This is a specifier; use `set-specifier' to change it.
796
797 The position of the default gutter is specified by the function
798 `set-default-gutter-position'.  If the corresponding position-specific
799 gutter thickness specifier (e.g. `top-gutter-height' if
800 `default-gutter-position' is 'top) does not specify a thickness in a
801 particular domain (a window or a frame), then the value of
802 `default-gutter-height' or `default-gutter-width' (depending on the
803 gutter orientation) in that domain, if any, will be used instead.
804
805 Note that `default-gutter-height' is only used when
806 `default-gutter-position' is 'top or 'bottom, and `default-gutter-width'
807 is only used when `default-gutter-position' is 'left or 'right.
808
809 Note that all of the position-specific gutter thickness specifiers
810 have a fallback value of zero when they do not correspond to the
811 default gutter.  Therefore, you will have to set a non-zero thickness
812 value if you want a position-specific gutter to be displayed.
813
814 If you set the height to 'autodetect the size of the gutter will be
815 calculated to be large enough to hold the contents of the gutter. This
816 is the default.
817 */ );
818   Vdefault_gutter_height = Fmake_specifier (Qgeneric);
819   set_specifier_caching (Vdefault_gutter_height,
820                          slot_offset (struct window,
821                                       default_gutter_height),
822                          default_gutter_size_changed_in_window,
823                          0, 0);
824
825   DEFVAR_SPECIFIER ("default-gutter-width", &Vdefault_gutter_width /*
826 *Width of the default gutter, if it's oriented vertically.
827 This is a specifier; use `set-specifier' to change it.
828
829 See `default-gutter-height' for more information.
830 */ );
831   Vdefault_gutter_width = Fmake_specifier (Qnatnum);
832   set_specifier_caching (Vdefault_gutter_width,
833                          slot_offset (struct window,
834                                       default_gutter_width),
835                          default_gutter_size_changed_in_window,
836                          0, 0);
837
838   DEFVAR_SPECIFIER ("top-gutter-height",
839                     &Vgutter_size[TOP_GUTTER] /*
840 *Height of the top gutter.
841 This is a specifier; use `set-specifier' to change it.
842
843 See `default-gutter-height' for more information.
844 */ );
845   Vgutter_size[TOP_GUTTER] = Fmake_specifier (Qgeneric);
846   set_specifier_caching (Vgutter_size[TOP_GUTTER],
847                          slot_offset (struct window,
848                                       gutter_size[TOP_GUTTER]),
849                          gutter_geometry_changed_in_window,
850                          0, 0);
851
852   DEFVAR_SPECIFIER ("bottom-gutter-height",
853                     &Vgutter_size[BOTTOM_GUTTER] /*
854 *Height of the bottom gutter.
855 This is a specifier; use `set-specifier' to change it.
856
857 See `default-gutter-height' for more information.
858 */ );
859   Vgutter_size[BOTTOM_GUTTER] = Fmake_specifier (Qgeneric);
860   set_specifier_caching (Vgutter_size[BOTTOM_GUTTER],
861                          slot_offset (struct window,
862                                       gutter_size[BOTTOM_GUTTER]),
863                          gutter_geometry_changed_in_window,
864                          0, 0);
865
866   DEFVAR_SPECIFIER ("left-gutter-width",
867                     &Vgutter_size[LEFT_GUTTER] /*
868 *Width of left gutter.
869 This is a specifier; use `set-specifier' to change it.
870
871 See `default-gutter-height' for more information.
872 */ );
873   Vgutter_size[LEFT_GUTTER] = Fmake_specifier (Qnatnum);
874   set_specifier_caching (Vgutter_size[LEFT_GUTTER],
875                          slot_offset (struct window,
876                                       gutter_size[LEFT_GUTTER]),
877                          gutter_geometry_changed_in_window,
878                          0, 0);
879
880   DEFVAR_SPECIFIER ("right-gutter-width",
881                     &Vgutter_size[RIGHT_GUTTER] /*
882 *Width of right gutter.
883 This is a specifier; use `set-specifier' to change it.
884
885 See `default-gutter-height' for more information.
886 */ );
887   Vgutter_size[RIGHT_GUTTER] = Fmake_specifier (Qnatnum);
888   set_specifier_caching (Vgutter_size[RIGHT_GUTTER],
889                          slot_offset (struct window,
890                                       gutter_size[RIGHT_GUTTER]),
891                          gutter_geometry_changed_in_window,
892                          0, 0);
893
894   fb = Qnil;
895 #ifdef HAVE_TTY
896   fb = Fcons (Fcons (list1 (Qtty), Qautodetect), fb);
897 #endif
898 #ifdef HAVE_X_WINDOWS
899   fb = Fcons (Fcons (list1 (Qx), Qautodetect), fb);
900 #endif
901 #ifdef HAVE_MS_WINDOWS
902   fb = Fcons (Fcons (list1 (Qmswindows), Qautodetect), fb);
903 #endif
904   if (!NILP (fb))
905     set_specifier_fallback (Vdefault_gutter_height, fb);
906
907   fb = Qnil;
908 #ifdef HAVE_TTY
909   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
910 #endif
911 #ifdef HAVE_X_WINDOWS
912   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_GUTTER_WIDTH)), fb);
913 #endif
914 #ifdef HAVE_MS_WINDOWS
915   fb = Fcons (Fcons (list1 (Qmswindows), 
916                      make_int (DEFAULT_GUTTER_WIDTH)), fb);
917 #endif
918   if (!NILP (fb))
919     set_specifier_fallback (Vdefault_gutter_width, fb);
920
921   set_specifier_fallback (Vgutter_size[TOP_GUTTER], Vdefault_gutter_height);
922   fb = list1 (Fcons (Qnil, Qzero));
923   set_specifier_fallback (Vgutter_size[BOTTOM_GUTTER], fb);
924   set_specifier_fallback (Vgutter_size[LEFT_GUTTER],   fb);
925   set_specifier_fallback (Vgutter_size[RIGHT_GUTTER],  fb);
926
927   DEFVAR_SPECIFIER ("default-gutter-border-width",
928                     &Vdefault_gutter_border_width /*
929 *Width of the border around the default gutter.
930 This is a specifier; use `set-specifier' to change it.
931
932 The position of the default gutter is specified by the function
933 `set-default-gutter-position'.  If the corresponding position-specific
934 gutter border width specifier (e.g. `top-gutter-border-width' if
935 `default-gutter-position' is 'top) does not specify a border width in a
936 particular domain (a window or a frame), then the value of
937 `default-gutter-border-width' in that domain, if any, will be used
938 instead.
939
940 */ );
941   Vdefault_gutter_border_width = Fmake_specifier (Qnatnum);
942   set_specifier_caching (Vdefault_gutter_border_width,
943                          slot_offset (struct window,
944                                       default_gutter_border_width),
945                          default_gutter_border_width_changed_in_window,
946                          0, 0);
947
948   DEFVAR_SPECIFIER ("top-gutter-border-width",
949                     &Vgutter_border_width[TOP_GUTTER] /*
950 *Border width of the top gutter.
951 This is a specifier; use `set-specifier' to change it.
952
953 See `default-gutter-height' for more information.
954 */ );
955   Vgutter_border_width[TOP_GUTTER] = Fmake_specifier (Qnatnum);
956   set_specifier_caching (Vgutter_border_width[TOP_GUTTER],
957                          slot_offset (struct window,
958                                       gutter_border_width[TOP_GUTTER]),
959                          gutter_geometry_changed_in_window,
960                          0, 0);
961
962   DEFVAR_SPECIFIER ("bottom-gutter-border-width",
963                     &Vgutter_border_width[BOTTOM_GUTTER] /*
964 *Border width of the bottom gutter.
965 This is a specifier; use `set-specifier' to change it.
966
967 See `default-gutter-height' for more information.
968 */ );
969   Vgutter_border_width[BOTTOM_GUTTER] = Fmake_specifier (Qnatnum);
970   set_specifier_caching (Vgutter_border_width[BOTTOM_GUTTER],
971                          slot_offset (struct window,
972                                       gutter_border_width[BOTTOM_GUTTER]),
973                          gutter_geometry_changed_in_window,
974                          0, 0);
975
976   DEFVAR_SPECIFIER ("left-gutter-border-width",
977                     &Vgutter_border_width[LEFT_GUTTER] /*
978 *Border width of left gutter.
979 This is a specifier; use `set-specifier' to change it.
980
981 See `default-gutter-height' for more information.
982 */ );
983   Vgutter_border_width[LEFT_GUTTER] = Fmake_specifier (Qnatnum);
984   set_specifier_caching (Vgutter_border_width[LEFT_GUTTER],
985                          slot_offset (struct window,
986                                       gutter_border_width[LEFT_GUTTER]),
987                          gutter_geometry_changed_in_window,
988                          0, 0);
989
990   DEFVAR_SPECIFIER ("right-gutter-border-width",
991                     &Vgutter_border_width[RIGHT_GUTTER] /*
992 *Border width of right gutter.
993 This is a specifier; use `set-specifier' to change it.
994
995 See `default-gutter-height' for more information.
996 */ );
997   Vgutter_border_width[RIGHT_GUTTER] = Fmake_specifier (Qnatnum);
998   set_specifier_caching (Vgutter_border_width[RIGHT_GUTTER],
999                          slot_offset (struct window,
1000                                       gutter_border_width[RIGHT_GUTTER]),
1001                          gutter_geometry_changed_in_window,
1002                          0, 0);
1003
1004   fb = Qnil;
1005 #ifdef HAVE_TTY
1006   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1007 #endif
1008 #ifdef HAVE_X_WINDOWS
1009   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_GUTTER_BORDER_WIDTH)), fb);
1010 #endif
1011 #ifdef HAVE_MS_WINDOWS
1012   fb = Fcons (Fcons (list1 (Qmswindows), make_int (DEFAULT_GUTTER_BORDER_WIDTH)), fb);
1013 #endif
1014   if (!NILP (fb))
1015     set_specifier_fallback (Vdefault_gutter_border_width, fb);
1016
1017   set_specifier_fallback (Vgutter_border_width[TOP_GUTTER], Vdefault_gutter_border_width);
1018   fb = list1 (Fcons (Qnil, Qzero));
1019   set_specifier_fallback (Vgutter_border_width[BOTTOM_GUTTER], fb);
1020   set_specifier_fallback (Vgutter_border_width[LEFT_GUTTER],   fb);
1021   set_specifier_fallback (Vgutter_border_width[RIGHT_GUTTER],  fb);
1022
1023   DEFVAR_SPECIFIER ("default-gutter-visible-p", &Vdefault_gutter_visible_p /*
1024 *Whether the default gutter is visible.
1025 This is a specifier; use `set-specifier' to change it.
1026
1027 The position of the default gutter is specified by the function
1028 `set-default-gutter-position'.  If the corresponding position-specific
1029 gutter visibility specifier (e.g. `top-gutter-visible-p' if
1030 `default-gutter-position' is 'top) does not specify a visible-p value
1031 in a particular domain (a window or a frame), then the value of
1032 `default-gutter-visible-p' in that domain, if any, will be used
1033 instead.
1034
1035 `default-gutter-visible-p' and all of the position-specific gutter
1036 visibility specifiers have a fallback value of true.
1037 */ );
1038   Vdefault_gutter_visible_p = Fmake_specifier (Qboolean);
1039   set_specifier_caching (Vdefault_gutter_visible_p,
1040                          slot_offset (struct window,
1041                                       default_gutter_visible_p),
1042                          default_gutter_visible_p_changed_in_window,
1043                          0, 0);
1044
1045   DEFVAR_SPECIFIER ("top-gutter-visible-p",
1046                     &Vgutter_visible_p[TOP_GUTTER] /*
1047 *Whether the top gutter is visible.
1048 This is a specifier; use `set-specifier' to change it.
1049
1050 See `default-gutter-visible-p' for more information.
1051 */ );
1052   Vgutter_visible_p[TOP_GUTTER] = Fmake_specifier (Qboolean);
1053   set_specifier_caching (Vgutter_visible_p[TOP_GUTTER],
1054                          slot_offset (struct window,
1055                                       gutter_visible_p[TOP_GUTTER]),
1056                          gutter_geometry_changed_in_window,
1057                          0, 0);
1058
1059   DEFVAR_SPECIFIER ("bottom-gutter-visible-p",
1060                     &Vgutter_visible_p[BOTTOM_GUTTER] /*
1061 *Whether the bottom gutter is visible.
1062 This is a specifier; use `set-specifier' to change it.
1063
1064 See `default-gutter-visible-p' for more information.
1065 */ );
1066   Vgutter_visible_p[BOTTOM_GUTTER] = Fmake_specifier (Qboolean);
1067   set_specifier_caching (Vgutter_visible_p[BOTTOM_GUTTER],
1068                          slot_offset (struct window,
1069                                       gutter_visible_p[BOTTOM_GUTTER]),
1070                          gutter_geometry_changed_in_window,
1071                          0, 0);
1072
1073   DEFVAR_SPECIFIER ("left-gutter-visible-p",
1074                     &Vgutter_visible_p[LEFT_GUTTER] /*
1075 *Whether the left gutter is visible.
1076 This is a specifier; use `set-specifier' to change it.
1077
1078 See `default-gutter-visible-p' for more information.
1079 */ );
1080   Vgutter_visible_p[LEFT_GUTTER] = Fmake_specifier (Qboolean);
1081   set_specifier_caching (Vgutter_visible_p[LEFT_GUTTER],
1082                          slot_offset (struct window,
1083                                       gutter_visible_p[LEFT_GUTTER]),
1084                          gutter_geometry_changed_in_window,
1085                          0, 0);
1086
1087   DEFVAR_SPECIFIER ("right-gutter-visible-p",
1088                     &Vgutter_visible_p[RIGHT_GUTTER] /*
1089 *Whether the right gutter is visible.
1090 This is a specifier; use `set-specifier' to change it.
1091
1092 See `default-gutter-visible-p' for more information.
1093 */ );
1094   Vgutter_visible_p[RIGHT_GUTTER] = Fmake_specifier (Qboolean);
1095   set_specifier_caching (Vgutter_visible_p[RIGHT_GUTTER],
1096                          slot_offset (struct window,
1097                                       gutter_visible_p[RIGHT_GUTTER]),
1098                          gutter_geometry_changed_in_window,
1099                          0, 0);
1100
1101   /* initially, top inherits from default; this can be
1102      changed with `set-default-gutter-position'. */
1103   fb = list1 (Fcons (Qnil, Qt));
1104   set_specifier_fallback (Vdefault_gutter_visible_p, fb);
1105   set_specifier_fallback (Vgutter_visible_p[TOP_GUTTER],
1106                           Vdefault_gutter_visible_p);
1107   set_specifier_fallback (Vgutter_visible_p[BOTTOM_GUTTER], fb);
1108   set_specifier_fallback (Vgutter_visible_p[LEFT_GUTTER],   fb);
1109   set_specifier_fallback (Vgutter_visible_p[RIGHT_GUTTER],  fb);
1110
1111 }