comparison src/gutter.c @ 428:3ecd8885ac67 r21-2-22

Import from CVS: tag r21-2-22
author cvs
date Mon, 13 Aug 2007 11:28:15 +0200
parents
children 84b14dcb0985
comparison
equal deleted inserted replaced
427:0a0253eac470 428:3ecd8885ac67
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
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 }