XEmacs 21.2.30 "Hygeia".
[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 /* #### I don't currently believe that redisplay needs to mark the
341    glyphs in its structures since these will always be referenced from
342    somewhere else. However, I'm not sure enough to stake my life on it
343    at this point, so we do the safe thing. */
344
345 /* See the comment in image_instantiate_cache_result as to why marking
346    the glyph will also mark the image_instance. */
347 void
348 mark_gutters (struct frame* f)
349 {
350   if (f->current_display_lines)
351     mark_redisplay_structs (f->current_display_lines);
352   if (f->desired_display_lines)
353     mark_redisplay_structs (f->desired_display_lines);
354 }
355
356 void
357 update_frame_gutters (struct frame *f)
358 {
359   if (f->gutter_changed || f->clear ||
360       f->glyphs_changed || f->subwindows_changed || 
361       f->windows_changed || f->windows_structure_changed || 
362       f->extents_changed || f->faces_changed)
363     {
364       enum gutter_pos pos;
365       
366       /* We don't actually care about these when outputting the gutter
367          so locally disable them. */
368       int local_clip_changed = f->clip_changed;
369       int local_buffers_changed = f->buffers_changed;
370       f->clip_changed = 0;
371       f->buffers_changed = 0;
372
373       /* and output */
374       GUTTER_POS_LOOP (pos)
375         {
376           if (FRAME_GUTTER_VISIBLE (f, pos))
377               output_gutter (f, pos);
378           else if (gutter_was_visible (f, pos))
379             clear_gutter (f, pos);
380         }
381       f->clip_changed = local_clip_changed;
382       f->buffers_changed = local_buffers_changed;
383       f->gutter_changed = 0;
384     }
385 }
386
387 void
388 reset_gutter_display_lines (struct frame* f)
389 {
390   if (f->current_display_lines)
391     Dynarr_reset (f->current_display_lines);
392 }
393
394 static void
395 redraw_exposed_gutter (struct frame *f, enum gutter_pos pos, int x, int y,
396                        int width, int height)
397 {
398   int g_x, g_y, g_width, g_height;
399
400   get_gutter_coords (f, pos, &g_x, &g_y, &g_width, &g_height);
401
402   if (((y + height) < g_y) || (y > (g_y + g_height)) || !height || !width || !g_height || !g_width)
403     return;
404   if (((x + width) < g_x) || (x > (g_x + g_width)))
405     return;
406
407   /* #### optimize this - redrawing the whole gutter for every expose
408      is very expensive. We reset the current display lines because if
409      they're being exposed they are no longer current. */
410   reset_gutter_display_lines (f);
411
412   /* Even if none of the gutter is in the area, the blank region at
413      the very least must be because the first thing we did is verify
414      that some portion of the gutter is in the exposed region. */
415   output_gutter (f, pos);
416 }
417
418 void
419 redraw_exposed_gutters (struct frame *f, int x, int y, int width,
420                         int height)
421 {
422   enum gutter_pos pos;
423   GUTTER_POS_LOOP (pos)
424     {
425       if (FRAME_GUTTER_VISIBLE (f, pos))
426         redraw_exposed_gutter (f, pos, x, y, width, height);
427     }
428 }
429
430 void
431 free_frame_gutters (struct frame *f)
432 {
433   if (f->current_display_lines)
434     {
435       free_display_lines (f->current_display_lines);
436       f->current_display_lines = 0;
437     }
438   if (f->desired_display_lines)
439     {
440       free_display_lines (f->desired_display_lines);
441       f->desired_display_lines = 0;
442     }
443 }
444
445 static enum gutter_pos
446 decode_gutter_position (Lisp_Object position)
447 {
448   if (EQ (position, Qtop))    return TOP_GUTTER;
449   if (EQ (position, Qbottom)) return BOTTOM_GUTTER;
450   if (EQ (position, Qleft))   return LEFT_GUTTER;
451   if (EQ (position, Qright))  return RIGHT_GUTTER;
452   signal_simple_error ("Invalid gutter position", position);
453
454   return TOP_GUTTER; /* not reached */
455 }
456
457 DEFUN ("set-default-gutter-position", Fset_default_gutter_position, 1, 1, 0, /*
458 Set the position that the `default-gutter' will be displayed at.
459 Valid positions are 'top, 'bottom, 'left and 'right.
460 See `default-gutter-position'.
461 */
462        (position))
463 {
464   enum gutter_pos cur = decode_gutter_position (Vdefault_gutter_position);
465   enum gutter_pos new = decode_gutter_position (position);
466
467   if (cur != new)
468     {
469       /* The following calls will automatically cause the dirty
470          flags to be set; we delay frame size changes to avoid
471          lots of frame flickering. */
472       /* #### I think this should be GC protected. -sb */
473       hold_frame_size_changes ();
474       set_specifier_fallback (Vgutter[cur], list1 (Fcons (Qnil, Qnil)));
475       set_specifier_fallback (Vgutter[new], Vdefault_gutter);
476       set_specifier_fallback (Vgutter_size[cur], list1 (Fcons (Qnil, Qzero)));
477       set_specifier_fallback (Vgutter_size[new],
478                               new == TOP_GUTTER || new == BOTTOM_GUTTER
479                               ? Vdefault_gutter_height
480                               : Vdefault_gutter_width);
481       set_specifier_fallback (Vgutter_border_width[cur],
482                               list1 (Fcons (Qnil, Qzero)));
483       set_specifier_fallback (Vgutter_border_width[new],
484                               Vdefault_gutter_border_width);
485       set_specifier_fallback (Vgutter_visible_p[cur],
486                               list1 (Fcons (Qnil, Qt)));
487       set_specifier_fallback (Vgutter_visible_p[new],
488                               Vdefault_gutter_visible_p);
489       Vdefault_gutter_position = position;
490       unhold_frame_size_changes ();
491     }
492
493   return position;
494 }
495
496 DEFUN ("default-gutter-position", Fdefault_gutter_position, 0, 0, 0, /*
497 Return the position that the `default-gutter' will be displayed at.
498 The `default-gutter' will only be displayed here if the corresponding
499 position-specific gutter specifier does not provide a value.
500 */
501        ())
502 {
503   return Vdefault_gutter_position;
504 }
505
506 DEFUN ("gutter-pixel-width", Fgutter_pixel_width, 0, 2, 0, /*
507 Return the pixel width of the gutter at POS in LOCALE.
508 POS defaults to the default gutter position. LOCALE defaults to
509 the current window.
510 */
511        (pos, locale))
512 {
513   int x, y, width, height;
514   enum gutter_pos p = TOP_GUTTER;
515   struct frame *f = decode_frame (FW_FRAME (locale));
516
517   if (NILP (pos))
518     pos = Vdefault_gutter_position;
519   p = decode_gutter_position (pos);
520
521   get_gutter_coords (f, p, &x, &y, &width, &height);
522   width -= (FRAME_GUTTER_BORDER_WIDTH (f, p) * 2);
523
524   return make_int (width);
525 }
526
527 DEFUN ("gutter-pixel-height", Fgutter_pixel_height, 0, 2, 0, /*
528 Return the pixel height of the gutter at POS in LOCALE.
529 POS defaults to the default gutter position. LOCALE defaults to
530 the current window.
531 */
532        (pos, locale))
533 {
534   int x, y, width, height;
535   enum gutter_pos p = TOP_GUTTER;
536   struct frame *f = decode_frame (FW_FRAME (locale));
537
538   if (NILP (pos))
539     pos = Vdefault_gutter_position;
540   p = decode_gutter_position (pos);
541
542   get_gutter_coords (f, p, &x, &y, &width, &height);
543   height -= (FRAME_GUTTER_BORDER_WIDTH (f, p) * 2);
544
545   return make_int (height);
546 }
547
548 DEFINE_SPECIFIER_TYPE (gutter);
549
550 static void
551 gutter_after_change (Lisp_Object specifier, Lisp_Object locale)
552 {
553   MARK_GUTTER_CHANGED;
554 }
555
556 static void
557 gutter_validate (Lisp_Object instantiator)
558 {
559   if (NILP (instantiator))
560     return;
561
562   if (!STRINGP (instantiator))
563     signal_simple_error ("Gutter spec must be string or nil", instantiator);
564 }
565
566 DEFUN ("gutter-specifier-p", Fgutter_specifier_p, 1, 1, 0, /*
567 Return non-nil if OBJECT is a gutter specifier.
568 Gutter specifiers are used to specify the format of a gutter.
569 The values of the variables `default-gutter', `top-gutter',
570 `left-gutter', `right-gutter', and `bottom-gutter' are always
571 gutter specifiers.
572
573 Valid gutter instantiators are called "gutter descriptors"
574 and are lists of vectors.  See `default-gutter' for a description
575 of the exact format.
576 */
577        (object))
578 {
579   return GUTTER_SPECIFIERP (object) ? Qt : Qnil;
580 }
581
582 \f
583 /*
584   Helper for invalidating the real specifier when default
585   specifier caching changes
586 */
587 static void
588 recompute_overlaying_specifier (Lisp_Object real_one[4])
589 {
590   enum gutter_pos pos = decode_gutter_position (Vdefault_gutter_position);
591   Fset_specifier_dirty_flag (real_one[pos]);
592 }
593
594 static void
595 gutter_specs_changed (Lisp_Object specifier, struct window *w,
596                        Lisp_Object oldval)
597 {
598   enum gutter_pos pos;
599   GUTTER_POS_LOOP (pos)
600     {
601       w->real_gutter_size[pos] = w->gutter_size[pos];
602       if (EQ (w->real_gutter_size[pos], Qautodetect)
603           && !NILP (w->gutter_visible_p[pos]))
604         {
605           w->real_gutter_size [pos] = calculate_gutter_size (w, pos);
606         }
607     }
608   MARK_GUTTER_CHANGED;
609   MARK_WINDOWS_CHANGED (w);
610 }
611
612 static void
613 default_gutter_specs_changed (Lisp_Object specifier, struct window *w,
614                                Lisp_Object oldval)
615 {
616   recompute_overlaying_specifier (Vgutter);
617 }
618
619 static void
620 gutter_geometry_changed_in_window (Lisp_Object specifier, struct window *w,
621                                     Lisp_Object oldval)
622 {
623   enum gutter_pos pos;
624   GUTTER_POS_LOOP (pos)
625     {
626       w->real_gutter_size[pos] = w->gutter_size[pos];
627       if (EQ (w->real_gutter_size[pos], Qautodetect)
628           && !NILP (w->gutter_visible_p[pos]))
629         {
630           w->real_gutter_size [pos] = calculate_gutter_size (w, pos);
631         }
632     }
633   
634   MARK_GUTTER_CHANGED;
635   MARK_WINDOWS_CHANGED (w);
636 }
637
638 static void
639 default_gutter_size_changed_in_window (Lisp_Object specifier, struct window *w,
640                                         Lisp_Object oldval)
641 {
642   recompute_overlaying_specifier (Vgutter_size);
643 }
644
645 static void
646 default_gutter_border_width_changed_in_window (Lisp_Object specifier,
647                                                 struct window *w,
648                                                 Lisp_Object oldval)
649 {
650   recompute_overlaying_specifier (Vgutter_border_width);
651 }
652
653 static void
654 default_gutter_visible_p_changed_in_window (Lisp_Object specifier,
655                                              struct window *w,
656                                              Lisp_Object oldval)
657 {
658   recompute_overlaying_specifier (Vgutter_visible_p);
659 }
660
661
662 DECLARE_SPECIFIER_TYPE (gutter_size);
663 #define GUTTER_SIZE_SPECIFIERP(x) SPECIFIER_TYPEP (x, gutter_size)
664 DEFINE_SPECIFIER_TYPE (gutter_size);
665
666 static void
667 gutter_size_validate (Lisp_Object instantiator)
668 {
669   if (NILP (instantiator))
670     return;
671
672   if (!INTP (instantiator) && !EQ (instantiator, Qautodetect))
673     signal_simple_error ("Gutter size must be an integer or 'autodetect", instantiator);
674 }
675
676 DEFUN ("gutter-size-specifier-p", Fgutter_size_specifier_p, 1, 1, 0, /*
677 Return non-nil if OBJECT is a gutter-size specifier.
678 */
679        (object))
680 {
681   return GUTTER_SIZE_SPECIFIERP (object) ? Qt : Qnil;
682 }
683
684 DEFUN ("redisplay-gutter-area", Fredisplay_gutter_area, 0, 0, 0, /*
685 Ensure that all gutters are correctly showing their gutter specifier.
686 */
687        ())
688 {
689   Lisp_Object devcons, concons;
690
691   DEVICE_LOOP_NO_BREAK (devcons, concons)
692     {
693       struct device *d = XDEVICE (XCAR (devcons));
694       Lisp_Object frmcons;
695
696       DEVICE_FRAME_LOOP (frmcons, d)
697         {
698           struct frame *f = XFRAME (XCAR (frmcons));
699
700           if (FRAME_REPAINT_P (f))
701             {
702               update_frame_gutters (f);
703             }
704         }
705
706       /* We now call the output_end routine for tty frames.  We delay
707          doing so in order to avoid cursor flicker.  So much for 100%
708          encapsulation. */
709       if (DEVICE_TTY_P (d))
710         DEVMETH (d, output_end, (d));
711     }
712
713   return Qnil;
714 }
715
716 void
717 init_frame_gutters (struct frame *f)
718 {
719   enum gutter_pos pos;
720   struct window* w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
721   /* We are here as far in frame creation so cached specifiers are
722      already recomputed, and possibly modified by resource
723      initialization. We need to recalculate autodetected gutters. */
724   GUTTER_POS_LOOP (pos)
725     {
726       w->real_gutter_size[pos] = w->gutter_size[pos];
727       if (EQ (w->gutter_size[pos], Qautodetect)
728           && !NILP (w->gutter_visible_p[pos]))
729         {
730           w->real_gutter_size [pos] = calculate_gutter_size (w, pos);
731           MARK_GUTTER_CHANGED;
732           MARK_WINDOWS_CHANGED (w);
733         }
734     }
735 }
736
737 void
738 syms_of_gutter (void)
739 {
740   DEFSUBR (Fgutter_specifier_p);
741   DEFSUBR (Fgutter_size_specifier_p);
742   DEFSUBR (Fset_default_gutter_position);
743   DEFSUBR (Fdefault_gutter_position);
744   DEFSUBR (Fgutter_pixel_height);
745   DEFSUBR (Fgutter_pixel_width);
746   DEFSUBR (Fredisplay_gutter_area);
747
748   defsymbol (&Qgutter_size, "gutter-size");
749 }
750
751 void
752 vars_of_gutter (void)
753 {
754   staticpro (&Vdefault_gutter_position);
755   Vdefault_gutter_position = Qtop;
756
757   Fprovide (Qgutter);
758 }
759
760 void
761 specifier_type_create_gutter (void)
762 {
763   INITIALIZE_SPECIFIER_TYPE (gutter, "gutter", "gutter-specifier-p");
764
765   SPECIFIER_HAS_METHOD (gutter, validate);
766   SPECIFIER_HAS_METHOD (gutter, after_change);
767
768   INITIALIZE_SPECIFIER_TYPE (gutter_size, "gutter-size", "gutter-size-specifier-p");
769
770   SPECIFIER_HAS_METHOD (gutter_size, validate);
771 }
772
773 void
774 reinit_specifier_type_create_gutter (void)
775 {
776   REINITIALIZE_SPECIFIER_TYPE (gutter);
777   REINITIALIZE_SPECIFIER_TYPE (gutter_size);
778 }
779
780 void
781 specifier_vars_of_gutter (void)
782 {
783   Lisp_Object fb;
784
785   DEFVAR_SPECIFIER ("default-gutter", &Vdefault_gutter /*
786 Specifier for a fallback gutter.
787 Use `set-specifier' to change this.
788
789 The position of this gutter is specified in the function
790 `default-gutter-position'.  If the corresponding position-specific
791 gutter (e.g. `top-gutter' if `default-gutter-position' is 'top)
792 does not specify a gutter in a particular domain (usually a window),
793 then the value of `default-gutter' in that domain, if any, will be
794 used instead.
795
796 Note that the gutter at any particular position will not be
797 displayed unless its visibility flag is true and its thickness
798 \(width or height, depending on orientation) is non-zero.  The
799 visibility is controlled by the specifiers `top-gutter-visible-p',
800 `bottom-gutter-visible-p', `left-gutter-visible-p', and
801 `right-gutter-visible-p', and the thickness is controlled by the
802 specifiers `top-gutter-height', `bottom-gutter-height',
803 `left-gutter-width', and `right-gutter-width'.
804
805 Note that one of the four visibility specifiers inherits from
806 `default-gutter-visibility' and one of the four thickness
807 specifiers inherits from either `default-gutter-width' or
808 `default-gutter-height' (depending on orientation), just
809 like for the gutter description specifiers (e.g. `top-gutter')
810 mentioned above.
811
812 Therefore, if you are setting `default-gutter', you should control
813 the visibility and thickness using `default-gutter-visible-p',
814 `default-gutter-width', and `default-gutter-height', rather than
815 using position-specific specifiers.  That way, you will get sane
816 behavior if the user changes the default gutter position.
817
818 The gutter value should be a string or nil. You can attach extents and
819 glyphs to the string and hence display glyphs and text in other fonts
820 in the gutter area.
821
822 */ );
823
824   Vdefault_gutter = Fmake_specifier (Qgutter);
825   /* #### It would be even nicer if the specifier caching
826      automatically knew about specifier fallbacks, so we didn't
827      have to do it ourselves. */
828   set_specifier_caching (Vdefault_gutter,
829                          offsetof (struct window, default_gutter),
830                          default_gutter_specs_changed,
831                          0, 0);
832
833   DEFVAR_SPECIFIER ("top-gutter",
834                     &Vgutter[TOP_GUTTER] /*
835 Specifier for the gutter at the top of the frame.
836 Use `set-specifier' to change this.
837 See `default-gutter' for a description of a valid gutter instantiator.
838 */ );
839   Vgutter[TOP_GUTTER] = Fmake_specifier (Qgutter);
840   set_specifier_caching (Vgutter[TOP_GUTTER],
841                          offsetof (struct window, gutter[TOP_GUTTER]),
842                          gutter_specs_changed,
843                          0, 0);
844
845   DEFVAR_SPECIFIER ("bottom-gutter",
846                     &Vgutter[BOTTOM_GUTTER] /*
847 Specifier for the gutter at the bottom of the frame.
848 Use `set-specifier' to change this.
849 See `default-gutter' for a description of a valid gutter instantiator.
850
851 Note that, unless the `default-gutter-position' is `bottom', by
852 default the height of the bottom gutter (controlled by
853 `bottom-gutter-height') is 0; thus, a bottom gutter will not be
854 displayed even if you provide a value for `bottom-gutter'.
855 */ );
856   Vgutter[BOTTOM_GUTTER] = Fmake_specifier (Qgutter);
857   set_specifier_caching (Vgutter[BOTTOM_GUTTER],
858                          offsetof (struct window, gutter[BOTTOM_GUTTER]),
859                          gutter_specs_changed,
860                          0, 0);
861
862   DEFVAR_SPECIFIER ("left-gutter",
863                     &Vgutter[LEFT_GUTTER] /*
864 Specifier for the gutter at the left edge of the frame.
865 Use `set-specifier' to change this.
866 See `default-gutter' for a description of a valid gutter instantiator.
867
868 Note that, unless the `default-gutter-position' is `left', by
869 default the height of the left gutter (controlled by
870 `left-gutter-width') is 0; thus, a left gutter will not be
871 displayed even if you provide a value for `left-gutter'.
872 */ );
873   Vgutter[LEFT_GUTTER] = Fmake_specifier (Qgutter);
874   set_specifier_caching (Vgutter[LEFT_GUTTER],
875                          offsetof (struct window, gutter[LEFT_GUTTER]),
876                          gutter_specs_changed,
877                          0, 0);
878
879   DEFVAR_SPECIFIER ("right-gutter",
880                     &Vgutter[RIGHT_GUTTER] /*
881 Specifier for the gutter at the right edge of the frame.
882 Use `set-specifier' to change this.
883 See `default-gutter' for a description of a valid gutter instantiator.
884
885 Note that, unless the `default-gutter-position' is `right', by
886 default the height of the right gutter (controlled by
887 `right-gutter-width') is 0; thus, a right gutter will not be
888 displayed even if you provide a value for `right-gutter'.
889 */ );
890   Vgutter[RIGHT_GUTTER] = Fmake_specifier (Qgutter);
891   set_specifier_caching (Vgutter[RIGHT_GUTTER],
892                          offsetof (struct window, gutter[RIGHT_GUTTER]),
893                          gutter_specs_changed,
894                          0, 0);
895
896   /* initially, top inherits from default; this can be
897      changed with `set-default-gutter-position'. */
898   fb = list1 (Fcons (Qnil, Qnil));
899   set_specifier_fallback (Vdefault_gutter, fb);
900   set_specifier_fallback (Vgutter[TOP_GUTTER], Vdefault_gutter);
901   set_specifier_fallback (Vgutter[BOTTOM_GUTTER], fb);
902   set_specifier_fallback (Vgutter[LEFT_GUTTER],   fb);
903   set_specifier_fallback (Vgutter[RIGHT_GUTTER],  fb);
904
905   DEFVAR_SPECIFIER ("default-gutter-height", &Vdefault_gutter_height /*
906 *Height of the default gutter, if it's oriented horizontally.
907 This is a specifier; use `set-specifier' to change it.
908
909 The position of the default gutter is specified by the function
910 `set-default-gutter-position'.  If the corresponding position-specific
911 gutter thickness specifier (e.g. `top-gutter-height' if
912 `default-gutter-position' is 'top) does not specify a thickness in a
913 particular domain (a window or a frame), then the value of
914 `default-gutter-height' or `default-gutter-width' (depending on the
915 gutter orientation) in that domain, if any, will be used instead.
916
917 Note that `default-gutter-height' is only used when
918 `default-gutter-position' is 'top or 'bottom, and `default-gutter-width'
919 is only used when `default-gutter-position' is 'left or 'right.
920
921 Note that all of the position-specific gutter thickness specifiers
922 have a fallback value of zero when they do not correspond to the
923 default gutter.  Therefore, you will have to set a non-zero thickness
924 value if you want a position-specific gutter to be displayed.
925
926 If you set the height to 'autodetect the size of the gutter will be
927 calculated to be large enough to hold the contents of the gutter. This
928 is the default.
929 */ );
930   Vdefault_gutter_height = Fmake_specifier (Qgutter_size);
931   set_specifier_caching (Vdefault_gutter_height,
932                          offsetof (struct window, default_gutter_height),
933                          default_gutter_size_changed_in_window,
934                          0, 0);
935
936   DEFVAR_SPECIFIER ("default-gutter-width", &Vdefault_gutter_width /*
937 *Width of the default gutter, if it's oriented vertically.
938 This is a specifier; use `set-specifier' to change it.
939
940 See `default-gutter-height' for more information.
941 */ );
942   Vdefault_gutter_width = Fmake_specifier (Qnatnum);
943   set_specifier_caching (Vdefault_gutter_width,
944                          offsetof (struct window, default_gutter_width),
945                          default_gutter_size_changed_in_window,
946                          0, 0);
947
948   DEFVAR_SPECIFIER ("top-gutter-height",
949                     &Vgutter_size[TOP_GUTTER] /*
950 *Height of the top gutter.
951 This is a specifier; use `set-specifier' to change it.
952
953 See `default-gutter-height' for more information.
954 */ );
955   Vgutter_size[TOP_GUTTER] = Fmake_specifier (Qgutter_size);
956   set_specifier_caching (Vgutter_size[TOP_GUTTER],
957                          offsetof (struct window, gutter_size[TOP_GUTTER]),
958                          gutter_geometry_changed_in_window,
959                          0, 0);
960
961   DEFVAR_SPECIFIER ("bottom-gutter-height",
962                     &Vgutter_size[BOTTOM_GUTTER] /*
963 *Height of the bottom gutter.
964 This is a specifier; use `set-specifier' to change it.
965
966 See `default-gutter-height' for more information.
967 */ );
968   Vgutter_size[BOTTOM_GUTTER] = Fmake_specifier (Qgutter_size);
969   set_specifier_caching (Vgutter_size[BOTTOM_GUTTER],
970                          offsetof (struct window, gutter_size[BOTTOM_GUTTER]),
971                          gutter_geometry_changed_in_window,
972                          0, 0);
973
974   DEFVAR_SPECIFIER ("left-gutter-width",
975                     &Vgutter_size[LEFT_GUTTER] /*
976 *Width of left gutter.
977 This is a specifier; use `set-specifier' to change it.
978
979 See `default-gutter-height' for more information.
980 */ );
981   Vgutter_size[LEFT_GUTTER] = Fmake_specifier (Qnatnum);
982   set_specifier_caching (Vgutter_size[LEFT_GUTTER],
983                          offsetof (struct window, gutter_size[LEFT_GUTTER]),
984                          gutter_geometry_changed_in_window,
985                          0, 0);
986
987   DEFVAR_SPECIFIER ("right-gutter-width",
988                     &Vgutter_size[RIGHT_GUTTER] /*
989 *Width of right gutter.
990 This is a specifier; use `set-specifier' to change it.
991
992 See `default-gutter-height' for more information.
993 */ );
994   Vgutter_size[RIGHT_GUTTER] = Fmake_specifier (Qnatnum);
995   set_specifier_caching (Vgutter_size[RIGHT_GUTTER],
996                          offsetof (struct window, gutter_size[RIGHT_GUTTER]),
997                          gutter_geometry_changed_in_window,
998                          0, 0);
999
1000   fb = Qnil;
1001 #ifdef HAVE_TTY
1002   fb = Fcons (Fcons (list1 (Qtty), Qautodetect), fb);
1003 #endif
1004 #ifdef HAVE_X_WINDOWS
1005   fb = Fcons (Fcons (list1 (Qx), Qautodetect), fb);
1006 #endif
1007 #ifdef HAVE_MS_WINDOWS
1008   fb = Fcons (Fcons (list1 (Qmsprinter), Qautodetect), fb);
1009   fb = Fcons (Fcons (list1 (Qmswindows), Qautodetect), fb);
1010 #endif
1011   if (!NILP (fb))
1012     set_specifier_fallback (Vdefault_gutter_height, fb);
1013
1014   fb = Qnil;
1015 #ifdef HAVE_TTY
1016   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1017 #endif
1018 #ifdef HAVE_X_WINDOWS
1019   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_GUTTER_WIDTH)), fb);
1020 #endif
1021 #ifdef HAVE_MS_WINDOWS
1022   fb = Fcons (Fcons (list1 (Qmsprinter), Qzero), fb);
1023   fb = Fcons (Fcons (list1 (Qmswindows), 
1024                      make_int (DEFAULT_GUTTER_WIDTH)), fb);
1025 #endif
1026   if (!NILP (fb))
1027     set_specifier_fallback (Vdefault_gutter_width, fb);
1028
1029   set_specifier_fallback (Vgutter_size[TOP_GUTTER], Vdefault_gutter_height);
1030   fb = list1 (Fcons (Qnil, Qzero));
1031   set_specifier_fallback (Vgutter_size[BOTTOM_GUTTER], fb);
1032   set_specifier_fallback (Vgutter_size[LEFT_GUTTER],   fb);
1033   set_specifier_fallback (Vgutter_size[RIGHT_GUTTER],  fb);
1034
1035   DEFVAR_SPECIFIER ("default-gutter-border-width",
1036                     &Vdefault_gutter_border_width /*
1037 *Width of the border around the default gutter.
1038 This is a specifier; use `set-specifier' to change it.
1039
1040 The position of the default gutter is specified by the function
1041 `set-default-gutter-position'.  If the corresponding position-specific
1042 gutter border width specifier (e.g. `top-gutter-border-width' if
1043 `default-gutter-position' is 'top) does not specify a border width in a
1044 particular domain (a window or a frame), then the value of
1045 `default-gutter-border-width' in that domain, if any, will be used
1046 instead.
1047
1048 */ );
1049   Vdefault_gutter_border_width = Fmake_specifier (Qnatnum);
1050   set_specifier_caching (Vdefault_gutter_border_width,
1051                          offsetof (struct window, default_gutter_border_width),
1052                          default_gutter_border_width_changed_in_window,
1053                          0, 0);
1054
1055   DEFVAR_SPECIFIER ("top-gutter-border-width",
1056                     &Vgutter_border_width[TOP_GUTTER] /*
1057 *Border width of the top gutter.
1058 This is a specifier; use `set-specifier' to change it.
1059
1060 See `default-gutter-height' for more information.
1061 */ );
1062   Vgutter_border_width[TOP_GUTTER] = Fmake_specifier (Qnatnum);
1063   set_specifier_caching (Vgutter_border_width[TOP_GUTTER],
1064                          offsetof (struct window,
1065                                    gutter_border_width[TOP_GUTTER]),
1066                          gutter_geometry_changed_in_window,
1067                          0, 0);
1068
1069   DEFVAR_SPECIFIER ("bottom-gutter-border-width",
1070                     &Vgutter_border_width[BOTTOM_GUTTER] /*
1071 *Border width of the bottom gutter.
1072 This is a specifier; use `set-specifier' to change it.
1073
1074 See `default-gutter-height' for more information.
1075 */ );
1076   Vgutter_border_width[BOTTOM_GUTTER] = Fmake_specifier (Qnatnum);
1077   set_specifier_caching (Vgutter_border_width[BOTTOM_GUTTER],
1078                          offsetof (struct window,
1079                                    gutter_border_width[BOTTOM_GUTTER]),
1080                          gutter_geometry_changed_in_window,
1081                          0, 0);
1082
1083   DEFVAR_SPECIFIER ("left-gutter-border-width",
1084                     &Vgutter_border_width[LEFT_GUTTER] /*
1085 *Border width of left gutter.
1086 This is a specifier; use `set-specifier' to change it.
1087
1088 See `default-gutter-height' for more information.
1089 */ );
1090   Vgutter_border_width[LEFT_GUTTER] = Fmake_specifier (Qnatnum);
1091   set_specifier_caching (Vgutter_border_width[LEFT_GUTTER],
1092                          offsetof (struct window,
1093                                    gutter_border_width[LEFT_GUTTER]),
1094                          gutter_geometry_changed_in_window,
1095                          0, 0);
1096
1097   DEFVAR_SPECIFIER ("right-gutter-border-width",
1098                     &Vgutter_border_width[RIGHT_GUTTER] /*
1099 *Border width of right gutter.
1100 This is a specifier; use `set-specifier' to change it.
1101
1102 See `default-gutter-height' for more information.
1103 */ );
1104   Vgutter_border_width[RIGHT_GUTTER] = Fmake_specifier (Qnatnum);
1105   set_specifier_caching (Vgutter_border_width[RIGHT_GUTTER],
1106                          offsetof (struct window,
1107                                    gutter_border_width[RIGHT_GUTTER]),
1108                          gutter_geometry_changed_in_window,
1109                          0, 0);
1110
1111   fb = Qnil;
1112 #ifdef HAVE_TTY
1113   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1114 #endif
1115 #ifdef HAVE_X_WINDOWS
1116   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_GUTTER_BORDER_WIDTH)), fb);
1117 #endif
1118 #ifdef HAVE_MS_WINDOWS
1119   fb = Fcons (Fcons (list1 (Qmsprinter), Qzero), fb);
1120   fb = Fcons (Fcons (list1 (Qmswindows), make_int (DEFAULT_GUTTER_BORDER_WIDTH)), fb);
1121 #endif
1122   if (!NILP (fb))
1123     set_specifier_fallback (Vdefault_gutter_border_width, fb);
1124
1125   set_specifier_fallback (Vgutter_border_width[TOP_GUTTER], Vdefault_gutter_border_width);
1126   fb = list1 (Fcons (Qnil, Qzero));
1127   set_specifier_fallback (Vgutter_border_width[BOTTOM_GUTTER], fb);
1128   set_specifier_fallback (Vgutter_border_width[LEFT_GUTTER],   fb);
1129   set_specifier_fallback (Vgutter_border_width[RIGHT_GUTTER],  fb);
1130
1131   DEFVAR_SPECIFIER ("default-gutter-visible-p", &Vdefault_gutter_visible_p /*
1132 *Whether the default gutter is visible.
1133 This is a specifier; use `set-specifier' to change it.
1134
1135 The position of the default gutter is specified by the function
1136 `set-default-gutter-position'.  If the corresponding position-specific
1137 gutter visibility specifier (e.g. `top-gutter-visible-p' if
1138 `default-gutter-position' is 'top) does not specify a visible-p value
1139 in a particular domain (a window or a frame), then the value of
1140 `default-gutter-visible-p' in that domain, if any, will be used
1141 instead.
1142
1143 `default-gutter-visible-p' and all of the position-specific gutter
1144 visibility specifiers have a fallback value of true.
1145 */ );
1146   Vdefault_gutter_visible_p = Fmake_specifier (Qboolean);
1147   set_specifier_caching (Vdefault_gutter_visible_p,
1148                          offsetof (struct window,
1149                                    default_gutter_visible_p),
1150                          default_gutter_visible_p_changed_in_window,
1151                          0, 0);
1152
1153   DEFVAR_SPECIFIER ("top-gutter-visible-p",
1154                     &Vgutter_visible_p[TOP_GUTTER] /*
1155 *Whether the top gutter is visible.
1156 This is a specifier; use `set-specifier' to change it.
1157
1158 See `default-gutter-visible-p' for more information.
1159 */ );
1160   Vgutter_visible_p[TOP_GUTTER] = Fmake_specifier (Qboolean);
1161   set_specifier_caching (Vgutter_visible_p[TOP_GUTTER],
1162                          offsetof (struct window,
1163                                    gutter_visible_p[TOP_GUTTER]),
1164                          gutter_geometry_changed_in_window,
1165                          0, 0);
1166
1167   DEFVAR_SPECIFIER ("bottom-gutter-visible-p",
1168                     &Vgutter_visible_p[BOTTOM_GUTTER] /*
1169 *Whether the bottom gutter is visible.
1170 This is a specifier; use `set-specifier' to change it.
1171
1172 See `default-gutter-visible-p' for more information.
1173 */ );
1174   Vgutter_visible_p[BOTTOM_GUTTER] = Fmake_specifier (Qboolean);
1175   set_specifier_caching (Vgutter_visible_p[BOTTOM_GUTTER],
1176                          offsetof (struct window,
1177                                    gutter_visible_p[BOTTOM_GUTTER]),
1178                          gutter_geometry_changed_in_window,
1179                          0, 0);
1180
1181   DEFVAR_SPECIFIER ("left-gutter-visible-p",
1182                     &Vgutter_visible_p[LEFT_GUTTER] /*
1183 *Whether the left gutter is visible.
1184 This is a specifier; use `set-specifier' to change it.
1185
1186 See `default-gutter-visible-p' for more information.
1187 */ );
1188   Vgutter_visible_p[LEFT_GUTTER] = Fmake_specifier (Qboolean);
1189   set_specifier_caching (Vgutter_visible_p[LEFT_GUTTER],
1190                          offsetof (struct window,
1191                                    gutter_visible_p[LEFT_GUTTER]),
1192                          gutter_geometry_changed_in_window,
1193                          0, 0);
1194
1195   DEFVAR_SPECIFIER ("right-gutter-visible-p",
1196                     &Vgutter_visible_p[RIGHT_GUTTER] /*
1197 *Whether the right gutter is visible.
1198 This is a specifier; use `set-specifier' to change it.
1199
1200 See `default-gutter-visible-p' for more information.
1201 */ );
1202   Vgutter_visible_p[RIGHT_GUTTER] = Fmake_specifier (Qboolean);
1203   set_specifier_caching (Vgutter_visible_p[RIGHT_GUTTER],
1204                          offsetof (struct window,
1205                                    gutter_visible_p[RIGHT_GUTTER]),
1206                          gutter_geometry_changed_in_window,
1207                          0, 0);
1208
1209   /* initially, top inherits from default; this can be
1210      changed with `set-default-gutter-position'. */
1211   fb = list1 (Fcons (Qnil, Qt));
1212   set_specifier_fallback (Vdefault_gutter_visible_p, fb);
1213   set_specifier_fallback (Vgutter_visible_p[TOP_GUTTER],
1214                           Vdefault_gutter_visible_p);
1215   set_specifier_fallback (Vgutter_visible_p[BOTTOM_GUTTER], fb);
1216   set_specifier_fallback (Vgutter_visible_p[LEFT_GUTTER],   fb);
1217   set_specifier_fallback (Vgutter_visible_p[RIGHT_GUTTER],  fb);
1218 }