comparison src/gutter.c @ 398:74fd4e045ea6 r21-2-29

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