XEmacs 21.2.27 "Hera".
[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                          offsetof (struct window, default_gutter),
809                          default_gutter_specs_changed,
810                          0, 0);
811
812   DEFVAR_SPECIFIER ("top-gutter",
813                     &Vgutter[TOP_GUTTER] /*
814 Specifier for the gutter at the top of the frame.
815 Use `set-specifier' to change this.
816 See `default-gutter' for a description of a valid gutter instantiator.
817 */ );
818   Vgutter[TOP_GUTTER] = Fmake_specifier (Qgutter);
819   set_specifier_caching (Vgutter[TOP_GUTTER],
820                          offsetof (struct window, gutter[TOP_GUTTER]),
821                          gutter_specs_changed,
822                          0, 0);
823
824   DEFVAR_SPECIFIER ("bottom-gutter",
825                     &Vgutter[BOTTOM_GUTTER] /*
826 Specifier for the gutter at the bottom of the frame.
827 Use `set-specifier' to change this.
828 See `default-gutter' for a description of a valid gutter instantiator.
829
830 Note that, unless the `default-gutter-position' is `bottom', by
831 default the height of the bottom gutter (controlled by
832 `bottom-gutter-height') is 0; thus, a bottom gutter will not be
833 displayed even if you provide a value for `bottom-gutter'.
834 */ );
835   Vgutter[BOTTOM_GUTTER] = Fmake_specifier (Qgutter);
836   set_specifier_caching (Vgutter[BOTTOM_GUTTER],
837                          offsetof (struct window, gutter[BOTTOM_GUTTER]),
838                          gutter_specs_changed,
839                          0, 0);
840
841   DEFVAR_SPECIFIER ("left-gutter",
842                     &Vgutter[LEFT_GUTTER] /*
843 Specifier for the gutter at the left edge of the frame.
844 Use `set-specifier' to change this.
845 See `default-gutter' for a description of a valid gutter instantiator.
846
847 Note that, unless the `default-gutter-position' is `left', by
848 default the height of the left gutter (controlled by
849 `left-gutter-width') is 0; thus, a left gutter will not be
850 displayed even if you provide a value for `left-gutter'.
851 */ );
852   Vgutter[LEFT_GUTTER] = Fmake_specifier (Qgutter);
853   set_specifier_caching (Vgutter[LEFT_GUTTER],
854                          offsetof (struct window, gutter[LEFT_GUTTER]),
855                          gutter_specs_changed,
856                          0, 0);
857
858   DEFVAR_SPECIFIER ("right-gutter",
859                     &Vgutter[RIGHT_GUTTER] /*
860 Specifier for the gutter at the right edge of the frame.
861 Use `set-specifier' to change this.
862 See `default-gutter' for a description of a valid gutter instantiator.
863
864 Note that, unless the `default-gutter-position' is `right', by
865 default the height of the right gutter (controlled by
866 `right-gutter-width') is 0; thus, a right gutter will not be
867 displayed even if you provide a value for `right-gutter'.
868 */ );
869   Vgutter[RIGHT_GUTTER] = Fmake_specifier (Qgutter);
870   set_specifier_caching (Vgutter[RIGHT_GUTTER],
871                          offsetof (struct window, gutter[RIGHT_GUTTER]),
872                          gutter_specs_changed,
873                          0, 0);
874
875   /* initially, top inherits from default; this can be
876      changed with `set-default-gutter-position'. */
877   fb = list1 (Fcons (Qnil, Qnil));
878   set_specifier_fallback (Vdefault_gutter, fb);
879   set_specifier_fallback (Vgutter[TOP_GUTTER], Vdefault_gutter);
880   set_specifier_fallback (Vgutter[BOTTOM_GUTTER], fb);
881   set_specifier_fallback (Vgutter[LEFT_GUTTER],   fb);
882   set_specifier_fallback (Vgutter[RIGHT_GUTTER],  fb);
883
884   DEFVAR_SPECIFIER ("default-gutter-height", &Vdefault_gutter_height /*
885 *Height of the default gutter, if it's oriented horizontally.
886 This is a specifier; use `set-specifier' to change it.
887
888 The position of the default gutter is specified by the function
889 `set-default-gutter-position'.  If the corresponding position-specific
890 gutter thickness specifier (e.g. `top-gutter-height' if
891 `default-gutter-position' is 'top) does not specify a thickness in a
892 particular domain (a window or a frame), then the value of
893 `default-gutter-height' or `default-gutter-width' (depending on the
894 gutter orientation) in that domain, if any, will be used instead.
895
896 Note that `default-gutter-height' is only used when
897 `default-gutter-position' is 'top or 'bottom, and `default-gutter-width'
898 is only used when `default-gutter-position' is 'left or 'right.
899
900 Note that all of the position-specific gutter thickness specifiers
901 have a fallback value of zero when they do not correspond to the
902 default gutter.  Therefore, you will have to set a non-zero thickness
903 value if you want a position-specific gutter to be displayed.
904
905 If you set the height to 'autodetect the size of the gutter will be
906 calculated to be large enough to hold the contents of the gutter. This
907 is the default.
908 */ );
909   Vdefault_gutter_height = Fmake_specifier (Qgutter_size);
910   set_specifier_caching (Vdefault_gutter_height,
911                          offsetof (struct window, default_gutter_height),
912                          default_gutter_size_changed_in_window,
913                          0, 0);
914
915   DEFVAR_SPECIFIER ("default-gutter-width", &Vdefault_gutter_width /*
916 *Width of the default gutter, if it's oriented vertically.
917 This is a specifier; use `set-specifier' to change it.
918
919 See `default-gutter-height' for more information.
920 */ );
921   Vdefault_gutter_width = Fmake_specifier (Qnatnum);
922   set_specifier_caching (Vdefault_gutter_width,
923                          offsetof (struct window, default_gutter_width),
924                          default_gutter_size_changed_in_window,
925                          0, 0);
926
927   DEFVAR_SPECIFIER ("top-gutter-height",
928                     &Vgutter_size[TOP_GUTTER] /*
929 *Height of the top gutter.
930 This is a specifier; use `set-specifier' to change it.
931
932 See `default-gutter-height' for more information.
933 */ );
934   Vgutter_size[TOP_GUTTER] = Fmake_specifier (Qgutter_size);
935   set_specifier_caching (Vgutter_size[TOP_GUTTER],
936                          offsetof (struct window, gutter_size[TOP_GUTTER]),
937                          gutter_geometry_changed_in_window,
938                          0, 0);
939
940   DEFVAR_SPECIFIER ("bottom-gutter-height",
941                     &Vgutter_size[BOTTOM_GUTTER] /*
942 *Height of the bottom gutter.
943 This is a specifier; use `set-specifier' to change it.
944
945 See `default-gutter-height' for more information.
946 */ );
947   Vgutter_size[BOTTOM_GUTTER] = Fmake_specifier (Qgutter_size);
948   set_specifier_caching (Vgutter_size[BOTTOM_GUTTER],
949                          offsetof (struct window, gutter_size[BOTTOM_GUTTER]),
950                          gutter_geometry_changed_in_window,
951                          0, 0);
952
953   DEFVAR_SPECIFIER ("left-gutter-width",
954                     &Vgutter_size[LEFT_GUTTER] /*
955 *Width of left gutter.
956 This is a specifier; use `set-specifier' to change it.
957
958 See `default-gutter-height' for more information.
959 */ );
960   Vgutter_size[LEFT_GUTTER] = Fmake_specifier (Qnatnum);
961   set_specifier_caching (Vgutter_size[LEFT_GUTTER],
962                          offsetof (struct window, gutter_size[LEFT_GUTTER]),
963                          gutter_geometry_changed_in_window,
964                          0, 0);
965
966   DEFVAR_SPECIFIER ("right-gutter-width",
967                     &Vgutter_size[RIGHT_GUTTER] /*
968 *Width of right gutter.
969 This is a specifier; use `set-specifier' to change it.
970
971 See `default-gutter-height' for more information.
972 */ );
973   Vgutter_size[RIGHT_GUTTER] = Fmake_specifier (Qnatnum);
974   set_specifier_caching (Vgutter_size[RIGHT_GUTTER],
975                          offsetof (struct window, gutter_size[RIGHT_GUTTER]),
976                          gutter_geometry_changed_in_window,
977                          0, 0);
978
979   fb = Qnil;
980 #ifdef HAVE_TTY
981   fb = Fcons (Fcons (list1 (Qtty), Qautodetect), fb);
982 #endif
983 #ifdef HAVE_X_WINDOWS
984   fb = Fcons (Fcons (list1 (Qx), Qautodetect), fb);
985 #endif
986 #ifdef HAVE_MS_WINDOWS
987   fb = Fcons (Fcons (list1 (Qmswindows), Qautodetect), fb);
988 #endif
989   if (!NILP (fb))
990     set_specifier_fallback (Vdefault_gutter_height, fb);
991
992   fb = Qnil;
993 #ifdef HAVE_TTY
994   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
995 #endif
996 #ifdef HAVE_X_WINDOWS
997   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_GUTTER_WIDTH)), fb);
998 #endif
999 #ifdef HAVE_MS_WINDOWS
1000   fb = Fcons (Fcons (list1 (Qmswindows), 
1001                      make_int (DEFAULT_GUTTER_WIDTH)), fb);
1002 #endif
1003   if (!NILP (fb))
1004     set_specifier_fallback (Vdefault_gutter_width, fb);
1005
1006   set_specifier_fallback (Vgutter_size[TOP_GUTTER], Vdefault_gutter_height);
1007   fb = list1 (Fcons (Qnil, Qzero));
1008   set_specifier_fallback (Vgutter_size[BOTTOM_GUTTER], fb);
1009   set_specifier_fallback (Vgutter_size[LEFT_GUTTER],   fb);
1010   set_specifier_fallback (Vgutter_size[RIGHT_GUTTER],  fb);
1011
1012   DEFVAR_SPECIFIER ("default-gutter-border-width",
1013                     &Vdefault_gutter_border_width /*
1014 *Width of the border around the default gutter.
1015 This is a specifier; use `set-specifier' to change it.
1016
1017 The position of the default gutter is specified by the function
1018 `set-default-gutter-position'.  If the corresponding position-specific
1019 gutter border width specifier (e.g. `top-gutter-border-width' if
1020 `default-gutter-position' is 'top) does not specify a border width in a
1021 particular domain (a window or a frame), then the value of
1022 `default-gutter-border-width' in that domain, if any, will be used
1023 instead.
1024
1025 */ );
1026   Vdefault_gutter_border_width = Fmake_specifier (Qnatnum);
1027   set_specifier_caching (Vdefault_gutter_border_width,
1028                          offsetof (struct window, default_gutter_border_width),
1029                          default_gutter_border_width_changed_in_window,
1030                          0, 0);
1031
1032   DEFVAR_SPECIFIER ("top-gutter-border-width",
1033                     &Vgutter_border_width[TOP_GUTTER] /*
1034 *Border width of the top gutter.
1035 This is a specifier; use `set-specifier' to change it.
1036
1037 See `default-gutter-height' for more information.
1038 */ );
1039   Vgutter_border_width[TOP_GUTTER] = Fmake_specifier (Qnatnum);
1040   set_specifier_caching (Vgutter_border_width[TOP_GUTTER],
1041                          offsetof (struct window,
1042                                    gutter_border_width[TOP_GUTTER]),
1043                          gutter_geometry_changed_in_window,
1044                          0, 0);
1045
1046   DEFVAR_SPECIFIER ("bottom-gutter-border-width",
1047                     &Vgutter_border_width[BOTTOM_GUTTER] /*
1048 *Border width of the bottom gutter.
1049 This is a specifier; use `set-specifier' to change it.
1050
1051 See `default-gutter-height' for more information.
1052 */ );
1053   Vgutter_border_width[BOTTOM_GUTTER] = Fmake_specifier (Qnatnum);
1054   set_specifier_caching (Vgutter_border_width[BOTTOM_GUTTER],
1055                          offsetof (struct window,
1056                                    gutter_border_width[BOTTOM_GUTTER]),
1057                          gutter_geometry_changed_in_window,
1058                          0, 0);
1059
1060   DEFVAR_SPECIFIER ("left-gutter-border-width",
1061                     &Vgutter_border_width[LEFT_GUTTER] /*
1062 *Border width of left gutter.
1063 This is a specifier; use `set-specifier' to change it.
1064
1065 See `default-gutter-height' for more information.
1066 */ );
1067   Vgutter_border_width[LEFT_GUTTER] = Fmake_specifier (Qnatnum);
1068   set_specifier_caching (Vgutter_border_width[LEFT_GUTTER],
1069                          offsetof (struct window,
1070                                    gutter_border_width[LEFT_GUTTER]),
1071                          gutter_geometry_changed_in_window,
1072                          0, 0);
1073
1074   DEFVAR_SPECIFIER ("right-gutter-border-width",
1075                     &Vgutter_border_width[RIGHT_GUTTER] /*
1076 *Border width of right gutter.
1077 This is a specifier; use `set-specifier' to change it.
1078
1079 See `default-gutter-height' for more information.
1080 */ );
1081   Vgutter_border_width[RIGHT_GUTTER] = Fmake_specifier (Qnatnum);
1082   set_specifier_caching (Vgutter_border_width[RIGHT_GUTTER],
1083                          offsetof (struct window,
1084                                    gutter_border_width[RIGHT_GUTTER]),
1085                          gutter_geometry_changed_in_window,
1086                          0, 0);
1087
1088   fb = Qnil;
1089 #ifdef HAVE_TTY
1090   fb = Fcons (Fcons (list1 (Qtty), Qzero), fb);
1091 #endif
1092 #ifdef HAVE_X_WINDOWS
1093   fb = Fcons (Fcons (list1 (Qx), make_int (DEFAULT_GUTTER_BORDER_WIDTH)), fb);
1094 #endif
1095 #ifdef HAVE_MS_WINDOWS
1096   fb = Fcons (Fcons (list1 (Qmswindows), make_int (DEFAULT_GUTTER_BORDER_WIDTH)), fb);
1097 #endif
1098   if (!NILP (fb))
1099     set_specifier_fallback (Vdefault_gutter_border_width, fb);
1100
1101   set_specifier_fallback (Vgutter_border_width[TOP_GUTTER], Vdefault_gutter_border_width);
1102   fb = list1 (Fcons (Qnil, Qzero));
1103   set_specifier_fallback (Vgutter_border_width[BOTTOM_GUTTER], fb);
1104   set_specifier_fallback (Vgutter_border_width[LEFT_GUTTER],   fb);
1105   set_specifier_fallback (Vgutter_border_width[RIGHT_GUTTER],  fb);
1106
1107   DEFVAR_SPECIFIER ("default-gutter-visible-p", &Vdefault_gutter_visible_p /*
1108 *Whether the default gutter is visible.
1109 This is a specifier; use `set-specifier' to change it.
1110
1111 The position of the default gutter is specified by the function
1112 `set-default-gutter-position'.  If the corresponding position-specific
1113 gutter visibility specifier (e.g. `top-gutter-visible-p' if
1114 `default-gutter-position' is 'top) does not specify a visible-p value
1115 in a particular domain (a window or a frame), then the value of
1116 `default-gutter-visible-p' in that domain, if any, will be used
1117 instead.
1118
1119 `default-gutter-visible-p' and all of the position-specific gutter
1120 visibility specifiers have a fallback value of true.
1121 */ );
1122   Vdefault_gutter_visible_p = Fmake_specifier (Qboolean);
1123   set_specifier_caching (Vdefault_gutter_visible_p,
1124                          offsetof (struct window,
1125                                    default_gutter_visible_p),
1126                          default_gutter_visible_p_changed_in_window,
1127                          0, 0);
1128
1129   DEFVAR_SPECIFIER ("top-gutter-visible-p",
1130                     &Vgutter_visible_p[TOP_GUTTER] /*
1131 *Whether the top gutter is visible.
1132 This is a specifier; use `set-specifier' to change it.
1133
1134 See `default-gutter-visible-p' for more information.
1135 */ );
1136   Vgutter_visible_p[TOP_GUTTER] = Fmake_specifier (Qboolean);
1137   set_specifier_caching (Vgutter_visible_p[TOP_GUTTER],
1138                          offsetof (struct window,
1139                                    gutter_visible_p[TOP_GUTTER]),
1140                          gutter_geometry_changed_in_window,
1141                          0, 0);
1142
1143   DEFVAR_SPECIFIER ("bottom-gutter-visible-p",
1144                     &Vgutter_visible_p[BOTTOM_GUTTER] /*
1145 *Whether the bottom gutter is visible.
1146 This is a specifier; use `set-specifier' to change it.
1147
1148 See `default-gutter-visible-p' for more information.
1149 */ );
1150   Vgutter_visible_p[BOTTOM_GUTTER] = Fmake_specifier (Qboolean);
1151   set_specifier_caching (Vgutter_visible_p[BOTTOM_GUTTER],
1152                          offsetof (struct window,
1153                                    gutter_visible_p[BOTTOM_GUTTER]),
1154                          gutter_geometry_changed_in_window,
1155                          0, 0);
1156
1157   DEFVAR_SPECIFIER ("left-gutter-visible-p",
1158                     &Vgutter_visible_p[LEFT_GUTTER] /*
1159 *Whether the left gutter is visible.
1160 This is a specifier; use `set-specifier' to change it.
1161
1162 See `default-gutter-visible-p' for more information.
1163 */ );
1164   Vgutter_visible_p[LEFT_GUTTER] = Fmake_specifier (Qboolean);
1165   set_specifier_caching (Vgutter_visible_p[LEFT_GUTTER],
1166                          offsetof (struct window,
1167                                    gutter_visible_p[LEFT_GUTTER]),
1168                          gutter_geometry_changed_in_window,
1169                          0, 0);
1170
1171   DEFVAR_SPECIFIER ("right-gutter-visible-p",
1172                     &Vgutter_visible_p[RIGHT_GUTTER] /*
1173 *Whether the right gutter is visible.
1174 This is a specifier; use `set-specifier' to change it.
1175
1176 See `default-gutter-visible-p' for more information.
1177 */ );
1178   Vgutter_visible_p[RIGHT_GUTTER] = Fmake_specifier (Qboolean);
1179   set_specifier_caching (Vgutter_visible_p[RIGHT_GUTTER],
1180                          offsetof (struct window,
1181                                    gutter_visible_p[RIGHT_GUTTER]),
1182                          gutter_geometry_changed_in_window,
1183                          0, 0);
1184
1185   /* initially, top inherits from default; this can be
1186      changed with `set-default-gutter-position'. */
1187   fb = list1 (Fcons (Qnil, Qt));
1188   set_specifier_fallback (Vdefault_gutter_visible_p, fb);
1189   set_specifier_fallback (Vgutter_visible_p[TOP_GUTTER],
1190                           Vdefault_gutter_visible_p);
1191   set_specifier_fallback (Vgutter_visible_p[BOTTOM_GUTTER], fb);
1192   set_specifier_fallback (Vgutter_visible_p[LEFT_GUTTER],   fb);
1193   set_specifier_fallback (Vgutter_visible_p[RIGHT_GUTTER],  fb);
1194
1195 }