comparison src/window.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* Window creation, deletion and examination for XEmacs.
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
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24 /* Synched up with: FSF 19.30. */
25 /* Beginning to diverge significantly. */
26
27 /* This file has been Mule-ized. */
28
29 #include <config.h>
30 #include "lisp.h"
31
32 #include "buffer.h"
33 #include "faces.h"
34 #include "frame.h"
35 #include "objects.h"
36 #include "glyphs.h"
37 #include "redisplay.h"
38 #include "window.h"
39 #include "commands.h"
40
41 Lisp_Object Qwindowp, Qwindow_live_p;
42 Lisp_Object Qwindow_configurationp;
43 Lisp_Object Qscroll_up;
44 Lisp_Object Qscroll_down;
45 Lisp_Object Qtemp_buffer_show_hook;
46 Lisp_Object Qdisplay_buffer;
47
48 #ifdef MEMORY_USAGE_STATS
49 Lisp_Object Qface_cache;
50 Lisp_Object Qglyph_cache;
51 Lisp_Object Qline_start_cache;
52 #ifdef HAVE_SCROLLBARS
53 Lisp_Object Qscrollbar_instances;
54 #endif
55 Lisp_Object Qother_redisplay;
56 #endif
57
58 static int window_pixel_width_to_char_width (struct window *w,
59 int pixel_width,
60 int include_margins_p);
61 static int window_char_width_to_pixel_width (struct window *w,
62 int char_width,
63 int include_margins_p);
64 static int window_pixel_height_to_char_height (struct window *w,
65 int pixel_height,
66 int include_gutters_p);
67 static int window_char_height_to_pixel_height (struct window *w,
68 int char_height,
69 int include_gutters_p);
70 static void change_window_height (struct window *w, int delta, int widthflag);
71
72
73 #ifdef ENERGIZE
74 extern void energize_buffer_shown_hook ();
75 extern void energize_buffer_hidden_hook ();
76 extern void energize_window_selected_hook ();
77 extern void energize_window_deselected_hook ();
78 extern Lisp_Object desired_psheet_buffer ();
79 extern void make_psheets_desired ();
80 #endif
81
82 /* Thickness of shadow border around 3d modelines. */
83 Lisp_Object Vmodeline_shadow_thickness;
84
85 /* Whether a modeline should be displayed. */
86 Lisp_Object Vhas_modeline_p;
87
88 /* Scroll if point lands on the bottom line and that line is partially
89 clipped. */
90 int scroll_on_clipped_lines;
91
92 /* The minibuffer window of the selected frame.
93 Note that you cannot test for minibufferness of an arbitrary window
94 by comparing against this; but you can test for minibufferness of
95 the selected window. */
96 Lisp_Object minibuf_window;
97
98 /* Non-nil means it is the window for C-M-v to scroll
99 when the minibuffer is selected. */
100 Lisp_Object Vminibuf_scroll_window;
101
102 /* Non-nil means this is the buffer whose window C-M-v should scroll. */
103 Lisp_Object Vother_window_scroll_buffer;
104
105 /* Non-nil means it's function to call to display temp buffers. */
106 Lisp_Object Vtemp_buffer_show_function;
107
108 Lisp_Object Vtemp_buffer_show_hook;
109
110 /* If a window gets smaller than either of these, it is removed. */
111 int window_min_height;
112 int window_min_width;
113
114 /* Hook run at end of temp_output_buffer_show. */
115 Lisp_Object Qtemp_buffer_show_hook;
116
117 /* Number of lines of continuity in scrolling by screenfuls. */
118 int next_screen_context_lines;
119
120 /* List of freed window configurations with 1 - 10 windows. */
121 Lisp_Object Vwindow_configuration_free_list[10];
122
123 #define SET_LAST_MODIFIED(w, cache_too) \
124 do { \
125 (w)->last_modified[CURRENT_DISP] = Qzero; \
126 (w)->last_modified[DESIRED_DISP] = Qzero; \
127 (w)->last_modified[CMOTION_DISP] = Qzero; \
128 if (cache_too) \
129 (w)->line_cache_last_updated = Qzero; \
130 } while (0)
131
132 #define SET_LAST_FACECHANGE(w) \
133 do { \
134 (w)->last_facechange[CURRENT_DISP] = Qzero; \
135 (w)->last_facechange[DESIRED_DISP] = Qzero; \
136 (w)->last_facechange[CMOTION_DISP] = Qzero; \
137 } while (0)
138
139
140 static Lisp_Object mark_window (Lisp_Object, void (*) (Lisp_Object));
141 static void print_window (Lisp_Object, Lisp_Object, int);
142 static void finalize_window (void *header, int for_disksave);
143 DEFINE_LRECORD_IMPLEMENTATION ("window", window,
144 mark_window, print_window, finalize_window,
145 0, 0, struct window);
146
147 #define MARK_DISP_VARIABLE(field) \
148 ((markobj) (window->field[CURRENT_DISP])); \
149 ((markobj) (window->field[DESIRED_DISP])); \
150 ((markobj) (window->field[CMOTION_DISP]));
151
152 static Lisp_Object
153 mark_window (Lisp_Object obj, void (*markobj) (Lisp_Object))
154 {
155 struct window *window = XWINDOW (obj);
156 ((markobj) (window->frame));
157 ((markobj) (window->mini_p));
158 ((markobj) (window->next));
159 ((markobj) (window->prev));
160 ((markobj) (window->hchild));
161 ((markobj) (window->vchild));
162 ((markobj) (window->parent));
163 ((markobj) (window->buffer));
164 MARK_DISP_VARIABLE (start);
165 MARK_DISP_VARIABLE (pointm);
166 ((markobj) (window->sb_point)); /* #### move to scrollbar.c? */
167 ((markobj) (window->use_time));
168 MARK_DISP_VARIABLE (last_modified);
169 MARK_DISP_VARIABLE (last_point);
170 MARK_DISP_VARIABLE (last_start);
171 MARK_DISP_VARIABLE (last_facechange);
172 ((markobj) (window->line_cache_last_updated));
173 ((markobj) (window->redisplay_end_trigger));
174 /* Cached specifiers: */
175 ((markobj) (window->display_table));
176 ((markobj) (window->has_modeline_p));
177 ((markobj) (window->modeline_shadow_thickness));
178 #ifdef HAVE_SCROLLBARS
179 ((markobj) (window->scrollbar_width));
180 ((markobj) (window->scrollbar_height));
181 ((markobj) (window->scrollbar_pointer));
182 #endif
183 ((markobj) (window->left_margin_width));
184 ((markobj) (window->right_margin_width));
185 #ifdef HAVE_TOOLBARS
186 ((markobj) (window->toolbar[0]));
187 ((markobj) (window->toolbar[1]));
188 ((markobj) (window->toolbar[2]));
189 ((markobj) (window->toolbar[3]));
190 ((markobj) (window->toolbar_size[0]));
191 ((markobj) (window->toolbar_size[1]));
192 ((markobj) (window->toolbar_size[2]));
193 ((markobj) (window->toolbar_size[3]));
194 ((markobj) (window->toolbar_visible_p[0]));
195 ((markobj) (window->toolbar_visible_p[1]));
196 ((markobj) (window->toolbar_visible_p[2]));
197 ((markobj) (window->toolbar_visible_p[3]));
198 ((markobj) (window->toolbar_buttons_captioned_p));
199 ((markobj) (window->default_toolbar));
200 ((markobj) (window->default_toolbar_height));
201 ((markobj) (window->default_toolbar_width));
202 ((markobj) (window->default_toolbar_visible_p));
203 #endif
204 ((markobj) (window->minimum_line_ascent));
205 ((markobj) (window->minimum_line_descent));
206 ((markobj) (window->use_left_overflow));
207 ((markobj) (window->use_right_overflow));
208 #ifdef HAVE_MENUBARS
209 ((markobj) (window->menubar_visible_p));
210 #endif
211 ((markobj) (window->text_cursor_visible_p));
212 /* End cached specifiers. */
213 ((markobj) (window->dedicated));
214 mark_face_cachels (window->face_cachels, markobj);
215 mark_glyph_cachels (window->glyph_cachels, markobj);
216 return (Qnil);
217 }
218
219 static void
220 print_window (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
221 {
222 char buf[200];
223
224 if (print_readably)
225 error ("printing unreadable object #<window 0x%x>",
226 XWINDOW (obj)->header.uid);
227
228 write_c_string ("#<window", printcharfun);
229 if (!NILP (XWINDOW (obj)->buffer))
230 {
231 Lisp_Object name = XBUFFER (XWINDOW (obj)->buffer)->name;
232 write_c_string (" on ", printcharfun);
233 print_internal (name, printcharfun, 1);
234 }
235 sprintf (buf, " 0x%x>", XWINDOW (obj)->header.uid);
236 write_c_string (buf, printcharfun);
237 }
238
239 static void
240 finalize_window (void *header, int for_disksave)
241 {
242 struct window *w = (struct window *) header;
243
244 if (w->line_start_cache)
245 {
246 Dynarr_free (w->line_start_cache);
247 w->line_start_cache = 0;
248 }
249
250 if (w->face_cachels)
251 {
252 int i;
253
254 for (i = 0; i < Dynarr_length (w->face_cachels); i++)
255 {
256 struct face_cachel *cachel = Dynarr_atp (w->face_cachels, i);
257 if (cachel->merged_faces)
258 {
259 Dynarr_free (cachel->merged_faces);
260 cachel->merged_faces = 0;
261 }
262 }
263 Dynarr_free (w->face_cachels);
264 w->face_cachels = 0;
265 }
266
267 if (w->glyph_cachels)
268 {
269 Dynarr_free (w->glyph_cachels);
270 w->glyph_cachels = 0;
271 }
272 }
273
274 #define INIT_DISP_VARIABLE(field, initialization) \
275 p->field[CURRENT_DISP] = initialization; \
276 p->field[DESIRED_DISP] = initialization; \
277 p->field[CMOTION_DISP] = initialization;
278
279 /* We have an implicit assertion that the first two elements (default
280 and modeline faces) are always present in the face_element_cache.
281 Normally redisplay ensures this. However, it is possible for a
282 window to get created and functions which reference these values
283 called before redisplay works with the window for the first time.
284 All callers of allocate_window should therefore call
285 reset_face_cachels on the created window. We can't do it
286 here because the window must have its frame pointer set or
287 reset_face_cachels will fail. */
288 Lisp_Object
289 allocate_window (void)
290 {
291 Lisp_Object val = Qnil;
292 struct window *p = alloc_lcrecord (sizeof (struct window),
293 lrecord_window);
294
295 zero_lcrecord (p);
296 XSETWINDOW (val, p);
297
298 p->dead = 0;
299 p->frame = Qnil;
300 p->mini_p = Qnil;
301 p->next = Qnil;
302 p->prev = Qnil;
303 p->hchild = Qnil;
304 p->vchild = Qnil;
305 p->parent = Qnil;
306 p->buffer = Qnil;
307 INIT_DISP_VARIABLE (start, Fmake_marker ());
308 INIT_DISP_VARIABLE (pointm, Fmake_marker ());
309 p->sb_point = Fmake_marker ();
310 p->use_time = Qzero;
311 INIT_DISP_VARIABLE (last_modified, Qzero);
312 INIT_DISP_VARIABLE (last_point, Fmake_marker ());
313 INIT_DISP_VARIABLE (last_start, Fmake_marker ());
314 INIT_DISP_VARIABLE (last_facechange, Qzero);
315 p->face_cachels = Dynarr_new (struct face_cachel);
316 p->glyph_cachels = Dynarr_new (struct glyph_cachel);
317 p->line_start_cache = Dynarr_new (struct line_start_cache);
318 p->line_cache_last_updated = Qzero;
319 INIT_DISP_VARIABLE (last_point_x, 0);
320 INIT_DISP_VARIABLE (last_point_y, 0);
321 INIT_DISP_VARIABLE (window_end_pos, 0);
322 p->redisplay_end_trigger = Qnil;
323 /* cached specifier values: will get set properly later */
324 p->display_table = Qnil;
325 p->has_modeline_p = Qnil;
326 p->modeline_shadow_thickness = Qnil;
327 #ifdef HAVE_SCROLLBARS
328 p->scrollbar_width = Qnil;
329 p->scrollbar_height = Qnil;
330 #endif
331 p->left_margin_width = Qnil;
332 p->right_margin_width = Qnil;
333 #ifdef HAVE_TOOLBARS
334 p->toolbar_size[0] = Qnil;
335 p->toolbar_size[1] = Qnil;
336 p->toolbar_size[2] = Qnil;
337 p->toolbar_size[3] = Qnil;
338 #endif
339 p->minimum_line_ascent = Qnil;
340 p->minimum_line_descent = Qnil;
341 p->use_left_overflow = Qnil;
342 p->use_right_overflow = Qnil;
343 #ifdef HAVE_MENUBARS
344 p->menubar_visible_p = Qnil;
345 #endif
346 #ifdef HAVE_TOOLBARS
347 p->toolbar_buttons_captioned_p = Qnil;
348 #endif
349 p->text_cursor_visible_p = Qnil;
350 /* end cached specifier values. */
351
352 p->dedicated = Qnil;
353 p->windows_changed = 1;
354 p->shadow_thickness_changed = 1;
355
356 return (val);
357 }
358 #undef INIT_DISP_VARIABLE
359
360 /*
361 * The redisplay structures used to be stored with each window. While
362 * they are logically something associated with frames they can't be
363 * stored there with a redisplay which handles variable height lines.
364 * Lines in horizontally split windows might not line up. So they get
365 * stored with the windows.
366 *
367 * The problem with this is window configurations. When restoring a
368 * window configuration it now becomes problematic to do an
369 * incremental redisplay. The solution is to store the redisplay
370 * structures with the frame as they should be but laid out in the
371 * same manner as the window structure. Thus is born the window
372 * mirror.
373 *
374 * It also becomes a convenient place to stick scrollbar instances
375 * since they extrapolate out to having the same problem described for
376 * the display structures.
377 */
378
379 /* Create a new mindow mirror structure and associated redisplay
380 structs. */
381 static struct window_mirror *
382 new_window_mirror (struct frame *f)
383 {
384 struct window_mirror *t;
385
386 t = (struct window_mirror *)
387 xmalloc (sizeof (struct window_mirror));
388 memset (t, 0, sizeof (struct window_mirror));
389
390 t->frame = f;
391
392 t->current_display_lines = Dynarr_new (struct display_line);
393 t->desired_display_lines = Dynarr_new (struct display_line);
394 t->buffer = NULL;
395
396 #ifdef HAVE_SCROLLBARS
397 t->scrollbar_vertical_instance = NULL;
398 t->scrollbar_horizontal_instance = NULL;
399 #endif
400
401 return t;
402 }
403
404 /* Synchronize the mirror structure with a given window structure.
405 This is normally called from update_frame_window_mirror with a
406 starting window of f->root_window. */
407 static struct window_mirror *
408 update_mirror_internal (Lisp_Object win, struct window_mirror *mir)
409 {
410 if (NILP (win))
411 {
412 if (mir)
413 {
414 free_window_mirror (mir);
415 mir = 0;
416 }
417 return mir;
418 }
419 else
420 if (!mir)
421 mir = new_window_mirror (XFRAME (XWINDOW (win)->frame));
422
423 mir->next = update_mirror_internal (XWINDOW (win)->next, mir->next);
424 mir->hchild = update_mirror_internal (XWINDOW (win)->hchild, mir->hchild);
425 mir->vchild = update_mirror_internal (XWINDOW (win)->vchild, mir->vchild);
426
427 /*
428 * If the redisplay structs are not empty and the mirror has
429 * children, then this mirror structure was formerly being used for
430 * display but is no longer. Reset its current display structs so
431 * that redisplay doesn't accidentally think they are accurate if it
432 * is later used for display purposes once again. Also, mark the
433 * scrollbar instance as not active.
434 */
435 if (mir->vchild || mir->hchild)
436 {
437 /* The redisplay structures are big. Leaving them around in
438 non-leaf windows can add up to a lot of wasted space. So
439 don't do it. */
440 free_display_structs (mir);
441 mir->current_display_lines = Dynarr_new (struct display_line);
442 mir->desired_display_lines = Dynarr_new (struct display_line);
443
444 #ifdef HAVE_SCROLLBARS
445 update_window_scrollbars (XWINDOW (win), mir, 0, 0);
446 #endif
447 mir->buffer = NULL;
448 }
449
450 return mir;
451 }
452
453 /* Given a window mirror, determine which real window it contains the
454 redisplay structures for. */
455 static Lisp_Object
456 real_window_internal (Lisp_Object win, struct window_mirror *rmir,
457 struct window_mirror *mir)
458 {
459 Lisp_Object retval;
460
461 for (; !NILP (win) && rmir ; win = XWINDOW (win)->next, rmir = rmir->next)
462 {
463 if (mir == rmir)
464 return win;
465 if (!NILP (XWINDOW (win)->vchild))
466 {
467 retval = real_window_internal (XWINDOW (win)->vchild, rmir->vchild,
468 mir);
469 if (!NILP (retval))
470 return retval;
471 }
472 if (!NILP (XWINDOW (win)->hchild))
473 {
474 retval = real_window_internal (XWINDOW (win)->hchild, rmir->hchild,
475 mir);
476 if (!NILP (retval))
477 return retval;
478 }
479 }
480
481 return Qnil;
482 }
483
484 /* Given a real window, find the mirror structure which contains its
485 redisplay structures. */
486 static struct window_mirror *
487 find_window_mirror_internal (Lisp_Object win, struct window_mirror *rmir,
488 struct window *w)
489 {
490 struct window_mirror *retval;
491
492 for (; !NILP (win); win = XWINDOW (win)->next, rmir = rmir->next)
493 {
494 if (w == XWINDOW (win))
495 return rmir;
496 if (!NILP (XWINDOW (win)->vchild) &&
497 (retval = find_window_mirror_internal (XWINDOW (win)->vchild,
498 rmir->vchild, w)))
499 return retval;
500 if (!NILP (XWINDOW (win)->hchild) &&
501 (retval = find_window_mirror_internal (XWINDOW (win)->hchild,
502 rmir->hchild, w)))
503 return retval;
504 }
505
506 return 0;
507 }
508
509 /* Update the mirror structure for the given frame. */
510 void
511 update_frame_window_mirror (struct frame *f)
512 {
513 f->root_mirror = update_mirror_internal (f->root_window, f->root_mirror);
514 f->mirror_dirty = 0;
515 }
516
517 /* Free a given mirror structure along with all of its children as
518 well as their associated display structures. */
519 void
520 free_window_mirror (struct window_mirror *mir)
521 {
522 struct window_mirror *p;
523
524 p = mir;
525 while (mir)
526 {
527 if (mir->hchild) free_window_mirror (mir->hchild);
528 if (mir->vchild) free_window_mirror (mir->vchild);
529 #ifdef HAVE_SCROLLBARS
530 release_window_mirror_scrollbars (mir);
531 #endif
532 free_display_structs (mir);
533 mir = mir->next;
534 xfree (p);
535 p = mir;
536 }
537 }
538
539 /* Given a mirror structure, return the window it mirrors. Calls
540 real_window_internal to do most of the work. */
541 Lisp_Object
542 real_window (struct window_mirror *mir, int no_abort)
543 {
544 Lisp_Object retval;
545
546 retval = real_window_internal (mir->frame->root_window,
547 mir->frame->root_mirror, mir);
548
549 if (NILP (retval) && !no_abort)
550 abort ();
551
552 return retval;
553 }
554
555 /* Given a real window, return its mirror structure. Calls
556 find_window_mirror_internal to do all of the work. */
557 struct window_mirror *
558 find_window_mirror (struct window *w)
559 {
560 struct frame *f = XFRAME (w->frame);
561 if (f->mirror_dirty)
562 update_frame_window_mirror (f);
563 return find_window_mirror_internal (f->root_window, f->root_mirror, w);
564 }
565
566 /*****************************************************************************
567 find_window_by_pixel_pos
568
569 Given a pixel position relative to a frame, find the window at that
570 position.
571 ****************************************************************************/
572 struct window *
573 find_window_by_pixel_pos (unsigned int pix_x, unsigned int pix_y,
574 Lisp_Object win)
575 {
576 struct window *w;
577
578 if (NILP (win))
579 return 0;
580
581 for (; !NILP (win); win = XWINDOW (win)->next)
582 {
583 if (!NILP (XWINDOW (win)->vchild) &&
584 (w = find_window_by_pixel_pos (pix_x, pix_y, XWINDOW (win)->vchild)))
585 return w;
586 if (!NILP (XWINDOW (win)->hchild) &&
587 (w = find_window_by_pixel_pos (pix_x, pix_y, XWINDOW (win)->hchild)))
588 return w;
589 w = XWINDOW (win);
590 if (pix_x >= WINDOW_LEFT (w)
591 && pix_x <= WINDOW_RIGHT (w)
592 && pix_y >= WINDOW_TOP (w)
593 && pix_y <= WINDOW_BOTTOM (w))
594 return w;
595 }
596 return 0;
597 }
598
599 /* Return a pointer to the display structures for the given window. */
600 display_line_dynarr *
601 window_display_lines (struct window *w, int which)
602 {
603 struct window_mirror *t;
604
605 if (XFRAME (w->frame)->mirror_dirty)
606 update_frame_window_mirror (XFRAME (w->frame));
607 t = find_window_mirror (w);
608 if (!t)
609 abort ();
610
611 if (which == CURRENT_DISP)
612 return t->current_display_lines;
613 else if (which == DESIRED_DISP)
614 return t->desired_display_lines;
615 else if (which == CMOTION_DISP)
616 /* The CMOTION_DISP display lines are global. */
617 return cmotion_display_lines;
618 else
619 abort ();
620
621 return 0; /* shut up compiler */
622 }
623
624 struct buffer *
625 window_display_buffer (struct window *w)
626 {
627 struct window_mirror *t;
628
629 if (XFRAME (w->frame)->mirror_dirty)
630 update_frame_window_mirror (XFRAME (w->frame));
631 t = find_window_mirror (w);
632 if (!t)
633 abort ();
634
635 return t->buffer;
636 }
637
638 void
639 set_window_display_buffer (struct window *w, struct buffer *b)
640 {
641 struct window_mirror *t;
642
643 if (XFRAME (w->frame)->mirror_dirty)
644 update_frame_window_mirror (XFRAME (w->frame));
645 t = find_window_mirror (w);
646 if (!t)
647 abort ();
648
649 t->buffer = b;
650 }
651
652
653 /* Determining a windows position based solely on its pixel
654 positioning doesn't work. Instead, we do it the intelligent way,
655 by checking its positioning in the window hierarchy. */
656 int
657 window_is_leftmost (struct window *w)
658 {
659 Lisp_Object parent, current_ancestor, window;
660
661 XSETWINDOW (window, w);
662
663 parent = XWINDOW (window)->parent;
664 current_ancestor = window;
665
666 while (!NILP (parent))
667 {
668 if (!NILP (XWINDOW (parent)->hchild) &&
669 !EQ (XWINDOW (parent)->hchild, current_ancestor))
670 return 0;
671
672 current_ancestor = parent;
673 parent = XWINDOW (parent)->parent;
674 }
675
676 return 1;
677 }
678
679 int
680 window_is_rightmost (struct window *w)
681 {
682 Lisp_Object parent, current_ancestor, window;
683
684 XSETWINDOW (window, w);
685
686 parent = XWINDOW (window)->parent;
687 current_ancestor = window;
688
689 while (!NILP (parent))
690 {
691 if (!NILP (XWINDOW (parent)->hchild)
692 && !NILP (XWINDOW (current_ancestor)->next))
693 return 0;
694
695 current_ancestor = parent;
696 parent = XWINDOW (parent)->parent;
697 }
698
699 return 1;
700 }
701
702 static int
703 window_full_width_p (struct window *w)
704 {
705 return window_is_leftmost (w) && window_is_rightmost (w);
706 }
707
708 static int
709 window_is_highest (struct window *w)
710 {
711 Lisp_Object parent, current_ancestor, window;
712
713 XSETWINDOW (window, w);
714
715 parent = XWINDOW (window)->parent;
716 current_ancestor = window;
717
718 while (!NILP (parent))
719 {
720 if (!NILP (XWINDOW (parent)->vchild) &&
721 !EQ (XWINDOW (parent)->vchild, current_ancestor))
722 return 0;
723
724 current_ancestor = parent;
725 parent = XWINDOW (parent)->parent;
726 }
727
728 /* This is really to catch the minibuffer but we make it generic in
729 case we ever change things around to let the minibuffer be on top. */
730 if (NILP (XWINDOW (current_ancestor)->prev))
731 return 1;
732 else
733 return 0;
734 }
735
736 static int
737 window_is_lowest (struct window *w)
738 {
739 Lisp_Object parent, current_ancestor, window;
740
741 XSETWINDOW (window, w);
742
743 parent = XWINDOW (window)->parent;
744 current_ancestor = window;
745
746 while (!NILP (parent))
747 {
748 if (!NILP (XWINDOW (parent)->vchild)
749 && !NILP (XWINDOW (current_ancestor)->next))
750 return 0;
751
752 current_ancestor = parent;
753 parent = XWINDOW (parent)->parent;
754 }
755
756 return 1;
757 }
758
759 #if 0 /* not currently used */
760
761 static int
762 window_full_height_p (struct window *w)
763 {
764 return window_is_highest (w) && window_is_lowest (w);
765 }
766
767 #endif
768
769 int
770 window_truncation_on (struct window *w)
771 {
772 /* Horizontally scrolled windows are truncated. */
773 if (w->hscroll)
774 return 1;
775
776 /* If truncate_partial_width_windows is true and the window is not
777 the full width of the frame it is truncated. */
778 if (truncate_partial_width_windows
779 && !(window_is_leftmost (w) && window_is_rightmost (w)))
780 return 1;
781
782 /* If the window's buffer's value of truncate_lines is non-nil, then
783 the window is truncated. */
784 if (!NILP (XBUFFER (w->buffer)->truncate_lines))
785 return 1;
786
787 return 0;
788 }
789
790 int
791 window_needs_vertical_divider (struct window *w)
792 {
793 #ifdef HAVE_SCROLLBARS
794 struct frame *f = XFRAME (w->frame);
795
796 if (!window_scrollbar_width (w))
797 {
798 if (f->scrollbar_on_left)
799 return (!window_is_leftmost (w));
800 else
801 return (!window_is_rightmost (w));
802 }
803 else
804 return 0;
805 #else
806 return (!window_is_leftmost (w));
807 #endif
808 }
809
810 int
811 window_scrollbar_width (struct window *w)
812 {
813 #ifdef HAVE_SCROLLBARS
814 if (!WINDOW_WIN_P (w)
815 || MINI_WINDOW_P (w)
816 || NILP (w->buffer))
817 /* #### when does NILP (w->buffer) happen? */
818 return 0;
819
820 return XINT (w->scrollbar_width);
821 #else
822 return 0;
823 #endif
824 }
825
826 /* Horizontal scrollbars are only active on windows with truncation
827 turned on. */
828 int
829 window_scrollbar_height (struct window *w)
830 {
831 #ifdef HAVE_SCROLLBARS
832 if (!WINDOW_WIN_P (w)
833 || MINI_WINDOW_P (w)
834 || NILP (w->buffer)
835 || !window_truncation_on (w))
836 return 0;
837
838 return XINT (w->scrollbar_height);
839 #else
840 return 0;
841 #endif
842 }
843
844 int
845 window_modeline_height (struct window *w)
846 {
847 struct frame *f = XFRAME (w->frame);
848 int modeline_height;
849
850 if (MINI_WINDOW_P (w) || NILP (w->buffer))
851 {
852 modeline_height = 0;
853 }
854 else if (!WINDOW_HAS_MODELINE_P (w))
855 {
856 if (window_scrollbar_height (w))
857 modeline_height = 0;
858 else
859 {
860 modeline_height = FRAMEMETH (f, divider_height, ());
861
862 if (!EQ (Qzero, w->modeline_shadow_thickness) && FRAME_WIN_P (f))
863 modeline_height += (2 * MODELINE_SHADOW_THICKNESS (w));
864 }
865 }
866 else
867 {
868 if (noninteractive)
869 modeline_height = 0;
870 else
871 {
872 display_line_dynarr *dla;
873
874 /* We don't force a regeneration of the modeline here.
875 Instead it is now a precondition that any function calling
876 this should make sure that one of these structures is
877 up-to-date. In practice this only affects two internal
878 redisplay functions, regenerate_window and
879 regenerate_window_point_center. */
880 /* We check DESIRED_DISP because if it is valid it is more
881 up-to-date than CURRENT_DISP. For calls to this outside
882 of redisplay it doesn't matter which structure we check
883 since there is a redisplay condition that these
884 structures be identical outside of redisplay. */
885 dla = window_display_lines (w, DESIRED_DISP);
886 if (dla && Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
887 modeline_height = (Dynarr_atp (dla, 0)->ascent +
888 Dynarr_atp (dla, 0)->descent);
889 else
890 {
891 dla = window_display_lines (w, CURRENT_DISP);
892 if (dla && Dynarr_length (dla) && Dynarr_atp (dla, 0)->modeline)
893 modeline_height = (Dynarr_atp (dla, 0)->ascent +
894 Dynarr_atp (dla, 0)->descent);
895 else
896 /* This should be an abort except I'm not yet 100%
897 confident that it won't ever get hit (though I
898 haven't been able to trigger it). It is extremely
899 unlikely to cause any noticable problem and even if
900 it does it will be a minor display glitch. */
901 /* #### Bullshit alert. It does get hit and it causes
902 noticeable glitches. real_current_modeline_height
903 is a kludge to fix this for 19.14. */
904 modeline_height = real_current_modeline_height (w);
905 }
906
907 if (!EQ (Qzero, w->modeline_shadow_thickness) && FRAME_WIN_P (f))
908 modeline_height += (2 * MODELINE_SHADOW_THICKNESS (w));
909 }
910 }
911
912 return modeline_height;
913 }
914
915 /*****************************************************************************
916 margin_width_internal
917
918 For a given window, return the width in pixels of the specified margin.
919 ****************************************************************************/
920 static int
921 margin_width_internal (struct window *w, int left_margin)
922 {
923 struct buffer *b;
924 int window_cwidth = window_char_width (w, 1);
925 int margin_cwidth;
926 int font_width;
927 Lisp_Object window = Qnil;
928
929 /* We might be getting called on a non-leaf. */
930 if (NILP (w->buffer))
931 return 0;
932
933 /* The minibuffer never has margins. */
934 if (MINI_WINDOW_P (w))
935 return 0;
936
937 XSETWINDOW (window, w);
938 b = XBUFFER (w->buffer);
939 margin_cwidth = (left_margin ? XINT (w->left_margin_width) :
940 XINT (w->right_margin_width));
941
942 default_face_height_and_width (window, 0, &font_width);
943
944 /* The left margin takes precedence over the right margin so we
945 subtract its width from the space available for the right
946 margin. */
947 if (!left_margin)
948 window_cwidth -= XINT (w->left_margin_width);
949
950 /* The margin cannot be wider than the window is. We allow the
951 value to be bigger since it is possible for the user to enlarge
952 the window such that the left margin value would no longer be too
953 big, but we won't return a value that is larger. */
954 if (margin_cwidth > window_cwidth)
955 margin_cwidth = window_cwidth;
956
957 /* At the user level the margin is always specified in characters.
958 Internally however it is manipulated in terms of pixels. */
959 return (margin_cwidth * font_width);
960 }
961
962 int
963 window_left_margin_width (struct window *w)
964 {
965 return margin_width_internal (w, 1);
966 }
967
968 int
969 window_right_margin_width (struct window *w)
970 {
971 return margin_width_internal (w, 0);
972 }
973
974 static int
975 window_top_toolbar_height (struct window *w)
976 {
977 /* #### implement this shit. */
978 return 0;
979 }
980
981 /* #### Currently used in scrollbar.c. Does it actually need to be? */
982 int
983 window_bottom_toolbar_height (struct window *w)
984 {
985 return 0;
986 }
987
988 static int
989 window_left_toolbar_width (struct window *w)
990 {
991 return 0;
992 }
993
994 static int
995 window_right_toolbar_width (struct window *w)
996 {
997 return 0;
998 }
999
1000 /*****************************************************************************
1001 Window Gutters
1002
1003 The gutters of a window are those areas in the boundary defined by
1004 w->pixel_top, w->pixel_left, w->pixel_height and w->pixel_width which
1005 do not contain text. Items which may be in the gutters include
1006 scrollbars, toolbars and modelines. The margin areas are not
1007 included. This is an exception made because redisplay special cases
1008 the handling of those areas in many places in such a way that
1009 including them in the gutter area would make life difficult.
1010
1011 The size functions refer to height for the bottom and top gutters and
1012 width for the left and right gutters. The starting position
1013 functions refer to the Y coord for bottom and top gutters and the X
1014 coord for left and right gutters. All starting positions are
1015 relative to the frame, not the window.
1016 ****************************************************************************/
1017
1018 int
1019 window_top_gutter_height (struct window *w)
1020 {
1021 int toolbar_height = window_top_toolbar_height (w);
1022
1023 if (!NILP (w->hchild) || !NILP (w->vchild))
1024 return 0;
1025
1026 #ifdef HAVE_SCROLLBARS
1027 if (XFRAME (w->frame)->scrollbar_on_top)
1028 return window_scrollbar_height (w) + toolbar_height;
1029 else
1030 #endif
1031 return toolbar_height;
1032 }
1033
1034 int
1035 window_bottom_gutter_height (struct window *w)
1036 {
1037 int other_height;
1038
1039 if (!NILP (w->hchild) || !NILP (w->vchild))
1040 return 0;
1041 else
1042 other_height =
1043 window_modeline_height (w) + window_bottom_toolbar_height (w);
1044
1045 #ifdef HAVE_SCROLLBARS
1046 if (!XFRAME (w->frame)->scrollbar_on_top)
1047 return window_scrollbar_height (w) + other_height;
1048 else
1049 #endif
1050 return other_height;
1051 }
1052
1053 static int
1054 window_left_right_gutter_width_internal (struct window *w, int modeline)
1055 {
1056 struct frame *f = XFRAME (w->frame);
1057 int scrollbar_width = window_scrollbar_width (w);
1058
1059 if (!NILP (w->hchild) || !NILP (w->vchild))
1060 return 0;
1061
1062 if (!modeline)
1063 {
1064 if (scrollbar_width)
1065 return scrollbar_width;
1066 else if (window_needs_vertical_divider (w))
1067 return FRAMEMETH (f, divider_width, ());
1068 else
1069 return 0;
1070 }
1071 else
1072 {
1073 /* The shadows on the 3D modelines provide a visual break
1074 between the modelines of horizontally split windows. 2D
1075 modelines need some help, though. */
1076 if (!EQ (Qzero, w->modeline_shadow_thickness))
1077 return 0;
1078 else if (window_needs_vertical_divider (w))
1079 return FRAMEMETH (f, divider_width, ());
1080 else
1081 return 0;
1082 }
1083 }
1084
1085 int
1086 window_left_gutter_width (struct window *w, int modeline)
1087 {
1088 if (!NILP (w->hchild) || !NILP (w->vchild))
1089 return 0;
1090
1091 #ifdef HAVE_SCROLLBARS
1092 if (XFRAME (w->frame)->scrollbar_on_left)
1093 {
1094 #endif
1095 return (window_left_right_gutter_width_internal (w, modeline) +
1096 window_left_toolbar_width (w));
1097 #ifdef HAVE_SCROLLBARS
1098 }
1099 else
1100 return window_left_toolbar_width (w);
1101 #endif
1102 }
1103
1104 int
1105 window_right_gutter_width (struct window *w, int modeline)
1106 {
1107 if (!NILP (w->hchild) || !NILP (w->vchild))
1108 return 0;
1109
1110 #ifdef HAVE_SCROLLBARS
1111 if (!XFRAME (w->frame)->scrollbar_on_left)
1112 {
1113 return (window_left_right_gutter_width_internal (w, modeline) +
1114 window_right_toolbar_width (w));
1115 }
1116 else
1117 #endif
1118 return window_right_toolbar_width (w);
1119 }
1120
1121
1122 DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0 /*
1123 Return t if OBJ is a window.
1124 */ )
1125 (obj)
1126 Lisp_Object obj;
1127 {
1128 return (WINDOWP (obj) ? Qt : Qnil);
1129 }
1130
1131 DEFUN ("window-live-p", Fwindow_live_p, Swindow_live_p, 1, 1, 0 /*
1132 Return t if OBJ is a window which is currently visible.
1133 */ )
1134 (obj)
1135 Lisp_Object obj;
1136 {
1137 return (WINDOWP (obj) && WINDOW_LIVE_P (XWINDOW (obj)) ? Qt : Qnil);
1138 }
1139
1140 DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 1, 0 /*
1141 Return the window that the cursor now appears in and commands apply to.
1142 If the optional argument CON-DEV-OR-FRAME is specified and is a frame, return
1143 the selected window used by that frame. If CON-DEV-OR-FRAME is a device,
1144 then the selected frame on that device will be used. If CON-DEV-OR-FRAME
1145 is a console, the selected frame on that console's selected device will
1146 be used. Otherwise, the selected frame is used.
1147 */ )
1148 (con_dev_or_frame)
1149 Lisp_Object con_dev_or_frame;
1150 {
1151 struct frame *f;
1152
1153 if (NILP (con_dev_or_frame) && NILP (Fselected_device (Qnil)))
1154 return Qnil; /* happens at startup */
1155
1156 f = decode_frame_or_selected (con_dev_or_frame);
1157 return FRAME_SELECTED_WINDOW (f);
1158 }
1159
1160 DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 1, 0 /*
1161 Return the window used now for minibuffers.
1162 If the optional argument CON-DEV-OR-FRAME is specified and is a frame, return
1163 the minibuffer window used by that frame. If CON-DEV-OR-FRAME is a device,
1164 then the selected frame on that device will be used. If CON-DEV-OR-FRAME
1165 is a console, the selected frame on that console's selected device will
1166 be used. Otherwise, the selected frame is used.
1167 */ )
1168 (con_dev_or_frame)
1169 Lisp_Object con_dev_or_frame;
1170 {
1171 struct frame *f = decode_frame_or_selected (con_dev_or_frame);
1172
1173 return FRAME_MINIBUF_WINDOW (f);
1174 }
1175
1176 DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 1, 1, 0 /*
1177 Return non-nil if WINDOW is a minibuffer window.
1178 */ )
1179 (window)
1180 Lisp_Object window;
1181 {
1182 struct window *w = decode_window (window);
1183 return (MINI_WINDOW_P (w) ? Qt : Qnil);
1184 }
1185
1186 DEFUN ("window-first-hchild", Fwindow_first_hchild, Swindow_first_hchild,
1187 1, 1, 0 /*
1188 Return the first horizontal child of WINDOW, or nil.
1189 */ )
1190 (window)
1191 Lisp_Object window;
1192 {
1193 struct window *w = decode_window (window);
1194 return w->hchild;
1195 }
1196
1197 DEFUN ("window-first-vchild", Fwindow_first_vchild, Swindow_first_vchild,
1198 1, 1, 0 /*
1199 Return the first vertical child of WINDOW, or nil.
1200 */ )
1201 (window)
1202 Lisp_Object window;
1203 {
1204 struct window *w = decode_window (window);
1205 return w->vchild;
1206 }
1207
1208 DEFUN ("window-next-child", Fwindow_next_child, Swindow_next_child,
1209 1, 1, 0 /*
1210 Return the next window on the same level as WINDOW, or nil.
1211 */ )
1212 (window)
1213 Lisp_Object window;
1214 {
1215 struct window *w = decode_window (window);
1216 return w->next;
1217 }
1218
1219 DEFUN ("window-previous-child", Fwindow_previous_child, Swindow_previous_child,
1220 1, 1, 0 /*
1221 Return the previous window on the same level as WINDOW, or nil.
1222 */ )
1223 (window)
1224 Lisp_Object window;
1225 {
1226 struct window *w = decode_window (window);
1227 return w->prev;
1228 }
1229
1230 DEFUN ("window-parent", Fwindow_parent, Swindow_parent,
1231 1, 1, 0 /*
1232 Return the parent of WINDOW, or nil.
1233 */ )
1234 (window)
1235 Lisp_Object window;
1236 {
1237 struct window *w = decode_window (window);
1238 return w->parent;
1239 }
1240
1241 DEFUN ("window-lowest-p", Fwindow_lowest_p, Swindow_lowest_p, 1, 1, 0 /*
1242 Return non-nil if WINDOW is along the bottom of its frame.
1243 */ )
1244 (window)
1245 Lisp_Object window;
1246 {
1247 struct window *w = decode_window (window);
1248 return window_is_lowest (w) ? Qt : Qnil;
1249 }
1250
1251 DEFUN ("window-highest-p", Fwindow_highest_p, Swindow_highest_p, 1, 1, 0 /*
1252 Return non-nil if WINDOW is along the top of its frame.
1253 */ )
1254 (window)
1255 Lisp_Object window;
1256 {
1257 struct window *w = decode_window (window);
1258 return window_is_highest (w) ? Qt : Qnil;
1259 }
1260
1261 DEFUN ("window-leftmost-p", Fwindow_leftmost_p, Swindow_leftmost_p, 1, 1, 0 /*
1262 Return non-nil if WINDOW is along the left edge of its frame.
1263 */ )
1264 (window)
1265 Lisp_Object window;
1266 {
1267 struct window *w = decode_window (window);
1268 return window_is_leftmost (w) ? Qt : Qnil;
1269 }
1270
1271 DEFUN ("window-rightmost-p", Fwindow_rightmost_p, Swindow_rightmost_p,
1272 1, 1, 0 /*
1273 Return non-nil if WINDOW is along the right edge of its frame.
1274 */ )
1275 (window)
1276 Lisp_Object window;
1277 {
1278 struct window *w = decode_window (window);
1279 return window_is_rightmost (w) ? Qt : Qnil;
1280 }
1281
1282 DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p,
1283 Spos_visible_in_window_p, 0, 2, 0 /*
1284 Return t if position POS is currently on the frame in WINDOW.
1285 Returns nil if that position is scrolled vertically out of view.
1286 POS defaults to point in WINDOW's buffer; WINDOW, to the selected window.
1287 */ )
1288 (pos, window)
1289 Lisp_Object pos, window;
1290 {
1291 struct window *w;
1292 Bufpos top;
1293 Bufpos posint;
1294 struct buffer *buf;
1295
1296 w = decode_window (window);
1297 top = marker_position (w->start[CURRENT_DISP]);
1298
1299 buf = XBUFFER (w->buffer);
1300
1301 if (NILP (pos))
1302 posint = BUF_PT (buf);
1303 else
1304 {
1305 CHECK_INT_COERCE_MARKER (pos);
1306 posint = XINT (pos);
1307 }
1308
1309 if (posint < top || posint > BUF_ZV (buf))
1310 return Qnil;
1311
1312 /* w->start can be out of range. If it is, do something reasonable. */
1313 if (top < BUF_BEGV (buf) || top > BUF_ZV (buf))
1314 return Qnil;
1315
1316 if (point_would_be_visible (w, top, posint))
1317 return Qt;
1318 else
1319 return Qnil;
1320 }
1321
1322
1323 struct window *
1324 decode_window (Lisp_Object window)
1325 {
1326 if (NILP (window))
1327 return XWINDOW (Fselected_window (Qnil));
1328
1329 CHECK_LIVE_WINDOW (window);
1330 return XWINDOW (window);
1331 }
1332
1333 DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0 /*
1334 Return the buffer that WINDOW is displaying.
1335 */ )
1336 (window)
1337 Lisp_Object window;
1338 {
1339 return decode_window (window)->buffer;
1340 }
1341
1342 DEFUN ("window-frame", Fwindow_frame, Swindow_frame, 0, 1, 0 /*
1343 Return the frame that window WINDOW is on.
1344 */ )
1345 (window)
1346 Lisp_Object window;
1347 {
1348 return decode_window (window)->frame;
1349 }
1350
1351 DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0 /*
1352 Return the number of default lines in WINDOW.
1353 This actually works by dividing the window's pixel height (including
1354 the modeline and horizontal scrollbar, if any) by the height of the
1355 default font; therefore, the number of displayed lines will probably
1356 be different.
1357 Use `window-height' to get consistent results in geometry calculations.
1358 Use `window-displayed-height' to get the actual number of lines
1359 currently displayed in a window.
1360 */ )
1361 (window)
1362 Lisp_Object window;
1363 {
1364 return make_int (window_char_height (decode_window (window), 1));
1365 }
1366
1367 DEFUN ("window-displayed-height", Fwindow_displayed_height,
1368 Swindow_displayed_height, 0, 1, 0 /*
1369 Return the number of lines currently displayed in WINDOW.
1370 This counts the actual number of lines displayed in WINDOW
1371 (as opposed to `window-height'). The modeline and horizontal
1372 scrollbar do not count as lines. If there is some blank space
1373 between the end of the buffer and the end of the window, this
1374 function pretends that there are lines of text in the default
1375 font there.
1376 */ )
1377 (window)
1378 Lisp_Object window;
1379 {
1380 return make_int (window_displayed_height (decode_window (window)));
1381 }
1382
1383 DEFUN ("window-pixel-height", Fwindow_pixel_height, Swindow_pixel_height,
1384 0, 1, 0 /*
1385 Return the height of WINDOW in pixels. Defaults to current window.
1386 This includes the window's modeline and horizontal scrollbar (if any).
1387 */ )
1388 (window)
1389 Lisp_Object window;
1390 {
1391 return (make_int (decode_window (window)->pixel_height));
1392 }
1393
1394 DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0 /*
1395 Return the number of display columns in WINDOW.
1396 This is the width that is usable columns available for text in WINDOW.
1397 */ )
1398 (window)
1399 Lisp_Object window;
1400 {
1401 struct window *w = decode_window (window);
1402 return (make_int (window_char_width (w, 0)));
1403 }
1404
1405 DEFUN ("window-pixel-width", Fwindow_pixel_width, Swindow_pixel_width,
1406 0, 1, 0 /*
1407 Return the width of WINDOW in pixels. Defaults to current window.
1408 */ )
1409 (window)
1410 Lisp_Object window;
1411 {
1412 return (make_int (decode_window (window)->pixel_width));
1413 }
1414
1415 DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0 /*
1416 Return the number of columns by which WINDOW is scrolled from left margin.
1417 */ )
1418 (window)
1419 Lisp_Object window;
1420 {
1421 return (make_int (decode_window (window)->hscroll));
1422 }
1423
1424 DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0 /*
1425 Set number of columns WINDOW is scrolled from left margin to NCOL.
1426 NCOL should be zero or positive.
1427 */ )
1428 (window, ncol)
1429 Lisp_Object window, ncol;
1430 {
1431 struct window *w;
1432 int ncols;
1433
1434 CHECK_INT (ncol);
1435 ncols = XINT (ncol);
1436 if (ncols < 0) ncols = 0;
1437 w = decode_window (window);
1438 if (w->hscroll != ncols)
1439 MARK_CLIP_CHANGED; /* FSF marks differently but we aren't FSF. */
1440 w->hscroll = ncols;
1441 return ncol;
1442 }
1443
1444 #if 0 /* bogus RMS crock */
1445
1446 xxDEFUN ("window-redisplay-end-trigger", Fwindow_redisplay_end_trigger,
1447 Swindow_redisplay_end_trigger, 0, 1, 0 /*
1448 Return WINDOW's redisplay end trigger value.
1449 See `set-window-redisplay-end-trigger' for more information.
1450 */ )
1451 (window)
1452 Lisp_Object window;
1453 {
1454 return decode_window (window)->redisplay_end_trigger;
1455 }
1456
1457 xxDEFUN ("set-window-redisplay-end-trigger", Fset_window_redisplay_end_trigger,
1458 Sset_window_redisplay_end_trigger, 2, 2, 0 /*
1459 Set WINDOW's redisplay end trigger value to VALUE.
1460 VALUE should be a buffer position (typically a marker) or nil.
1461 If it is a buffer position, then if redisplay in WINDOW reaches a position
1462 beyond VALUE, the functions in `redisplay-end-trigger-functions' are called
1463 with two arguments: WINDOW, and the end trigger value.
1464 Afterwards the end-trigger value is reset to nil.
1465 */ )
1466 (window, value)
1467 register Lisp_Object window, value;
1468 {
1469 register struct window *w;
1470
1471 w = decode_window (window);
1472 w->redisplay_end_trigger = value;
1473 return value;
1474 }
1475
1476 #endif /* 0 */
1477
1478 DEFUN ("window-pixel-edges", Fwindow_pixel_edges, Swindow_pixel_edges,
1479 0, 1, 0 /*
1480 Return a list of the pixel edge coordinates of WINDOW.
1481 \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of frame.
1482 The frame toolbars and menubars are considered to be outside of this area.
1483 */ )
1484 (window)
1485 Lisp_Object window;
1486 {
1487 struct window *w = decode_window (window);
1488 struct frame *f = XFRAME (w->frame);
1489 int left, top;
1490
1491 left = w->pixel_left - FRAME_LEFT_BORDER_END (f);
1492 top = w->pixel_top - FRAME_TOP_BORDER_END (f);
1493
1494 return list4 (make_int (left),
1495 make_int (top),
1496 make_int (left + w->pixel_width),
1497 make_int (top + w->pixel_height));
1498 }
1499
1500 DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0 /*
1501 Return current value of point in WINDOW.
1502 For a nonselected window, this is the value point would have
1503 if that window were selected.
1504
1505 Note that, when WINDOW is the selected window and its buffer
1506 is also currently selected, the value returned is the same as (point).
1507 It would be more strictly correct to return the `top-level' value
1508 of point, outside of any save-excursion forms.
1509 But that is hard to define.
1510 */ )
1511 (window)
1512 Lisp_Object window;
1513 {
1514 struct window *w = decode_window (window);
1515
1516 /* The special check for current buffer is necessary for this
1517 function to work as defined when called within an excursion. */
1518 if (w == XWINDOW (Fselected_window (XFRAME (w->frame)->device))
1519 && current_buffer == XBUFFER (w->buffer))
1520 return Fpoint (Qnil);
1521 return Fmarker_position (w->pointm[CURRENT_DISP]);
1522 }
1523
1524 DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0 /*
1525 Return position at which display currently starts in WINDOW.
1526 This is updated by redisplay or by calling `set-window-start'.
1527 */ )
1528 (window)
1529 Lisp_Object window;
1530 {
1531 return Fmarker_position (decode_window (window)->start[CURRENT_DISP]);
1532 }
1533
1534 DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 2, 0 /*
1535 Return position at which display currently ends in WINDOW.
1536 This is updated by redisplay, when it runs to completion.
1537 Simply changing the buffer text or setting `window-start'
1538 does not update this value.
1539 If GUARANTEE is non-nil, then the return value is guaranteed to be
1540 the value of window-end at the end of the next full redisplay assuming
1541 nothing else changes in the meantime. This function is potentially much
1542 slower with this flag set.
1543 */ )
1544 (window, guarantee)
1545 Lisp_Object window, guarantee;
1546 {
1547 Lisp_Object value;
1548 struct window *w = decode_window (window);
1549 Lisp_Object buf;
1550
1551 if (NILP (guarantee))
1552 {
1553 buf = w->buffer;
1554 CHECK_BUFFER (buf);
1555
1556 XSETINT (value, BUF_Z (XBUFFER (buf)) - w->window_end_pos[CURRENT_DISP]);
1557
1558 return value;
1559 }
1560 else
1561 {
1562 Bufpos startp = marker_position (w->start[CURRENT_DISP]);
1563 return (make_int (end_of_last_line (w, startp)));
1564 }
1565 }
1566
1567 DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0 /*
1568 Make point value in WINDOW be at position POS in WINDOW's buffer.
1569 */ )
1570 (window, pos)
1571 Lisp_Object window, pos;
1572 {
1573 struct window *w = decode_window (window);
1574
1575 CHECK_INT_COERCE_MARKER (pos);
1576 if (w == XWINDOW (Fselected_window (Qnil)))
1577 Fgoto_char (pos, Fcurrent_buffer ());
1578 else
1579 set_marker_restricted (w->pointm[CURRENT_DISP], pos, w->buffer);
1580
1581 MARK_POINT_CHANGED;
1582 return pos;
1583 }
1584
1585 DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0 /*
1586 Make display in WINDOW start at position POS in WINDOW's buffer.
1587 Optional third arg NOFORCE non-nil inhibits next redisplay
1588 from overriding motion of point in order to display at this exact start.
1589 */ )
1590 (window, pos, noforce)
1591 Lisp_Object window, pos, noforce;
1592 {
1593 struct window *w = decode_window (window);
1594
1595 CHECK_INT_COERCE_MARKER (pos);
1596 set_marker_restricted (w->start[CURRENT_DISP], pos, w->buffer);
1597 /* this is not right, but much easier than doing what is right. */
1598 w->start_at_line_beg = 0;
1599 if (NILP (noforce))
1600 w->force_start = 1;
1601 w->redo_modeline = 1;
1602 SET_LAST_MODIFIED (w, 0);
1603 SET_LAST_FACECHANGE (w);
1604
1605 MARK_WINDOWS_CHANGED (w);
1606
1607 return pos;
1608 }
1609
1610 DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p,
1611 1, 1, 0 /*
1612 Return WINDOW's dedicated object, usually t or nil.
1613 See also `set-window-dedicated-p'.
1614 */ )
1615 (window)
1616 Lisp_Object window;
1617 {
1618 return decode_window (window)->dedicated;
1619 }
1620
1621 DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p,
1622 Sset_window_dedicated_p, 2, 2, 0 /*
1623 Control whether WINDOW is dedicated to the buffer it displays.
1624 If it is dedicated, Emacs will not automatically change
1625 which buffer appears in it.
1626 The second argument is the new value for the dedication flag;
1627 non-nil means yes.
1628 */ )
1629 (window, arg)
1630 Lisp_Object window, arg;
1631 {
1632 register struct window *w = decode_window (window);
1633
1634 if (NILP (arg))
1635 w->dedicated = Qnil;
1636 else
1637 w->dedicated = Qt;
1638
1639 return w->dedicated;
1640 }
1641
1642 /* FSFmacs has window-display-table here. We have display table as a
1643 specifier. */
1644
1645
1646 /* Record info on buffer window w is displaying
1647 when it is about to cease to display that buffer. */
1648 static void
1649 unshow_buffer (struct window *w)
1650 {
1651 Lisp_Object buf = w->buffer;
1652
1653 if (XBUFFER (buf) != XMARKER (w->pointm[CURRENT_DISP])->buffer)
1654 abort ();
1655
1656 #ifdef ENERGIZE
1657 energize_buffer_hidden_hook (w);
1658 #endif
1659
1660 /* FSF disables this check, so I'll do it too. I hope it won't
1661 break things. --ben */
1662 #if 0
1663 if (w == XWINDOW (Fselected_window (Qnil))
1664 || ! EQ (buf, XWINDOW (Fselected_window (Qnil))->buffer))
1665 /* Do this except when the selected window's buffer
1666 is being removed from some other window. */
1667 #endif
1668 /* last_window_start records the start position that this buffer
1669 had in the last window to be disconnected from it.
1670 Now that this statement is unconditional,
1671 it is possible for the buffer to be displayed in the
1672 selected window, while last_window_start reflects another
1673 window which was recently showing the same buffer.
1674 Some people might say that might be a good thing. Let's see. */
1675 XBUFFER (buf)->last_window_start =
1676 marker_position (w->start[CURRENT_DISP]);
1677
1678 /* Point in the selected window's buffer
1679 is actually stored in that buffer, and the window's pointm isn't used.
1680 So don't clobber point in that buffer. */
1681 if (! EQ (buf, XWINDOW (Fselected_window (Qnil))->buffer))
1682 {
1683 struct buffer *b= XBUFFER (buf);
1684 BUF_SET_PT (b, bufpos_clip_to_bounds (BUF_BEGV (b),
1685 marker_position (w->pointm[CURRENT_DISP]),
1686 BUF_ZV (b)));
1687 }
1688 }
1689
1690 /* Put REPLACEMENT into the window structure in place of OLD. */
1691 static void
1692 replace_window (Lisp_Object old, Lisp_Object replacement)
1693 {
1694 Lisp_Object tem;
1695 struct window *o = XWINDOW (old), *p = XWINDOW (replacement);
1696
1697 /* If OLD is its frame's root_window, then replacement is the new
1698 root_window for that frame. */
1699
1700 if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame))))
1701 FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement;
1702
1703 WINDOW_LEFT (p) = WINDOW_LEFT (o);
1704 WINDOW_TOP (p) = WINDOW_TOP (o);
1705 WINDOW_WIDTH (p) = WINDOW_WIDTH (o);
1706 WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o);
1707
1708 p->next = tem = o->next;
1709 if (!NILP (tem))
1710 XWINDOW (tem)->prev = replacement;
1711
1712 p->prev = tem = o->prev;
1713 if (!NILP (tem))
1714 XWINDOW (tem)->next = replacement;
1715
1716 p->parent = tem = o->parent;
1717 if (!NILP (tem))
1718 {
1719 if (EQ (XWINDOW (tem)->vchild, old))
1720 XWINDOW (tem)->vchild = replacement;
1721 if (EQ (XWINDOW (tem)->hchild, old))
1722 XWINDOW (tem)->hchild = replacement;
1723 }
1724
1725 /* #### Here, if replacement is a vertical combination
1726 and so is its new parent, we should make replacement's
1727 children be children of that parent instead. */
1728 }
1729
1730 /* we're deleting W; set the structure of W to indicate this. */
1731
1732 static void
1733 mark_window_as_deleted (struct window *w)
1734 {
1735 /* In the loop
1736 (while t (split-window) (delete-window))
1737 we end up with a tree of deleted windows which are all connected
1738 through the `next' slot. This might not seem so bad, as they're
1739 deleted, and will presumably be GCed - but if even *one* of those
1740 windows is still being pointed to, by the user, or by a window
1741 configuration, then *all* of those windows stick around.
1742
1743 Since the window-configuration code doesn't need any of the
1744 pointers to other windows (they are all recreated from the
1745 window-config data), we set them all to nil so that we
1746 are able to collect more actual garbage.
1747 */
1748 w->next = Qnil;
1749 w->prev = Qnil;
1750 w->hchild = Qnil;
1751 w->vchild = Qnil;
1752 w->parent = Qnil;
1753
1754 w->dead = 1;
1755
1756 /* Free the extra data structures attached to windows immediately so
1757 they don't sit around consuming excess space. They will be
1758 reinitialized by the window-configuration code as necessary. */
1759 finalize_window ((void *) w, 0);
1760 }
1761
1762 DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 2, "" /*
1763 Remove WINDOW from the display. Default is selected window.
1764 If window is the only one on the frame, the frame is destroyed.
1765 Normally, you cannot delete the last non-minibuffer-only frame (you must
1766 use `save-buffers-kill-emacs' or `kill-emacs'). However, if optional
1767 second argument FORCE is non-nil, you can delete the last frame. (This
1768 will automatically call `save-buffers-kill-emacs'.)
1769 */ )
1770 (window, force)
1771 Lisp_Object window, force;
1772 {
1773 /* This function can GC if this is the only window in the frame */
1774 struct window *w;
1775 Lisp_Object parent;
1776 struct window *par;
1777 Lisp_Object frame;
1778 struct frame *f;
1779 struct device *d;
1780
1781 /* Note: this function is called by other C code on non-leaf
1782 windows. */
1783
1784 /* Do the equivalent of decode_window() but don't error out on
1785 deleted window; it's OK to delete an already-deleted window. */
1786 if (NILP (window))
1787 window = Fselected_window (Qnil);
1788 else
1789 CHECK_WINDOW (window);
1790 w = XWINDOW (window);
1791
1792 /* It's okay to delete an already-deleted window. */
1793 if (! WINDOW_LIVE_P (w))
1794 return Qnil;
1795
1796 frame = WINDOW_FRAME (w);
1797 f = XFRAME (frame);
1798 d = XDEVICE (FRAME_DEVICE (f));
1799
1800 if (TOP_LEVEL_WINDOW_P (w))
1801 {
1802 if (NILP (memq_no_quit (frame, DEVICE_FRAME_LIST (d))))
1803 /* this frame isn't fully initialized yet; don't blow up. */
1804 return Qnil;
1805
1806 if (MINI_WINDOW_P (XWINDOW (window)))
1807 error ("Attempt to delete the minibuffer window");
1808
1809 /* It has been suggested that it's a good thing for C-x 0 to have this
1810 behavior, but not such a good idea for #'delete-window to have it.
1811 Maybe C-x 0 should be bound to something else, or maybe frame
1812 deletion should only happen when this is called interactively.
1813 */
1814 delete_frame_internal (f, !NILP (force), 0, 0);
1815 return Qnil;
1816 }
1817
1818 /* At this point, we know the window has a parent. */
1819 parent = w->parent;
1820 par = XWINDOW (parent);
1821
1822 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
1823
1824 /* Are we trying to delete any frame's selected window?
1825 Note that we could be dealing with a non-leaf window
1826 where the selected window is one of our children.
1827 So, we check by scanning all the ancestors of the
1828 frame's selected window and comparing each one with
1829 WINDOW. */
1830 {
1831 Lisp_Object pwindow;
1832
1833 pwindow = FRAME_SELECTED_WINDOW (f);
1834
1835 while (!NILP (pwindow))
1836 {
1837 if (EQ (window, pwindow))
1838 break;
1839 pwindow = XWINDOW (pwindow)->parent;
1840 }
1841
1842 if (EQ (window, pwindow))
1843 {
1844 /* OK, we found it. */
1845 Lisp_Object alternative;
1846 alternative = Fnext_window (window, Qlambda, Qnil, Qnil);
1847
1848 /* If we're about to delete the selected window on the
1849 selected frame, then we should use Fselect_window to select
1850 the new window. On the other hand, if we're about to
1851 delete the selected window on any other frame, we shouldn't do
1852 anything but set the frame's selected_window slot. */
1853 if (EQ (frame, Fselected_frame (Qnil)))
1854 Fselect_window (alternative);
1855 else
1856 set_frame_selected_window (f, alternative);
1857 }
1858 }
1859
1860 /* w->buffer is nil in a non-leaf window; in this case,
1861 get rid of the markers we maintain that point into that buffer. */
1862 if (!NILP (w->buffer))
1863 {
1864 unshow_buffer (w);
1865 unchain_marker (w->pointm[CURRENT_DISP]);
1866 unchain_marker (w->pointm[DESIRED_DISP]);
1867 unchain_marker (w->pointm[CMOTION_DISP]);
1868 unchain_marker (w->start[CURRENT_DISP]);
1869 unchain_marker (w->start[DESIRED_DISP]);
1870 unchain_marker (w->start[CMOTION_DISP]);
1871 unchain_marker (w->sb_point);
1872 /* This breaks set-window-configuration if windows in the saved
1873 configuration get deleted and multiple frames are in use. */
1874 /* w->buffer = Qnil; */
1875 }
1876
1877 /* close up the hole in the sibling list */
1878 if (!NILP (w->next))
1879 XWINDOW (w->next)->prev = w->prev;
1880 if (!NILP (w->prev))
1881 XWINDOW (w->prev)->next = w->next;
1882 if (EQ (window, par->hchild))
1883 par->hchild = w->next;
1884 if (EQ (window, par->vchild))
1885 par->vchild = w->next;
1886
1887 /* Find one of our siblings to give our space to. */
1888 {
1889 Lisp_Object sib = w->prev;
1890 if (NILP (sib))
1891 {
1892 /* If w gives its space to its next sibling, that sibling needs
1893 to have its top/left side pulled back to where w's is.
1894 set_window_{height,width} will re-position the sibling's
1895 children. */
1896 sib = w->next;
1897 WINDOW_TOP (XWINDOW (sib)) = WINDOW_TOP (w);
1898 WINDOW_LEFT (XWINDOW (sib)) = WINDOW_LEFT (w);
1899 }
1900
1901 /* Stretch that sibling. */
1902 if (!NILP (par->vchild))
1903 set_window_pixheight
1904 (sib, (WINDOW_HEIGHT (XWINDOW (sib)) + WINDOW_HEIGHT (w)), 1);
1905 if (!NILP (par->hchild))
1906 set_window_pixwidth
1907 (sib, (WINDOW_WIDTH (XWINDOW (sib)) + WINDOW_WIDTH (w)), 1);
1908 }
1909
1910 /* If parent now has only one child,
1911 put the child into the parent's place. */
1912 {
1913 Lisp_Object parchild = par->hchild;
1914 if (NILP (parchild))
1915 parchild = par->vchild;
1916 if (NILP (XWINDOW (parchild)->next))
1917 {
1918 replace_window (parent, parchild);
1919 mark_window_as_deleted (XWINDOW (parent));
1920 }
1921 }
1922
1923 /* Since we may be deleting combination windows, we must make sure that
1924 not only W but all its children have been marked as deleted. */
1925 if (!NILP (w->hchild))
1926 delete_all_subwindows (XWINDOW (w->hchild));
1927 else if (!NILP (w->vchild))
1928 delete_all_subwindows (XWINDOW (w->vchild));
1929
1930 mark_window_as_deleted (w);
1931
1932 f->mirror_dirty = 1;
1933 return Qnil;
1934 }
1935
1936
1937 DEFUN ("next-window", Fnext_window, Snext_window, 0, 4, 0 /*
1938 Return next window after WINDOW in canonical ordering of windows.
1939 If omitted, WINDOW defaults to the selected window.
1940
1941 Optional second arg MINIBUF t means count the minibuffer window even
1942 if not active. MINIBUF nil or omitted means count the minibuffer iff
1943 it is active. MINIBUF neither t nor nil means not to count the
1944 minibuffer even if it is active.
1945
1946 Several frames may share a single minibuffer; if the minibuffer
1947 counts, all windows on all frames that share that minibuffer count
1948 too. Therefore, `next-window' can be used to iterate through the
1949 set of windows even when the minibuffer is on another frame. If the
1950 minibuffer does not count, only windows from WINDOW's frame count.
1951
1952 Optional third arg ALL-FRAMES t means include windows on all frames.
1953 ALL-FRAMES nil or omitted means cycle within the frames as specified
1954 above. ALL-FRAMES = `visible' means include windows on all visible frames.
1955 ALL-FRAMES = 0 means include windows on all visible and iconified frames.
1956 If ALL-FRAMES is a frame, restrict search to windows on that frame.
1957 Anything else means restrict to WINDOW's frame.
1958
1959 Optional fourth argument CONSOLE controls which consoles or devices the
1960 returned window may be on. If CONSOLE is a console, return windows only
1961 on that console. If CONSOLE is a device, return windows only on that
1962 device. If CONSOLE is a console type, return windows only on consoles
1963 of that type. If CONSOLE is 'window-system, return any windows on any
1964 window-system consoles. If CONSOLE is nil or omitted, return windows only
1965 on WINDOW's console. Otherwise, all windows are considered.
1966
1967 If you use consistent values for MINIBUF, ALL-FRAMES, and CONSOLE, you
1968 can use `next-window' to iterate through the entire cycle of acceptable
1969 windows, eventually ending up back at the window you started with.
1970 `previous-window' traverses the same cycle, in the reverse order.
1971 */ )
1972 (window, minibuf, all_frames, console)
1973 Lisp_Object window, minibuf, all_frames, console;
1974 {
1975 Lisp_Object tem;
1976 Lisp_Object start_window;
1977
1978 if (NILP (window))
1979 window = Fselected_window (Qnil);
1980 else
1981 CHECK_LIVE_WINDOW (window);
1982
1983 start_window = window;
1984
1985 /* minibuf == nil may or may not include minibuffers.
1986 Decide if it does. */
1987 if (NILP (minibuf))
1988 minibuf = (minibuf_level ? minibuf_window : Qlambda);
1989 else if (! EQ (minibuf, Qt))
1990 minibuf = Qlambda;
1991 /* Now minibuf can be t => count all minibuffer windows,
1992 lambda => count none of them,
1993 or a specific minibuffer window (the active one) to count. */
1994
1995 /* all_frames == nil doesn't specify which frames to include. */
1996 if (NILP (all_frames))
1997 all_frames = (! EQ (minibuf, Qlambda)
1998 ? (FRAME_MINIBUF_WINDOW
1999 (XFRAME
2000 (WINDOW_FRAME
2001 (XWINDOW (window)))))
2002 : Qnil);
2003 else if (EQ (all_frames, Qvisible))
2004 ;
2005 else if (ZEROP (all_frames))
2006 ;
2007 else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
2008 /* If all_frames is a frame and window arg isn't on that frame, just
2009 return the first window on the frame. */
2010 return frame_first_window (XFRAME (all_frames));
2011 else if (! EQ (all_frames, Qt))
2012 all_frames = Qnil;
2013 /* Now all_frames is t meaning search all frames,
2014 nil meaning search just current frame,
2015 visible meaning search just visible frames,
2016 0 meaning search visible and iconified frames,
2017 or a window, meaning search the frame that window belongs to. */
2018
2019 /* Do this loop at least once, to get the next window, and perhaps
2020 again, if we hit the minibuffer and that is not acceptable. */
2021 do
2022 {
2023 /* Find a window that actually has a next one. This loop
2024 climbs up the tree. */
2025 while (tem = XWINDOW (window)->next, NILP (tem))
2026 if (tem = XWINDOW (window)->parent, !NILP (tem))
2027 window = tem;
2028 else /* window must be minibuffer window now */
2029 {
2030 /* We've reached the end of this frame.
2031 Which other frames are acceptable? */
2032 tem = WINDOW_FRAME (XWINDOW (window));
2033
2034 if (! NILP (all_frames))
2035 {
2036 Lisp_Object tem1;
2037
2038 tem1 = tem;
2039 tem = next_frame (tem, all_frames, console);
2040 /* In the case where the minibuffer is active,
2041 and we include its frame as well as the selected one,
2042 next_frame may get stuck in that frame.
2043 If that happens, go back to the selected frame
2044 so we can complete the cycle. */
2045 if (EQ (tem, tem1))
2046 XSETFRAME (tem, selected_frame ());
2047 }
2048
2049 tem = FRAME_ROOT_WINDOW (XFRAME (tem));
2050 break;
2051 }
2052
2053 window = tem;
2054
2055 /* If we're in a combination window, find its first child and
2056 recurse on that. Otherwise, we've found the window we want. */
2057 while (1)
2058 {
2059 if (!NILP (XWINDOW (window)->hchild))
2060 window = XWINDOW (window)->hchild;
2061 else if (!NILP (XWINDOW (window)->vchild))
2062 window = XWINDOW (window)->vchild;
2063 else break;
2064 }
2065 }
2066 /* "acceptable" is the correct spelling. */
2067 /* Which windows are acceptable?
2068 Exit the loop and accept this window if
2069 this isn't a minibuffer window,
2070 or we're accepting all minibuffer windows,
2071 or this is the active minibuffer and we are accepting that one, or
2072 we've come all the way around and we're back at the original window. */
2073 while (MINI_WINDOW_P (XWINDOW (window))
2074 && ! EQ (minibuf, Qt)
2075 && ! EQ (minibuf, window)
2076 && ! EQ (window, start_window));
2077
2078 return window;
2079 }
2080
2081 DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 4, 0 /*
2082 Return the window preceeding WINDOW in canonical ordering of windows.
2083 If omitted, WINDOW defaults to the selected window.
2084
2085 Optional second arg MINIBUF t means count the minibuffer window even
2086 if not active. MINIBUF nil or omitted means count the minibuffer iff
2087 it is active. MINIBUF neither t nor nil means not to count the
2088 minibuffer even if it is active.
2089
2090 Several frames may share a single minibuffer; if the minibuffer
2091 counts, all windows on all frames that share that minibuffer count
2092 too. Therefore, `previous-window' can be used to iterate through
2093 the set of windows even when the minibuffer is on another frame. If
2094 the minibuffer does not count, only windows from WINDOW's frame count
2095
2096 If optional third arg ALL-FRAMES t means include windows on all frames.
2097 ALL-FRAMES nil or omitted means cycle within the frames as specified
2098 above. ALL-FRAMES = `visible' means include windows on all visible frames.
2099 ALL-FRAMES = 0 means include windows on all visible and iconified frames.
2100 If ALL-FRAMES is a frame, restrict search to windows on that frame.
2101 Anything else means restrict to WINDOW's frame.
2102
2103 Optional fourth argument CONSOLE controls which consoles or devices the
2104 returned window may be on. If CONSOLE is a console, return windows only
2105 on that console. If CONSOLE is a device, return windows only on that
2106 device. If CONSOLE is a console type, return windows only on consoles
2107 of that type. If CONSOLE is 'window-system, return any windows on any
2108 window-system consoles. If CONSOLE is nil or omitted, return windows only
2109 on WINDOW's console. Otherwise, all windows are considered.
2110
2111 If you use consistent values for MINIBUF, ALL-FRAMES, and CONSOLE, you
2112 can use `previous-window' to iterate through the entire cycle of acceptable
2113 windows, eventually ending up back at the window you started with.
2114 `next-window' traverses the same cycle, in the reverse order.
2115 */ )
2116 (window, minibuf, all_frames, console)
2117 Lisp_Object window, minibuf, all_frames, console;
2118 {
2119 Lisp_Object tem;
2120 Lisp_Object start_window;
2121
2122 if (NILP (window))
2123 window = Fselected_window (Qnil);
2124 else
2125 CHECK_LIVE_WINDOW (window);
2126
2127 start_window = window;
2128
2129 /* minibuf == nil may or may not include minibuffers.
2130 Decide if it does. */
2131 if (NILP (minibuf))
2132 minibuf = (minibuf_level ? minibuf_window : Qlambda);
2133 else if (! EQ (minibuf, Qt))
2134 minibuf = Qlambda;
2135 /* Now minibuf can be t => count all minibuffer windows,
2136 lambda => count none of them,
2137 or a specific minibuffer window (the active one) to count. */
2138
2139 /* all_frames == nil doesn't specify which frames to include.
2140 Decide which frames it includes. */
2141 if (NILP (all_frames))
2142 all_frames = (! EQ (minibuf, Qlambda)
2143 ? (FRAME_MINIBUF_WINDOW
2144 (XFRAME
2145 (WINDOW_FRAME
2146 (XWINDOW (window)))))
2147 : Qnil);
2148 else if (EQ (all_frames, Qvisible))
2149 ;
2150 else if (ZEROP (all_frames))
2151 ;
2152 else if (FRAMEP (all_frames) && ! EQ (all_frames, Fwindow_frame (window)))
2153 /* If all_frames is a frame and window arg isn't on that frame, just
2154 return the first window on the frame. */
2155 return frame_first_window (XFRAME (all_frames));
2156 else if (! EQ (all_frames, Qt))
2157 all_frames = Qnil;
2158 /* Now all_frames is t meaning search all frames,
2159 nil meaning search just current frame,
2160 visible meaning search just visible frames,
2161 0 meaning search visible and iconified frames,
2162 or a window, meaning search the frame that window belongs to. */
2163
2164 /* Do this loop at least once, to get the next window, and perhaps
2165 again, if we hit the minibuffer and that is not acceptable. */
2166 do
2167 {
2168 /* Find a window that actually has a next one. This loop
2169 climbs up the tree. */
2170 while (tem = XWINDOW (window)->prev, NILP (tem))
2171 if (tem = XWINDOW (window)->parent, !NILP (tem))
2172 window = tem;
2173 else /* window must be minibuffer window now */
2174 {
2175 /* We have found the top window on the frame.
2176 Which frames are acceptable? */
2177 tem = WINDOW_FRAME (XWINDOW (window));
2178
2179 if (! NILP (all_frames))
2180 /* It's actually important that we use prev_frame here,
2181 rather than next_frame. All the windows acceptable
2182 according to the given parameters should form a ring;
2183 Fnext_window and Fprevious_window should go back and
2184 forth around the ring. If we use next_frame here,
2185 then Fnext_window and Fprevious_window take different
2186 paths through the set of acceptable windows.
2187 window_loop assumes that these `ring' requirement are
2188 met. */
2189 {
2190 Lisp_Object tem1;
2191
2192 tem1 = tem;
2193 tem = prev_frame (tem, all_frames, console);
2194 /* In the case where the minibuffer is active,
2195 and we include its frame as well as the selected one,
2196 next_frame may get stuck in that frame.
2197 If that happens, go back to the selected frame
2198 so we can complete the cycle. */
2199 if (EQ (tem, tem1))
2200 XSETFRAME (tem, selected_frame ());
2201 }
2202
2203 /* If this frame has a minibuffer, find that window first,
2204 because it is conceptually the last window in that frame. */
2205 if (FRAME_HAS_MINIBUF_P (XFRAME (tem)))
2206 tem = FRAME_MINIBUF_WINDOW (XFRAME (tem));
2207 else
2208 tem = FRAME_ROOT_WINDOW (XFRAME (tem));
2209
2210 break;
2211 }
2212
2213 window = tem;
2214
2215 /* If we're in a combination window, find its first child and
2216 recurse on that. Otherwise, we've found the window we want. */
2217 while (1)
2218 {
2219 if (!NILP (XWINDOW (window)->hchild))
2220 window = XWINDOW (window)->hchild;
2221 else if (!NILP (XWINDOW (window)->vchild))
2222 window = XWINDOW (window)->vchild;
2223 else break;
2224 while (tem = XWINDOW (window)->next, !NILP (tem))
2225 window = tem;
2226 }
2227 }
2228 /* "acceptable" is the correct spelling. */
2229 /* Which windows are acceptable?
2230 Exit the loop and accept this window if
2231 this isn't a minibuffer window,
2232 or we're accepting all minibuffer windows,
2233 or this is the active minibuffer and we are accepting that one, or
2234 we've come all the way around and we're back at the original window. */
2235 while (MINI_WINDOW_P (XWINDOW (window))
2236 && ! EQ (minibuf, Qt)
2237 && ! EQ (minibuf, window)
2238 && ! EQ (window, start_window));
2239
2240 return window;
2241 }
2242
2243 DEFUN ("next-vertical-window", Fnext_vertical_window, Snext_vertical_window,
2244 0, 1, 0 /*
2245 Return the next window which is vertically after WINDOW.
2246 */ )
2247 (window)
2248 Lisp_Object window;
2249 {
2250 Lisp_Object root;
2251 struct window *w = decode_window (window);
2252 XSETWINDOW (window, w);
2253
2254 if (MINI_WINDOW_P (XWINDOW (window)))
2255 return Qnil;
2256
2257 root = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (XWINDOW (window))));
2258
2259 if (EQ (window, root))
2260 {
2261 while (1)
2262 if (!NILP (XWINDOW (window)->hchild))
2263 window = XWINDOW (window)->hchild;
2264 else if (!NILP (XWINDOW (window)->vchild))
2265 window = XWINDOW (window)->vchild;
2266 else
2267 return window;
2268 }
2269
2270 do
2271 {
2272 if (!NILP (XWINDOW (window)->parent) &&
2273 !NILP (XWINDOW (XWINDOW (window)->parent)->vchild))
2274 {
2275 if (!NILP (XWINDOW (window)->next))
2276 return XWINDOW (window)->next;
2277 else
2278 window = XWINDOW (window)->parent;
2279 }
2280 else
2281 window = XWINDOW (window)->parent;
2282 }
2283 while (!EQ (window, root));
2284
2285 while (1)
2286 if (!NILP (XWINDOW (window)->hchild))
2287 window = XWINDOW (window)->hchild;
2288 else if (!NILP (XWINDOW (window)->vchild))
2289 window = XWINDOW (window)->vchild;
2290 else
2291 return window;
2292 }
2293
2294 DEFUN ("other-window", Fother_window, Sother_window, 1, 3, "p" /*
2295 Select the N'th different window on this frame.
2296 All windows on current frame are arranged in a cyclic order.
2297 This command selects the window N steps away in that order.
2298 A negative N moves in the opposite order.
2299
2300 If optional argument FRAME is `visible', search all visible frames.
2301 If FRAME is 0, search all visible and iconified frames.
2302 If FRAME is t, search all frames.
2303 If FRAME is nil, search only the selected frame.
2304 If FRAME is a frame, search only that frame.
2305
2306 Optional third argument CONSOLE controls which consoles or devices the
2307 returned window may be on. If CONSOLE is a console, return windows only
2308 on that console. If CONSOLE is a device, return windows only on that
2309 device. If CONSOLE is a console type, return windows only on consoles
2310 of that type. If CONSOLE is 'window-system, return any windows on any
2311 window-system consoles. If CONSOLE is nil or omitted, return windows only
2312 on FRAME'S console, or on the selected console if FRAME is not a frame.
2313 Otherwise, all windows are considered.
2314 */ )
2315 (n, frame, console)
2316 Lisp_Object n, frame, console;
2317 {
2318 int i;
2319 Lisp_Object w;
2320
2321 CHECK_INT (n);
2322 w = Fselected_window (Qnil);
2323 i = XINT (n);
2324
2325 while (i > 0)
2326 {
2327 w = Fnext_window (w, Qnil, frame, console);
2328 i--;
2329 }
2330 while (i < 0)
2331 {
2332 w = Fprevious_window (w, Qnil, frame, console);
2333 i++;
2334 }
2335 Fselect_window (w);
2336 return Qnil;
2337 }
2338
2339
2340 /* Look at all windows, performing an operation specified by TYPE
2341 with argument OBJ.
2342
2343 If FRAMES is Qt, look at all frames, if Qnil, look at just the selected
2344 frame. If FRAMES is a frame, just look at windows on that frame.
2345 If MINI is non-zero, perform the operation on minibuffer windows too.
2346 */
2347
2348 enum window_loop
2349 {
2350 WINDOW_LOOP_UNUSED,
2351 GET_BUFFER_WINDOW, /* Arg is buffer */
2352 GET_LRU_WINDOW, /* Arg is t for full-width windows only */
2353 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */
2354 DELETE_BUFFER_WINDOWS, /* Arg is buffer */
2355 GET_LARGEST_WINDOW,
2356 UNSHOW_BUFFER, /* Arg is buffer */
2357 GET_BUFFER_WINDOW_COUNT, /* Arg is buffer */
2358 GET_BUFFER_MRU_WINDOW /* Arg is buffer */
2359 };
2360
2361 static Lisp_Object
2362 window_loop (enum window_loop type,
2363 Lisp_Object obj,
2364 int mini,
2365 Lisp_Object frames,
2366 int dedicated_too,
2367 Lisp_Object console)
2368 {
2369 /* This function can GC if type == DELETE_BUFFER_WINDOWS or UNSHOW_BUFFER */
2370 Lisp_Object w;
2371 Lisp_Object best_window = Qnil;
2372 Lisp_Object next_window;
2373 Lisp_Object last_window;
2374 struct frame *frame;
2375 Lisp_Object frame_arg = Qt;
2376 int count = 0; /* for GET_BUFFER_WINDOW_COUNT */
2377 /* #### I think the change of "precomputing" last_window and next_window
2378 * #### catch the lossage this is meant(?) to punt on...
2379 */
2380 int lose_lose = 0;
2381 Lisp_Object devcons, concons;
2382
2383 /* FRAME_ARG is Qlambda to stick to one frame,
2384 Qvisible to consider all visible frames,
2385 or Qt otherwise. */
2386
2387 /* If we're only looping through windows on a particular frame,
2388 FRAME points to that frame. If we're looping through windows
2389 on all frames, FRAME is 0. */
2390
2391 if (FRAMEP (frames))
2392 frame = XFRAME (frames);
2393 else if (NILP (frames))
2394 frame = selected_frame ();
2395 else
2396 frame = 0;
2397 if (frame)
2398 frame_arg = Qlambda;
2399 else if (ZEROP (frames))
2400 frame_arg = frames;
2401 else if (EQ (frames, Qvisible))
2402 frame_arg = frames;
2403
2404 DEVICE_LOOP_NO_BREAK (devcons, concons)
2405 {
2406 Lisp_Object device = XCAR (devcons);
2407 Lisp_Object the_frame = Qnil;
2408
2409 if (frame)
2410 XSETFRAME (the_frame, frame);
2411 else
2412 the_frame = DEVICE_SELECTED_FRAME (XDEVICE (device));
2413
2414 if (NILP (the_frame))
2415 continue;
2416
2417 if (!device_matches_console_spec (the_frame, device, console))
2418 continue;
2419
2420 /* Pick a window to start with. */
2421 if (WINDOWP (obj))
2422 w = obj;
2423 else
2424 w = FRAME_SELECTED_WINDOW (XFRAME (the_frame));
2425
2426 /* Figure out the last window we're going to mess with. Since
2427 Fnext_window, given the same options, is guaranteed to go in a
2428 ring, we can just use Fprevious_window to find the last one.
2429
2430 We can't just wait until we hit the first window again,
2431 because it might be deleted. */
2432
2433 last_window = Fprevious_window (w, mini ? Qt : Qnil, frame_arg, Qt);
2434
2435 best_window = Qnil;
2436 for (;;)
2437 {
2438 struct window *p = XWINDOW (w);
2439 struct frame *w_frame = XFRAME (WINDOW_FRAME (p));
2440
2441 /* Pick the next window now, since some operations will delete
2442 the current window. */
2443 next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg, Qt);
2444
2445 /* #### Still needed ?? */
2446 /* Given the outstanding quality of the rest of this code,
2447 I feel no shame about putting this piece of shit in. */
2448 if (++lose_lose >= 500)
2449 return Qnil;
2450
2451 /* Note that we do not pay attention here to whether
2452 the frame is visible, since Fnext_window skips non-visible frames
2453 if that is desired, under the control of frame_arg. */
2454 if (! MINI_WINDOW_P (p)
2455 || (mini && minibuf_level > 0))
2456 switch (type)
2457 {
2458 case GET_BUFFER_WINDOW:
2459 {
2460 if (XBUFFER (p->buffer) == XBUFFER (obj))
2461 return w;
2462 break;
2463 }
2464
2465 case GET_BUFFER_WINDOW_COUNT:
2466 {
2467 if (XBUFFER (p->buffer) == XBUFFER (obj))
2468 count++;
2469 break;
2470 }
2471
2472 case GET_LRU_WINDOW:
2473 {
2474 /* t as arg means consider only full-width windows */
2475 if (!NILP (obj)
2476 && !window_full_width_p (p))
2477 break;
2478 /* Ignore dedicated windows and minibuffers. */
2479 if (MINI_WINDOW_P (p)
2480 || (dedicated_too ? 0 : !NILP (p->dedicated)))
2481 break;
2482 if (NILP (best_window)
2483 || (XINT (XWINDOW (best_window)->use_time)
2484 > XINT (p->use_time)))
2485 best_window = w;
2486 break;
2487 }
2488
2489 case GET_BUFFER_MRU_WINDOW:
2490 {
2491 /* #### what about the first check in GET_LRU_WINDOW? */
2492 /* Ignore dedicated windows and minibuffers. */
2493 if (MINI_WINDOW_P (p)
2494 || (dedicated_too ? 0 : !NILP (p->dedicated)))
2495 break;
2496
2497 if (XBUFFER (p->buffer) == XBUFFER (obj))
2498 {
2499 if (NILP (best_window)
2500 || (XINT (XWINDOW (best_window)->use_time)
2501 < XINT (p->use_time)))
2502 best_window = w;
2503 }
2504 break;
2505 }
2506
2507 case DELETE_OTHER_WINDOWS:
2508 {
2509 /* Don't delete the last window on a frame; this can
2510 happen when the minibuffer is selected, and would
2511 cause the frame to be deleted. */
2512 if (p != XWINDOW (obj) && !TOP_LEVEL_WINDOW_P (XWINDOW (w)))
2513 Fdelete_window (w, Qnil);
2514 break;
2515 }
2516
2517 case DELETE_BUFFER_WINDOWS:
2518 {
2519 if (EQ (p->buffer, obj))
2520 {
2521 struct frame *f = XFRAME (WINDOW_FRAME (p));
2522
2523 /* If this window is dedicated, and in a frame
2524 of its own, kill the frame. */
2525 if (EQ (w, FRAME_ROOT_WINDOW (f))
2526 && !NILP (p->dedicated)
2527 && other_visible_frames (f))
2528 {
2529 /* Skip the other windows on this frame.
2530 There might be one, the minibuffer! */
2531 if (! EQ (w, last_window))
2532 while (f == XFRAME (WINDOW_FRAME
2533 (XWINDOW (next_window))))
2534 {
2535 /* As we go, check for the end of the
2536 loop. We mustn't start going
2537 around a second time. */
2538 if (EQ (next_window, last_window))
2539 {
2540 last_window = w;
2541 break;
2542 }
2543 next_window = Fnext_window (next_window,
2544 mini ? Qt : Qnil,
2545 frame_arg, Qt);
2546 }
2547 /* Now we can safely delete the frame. */
2548 Fdelete_frame (WINDOW_FRAME (p), Qnil);
2549 }
2550 else
2551 /* If we're deleting the buffer displayed in
2552 the only window on the frame, find a new
2553 buffer to display there. */
2554 if (NILP (p->parent))
2555 {
2556 Lisp_Object new_buffer;
2557 new_buffer = Fother_buffer (obj, Qnil, Qnil);
2558 if (NILP (new_buffer))
2559 new_buffer = Fget_buffer_create (QSscratch);
2560 Fset_window_buffer (w, new_buffer);
2561 if (EQ (w, Fselected_window (Qnil)))
2562 Fset_buffer (p->buffer);
2563 }
2564 else
2565 Fdelete_window (w, Qnil);
2566 }
2567 break;
2568 }
2569
2570 case GET_LARGEST_WINDOW:
2571 {
2572 /* Ignore dedicated windows and minibuffers. */
2573 if (MINI_WINDOW_P (p)
2574 || (dedicated_too ? 0 : !NILP (p->dedicated)))
2575 break;
2576 {
2577 /* write the check as follows to avoid tripping
2578 error_check_window() --ben */
2579 struct window *b = NILP (best_window) ? 0 :
2580 XWINDOW (best_window);
2581 if (NILP (best_window)
2582 || ((WINDOW_HEIGHT (p) * WINDOW_WIDTH (p))
2583 > (WINDOW_HEIGHT (b) * WINDOW_WIDTH (b))))
2584 best_window = w;
2585 }
2586 break;
2587 }
2588
2589 case UNSHOW_BUFFER:
2590 {
2591 if (EQ (p->buffer, obj))
2592 {
2593 /* Find another buffer to show in this window. */
2594 Lisp_Object another_buffer =
2595 Fother_buffer (obj, Qnil, Qnil);
2596 if (NILP (another_buffer))
2597 another_buffer
2598 = Fget_buffer_create (QSscratch);
2599 /* If this window is dedicated, and in a frame
2600 of its own, kill the frame. */
2601 if (EQ (w, FRAME_ROOT_WINDOW (w_frame))
2602 && !NILP (p->dedicated)
2603 && other_visible_frames (w_frame))
2604 {
2605 /* Skip the other windows on this frame.
2606 There might be one, the minibuffer! */
2607 if (! EQ (w, last_window))
2608 while (w_frame == XFRAME (WINDOW_FRAME
2609 (XWINDOW (next_window))))
2610 {
2611 /* As we go, check for the end of the
2612 loop. We mustn't start going
2613 around a second time. */
2614 if (EQ (next_window, last_window))
2615 {
2616 last_window = w;
2617 break;
2618 }
2619 next_window = Fnext_window (next_window,
2620 mini ? Qt : Qnil,
2621 frame_arg, Qt);
2622 }
2623 /* Now we can safely delete the frame. */
2624 delete_frame_internal (XFRAME (WINDOW_FRAME (p)),
2625 0, 0, 0);
2626 }
2627 else
2628 {
2629 /* Otherwise show a different buffer in the
2630 window. */
2631 p->dedicated = Qnil;
2632 Fset_window_buffer (w, another_buffer);
2633 if (EQ (w, Fselected_window (Qnil)))
2634 Fset_buffer (p->buffer);
2635 }
2636 }
2637 break;
2638 }
2639
2640 default:
2641 abort ();
2642 }
2643
2644 if (EQ (w, last_window))
2645 break;
2646
2647 w = next_window;
2648 }
2649 }
2650
2651 if (type == GET_BUFFER_WINDOW_COUNT)
2652 return (make_int (count));
2653 else
2654 return (best_window);
2655 }
2656
2657 #if 0 /* not currently used */
2658
2659 int
2660 buffer_window_count (struct buffer *b, struct frame *f)
2661 {
2662 Lisp_Object buffer, frame;
2663
2664 XSETFRAME (frame, f);
2665 XSETBUFFER (buffer, b);
2666
2667 return XINT (window_loop (GET_BUFFER_WINDOW_COUNT, buffer, 0, frame, 1,
2668 Qnil));
2669 }
2670
2671 int
2672 buffer_window_mru (struct window *w)
2673 {
2674 Lisp_Object window =
2675 window_loop (GET_BUFFER_MRU_WINDOW, w->buffer, 0, w->frame, 1, Qnil);
2676
2677 if (NILP (window))
2678 return 0;
2679 else if (XWINDOW (window) == w)
2680 return 1;
2681 else
2682 return 0;
2683 }
2684
2685 #endif
2686
2687
2688 DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 2, 0 /*
2689 Return the window least recently selected or used for display.
2690 If optional argument FRAME is `visible', search all visible frames.
2691 If FRAME is 0, search all visible and iconified frames.
2692 If FRAME is t, search all frames.
2693 If FRAME is nil, search only the selected frame.
2694 If FRAME is a frame, search only that frame.
2695
2696 Optional second argument CONSOLE controls which consoles or devices the
2697 returned window may be on. If CONSOLE is a console, return windows only
2698 on that console. If CONSOLE is a device, return windows only on that
2699 device. If CONSOLE is a console type, return windows only on consoles
2700 of that type. If CONSOLE is 'window-system, return any windows on any
2701 window-system consoles. If CONSOLE is nil or omitted, return windows only
2702 on FRAME'S console, or on the selected console if FRAME is not a frame.
2703 Otherwise, all windows are considered.
2704 */ )
2705 (frame, console)
2706 Lisp_Object frame, console;
2707 {
2708 Lisp_Object w;
2709 /* First try for a non-dedicated window that is full-width */
2710 w = window_loop (GET_LRU_WINDOW, Qt, 0, frame, 0, console);
2711 if (!NILP (w) && !EQ (w, Fselected_window (Qnil)))
2712 return w;
2713
2714 /* Then try for any non-dedicated window */
2715 w = window_loop (GET_LRU_WINDOW, Qnil, 0, frame, 0, console);
2716 if (!NILP (w) && !EQ (w, Fselected_window (Qnil)))
2717 return w;
2718
2719 #if 0
2720 /* FSFmacs never returns a dedicated window here. If we do,
2721 it makes `display-buffer' not work right. #### All of this
2722 shit is so disgusting and awful that it needs to be rethought
2723 from scratch. */
2724 /* then try for a dedicated window that is full-width */
2725 w = window_loop (GET_LRU_WINDOW, Qt, 0, frame, 1, console);
2726 if (!NILP (w) && !EQ (w, Fselected_window (Qnil)))
2727 return w;
2728
2729 /* If none of them, then all windows, dedicated or not. */
2730 w = window_loop (GET_LRU_WINDOW, Qnil, 0, frame, 1, console);
2731
2732 /* At this point we damn well better have found something. */
2733 if (NILP (w)) abort ();
2734 #endif
2735
2736 return (w);
2737 }
2738
2739 DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 2, 0 /*
2740 Return the window largest in area.
2741 If optional argument FRAME is `visible', search all visible frames.
2742 If FRAME is 0, search all visible and iconified frames.
2743 If FRAME is t, search all frames.
2744 If FRAME is nil, search only the selected frame.
2745 If FRAME is a frame, search only that frame.
2746
2747 Optional second argument CONSOLE controls which consoles or devices the
2748 returned window may be on. If CONSOLE is a console, return windows only
2749 on that console. If CONSOLE is a device, return windows only on that
2750 device. If CONSOLE is a console type, return windows only on consoles
2751 of that type. If CONSOLE is 'window-system, return any windows on any
2752 window-system consoles. If CONSOLE is nil or omitted, return windows only
2753 on FRAME'S console, or on the selected console if FRAME is not a frame.
2754 Otherwise, all windows are considered.
2755 */ )
2756 (frame, console)
2757 Lisp_Object frame, console;
2758 {
2759 /* Don't search dedicated windows because FSFmacs doesn't.
2760 This stuff is all black magic so don't try to apply common
2761 sense to it. */
2762 return window_loop (GET_LARGEST_WINDOW, Qnil, 0, frame, 0, console);
2763 }
2764
2765 DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 3, 0 /*
2766 Return a window currently displaying BUFFER, or nil if none.
2767 If optional argument FRAME is `visible', search all visible frames.
2768 If optional argument FRAME is 0, search all visible and iconified frames.
2769 If FRAME is t, search all frames.
2770 If FRAME is nil, search only the selected frame.
2771 If FRAME is a frame, search only that frame.
2772
2773 Optional third argument CONSOLE controls which consoles or devices the
2774 returned window may be on. If CONSOLE is a console, return windows only
2775 on that console. If CONSOLE is a device, return windows only on that
2776 device. If CONSOLE is a console type, return windows only on consoles
2777 of that type. If CONSOLE is 'window-system, return any windows on any
2778 window-system consoles. If CONSOLE is nil or omitted, return windows only
2779 on FRAME'S console, or on the selected console if FRAME is not a frame.
2780 Otherwise, all windows are considered.
2781 */ )
2782 (buffer, frame, console)
2783 Lisp_Object buffer, frame, console;
2784 {
2785 buffer = Fget_buffer (buffer);
2786 if (BUFFERP (buffer))
2787 /* Search dedicated windows too. (Doesn't matter here anyway.) */
2788 return window_loop (GET_BUFFER_WINDOW, buffer, 1, frame, 1, console);
2789 else
2790 return Qnil;
2791 }
2792
2793 /* These functions used to be `buffer-left-margin-pixel-width', etc.
2794 but there is no sensible way to implement those functions, since
2795 you can't in general derive a window from a buffer. */
2796
2797 DEFUN ("window-left-margin-pixel-width", Fwindow_left_margin_pixel_width,
2798 Swindow_left_margin_pixel_width, 0, 1, 0 /*
2799 Return the width in pixels of the left outside margin of window WINDOW.
2800 If WINDOW is nil, the selected window is assumed.
2801 */ )
2802 (window)
2803 Lisp_Object window;
2804 {
2805 struct window *w = decode_window (window);
2806
2807 return (make_int (window_left_margin_width (w)));
2808 }
2809
2810 DEFUN ("window-right-margin-pixel-width", Fwindow_right_margin_pixel_width,
2811 Swindow_right_margin_pixel_width, 0, 1, 0 /*
2812 Return the width in pixels of the right outside margin of window WINDOW.
2813 If WINDOW is nil, the selected window is assumed.
2814 */ )
2815 (window)
2816 Lisp_Object window;
2817 {
2818 struct window *w = decode_window (window);
2819
2820 return (make_int (window_right_margin_width (w)));
2821 }
2822
2823 DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows,
2824 0, 1, "" /*
2825 Make WINDOW (or the selected window) fill its frame.
2826 Only the frame WINDOW is on is affected.
2827 This function tries to reduce display jumps
2828 by keeping the text previously visible in WINDOW
2829 in the same place on the frame. Doing this depends on
2830 the value of (window-start WINDOW), so if calling this function
2831 in a program gives strange scrolling, make sure the window-start
2832 value is reasonable when this function is called.
2833 */ )
2834 (window)
2835 Lisp_Object window;
2836 {
2837 struct window *w = decode_window (window);
2838 struct buffer *b = XBUFFER (w->buffer);
2839 Bufpos start_pos;
2840 int old_top = WINDOW_TOP (w);
2841
2842 XSETWINDOW (window, w);
2843
2844 if (MINI_WINDOW_P (w) && old_top > 0)
2845 error ("Can't expand minibuffer to full frame");
2846
2847 /* Ignore dedicated windows. */
2848 window_loop (DELETE_OTHER_WINDOWS, window, 0, w->frame, 0, Qnil);
2849
2850 start_pos = marker_position (w->start[CURRENT_DISP]);
2851
2852 /* Try to minimize scrolling, by setting the window start to the
2853 point which will cause the text at the old window start to be at
2854 the same place on the frame. But don't try to do this if the
2855 window start is outside the visible portion (as might happen when
2856 the display is not current, due to typeahead). */
2857 if (start_pos >= BUF_BEGV (b) && start_pos <= BUF_ZV (b)
2858 && !MINI_WINDOW_P (w))
2859 {
2860 Bufpos new_start = start_with_line_at_pixpos (w, start_pos, old_top);
2861
2862 if (new_start >= BUF_BEGV (b) && new_start <= BUF_ZV (b))
2863 {
2864 Fset_marker (w->start[CURRENT_DISP], make_int (new_start),
2865 w->buffer);
2866 w->start_at_line_beg = beginning_of_line_p (b, new_start);
2867 }
2868 /* We need to do this, so that the window-scroll-functions
2869 get called. */
2870 w->force_start = 1;
2871 }
2872
2873 return Qnil;
2874 }
2875
2876 DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on,
2877 1, 3, "bDelete windows on (buffer): " /*
2878 Delete all windows showing BUFFER.
2879 Optional second argument FRAME controls which frames are affected.
2880 If nil or omitted, delete all windows showing BUFFER in any frame.
2881 If t, delete only windows showing BUFFER in the selected frame.
2882 If `visible', delete all windows showing BUFFER in any visible frame.
2883 If a frame, delete only windows showing BUFFER in that frame.
2884
2885 Optional third argument CONSOLE controls which consoles or devices the
2886 returned window may be on. If CONSOLE is a console, return windows only
2887 on that console. If CONSOLE is a device, return windows only on that
2888 device. If CONSOLE is a console type, return windows only on consoles
2889 of that type. If CONSOLE is 'window-system, return any windows on any
2890 window-system consoles. If CONSOLE is nil or omitted, return windows only
2891 on FRAME'S console, or on the selected console if FRAME is not a frame.
2892 Otherwise, all windows are considered.
2893 */ )
2894 (buffer, frame, console)
2895 Lisp_Object buffer, frame, console;
2896 {
2897 /* This function can GC */
2898 /* FRAME uses t and nil to mean the opposite of what window_loop
2899 expects. */
2900 if (!FRAMEP (frame))
2901 frame = NILP (frame) ? Qt : Qnil;
2902
2903 if (!NILP (buffer))
2904 {
2905 buffer = Fget_buffer (buffer);
2906 CHECK_BUFFER (buffer);
2907 /* Ignore dedicated windows. */
2908 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, frame, 0, console);
2909 }
2910 return Qnil;
2911 }
2912
2913 DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows,
2914 Sreplace_buffer_in_windows,
2915 1, 1, "bReplace buffer in windows: " /*
2916 Replace BUFFER with some other buffer in all windows showing it.
2917 */ )
2918 (buffer)
2919 Lisp_Object buffer;
2920 {
2921 /* This function can GC */
2922 if (!NILP (buffer))
2923 {
2924 buffer = Fget_buffer (buffer);
2925 CHECK_BUFFER (buffer);
2926 /* Ignore dedicated windows. */
2927 window_loop (UNSHOW_BUFFER, buffer, 0, Qt, 0, Qnil);
2928 }
2929 return Qnil;
2930 }
2931
2932 /* The smallest acceptable dimensions for a window. Anything smaller
2933 might crash Emacs. */
2934 #define MIN_SAFE_WINDOW_WIDTH (2)
2935 #define MIN_SAFE_WINDOW_HEIGHT (2)
2936
2937 /* Make sure that window_min_height and window_min_width are
2938 not too small; if they are, set them to safe minima. */
2939
2940 static void
2941 check_min_window_sizes (void)
2942 {
2943 /* Smaller values might permit a crash. */
2944 if (window_min_width < MIN_SAFE_WINDOW_WIDTH)
2945 window_min_width = MIN_SAFE_WINDOW_WIDTH;
2946 if (window_min_height < MIN_SAFE_WINDOW_HEIGHT)
2947 window_min_height = MIN_SAFE_WINDOW_HEIGHT;
2948 }
2949
2950 /* If *ROWS or *COLS are too small a size for FRAME, set them to the
2951 minimum allowable size. */
2952 void
2953 check_frame_size (struct frame *frame, int *rows, int *cols)
2954 {
2955 /* For height, we have to see whether the frame has a minibuffer, and
2956 whether it wants a modeline. */
2957 int min_height =
2958 (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1
2959 : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT
2960 : 2 * MIN_SAFE_WINDOW_HEIGHT - 1);
2961
2962 if (*rows < min_height)
2963 *rows = min_height;
2964 if (*cols < MIN_SAFE_WINDOW_WIDTH)
2965 *cols = MIN_SAFE_WINDOW_WIDTH;
2966 }
2967
2968 /* Normally the window is deleted if it gets too small.
2969 nodelete nonzero means do not do this.
2970 (The caller should check later and do so if appropriate) */
2971 static void
2972 set_window_pixsize (Lisp_Object window, int new_pixsize, int nodelete,
2973 int set_height)
2974 {
2975 struct window *w = XWINDOW (window);
2976 struct frame *f = XFRAME (w->frame);
2977 struct window *c;
2978 int old_pixsize = (set_height ? WINDOW_HEIGHT (w) : WINDOW_WIDTH (w));
2979 Lisp_Object child, minor_kid, major_kid;
2980 int minsize;
2981 int line_size;
2982 int defheight, defwidth;
2983
2984 /* #### This is very likely incorrect and instead the char_to_pixel_
2985 functions should be called. */
2986 default_face_height_and_width (window, &defheight, &defwidth);
2987 line_size = (set_height ? defheight : defwidth);
2988
2989 minsize = (set_height ? window_min_height : window_min_width);
2990 minsize *= line_size;
2991
2992 check_min_window_sizes ();
2993
2994 if (!nodelete
2995 && !TOP_LEVEL_WINDOW_P (w)
2996 && new_pixsize < minsize)
2997 {
2998 Fdelete_window (window, Qnil);
2999 return;
3000 }
3001
3002 SET_LAST_MODIFIED (w, 0);
3003 SET_LAST_FACECHANGE (w);
3004 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); /* multiple windows affected */
3005 if (set_height)
3006 {
3007 WINDOW_HEIGHT (w) = new_pixsize;
3008 major_kid = w->vchild;
3009 minor_kid = w->hchild;
3010 }
3011 else
3012 {
3013 WINDOW_WIDTH (w) = new_pixsize;
3014 major_kid = w->hchild;
3015 minor_kid = w->vchild;
3016 }
3017
3018 if (!NILP (minor_kid))
3019 {
3020 for (child = minor_kid; !NILP (child); child = XWINDOW (child)->next)
3021 {
3022 if (set_height)
3023 WINDOW_TOP (XWINDOW (child)) = WINDOW_TOP (w);
3024 else
3025 WINDOW_LEFT (XWINDOW (child)) = WINDOW_LEFT (w);
3026
3027 set_window_pixsize (child, new_pixsize, nodelete, set_height);
3028 }
3029 }
3030 else if (!NILP (major_kid))
3031 {
3032 int last_pos, last_old_pos, pos, old_pos, first;
3033 int pixel_adj_left = new_pixsize - old_pixsize;
3034 int div_val = old_pixsize << 1;
3035
3036 /* Sometimes we may get called with our old size. In that case
3037 we don't need to do anything. */
3038 if (!pixel_adj_left)
3039 return;
3040
3041 last_pos = first = (set_height ? WINDOW_TOP (w) : WINDOW_LEFT (w));
3042 last_old_pos = 0;
3043
3044 for (child = major_kid; !NILP (child); child = c->next)
3045 {
3046 c = XWINDOW (child);
3047
3048 if (set_height)
3049 {
3050 old_pos = last_old_pos + WINDOW_HEIGHT (c);
3051 WINDOW_TOP (c) = last_pos;
3052 }
3053 else
3054 {
3055 old_pos = last_old_pos + WINDOW_WIDTH (c);
3056 WINDOW_LEFT (c) = last_pos;
3057 }
3058
3059 pos = (((old_pos * new_pixsize) << 1) + old_pixsize) / div_val;
3060 /* All but the the last window should have a height which is
3061 a multiple of the default line height. */
3062 if (!NILP (c->next))
3063 pos = (pos / line_size) * line_size;
3064
3065 /* Avoid confusion: don't delete child if it becomes too small */
3066 set_window_pixsize (child, pos + first - last_pos, 1, set_height);
3067
3068 last_pos = pos + first;
3069 last_old_pos = old_pos;
3070 }
3071
3072 /* Now delete any children that became too small. */
3073 if (!nodelete)
3074 for (child = major_kid; !NILP (child); child = XWINDOW (child)->next)
3075 {
3076 if (set_height)
3077 set_window_pixheight (child, WINDOW_HEIGHT (XWINDOW (child)), 0);
3078 else
3079 set_window_pixwidth (child, WINDOW_WIDTH (XWINDOW (child)), 0);
3080 }
3081 }
3082 }
3083
3084 /* Set the height of WINDOW and all its inferiors. */
3085 void
3086 set_window_pixheight (Lisp_Object window, int new_pixheight, int nodelete)
3087 {
3088 set_window_pixsize (window, new_pixheight, nodelete, 1);
3089 }
3090
3091 /* Recursively set width of WINDOW and its inferiors. */
3092 void
3093 set_window_pixwidth (Lisp_Object window, int new_pixwidth, int nodelete)
3094 {
3095 set_window_pixsize (window, new_pixwidth, nodelete, 0);
3096 }
3097
3098
3099 static int window_select_count;
3100
3101 DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0 /*
3102 Make WINDOW display BUFFER as its contents.
3103 BUFFER can be a buffer or buffer name.
3104 */ )
3105 (window, buffer)
3106 Lisp_Object window, buffer;
3107 {
3108 Lisp_Object tem;
3109 struct window *w = decode_window (window);
3110
3111 buffer = Fget_buffer (buffer);
3112 CHECK_BUFFER (buffer);
3113
3114 if (!BUFFER_LIVE_P (XBUFFER (buffer)))
3115 error ("Attempt to display deleted buffer");
3116
3117 tem = w->buffer;
3118 if (NILP (tem))
3119 error ("Window is deleted");
3120
3121 /* While this seems like a logical thing to do, it causes problems
3122 because of saved window configurations. It is possible for a
3123 buffer to get restored into a window in which it is already being
3124 displayed, but start and point are actually at completely
3125 different locations. So we let this function complete fully and
3126 it will then make sure redisplay correctly updates things.
3127
3128 #### This is a kludge. The correct approach is not to do this
3129 but to fix set-window-configuration. */
3130 #if 0
3131 else if (EQ (tem, buffer))
3132 return (Qnil);
3133 #endif
3134 else if (! EQ (tem, Qt)) /* w->buffer is t when the window
3135 is first being set up. */
3136 {
3137 if (!NILP (w->dedicated) && !EQ (tem, buffer))
3138 error ("Window is dedicated to buffer %s",
3139 string_data (XSTRING (XBUFFER (tem)->name)));
3140
3141 unshow_buffer (w);
3142 }
3143
3144 w->buffer = buffer;
3145 w->window_end_pos[CURRENT_DISP] = 0;
3146 w->hscroll = 0;;
3147 Fset_marker (w->pointm[CURRENT_DISP],
3148 make_int (BUF_PT (XBUFFER (buffer))),
3149 buffer);
3150 set_marker_restricted (w->start[CURRENT_DISP],
3151 make_int (XBUFFER (buffer)->last_window_start),
3152 buffer);
3153 Fset_marker (w->sb_point, w->start[CURRENT_DISP], buffer);
3154 w->start_at_line_beg = 0;
3155 w->force_start = 0; /* Lucid fix */
3156 SET_LAST_MODIFIED (w, 1);
3157 SET_LAST_FACECHANGE (w);
3158 MARK_WINDOWS_CHANGED (w);
3159 recompute_all_cached_specifiers_in_window (w);
3160 if (EQ (window, Fselected_window (Qnil)))
3161 {
3162 Fset_buffer (buffer);
3163 #ifdef ENERGIZE
3164 energize_buffer_shown_hook (w);
3165 #endif
3166 }
3167 return Qnil;
3168 }
3169
3170 DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0 /*
3171 Select WINDOW. Most editing will apply to WINDOW's buffer.
3172 The main editor command loop selects the buffer of the selected window
3173 before each command.
3174 */ )
3175 (window)
3176 Lisp_Object window;
3177 {
3178 struct window *w;
3179 Lisp_Object old_selected_window = Fselected_window (Qnil);
3180
3181 CHECK_LIVE_WINDOW (window);
3182 w = XWINDOW (window);
3183
3184 /* we have already caught dead-window errors */
3185 if (!NILP (w->hchild) || !NILP (w->vchild))
3186 error ("Trying to select non-leaf window");
3187
3188 w->use_time = make_int (++window_select_count);
3189 if (EQ (window, old_selected_window))
3190 return window;
3191
3192 /* deselect the old window, if it exists (it might not exist if
3193 the selected device has no frames, which occurs at startup) */
3194 if (!NILP (old_selected_window))
3195 {
3196 struct window *ow = XWINDOW (old_selected_window);
3197
3198 #ifdef ENERGIZE
3199 if (! MINI_WINDOW_P (w))
3200 energize_window_deselected_hook (ow);
3201 #endif
3202
3203 Fset_marker (ow->pointm[CURRENT_DISP],
3204 make_int (BUF_PT (XBUFFER (ow->buffer))),
3205 ow->buffer);
3206
3207 MARK_WINDOWS_CHANGED (ow);
3208 }
3209
3210 /* now select the window's frame */
3211 set_frame_selected_window (XFRAME (WINDOW_FRAME (w)), window);
3212
3213 select_frame_1 (WINDOW_FRAME (w));
3214
3215 /* also select the window's buffer */
3216 Frecord_buffer (w->buffer);
3217 Fset_buffer (w->buffer);
3218
3219 /* Go to the point recorded in the window.
3220 This is important when the buffer is in more
3221 than one window. It also matters when
3222 redisplay_window has altered point after scrolling,
3223 because it makes the change only in the window. */
3224 {
3225 Bufpos new_point = marker_position (w->pointm[CURRENT_DISP]);
3226 if (new_point < BUF_BEGV (current_buffer))
3227 new_point = BUF_BEGV (current_buffer);
3228 else if (new_point > BUF_ZV (current_buffer))
3229 new_point = BUF_ZV (current_buffer);
3230
3231 BUF_SET_PT (current_buffer, new_point);
3232 }
3233
3234 MARK_WINDOWS_CHANGED (w);
3235
3236 #ifdef ENERGIZE
3237 if (! MINI_WINDOW_P (w))
3238 energize_window_selected_hook (w);
3239 #endif
3240
3241 return window;
3242 }
3243
3244 Lisp_Object
3245 display_buffer (Lisp_Object buffer, Lisp_Object not_this_window_p,
3246 Lisp_Object override_frame)
3247 {
3248 return call3 (Qdisplay_buffer, buffer, not_this_window_p, override_frame);
3249 }
3250
3251 void
3252 temp_output_buffer_show (Lisp_Object buf, Lisp_Object same_frame)
3253 {
3254 /* This function can GC */
3255 Lisp_Object window;
3256 struct window *w;
3257 struct buffer *b = XBUFFER (buf);
3258
3259 BUF_SAVE_MODIFF (XBUFFER (buf)) = BUF_MODIFF (b);
3260 widen_buffer (b, 0);
3261 BUF_SET_PT (b, BUF_BEG (b));
3262
3263 if (!EQ (Vtemp_buffer_show_function, Qnil))
3264 call1 (Vtemp_buffer_show_function, buf);
3265 else
3266 {
3267 window = display_buffer (buf, Qnil, same_frame);
3268
3269 if (!EQ (XWINDOW (window)->frame, Fselected_frame (Qnil)))
3270 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window)));
3271
3272 Vminibuf_scroll_window = window;
3273 w = XWINDOW (window);
3274 w->hscroll = 0;
3275 set_marker_restricted (w->start[CURRENT_DISP], make_int (1), buf);
3276 set_marker_restricted (w->pointm[CURRENT_DISP], make_int (1), buf);
3277 set_marker_restricted (w->sb_point, make_int (1), buf);
3278
3279 /* Run temp-buffer-show-hook, with the chosen window selected. */
3280 if (!preparing_for_armageddon)
3281 {
3282 Lisp_Object tem;
3283 tem = Fboundp (Qtemp_buffer_show_hook);
3284 if (!NILP (tem))
3285 {
3286 tem = Fsymbol_value (Qtemp_buffer_show_hook);
3287 if (!NILP (tem))
3288 {
3289 int count = specpdl_depth ();
3290
3291 /* Select the window that was chosen, for running
3292 the hook. */
3293 record_unwind_protect (save_window_excursion_unwind,
3294 Fcurrent_window_configuration (Qnil));
3295
3296 Fselect_window (window);
3297 run_hook (Qtemp_buffer_show_hook);
3298 unbind_to (count, Qnil);
3299 }
3300 }
3301 }
3302 }
3303 }
3304
3305 static void
3306 make_dummy_parent (Lisp_Object window)
3307 {
3308 Lisp_Object new = Qnil;
3309 struct window *o = XWINDOW (window);
3310 struct window *p = alloc_lcrecord (sizeof (struct window),
3311 lrecord_window);
3312
3313 XSETWINDOW (new, p);
3314 copy_lcrecord (p, o);
3315
3316 /* Don't copy the pointers to the line start cache or the face
3317 instances. */
3318 p->line_start_cache = Dynarr_new (struct line_start_cache);
3319 p->face_cachels = Dynarr_new (struct face_cachel);
3320 p->glyph_cachels = Dynarr_new (struct glyph_cachel);
3321
3322 /* Put new into window structure in place of window */
3323 replace_window (window, new);
3324
3325 o->next = Qnil;
3326 o->prev = Qnil;
3327 o->vchild = Qnil;
3328 o->hchild = Qnil;
3329 o->parent = new;
3330
3331 p->start[CURRENT_DISP] = Qnil;
3332 p->start[DESIRED_DISP] = Qnil;
3333 p->start[CMOTION_DISP] = Qnil;
3334 p->pointm[CURRENT_DISP] = Qnil;
3335 p->pointm[DESIRED_DISP] = Qnil;
3336 p->pointm[CMOTION_DISP] = Qnil;
3337 p->sb_point = Qnil;
3338 p->buffer = Qnil;
3339 }
3340
3341 DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "" /*
3342 Split WINDOW, putting SIZE lines in the first of the pair.
3343 WINDOW defaults to selected one and SIZE to half its size.
3344 If optional third arg HOR-FLAG is non-nil, split side by side
3345 and put SIZE columns in the first of the pair.
3346 */ )
3347 (window, chsize, horflag)
3348 Lisp_Object window, chsize, horflag;
3349 {
3350 Lisp_Object new;
3351 struct window *o, *p;
3352 struct frame *f;
3353 int size;
3354 int psize;
3355
3356 if (NILP (window))
3357 window = Fselected_window (Qnil);
3358 else
3359 CHECK_WINDOW (window);
3360
3361 o = XWINDOW (window);
3362 f = XFRAME (WINDOW_FRAME (o));
3363
3364 if (NILP (chsize))
3365 {
3366 if (!NILP (horflag))
3367 /* In the new scheme, we are symmetric with respect to separators
3368 so there is no need to do weird things here. */
3369 {
3370 psize = WINDOW_WIDTH (o) >> 1;
3371 size = window_pixel_width_to_char_width (o, psize, 0);
3372 }
3373 else
3374 {
3375 psize = WINDOW_HEIGHT (o) >> 1;
3376 size = window_pixel_height_to_char_height (o, psize, 1);
3377 }
3378 }
3379 else
3380 {
3381 CHECK_INT (chsize);
3382 size = XINT (chsize);
3383 if (!NILP (horflag))
3384 psize = window_char_width_to_pixel_width (o, size, 0);
3385 else
3386 psize = window_char_height_to_pixel_height (o, size, 1);
3387 }
3388
3389 if (MINI_WINDOW_P (o))
3390 error ("Attempt to split minibuffer window");
3391 else if (FRAME_NO_SPLIT_P (XFRAME (WINDOW_FRAME (o))))
3392 error ("Attempt to split unsplittable frame");
3393
3394 check_min_window_sizes ();
3395
3396 if (NILP (horflag))
3397 {
3398 if (size < window_min_height)
3399 error ("Window height %d too small (after splitting)", size);
3400 if (size + window_min_height > window_char_height (o, 1))
3401 error ("Window height %d too small (after splitting)",
3402 window_char_height (o, 1) - size);
3403 if (NILP (o->parent)
3404 || NILP (XWINDOW (o->parent)->vchild))
3405 {
3406 make_dummy_parent (window);
3407 reset_face_cachels (XWINDOW (window));
3408 new = o->parent;
3409 XWINDOW (new)->vchild = window;
3410 XFRAME (o->frame)->mirror_dirty = 1;
3411 }
3412 }
3413 else
3414 {
3415 if (size < window_min_width)
3416 error ("Window width %d too small (after splitting)", size);
3417 if (size + window_min_width > window_char_width (o, 0))
3418 error ("Window width %d too small (after splitting)",
3419 window_char_width (o, 0) - size);
3420 if (NILP (o->parent)
3421 || NILP (XWINDOW (o->parent)->hchild))
3422 {
3423 make_dummy_parent (window);
3424 reset_face_cachels (XWINDOW (window));
3425 new = o->parent;
3426 XWINDOW (new)->hchild = window;
3427 XFRAME (o->frame)->mirror_dirty = 1;
3428 }
3429 }
3430
3431 /* Now we know that window's parent is a vertical combination
3432 if we are dividing vertically, or a horizontal combination
3433 if we are making side-by-side windows */
3434
3435 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
3436 new = allocate_window ();
3437 p = XWINDOW (new);
3438
3439 p->frame = o->frame;
3440 p->next = o->next;
3441 if (!NILP (p->next))
3442 XWINDOW (p->next)->prev = new;
3443 p->prev = window;
3444 o->next = new;
3445 p->parent = o->parent;
3446 p->buffer = Qt;
3447
3448 reset_face_cachels (p);
3449 reset_glyph_cachels (p);
3450
3451
3452 /* Apportion the available frame space among the two new windows */
3453
3454 if (!NILP (horflag))
3455 {
3456 WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o);
3457 WINDOW_TOP (p) = WINDOW_TOP (o);
3458 WINDOW_WIDTH (p) = WINDOW_WIDTH (o) - psize;
3459 WINDOW_WIDTH (o) = psize;
3460 WINDOW_LEFT (p) = WINDOW_LEFT (o) + psize;
3461 }
3462 else
3463 {
3464 WINDOW_LEFT (p) = WINDOW_LEFT (o);
3465 WINDOW_WIDTH (p) = WINDOW_WIDTH (o);
3466 WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o) - psize;
3467 WINDOW_HEIGHT (o) = psize;
3468 WINDOW_TOP (p) = WINDOW_TOP (o) + psize;
3469 }
3470
3471 XFRAME (p->frame)->mirror_dirty = 1;
3472 /* do this last (after the window is completely initialized and
3473 the mirror-dirty flag is set) so that specifier recomputation
3474 caused as a result of this will work properly and not abort. */
3475 Fset_window_buffer (new, o->buffer);
3476 return new;
3477 }
3478
3479
3480 DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 3, "_p" /*
3481 Make the selected window ARG lines bigger.
3482 From program, optional second arg non-nil means grow sideways ARG columns,
3483 and optional third ARG specifies the window to change instead of the
3484 selected window.
3485 */ )
3486 (n, side, window)
3487 Lisp_Object n, side, window;
3488 {
3489 struct window *w = decode_window (window);
3490 CHECK_INT (n);
3491 change_window_height (w, XINT (n), !NILP (side));
3492 return Qnil;
3493 }
3494
3495 DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 3, "_p" /*
3496 Make the selected window ARG lines smaller.
3497 From program, optional second arg non-nil means shrink sideways ARG columns,
3498 and optional third ARG specifies the window to change instead of the
3499 selected window.
3500 */ )
3501 (n, side, window)
3502 Lisp_Object n, side, window;
3503 {
3504 struct window *w = decode_window (window);
3505 CHECK_INT (n);
3506 change_window_height (w, -XINT (n), !NILP (side));
3507 return Qnil;
3508 }
3509
3510 static int
3511 window_pixel_height (Lisp_Object window)
3512 {
3513 struct window *w = XWINDOW (window);
3514 return WINDOW_HEIGHT (w);
3515 }
3516
3517 static int
3518 window_pixel_height_to_char_height (struct window *w, int pixel_height,
3519 int include_gutters_p)
3520 {
3521 int avail_height;
3522 int defheight, defwidth;
3523 int char_height;
3524 Lisp_Object window;
3525
3526 XSETWINDOW (window, w);
3527
3528 avail_height = (pixel_height -
3529 (include_gutters_p ? 0 :
3530 window_top_gutter_height (w) +
3531 window_bottom_gutter_height (w)));
3532
3533 default_face_height_and_width (window, &defheight, &defwidth);
3534
3535 char_height = avail_height / defheight;
3536
3537 /* It's the calling function's responsibility to check these values
3538 and make sure they're not out of range.
3539
3540 #### We need to go through the calling functions and actually
3541 do this. */
3542 if (char_height < 0)
3543 return 0;
3544 else
3545 return char_height;
3546 }
3547
3548 static int
3549 window_char_height_to_pixel_height (struct window *w, int char_height,
3550 int include_gutters_p)
3551 {
3552 int avail_height;
3553 int defheight, defwidth;
3554 int pixel_height;
3555
3556 Lisp_Object window;
3557
3558 XSETWINDOW (window, w);
3559
3560 default_face_height_and_width (window, &defheight, &defwidth);
3561
3562 avail_height = char_height * defheight;
3563 pixel_height = (avail_height +
3564 (include_gutters_p ? 0 :
3565 window_top_gutter_height (w) +
3566 window_bottom_gutter_height (w)));
3567
3568 /* It's the calling function's responsibility to check these values
3569 and make sure they're not out of range.
3570
3571 #### We need to go through the calling functions and actually
3572 do this. */
3573 if (pixel_height < 0)
3574 return 0;
3575 else
3576 return pixel_height;
3577 }
3578
3579 /* Return number of default lines of text can fit in the window W.
3580 If INCLUDE_GUTTERS_P is 1, include "gutter" space (modeline plus
3581 horizontal scrollbar) in the space that is used for the calculation.
3582 */
3583 int
3584 window_char_height (struct window *w, int include_gutters_p)
3585 {
3586 return window_pixel_height_to_char_height (w, WINDOW_HEIGHT (w),
3587 include_gutters_p);
3588 }
3589
3590 /*
3591 * Return number of lines currently displayed in window w. If
3592 * end-of-buffer is displayed then the area below end-of-buffer is assume
3593 * to be blank lines of default height.
3594 * Does not include the modeline.
3595 */
3596 int
3597 window_displayed_height (struct window *w)
3598 {
3599 struct buffer *b = XBUFFER (w->buffer);
3600 display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
3601 int num_lines;
3602 Charcount end_pos = (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b)
3603 ? -1
3604 : w->window_end_pos[CURRENT_DISP]);
3605
3606 if (!Dynarr_length (dla))
3607 return window_char_height (w, 0);
3608
3609 num_lines = Dynarr_length (dla);
3610
3611 /* #### Document and assert somewhere that w->window_end_pos == -1
3612 indicates that end-of-buffer is being displayed. */
3613 if (end_pos == -1)
3614 {
3615 struct display_line *dl = Dynarr_atp (dla, 0);
3616 int ypos1 = dl->ypos + dl->descent;
3617 int ypos2 = WINDOW_TEXT_BOTTOM (w);
3618 Lisp_Object window;
3619 int defheight, defwidth;
3620
3621 XSETWINDOW (window, w);
3622
3623 if (dl->modeline)
3624 {
3625 num_lines--;
3626
3627 if (Dynarr_length (dla) == 1)
3628 ypos1 = WINDOW_TEXT_TOP (w);
3629 else
3630 {
3631 dl = Dynarr_atp (dla, Dynarr_length (dla) - 1);
3632 /* If this line is clipped then we know that there is no
3633 blank room between eob and the modeline. If we are
3634 scrolling on clipped lines just know off the clipped
3635 line and return .*/
3636 if (scroll_on_clipped_lines && dl->clip)
3637 return (num_lines - 1);
3638 ypos1 = dl->ypos + dl->descent - dl->clip;
3639 }
3640 }
3641
3642 default_face_height_and_width (window, &defheight, &defwidth);
3643 /* #### This probably needs to know about the clipping area once a
3644 final definition is decided on. */
3645 num_lines += ((ypos2 - ypos1) / defheight);
3646 }
3647 else
3648 {
3649 if (num_lines > 1 && Dynarr_atp (dla, 0)->modeline)
3650 num_lines--;
3651
3652 if (scroll_on_clipped_lines
3653 && Dynarr_atp (dla, Dynarr_length (dla) - 1)->clip)
3654 num_lines--;
3655 }
3656
3657 return num_lines;
3658 }
3659
3660 static int
3661 window_pixel_width (Lisp_Object window)
3662 {
3663 struct window *w = XWINDOW (window);
3664 return WINDOW_WIDTH (w);
3665 }
3666
3667 static int
3668 window_pixel_width_to_char_width (struct window *w, int pixel_width,
3669 int include_margins_p)
3670 {
3671 int avail_width;
3672 int char_width;
3673 int defheight, defwidth;
3674 Lisp_Object window;
3675
3676 XSETWINDOW (window, w);
3677
3678 avail_width = (pixel_width -
3679 window_left_gutter_width (w, 0) -
3680 window_right_gutter_width (w, 0) -
3681 (include_margins_p ? 0 : window_left_margin_width (w)) -
3682 (include_margins_p ? 0 : window_right_margin_width (w)));
3683
3684 default_face_height_and_width (window, &defheight, &defwidth);
3685
3686 char_width = (avail_width / defwidth);
3687
3688 /* It's the calling function's responsibility to check these values
3689 and make sure they're not out of range.
3690
3691 #### We need to go through the calling functions and actually
3692 do this. */
3693 if (char_width < 0)
3694 return 0;
3695 else
3696 return char_width;
3697 }
3698
3699 static int
3700 window_char_width_to_pixel_width (struct window *w, int char_width,
3701 int include_margins_p)
3702 {
3703 int avail_width;
3704 int pixel_width;
3705 int defheight, defwidth;
3706 Lisp_Object window;
3707
3708 XSETWINDOW (window, w);
3709
3710 default_face_height_and_width (window, &defheight, &defwidth);
3711
3712 avail_width = char_width * defwidth;
3713 pixel_width = (avail_width +
3714 window_left_gutter_width (w, 0) +
3715 window_right_gutter_width (w, 0) +
3716 (include_margins_p ? 0 : window_left_margin_width (w)) +
3717 (include_margins_p ? 0 : window_right_margin_width (w)));
3718
3719 /* It's the calling function's responsibility to check these values
3720 and make sure they're not out of range.
3721
3722 #### We need to go through the calling functions and actually
3723 do this. */
3724 if (pixel_width < 0)
3725 return 0;
3726 else
3727 return pixel_width;
3728 }
3729
3730 /* This returns the usable space which doesn't include space needed by
3731 scrollbars or divider lines. */
3732 int
3733 window_char_width (struct window *w, int include_margins_p)
3734 {
3735 return window_pixel_width_to_char_width (w, WINDOW_WIDTH (w),
3736 include_margins_p);
3737 }
3738
3739 #define MINSIZE(w) \
3740 (widthflag \
3741 ? window_min_width * defwidth \
3742 : (defheight * (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height)))
3743
3744 #define CURBEG(w) \
3745 *(widthflag ? (int *) &WINDOW_LEFT (w) : (int *) &WINDOW_TOP (w))
3746
3747 #define CURSIZE(w) \
3748 *(widthflag ? (int *) &WINDOW_WIDTH (w) : (int *) &WINDOW_HEIGHT (w))
3749
3750 #define CURCHARSIZE(w) \
3751 (widthflag ? window_char_width (w, 0) : window_char_height (w, 1))
3752
3753 #define MINCHARSIZE(window) \
3754 (widthflag ? window_min_width : MINI_WINDOW_P (XWINDOW (window)) \
3755 ? 1 : window_min_height)
3756
3757 /* Unlike set_window_pixheight, this function
3758 also changes the heights of the siblings so as to
3759 keep everything consistent. */
3760
3761 static void
3762 change_window_height (struct window *win, int delta, int widthflag)
3763 {
3764 Lisp_Object parent;
3765 Lisp_Object window = Qnil;
3766 struct window *w;
3767 struct frame *f;
3768 int *sizep;
3769 int (*sizefun) (Lisp_Object) = (widthflag
3770 ? window_pixel_width
3771 : window_pixel_height);
3772 void (*setsizefun) (Lisp_Object, int, int) = (widthflag
3773 ? set_window_pixwidth
3774 : set_window_pixheight);
3775 int dim;
3776 int defheight, defwidth;
3777
3778 if (delta == 0)
3779 return;
3780
3781 check_min_window_sizes ();
3782
3783 XSETWINDOW (window, win);
3784 f = XFRAME (win->frame);
3785 if (EQ (window, FRAME_ROOT_WINDOW (f)))
3786 error ("Won't change only window");
3787
3788 /* #### This is very likely incorrect and instead the char_to_pixel_
3789 functions should be called. */
3790 default_face_height_and_width (window, &defheight, &defwidth);
3791
3792 while (1)
3793 {
3794 w = XWINDOW (window);
3795 parent = w->parent;
3796 if (NILP (parent))
3797 {
3798 if (widthflag)
3799 error ("No other window to side of this one");
3800 break;
3801 }
3802 if (widthflag
3803 ? !NILP (XWINDOW (parent)->hchild)
3804 : !NILP (XWINDOW (parent)->vchild))
3805 break;
3806 window = parent;
3807 }
3808
3809 sizep = &CURSIZE (w);
3810 dim = CURCHARSIZE (w);
3811
3812 if ((dim + delta) < MINCHARSIZE (window))
3813 {
3814 if (MINI_WINDOW_P (XWINDOW (window)))
3815 return;
3816 else if (!NILP (parent))
3817 {
3818 Fdelete_window (window, Qnil);
3819 return;
3820 }
3821 }
3822
3823 delta *= (widthflag ? defwidth : defheight);
3824
3825 {
3826 int maxdelta;
3827
3828 maxdelta = ((!NILP (parent))
3829 ? (*sizefun) (parent) - *sizep
3830 : ((!NILP (w->next))
3831 ? (*sizefun) (w->next) - MINSIZE (w->next)
3832 : ((!NILP (w->prev))
3833 ? (*sizefun) (w->prev) - MINSIZE (w->prev)
3834 /* This is a frame with only one window,
3835 a minibuffer-only or a minibufferless frame. */
3836 : (delta = 0))));
3837
3838 if (delta > maxdelta)
3839 /* This case traps trying to make the minibuffer
3840 the full frame, or make the only window aside from the
3841 minibuffer the full frame. */
3842 delta = maxdelta;
3843
3844 if (delta == 0)
3845 return;
3846
3847 #if 0 /* FSFmacs */
3848 /* #### Chuck: is this correct? */
3849 if (*sizep + delta < MINSIZE (window))
3850 {
3851 Fdelete_window (window);
3852 return;
3853 }
3854 #endif
3855 }
3856
3857 if (!NILP (w->next) &&
3858 (*sizefun) (w->next) - delta >= (int) MINSIZE (w->next))
3859 {
3860 CURBEG (XWINDOW (w->next)) += delta;
3861 (*setsizefun) (w->next, (*sizefun) (w->next) - delta, 0);
3862 (*setsizefun) (window, *sizep + delta, 0);
3863 }
3864 else if (!NILP (w->prev) &&
3865 (*sizefun) (w->prev) - delta >= (int) MINSIZE (w->prev))
3866 {
3867 (*setsizefun) (w->prev, (*sizefun) (w->prev) - delta, 0);
3868 CURBEG (w) -= delta;
3869 (*setsizefun) (window, *sizep + delta, 0);
3870 }
3871 else
3872 {
3873 int delta1;
3874 int opht = (*sizefun) (parent);
3875
3876 /* If trying to grow this window to or beyond size of the parent,
3877 make delta1 so big that, on shrinking back down,
3878 all the siblings end up with less than one line and are deleted. */
3879 if (opht <= *sizep + delta)
3880 delta1 = opht * opht * 2;
3881 /* Otherwise, make delta1 just right so that if we add delta1
3882 lines to this window and to the parent, and then shrink
3883 the parent back to its original size, the new proportional
3884 size of this window will increase by delta. */
3885 else
3886 delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100);
3887
3888 /* Add delta1 lines or columns to this window, and to the parent,
3889 keeping things consistent while not affecting siblings. */
3890 CURSIZE (XWINDOW (parent)) = opht + delta1;
3891 (*setsizefun) (window, *sizep + delta1, 0);
3892
3893 /* Squeeze out delta1 lines or columns from our parent,
3894 shriking this window and siblings proportionately.
3895 This brings parent back to correct size.
3896 Delta1 was calculated so this makes this window the desired size,
3897 taking it all out of the siblings. */
3898 (*setsizefun) (parent, opht, 0);
3899 }
3900
3901 SET_LAST_MODIFIED (w, 0);
3902 SET_LAST_FACECHANGE (w);
3903 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
3904 }
3905 #undef MINSIZE
3906 #undef CURBEG
3907 #undef CURSIZE
3908 #undef CURCHARSIZE
3909 #undef MINCHARSIZE
3910
3911
3912
3913 /* Scroll contents of window WINDOW up N lines. */
3914 void
3915 window_scroll (Lisp_Object window, Lisp_Object n, int direction,
3916 Error_behavior errb)
3917 {
3918 struct window *w = XWINDOW (window);
3919 struct buffer *b = XBUFFER (w->buffer);
3920 int selected = EQ (window, Fselected_window (Qnil));
3921 int value = 0;
3922 Lisp_Object point, tem;
3923
3924 if (selected)
3925 point = make_int (BUF_PT (b));
3926 else
3927 {
3928 Bufpos pos = marker_position (w->pointm[CURRENT_DISP]);
3929
3930 if (pos < BUF_BEGV (b))
3931 pos = BUF_BEGV (b);
3932 else if (pos > BUF_ZV (b))
3933 pos = BUF_ZV (b);
3934
3935 point = make_int (pos);
3936 }
3937
3938 /* Always set force_start so that redisplay_window will run
3939 thw window-scroll-functions. */
3940 w->force_start = 1;
3941
3942 /* #### When the fuck does this happen? I'm so glad that history has
3943 completely documented the behavior of the scrolling functions under
3944 all circumstances. */
3945 tem = Fpos_visible_in_window_p (point, window);
3946 if (NILP (tem))
3947 {
3948 Fvertical_motion (make_int (-window_char_height (w, 0) / 2), window);
3949 Fset_marker (w->start[CURRENT_DISP], point, w->buffer);
3950 w->start_at_line_beg = beginning_of_line_p (b, XINT (point));
3951 MARK_WINDOWS_CHANGED (w);
3952 }
3953
3954 if (!NILP (n))
3955 {
3956 if (EQ (n, Qminus))
3957 direction *= -1;
3958 else
3959 {
3960 n = Fprefix_numeric_value (n);
3961 value = XINT (n) * direction;
3962
3963 if (!value)
3964 return; /* someone just made a pointless call */
3965 }
3966 }
3967
3968 /* If the user didn't specify how far to scroll then we have to figure it
3969 out by ourselves. */
3970 if (NILP (n) || EQ (n, Qminus))
3971 {
3972 /* Going forwards is easy. If that is what we are doing then just
3973 set value and the section which handles the user specifying a
3974 positive value will work. */
3975 if (direction == 1)
3976 {
3977 value = window_displayed_height (w) - next_screen_context_lines;
3978 value = (value < 1 ? 1 : value);
3979 }
3980
3981 /* Going backwards is hard. We can't use the same loop used if the
3982 user specified a negative value because we care about
3983 next_screen_context_lines. In a variable height world you don't
3984 know how many lines above you can actually be displayed and still
3985 have the context lines appear. So we leave value set to 0 and add
3986 a separate section to deal with this. */
3987
3988 }
3989
3990 if (direction == 1 && !value)
3991 {
3992 return;
3993 }
3994 else if (value > 0)
3995 {
3996 int vtarget;
3997 Bufpos startp, old_start;
3998
3999 old_start = marker_position (w->start[CURRENT_DISP]);
4000 startp = vmotion (w, old_start, value, &vtarget);
4001
4002 if (vtarget < value &&
4003 (w->window_end_pos[CURRENT_DISP] == -1
4004 || (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b))))
4005 {
4006 maybe_signal_error (Qend_of_buffer, Qnil, Qwindow, errb);
4007 return;
4008 }
4009 else
4010 {
4011 set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4012 w->buffer);
4013 w->force_start = 1;
4014 w->start_at_line_beg = beginning_of_line_p (b, startp);
4015 MARK_WINDOWS_CHANGED (w);
4016
4017 if (!point_would_be_visible (w, startp, XINT (point)))
4018 {
4019 if (selected)
4020 BUF_SET_PT (b, startp);
4021 else
4022 set_marker_restricted (w->pointm[CURRENT_DISP],
4023 make_int (startp),
4024 w->buffer);
4025 }
4026 }
4027 }
4028 else if (value < 0)
4029 {
4030 int vtarget;
4031 Bufpos startp, old_start;
4032
4033 old_start = marker_position (w->start[CURRENT_DISP]);
4034 startp = vmotion (w, old_start, value, &vtarget);
4035
4036 if (vtarget > value
4037 && marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4038 {
4039 maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4040 return;
4041 }
4042 else
4043 {
4044 set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4045 w->buffer);
4046 w->force_start = 1;
4047 w->start_at_line_beg = beginning_of_line_p (b, startp);
4048 MARK_WINDOWS_CHANGED (w);
4049
4050 if (!point_would_be_visible (w, startp, XINT (point)))
4051 {
4052 Bufpos new_point;
4053
4054 if (MINI_WINDOW_P (w))
4055 new_point = startp;
4056 else
4057 new_point = start_of_last_line (w, startp);
4058
4059 if (selected)
4060 BUF_SET_PT (b, new_point);
4061 else
4062 set_marker_restricted (w->pointm[CURRENT_DISP],
4063 make_int (new_point),
4064 w->buffer);
4065 }
4066 }
4067 }
4068 else /* value == 0 && direction == -1 */
4069 {
4070 if (marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b))
4071 {
4072 maybe_signal_error (Qbeginning_of_buffer, Qnil, Qwindow, errb);
4073 return;
4074 }
4075 else
4076 {
4077 int vtarget;
4078 int movement = next_screen_context_lines - 1;
4079 Bufpos old_startp = marker_position (w->start[CURRENT_DISP]);
4080 Bufpos bottom = vmotion (w, old_startp, movement, &vtarget);
4081 Bufpos startp =
4082 start_with_point_on_display_line (w, bottom,
4083 -1 - (movement - vtarget));
4084
4085 if (startp >= old_startp)
4086 startp = vmotion (w, old_startp, -1, NULL);
4087
4088 set_marker_restricted (w->start[CURRENT_DISP], make_int (startp),
4089 w->buffer);
4090 w->force_start = 1;
4091 w->start_at_line_beg = beginning_of_line_p (b, startp);
4092 MARK_WINDOWS_CHANGED (w);
4093
4094 if (!point_would_be_visible (w, startp, XINT (point)))
4095 {
4096 Bufpos new_point = start_of_last_line (w, startp);
4097
4098 if (selected)
4099 BUF_SET_PT (b, new_point);
4100 else
4101 set_marker_restricted (w->pointm[CURRENT_DISP],
4102 make_int (new_point),
4103 w->buffer);
4104 }
4105 }
4106 }
4107
4108 }
4109
4110 DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "_P" /*
4111 Scroll text of current window upward ARG lines; or near full screen if no ARG.
4112 A near full screen is `next-screen-context-lines' less than a full screen.
4113 Negative ARG means scroll downward.
4114 When calling from a program, supply a number as argument or nil.
4115 */ )
4116 (n)
4117 Lisp_Object n;
4118 {
4119 window_scroll (Fselected_window (Qnil), n, 1, ERROR_ME);
4120 return Qnil;
4121 }
4122
4123 DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "_P" /*
4124 Scroll text of current window downward ARG lines; or near full screen if no ARG.
4125 A near full screen is `next-screen-context-lines' less than a full screen.
4126 Negative ARG means scroll upward.
4127 When calling from a program, supply a number as argument or nil.
4128 */ )
4129 (n)
4130 Lisp_Object n;
4131 {
4132 window_scroll (Fselected_window (Qnil), n, -1, ERROR_ME);
4133 return Qnil;
4134 }
4135
4136 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, Sother_window_for_scrolling, 0, 0, 0 /*
4137 Return the other window for \"other window scroll\" commands.
4138 If in the minibuffer, `minibuffer-scroll-window' if non-nil
4139 specifies the window.
4140 If `other-window-scroll-buffer' is non-nil, a window
4141 showing that buffer is used.
4142 */ )
4143 ()
4144 {
4145 Lisp_Object window;
4146 Lisp_Object selected_window = Fselected_window (Qnil);
4147
4148 if (MINI_WINDOW_P (XWINDOW (selected_window))
4149 && !NILP (Vminibuf_scroll_window))
4150 window = Vminibuf_scroll_window;
4151 /* If buffer is specified, scroll that buffer. */
4152 else if (!NILP (Vother_window_scroll_buffer))
4153 {
4154 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil, Qnil);
4155 if (NILP (window))
4156 window = display_buffer (Vother_window_scroll_buffer, Qt, Qnil);
4157 }
4158 else
4159 {
4160 /* Nothing specified; look for a neighboring window on the same
4161 frame. */
4162 window = Fnext_window (selected_window, Qnil, Qnil, Qnil);
4163
4164 if (EQ (window, selected_window))
4165 /* That didn't get us anywhere; look for a window on another
4166 visible frame. */
4167 do
4168 window = Fnext_window (window, Qnil, Qt, Qnil);
4169 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window))))
4170 && ! EQ (window, selected_window));
4171 }
4172
4173 CHECK_LIVE_WINDOW (window);
4174
4175 if (EQ (window, selected_window))
4176 error ("There is no other window");
4177
4178 return window;
4179 }
4180
4181 DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "_P" /*
4182 Scroll next window upward ARG lines; or near full frame if no ARG.
4183 The next window is the one below the current one; or the one at the top
4184 if the current one is at the bottom. Negative ARG means scroll downward.
4185 When calling from a program, supply a number as argument or nil.
4186
4187 If in the minibuffer, `minibuf-scroll-window' if non-nil
4188 specifies the window to scroll.
4189 If `other-window-scroll-buffer' is non-nil, scroll the window
4190 showing that buffer, popping the buffer up if necessary.
4191 */ )
4192 (n)
4193 Lisp_Object n;
4194 {
4195 window_scroll (Fother_window_for_scrolling (), n, 1, ERROR_ME);
4196 return Qnil;
4197 }
4198
4199 DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 0, 1, "_P" /*
4200 Scroll selected window display ARG columns left.
4201 Default for ARG is window width minus 2.
4202 */ )
4203 (arg)
4204 Lisp_Object arg;
4205 {
4206 Lisp_Object window = Fselected_window (Qnil);
4207 struct window *w = XWINDOW (window);
4208
4209 if (NILP (arg))
4210 arg = make_int (window_char_width (w, 0) - 2);
4211 else
4212 arg = Fprefix_numeric_value (arg);
4213
4214 return
4215 Fset_window_hscroll (window, make_int (w->hscroll + XINT (arg)));
4216 }
4217
4218 DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 0, 1, "_P" /*
4219 Scroll selected window display ARG columns right.
4220 Default for ARG is window width minus 2.
4221 */ )
4222 (arg)
4223 Lisp_Object arg;
4224 {
4225 Lisp_Object window = Fselected_window (Qnil);
4226 struct window *w = XWINDOW (window);
4227
4228 if (NILP (arg))
4229 arg = make_int (window_char_width (w, 0) - 2);
4230 else
4231 arg = Fprefix_numeric_value (arg);
4232
4233 return
4234 Fset_window_hscroll (window, make_int (w->hscroll - XINT (arg)));
4235 }
4236
4237 DEFUN ("recenter", Frecenter, Srecenter, 0, 2, "_P" /*
4238 Center point in WINDOW and redisplay frame. With ARG, put point on line ARG.
4239 The desired position of point is always relative to the window.
4240 Just C-u as prefix means put point in the center of the window.
4241 No arg (i.e., it is nil) erases the entire frame and then
4242 redraws with point in the center of the window.
4243 If WINDOW is nil, the selected window is used.
4244 */ )
4245 (n, window)
4246 Lisp_Object n, window;
4247 {
4248 struct window *w;
4249 struct buffer *b;
4250 Bufpos startp;
4251 Bufpos opoint;
4252
4253 if (NILP (window))
4254 window = Fselected_window (Qnil);
4255 else
4256 CHECK_WINDOW (window);
4257 w = XWINDOW (window);
4258 b = XBUFFER (w->buffer);
4259
4260 opoint = BUF_PT (b);
4261
4262 if (NILP (n) || CONSP (n))
4263 {
4264 struct frame *f = XFRAME (w->frame);
4265
4266 if (NILP (n))
4267 {
4268 MARK_FRAME_CHANGED (f);
4269 SET_FRAME_CLEAR (f);
4270 }
4271
4272 startp = start_with_line_at_pixpos (w, opoint, window_half_pixpos (w));
4273 }
4274 else
4275 {
4276 n = Fprefix_numeric_value (n);
4277 CHECK_INT (n);
4278
4279 startp = start_with_point_on_display_line (w, opoint, XINT (n));
4280 }
4281
4282 Fset_marker (w->start[CURRENT_DISP], make_int (startp), w->buffer);
4283
4284 w->start_at_line_beg = beginning_of_line_p (b, startp);
4285 w->force_start = 1;
4286 MARK_WINDOWS_CHANGED (w);
4287 return Qnil;
4288 }
4289
4290 DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line,
4291 1, 2, "_P" /*
4292 Position point relative to WINDOW.
4293 With no argument, position text at center of window.
4294 An argument specifies window line; zero means top of window,
4295 negative means relative to bottom of window.
4296 If WINDOW is nil, the selected window is used.
4297 */ )
4298 (arg, window)
4299 Lisp_Object arg, window;
4300 {
4301 struct window *w;
4302 struct buffer *b;
4303 int height;
4304 Bufpos start, new_point;
4305 int selected;
4306
4307 if (NILP (window))
4308 window = Fselected_window (Qnil);
4309 else
4310 CHECK_WINDOW (window);
4311 w = XWINDOW (window);
4312 b = XBUFFER (w->buffer);
4313
4314 height = window_displayed_height (w);
4315 selected = EQ (window, Fselected_window (w->frame));
4316
4317 if (NILP (arg))
4318 {
4319 int retval;
4320
4321 if (XINT (w->last_modified[CURRENT_DISP]) >= BUF_MODIFF (b)
4322 && XINT (w->last_facechange[CURRENT_DISP]) >= BUF_FACECHANGE (b))
4323 {
4324 new_point = point_at_center (w, CURRENT_DISP, 0, 0);
4325
4326 if (selected)
4327 BUF_SET_PT (b, new_point);
4328 else
4329 Fset_window_point (window, make_int (new_point));
4330
4331 retval = line_at_center (w, CURRENT_DISP, 0, 0);
4332 }
4333 else
4334 {
4335 start = marker_position (w->start[CURRENT_DISP]);
4336 if (start < BUF_BEGV (b))
4337 start = BUF_BEGV (b);
4338 else if (start > BUF_ZV (b))
4339 start = BUF_ZV (b);
4340
4341 if (selected)
4342 new_point = BUF_PT (b);
4343 else
4344 new_point = marker_position (w->pointm[CURRENT_DISP]);
4345
4346 new_point = point_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4347
4348 if (selected)
4349 BUF_SET_PT (b, new_point);
4350 else
4351 Fset_window_point (window, make_int (new_point));
4352
4353 retval = line_at_center (w, CMOTION_DISP, start, BUF_PT (b));
4354 }
4355
4356 return (make_int (retval));
4357 }
4358 else
4359 {
4360 /* #### Is this going to work right when at eob? */
4361 arg = Fprefix_numeric_value (arg);
4362 if (XINT (arg) < 0)
4363 XSETINT (arg, XINT (arg) + height);
4364 }
4365
4366 start = marker_position (w->start[CURRENT_DISP]);
4367 if (start < BUF_BEGV (b) || start > BUF_ZV (b))
4368 {
4369 if (selected)
4370 new_point = BUF_PT (b);
4371 else
4372 new_point = marker_position (w->pointm[CURRENT_DISP]);
4373
4374 new_point = vmotion (XWINDOW (window), new_point, -height / 2, 0);
4375
4376 if (selected)
4377 BUF_SET_PT (b, new_point);
4378 else
4379 Fset_window_point (window, make_int (new_point));
4380
4381 Fset_marker (w->start[CURRENT_DISP], make_int (new_point),
4382 w->buffer);
4383 w->start_at_line_beg = beginning_of_line_p (b, new_point);
4384 w->force_start = 1;
4385 }
4386 else
4387 {
4388 if (selected)
4389 BUF_SET_PT (b, start);
4390 else
4391 Fset_window_point (window, make_int (start));
4392 }
4393
4394 if (selected)
4395 return Fvertical_motion (arg, window);
4396 else
4397 {
4398 int vpos;
4399 new_point = vmotion (XWINDOW (window),
4400 marker_position (w->pointm[CURRENT_DISP]),
4401 XINT (arg), &vpos);
4402 Fset_window_point (window, make_int (new_point));
4403 return make_int (vpos);
4404 }
4405 }
4406
4407
4408 static int
4409 map_windows_1 (Lisp_Object window,
4410 int (*mapfun) (struct window *w, void *closure),
4411 void *closure)
4412 {
4413 int retval;
4414
4415 for (; !NILP (window); window = XWINDOW (window)->next)
4416 {
4417 struct window *w = XWINDOW (window);
4418 if (!NILP (w->vchild))
4419 retval = map_windows_1 (w->vchild, mapfun, closure);
4420 else if (!NILP (w->hchild))
4421 retval = map_windows_1 (w->hchild, mapfun, closure);
4422 else
4423 retval = (mapfun) (w, closure);
4424 if (retval)
4425 return retval;
4426 }
4427
4428 return 0;
4429 }
4430
4431 /* Map MAPFUN over the windows in F. CLOSURE is passed to each
4432 invocation of MAPFUN. If any invocation of MAPFUN returns non-zero,
4433 the mapping is halted and the value returned is the return value
4434 of map_windows(). Otherwise, map_windows() maps over all windows
4435 in F and returns 0. */
4436
4437 int
4438 map_windows (struct frame *f, int (*mapfun) (struct window *w, void *closure),
4439 void *closure)
4440 {
4441 return map_windows_1 (FRAME_ROOT_WINDOW (f), mapfun, closure);
4442 }
4443
4444
4445 static void
4446 modeline_shadow_thickness_changed (Lisp_Object specifier, struct window *w,
4447 Lisp_Object oldval)
4448 {
4449 w->shadow_thickness_changed = 1;
4450 MARK_WINDOWS_CHANGED (w);
4451 }
4452
4453 /* also used in scrollbar.c */
4454 void
4455 some_window_value_changed (Lisp_Object specifier, struct window *w,
4456 Lisp_Object oldval)
4457 {
4458 MARK_WINDOWS_CHANGED (w);
4459 }
4460
4461 #ifdef MEMORY_USAGE_STATS
4462
4463 struct window_stats
4464 {
4465 int face;
4466 int glyph;
4467 #ifdef HAVE_SCROLLBARS
4468 int scrollbar;
4469 #endif
4470 int line_start;
4471 int other_redisplay;
4472 int other;
4473 };
4474
4475 static void
4476 compute_window_mirror_usage (struct window_mirror *mir,
4477 struct window_stats *stats,
4478 struct overhead_stats *ovstats)
4479 {
4480 if (!mir)
4481 return;
4482 stats->other += malloced_storage_size (mir, sizeof (struct window_mirror),
4483 ovstats);
4484 #ifdef HAVE_SCROLLBARS
4485 {
4486 struct device *d = XDEVICE (FRAME_DEVICE (mir->frame));
4487
4488 stats->scrollbar +=
4489 compute_scrollbar_instance_usage (d, mir->scrollbar_vertical_instance,
4490 ovstats);
4491 stats->scrollbar +=
4492 compute_scrollbar_instance_usage (d, mir->scrollbar_horizontal_instance,
4493 ovstats);
4494 }
4495 #endif
4496 stats->other_redisplay +=
4497 compute_display_line_dynarr_usage (mir->current_display_lines, ovstats);
4498 stats->other_redisplay +=
4499 compute_display_line_dynarr_usage (mir->desired_display_lines, ovstats);
4500 }
4501
4502 static void
4503 compute_window_usage (struct window *w, struct window_stats *stats,
4504 struct overhead_stats *ovstats)
4505 {
4506 memset (stats, 0, sizeof (*stats));
4507 stats->other += malloced_storage_size (w, sizeof (struct window), ovstats);
4508 stats->face += compute_face_cachel_usage (w->face_cachels, ovstats);
4509 stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ovstats);
4510 stats->line_start +=
4511 compute_line_start_cache_dynarr_usage (w->line_start_cache, ovstats);
4512 compute_window_mirror_usage (find_window_mirror (w), stats, ovstats);
4513 }
4514
4515 DEFUN ("window-memory-usage", Fwindow_memory_usage, Swindow_memory_usage,
4516 1, 1, 0 /*
4517 Return stats about the memory usage of window WINDOW.
4518 The values returned are in the form an alist of usage types and byte
4519 counts. The byte counts attempt to encompass all the memory used
4520 by the window (separate from the memory logically associated with a
4521 buffer or frame), including internal structures and any malloc()
4522 overhead associated with them. In practice, the byte counts are
4523 underestimated because certain memory usage is very hard to determine
4524 (e.g. the amount of memory used inside the Xt library or inside the
4525 X server) and because there is other stuff that might logically
4526 be associated with a window, buffer, or frame (e.g. window configurations,
4527 glyphs) but should not obviously be included in the usage counts.
4528
4529 Multiple slices of the total memory usage may be returned, separated
4530 by a nil. Each slice represents a particular view of the memory, a
4531 particular way of partitioning it into groups. Within a slice, there
4532 is no overlap between the groups of memory, and each slice collectively
4533 represents all the memory concerned.
4534 */ )
4535 (window)
4536 Lisp_Object window;
4537 {
4538 struct window_stats stats;
4539 struct overhead_stats ovstats;
4540
4541 CHECK_WINDOW (window); /* dead windows should be allowed, no? */
4542 memset (&ovstats, 0, sizeof (ovstats));
4543 compute_window_usage (XWINDOW (window), &stats, &ovstats);
4544
4545 return nconc2 (
4546 #ifdef HAVE_SCROLLBARS
4547 list6
4548 #else
4549 list5
4550 #endif
4551 (Fcons (Qface_cache, make_int (stats.face)),
4552 Fcons (Qglyph_cache, make_int (stats.glyph)),
4553 #ifdef HAVE_SCROLLBARS
4554 Fcons (Qscrollbar_instances, make_int (stats.scrollbar)),
4555 #endif
4556 Fcons (Qline_start_cache, make_int (stats.line_start)),
4557 Fcons (Qother_redisplay, make_int (stats.other_redisplay)),
4558 Fcons (Qother, make_int (stats.other))),
4559 list4 (Qnil,
4560 Fcons (Qactually_requested,
4561 make_int (ovstats.was_requested)),
4562 Fcons (Qmalloc_overhead,
4563 make_int (ovstats.malloc_overhead)),
4564 Fcons (Qdynarr_overhead,
4565 make_int (ovstats.dynarr_overhead))));
4566 }
4567
4568 #endif /* MEMORY_USAGE_STATS */
4569
4570
4571 /************************************************************************/
4572 /* Window configurations */
4573 /************************************************************************/
4574
4575 /* #### This window configuration stuff has had serious bugs lurking in it
4576 for years; it would be a -huge- win if this was reimplemented in lisp.
4577 */
4578
4579 /* If you add anything to this structure make sure saved_window_equal
4580 knows about it. */
4581 struct saved_window
4582 {
4583 Lisp_Object window; /* window */
4584 Lisp_Object buffer; /* buffer */
4585 Lisp_Object start; /* copied marker */
4586 Lisp_Object pointm; /* copied marker */
4587 Lisp_Object sb_point; /* copied marker */
4588 Lisp_Object mark; /* copied marker */
4589 int pixel_left;
4590 int pixel_top;
4591 int pixel_width;
4592 int pixel_height;
4593 int hscroll;
4594 int parent_index; /* index into saved_windows */
4595 int prev_index; /* index into saved_windows */
4596 Lisp_Object dedicated;
4597 char start_at_line_beg; /* boolean */
4598 };
4599
4600 /* If you add anything to this structure make sure window_config_equal
4601 knows about it. */
4602 struct window_config
4603 {
4604 struct lcrecord_header header;
4605 int frame_width;
4606 int frame_height;
4607 #if 0 /* FSFmacs */
4608 Lisp_Object selected_frame;
4609 #endif
4610 Lisp_Object current_window;
4611 Lisp_Object current_buffer;
4612 Lisp_Object minibuf_scroll_window;
4613 Lisp_Object root_window;
4614 /* Record the values of window-min-width and window-min-height
4615 so that window sizes remain consistent with them. */
4616 int min_width, min_height;
4617 #ifdef ENERGIZE
4618 /* The buffer whose p_sheets are visible */
4619 Lisp_Object p_sheet_buffer;
4620 #endif
4621 int saved_windows_count;
4622 /* Zero-sized arrays aren't ANSI C */
4623 struct saved_window saved_windows[1];
4624 };
4625 #define SAVED_WINDOW_N(conf, n) (&((conf)->saved_windows[(n)]))
4626
4627 static Lisp_Object mark_window_config (Lisp_Object, void (*) (Lisp_Object));
4628 static void print_window_config (Lisp_Object, Lisp_Object, int);
4629 static unsigned int sizeof_window_config (CONST void *);
4630
4631 #define XWINDOW_CONFIGURATION(x) XRECORD (x, window_configuration, struct window_config)
4632 #define XSETWINDOW_CONFIGURATION(x, p) XSETRECORD (x, p, window_configuration)
4633 #define WINDOW_CONFIGURATIONP(x) RECORDP (x, window_configuration)
4634 #define GC_WINDOW_CONFIGURATIONP(x) GC_RECORDP (x, window_configuration)
4635 #define CHECK_WINDOW_CONFIGURATION(x) CHECK_RECORD (x, window_configuration)
4636
4637 DEFINE_LRECORD_SEQUENCE_IMPLEMENTATION ("window-configuration",
4638 window_configuration,
4639 mark_window_config,
4640 print_window_config,
4641 0, 0, 0, sizeof_window_config,
4642 struct window_config);
4643
4644 static Lisp_Object
4645 mark_window_config (Lisp_Object obj, void (*markobj) (Lisp_Object))
4646 {
4647 struct window_config *config = XWINDOW_CONFIGURATION (obj);
4648 int i;
4649 ((markobj) (config->current_window));
4650 ((markobj) (config->current_buffer));
4651 ((markobj) (config->minibuf_scroll_window));
4652 ((markobj) (config->root_window));
4653 #ifdef ENERGIZE
4654 ((markobj) (config->p_sheet_buffer));
4655 #endif
4656 for (i = 0; i < config->saved_windows_count; i++)
4657 {
4658 struct saved_window *s = SAVED_WINDOW_N (config, i);
4659 ((markobj) (s->window));
4660 ((markobj) (s->buffer));
4661 ((markobj) (s->start));
4662 ((markobj) (s->pointm));
4663 ((markobj) (s->sb_point));
4664 ((markobj) (s->mark));
4665 ((markobj) (s->dedicated));
4666 }
4667 return (Qnil);
4668 }
4669
4670 static int
4671 sizeof_window_config_for_n_windows (int n)
4672 {
4673 return (sizeof (struct window_config) +
4674 /* n - 1 because zero-sized arrays aren't ANSI C */
4675 (n - 1) *sizeof (struct saved_window));
4676 }
4677
4678 static unsigned int
4679 sizeof_window_config (CONST void *h)
4680 {
4681 CONST struct window_config *c = h;
4682 return sizeof_window_config_for_n_windows (c->saved_windows_count);
4683 }
4684
4685 static void
4686 print_window_config (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
4687 {
4688 struct window_config *config = XWINDOW_CONFIGURATION (obj);
4689 char buf[200];
4690 if (print_readably)
4691 error ("printing unreadable object #<window-configuration 0x%x>",
4692 config->header.uid);
4693 write_c_string ("#<window-configuration ", printcharfun);
4694 sprintf (buf, "0x%x>", config->header.uid);
4695 write_c_string (buf, printcharfun);
4696 }
4697
4698 /* Returns a boolean indicating whether the two saved windows are
4699 identical. */
4700 static int
4701 saved_window_equal (struct saved_window *win1, struct saved_window *win2)
4702 {
4703 if (!EQ (win1->window, win2->window))
4704 return 0;
4705 else if (!EQ (win1->buffer, win2->buffer))
4706 return 0;
4707 else if (NILP (Fequal (win1->start, win2->start)))
4708 return 0;
4709 else if (NILP (Fequal (win1->pointm, win2->pointm)))
4710 return 0;
4711 else if (NILP (Fequal (win1->sb_point, win2->sb_point)))
4712 return 0;
4713 else if (NILP (Fequal (win1->mark, win2->mark)))
4714 return 0;
4715 else if (win1->pixel_left != win2->pixel_left)
4716 return 0;
4717 else if (win1->pixel_top != win2->pixel_top)
4718 return 0;
4719 else if (win1->pixel_width != win2->pixel_width)
4720 return 0;
4721 else if (win1->pixel_height != win2->pixel_height)
4722 return 0;
4723 else if (win1->hscroll != win2->hscroll)
4724 return 0;
4725 else if (win1->parent_index != win2->parent_index)
4726 return 0;
4727 else if (win1->prev_index != win2->prev_index)
4728 return 0;
4729 else if (!EQ (win1->dedicated, win2->dedicated))
4730 return 0;
4731 else if (win1->start_at_line_beg != win2->start_at_line_beg)
4732 return 0;
4733
4734 return 1;
4735 }
4736
4737 /* Returns a boolean indicating whether the two given configurations
4738 are identical. */
4739 static int
4740 window_config_equal (Lisp_Object conf1, Lisp_Object conf2)
4741 {
4742 struct window_config *fig1, *fig2;
4743 int i;
4744
4745 /* First check if they are truly the same. */
4746 if (EQ (conf1, conf2))
4747 return 1;
4748
4749 fig1 = XWINDOW_CONFIGURATION (conf1);
4750 fig2 = XWINDOW_CONFIGURATION (conf2);
4751
4752 if (fig1->saved_windows_count != fig2->saved_windows_count)
4753 return 0;
4754 else if (!EQ (fig1->current_window, fig2->current_window))
4755 return 0;
4756 else if (!EQ (fig1->current_buffer, fig2->current_buffer))
4757 return 0;
4758 else if (!EQ (fig1->root_window, fig2->root_window))
4759 return 0;
4760 else if (!EQ (fig1->minibuf_scroll_window, fig2->minibuf_scroll_window))
4761 return 0;
4762 else if (fig1->frame_width != fig2->frame_width)
4763 return 0;
4764 else if (fig1->frame_height != fig2->frame_height)
4765 return 0;
4766 #ifdef ENERGIZE
4767 else if (!EQ (fig1->p_sheet_buffer, fig2->p_sheet_buffer))
4768 return 0;
4769 #endif
4770
4771 for (i = 0; i < fig1->saved_windows_count; i++)
4772 {
4773 if (!saved_window_equal (SAVED_WINDOW_N (fig1, i),
4774 SAVED_WINDOW_N (fig2, i)))
4775 return 0;
4776 }
4777
4778 return 1;
4779 }
4780
4781 DEFUN ("window-configuration-p", Fwindow_configuration_p,
4782 Swindow_configuration_p, 1, 1, 0 /*
4783 T if OBJECT is a window-configuration object.
4784 */ )
4785 (obj)
4786 Lisp_Object obj;
4787 {
4788 return (WINDOW_CONFIGURATIONP (obj) ? Qt : Qnil);
4789 }
4790
4791 /*
4792 * There are getting to be a lot of functions which traverse the
4793 * window structure doing various things. It may be worth writing a
4794 * generic map-windows function.
4795 * #### I just did. Feel free to rewrite. --ben
4796 */
4797 void
4798 mark_windows_in_use (Lisp_Object window, int mark)
4799 {
4800 for (; !NILP (window) ; window = XWINDOW (window)->next)
4801 {
4802 XWINDOW (window)->config_mark = mark;
4803
4804 if (!NILP (XWINDOW (window)->vchild))
4805 mark_windows_in_use (XWINDOW (window)->vchild, mark);
4806 else if (!NILP (XWINDOW (window)->hchild))
4807 mark_windows_in_use (XWINDOW (window)->hchild, mark);
4808 }
4809 }
4810
4811 /* Lisp_Object return value so it can be used in record_unwind_protect() */
4812 static Lisp_Object
4813 free_window_configuration (Lisp_Object window_config)
4814 {
4815 int i;
4816 struct window_config *config = XWINDOW_CONFIGURATION (window_config);
4817
4818 /* Free all the markers. It's not completely necessary that
4819 we do this (window configs sitting in a free list aren't
4820 marked normally so the markers wouldn't be marked anyway)
4821 but it's more efficient. */
4822 for (i = 0; i < config->saved_windows_count; i++)
4823 {
4824 struct saved_window *p = SAVED_WINDOW_N (config, i);
4825
4826 if (!NILP (p->pointm))
4827 {
4828 free_marker (XMARKER (p->pointm));
4829 p->pointm = Qnil;
4830 }
4831 if (!NILP (p->start))
4832 {
4833 free_marker (XMARKER (p->start));
4834 p->start = Qnil;
4835 }
4836 if (!NILP (p->sb_point))
4837 {
4838 free_marker (XMARKER (p->sb_point));
4839 p->sb_point = Qnil;
4840 }
4841 if (!NILP (p->mark))
4842 {
4843 free_marker (XMARKER (p->mark));
4844 p->mark = Qnil;
4845 }
4846 }
4847
4848 if (config->saved_windows_count <= countof (Vwindow_configuration_free_list))
4849 free_managed_lcrecord (Vwindow_configuration_free_list
4850 [config->saved_windows_count - 1],
4851 window_config);
4852
4853 return Qnil;
4854 }
4855
4856 DEFUN ("set-window-configuration",
4857 Fset_window_configuration, Sset_window_configuration,
4858 1, 1, 0 /*
4859 Set the configuration of windows and buffers as specified by CONFIGURATION.
4860 CONFIGURATION must be a value previously returned
4861 by `current-window-configuration' (which see).
4862 */ )
4863 (configuration)
4864 Lisp_Object configuration;
4865 {
4866 struct window *w;
4867 struct window_config *config;
4868 struct saved_window *p;
4869 Lisp_Object new_current_buffer;
4870 int k;
4871 Lisp_Object frame;
4872 struct frame *f;
4873 struct gcpro gcpro1;
4874 Lisp_Object old_window_config;
4875 int previous_frame_height;
4876 int previous_frame_width;
4877 int specpdl_count = specpdl_depth ();
4878
4879 GCPRO1 (configuration);
4880
4881 CHECK_WINDOW_CONFIGURATION (configuration);
4882 config = XWINDOW_CONFIGURATION (configuration);
4883
4884 frame = XWINDOW (SAVED_WINDOW_N (config, 0)->window)->frame;
4885 f = XFRAME (frame);
4886
4887 /* Do not signal an error here if the frame was deleted. There are
4888 reasonable cases where we could get here with a deleted frame and
4889 just want to do close to nothing instead. */
4890
4891 if (FRAME_LIVE_P (f))
4892 {
4893 /* restore the frame characteristics */
4894 #ifdef ENERGIZE
4895 if (FRAME_X_P (f))
4896 {
4897 Lisp_Object new_desired = config->p_sheet_buffer;
4898
4899 if (BUFFERP (new_desired) &&
4900 !BUFFER_LIVE_P (XBUFFER (new_desired)))
4901 new_desired = Qnil; /* the desired buffer was killed */
4902
4903 /* need to restore the desired buffer */
4904 if (!EQ (new_desired, desired_psheet_buffer (f)))
4905 make_psheets_desired (f, new_desired);
4906 }
4907 #endif
4908
4909 new_current_buffer = config->current_buffer;
4910 if (!BUFFER_LIVE_P (XBUFFER (new_current_buffer)))
4911 new_current_buffer = Qnil;
4912
4913 /*
4914 * Assumed precondition: w->config_mark = 0 for all w
4915 * This procedure should ensure this is true by the time it exits
4916 * to ensure the precondition for future calls.
4917 *
4918 * We use w->config_mark to know whether we're modifying a
4919 * window that is currently visible on the frame (#### we
4920 * should just be able to check whether the window is dead
4921 * or not, but this way is safer?). As we process each
4922 * window, we set its config_mark to 0. At the end, we
4923 * go through all the windows that used to be on the frame,
4924 * set each one's config_mark to 0 (to maintain the
4925 * assumed precondition) and delete each one that's no
4926 * longer in use.
4927 *
4928 * #### Using a window-configuration to keep track of
4929 * the current windows is wasteful. All we need is the
4930 * list of windows, so we could just use a dynarr.
4931 */
4932 old_window_config = Fcurrent_window_configuration (frame);
4933
4934 /* If the new configuration is already equal to the old, then stop
4935 right here. This saves the work below and it also saves
4936 triggering a full redisplay of this window. This is a huge win
4937 when using the mouse since the mode motion code uses
4938 save-window-excursion extensively but will rarely cause the
4939 configuration to actually change. */
4940 if (window_config_equal (configuration, old_window_config))
4941 {
4942 free_window_configuration (old_window_config);
4943 UNGCPRO;
4944 return Qnil;
4945 }
4946
4947 /* We can't quit or even check for quit because that may cause
4948 investigation of the frame state, which may crash if the frame is
4949 in an inconsistent state. */
4950 begin_dont_check_for_quit ();
4951 record_unwind_protect (free_window_configuration, old_window_config);
4952
4953 mark_windows_in_use (f->root_window, 1);
4954
4955 previous_frame_width = FRAME_WIDTH (f);
4956 previous_frame_height = FRAME_HEIGHT (f);
4957 /* If the frame has been resized since this window configuration was
4958 made, we change the frame to the size specified in the
4959 configuration, restore the configuration, and then resize it
4960 back. We keep track of the prevailing height in these variables. */
4961 if (config->frame_height != FRAME_HEIGHT (f)
4962 || config->frame_width != FRAME_WIDTH (f))
4963 change_frame_size (f, config->frame_height, config->frame_width, 0);
4964
4965 /* Temporarily avoid any problems with windows that are smaller
4966 than they are supposed to be. */
4967 window_min_height = 1;
4968 window_min_width = 1;
4969
4970 /* OK, now restore all the windows in the window config.
4971 This may involve "undeleting" windows, since the
4972 windows in the window config may be deleted.
4973 */
4974 for (k = 0; k < config->saved_windows_count; k++)
4975 {
4976 p = SAVED_WINDOW_N (config, k);
4977 w = XWINDOW (p->window);
4978 w->next = Qnil;
4979
4980 /* The window might be dead. In this case, its redisplay
4981 structures were freed, so we need to reallocate them. */
4982 if (!w->face_cachels)
4983 {
4984 w->face_cachels = Dynarr_new (struct face_cachel);
4985 reset_face_cachels (w);
4986 }
4987 if (!w->glyph_cachels)
4988 w->glyph_cachels = Dynarr_new (struct glyph_cachel);
4989 if (!w->line_start_cache)
4990 w->line_start_cache = Dynarr_new (struct line_start_cache);
4991 w->dead = 0;
4992
4993 if (p->parent_index >= 0)
4994 w->parent = SAVED_WINDOW_N (config, p->parent_index)->window;
4995 else
4996 w->parent = Qnil;
4997
4998 if (p->prev_index >= 0)
4999 {
5000 w->prev = SAVED_WINDOW_N (config, p->prev_index)->window;
5001
5002 /* This is true for a minibuffer-only frame. */
5003 if (!NILP (w->mini_p) && EQ (w->prev, p->window))
5004 w->next = Qnil;
5005 else
5006 XWINDOW (w->prev)->next = p->window;
5007 }
5008 else
5009 {
5010 w->prev = Qnil;
5011 if (!NILP (w->parent))
5012 {
5013 if (WINDOW_WIDTH (p) == WINDOW_WIDTH (XWINDOW (w->parent)))
5014 {
5015 XWINDOW (w->parent)->vchild = p->window;
5016 XWINDOW (w->parent)->hchild = Qnil;
5017 }
5018 else
5019 {
5020 XWINDOW (w->parent)->hchild = p->window;
5021 XWINDOW (w->parent)->vchild = Qnil;
5022 }
5023 }
5024 }
5025 if (!w->config_mark)
5026 {
5027 /* #### This should be equivalent to the window previously
5028 having been dead. If we're brave, we'll put in an
5029 assertion to this effect. */
5030 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f);
5031 }
5032 else /* if (!EQ (w->buffer, p->buffer)) */
5033 {
5034 /* With the new redisplay we let it know that a change has
5035 been made and it will take care of the rest. If we don't
5036 tell it something has possibly changed it could lead to
5037 incorrect display. */
5038 MARK_WINDOWS_CHANGED (w);
5039 }
5040
5041 WINDOW_LEFT (w) = WINDOW_LEFT (p);
5042 WINDOW_TOP (w) = WINDOW_TOP (p);
5043 WINDOW_WIDTH (w) = WINDOW_WIDTH (p);
5044 WINDOW_HEIGHT (w) = WINDOW_HEIGHT (p);
5045 w->hscroll = p->hscroll;
5046 /* #### Here we need to restore the saved specs for
5047 has-modeline-p, scrollbar-width, scrollbar-height,
5048 modeline-shadow-thickness, left-margin-width,
5049 right-margin-width, and current-display-table. */
5050 w->dedicated = p->dedicated;
5051 w->line_cache_last_updated = Qzero;
5052 SET_LAST_MODIFIED (w, 1);
5053 SET_LAST_FACECHANGE (w);
5054 w->config_mark = 0;
5055
5056 /* Reinstall the saved buffer and pointers into it. */
5057 if (NILP (p->buffer))
5058 w->buffer = p->buffer;
5059 else
5060 {
5061 if (BUFFER_LIVE_P (XBUFFER (p->buffer)))
5062 /* If saved buffer is alive, install it. */
5063 {
5064 w->buffer = p->buffer;
5065 w->start_at_line_beg = p->start_at_line_beg;
5066 set_marker_restricted (w->start[CURRENT_DISP],
5067 Fmarker_position (p->start),
5068 w->buffer);
5069 set_marker_restricted (w->pointm[CURRENT_DISP],
5070 Fmarker_position (p->pointm),
5071 w->buffer);
5072 set_marker_restricted (w->sb_point,
5073 Fmarker_position (p->sb_point),
5074 w->buffer);
5075 Fset_marker (XBUFFER (w->buffer)->mark,
5076 Fmarker_position (p->mark), w->buffer);
5077
5078 /* As documented in Fcurrent_window_configuration, don't
5079 save the location of point in the buffer which was current
5080 when the window configuration was recorded. */
5081 if (!EQ (p->buffer, new_current_buffer) &&
5082 XBUFFER (p->buffer) == current_buffer)
5083 Fgoto_char (w->pointm[CURRENT_DISP], Fcurrent_buffer ());
5084 }
5085 else if (NILP (w->buffer) ||
5086 !BUFFER_LIVE_P (XBUFFER (w->buffer)))
5087 /* Else if window's old buffer is dead too, get a live one. */
5088 {
5089 /* #### The following line makes me nervous... */
5090 /* w->buffer = Fcdr (Fcar (XFRAME (w->frame)->buffer_alist));*/
5091 w->buffer = Fget_buffer_create (QSscratch);
5092 /* w->buffer = Fother_buffer (Qnil, w->frame, Qnil); */
5093 /* This will set the markers to beginning of visible
5094 range. */
5095 set_marker_restricted (w->start[CURRENT_DISP], Qzero, w->buffer);
5096 set_marker_restricted (w->pointm[CURRENT_DISP], Qzero,
5097 w->buffer);
5098 set_marker_restricted (w->sb_point, Qzero, w->buffer);
5099 w->start_at_line_beg = 1;
5100 }
5101 else
5102 /* Keeping window's old buffer; make sure the markers
5103 are real. */
5104 {
5105 /* Set window markers at start of visible range. */
5106 if (XMARKER (w->start[CURRENT_DISP])->buffer == 0)
5107 set_marker_restricted (w->start[CURRENT_DISP], Qzero,
5108 w->buffer);
5109 if (XMARKER (w->sb_point)->buffer == 0)
5110 set_marker_restricted (w->sb_point, Qzero, w->buffer);
5111 if (XMARKER (w->pointm[CURRENT_DISP])->buffer == 0)
5112 set_marker_restricted (w->pointm[CURRENT_DISP],
5113 make_int
5114 (BUF_PT (XBUFFER (w->buffer))),
5115 w->buffer);
5116 w->start_at_line_beg = 1;
5117 }
5118 }
5119 }
5120
5121 FRAME_ROOT_WINDOW (f) = config->root_window;
5122 /* Note that FSFmacs unilaterally calls Fselect_window() here, and
5123 then calls do_switch_frame() below to select the frame that was
5124 recorded in the window config as being selected.
5125
5126 Instead, we don't ever change the selected frame, and either
5127 call Fselect_window() below if the window config's frame is
5128 currently selected, or just set the selected window of the
5129 window config's frame. */
5130
5131 /* Set the frame height to the value it had before this function. */
5132 if (previous_frame_height != FRAME_HEIGHT (f)
5133 || previous_frame_width != FRAME_WIDTH (f))
5134 change_frame_size (f, previous_frame_height, previous_frame_width, 0);
5135
5136 /* If restoring in the current frame make the window current,
5137 otherwise just update the frame selected_window slot to be
5138 the restored current_window. */
5139 if (f == selected_frame ())
5140 {
5141 /* When using `pop-window-configuration', often the minibuffer
5142 ends up as the selected window even though it's not active ...
5143 I really don't know the cause of this, but it should never
5144 happen. This kludge should fix it.
5145
5146 #### Find out why this is really going wrong. */
5147 if (!minibuf_level &&
5148 MINI_WINDOW_P (XWINDOW (config->current_window)))
5149 Fselect_window (Fnext_window (config->current_window,
5150 Qnil, Qnil, Qnil));
5151 else
5152 Fselect_window (config->current_window);
5153 if (!NILP (new_current_buffer))
5154 Fset_buffer (new_current_buffer);
5155 else
5156 Fset_buffer (XWINDOW (Fselected_window (Qnil))->buffer);
5157 #ifdef ENERGIZE
5158 energize_buffer_shown_hook (XWINDOW (Fselected_window (Qnil)));
5159 #endif
5160 }
5161 else
5162 set_frame_selected_window (f, config->current_window);
5163 }
5164
5165 /* Restore the minimum heights recorded in the configuration. */
5166 window_min_height = config->min_height;
5167 window_min_width = config->min_width;
5168
5169 #if 0 /* FSFmacs */
5170 /* see above comment */
5171 /* Fselect_window will have made f the selected frame, so we
5172 reselect the proper frame here. Fhandle_switch_frame will change the
5173 selected window too, but that doesn't make the call to
5174 Fselect_window above totally superfluous; it still sets f's
5175 selected window. */
5176 if (FRAME_LIVE_P (XFRAME (config->selected_frame)))
5177 do_switch_frame (config->selected_frame, Qnil, 0);
5178 #endif
5179
5180 Vminibuf_scroll_window = config->minibuf_scroll_window;
5181
5182 if (FRAME_LIVE_P (f))
5183 {
5184 /* Do this before calling recompute_all_cached_specifiers_in_window()
5185 so that things like redisplay_redraw_cursor() won't abort due
5186 to no window mirror present. */
5187 f->mirror_dirty = 1;
5188
5189 config = XWINDOW_CONFIGURATION (old_window_config);
5190 for (k = 0; k < config->saved_windows_count; k++)
5191 {
5192 p = SAVED_WINDOW_N (config, k);
5193 w = XWINDOW (p->window);
5194 /* Remember, we set w->config_mark on all currently visible
5195 windows, and reset it on all newly visible windows.
5196 Any windows still marked need to be deleted. */
5197 if (w->config_mark)
5198 {
5199 mark_window_as_deleted (w);
5200 w->config_mark = 0;
5201 }
5202 else
5203 {
5204 /* We just potentially changed the window's buffer and
5205 potentially turned a dead window into a live one,
5206 so we need to recompute the cached specifier values. */
5207 recompute_all_cached_specifiers_in_window (w);
5208 }
5209 }
5210 }
5211
5212 /* Now restore things, when everything else if OK. */
5213
5214 unbind_to (specpdl_count, Qnil);
5215
5216 UNGCPRO;
5217
5218 return (Qnil);
5219 }
5220
5221 /* Mark all subwindows of a window as deleted. The argument
5222 W is actually the subwindow tree of the window in question. */
5223
5224 void
5225 delete_all_subwindows (struct window *w)
5226 {
5227 if (!NILP (w->next))
5228 delete_all_subwindows (XWINDOW (w->next));
5229 if (!NILP (w->vchild))
5230 delete_all_subwindows (XWINDOW (w->vchild));
5231 if (!NILP (w->hchild))
5232 delete_all_subwindows (XWINDOW (w->hchild));
5233
5234 mark_window_as_deleted (w);
5235 }
5236
5237
5238 static int
5239 count_windows (struct window *window)
5240 {
5241 int count = 1;
5242 if (!NILP (window->next))
5243 count += count_windows (XWINDOW (window->next));
5244 if (!NILP (window->vchild))
5245 count += count_windows (XWINDOW (window->vchild));
5246 if (!NILP (window->hchild))
5247 count += count_windows (XWINDOW (window->hchild));
5248 return count;
5249 }
5250
5251 static int
5252 saved_window_index (Lisp_Object window, struct window_config *config, int lim)
5253 {
5254 int j;
5255 for (j = 0; j < lim; j++)
5256 {
5257 if (EQ (SAVED_WINDOW_N (config, j)->window, window))
5258 {
5259 return (j);
5260 }
5261 }
5262 abort ();
5263 return 0; /* suppress compiler warning */
5264 }
5265
5266 static int
5267 save_window_save (Lisp_Object window, struct window_config *config, int i)
5268 {
5269 struct saved_window *p;
5270 struct window *w;
5271
5272 for (; !NILP (window); window = w->next)
5273 {
5274 p = SAVED_WINDOW_N (config, i);
5275 w = XWINDOW (window);
5276
5277 i++;
5278 p->window = window;
5279 p->buffer = w->buffer;
5280 WINDOW_LEFT (p) = WINDOW_LEFT (w);
5281 WINDOW_TOP (p) = WINDOW_TOP (w);
5282 WINDOW_WIDTH (p) = WINDOW_WIDTH (w);
5283 WINDOW_HEIGHT (p) = WINDOW_HEIGHT (w);
5284 p->hscroll = w->hscroll;
5285 /* #### Here we need to save the specs for
5286 has-modeline-p, scrollbar-width, scrollbar-height,
5287 modeline-shadow-thickness, left-margin-width,
5288 right-margin-width, current-display-table, etc. */
5289 if (!NILP (w->buffer))
5290 {
5291 /* Save w's value of point in the window configuration.
5292 If w is the selected window, then get the value of point
5293 from the buffer; pointm is garbage in the selected window. */
5294 if (EQ (window, Fselected_window (Qnil)))
5295 {
5296 p->pointm = noseeum_make_marker ();
5297 Fset_marker (p->pointm,
5298 make_int (BUF_PT (XBUFFER (w->buffer))),
5299 w->buffer);
5300 }
5301 else
5302 p->pointm = noseeum_copy_marker (w->pointm[CURRENT_DISP], Qnil);
5303
5304 p->start = noseeum_copy_marker (w->start[CURRENT_DISP], Qnil);
5305 p->sb_point = noseeum_copy_marker (w->sb_point, Qnil);
5306 p->start_at_line_beg = w->start_at_line_beg;
5307
5308 p->mark = noseeum_copy_marker (XBUFFER (w->buffer)->mark, Qnil);
5309 }
5310 else
5311 {
5312 p->pointm = Qnil;
5313 p->start = Qnil;
5314 p->sb_point = Qnil;
5315 p->mark = Qnil;
5316 p->start_at_line_beg = 0;
5317 }
5318
5319 if (NILP (w->parent))
5320 p->parent_index = -1;
5321 else
5322 p->parent_index = saved_window_index (w->parent, config, i);
5323 if (NILP (w->prev))
5324 p->prev_index = -1;
5325 else
5326 p->prev_index = saved_window_index (w->prev, config, i);
5327 p->dedicated = w->dedicated;
5328 if (!NILP (w->vchild))
5329 i = save_window_save (w->vchild, config, i);
5330 if (!NILP (w->hchild))
5331 i = save_window_save (w->hchild, config, i);
5332 }
5333
5334 return i;
5335 }
5336
5337 #if 0 /* FSFmacs */
5338 /* Added to doc string:
5339
5340 This also records the currently selected frame, and FRAME's focus
5341 redirection (see `redirect-frame-focus').
5342
5343 */
5344 #endif
5345
5346 DEFUN ("current-window-configuration",
5347 Fcurrent_window_configuration, Scurrent_window_configuration, 0, 1, 0 /*
5348 Return an object representing the current window configuration of FRAME.
5349 If FRAME is nil or omitted, use the selected frame.
5350 This describes the number of windows, their sizes and current buffers,
5351 and for each displayed buffer, where display starts, and the positions of
5352 point and mark. An exception is made for point in the current buffer:
5353 its value is -not- saved.
5354 */ )
5355 (frame)
5356 Lisp_Object frame;
5357 {
5358 Lisp_Object result = Qnil;
5359 struct frame *f;
5360 int n_windows;
5361
5362 struct window_config *config;
5363
5364 f = decode_frame (frame);
5365
5366 n_windows = count_windows (XWINDOW (FRAME_ROOT_WINDOW (f)));
5367 if (n_windows <= countof (Vwindow_configuration_free_list))
5368 config =
5369 XWINDOW_CONFIGURATION (allocate_managed_lcrecord
5370 (Vwindow_configuration_free_list
5371 [n_windows - 1]));
5372 else
5373 /* More than ten windows; just allocate directly */
5374 config = alloc_lcrecord (sizeof_window_config_for_n_windows (n_windows),
5375 lrecord_window_configuration);
5376 XSETWINDOW_CONFIGURATION (result, config);
5377
5378 config->frame_width = FRAME_WIDTH (f);
5379 config->frame_height = FRAME_HEIGHT (f);
5380 config->current_window = FRAME_SELECTED_WINDOW (f);
5381 XSETBUFFER (config->current_buffer, current_buffer);
5382 config->minibuf_scroll_window = Vminibuf_scroll_window;
5383 config->root_window = FRAME_ROOT_WINDOW (f);
5384 config->min_height = window_min_height;
5385 config->min_width = window_min_width;
5386 config->saved_windows_count = n_windows;
5387 #ifdef ENERGIZE
5388 {
5389 config->p_sheet_buffer = desired_psheet_buffer (f);
5390 if (ZEROP (config->p_sheet_buffer)) /* #### necessaryp? */
5391 config->p_sheet_buffer = Qnil;
5392 }
5393 #endif
5394 save_window_save (FRAME_ROOT_WINDOW (f), config, 0);
5395 return (result);
5396 }
5397
5398 Lisp_Object
5399 save_window_excursion_unwind (Lisp_Object window_config)
5400 {
5401 Lisp_Object val = Fset_window_configuration (window_config);
5402 free_window_configuration (window_config);
5403 return val;
5404 }
5405
5406 DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion,
5407 0, UNEVALLED, 0 /*
5408 Execute body, preserving window sizes and contents.
5409 Restores which buffer appears in which window, where display starts,
5410 as well as the current buffer.
5411 Does not restore the value of point in current buffer.
5412 */ )
5413 (args)
5414 Lisp_Object args;
5415 {
5416 /* This function can GC */
5417 Lisp_Object val;
5418 int speccount = specpdl_depth ();
5419
5420 record_unwind_protect (save_window_excursion_unwind,
5421 Fcurrent_window_configuration (Qnil));
5422 val = Fprogn (args);
5423 return unbind_to (speccount, val);
5424 }
5425
5426
5427 #ifdef DEBUG_XEMACS
5428 /* This is short and simple in elisp, but... it was written to debug
5429 problems purely on the C side. That is where we need to call it so
5430 here it is. */
5431 static void
5432 debug_print_window (Lisp_Object window, int level)
5433 {
5434 Lisp_Object child;
5435 int i = level;
5436
5437 child = Fwindow_first_vchild (window);
5438 if (NILP (child))
5439 child = Fwindow_first_hchild (window);
5440
5441 while (i > 0)
5442 {
5443 fprintf (stderr, "\t");
5444 i--;
5445 }
5446
5447 fprintf (stderr, "#<window");
5448 if (!NILP (XWINDOW (window)->buffer) && BUFFERP (XWINDOW (window)->buffer))
5449 {
5450 struct buffer *b = XBUFFER (XWINDOW (window)->buffer);
5451 fprintf (stderr, " on %s", string_data (XSTRING (b->name)));
5452 }
5453 fprintf (stderr, " 0x%x>", XWINDOW (window)->header.uid);
5454
5455 while (!NILP (child))
5456 {
5457 debug_print_window (child, level + 1);
5458 child = Fwindow_next_child (child);
5459 }
5460 }
5461
5462 void debug_print_windows (struct frame *f);
5463 void
5464 debug_print_windows (struct frame *f)
5465 {
5466 debug_print_window (f->root_window, 0);
5467 fprintf (stderr, "\n");
5468 }
5469 #endif /* DEBUG_XEMACS */
5470
5471
5472 /************************************************************************/
5473 /* initialization */
5474 /************************************************************************/
5475
5476 void
5477 syms_of_window (void)
5478 {
5479 defsymbol (&Qwindowp, "windowp");
5480 defsymbol (&Qwindow_live_p, "window-live-p");
5481 defsymbol (&Qwindow_configurationp, "window-configuration-p");
5482 defsymbol (&Qscroll_up, "scroll-up");
5483 defsymbol (&Qscroll_down, "scroll-down");
5484 defsymbol (&Qtemp_buffer_show_hook, "temp-buffer-show-hook");
5485 defsymbol (&Qdisplay_buffer, "display-buffer");
5486
5487 #ifdef MEMORY_USAGE_STATS
5488 defsymbol (&Qface_cache, "face-cache");
5489 defsymbol (&Qglyph_cache, "glyph-cache");
5490 defsymbol (&Qline_start_cache, "line-start-cache");
5491 #ifdef HAVE_SCROLLBARS
5492 defsymbol (&Qscrollbar_instances, "scrollbar-instances");
5493 #endif
5494 defsymbol (&Qother_redisplay, "other-redisplay");
5495 /* Qother in general.c */
5496 #endif
5497
5498 defsubr (&Sselected_window);
5499 defsubr (&Sminibuffer_window);
5500 defsubr (&Swindow_minibuffer_p);
5501 defsubr (&Swindowp);
5502 defsubr (&Swindow_live_p);
5503 defsubr (&Swindow_first_hchild);
5504 defsubr (&Swindow_first_vchild);
5505 defsubr (&Swindow_next_child);
5506 defsubr (&Swindow_previous_child);
5507 defsubr (&Swindow_parent);
5508 defsubr (&Swindow_lowest_p);
5509 defsubr (&Swindow_highest_p);
5510 defsubr (&Swindow_leftmost_p);
5511 defsubr (&Swindow_rightmost_p);
5512 defsubr (&Spos_visible_in_window_p);
5513 defsubr (&Swindow_buffer);
5514 defsubr (&Swindow_frame);
5515 defsubr (&Swindow_height);
5516 defsubr (&Swindow_displayed_height);
5517 defsubr (&Swindow_width);
5518 defsubr (&Swindow_pixel_height);
5519 defsubr (&Swindow_pixel_width);
5520 defsubr (&Swindow_hscroll);
5521 #if 0 /* bogus RMS crock */
5522 defsubr (&Swindow_redisplay_end_trigger);
5523 defsubr (&Sset_window_redisplay_end_trigger);
5524 #endif
5525 defsubr (&Sset_window_hscroll);
5526 defsubr (&Swindow_pixel_edges);
5527 defsubr (&Swindow_point);
5528 defsubr (&Swindow_start);
5529 defsubr (&Swindow_end);
5530 defsubr (&Sset_window_point);
5531 defsubr (&Sset_window_start);
5532 defsubr (&Swindow_dedicated_p);
5533 defsubr (&Sset_window_dedicated_p);
5534 defsubr (&Snext_window);
5535 defsubr (&Sprevious_window);
5536 defsubr (&Snext_vertical_window);
5537 defsubr (&Sother_window);
5538 defsubr (&Sget_lru_window);
5539 defsubr (&Sget_largest_window);
5540 defsubr (&Sget_buffer_window);
5541 defsubr (&Swindow_left_margin_pixel_width);
5542 defsubr (&Swindow_right_margin_pixel_width);
5543 defsubr (&Sdelete_other_windows);
5544 defsubr (&Sdelete_windows_on);
5545 defsubr (&Sreplace_buffer_in_windows);
5546 defsubr (&Sdelete_window);
5547 defsubr (&Sset_window_buffer);
5548 defsubr (&Sselect_window);
5549 defsubr (&Ssplit_window);
5550 defsubr (&Senlarge_window);
5551 defsubr (&Sshrink_window);
5552 defsubr (&Sscroll_up);
5553 defsubr (&Sscroll_down);
5554 defsubr (&Sscroll_left);
5555 defsubr (&Sscroll_right);
5556 defsubr (&Sother_window_for_scrolling);
5557 defsubr (&Sscroll_other_window);
5558 defsubr (&Srecenter);
5559 defsubr (&Smove_to_window_line);
5560 #ifdef MEMORY_USAGE_STATS
5561 defsubr (&Swindow_memory_usage);
5562 #endif
5563 defsubr (&Swindow_configuration_p);
5564 defsubr (&Sset_window_configuration);
5565 defsubr (&Scurrent_window_configuration);
5566 defsubr (&Ssave_window_excursion);
5567 }
5568
5569 void
5570 vars_of_window (void)
5571 {
5572 /* Make sure all windows get marked */
5573 minibuf_window = Qnil;
5574 staticpro (&minibuf_window);
5575
5576 DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /*
5577 *Non-nil means to scroll if point lands on a line which is clipped.
5578 */ );
5579 scroll_on_clipped_lines = 1;
5580
5581 DEFVAR_LISP ("temp-buffer-show-hook", &Vtemp_buffer_show_hook /*
5582 See `temp-buffer-show-function'.
5583 */ );
5584 Vtemp_buffer_show_hook = Qnil;
5585
5586 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function /*
5587 Non-nil means call as function to display a help buffer.
5588 The function is called with one argument, the buffer to be displayed.
5589 Used by `with-output-to-temp-buffer'.
5590 If this function is used, then it must do the entire job of showing
5591 the buffer; `temp-buffer-show-hook' is not run unless this function runs it.
5592 */ );
5593 Vtemp_buffer_show_function = Qnil;
5594
5595 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window /*
5596 Non-nil means it is the window that \\<minibuffer-local-map>\\[scroll-other-window] in minibuffer should scroll.
5597 */ );
5598 Vminibuf_scroll_window = Qnil;
5599
5600 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer /*
5601 If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window.
5602 */ );
5603 Vother_window_scroll_buffer = Qnil;
5604
5605 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines /*
5606 *Number of lines of continuity when scrolling by screenfuls.
5607 */ );
5608 next_screen_context_lines = 2;
5609
5610 DEFVAR_INT ("window-min-height", &window_min_height /*
5611 *Delete any window less than this tall (including its modeline).
5612 */ );
5613 window_min_height = 4;
5614
5615 DEFVAR_INT ("window-min-width", &window_min_width /*
5616 *Delete any window less than this wide.
5617 */ );
5618 window_min_width = 10;
5619
5620 {
5621 int i;
5622
5623 for (i = 0; i < countof (Vwindow_configuration_free_list); i++)
5624 {
5625 Vwindow_configuration_free_list[i] =
5626 make_lcrecord_list (sizeof_window_config_for_n_windows (i + 1),
5627 lrecord_window_configuration);
5628 staticpro (&Vwindow_configuration_free_list[i]);
5629 }
5630 }
5631 }
5632
5633 void
5634 specifier_vars_of_window (void)
5635 {
5636 DEFVAR_SPECIFIER ("modeline-shadow-thickness", &Vmodeline_shadow_thickness /*
5637 *How thick to draw 3D shadows around modelines.
5638 If this is set to 0, modelines will be the traditional 2D. Sizes above
5639 10 will be accepted but the maximum thickness that will be drawn is 10.
5640 This is a specifier; use `set-specifier' to change it.
5641 */ );
5642 Vmodeline_shadow_thickness = Fmake_specifier (Qinteger);
5643 /* The initial value for modeline-shadow-thickness is 2, but if the
5644 user removes all specifications we provide a fallback value of 0,
5645 which is probably what was expected. */
5646 set_specifier_fallback (Vmodeline_shadow_thickness,
5647 list1 (Fcons (Qnil, Qzero)));
5648 Fadd_spec_to_specifier (Vmodeline_shadow_thickness, make_int (2),
5649 Qnil, Qnil, Qnil);
5650 set_specifier_caching (Vmodeline_shadow_thickness,
5651 slot_offset (struct window,
5652 modeline_shadow_thickness),
5653 modeline_shadow_thickness_changed,
5654 0, 0);
5655
5656 DEFVAR_SPECIFIER ("has-modeline-p", &Vhas_modeline_p /*
5657 *Whether the modeline should be displayed.
5658 This is a specifier; use `set-specifier' to change it.
5659 */ );
5660 Vhas_modeline_p = Fmake_specifier (Qboolean);
5661 set_specifier_fallback (Vhas_modeline_p,
5662 list1 (Fcons (Qnil, Qt)));
5663 set_specifier_caching (Vhas_modeline_p,
5664 slot_offset (struct window,
5665 has_modeline_p),
5666 /* #### It's strange that we need a special
5667 flag to indicate that the shadow-thickness
5668 has changed, but not one to indicate that
5669 the modeline has been turned off or on. */
5670 some_window_value_changed,
5671 0, 0);
5672 }