1 /* Window creation, deletion and examination for SXEmacs.
2 Copyright (C) 1985-1987, 1992-1995 Free Software Foundation, Inc.
3 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
4 Copyright (C) 1995, 1996 Ben Wing.
5 Copyright (C) 1996 Chuck Thompson.
6 Copyright (C) 2004 Johann "Myrkraverk" Oskarsson.
8 This file is part of SXEmacs
10 SXEmacs is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
15 SXEmacs is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>. */
24 /* Synched up with: FSF 19.30. */
25 /* Beginning to diverge significantly. */
27 /* window-configuraion-hook, by Johann "Myrkraverk" Oskarsson, Jun 2004. */
29 /* This file has been Mule-ized. */
39 #include "redisplay.h"
45 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configurationp;
46 Lisp_Object Qdisplay_buffer;
48 #if defined MEMORY_USAGE_STATS && !(defined HAVE_BDWGC && defined EF_USE_BDWGC)
49 Lisp_Object Qface_cache, Qglyph_cache, Qline_start_cache, Qother_redisplay;
50 #ifdef HAVE_SCROLLBARS
51 Lisp_Object Qscrollbar_instances;
55 extern int allow_deletion_of_last_visible_frame;
57 EXFUN(Fnext_window, 4);
59 static int window_pixel_width_to_char_width(struct window *w,
61 int include_margins_p);
62 static int window_char_width_to_pixel_width(struct window *w,
64 int include_margins_p);
65 static int window_pixel_height_to_char_height(struct window *w,
67 int include_gutters_p);
68 static int window_char_height_to_pixel_height(struct window *w,
70 int include_gutters_p);
71 static void change_window_height(Lisp_Object window, int delta,
72 Lisp_Object horizontalp, int inpixels);
74 /* Thickness of shadow border around 3d modelines. */
75 Lisp_Object Vmodeline_shadow_thickness;
77 /* Whether vertical dividers are draggable and displayed */
78 Lisp_Object Vvertical_divider_always_visible_p;
80 /* Whether a modeline should be displayed. */
81 Lisp_Object Vhas_modeline_p;
83 /* Thickness of shadow border around vertical dividers. */
84 Lisp_Object Vvertical_divider_shadow_thickness;
86 /* Divider surface width (not counting 3-d borders) */
87 Lisp_Object Vvertical_divider_line_width;
89 /* Spacing between outer edge of divider border and window edge */
90 Lisp_Object Vvertical_divider_spacing;
92 /* How much to scroll by per-line. */
93 Lisp_Object Vwindow_pixel_scroll_increment;
95 /* Scroll if point lands on the bottom line and that line is partially
97 int scroll_on_clipped_lines;
99 /* The minibuffer window of the selected frame.
100 Note that you cannot test for minibufferness of an arbitrary window
101 by comparing against this; but you can test for minibufferness of
102 the selected window. */
103 Lisp_Object minibuf_window;
105 /* Non-nil means it is the window for C-M-v to scroll
106 when the minibuffer is selected. */
107 Lisp_Object Vminibuffer_scroll_window;
109 /* Non-nil means this is the buffer whose window C-M-v should scroll. */
110 Lisp_Object Vother_window_scroll_buffer;
112 /* Non-nil means it's the function to call to display temp buffers. */
113 Lisp_Object Vtemp_buffer_show_function;
115 Lisp_Object Vtemp_buffer_show_hook;
117 /* If a window gets smaller than either of these, it is removed. */
118 Fixnum window_min_height;
119 Fixnum window_min_width;
121 /* Hook run at end of temp_output_buffer_show. */
122 Lisp_Object Qtemp_buffer_show_hook;
124 /* Number of lines of continuity in scrolling by screenfuls. */
125 Fixnum next_screen_context_lines;
127 #if !defined HAVE_BDWGC || !defined EF_USE_BDWGC
128 /* List of freed window configurations with 1 - 10 windows. */
129 static Lisp_Object Vwindow_configuration_free_list[10];
132 Lisp_Object Qtruncate_partial_width_windows;
134 Lisp_Object Qwindow_configuration_hook, Vwindow_configuration_hook;
136 #define SET_LAST_MODIFIED(w, cache_too) \
138 (w)->last_modified[CURRENT_DISP] = Qzero; \
139 (w)->last_modified[DESIRED_DISP] = Qzero; \
140 (w)->last_modified[CMOTION_DISP] = Qzero; \
142 (w)->line_cache_last_updated = Qzero; \
145 #define SET_LAST_FACECHANGE(w) \
147 (w)->last_facechange[CURRENT_DISP] = Qzero; \
148 (w)->last_facechange[DESIRED_DISP] = Qzero; \
149 (w)->last_facechange[CMOTION_DISP] = Qzero; \
152 #define MARK_DISP_VARIABLE(field) \
153 mark_object (window->field[CURRENT_DISP]); \
154 mark_object (window->field[DESIRED_DISP]); \
155 mark_object (window->field[CMOTION_DISP]);
157 static Lisp_Object mark_window(Lisp_Object obj)
159 struct window *window = XWINDOW(obj);
160 mark_object(window->frame);
161 mark_object(window->mini_p);
162 mark_object(window->next);
163 mark_object(window->prev);
164 mark_object(window->hchild);
165 mark_object(window->vchild);
166 mark_object(window->parent);
167 mark_object(window->buffer);
168 MARK_DISP_VARIABLE(start);
169 MARK_DISP_VARIABLE(pointm);
170 mark_object(window->sb_point); /* #### move to scrollbar.c? */
171 mark_object(window->use_time);
172 MARK_DISP_VARIABLE(last_modified);
173 MARK_DISP_VARIABLE(last_point);
174 MARK_DISP_VARIABLE(last_start);
175 MARK_DISP_VARIABLE(last_facechange);
176 mark_object(window->line_cache_last_updated);
177 mark_object(window->redisplay_end_trigger);
178 mark_object(window->subwindow_instance_cache);
180 mark_face_cachels(window->face_cachels);
181 mark_glyph_cachels(window->glyph_cachels);
183 #define WINDOW_SLOT(slot, compare) mark_object (window->slot)
184 #include "winslots.h"
190 run_window_configuration_hook ( Lisp_Object win )
197 win = Fselected_window(Qnil);
202 frame = WINDOW_FRAME (w);
205 if ( ! f->window_configuration_hook ) {
206 f->window_configuration_hook = 1;
207 va_run_hook_with_args(Qwindow_configuration_hook, 1, win);
208 f->window_configuration_hook = 0;
213 print_window(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
216 error("printing unreadable object #<window 0x%x>",
217 XWINDOW(obj)->header.uid);
219 write_c_string("#<window", printcharfun);
220 if (!NILP(XWINDOW(obj)->buffer)) {
221 Lisp_Object name = XBUFFER(XWINDOW(obj)->buffer)->name;
222 write_c_string(" on ", printcharfun);
223 print_internal(name, printcharfun, 1);
225 write_fmt_str(printcharfun, " 0x%x>", XWINDOW(obj)->header.uid);
228 static void finalize_window(void *header, int for_disksave)
230 struct window *w = (struct window *)header;
232 if (w->line_start_cache) {
233 Dynarr_free(w->line_start_cache);
234 w->line_start_cache = 0;
237 if (w->face_cachels) {
240 for (i = 0; i < Dynarr_length(w->face_cachels); i++) {
241 struct face_cachel *cachel =
242 Dynarr_atp(w->face_cachels, i);
243 if (cachel->merged_faces) {
244 Dynarr_free(cachel->merged_faces);
245 cachel->merged_faces = 0;
248 Dynarr_free(w->face_cachels);
252 if (w->glyph_cachels) {
253 Dynarr_free(w->glyph_cachels);
254 w->glyph_cachels = 0;
258 DEFINE_LRECORD_IMPLEMENTATION("window", window,
259 mark_window, print_window, finalize_window,
260 0, 0, 0, struct window);
262 #define INIT_DISP_VARIABLE(field, initialization) \
263 p->field[CURRENT_DISP] = initialization; \
264 p->field[DESIRED_DISP] = initialization; \
265 p->field[CMOTION_DISP] = initialization;
267 /* We have an implicit assertion that the first two elements (default
268 and modeline faces) are always present in the face_element_cache.
269 Normally redisplay ensures this. However, it is possible for a
270 window to get created and functions which reference these values
271 called before redisplay works with the window for the first time.
272 All callers of allocate_window should therefore call
273 reset_face_cachels on the created window. We can't do it
274 here because the window must have its frame pointer set or
275 reset_face_cachels will fail. */
276 Lisp_Object allocate_window(void)
279 struct window *p = alloc_lcrecord_type(struct window, &lrecord_window);
293 INIT_DISP_VARIABLE(start, Fmake_marker());
294 INIT_DISP_VARIABLE(pointm, Fmake_marker());
295 p->sb_point = Fmake_marker();
297 INIT_DISP_VARIABLE(last_modified, Qzero);
298 INIT_DISP_VARIABLE(last_point, Fmake_marker());
299 INIT_DISP_VARIABLE(last_start, Fmake_marker());
300 INIT_DISP_VARIABLE(last_facechange, Qzero);
301 p->face_cachels = Dynarr_new(face_cachel);
302 p->glyph_cachels = Dynarr_new(glyph_cachel);
303 p->line_start_cache = Dynarr_new(line_start_cache);
304 p->subwindow_instance_cache = make_image_instance_cache_hash_table();
306 p->line_cache_last_updated = Qzero;
307 INIT_DISP_VARIABLE(last_point_x, 0);
308 INIT_DISP_VARIABLE(last_point_y, 0);
309 INIT_DISP_VARIABLE(window_end_pos, 0);
310 p->redisplay_end_trigger = Qnil;
312 p->gutter_extent_modiff[0] = 0;
313 p->gutter_extent_modiff[1] = 0;
314 p->gutter_extent_modiff[2] = 0;
315 p->gutter_extent_modiff[3] = 0;
317 #define WINDOW_SLOT(slot, compare) p->slot = Qnil
318 #include "winslots.h"
320 p->windows_changed = 1;
321 p->shadow_thickness_changed = 1;
326 #undef INIT_DISP_VARIABLE
329 * The redisplay structures used to be stored with each window. While
330 * they are logically something associated with frames they can't be
331 * stored there with a redisplay which handles variable height lines.
332 * Lines in horizontally split windows might not line up. So they get
333 * stored with the windows.
335 * The problem with this is window configurations. When restoring a
336 * window configuration it now becomes problematic to do an
337 * incremental redisplay. The solution is to store the redisplay
338 * structures with the frame as they should be but laid out in the
339 * same manner as the window structure. Thus is born the window
342 * It also becomes a convenient place to stick scrollbar instances
343 * since they extrapolate out to having the same problem described for
344 * the display structures.
347 /* Create a new window mirror structure and associated redisplay
349 static struct window_mirror *new_window_mirror(struct frame *f)
351 struct window_mirror *t = xnew_and_zero(struct window_mirror);
355 t->current_display_lines = Dynarr_new(display_line);
356 t->desired_display_lines = Dynarr_new(display_line);
359 #ifdef HAVE_SCROLLBARS
360 t->scrollbar_vertical_instance = NULL;
361 t->scrollbar_horizontal_instance = NULL;
367 /* Synchronize the mirror structure with a given window structure.
368 This is normally called from update_frame_window_mirror with a
369 starting window of f->root_window. */
370 static struct window_mirror *update_mirror_internal(Lisp_Object win,
371 struct window_mirror *mir)
375 free_window_mirror(mir);
380 mir = new_window_mirror(XFRAME(XWINDOW(win)->frame));
382 mir->next = update_mirror_internal(XWINDOW(win)->next, mir->next);
383 mir->hchild = update_mirror_internal(XWINDOW(win)->hchild, mir->hchild);
384 mir->vchild = update_mirror_internal(XWINDOW(win)->vchild, mir->vchild);
387 * If the redisplay structs are not empty and the mirror has
388 * children, then this mirror structure was formerly being used for
389 * display but is no longer. Reset its current display structs so
390 * that redisplay doesn't accidentally think they are accurate if it
391 * is later used for display purposes once again. Also, mark the
392 * scrollbar instance as not active.
394 if (mir->vchild || mir->hchild) {
395 /* The redisplay structures are big. Leaving them around in
396 non-leaf windows can add up to a lot of wasted space. So
398 free_display_structs(mir);
399 mir->current_display_lines = Dynarr_new(display_line);
400 mir->desired_display_lines = Dynarr_new(display_line);
402 #ifdef HAVE_SCROLLBARS
403 update_window_scrollbars(XWINDOW(win), mir, 0, 0);
411 /* Given a window mirror, determine which real window it contains the
412 redisplay structures for. */
414 real_window_internal(Lisp_Object win, struct window_mirror *rmir,
415 struct window_mirror *mir)
417 for (; !NILP(win) && rmir; win = XWINDOW(win)->next, rmir = rmir->next) {
420 if (!NILP(XWINDOW(win)->vchild)) {
422 real_window_internal(XWINDOW(win)->vchild,
427 if (!NILP(XWINDOW(win)->hchild)) {
429 real_window_internal(XWINDOW(win)->hchild,
439 /* Given a real window, find the mirror structure which contains its
440 redisplay structures. */
441 static struct window_mirror *find_window_mirror_internal(Lisp_Object win,
446 for (; !NILP(win); win = XWINDOW(win)->next, rmir = rmir->next) {
447 if (w == XWINDOW(win))
450 if (!NILP(XWINDOW(win)->vchild)) {
451 struct window_mirror *retval =
452 find_window_mirror_internal(XWINDOW(win)->vchild,
458 if (!NILP(XWINDOW(win)->hchild)) {
459 struct window_mirror *retval =
460 find_window_mirror_internal(XWINDOW(win)->hchild,
470 /* Update the mirror structure for the given frame. */
471 void update_frame_window_mirror(struct frame *f)
473 f->root_mirror = update_mirror_internal(f->root_window, f->root_mirror);
477 /* Free a given mirror structure along with all of its children as
478 well as their associated display structures. */
479 void free_window_mirror(struct window_mirror *mir)
482 struct window_mirror *free_me = mir;
484 free_window_mirror(mir->hchild);
486 free_window_mirror(mir->vchild);
487 #ifdef HAVE_SCROLLBARS
488 release_window_mirror_scrollbars(mir);
490 free_display_structs(mir);
496 /* Given a mirror structure, return the window it mirrors. Calls
497 real_window_internal to do most of the work. */
498 Lisp_Object real_window(struct window_mirror *mir, int no_abort)
500 Lisp_Object retval = real_window_internal(mir->frame->root_window,
501 mir->frame->root_mirror, mir);
502 if (NILP(retval) && !no_abort)
508 /* Given a real window, return its mirror structure. Calls
509 find_window_mirror_internal to do all of the work. */
510 struct window_mirror *find_window_mirror(struct window *w)
512 struct frame *f = XFRAME(w->frame);
514 update_frame_window_mirror(f);
515 return find_window_mirror_internal(f->root_window, f->root_mirror, w);
518 /*****************************************************************************
519 find_window_by_pixel_pos
521 Given a pixel position relative to a frame, find the window at that
523 ****************************************************************************/
524 struct window *find_window_by_pixel_pos(int pix_x, int pix_y, Lisp_Object win)
529 for (; !NILP(win); win = XWINDOW(win)->next) {
532 if (!NILP(XWINDOW(win)->vchild)) {
533 w = find_window_by_pixel_pos(pix_x, pix_y,
534 XWINDOW(win)->vchild);
538 if (!NILP(XWINDOW(win)->hchild)) {
539 w = find_window_by_pixel_pos(pix_x, pix_y,
540 XWINDOW(win)->hchild);
545 if (pix_x >= WINDOW_LEFT(w)
546 && pix_x <= WINDOW_RIGHT(w)
547 && pix_y >= WINDOW_TOP(w)
548 && pix_y <= WINDOW_BOTTOM(w))
554 /* Return a pointer to the display structures for the given window. */
555 display_line_dynarr *window_display_lines(struct window * w, int which)
557 struct window_mirror *t;
559 if (XFRAME(w->frame)->mirror_dirty)
560 update_frame_window_mirror(XFRAME(w->frame));
561 t = find_window_mirror(w);
565 if (which == CURRENT_DISP)
566 return t->current_display_lines;
567 else if (which == DESIRED_DISP)
568 return t->desired_display_lines;
569 else if (which == CMOTION_DISP)
570 /* The CMOTION_DISP display lines are global. */
571 return cmotion_display_lines;
575 return 0; /* shut up compiler */
578 struct buffer *window_display_buffer(struct window *w)
580 struct window_mirror *t;
582 if (XFRAME(w->frame)->mirror_dirty)
583 update_frame_window_mirror(XFRAME(w->frame));
584 t = find_window_mirror(w);
591 void set_window_display_buffer(struct window *w, struct buffer *b)
593 struct window_mirror *t;
595 if (XFRAME(w->frame)->mirror_dirty)
596 update_frame_window_mirror(XFRAME(w->frame));
597 t = find_window_mirror(w);
604 /* Determining a window's position based solely on its pixel
605 positioning doesn't work. Instead, we do it the intelligent way,
606 by checking its positioning in the window hierarchy. */
607 int window_is_leftmost(struct window *w)
609 Lisp_Object parent, current_ancestor, window;
611 XSETWINDOW(window, w);
613 parent = XWINDOW(window)->parent;
614 current_ancestor = window;
616 while (!NILP(parent)) {
617 if (!NILP(XWINDOW(parent)->hchild) &&
618 !EQ(XWINDOW(parent)->hchild, current_ancestor))
621 current_ancestor = parent;
622 parent = XWINDOW(parent)->parent;
628 int window_is_rightmost(struct window *w)
630 Lisp_Object parent, current_ancestor, window;
632 XSETWINDOW(window, w);
634 parent = XWINDOW(window)->parent;
635 current_ancestor = window;
637 while (!NILP(parent)) {
638 if (!NILP(XWINDOW(parent)->hchild)
639 && !NILP(XWINDOW(current_ancestor)->next))
642 current_ancestor = parent;
643 parent = XWINDOW(parent)->parent;
649 static int window_full_width_p(struct window *w)
651 return window_is_leftmost(w) && window_is_rightmost(w);
654 int window_is_highest(struct window *w)
656 Lisp_Object parent, current_ancestor, window;
658 XSETWINDOW(window, w);
660 parent = XWINDOW(window)->parent;
661 current_ancestor = window;
663 while (!NILP(parent)) {
664 if (!NILP(XWINDOW(parent)->vchild) &&
665 !EQ(XWINDOW(parent)->vchild, current_ancestor))
668 current_ancestor = parent;
669 parent = XWINDOW(parent)->parent;
672 /* This is really to catch the minibuffer but we make it generic in
673 case we ever change things around to let the minibuffer be on top. */
674 if (NILP(XWINDOW(current_ancestor)->prev))
680 int window_is_lowest(struct window *w)
682 Lisp_Object parent, current_ancestor, window;
684 XSETWINDOW(window, w);
686 parent = XWINDOW(window)->parent;
687 current_ancestor = window;
689 while (!NILP(parent)) {
690 if (!NILP(XWINDOW(parent)->vchild)
691 && !NILP(XWINDOW(current_ancestor)->next))
694 current_ancestor = parent;
695 parent = XWINDOW(parent)->parent;
701 #if 0 /* not currently used */
703 static int window_full_height_p(struct window *w)
705 return window_is_highest(w) && window_is_lowest(w);
710 int window_truncation_on(struct window *w)
712 /* Minibuffer windows are never truncated.
713 #### is this the right way ? */
714 if (MINI_WINDOW_P(w))
717 /* Horizontally scrolled windows are truncated. */
721 /* If truncate_partial_width_windows is true and the window is not
722 the full width of the frame it is truncated. */
723 if (!NILP(symbol_value_in_buffer(Qtruncate_partial_width_windows,
725 && !(window_is_leftmost(w) && window_is_rightmost(w)))
728 /* If the window's buffer's value of truncate_lines is non-nil, then
729 the window is truncated. */
730 if (!NILP(XBUFFER(w->buffer)->truncate_lines))
736 DEFUN("window-truncated-p", Fwindow_truncated_p, 0, 1, 0, /*
737 Returns non-nil if text in the window is truncated.
741 struct window *w = decode_window(window);
743 return window_truncation_on(w) ? Qt : Qnil;
746 static int have_undivided_common_edge(struct window *w_right, void *closure)
748 struct window *w_left = (struct window *)closure;
749 return (WINDOW_RIGHT(w_left) == WINDOW_LEFT(w_right)
750 && WINDOW_TOP(w_left) < WINDOW_BOTTOM(w_right)
751 && WINDOW_TOP(w_right) < WINDOW_BOTTOM(w_left)
752 #ifdef HAVE_SCROLLBARS
753 && (NILP(w_right->scrollbar_on_left_p)
754 || NILP(w_right->vertical_scrollbar_visible_p)
755 || ZEROP(w_right->scrollbar_width))
760 static int window_needs_vertical_divider_1(struct window *w)
762 /* Never if we're on the right */
763 if (window_is_rightmost(w))
766 /* Always if draggable */
767 if (!NILP(w->vertical_divider_always_visible_p))
770 #ifdef HAVE_SCROLLBARS
771 /* Our right scrollbar is enough to separate us at the right */
772 if (NILP(w->scrollbar_on_left_p)
773 && !NILP(w->vertical_scrollbar_visible_p)
774 && !ZEROP(w->scrollbar_width))
778 /* Ok. to determine whether we need a divider on the left, we must
779 check that our right neighbor windows ha