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