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