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