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