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