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