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