Mercurial > hg > xemacs-beta
annotate src/window.c @ 5090:0ca81354c4c7
Further frame-geometry cleanups
-------------------- ChangeLog entries follow: --------------------
man/ChangeLog addition:
2010-03-03 Ben Wing <ben@xemacs.org>
* internals/internals.texi (Intro to Window and Frame Geometry):
* internals/internals.texi (The Paned Area):
* internals/internals.texi (The Displayable Area):
Update to make note of e.g. the fact that the bottom gutter is
actually above the minibuffer.
src/ChangeLog addition:
2010-03-03 Ben Wing <ben@xemacs.org>
* emacs.c:
* emacs.c (assert_equal_failed):
* lisp.h:
* lisp.h (assert_equal):
New fun assert_equal, asserting that two values == each other, and
printing out both values upon failure.
* frame-gtk.c (gtk_initialize_frame_size):
* frame-impl.h:
* frame-impl.h (FRAME_TOP_INTERNAL_BORDER_START):
* frame-impl.h (FRAME_BOTTOM_INTERNAL_BORDER_START):
* frame-impl.h (FRAME_LEFT_INTERNAL_BORDER_START):
* frame-impl.h (FRAME_PANED_TOP_EDGE):
* frame-impl.h (FRAME_NONPANED_SIZE):
* frame-x.c (x_initialize_frame_size):
* frame.c:
* gutter.c (get_gutter_coords):
* gutter.c (calculate_gutter_size):
* gutter.h:
* gutter.h (WINDOW_REAL_TOP_GUTTER_BOUNDS):
* gutter.h (FRAME_TOP_GUTTER_BOUNDS):
* input-method-xlib.c:
* input-method-xlib.c (XIM_SetGeometry):
* redisplay-output.c (clear_left_border):
* redisplay-output.c (clear_right_border):
* redisplay-output.c (redisplay_output_pixmap):
* redisplay-output.c (redisplay_clear_region):
* redisplay-output.c (redisplay_clear_top_of_window):
* redisplay-output.c (redisplay_clear_to_window_end):
* redisplay-xlike-inc.c (XLIKE_clear_frame):
* redisplay.c:
* redisplay.c (UPDATE_CACHE_RETURN):
* redisplay.c (pixel_to_glyph_translation):
* toolbar.c (update_frame_toolbars_geometry):
* window.c (Fwindow_pixel_edges):
Get rid of some redundant macros. Consistently use the
FRAME_TOP_*_START, FRAME_RIGHT_*_END, etc. format. Rename
FRAME_*_BORDER_* to FRAME_*_INTERNAL_BORDER_*. Comment out
FRAME_BOTTOM_* for gutters and the paned area due to the
uncertainty over where the paned area actually begins. (Eventually
we should probably move the gutters outside the minibuffer so that
the paned area is contiguous.) Use FRAME_PANED_* more often in the
code to make things clearer.
Update the diagram to show that the bottom gutter is inside the
minibuffer (!) and that there are "junk boxes" when you have left
and/or right gutters (dead boxes that are mistakenly left uncleared,
unlike the corresponding scrollbar dead boxes). Update the text
appropriately to cover the bottom gutter position, etc.
Rewrite gutter-geometry code to use the FRAME_*_GUTTER_* in place of
equivalent expressions referencing other frame elements, to make the
code more portable in case we move around the gutter location.
Cleanup FRAME_*_GUTTER_BOUNDS() in gutter.h.
Add some #### GEOM! comments where I think code is incorrect --
typically, it wasn't fixed up properly when the gutter was added.
Some cosmetic changes.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Wed, 03 Mar 2010 05:07:47 -0600 |
parents | 92dc90c0bb40 |
children | 7be849cb8828 |
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. | |
5043 | 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 | |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
1178 default_face_width_and_height (window, &font_width, 0); |
428 | 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 | |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
1661 default_face_width_and_height (window, NULL, &defheight); |
428 | 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 | |
5090 | 1816 int left = w->pixel_left - FRAME_PANED_LEFT_EDGE (f); |
1817 int top = w->pixel_top - FRAME_PANED_TOP_EDGE (f); | |
428 | 1818 |
1819 return list4 (make_int (left), | |
1820 make_int (top), | |
1821 make_int (left + w->pixel_width), | |
1822 make_int (top + w->pixel_height)); | |
1823 } | |
1824 | |
1825 DEFUN ("window-text-area-pixel-edges", | |
1826 Fwindow_text_area_pixel_edges, 0, 1, 0, /* | |
1827 Return a list of the pixel edge coordinates of the text area of WINDOW. | |
444 | 1828 The returned list is of the form (LEFT TOP RIGHT BOTTOM), |
1829 all relative to 0, 0 at the top left corner of the total area allocated | |
1830 to the window, which includes the scrollbars. | |
428 | 1831 */ |
1832 (window)) | |
1833 { | |
1834 struct window *w = decode_window (window); | |
1835 | |
1836 int left = window_left_gutter_width (w, /* modeline = */ 0); | |
1837 int top = window_top_gutter_height (w); | |
1838 int right = WINDOW_WIDTH (w) - window_right_gutter_width (w, 0); | |
1839 int bottom = WINDOW_HEIGHT (w) - window_bottom_gutter_height (w); | |
1840 | |
1841 return list4 (make_int (left), | |
1842 make_int (top), | |
1843 make_int (right), | |
1844 make_int (bottom)); | |
1845 } | |
1846 | |
1847 DEFUN ("window-point", Fwindow_point, 0, 1, 0, /* | |
1848 Return current value of point in WINDOW. | |
442 | 1849 For a non-selected window, this is the value point would have |
428 | 1850 if that window were selected. |
1851 | |
1852 Note that, when WINDOW is the selected window and its buffer | |
1853 is also currently selected, the value returned is the same as (point). | |
1854 It would be more strictly correct to return the `top-level' value | |
1855 of point, outside of any save-excursion forms. | |
444 | 1856 But that value is hard to find. |
428 | 1857 */ |
1858 (window)) | |
1859 { | |
1860 struct window *w = decode_window (window); | |
1861 | |
1862 /* The special check for current buffer is necessary for this | |
1863 function to work as defined when called within an excursion. */ | |
1864 if (w == XWINDOW (Fselected_window (XFRAME (w->frame)->device)) | |
1865 && current_buffer == XBUFFER (w->buffer)) | |
1866 return Fpoint (Qnil); | |
1867 return Fmarker_position (w->pointm[CURRENT_DISP]); | |
1868 } | |
1869 | |
1870 DEFUN ("window-start", Fwindow_start, 0, 1, 0, /* | |
1871 Return position at which display currently starts in WINDOW. | |
1872 This is updated by redisplay or by calling `set-window-start'. | |
1873 */ | |
1874 (window)) | |
1875 { | |
1876 return Fmarker_position (decode_window (window)->start[CURRENT_DISP]); | |
1877 } | |
1878 | |
1879 DEFUN ("window-end", Fwindow_end, 0, 2, 0, /* | |
1880 Return position at which display currently ends in WINDOW. | |
1881 This is updated by redisplay, when it runs to completion. | |
444 | 1882 Simply changing the buffer text or setting `window-start' does not |
1883 update this value. WINDOW defaults to the selected window. | |
1884 | |
1885 If optional arg GUARANTEE is non-nil, the return value is guaranteed | |
1886 to be the same value as this function would return at the end of the | |
1887 next full redisplay assuming nothing else changes in the meantime. | |
1888 This function is potentially much slower with this flag set. | |
428 | 1889 */ |
1890 (window, guarantee)) | |
1891 { | |
1892 struct window *w = decode_window (window); | |
1893 | |
1894 if (NILP (guarantee)) | |
1895 { | |
1896 Lisp_Object buf; | |
1897 buf = w->buffer; | |
1898 CHECK_BUFFER (buf); | |
1899 return make_int (BUF_Z (XBUFFER (buf)) - w->window_end_pos[CURRENT_DISP]); | |
1900 } | |
1901 else | |
1902 { | |
665 | 1903 Charbpos startp = marker_position (w->start[CURRENT_DISP]); |
428 | 1904 return make_int (end_of_last_line (w, startp)); |
1905 } | |
1906 } | |
1907 | |
442 | 1908 DEFUN ("window-last-line-visible-height", Fwindow_last_line_visible_height, 0, 1, 0, /* |
1909 Return pixel height of visible part of last window line if it is clipped. | |
1910 If the last line is not clipped, return nil. | |
1911 */ | |
1912 (window)) | |
1913 { | |
1914 struct window *w = decode_window (window); | |
1915 display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP); | |
1916 int num_lines = Dynarr_length (dla); | |
1917 struct display_line *dl; | |
1918 | |
1919 /* No lines - no clipped lines */ | |
4967 | 1920 if (num_lines == 0 || (num_lines == 1 && Dynarr_begin (dla)->modeline)) |
442 | 1921 return Qnil; |
1922 | |
1923 dl = Dynarr_atp (dla, num_lines - 1); | |
1924 if (dl->clip == 0) | |
1925 return Qnil; | |
1926 | |
1927 return make_int (dl->ascent + dl->descent - dl->clip); | |
1928 } | |
1929 | |
428 | 1930 DEFUN ("set-window-point", Fset_window_point, 2, 2, 0, /* |
1931 Make point value in WINDOW be at position POS in WINDOW's buffer. | |
1161 | 1932 If WINDOW is the selected window, and window's buffer is the current |
1933 buffer, this actually changes the buffer's point instead of the window's | |
1934 point. (The equivalence of the selected window's point with its buffer's | |
1935 point is maintained throughout XEmacs. However, enforcing the additional | |
1936 restriction on the current buffer is "bug compatible" with FSF and is | |
1937 perhaps more logical.) | |
428 | 1938 */ |
1939 (window, pos)) | |
1940 { | |
1941 struct window *w = decode_window (window); | |
1942 | |
1943 CHECK_INT_COERCE_MARKER (pos); | |
1161 | 1944 |
844 | 1945 /* Don't dereference selected-window because there may not |
1946 be one -- e.g. at startup */ | |
1161 | 1947 if (EQ (wrap_window (w), Fselected_window (Qnil)) |
1948 && EQ (w->buffer, Fcurrent_buffer ())) | |
1949 Fgoto_char (pos, Qnil); | |
428 | 1950 else |
1951 set_marker_restricted (w->pointm[CURRENT_DISP], pos, w->buffer); | |
1952 | |
1953 MARK_POINT_CHANGED; | |
1954 return pos; | |
1955 } | |
1956 | |
1957 DEFUN ("set-window-start", Fset_window_start, 2, 3, 0, /* | |
1958 Make display in WINDOW start at position POS in WINDOW's buffer. | |
1959 Optional third arg NOFORCE non-nil inhibits next redisplay | |
1960 from overriding motion of point in order to display at this exact start. | |
1961 */ | |
1962 (window, pos, noforce)) | |
1963 { | |
1964 struct window *w = decode_window (window); | |
1965 | |
1966 CHECK_INT_COERCE_MARKER (pos); | |
1967 set_marker_restricted (w->start[CURRENT_DISP], pos, w->buffer); | |
1968 /* this is not right, but much easier than doing what is right. */ | |
1969 /* w->start_at_line_beg = 0; */ | |
1970 /* WTF is the above supposed to mean? GE */ | |
1971 w->start_at_line_beg = beginning_of_line_p (XBUFFER (w->buffer), | |
1972 marker_position (w->start[CURRENT_DISP])); | |
1973 if (NILP (noforce)) | |
1974 w->force_start = 1; | |
1975 w->redo_modeline = 1; | |
1976 SET_LAST_MODIFIED (w, 0); | |
1977 SET_LAST_FACECHANGE (w); | |
1978 | |
1979 MARK_WINDOWS_CHANGED (w); | |
1980 | |
1981 return pos; | |
1982 } | |
1983 | |
1984 DEFUN ("window-dedicated-p", Fwindow_dedicated_p, 1, 1, 0, /* | |
1985 Return WINDOW's dedicated object, usually t or nil. | |
1986 See also `set-window-dedicated-p'. | |
1987 */ | |
1988 (window)) | |
1989 { | |
1990 return decode_window (window)->dedicated; | |
1991 } | |
1992 | |
1993 DEFUN ("set-window-dedicated-p", Fset_window_dedicated_p, 2, 2, 0, /* | |
1994 Control whether WINDOW is dedicated to the buffer it displays. | |
1995 If it is dedicated, Emacs will not automatically change | |
1996 which buffer appears in it. | |
1997 The second argument is the new value for the dedication flag; | |
1998 non-nil means yes. | |
1999 */ | |
2000 (window, arg)) | |
2001 { | |
2002 struct window *w = decode_window (window); | |
2003 | |
2004 w->dedicated = NILP (arg) ? Qnil : Qt; | |
2005 | |
2006 return w->dedicated; | |
2007 } | |
2008 | |
2009 /* FSFmacs has window-display-table here. We have display table as a | |
2010 specifier. */ | |
2011 | |
2012 | |
2013 /* Record info on buffer window w is displaying | |
2014 when it is about to cease to display that buffer. */ | |
2015 static void | |
2016 unshow_buffer (struct window *w) | |
2017 { | |
2018 Lisp_Object buf = w->buffer; | |
844 | 2019 struct buffer *b = XBUFFER (buf); |
2020 | |
5050
6f2158fa75ed
Fix quick-build, use asserts() in place of ABORT()
Ben Wing <ben@xemacs.org>
parents:
4967
diff
changeset
|
2021 assert (b == XMARKER (w->pointm[CURRENT_DISP])->buffer); |
428 | 2022 |
2023 /* FSF disables this check, so I'll do it too. I hope it won't | |
2024 break things. --ben */ | |
2025 #if 0 | |
2026 if (w == XWINDOW (Fselected_window (Qnil)) | |
2027 || ! EQ (buf, XWINDOW (Fselected_window (Qnil))->buffer)) | |
2028 /* Do this except when the selected window's buffer | |
2029 is being removed from some other window. */ | |
2030 #endif | |
2031 /* last_window_start records the start position that this buffer | |
2032 had in the last window to be disconnected from it. | |
2033 Now that this statement is unconditional, | |
2034 it is possible for the buffer to be displayed in the | |
2035 selected window, while last_window_start reflects another | |
2036 window which was recently showing the same buffer. | |
2037 Some people might say that might be a good thing. Let's see. */ | |
2038 XBUFFER (buf)->last_window_start = | |
2039 marker_position (w->start[CURRENT_DISP]); | |
2040 | |
2041 /* Point in the selected window's buffer | |
2042 is actually stored in that buffer, and the window's pointm isn't used. | |
2043 So don't clobber point in that buffer. */ | |
2044 if (! EQ (buf, XWINDOW (Fselected_window (Qnil))->buffer)) | |
844 | 2045 BUF_SET_PT (b, |
2046 charbpos_clip_to_bounds | |
2047 (BUF_BEGV (b), | |
2048 marker_position (w->pointm[CURRENT_DISP]), | |
2049 BUF_ZV (b))); | |
2050 | |
2051 { | |
2052 Lisp_Object marker = Fgethash (buf, w->saved_point_cache, Qnil); | |
2053 int selected = EQ (wrap_window (w), Fselected_window (Qnil)); | |
2054 | |
2055 if (NILP (marker)) | |
2056 { | |
2057 marker = Fmake_marker (); | |
2058 Fputhash (buf, marker, w->saved_point_cache); | |
2059 } | |
2060 Fset_marker (marker, | |
2061 selected ? make_int (BUF_PT (b)) : w->pointm[CURRENT_DISP], | |
2062 buf); | |
2063 | |
2064 marker = Fgethash (buf, w->saved_last_window_start_cache, Qnil); | |
2065 | |
2066 if (NILP (marker)) | |
2067 { | |
2068 marker = Fmake_marker (); | |
2069 Fputhash (buf, marker, w->saved_last_window_start_cache); | |
2070 } | |
2071 Fset_marker (marker, w->start[CURRENT_DISP], buf); | |
2072 } | |
428 | 2073 } |
2074 | |
2075 /* Put REPLACEMENT into the window structure in place of OLD. */ | |
2076 static void | |
2077 replace_window (Lisp_Object old, Lisp_Object replacement) | |
2078 { | |
2079 Lisp_Object tem; | |
2080 struct window *o = XWINDOW (old), *p = XWINDOW (replacement); | |
2081 | |
2082 /* If OLD is its frame's root_window, then replacement is the new | |
2083 root_window for that frame. */ | |
2084 | |
2085 if (EQ (old, FRAME_ROOT_WINDOW (XFRAME (o->frame)))) | |
2086 FRAME_ROOT_WINDOW (XFRAME (o->frame)) = replacement; | |
2087 | |
2088 WINDOW_LEFT (p) = WINDOW_LEFT (o); | |
2089 WINDOW_TOP (p) = WINDOW_TOP (o); | |
2090 WINDOW_WIDTH (p) = WINDOW_WIDTH (o); | |
2091 WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o); | |
2092 | |
2093 p->next = tem = o->next; | |
2094 if (!NILP (tem)) | |
2095 XWINDOW (tem)->prev = replacement; | |
2096 | |
2097 p->prev = tem = o->prev; | |
2098 if (!NILP (tem)) | |
2099 XWINDOW (tem)->next = replacement; | |
2100 | |
2101 p->parent = tem = o->parent; | |
2102 if (!NILP (tem)) | |
2103 { | |
2104 if (EQ (XWINDOW (tem)->vchild, old)) | |
2105 XWINDOW (tem)->vchild = replacement; | |
2106 if (EQ (XWINDOW (tem)->hchild, old)) | |
2107 XWINDOW (tem)->hchild = replacement; | |
2108 } | |
2109 | |
2110 /* #### Here, if replacement is a vertical combination | |
2111 and so is its new parent, we should make replacement's | |
2112 children be children of that parent instead. */ | |
442 | 2113 |
2114 ERROR_CHECK_SUBWINDOW_CACHE (p); | |
2115 } | |
2116 | |
2117 static void | |
2118 window_unmap_subwindows (struct window* w) | |
2119 { | |
2120 assert (!NILP (w->subwindow_instance_cache)); | |
2121 elisp_maphash (unmap_subwindow_instance_cache_mapper, | |
2122 w->subwindow_instance_cache, (void*)1); | |
428 | 2123 } |
2124 | |
2125 /* we're deleting W; set the structure of W to indicate this. */ | |
2126 | |
2127 static void | |
2128 mark_window_as_deleted (struct window *w) | |
2129 { | |
442 | 2130 /* The window instance cache is going away now, so need to get the |
2131 cachels reset by redisplay. */ | |
2132 MARK_FRAME_SUBWINDOWS_CHANGED (XFRAME (WINDOW_FRAME (w))); | |
2133 | |
2134 /* The cache is going away. If we leave unmapping to | |
2135 reset_subwindow_cachels then we get in a situation where the | |
2136 domain (the window) has been deleted but we still need access to | |
2137 its attributes in order to unmap windows properly. Since the | |
2138 subwindows are going to get GC'd anyway as a result of the domain | |
2139 going away, it is safer to just unmap them all while we know the | |
2140 domain is still valid. */ | |
2141 ERROR_CHECK_SUBWINDOW_CACHE (w); | |
2142 window_unmap_subwindows (w); | |
2143 | |
617 | 2144 /* Free the extra data structures attached to windows immediately so |
2145 they don't sit around consuming excess space. They will be | |
2146 reinitialized by the window-configuration code as necessary. */ | |
2147 finalize_window ((void *) w, 0); | |
2148 | |
1149 | 2149 /* Nobody should be accessing anything in this object any more, |
618 | 2150 and making them Qnil allows for better GC'ing in case a pointer |
2151 to the dead window continues to hang around. Zero all other | |
2152 structs in case someone tries to access something through them. | |
2153 | |
2154 (So, in point of fact, we zero out all of the "saved" slots, | |
2155 which are obviously restored from the window config, plus the | |
2156 slots which were already zeroed.) | |
617 | 2157 |
2158 As an example of why setting the values to Qnil is good, here | |
2159 is an old comment: | |
2160 | |
2161 In the loop | |
428 | 2162 (while t (split-window) (delete-window)) |
2163 we end up with a tree of deleted windows which are all connected | |
2164 through the `next' slot. This might not seem so bad, as they're | |
2165 deleted, and will presumably be GCed - but if even *one* of those | |
2166 windows is still being pointed to, by the user, or by a window | |
1149 | 2167 configuration, then *all* of those windows stick around. */ |
617 | 2168 |
618 | 2169 #define WINDOW_SLOT(slot) |
2170 #define WINDOW_SAVED_SLOT(slot, compare) w->slot = Qnil; | |
617 | 2171 #include "winslots.h" |
428 | 2172 |
618 | 2173 w->next = Qnil; |
2174 w->prev = Qnil; | |
2175 w->hchild = Qnil; | |
2176 w->vchild = Qnil; | |
2177 w->parent = Qnil; | |
2178 w->subwindow_instance_cache = Qnil; | |
2179 | |
428 | 2180 w->dead = 1; |
853 | 2181 note_object_deleted (wrap_window (w)); |
428 | 2182 } |
2183 | |
1207 | 2184 /* Check if window contains pwindow. */ |
2185 | |
2186 static int | |
2187 contains_window (Lisp_Object window, Lisp_Object pwindow) | |
2188 { | |
2189 while (!NILP (pwindow)) | |
2190 { | |
2191 if (EQ (window, pwindow)) | |
2192 return 1; | |
2193 pwindow = XWINDOW (pwindow)->parent; | |
2194 } | |
2195 return 0; | |
2196 } | |
2197 | |
428 | 2198 DEFUN ("delete-window", Fdelete_window, 0, 2, "", /* |
2199 Remove WINDOW from the display. Default is selected window. | |
444 | 2200 If window is the only one on its frame, the frame is deleted as well. |
428 | 2201 Normally, you cannot delete the last non-minibuffer-only frame (you must |
2202 use `save-buffers-kill-emacs' or `kill-emacs'). However, if optional | |
2203 second argument FORCE is non-nil, you can delete the last frame. (This | |
2204 will automatically call `save-buffers-kill-emacs'.) | |
2205 */ | |
2206 (window, force)) | |
2207 { | |
2208 /* This function can GC if this is the only window in the frame */ | |
2209 struct window *w; | |
2210 Lisp_Object parent; | |
2211 struct window *par; | |
2212 Lisp_Object frame; | |
2213 struct frame *f; | |
2214 struct device *d; | |
2215 | |
2216 /* Note: this function is called by other C code on non-leaf | |
2217 windows. */ | |
2218 | |
2219 /* Do the equivalent of decode_window() but don't error out on | |
2220 deleted window; it's OK to delete an already-deleted window. */ | |
2221 if (NILP (window)) | |
2222 window = Fselected_window (Qnil); | |
2223 else | |
2224 CHECK_WINDOW (window); | |
442 | 2225 |
428 | 2226 w = XWINDOW (window); |
2227 | |
2228 /* It's okay to delete an already-deleted window. */ | |
2229 if (! WINDOW_LIVE_P (w)) | |
2230 return Qnil; | |
2231 | |
853 | 2232 check_allowed_operation (OPERATION_DELETE_OBJECT, window, Qnil); |
2233 | |
428 | 2234 frame = WINDOW_FRAME (w); |
2235 f = XFRAME (frame); | |
2236 d = XDEVICE (FRAME_DEVICE (f)); | |
2237 | |
2238 if (TOP_LEVEL_WINDOW_P (w)) | |
2239 { | |
2240 if (NILP (memq_no_quit (frame, DEVICE_FRAME_LIST (d)))) | |
2241 /* this frame isn't fully initialized yet; don't blow up. */ | |
2242 return Qnil; | |
2243 | |
2244 if (MINI_WINDOW_P (XWINDOW (window))) | |
563 | 2245 signal_error (Qinvalid_operation, "Attempt to delete the minibuffer window", Qunbound); |
428 | 2246 |
2247 /* It has been suggested that it's a good thing for C-x 0 to have this | |
2248 behavior, but not such a good idea for #'delete-window to have it. | |
2249 Maybe C-x 0 should be bound to something else, or maybe frame | |
2250 deletion should only happen when this is called interactively. | |
2251 */ | |
2252 delete_frame_internal (f, !NILP (force), 0, 0); | |
2253 return Qnil; | |
2254 } | |
2255 | |
2256 /* At this point, we know the window has a parent. */ | |
2257 parent = w->parent; | |
2258 par = XWINDOW (parent); | |
2259 | |
2260 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); | |
430 | 2261 /* It's quite likely that deleting a window will result in |
2262 subwindows needing to be deleted also (since they are cached | |
2263 per-window). So we mark them as changed, so that the cachels will | |
2264 get reset by redisplay and thus deleted subwindows can get | |
2265 GC'd. */ | |
2266 MARK_FRAME_SUBWINDOWS_CHANGED (f); | |
428 | 2267 |
2268 /* Are we trying to delete any frame's selected window? | |
2269 Note that we could be dealing with a non-leaf window | |
2270 where the selected window is one of our children. | |
2271 So, we check by scanning all the ancestors of the | |
2272 frame's selected window and comparing each one with | |
2273 WINDOW. */ | |
1207 | 2274 if (contains_window (window, FRAME_SELECTED_WINDOW (f))) |
2275 { | |
2276 Lisp_Object alternative; | |
2277 alternative = Fnext_window (window, Qlambda, Qnil, Qnil); | |
2278 | |
2279 /* #### */ | |
2280 /* If we're about to delete the selected window on the | |
2281 selected frame, then we should use Fselect_window to select | |
2282 the new window. On the other hand, if we're about to | |
2283 delete the selected window on any other frame, we shouldn't do | |
2284 anything but set the frame's selected_window slot. */ | |
2285 if (EQ (frame, Fselected_frame (Qnil))) | |
2286 Fselect_window (alternative, Qnil); | |
2287 else | |
2288 set_frame_selected_window (f, alternative); | |
2289 } | |
2290 | |
2291 /* Some display parameters (gutter display specifically) depend on | |
2292 FRAME_LAST_NONMINIBUF (f) to be set to a live window. Ensure that. */ | |
2293 if (contains_window (window, FRAME_LAST_NONMINIBUF_WINDOW (f))) | |
2294 f->last_nonminibuf_window = Fnext_window (window, Qlambda, Qnil, Qnil); | |
428 | 2295 |
2296 /* w->buffer is nil in a non-leaf window; in this case, | |
2297 get rid of the markers we maintain that point into that buffer. */ | |
2298 if (!NILP (w->buffer)) | |
2299 { | |
2300 unshow_buffer (w); | |
2301 unchain_marker (w->pointm[CURRENT_DISP]); | |
2302 unchain_marker (w->pointm[DESIRED_DISP]); | |
2303 unchain_marker (w->pointm[CMOTION_DISP]); | |
2304 unchain_marker (w->start[CURRENT_DISP]); | |
2305 unchain_marker (w->start[DESIRED_DISP]); | |
2306 unchain_marker (w->start[CMOTION_DISP]); | |
2307 unchain_marker (w->sb_point); | |
1149 | 2308 w->buffer = Qnil; |
428 | 2309 } |
2310 | |
2311 /* close up the hole in the sibling list */ | |
2312 if (!NILP (w->next)) | |
2313 XWINDOW (w->next)->prev = w->prev; | |
2314 if (!NILP (w->prev)) | |
2315 XWINDOW (w->prev)->next = w->next; | |
2316 if (EQ (window, par->hchild)) | |
2317 par->hchild = w->next; | |
2318 if (EQ (window, par->vchild)) | |
2319 par->vchild = w->next; | |
2320 | |
2321 /* Find one of our siblings to give our space to. */ | |
2322 { | |
2323 Lisp_Object sib = w->prev; | |
2324 if (NILP (sib)) | |
2325 { | |
2326 /* If w gives its space to its next sibling, that sibling needs | |
2327 to have its top/left side pulled back to where w's is. | |
2328 set_window_{height,width} will re-position the sibling's | |
2329 children. */ | |
2330 sib = w->next; | |
2331 WINDOW_TOP (XWINDOW (sib)) = WINDOW_TOP (w); | |
2332 WINDOW_LEFT (XWINDOW (sib)) = WINDOW_LEFT (w); | |
2333 } | |
2334 | |
2335 /* Stretch that sibling. */ | |
2336 if (!NILP (par->vchild)) | |
2337 set_window_pixheight | |
2338 (sib, (WINDOW_HEIGHT (XWINDOW (sib)) + WINDOW_HEIGHT (w)), 1); | |
2339 if (!NILP (par->hchild)) | |
2340 set_window_pixwidth | |
2341 (sib, (WINDOW_WIDTH (XWINDOW (sib)) + WINDOW_WIDTH (w)), 1); | |
2342 } | |
2343 | |
2344 /* If parent now has only one child, | |
2345 put the child into the parent's place. */ | |
2346 { | |
2347 Lisp_Object parchild = par->hchild; | |
2348 if (NILP (parchild)) | |
2349 parchild = par->vchild; | |
2350 if (NILP (XWINDOW (parchild)->next)) | |
2351 { | |
2352 replace_window (parent, parchild); | |
2353 mark_window_as_deleted (XWINDOW (parent)); | |
2354 } | |
2355 } | |
2356 | |
2357 /* Since we may be deleting combination windows, we must make sure that | |
2358 not only W but all its children have been marked as deleted. */ | |
2359 if (!NILP (w->hchild)) | |
2360 delete_all_subwindows (XWINDOW (w->hchild)); | |
2361 else if (!NILP (w->vchild)) | |
2362 delete_all_subwindows (XWINDOW (w->vchild)); | |
2363 | |
1752 | 2364 /* Warning: mark_window_as_deleted calls window_unmap_subwindows and |
2365 therefore redisplay, so it requires the mirror structure to be | |
2366 correct. We must dirty the mirror before it is called. */ | |
2367 f->mirror_dirty = 1; | |
2368 | |
428 | 2369 mark_window_as_deleted (w); |
2370 | |
2371 return Qnil; | |
2372 } | |
2373 | |
2374 | |
2375 DEFUN ("next-window", Fnext_window, 0, 4, 0, /* | |
442 | 2376 Return the next window after WINDOW in the canonical ordering of windows. |
428 | 2377 If omitted, WINDOW defaults to the selected window. |
2378 | |
2379 Optional second arg MINIBUF t means count the minibuffer window even | |
2380 if not active. MINIBUF nil or omitted means count the minibuffer iff | |
2381 it is active. MINIBUF neither t nor nil means not to count the | |
2382 minibuffer even if it is active. | |
2383 | |
2384 Several frames may share a single minibuffer; if the minibuffer | |
2385 counts, all windows on all frames that share that minibuffer count | |
2386 too. Therefore, `next-window' can be used to iterate through the | |
2387 set of windows even when the minibuffer is on another frame. If the | |
2388 minibuffer does not count, only windows from WINDOW's frame count. | |
2389 | |
444 | 2390 By default, only the windows in the selected frame are considered. |
2391 The optional argument WHICH-FRAMES changes this behavior: | |
2392 WHICH-FRAMES = `visible' means search windows on all visible frames. | |
448 | 2393 WHICH-FRAMES = 0 means search windows on all visible and iconified frames. |
444 | 2394 WHICH-FRAMES = t means search windows on all frames including invisible frames. |
2395 WHICH-FRAMES = a frame means search only windows on that frame. | |
2396 Anything else means restrict to the selected frame. | |
2397 | |
2398 The optional fourth argument WHICH-DEVICES further clarifies on which | |
2399 devices to search for frames as specified by WHICH-FRAMES. This value | |
2400 is only meaningful if WHICH-FRAMES is non-nil. | |
2401 If nil or omitted, search all devices on the selected console. | |
2402 If a device, only search that device. | |
2403 If a console, search all devices on that console. | |
2404 If a device type, search all devices of that type. | |
2405 If `window-system', search all window-system devices. | |
2406 Any other non-nil value means search all devices. | |
2407 | |
2408 If you use consistent values for MINIBUF, WHICH-FRAMES, and WHICH-DEVICES, | |
2409 you can use `next-window' to iterate through the entire cycle of | |
2410 acceptable windows, eventually ending up back at the window you started with. | |
428 | 2411 `previous-window' traverses the same cycle, in the reverse order. |
2412 */ | |
444 | 2413 (window, minibuf, which_frames, which_devices)) |
428 | 2414 { |
2415 Lisp_Object tem; | |
2416 Lisp_Object start_window; | |
2417 | |
2418 if (NILP (window)) | |
2419 window = Fselected_window (Qnil); | |
2420 else | |
2421 CHECK_LIVE_WINDOW (window); | |
2422 | |
2423 start_window = window; | |
2424 | |
2425 /* minibuf == nil may or may not include minibuffers. | |
2426 Decide if it does. */ | |
2427 if (NILP (minibuf)) | |
2428 minibuf = (minibuf_level ? minibuf_window : Qlambda); | |
2429 else if (! EQ (minibuf, Qt)) | |
2430 minibuf = Qlambda; | |
442 | 2431 /* Now `minibuf' is one of: |
2432 t => count all minibuffer windows | |
2433 lambda => count none of them | |
428 | 2434 or a specific minibuffer window (the active one) to count. */ |
2435 | |
444 | 2436 /* which_frames == nil doesn't specify which frames to include. */ |
2437 if (NILP (which_frames)) | |
2438 which_frames = (! EQ (minibuf, Qlambda) | |
428 | 2439 ? (FRAME_MINIBUF_WINDOW |
2440 (XFRAME | |
2441 (WINDOW_FRAME | |
2442 (XWINDOW (window))))) | |
2443 : Qnil); | |
444 | 2444 else if (EQ (which_frames, Qvisible)) |
428 | 2445 ; |
444 | 2446 else if (ZEROP (which_frames)) |
428 | 2447 ; |
444 | 2448 else if (FRAMEP (which_frames) && ! EQ (which_frames, Fwindow_frame (window))) |
2449 /* If which_frames is a frame and window arg isn't on that frame, just | |
428 | 2450 return the first window on the frame. */ |
444 | 2451 return frame_first_window (XFRAME (which_frames)); |
2452 else if (! EQ (which_frames, Qt)) | |
2453 which_frames = Qnil; | |
2454 /* Now `which_frames' is one of: | |
442 | 2455 t => search all frames |
2456 nil => search just the current frame | |
2457 visible => search just visible frames | |
2458 0 => search visible and iconified frames | |
2459 a window => search the frame that window belongs to. */ | |
428 | 2460 |
2461 /* Do this loop at least once, to get the next window, and perhaps | |
2462 again, if we hit the minibuffer and that is not acceptable. */ | |
2463 do | |
2464 { | |
2465 /* Find a window that actually has a next one. This loop | |
2466 climbs up the tree. */ | |
2467 while (tem = XWINDOW (window)->next, NILP (tem)) | |
2468 if (tem = XWINDOW (window)->parent, !NILP (tem)) | |
2469 window = tem; | |
2470 else /* window must be minibuffer window now */ | |
2471 { | |
2472 /* We've reached the end of this frame. | |
2473 Which other frames are acceptable? */ | |
2474 tem = WINDOW_FRAME (XWINDOW (window)); | |
2475 | |
444 | 2476 if (! NILP (which_frames)) |
428 | 2477 { |
442 | 2478 Lisp_Object tem1 = tem; |
444 | 2479 tem = next_frame (tem, which_frames, which_devices); |
442 | 2480 |
428 | 2481 /* In the case where the minibuffer is active, |
2482 and we include its frame as well as the selected one, | |
2483 next_frame may get stuck in that frame. | |
2484 If that happens, go back to the selected frame | |
2485 so we can complete the cycle. */ | |
2486 if (EQ (tem, tem1)) | |
793 | 2487 tem = wrap_frame (selected_frame ()); |
428 | 2488 } |
2489 | |
2490 tem = FRAME_ROOT_WINDOW (XFRAME (tem)); | |
2491 break; | |
2492 } | |
2493 | |
2494 window = tem; | |
2495 | |
2496 /* If we're in a combination window, find its first child and | |
2497 recurse on that. Otherwise, we've found the window we want. */ | |
2498 while (1) | |
2499 { | |
2500 if (!NILP (XWINDOW (window)->hchild)) | |
2501 window = XWINDOW (window)->hchild; | |
2502 else if (!NILP (XWINDOW (window)->vchild)) | |
2503 window = XWINDOW (window)->vchild; | |
2504 else break; | |
2505 } | |
2506 } | |
2507 /* Which windows are acceptable? | |
2508 Exit the loop and accept this window if | |
2509 this isn't a minibuffer window, | |
2510 or we're accepting all minibuffer windows, | |
2511 or this is the active minibuffer and we are accepting that one, or | |
2512 we've come all the way around and we're back at the original window. */ | |
2513 while (MINI_WINDOW_P (XWINDOW (window)) | |
2514 && ! EQ (minibuf, Qt) | |
2515 && ! EQ (minibuf, window) | |
2516 && ! EQ (window, start_window)); | |
2517 | |
2518 return window; | |
2519 } | |
2520 | |
2521 DEFUN ("previous-window", Fprevious_window, 0, 4, 0, /* | |
442 | 2522 Return the window preceding WINDOW in the canonical ordering of windows. |
428 | 2523 If omitted, WINDOW defaults to the selected window. |
2524 | |
2525 Optional second arg MINIBUF t means count the minibuffer window even | |
2526 if not active. MINIBUF nil or omitted means count the minibuffer iff | |
2527 it is active. MINIBUF neither t nor nil means not to count the | |
2528 minibuffer even if it is active. | |
2529 | |
2530 Several frames may share a single minibuffer; if the minibuffer | |
2531 counts, all windows on all frames that share that minibuffer count | |
2532 too. Therefore, `previous-window' can be used to iterate through | |
2533 the set of windows even when the minibuffer is on another frame. If | |
442 | 2534 the minibuffer does not count, only windows from WINDOW's frame count. |
2535 | |
444 | 2536 By default, only the windows in the selected frame are considered. |
2537 The optional argument WHICH-FRAMES changes this behavior: | |
2538 WHICH-FRAMES = `visible' means search windows on all visible frames. | |
448 | 2539 WHICH-FRAMES = 0 means search windows on all visible and iconified frames. |
444 | 2540 WHICH-FRAMES = t means search windows on all frames including invisible frames. |
2541 WHICH-FRAMES = a frame means search only windows on that frame. | |
2542 Anything else means restrict to the selected frame. | |
2543 | |
2544 The optional fourth argument WHICH-DEVICES further clarifies on which | |
2545 devices to search for frames as specified by WHICH-FRAMES. This value | |
2546 is only meaningful if WHICH-FRAMES is non-nil. | |
2547 If nil or omitted, search all devices on the selected console. | |
2548 If a device, only search that device. | |
2549 If a console, search all devices on that console. | |
2550 If a device type, search all devices of that type. | |
2551 If `window-system', search all window-system devices. | |
2552 Any other non-nil value means search all devices. | |
2553 | |
2554 If you use consistent values for MINIBUF, WHICH-FRAMES, and WHICH-DEVICES, | |
2555 you can use `previous-window' to iterate through the entire cycle of | |
2556 acceptable windows, eventually ending up back at the window you started with. | |
428 | 2557 `next-window' traverses the same cycle, in the reverse order. |
2558 */ | |
444 | 2559 (window, minibuf, which_frames, devices)) |
428 | 2560 { |
2561 Lisp_Object tem; | |
2562 Lisp_Object start_window; | |
2563 | |
2564 if (NILP (window)) | |
2565 window = Fselected_window (Qnil); | |
2566 else | |
2567 CHECK_LIVE_WINDOW (window); | |
2568 | |
2569 start_window = window; | |
2570 | |
2571 /* minibuf == nil may or may not include minibuffers. | |
2572 Decide if it does. */ | |
2573 if (NILP (minibuf)) | |
2574 minibuf = (minibuf_level ? minibuf_window : Qlambda); | |
2575 else if (! EQ (minibuf, Qt)) | |
2576 minibuf = Qlambda; | |
442 | 2577 /* Now `minibuf' is one of: |
2578 t => count all minibuffer windows | |
2579 lambda => count none of them | |
428 | 2580 or a specific minibuffer window (the active one) to count. */ |
2581 | |
444 | 2582 /* which_frames == nil doesn't specify which frames to include. |
428 | 2583 Decide which frames it includes. */ |
444 | 2584 if (NILP (which_frames)) |
2585 which_frames = (! EQ (minibuf, Qlambda) | |
428 | 2586 ? (FRAME_MINIBUF_WINDOW |
2587 (XFRAME | |
2588 (WINDOW_FRAME | |
2589 (XWINDOW (window))))) | |
2590 : Qnil); | |
444 | 2591 else if (EQ (which_frames, Qvisible)) |
428 | 2592 ; |
444 | 2593 else if (ZEROP (which_frames)) |
428 | 2594 ; |
444 | 2595 else if (FRAMEP (which_frames) && ! EQ (which_frames, Fwindow_frame (window))) |
2596 /* If which_frames is a frame and window arg isn't on that frame, just | |
428 | 2597 return the first window on the frame. */ |
444 | 2598 return frame_first_window (XFRAME (which_frames)); |
2599 else if (! EQ (which_frames, Qt)) | |
2600 which_frames = Qnil; | |
2601 /* Now `which_frames' is one of: | |
442 | 2602 t => search all frames |
2603 nil => search just the current frame | |
2604 visible => search just visible frames | |
2605 0 => search visible and iconified frames | |
2606 a window => search the frame that window belongs to. */ | |
428 | 2607 |
2608 /* Do this loop at least once, to get the next window, and perhaps | |
2609 again, if we hit the minibuffer and that is not acceptable. */ | |
2610 do | |
2611 { | |
2612 /* Find a window that actually has a next one. This loop | |
2613 climbs up the tree. */ | |
2614 while (tem = XWINDOW (window)->prev, NILP (tem)) | |
2615 if (tem = XWINDOW (window)->parent, !NILP (tem)) | |
2616 window = tem; | |
2617 else /* window must be minibuffer window now */ | |
2618 { | |
2619 /* We have found the top window on the frame. | |
2620 Which frames are acceptable? */ | |
2621 tem = WINDOW_FRAME (XWINDOW (window)); | |
2622 | |
444 | 2623 if (! NILP (which_frames)) |
442 | 2624 /* It's actually important that we use previous_frame here, |
428 | 2625 rather than next_frame. All the windows acceptable |
2626 according to the given parameters should form a ring; | |
2627 Fnext_window and Fprevious_window should go back and | |
2628 forth around the ring. If we use next_frame here, | |
2629 then Fnext_window and Fprevious_window take different | |
2630 paths through the set of acceptable windows. | |
2631 window_loop assumes that these `ring' requirement are | |
2632 met. */ | |
2633 { | |
442 | 2634 Lisp_Object tem1 = tem; |
444 | 2635 tem = previous_frame (tem, which_frames, devices); |
428 | 2636 /* In the case where the minibuffer is active, |
2637 and we include its frame as well as the selected one, | |
2638 next_frame may get stuck in that frame. | |
2639 If that happens, go back to the selected frame | |
2640 so we can complete the cycle. */ | |
2641 if (EQ (tem, tem1)) | |
793 | 2642 tem = wrap_frame (selected_frame ()); |
428 | 2643 } |
2644 | |
2645 /* If this frame has a minibuffer, find that window first, | |
2646 because it is conceptually the last window in that frame. */ | |
2647 if (FRAME_HAS_MINIBUF_P (XFRAME (tem))) | |
2648 tem = FRAME_MINIBUF_WINDOW (XFRAME (tem)); | |
2649 else | |
2650 tem = FRAME_ROOT_WINDOW (XFRAME (tem)); | |
2651 | |
2652 break; | |
2653 } | |
2654 | |
2655 window = tem; | |
2656 | |
2657 /* If we're in a combination window, find its first child and | |
2658 recurse on that. Otherwise, we've found the window we want. */ | |
2659 while (1) | |
2660 { | |
2661 if (!NILP (XWINDOW (window)->hchild)) | |
2662 window = XWINDOW (window)->hchild; | |
2663 else if (!NILP (XWINDOW (window)->vchild)) | |
2664 window = XWINDOW (window)->vchild; | |
2665 else break; | |
2666 while (tem = XWINDOW (window)->next, !NILP (tem)) | |
2667 window = tem; | |
2668 } | |
2669 } | |
2670 /* Which windows are acceptable? | |
2671 Exit the loop and accept this window if | |
2672 this isn't a minibuffer window, | |
2673 or we're accepting all minibuffer windows, | |
2674 or this is the active minibuffer and we are accepting that one, or | |
2675 we've come all the way around and we're back at the original window. */ | |
2676 while (MINI_WINDOW_P (XWINDOW (window)) | |
2677 && ! EQ (minibuf, Qt) | |
2678 && ! EQ (minibuf, window) | |
2679 && ! EQ (window, start_window)); | |
2680 | |
2681 return window; | |
2682 } | |
2683 | |
2684 DEFUN ("next-vertical-window", Fnext_vertical_window, 0, 1, 0, /* | |
2685 Return the next window which is vertically after WINDOW. | |
2686 */ | |
2687 (window)) | |
2688 { | |
2689 Lisp_Object root; | |
2690 struct window *w = decode_window (window); | |
793 | 2691 window = wrap_window (w); |
428 | 2692 |
2693 if (MINI_WINDOW_P (XWINDOW (window))) | |
2694 return Qnil; | |
2695 | |
2696 root = FRAME_ROOT_WINDOW (XFRAME (WINDOW_FRAME (XWINDOW (window)))); | |
2697 | |
2698 if (EQ (window, root)) | |
2699 { | |
2700 while (1) | |
2701 if (!NILP (XWINDOW (window)->hchild)) | |
2702 window = XWINDOW (window)->hchild; | |
2703 else if (!NILP (XWINDOW (window)->vchild)) | |
2704 window = XWINDOW (window)->vchild; | |
2705 else | |
2706 return window; | |
2707 } | |
2708 | |
2709 do | |
2710 { | |
2711 if (!NILP (XWINDOW (window)->parent) && | |
2712 !NILP (XWINDOW (XWINDOW (window)->parent)->vchild)) | |
2713 { | |
2714 if (!NILP (XWINDOW (window)->next)) | |
2715 return XWINDOW (window)->next; | |
2716 else | |
2717 window = XWINDOW (window)->parent; | |
2718 } | |
2719 else | |
2720 window = XWINDOW (window)->parent; | |
2721 } | |
2722 while (!EQ (window, root)); | |
2723 | |
2724 while (1) | |
2725 if (!NILP (XWINDOW (window)->hchild)) | |
2726 window = XWINDOW (window)->hchild; | |
2727 else if (!NILP (XWINDOW (window)->vchild)) | |
2728 window = XWINDOW (window)->vchild; | |
2729 else | |
2730 return window; | |
2731 } | |
2732 | |
2733 DEFUN ("other-window", Fother_window, 1, 3, "p", /* | |
444 | 2734 Select the COUNT'th different window on this frame. |
428 | 2735 All windows on current frame are arranged in a cyclic order. |
444 | 2736 This command selects the window COUNT steps away in that order. |
2737 A negative COUNT moves in the opposite order. | |
2738 | |
2739 By default, only the windows in the selected frame are considered. | |
2740 The optional argument WHICH-FRAMES changes this behavior: | |
2741 WHICH-FRAMES = `visible' means search windows on all visible frames. | |
448 | 2742 WHICH-FRAMES = 0 means search windows on all visible and iconified frames. |
444 | 2743 WHICH-FRAMES = t means search windows on all frames including invisible frames. |
2744 WHICH-FRAMES = a frame means search only windows on that frame. | |
2745 Anything else means restrict to the selected frame. | |
2746 | |
2747 The optional argument WHICH-DEVICES further clarifies on which devices | |
2748 to search for frames as specified by WHICH-FRAMES. This value is only | |
2749 meaningful if WHICH-FRAMES is non-nil. | |
2750 If nil or omitted, search all devices on the selected console. | |
2751 If a device, only search that device. | |
2752 If a console, search all devices on that console. | |
2753 If a device type, search all devices of that type. | |
2754 If `window-system', search all window-system devices. | |
2755 Any other non-nil value means search all devices. | |
428 | 2756 */ |
444 | 2757 (count, which_frames, which_devices)) |
428 | 2758 { |
2759 int i; | |
2760 Lisp_Object w; | |
2761 | |
444 | 2762 CHECK_INT (count); |
428 | 2763 w = Fselected_window (Qnil); |
444 | 2764 i = XINT (count); |
428 | 2765 |
2766 while (i > 0) | |
2767 { | |
444 | 2768 w = Fnext_window (w, Qnil, which_frames, which_devices); |
428 | 2769 i--; |
2770 } | |
2771 while (i < 0) | |
2772 { | |
444 | 2773 w = Fprevious_window (w, Qnil, which_frames, which_devices); |
428 | 2774 i++; |
2775 } | |
2776 Fselect_window (w, Qnil); | |
2777 return Qnil; | |
2778 } | |
2779 | |
2780 | |
2781 /* Look at all windows, performing an operation specified by TYPE | |
2782 with argument OBJ. | |
2783 | |
2784 If FRAMES is Qt, look at all frames, if Qnil, look at just the selected | |
2785 frame. If FRAMES is a frame, just look at windows on that frame. | |
2786 If MINI is non-zero, perform the operation on minibuffer windows too. | |
2787 */ | |
2788 | |
2789 enum window_loop | |
2790 { | |
2791 WINDOW_LOOP_UNUSED, | |
2792 GET_BUFFER_WINDOW, /* Arg is buffer */ | |
2793 GET_LRU_WINDOW, /* Arg is t for full-width windows only */ | |
2794 DELETE_OTHER_WINDOWS, /* Arg is window not to delete */ | |
2795 DELETE_BUFFER_WINDOWS, /* Arg is buffer */ | |
2796 GET_LARGEST_WINDOW, | |
2797 GET_BUFFER_WINDOW_COUNT, /* Arg is buffer */ | |
2798 GET_BUFFER_MRU_WINDOW /* Arg is buffer */ | |
2799 }; | |
2800 | |
2801 static Lisp_Object | |
2802 window_loop (enum window_loop type, | |
2803 Lisp_Object obj, | |
2804 int mini, | |
444 | 2805 Lisp_Object which_frames, |
428 | 2806 int dedicated_too, |
444 | 2807 Lisp_Object which_devices) |
428 | 2808 { |
448 | 2809 /* This function can GC if type == DELETE_BUFFER_WINDOWS */ |
428 | 2810 Lisp_Object w; |
2811 Lisp_Object best_window = Qnil; | |
2812 Lisp_Object next_window; | |
2813 Lisp_Object last_window; | |
2814 struct frame *frame; | |
2815 Lisp_Object frame_arg = Qt; | |
2816 int count = 0; /* for GET_BUFFER_WINDOW_COUNT */ | |
2817 /* #### I think the change of "precomputing" last_window and next_window | |
2818 * #### catch the lossage this is meant(?) to punt on... | |
2819 */ | |
2820 int lose_lose = 0; | |
2821 Lisp_Object devcons, concons; | |
2822 | |
2823 /* If we're only looping through windows on a particular frame, | |
2824 FRAME points to that frame. If we're looping through windows | |
2825 on all frames, FRAME is 0. */ | |
444 | 2826 if (FRAMEP (which_frames)) |
2827 frame = XFRAME (which_frames); | |
2828 else if (NILP (which_frames)) | |
428 | 2829 frame = selected_frame (); |
2830 else | |
2831 frame = 0; | |
442 | 2832 |
2833 /* FRAME_ARG is Qlambda to stick to one frame, | |
2834 Qvisible to consider all visible frames, | |
2835 or Qt otherwise. */ | |
428 | 2836 if (frame) |
2837 frame_arg = Qlambda; | |
444 | 2838 else if (ZEROP (which_frames)) |
2839 frame_arg = which_frames; | |
2840 else if (EQ (which_frames, Qvisible)) | |
2841 frame_arg = which_frames; | |
428 | 2842 |
2843 DEVICE_LOOP_NO_BREAK (devcons, concons) | |
2844 { | |
2845 Lisp_Object device = XCAR (devcons); | |
2846 Lisp_Object the_frame; | |
2847 | |
2848 if (frame) | |
793 | 2849 the_frame = wrap_frame (frame); |
428 | 2850 else |
2851 the_frame = DEVICE_SELECTED_FRAME (XDEVICE (device)); | |
2852 | |
2853 if (NILP (the_frame)) | |
2854 continue; | |
2855 | |
444 | 2856 if (!device_matches_device_spec (device, |
2857 NILP (which_devices) ? | |
2858 FRAME_CONSOLE (XFRAME (the_frame)) : | |
2859 which_devices)) | |
428 | 2860 continue; |
2861 | |
2862 /* Pick a window to start with. */ | |
2863 if (WINDOWP (obj)) | |
2864 w = obj; | |
2865 else | |
2866 w = FRAME_SELECTED_WINDOW (XFRAME (the_frame)); | |
2867 | |
2868 /* Figure out the last window we're going to mess with. Since | |
2869 Fnext_window, given the same options, is guaranteed to go in a | |
2870 ring, we can just use Fprevious_window to find the last one. | |
2871 | |
2872 We can't just wait until we hit the first window again, | |
2873 because it might be deleted. */ | |
2874 | |
707 | 2875 last_window = Fprevious_window (w, mini ? Qt : Qnil, frame_arg, device); |
428 | 2876 |
2877 best_window = Qnil; | |
2878 for (;;) | |
2879 { | |
2880 struct window *p = XWINDOW (w); | |
2881 | |
2882 /* Pick the next window now, since some operations will delete | |
2883 the current window. */ | |
442 | 2884 next_window = Fnext_window (w, mini ? Qt : Qnil, frame_arg, device); |
428 | 2885 |
2886 /* #### Still needed ?? */ | |
2887 /* Given the outstanding quality of the rest of this code, | |
2888 I feel no shame about putting this piece of shit in. */ | |
2889 if (++lose_lose >= 500) | |
707 | 2890 { |
2500 | 2891 /* Call to ABORT() added by Darryl Okahata (16 Nov. 2001), |
707 | 2892 at Ben's request, to catch any remaining bugs. |
2893 | |
2894 If you find that XEmacs is aborting here, and you | |
2895 need to be up and running ASAP, it should be safe to | |
2500 | 2896 comment out the following ABORT(), as long as you |
707 | 2897 leave the "break;" alone. */ |
2500 | 2898 ABORT(); |
707 | 2899 break; /* <--- KEEP THIS HERE! Do not delete! */ |
2900 } | |
428 | 2901 |
2902 /* Note that we do not pay attention here to whether | |
2903 the frame is visible, since Fnext_window skips non-visible frames | |
2904 if that is desired, under the control of frame_arg. */ | |
2905 if (! MINI_WINDOW_P (p) | |
2906 || (mini && minibuf_level > 0)) | |
2907 switch (type) | |
2908 { | |
2909 case GET_BUFFER_WINDOW: | |
2910 { | |
2911 if (XBUFFER (p->buffer) == XBUFFER (obj)) | |
2912 return w; | |
2913 break; | |
2914 } | |
2915 | |
2916 case GET_BUFFER_WINDOW_COUNT: | |
2917 { | |
2918 if (XBUFFER (p->buffer) == XBUFFER (obj)) | |
2919 count++; | |
2920 break; | |
2921 } | |
2922 | |
2923 case GET_LRU_WINDOW: | |
2924 { | |
2925 /* t as arg means consider only full-width windows */ | |
2926 if (!NILP (obj) | |
2927 && !window_full_width_p (p)) | |
2928 break; | |
2929 /* Ignore dedicated windows and minibuffers. */ | |
2930 if (MINI_WINDOW_P (p) | |
2931 || (dedicated_too ? 0 : !NILP (p->dedicated))) | |
2932 break; | |
2933 if (NILP (best_window) | |
2934 || (XINT (XWINDOW (best_window)->use_time) | |
2935 > XINT (p->use_time))) | |
2936 best_window = w; | |
2937 break; | |
2938 } | |
2939 | |
2940 case GET_BUFFER_MRU_WINDOW: | |
2941 { | |
2942 /* #### what about the first check in GET_LRU_WINDOW? */ | |
2943 /* Ignore dedicated windows and minibuffers. */ | |
2944 if (MINI_WINDOW_P (p) | |
2945 || (dedicated_too ? 0 : !NILP (p->dedicated))) | |
2946 break; | |
2947 | |
2948 if (XBUFFER (p->buffer) == XBUFFER (obj)) | |
2949 { | |
2950 if (NILP (best_window) | |
2951 || (XINT (XWINDOW (best_window)->use_time) | |
2952 < XINT (p->use_time))) | |
2953 best_window = w; | |
2954 } | |
2955 break; | |
2956 } | |
2957 | |
2958 case DELETE_OTHER_WINDOWS: | |
2959 { | |
2960 /* Don't delete the last window on a frame; this can | |
2961 happen when the minibuffer is selected, and would | |
2962 cause the frame to be deleted. */ | |
2963 if (p != XWINDOW (obj) && !TOP_LEVEL_WINDOW_P (XWINDOW (w))) | |
2964 Fdelete_window (w, Qnil); | |
2965 break; | |
2966 } | |
2967 | |
2968 case DELETE_BUFFER_WINDOWS: | |
2969 { | |
2970 if (EQ (p->buffer, obj)) | |
2971 { | |
2972 struct frame *f = XFRAME (WINDOW_FRAME (p)); | |
2973 | |
2974 /* If this window is dedicated, and in a frame | |
2975 of its own, kill the frame. */ | |
2976 if (EQ (w, FRAME_ROOT_WINDOW (f)) | |
2977 && !NILP (p->dedicated) | |
1979 | 2978 && (allow_deletion_of_last_visible_frame |
2979 || other_visible_frames (f))) | |
428 | 2980 { |
2981 /* Skip the other windows on this frame. | |
2982 There might be one, the minibuffer! */ | |
2983 if (! EQ (w, last_window)) | |
2984 while (f == XFRAME (WINDOW_FRAME | |
2985 (XWINDOW (next_window)))) | |
2986 { | |
2987 /* As we go, check for the end of the | |
2988 loop. We mustn't start going | |
2989 around a second time. */ | |
2990 if (EQ (next_window, last_window)) | |
2991 { | |
2992 last_window = w; | |
2993 break; | |
2994 } | |
2995 next_window = Fnext_window (next_window, | |
2996 mini ? Qt : Qnil, | |
2997 frame_arg, Qt); | |
2998 } | |
2999 /* Now we can safely delete the frame. */ | |
3000 Fdelete_frame (WINDOW_FRAME (p), Qnil); | |
3001 } | |
3002 else | |
3003 /* If we're deleting the buffer displayed in | |
3004 the only window on the frame, find a new | |
3005 buffer to display there. */ | |
3006 if (NILP (p->parent)) | |
3007 { | |
3008 Lisp_Object new_buffer; | |
3009 new_buffer = Fother_buffer (obj, Qnil, Qnil); | |
3010 if (NILP (new_buffer)) | |
3011 new_buffer = Fget_buffer_create (QSscratch); | |
440 | 3012 Fset_window_buffer (w, new_buffer, Qnil); |
428 | 3013 if (EQ (w, Fselected_window (Qnil))) |
3014 Fset_buffer (p->buffer); | |
3015 } | |
3016 else | |
3017 Fdelete_window (w, Qnil); | |
3018 } | |
3019 break; | |
3020 } | |
3021 | |
3022 case GET_LARGEST_WINDOW: | |
3023 { | |
3024 /* Ignore dedicated windows and minibuffers. */ | |
3025 if (MINI_WINDOW_P (p) | |
3026 || (dedicated_too ? 0 : !NILP (p->dedicated))) | |
3027 break; | |
3028 { | |
3029 /* write the check as follows to avoid tripping | |
3030 error_check_window() --ben */ | |
3031 struct window *b = NILP (best_window) ? 0 : | |
3032 XWINDOW (best_window); | |
3033 if (NILP (best_window) | |
3034 || ((WINDOW_HEIGHT (p) * WINDOW_WIDTH (p)) | |
3035 > (WINDOW_HEIGHT (b) * WINDOW_WIDTH (b)))) | |
3036 best_window = w; | |
3037 } | |
3038 break; | |
3039 } | |
3040 | |
3041 default: | |
2500 | 3042 ABORT (); |
428 | 3043 } |
3044 | |
3045 if (EQ (w, last_window)) | |
3046 break; | |
3047 | |
3048 w = next_window; | |
3049 } | |
3050 } | |
3051 | |
3052 return type == GET_BUFFER_WINDOW_COUNT ? make_int (count) : best_window; | |
3053 } | |
3054 | |
3055 #if 0 /* not currently used */ | |
3056 | |
3057 int | |
3058 buffer_window_count (struct buffer *b, struct frame *f) | |
3059 { | |
3060 Lisp_Object buffer, frame; | |
3061 | |
793 | 3062 frame = wrap_frame (f); |
3063 buffer = wrap_buffer (b); | |
428 | 3064 |
3065 return XINT (window_loop (GET_BUFFER_WINDOW_COUNT, buffer, 0, frame, 1, | |
3066 Qnil)); | |
3067 } | |
3068 | |
3069 int | |
3070 buffer_window_mru (struct window *w) | |
3071 { | |
3072 Lisp_Object window = | |
3073 window_loop (GET_BUFFER_MRU_WINDOW, w->buffer, 0, w->frame, 1, Qnil); | |
3074 | |
3075 if (NILP (window)) | |
3076 return 0; | |
3077 else if (XWINDOW (window) == w) | |
3078 return 1; | |
3079 else | |
3080 return 0; | |
3081 } | |
3082 | |
3083 #endif | |
3084 | |
3085 | |
3086 DEFUN ("get-lru-window", Fget_lru_window, 0, 2, 0, /* | |
3087 Return the window least recently selected or used for display. | |
444 | 3088 |
3089 By default, only the windows in the selected frame are considered. | |
3090 The optional argument WHICH-FRAMES changes this behavior: | |
3091 If optional argument WHICH-FRAMES is `visible', search all visible frames. | |
3092 If WHICH-FRAMES is 0, search all visible and iconified frames. | |
3093 If WHICH-FRAMES is t, search all frames. | |
3094 If WHICH-FRAMES is nil, search only the selected frame. | |
3095 If WHICH-FRAMES is a frame, search only that frame. | |
3096 | |
3097 The optional argument WHICH-DEVICES further clarifies on which devices | |
3098 to search for frames as specified by WHICH-FRAMES. This value is only | |
3099 meaningful if WHICH-FRAMES is non-nil. | |
3100 If nil or omitted, search all devices on the selected console. | |
3101 If a device, only search that device. | |
3102 If a console, search all devices on that console. | |
3103 If a device type, search all devices of that type. | |
3104 If `window-system', search all devices on window-system consoles. | |
3105 Any other non-nil value means search all devices. | |
428 | 3106 */ |
444 | 3107 (which_frames, which_devices)) |
428 | 3108 { |
3109 Lisp_Object w; | |
3110 /* First try for a non-dedicated window that is full-width */ | |
444 | 3111 w = window_loop (GET_LRU_WINDOW, Qt, 0, which_frames, 0, which_devices); |
428 | 3112 if (!NILP (w) && !EQ (w, Fselected_window (Qnil))) |
3113 return w; | |
3114 | |
3115 /* Then try for any non-dedicated window */ | |
444 | 3116 w = window_loop (GET_LRU_WINDOW, Qnil, 0, which_frames, 0, which_devices); |
428 | 3117 if (!NILP (w) && !EQ (w, Fselected_window (Qnil))) |
3118 return w; | |
3119 | |
3120 #if 0 | |
3121 /* FSFmacs never returns a dedicated window here. If we do, | |
3122 it makes `display-buffer' not work right. #### All of this | |
3123 shit is so disgusting and awful that it needs to be rethought | |
3124 from scratch. */ | |
3125 /* then try for a dedicated window that is full-width */ | |
444 | 3126 w = window_loop (GET_LRU_WINDOW, Qt, 0, which_frames, 1, which_devices); |
428 | 3127 if (!NILP (w) && !EQ (w, Fselected_window (Qnil))) |
3128 return w; | |
3129 | |
3130 /* If none of them, then all windows, dedicated or not. */ | |
444 | 3131 w = window_loop (GET_LRU_WINDOW, Qnil, 0, which_frames, 1, which_devices); |
428 | 3132 |
3133 /* 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
|
3134 assert (!NILP (w)); |
428 | 3135 #endif |
3136 | |
3137 return w; | |
3138 } | |
3139 | |
3140 DEFUN ("get-largest-window", Fget_largest_window, 0, 2, 0, /* | |
3141 Return the window largest in area. | |
444 | 3142 |
3143 By default, only the windows in the selected frame are considered. | |
3144 The optional argument WHICH-FRAMES changes this behavior: | |
3145 If optional argument WHICH-FRAMES is `visible', search all visible frames. | |
3146 If WHICH-FRAMES is 0, search all visible and iconified frames. | |
3147 If WHICH-FRAMES is t, search all frames. | |
3148 If WHICH-FRAMES is nil, search only the selected frame. | |
3149 If WHICH-FRAMES is a frame, search only that frame. | |
3150 | |
3151 The optional argument WHICH-DEVICES further clarifies on which devices | |
3152 to search for frames as specified by WHICH-FRAMES. This value is only | |
3153 meaningful if WHICH-FRAMES is non-nil. | |
3154 If nil or omitted, search all devices on the selected console. | |
3155 If a device, only search that device. | |
3156 If a console, search all devices on that console. | |
3157 If a device type, search all devices of that type. | |
3158 If `window-system', search all devices on window-system consoles. | |
3159 Any other non-nil value means search all devices. | |
428 | 3160 */ |
444 | 3161 (which_frames, which_devices)) |
428 | 3162 { |
3163 /* Don't search dedicated windows because FSFmacs doesn't. | |
3164 This stuff is all black magic so don't try to apply common | |
3165 sense to it. */ | |
444 | 3166 return window_loop (GET_LARGEST_WINDOW, Qnil, 0, |
3167 which_frames, 0, which_devices); | |
428 | 3168 } |
3169 | |
3170 DEFUN ("get-buffer-window", Fget_buffer_window, 1, 3, 0, /* | |
3171 Return a window currently displaying BUFFER, or nil if none. | |
444 | 3172 |
3173 By default, only the windows in the selected frame are considered. | |
3174 The optional argument WHICH-FRAMES changes this behavior: | |
3175 If optional argument WHICH-FRAMES is `visible', search all visible frames. | |
3176 If WHICH-FRAMES is 0, search all visible and iconified frames. | |
3177 If WHICH-FRAMES is t, search all frames. | |
3178 If WHICH-FRAMES is nil, search only the selected frame. | |
3179 If WHICH-FRAMES is a frame, search only that frame. | |
3180 | |
3181 The optional argument WHICH-DEVICES further clarifies on which devices | |
3182 to search for frames as specified by WHICH-FRAMES. This value is only | |
3183 meaningful if WHICH-FRAMES is non-nil. | |
3184 If nil or omitted, search all devices on the selected console. | |
3185 If a device, only search that device. | |
3186 If a console, search all devices on that console. | |
3187 If a device type, search all devices of that type. | |
3188 If `window-system', search all devices on window-system consoles. | |
3189 Any other non-nil value means search all devices. | |
428 | 3190 */ |
444 | 3191 (buffer, which_frames, which_devices)) |
428 | 3192 { |
3193 buffer = Fget_buffer (buffer); | |
3194 if (BUFFERP (buffer)) | |
3195 /* Search dedicated windows too. (Doesn't matter here anyway.) */ | |
444 | 3196 return window_loop (GET_BUFFER_WINDOW, buffer, 1, |
3197 which_frames, 1, which_devices); | |
428 | 3198 else |
3199 return Qnil; | |
3200 } | |
3201 | |
3202 /* These functions used to be `buffer-left-margin-pixel-width', etc. | |
3203 but there is no sensible way to implement those functions, since | |
3204 you can't in general derive a window from a buffer. */ | |
3205 | |
3206 DEFUN ("window-left-margin-pixel-width", Fwindow_left_margin_pixel_width, | |
3207 0, 1, 0, /* | |
3208 Return the width in pixels of the left outside margin of window WINDOW. | |
3209 If WINDOW is nil, the selected window is assumed. | |
3210 */ | |
3211 (window)) | |
3212 { | |
3213 return make_int (window_left_margin_width (decode_window (window))); | |
3214 } | |
3215 | |
3216 DEFUN ("window-right-margin-pixel-width", Fwindow_right_margin_pixel_width, | |
3217 0, 1, 0, /* | |
3218 Return the width in pixels of the right outside margin of window WINDOW. | |
3219 If WINDOW is nil, the selected window is assumed. | |
3220 */ | |
3221 (window)) | |
3222 { | |
3223 return make_int (window_right_margin_width (decode_window (window))); | |
3224 } | |
3225 | |
3226 DEFUN ("delete-other-windows", Fdelete_other_windows, 0, 1, "", /* | |
3227 Make WINDOW (or the selected window) fill its frame. | |
3228 Only the frame WINDOW is on is affected. | |
3229 This function tries to reduce display jumps | |
3230 by keeping the text previously visible in WINDOW | |
3231 in the same place on the frame. Doing this depends on | |
3232 the value of (window-start WINDOW), so if calling this function | |
3233 in a program gives strange scrolling, make sure the window-start | |
3234 value is reasonable when this function is called. | |
3235 */ | |
3236 (window)) | |
3237 { | |
3238 struct window *w = decode_window (window); | |
1207 | 3239 struct buffer *b; |
665 | 3240 Charbpos start_pos; |
428 | 3241 int old_top = WINDOW_TOP (w); |
3242 | |
1207 | 3243 if (NILP (WINDOW_BUFFER (w))) |
3244 invalid_operation ("Can't delete other windows of combination", window); | |
3245 | |
793 | 3246 window = wrap_window (w); |
1207 | 3247 b = XBUFFER (WINDOW_BUFFER (w)); |
428 | 3248 |
3249 if (MINI_WINDOW_P (w) && old_top > 0) | |
563 | 3250 invalid_operation ("Can't expand minibuffer to full frame", Qunbound); |
428 | 3251 |
3252 /* Ignore dedicated windows. */ | |
3253 window_loop (DELETE_OTHER_WINDOWS, window, 0, w->frame, 0, Qnil); | |
3254 | |
3255 start_pos = marker_position (w->start[CURRENT_DISP]); | |
3256 | |
3257 /* Try to minimize scrolling, by setting the window start to the | |
3258 point which will cause the text at the old window start to be at | |
3259 the same place on the frame. But don't try to do this if the | |
3260 window start is outside the visible portion (as might happen when | |
3261 the display is not current, due to typeahead). */ | |
3262 if (start_pos >= BUF_BEGV (b) && start_pos <= BUF_ZV (b) | |
3263 && !MINI_WINDOW_P (w)) | |
3264 { | |
665 | 3265 Charbpos new_start = start_with_line_at_pixpos (w, start_pos, old_top); |
428 | 3266 |
3267 if (new_start >= BUF_BEGV (b) && new_start <= BUF_ZV (b)) | |
3268 { | |
3269 Fset_marker (w->start[CURRENT_DISP], make_int (new_start), | |
3270 w->buffer); | |
3271 w->start_at_line_beg = beginning_of_line_p (b, new_start); | |
3272 } | |
3273 /* We need to do this, so that the window-scroll-functions | |
3274 get called. */ | |
3275 w->force_start = 1; | |
3276 } | |
3277 | |
3278 return Qnil; | |
3279 } | |
3280 | |
3281 DEFUN ("delete-windows-on", Fdelete_windows_on, 1, 3, | |
3282 "bDelete windows on (buffer): ", /* | |
3283 Delete all windows showing BUFFER. | |
444 | 3284 |
3285 Optional second argument WHICH-FRAMES controls which frames are affected. | |
428 | 3286 If nil or omitted, delete all windows showing BUFFER in any frame. |
3287 If t, delete only windows showing BUFFER in the selected frame. | |
3288 If `visible', delete all windows showing BUFFER in any visible frame. | |
3289 If a frame, delete only windows showing BUFFER in that frame. | |
444 | 3290 Warning: WHICH-FRAMES has the same meaning as with `next-window', |
3291 except that the meanings of nil and t are reversed. | |
3292 | |
3293 The optional third argument WHICH-DEVICES further clarifies on which | |
3294 devices to search for frames as specified by WHICH-FRAMES. This value | |
3295 is only meaningful if WHICH-FRAMES is not t. | |
3296 If nil or omitted, search only the selected console. | |
3297 If a device, only search that device. | |
3298 If a console, search all devices on that console. | |
3299 If a device type, search all devices of that type. | |
3300 If `window-system', search all devices on a window system. | |
3301 Any other non-nil value means search all devices. | |
428 | 3302 */ |
444 | 3303 (buffer, which_frames, which_devices)) |
428 | 3304 { |
3305 /* This function can GC */ | |
444 | 3306 buffer = Fget_buffer (buffer); |
3307 CHECK_BUFFER (buffer); | |
3308 | |
3309 /* WHICH-FRAMES values t and nil mean the opposite of what | |
3310 window_loop expects. */ | |
3311 if (EQ (which_frames, Qnil)) | |
3312 which_frames = Qt; | |
3313 else if (EQ (which_frames, Qt)) | |
3314 which_frames = Qnil; | |
3315 | |
3316 /* Ignore dedicated windows. */ | |
3317 window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, | |
3318 which_frames, 0, which_devices); | |
428 | 3319 return Qnil; |
3320 } | |
3321 | |
448 | 3322 static Lisp_Object |
3323 list_windows (struct window *w, Lisp_Object value) | |
3324 { | |
3325 for (;;) | |
3326 { | |
3327 if (!NILP (w->hchild)) | |
3328 value = list_windows (XWINDOW (w->hchild), value); | |
3329 else if (!NILP (w->vchild)) | |
3330 value = list_windows (XWINDOW (w->vchild), value); | |
3331 else | |
3332 { | |
793 | 3333 Lisp_Object window = wrap_window (w); |
3334 | |
448 | 3335 value = Fcons (window, value); |
3336 } | |
3337 if (NILP (w->next)) | |
3338 break; | |
3339 w = XWINDOW (w->next); | |
3340 } | |
3341 return value; | |
3342 } | |
3343 | |
3344 static Lisp_Object | |
3345 list_all_windows (Lisp_Object frame_spec, Lisp_Object device_spec) | |
3346 { | |
3347 Lisp_Object devcons, concons; | |
3348 Lisp_Object retval = Qnil; | |
3349 | |
3350 DEVICE_LOOP_NO_BREAK (devcons, concons) | |
3351 { | |
3352 Lisp_Object frame_list, the_window; | |
3353 Lisp_Object device, tail; | |
3354 | |
3355 device = XCAR (devcons); | |
3356 frame_list = DEVICE_FRAME_LIST (XDEVICE (device)); | |
3357 | |
3358 LIST_LOOP (tail, frame_list) | |
3359 { | |
3360 if ((NILP (frame_spec) | |
3361 && !EQ (XCAR (tail), DEVICE_SELECTED_FRAME (XDEVICE (device)))) | |
3362 || (EQ (frame_spec, Qvisible) | |
3363 && !FRAME_VISIBLE_P (XFRAME (XCAR (tail)))) | |
3364 || (FRAMEP (frame_spec) | |
3365 && !EQ (frame_spec, XCAR (tail))) | |
3366 || (!NILP (frame_spec) | |
3367 && !device_matches_device_spec (device, | |
3368 NILP (device_spec) ? | |
3369 Vselected_console : | |
3370 device_spec))) | |
3371 continue; | |
3372 the_window = FRAME_ROOT_WINDOW (XFRAME (XCAR (tail))); | |
3373 retval = list_windows (XWINDOW (the_window), retval); | |
3374 } | |
3375 } | |
3376 return Fnreverse (retval); | |
3377 } | |
3378 | |
444 | 3379 DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows, 1, 3, |
428 | 3380 "bReplace buffer in windows: ", /* |
3381 Replace BUFFER with some other buffer in all windows showing it. | |
444 | 3382 |
3383 Optional second argument WHICH-FRAMES controls which frames are affected. | |
3384 If nil or omitted, all frames are affected. | |
3385 If t, only the selected frame is affected. | |
3386 If `visible', all visible frames are affected. | |
3387 If a frame, only that frame is affected. | |
3388 Warning: WHICH-FRAMES has the same meaning as with `next-window', | |
3389 except that the meanings of nil and t are reversed. | |
3390 | |
3391 The optional third argument WHICH-DEVICES further clarifies on which | |
3392 devices to search for frames as specified by WHICH-FRAMES. This value | |
3393 is only meaningful if WHICH-FRAMES is not t. | |
3394 If nil or omitted, search only the selected console. | |
3395 If a device, only search that device. | |
3396 If a console, search all devices on that console. | |
3397 If a device type, search all devices of that type. | |
3398 If `window-system', search all devices on a window system. | |
3399 Any other non-nil value means search all devices. | |
428 | 3400 */ |
444 | 3401 (buffer, which_frames, which_devices)) |
428 | 3402 { |
3403 /* This function can GC */ | |
448 | 3404 Lisp_Object window_list; |
3405 Lisp_Object tail; | |
3406 struct gcpro gcpro1, gcpro2; | |
3407 | |
444 | 3408 if (EQ (which_frames, Qnil)) |
3409 which_frames = Qt; | |
3410 else if (EQ (which_frames, Qt)) | |
3411 which_frames = Qnil; | |
448 | 3412 window_list = list_all_windows (which_frames, which_devices); |
3413 | |
3414 buffer = Fget_buffer (buffer); | |
3415 CHECK_BUFFER (buffer); | |
3416 | |
3417 GCPRO2 (window_list, buffer); | |
3418 LIST_LOOP (tail, window_list) | |
3419 { | |
3420 Lisp_Object window = XCAR (tail); | |
3421 if (!MINI_WINDOW_P (XWINDOW (window)) | |
3422 && EQ (XWINDOW (window)->buffer, buffer)) | |
3423 { | |
3424 Lisp_Object another_buffer = Fother_buffer (buffer, Qnil, Qnil); | |
3425 Lisp_Object frame = WINDOW_FRAME (XWINDOW (window)); | |
3426 if (NILP (another_buffer)) | |
3427 another_buffer = Fget_buffer_create (QSscratch); | |
3428 if (!NILP (XWINDOW (window)->dedicated) | |
3429 && EQ (window, | |
3430 FRAME_ROOT_WINDOW (XFRAME (frame))) | |
1979 | 3431 && (allow_deletion_of_last_visible_frame |
3432 || other_visible_frames (XFRAME (frame)))) | |
448 | 3433 { |
3434 delete_frame_internal (XFRAME (frame), 0, 0, 0); /* GC */ | |
3435 } | |
3436 else | |
3437 { | |
3438 Fset_window_buffer (window, another_buffer, Qnil); | |
3439 if (EQ (window, Fselected_window (Qnil))) | |
3440 Fset_buffer (XWINDOW (window)->buffer); | |
3441 } | |
3442 } | |
3443 } | |
3444 UNGCPRO; | |
428 | 3445 return Qnil; |
3446 } | |
3447 | |
3448 /* The smallest acceptable dimensions for a window. Anything smaller | |
3449 might crash Emacs. */ | |
3450 #define MIN_SAFE_WINDOW_WIDTH (2) | |
3451 #define MIN_SAFE_WINDOW_HEIGHT (2) | |
3452 | |
3453 /* Make sure that window_min_height and window_min_width are | |
3454 not too small; if they are, set them to safe minima. */ | |
3455 | |
3456 static void | |
3457 check_min_window_sizes (void) | |
3458 { | |
3459 /* Smaller values might permit a crash. */ | |
3460 if (window_min_width < MIN_SAFE_WINDOW_WIDTH) | |
3461 window_min_width = MIN_SAFE_WINDOW_WIDTH; | |
3462 if (window_min_height < MIN_SAFE_WINDOW_HEIGHT) | |
3463 window_min_height = MIN_SAFE_WINDOW_HEIGHT; | |
3464 } | |
3465 | |
440 | 3466 static int |
3467 frame_min_height (struct frame *frame) | |
3468 { | |
3469 /* For height, we have to see whether the frame has a minibuffer, and | |
3470 whether it wants a modeline. */ | |
3471 return (FRAME_MINIBUF_ONLY_P (frame) ? MIN_SAFE_WINDOW_HEIGHT - 1 | |
3472 : (! FRAME_HAS_MINIBUF_P (frame)) ? MIN_SAFE_WINDOW_HEIGHT | |
3473 : 2 * MIN_SAFE_WINDOW_HEIGHT - 1); | |
3474 } | |
3475 | |
3476 /* Return non-zero if both frame sizes are less than or equal to | |
3477 minimal allowed values. ROWS and COLS are in characters */ | |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
3478 static int |
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
3479 frame_size_valid_p (struct frame *frame, int cols, int rows) |
440 | 3480 { |
3481 return (rows >= frame_min_height (frame) | |
3482 && cols >= MIN_SAFE_WINDOW_WIDTH); | |
3483 } | |
3484 | |
3485 /* Return non-zero if both frame sizes are less than or equal to | |
3486 minimal allowed values. WIDTH and HEIGHT are in pixels */ | |
3487 int | |
3488 frame_pixsize_valid_p (struct frame *frame, int width, int height) | |
3489 { | |
3490 int rows, cols; | |
5043 | 3491 pixel_to_char_size (frame, width, height, &cols, &rows); |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
3492 return frame_size_valid_p (frame, cols, rows); |
440 | 3493 } |
3494 | |
428 | 3495 /* If *ROWS or *COLS are too small a size for FRAME, set them to the |
3496 minimum allowable size. */ | |
3497 void | |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
3498 check_frame_size (struct frame *frame, int *cols, int *rows) |
428 | 3499 { |
440 | 3500 int min_height = frame_min_height (frame); |
5043 | 3501 int min_pixwidth, min_pixheight; |
3502 int min_geomwidth, min_geomheight; | |
3503 | |
3504 /* There is no char_to_frame_unit_size(). This can be done with | |
3505 frame_conversion_internal(), but that's currently static, and we can | |
3506 do it fine with two steps, as follows. */ | |
3507 char_to_pixel_size (frame, MIN_SAFE_WINDOW_WIDTH, min_height, | |
3508 &min_pixwidth, &min_pixheight); | |
3509 pixel_to_frame_unit_size (frame, min_pixwidth, min_pixheight, | |
3510 &min_geomwidth, &min_geomheight); | |
3511 if (*rows < min_geomheight) | |
3512 *rows = min_geomheight; | |
3513 if (*cols < min_geomwidth) | |
3514 *cols = min_geomwidth; | |
428 | 3515 } |
3516 | |
3517 /* Normally the window is deleted if it gets too small. | |
3518 nodelete nonzero means do not do this. | |
3519 (The caller should check later and do so if appropriate) */ | |
3520 static void | |
3521 set_window_pixsize (Lisp_Object window, int new_pixsize, int nodelete, | |
3522 int set_height) | |
3523 { | |
3524 struct window *w = XWINDOW (window); | |
3525 struct frame *f = XFRAME (w->frame); | |
3526 struct window *c; | |
3527 int old_pixsize = (set_height ? WINDOW_HEIGHT (w) : WINDOW_WIDTH (w)); | |
3528 Lisp_Object child, minor_kid, major_kid; | |
3529 int minsize; | |
3530 int line_size; | |
3531 int defheight, defwidth; | |
3532 | |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
3533 default_face_width_and_height (window, &defwidth, &defheight); |
428 | 3534 line_size = (set_height ? defheight : defwidth); |
3535 | |
3536 check_min_window_sizes (); | |
3537 | |
3538 minsize = (set_height ? window_min_height : window_min_width); | |
3539 minsize *= line_size; | |
3540 | |
3541 if (!nodelete | |
3542 && !TOP_LEVEL_WINDOW_P (w) | |
4375
74e0e1131e01
Update window-size computation.
Mike Sperber <sperber@deinprogramm.de>
parents:
3707
diff
changeset
|
3543 && (new_pixsize + window_modeline_height (w)) < minsize) |
428 | 3544 { |
3545 Fdelete_window (window, Qnil); | |
3546 return; | |
3547 } | |
3548 | |
3549 SET_LAST_MODIFIED (w, 0); | |
3550 SET_LAST_FACECHANGE (w); | |
3551 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); /* multiple windows affected */ | |
3552 if (set_height) | |
3553 { | |
3554 WINDOW_HEIGHT (w) = new_pixsize; | |
3555 major_kid = w->vchild; | |
3556 minor_kid = w->hchild; | |
3557 } | |
3558 else | |
3559 { | |
3560 WINDOW_WIDTH (w) = new_pixsize; | |
3561 major_kid = w->hchild; | |
3562 minor_kid = w->vchild; | |
3563 } | |
3564 | |
3565 if (!NILP (minor_kid)) | |
3566 { | |
3567 for (child = minor_kid; !NILP (child); child = XWINDOW (child)->next) | |
3568 { | |
3569 if (set_height) | |
3570 WINDOW_TOP (XWINDOW (child)) = WINDOW_TOP (w); | |
3571 else | |
3572 WINDOW_LEFT (XWINDOW (child)) = WINDOW_LEFT (w); | |
3573 | |
3574 set_window_pixsize (child, new_pixsize, nodelete, set_height); | |
3575 } | |
3576 } | |
3577 else if (!NILP (major_kid)) | |
3578 { | |
3579 int last_pos, last_old_pos, pos, old_pos, first; | |
3580 int pixel_adj_left = new_pixsize - old_pixsize; | |
3581 int div_val = old_pixsize << 1; | |
3582 | |
3583 /* | |
3584 * Previously we bailed out here if there was no size change. | |
3585 * (pixel_adj_left == 0) But this broke toolbar updates. If a | |
3586 * toolbar appears or disappears, windows may not change size, | |
3587 * but their top and left coordinates need to be updated. | |
3588 * | |
3589 * So we don't bail until after the loop below. | |
3590 */ | |
3591 | |
3592 last_pos = first = (set_height ? WINDOW_TOP (w) : WINDOW_LEFT (w)); | |
3593 last_old_pos = 0; | |
3594 | |
3595 for (child = major_kid; !NILP (child); child = c->next) | |
3596 { | |
3597 c = XWINDOW (child); | |
3598 | |
3599 if (set_height) | |
3600 { | |
3601 old_pos = last_old_pos + WINDOW_HEIGHT (c); | |
3602 WINDOW_TOP (c) = last_pos; | |
3603 } | |
3604 else | |
3605 { | |
3606 old_pos = last_old_pos + WINDOW_WIDTH (c); | |
3607 WINDOW_LEFT (c) = last_pos; | |
3608 } | |
3609 | |
3610 pos = (((old_pos * new_pixsize) << 1) + old_pixsize) / div_val; | |
3611 /* All but the last window should have a height which is | |
3612 a multiple of the default line height. */ | |
3613 if (!NILP (c->next)) | |
4446
c32b3d10c56b
Fix problem with `resize-minibuffer-mode'.
Mike Sperber <sperber@deinprogramm.de>
parents:
4375
diff
changeset
|
3614 { |
c32b3d10c56b
Fix problem with `resize-minibuffer-mode'.
Mike Sperber <sperber@deinprogramm.de>
parents:
4375
diff
changeset
|
3615 /* |
c32b3d10c56b
Fix problem with `resize-minibuffer-mode'.
Mike Sperber <sperber@deinprogramm.de>
parents:
4375
diff
changeset
|
3616 * 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
|
3617 * 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
|
3618 * cancel out actually do cancel out. |
c32b3d10c56b
Fix problem with `resize-minibuffer-mode'.
Mike Sperber <sperber@deinprogramm.de>
parents:
4375
diff
changeset
|
3619 */ |
c32b3d10c56b
Fix problem with `resize-minibuffer-mode'.
Mike Sperber <sperber@deinprogramm.de>
parents:
4375
diff
changeset
|
3620 if (pixel_adj_left < 0) |
c32b3d10c56b
Fix problem with `resize-minibuffer-mode'.
Mike Sperber <sperber@deinprogramm.de>
parents:
4375
diff
changeset
|
3621 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
|
3622 else |
c32b3d10c56b
Fix problem with `resize-minibuffer-mode'.
Mike Sperber <sperber@deinprogramm.de>
parents:
4375
diff
changeset
|
3623 pos = (pos / line_size) * line_size; |
c32b3d10c56b
Fix problem with `resize-minibuffer-mode'.
Mike Sperber <sperber@deinprogramm.de>
parents:
4375
diff
changeset
|
3624 } |
428 | 3625 |
3626 /* Avoid confusion: don't delete child if it becomes too small */ | |
3627 set_window_pixsize (child, pos + first - last_pos, 1, set_height); | |
3628 | |
3629 last_pos = pos + first; | |
3630 last_old_pos = old_pos; | |
3631 } | |
3632 | |
3633 /* Sometimes we may get called with our old size. In that case | |
3634 we don't need to do anything else. */ | |
3635 if (!pixel_adj_left) | |
3636 return; | |
3637 | |
3638 /* Now delete any children that became too small. */ | |
3639 if (!nodelete) | |
3640 for (child = major_kid; !NILP (child); child = XWINDOW (child)->next) | |
3641 { | |
3642 if (set_height) | |
3643 set_window_pixheight (child, WINDOW_HEIGHT (XWINDOW (child)), 0); | |
3644 else | |
3645 set_window_pixwidth (child, WINDOW_WIDTH (XWINDOW (child)), 0); | |
3646 } | |
3647 } | |
3648 } | |
3649 | |
3650 /* Set the height of WINDOW and all its inferiors. */ | |
3651 void | |
3652 set_window_pixheight (Lisp_Object window, int new_pixheight, int nodelete) | |
3653 { | |
3654 set_window_pixsize (window, new_pixheight, nodelete, 1); | |
3655 } | |
3656 | |
3657 /* Recursively set width of WINDOW and its inferiors. */ | |
3658 void | |
3659 set_window_pixwidth (Lisp_Object window, int new_pixwidth, int nodelete) | |
3660 { | |
3661 set_window_pixsize (window, new_pixwidth, nodelete, 0); | |
3662 } | |
3663 | |
3664 | |
3665 static int window_select_count; | |
3666 | |
440 | 3667 DEFUN ("set-window-buffer", Fset_window_buffer, 2, 3, 0, /* |
428 | 3668 Make WINDOW display BUFFER as its contents. |
3669 BUFFER can be a buffer or buffer name. | |
440 | 3670 |
442 | 3671 With non-nil optional argument NORECORD, do not modify the |
440 | 3672 global or per-frame buffer ordering. |
428 | 3673 */ |
440 | 3674 (window, buffer, norecord)) |
428 | 3675 { |
3676 Lisp_Object tem; | |
3677 struct window *w = decode_window (window); | |
448 | 3678 int old_buffer_local_face_property = 0; |
428 | 3679 |
3680 buffer = Fget_buffer (buffer); | |
3681 CHECK_BUFFER (buffer); | |
3682 | |
3683 if (!BUFFER_LIVE_P (XBUFFER (buffer))) | |
563 | 3684 invalid_operation ("Attempt to display deleted buffer", Qunbound); |
428 | 3685 |
3686 tem = w->buffer; | |
3687 if (NILP (tem)) | |
563 | 3688 invalid_operation ("Window is deleted", Qunbound); |
428 | 3689 else if (EQ (tem, buffer)) |
3690 return Qnil; | |
3691 else if (! EQ (tem, Qt)) /* w->buffer is t when the window | |
3692 is first being set up. */ | |
3693 { | |
3694 if (!NILP (w->dedicated) && !EQ (tem, buffer)) | |
563 | 3695 signal_error (Qinvalid_operation, "Window is dedicated to buffer", tem); |
428 | 3696 |
448 | 3697 old_buffer_local_face_property = |
3698 XBUFFER (w->buffer)->buffer_local_face_property; | |
428 | 3699 unshow_buffer (w); |
3700 } | |
3701 | |
3702 w->buffer = buffer; | |
3703 w->window_end_pos[CURRENT_DISP] = 0; | |
3704 w->hscroll = 0; | |
3705 w->modeline_hscroll = 0; | |
844 | 3706 #if 0 /* pre point caches */ |
428 | 3707 Fset_marker (w->pointm[CURRENT_DISP], |
3708 make_int (BUF_PT (XBUFFER (buffer))), | |
3709 buffer); | |
3710 set_marker_restricted (w->start[CURRENT_DISP], | |
3711 make_int (XBUFFER (buffer)->last_window_start), | |
3712 buffer); | |
844 | 3713 #else |
3714 { | |
3715 Lisp_Object marker = Fgethash (buffer, w->saved_point_cache, Qnil); | |
3716 Lisp_Object newpoint = | |
3717 !NILP (marker) ? make_int (marker_position (marker)) : | |
3718 make_int (BUF_PT (XBUFFER (buffer))); | |
3719 /* Previously, we had in here set-window-point, which did one of the | |
3720 following two, but not both. However, that could result in pointm | |
3721 being in a different buffer from the window's buffer! Probably | |
3722 not a travesty since it always occurred when the window was | |
3723 selected, meaning its value of point was ignored in favor of the | |
3724 buffer's; but it tripped an assert() in unshow_buffer(). */ | |
3725 set_marker_restricted (w->pointm[CURRENT_DISP], newpoint, buffer); | |
3726 if (EQ (wrap_window (w), Fselected_window (Qnil))) | |
3727 Fgoto_char (newpoint, buffer); /* this will automatically clip to | |
3728 accessible */ | |
3729 marker = Fgethash (buffer, w->saved_last_window_start_cache, Qnil); | |
3730 set_marker_restricted (w->start[CURRENT_DISP], | |
3731 !NILP (marker) ? | |
3732 make_int (marker_position (marker)) : | |
3733 make_int (XBUFFER (buffer)->last_window_start), | |
3734 buffer); | |
3735 } | |
3736 #endif | |
3737 | |
428 | 3738 Fset_marker (w->sb_point, w->start[CURRENT_DISP], buffer); |
3739 /* set start_at_line_beg correctly. GE */ | |
844 | 3740 w->start_at_line_beg = |
3741 beginning_of_line_p (XBUFFER (buffer), | |
3742 marker_position (w->start[CURRENT_DISP])); | |
3743 w->force_start = 0; /* XEmacs fix */ | |
428 | 3744 SET_LAST_MODIFIED (w, 1); |
3745 SET_LAST_FACECHANGE (w); | |
3746 MARK_WINDOWS_CHANGED (w); | |
448 | 3747 { |
3748 int new_buffer_local_face_property = | |
3749 XBUFFER (w->buffer)->buffer_local_face_property; | |
3750 | |
3751 if (new_buffer_local_face_property | |
3752 || new_buffer_local_face_property != old_buffer_local_face_property) | |
3753 MARK_WINDOW_FACES_CHANGED (w); | |
3754 } | |
428 | 3755 recompute_all_cached_specifiers_in_window (w); |
3756 if (EQ (window, Fselected_window (Qnil))) | |
3757 { | |
440 | 3758 if (NILP (norecord)) |
3759 Frecord_buffer (buffer); | |
3760 | |
428 | 3761 Fset_buffer (buffer); |
3762 } | |
3763 return Qnil; | |
3764 } | |
3765 | |
3766 DEFUN ("select-window", Fselect_window, 1, 2, 0, /* | |
3767 Select WINDOW. Most editing will apply to WINDOW's buffer. | |
3768 The main editor command loop selects the buffer of the selected window | |
3769 before each command. | |
3770 | |
442 | 3771 With non-nil optional argument NORECORD, do not modify the |
428 | 3772 global or per-frame buffer ordering. |
3773 */ | |
3774 (window, norecord)) | |
3775 { | |
3776 struct window *w; | |
3777 Lisp_Object old_selected_window = Fselected_window (Qnil); | |
3778 | |
3779 CHECK_LIVE_WINDOW (window); | |
3780 w = XWINDOW (window); | |
3781 | |
3782 /* we have already caught dead-window errors */ | |
3783 if (!NILP (w->hchild) || !NILP (w->vchild)) | |
563 | 3784 invalid_operation ("Trying to select non-leaf window", Qunbound); |
428 | 3785 |
3786 w->use_time = make_int (++window_select_count); | |
442 | 3787 |
428 | 3788 if (EQ (window, old_selected_window)) |
3789 return window; | |
3790 | |
3791 /* deselect the old window, if it exists (it might not exist if | |
3792 the selected device has no frames, which occurs at startup) */ | |
3793 if (!NILP (old_selected_window)) | |
3794 { | |
3795 struct window *ow = XWINDOW (old_selected_window); | |
3796 | |
3797 Fset_marker (ow->pointm[CURRENT_DISP], | |
3798 make_int (BUF_PT (XBUFFER (ow->buffer))), | |
3799 ow->buffer); | |
3800 | |
3801 MARK_WINDOWS_CHANGED (ow); | |
3802 } | |
3803 | |
3804 /* now select the window's frame */ | |
3805 set_frame_selected_window (XFRAME (WINDOW_FRAME (w)), window); | |
3806 | |
3807 select_frame_1 (WINDOW_FRAME (w)); | |
3808 | |
3809 /* also select the window's buffer */ | |
3810 if (NILP (norecord)) | |
3811 Frecord_buffer (w->buffer); | |
3812 Fset_buffer (w->buffer); | |
3813 | |
3814 /* Go to the point recorded in the window. | |
3815 This is important when the buffer is in more | |
3816 than one window. It also matters when | |
3817 redisplay_window has altered point after scrolling, | |
3818 because it makes the change only in the window. */ | |
3819 { | |
665 | 3820 Charbpos new_point = marker_position (w->pointm[CURRENT_DISP]); |
428 | 3821 if (new_point < BUF_BEGV (current_buffer)) |
3822 new_point = BUF_BEGV (current_buffer); | |
3823 else if (new_point > BUF_ZV (current_buffer)) | |
3824 new_point = BUF_ZV (current_buffer); | |
3825 | |
3826 BUF_SET_PT (current_buffer, new_point); | |
3827 } | |
3828 | |
3829 MARK_WINDOWS_CHANGED (w); | |
3830 | |
3831 return window; | |
3832 } | |
3833 | |
3834 Lisp_Object | |
3835 display_buffer (Lisp_Object buffer, Lisp_Object not_this_window_p, | |
3836 Lisp_Object override_frame) | |
3837 { | |
3838 return call3 (Qdisplay_buffer, buffer, not_this_window_p, override_frame); | |
3839 } | |
3840 | |
3841 void | |
3842 temp_output_buffer_show (Lisp_Object buf, Lisp_Object same_frame) | |
3843 { | |
3844 /* This function can GC */ | |
3845 Lisp_Object window; | |
3846 struct window *w; | |
3847 struct buffer *b = XBUFFER (buf); | |
3848 | |
3849 BUF_SAVE_MODIFF (XBUFFER (buf)) = BUF_MODIFF (b); | |
3850 widen_buffer (b, 0); | |
3851 BUF_SET_PT (b, BUF_BEG (b)); | |
3852 | |
3853 if (!NILP (Vtemp_buffer_show_function)) | |
3854 call1 (Vtemp_buffer_show_function, buf); | |
3855 else | |
3856 { | |
3857 window = display_buffer (buf, Qnil, same_frame); | |
3858 | |
3859 if (!EQ (XWINDOW (window)->frame, Fselected_frame (Qnil))) | |
3860 Fmake_frame_visible (WINDOW_FRAME (XWINDOW (window))); | |
3861 | |
3862 Vminibuffer_scroll_window = window; | |
3863 w = XWINDOW (window); | |
3864 w->hscroll = 0; | |
3865 w->modeline_hscroll = 0; | |
3866 set_marker_restricted (w->start[CURRENT_DISP], make_int (1), buf); | |
3867 set_marker_restricted (w->pointm[CURRENT_DISP], make_int (1), buf); | |
3868 set_marker_restricted (w->sb_point, make_int (1), buf); | |
3869 } | |
3870 } | |
3871 | |
3872 static void | |
3873 make_dummy_parent (Lisp_Object window) | |
3874 { | |
3025 | 3875 Lisp_Object new_; |
428 | 3876 struct window *o = XWINDOW (window); |
3017 | 3877 struct window *p = ALLOC_LCRECORD_TYPE (struct window, &lrecord_window); |
428 | 3878 |
3025 | 3879 new_ = wrap_window (p); |
3017 | 3880 COPY_LCRECORD (p, o); |
428 | 3881 |
3882 /* Don't copy the pointers to the line start cache or the face | |
3883 instances. */ | |
3884 p->line_start_cache = Dynarr_new (line_start_cache); | |
3092 | 3885 #ifdef NEW_GC |
3886 p->face_cachels = Dynarr_lisp_new (face_cachel, | |
3887 &lrecord_face_cachel_dynarr, | |
3888 &lrecord_face_cachel); | |
3889 p->glyph_cachels = Dynarr_lisp_new (glyph_cachel, | |
3890 &lrecord_glyph_cachel_dynarr, | |
3891 &lrecord_glyph_cachel); | |
3892 #else /* not NEW_GC */ | |
428 | 3893 p->face_cachels = Dynarr_new (face_cachel); |
3894 p->glyph_cachels = Dynarr_new (glyph_cachel); | |
3092 | 3895 #endif /* not NEW_GC */ |
442 | 3896 p->subwindow_instance_cache = |
450 | 3897 make_image_instance_cache_hash_table (); |
428 | 3898 |
3899 /* Put new into window structure in place of window */ | |
3025 | 3900 replace_window (window, new_); |
428 | 3901 |
3902 o->next = Qnil; | |
3903 o->prev = Qnil; | |
3904 o->vchild = Qnil; | |
3905 o->hchild = Qnil; | |
3025 | 3906 o->parent = new_; |
428 | 3907 |
3908 p->start[CURRENT_DISP] = Qnil; | |
3909 p->start[DESIRED_DISP] = Qnil; | |
3910 p->start[CMOTION_DISP] = Qnil; | |
3911 p->pointm[CURRENT_DISP] = Qnil; | |
3912 p->pointm[DESIRED_DISP] = Qnil; | |
3913 p->pointm[CMOTION_DISP] = Qnil; | |
3914 p->sb_point = Qnil; | |
844 | 3915 p->saved_point_cache = make_saved_buffer_point_cache (); |
3916 p->saved_last_window_start_cache = make_saved_buffer_point_cache (); | |
428 | 3917 p->buffer = Qnil; |
3918 } | |
3919 | |
3920 DEFUN ("split-window", Fsplit_window, 0, 3, "", /* | |
3921 Split WINDOW, putting SIZE lines in the first of the pair. | |
444 | 3922 WINDOW defaults to the selected one and SIZE to half its size. |
707 | 3923 If optional third arg HORFLAG is non-nil, split side by side and put |
3924 SIZE columns in the first of the pair. The newly created window is | |
3925 returned. | |
428 | 3926 */ |
444 | 3927 (window, size, horflag)) |
428 | 3928 { |
3025 | 3929 Lisp_Object new_; |
428 | 3930 struct window *o, *p; |
3931 struct frame *f; | |
444 | 3932 int csize; |
428 | 3933 int psize; |
3934 | |
3935 if (NILP (window)) | |
3936 window = Fselected_window (Qnil); | |
3937 else | |
3938 CHECK_LIVE_WINDOW (window); | |
3939 | |
3940 o = XWINDOW (window); | |
3941 f = XFRAME (WINDOW_FRAME (o)); | |
3942 | |
444 | 3943 if (NILP (size)) |
428 | 3944 { |
3945 if (!NILP (horflag)) | |
3946 /* In the new scheme, we are symmetric with respect to separators | |
3947 so there is no need to do weird things here. */ | |
3948 { | |
956 | 3949 psize = (WINDOW_WIDTH (o) + window_divider_width (o)) >> 1; |
444 | 3950 csize = window_pixel_width_to_char_width (o, psize, 0); |
428 | 3951 } |
3952 else | |
3953 { | |
3954 psize = WINDOW_HEIGHT (o) >> 1; | |
444 | 3955 csize = window_pixel_height_to_char_height (o, psize, 1); |
428 | 3956 } |
3957 } | |
3958 else | |
3959 { | |
444 | 3960 CHECK_INT (size); |
3961 csize = XINT (size); | |
428 | 3962 if (!NILP (horflag)) |
444 | 3963 psize = window_char_width_to_pixel_width (o, csize, 0); |
428 | 3964 else |
444 | 3965 psize = window_char_height_to_pixel_height (o, csize, 1); |
428 | 3966 } |
3967 | |
3968 if (MINI_WINDOW_P (o)) | |
563 | 3969 invalid_operation ("Attempt to split minibuffer window", Qunbound); |
428 | 3970 else if (FRAME_NO_SPLIT_P (XFRAME (WINDOW_FRAME (o)))) |
563 | 3971 invalid_operation ("Attempt to split unsplittable frame", Qunbound); |
428 | 3972 |
3973 check_min_window_sizes (); | |
3974 | |
3975 if (NILP (horflag)) | |
3976 { | |
444 | 3977 if (csize < window_min_height) |
563 | 3978 signal_error (Qinvalid_operation, "Window height too small (after splitting)", make_int (csize)); |
444 | 3979 if (csize + window_min_height > window_char_height (o, 1)) |
563 | 3980 signal_error (Qinvalid_operation, "Window height too small (after splitting)", |
3981 make_int (window_char_height (o, 1) - csize)); | |
428 | 3982 if (NILP (o->parent) |
3983 || NILP (XWINDOW (o->parent)->vchild)) | |
3984 { | |
3985 make_dummy_parent (window); | |
448 | 3986 #if 0 |
3987 /* #### I can't understand why you have to reset face | |
3988 cachels here. This can cause crash so let's disable it | |
3989 and see the difference. See redisplay-tests.el --yh */ | |
428 | 3990 reset_face_cachels (XWINDOW (window)); |
448 | 3991 #endif |
3025 | 3992 new_ = o->parent; |
3993 XWINDOW (new_)->vchild = window; | |
428 | 3994 XFRAME (o->frame)->mirror_dirty = 1; |
3995 } | |
3996 } | |
3997 else | |
3998 { | |
444 | 3999 if (csize < window_min_width) |
563 | 4000 signal_error (Qinvalid_operation, "Window width too small (after splitting)", make_int (csize)); |
444 | 4001 if (csize + window_min_width > window_char_width (o, 0)) |
563 | 4002 signal_error (Qinvalid_operation, "Window width too small (after splitting)", |
4003 make_int (window_char_width (o, 0) - csize)); | |
428 | 4004 if (NILP (o->parent) |
4005 || NILP (XWINDOW (o->parent)->hchild)) | |
4006 { | |
4007 make_dummy_parent (window); | |
448 | 4008 #if 0 |
4009 /* #### See above. */ | |
428 | 4010 reset_face_cachels (XWINDOW (window)); |
448 | 4011 #endif |
3025 | 4012 new_ = o->parent; |
4013 XWINDOW (new_)->hchild = window; | |
428 | 4014 XFRAME (o->frame)->mirror_dirty = 1; |
4015 } | |
4016 } | |
4017 | |
4018 /* Now we know that window's parent is a vertical combination | |
4019 if we are dividing vertically, or a horizontal combination | |
4020 if we are making side-by-side windows */ | |
4021 | |
4022 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); | |
3025 | 4023 new_ = allocate_window (); |
4024 p = XWINDOW (new_); | |
428 | 4025 |
4026 p->frame = o->frame; | |
4027 p->next = o->next; | |
4028 if (!NILP (p->next)) | |
3025 | 4029 XWINDOW (p->next)->prev = new_; |
428 | 4030 p->prev = window; |
3025 | 4031 o->next = new_; |
428 | 4032 p->parent = o->parent; |
4033 p->buffer = Qt; | |
4034 | |
4035 reset_face_cachels (p); | |
4036 reset_glyph_cachels (p); | |
4037 | |
4038 | |
4039 /* Apportion the available frame space among the two new windows */ | |
4040 | |
4041 if (!NILP (horflag)) | |
4042 { | |
4043 WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o); | |
4044 WINDOW_TOP (p) = WINDOW_TOP (o); | |
4045 WINDOW_WIDTH (p) = WINDOW_WIDTH (o) - psize; | |
4046 WINDOW_WIDTH (o) = psize; | |
4047 WINDOW_LEFT (p) = WINDOW_LEFT (o) + psize; | |
4048 } | |
4049 else | |
4050 { | |
4051 WINDOW_LEFT (p) = WINDOW_LEFT (o); | |
4052 WINDOW_WIDTH (p) = WINDOW_WIDTH (o); | |
4053 WINDOW_HEIGHT (p) = WINDOW_HEIGHT (o) - psize; | |
4054 WINDOW_HEIGHT (o) = psize; | |
4055 WINDOW_TOP (p) = WINDOW_TOP (o) + psize; | |
4056 } | |
4057 | |
4058 XFRAME (p->frame)->mirror_dirty = 1; | |
853 | 4059 |
3025 | 4060 note_object_created (new_); |
853 | 4061 |
428 | 4062 /* do this last (after the window is completely initialized and |
4063 the mirror-dirty flag is set) so that specifier recomputation | |
4064 caused as a result of this will work properly and not abort. */ | |
3025 | 4065 Fset_window_buffer (new_, o->buffer, Qt); |
4066 return new_; | |
428 | 4067 } |
4068 | |
4069 | |
4070 DEFUN ("enlarge-window", Fenlarge_window, 1, 3, "_p", /* | |
444 | 4071 Make the selected window COUNT lines taller. |
4072 From program, optional second arg HORIZONTALP non-nil means grow | |
4073 sideways COUNT columns, and optional third arg WINDOW specifies the | |
4074 window to change instead of the selected window. | |
428 | 4075 */ |
444 | 4076 (count, horizontalp, window)) |
4077 { | |
4078 CHECK_INT (count); | |
4079 change_window_height (window, XINT (count), horizontalp, /* inpixels */ 0); | |
428 | 4080 return Qnil; |
4081 } | |
4082 | |
4083 DEFUN ("enlarge-window-pixels", Fenlarge_window_pixels, 1, 3, "_p", /* | |
444 | 4084 Make the selected window COUNT pixels taller. |
4085 From program, optional second arg HORIZONTALP non-nil means grow | |
4086 sideways COUNT pixels, and optional third arg WINDOW specifies the | |
4087 window to change instead of the selected window. | |
428 | 4088 */ |
444 | 4089 (count, horizontalp, window)) |
4090 { | |
4091 CHECK_INT (count); | |
4092 change_window_height (window, XINT (count), horizontalp, /* inpixels */ 1); | |
428 | 4093 return Qnil; |
4094 } | |
4095 | |
4096 DEFUN ("shrink-window", Fshrink_window, 1, 3, "_p", /* | |
444 | 4097 Make the selected window COUNT lines shorter. |
4098 From program, optional second arg HORIZONTALP non-nil means shrink | |
4099 sideways COUNT columns, and optional third arg WINDOW specifies the | |
4100 window to change instead of the selected window. | |
428 | 4101 */ |
444 | 4102 (count, horizontalp, window)) |
4103 { | |
4104 CHECK_INT (count); | |
4105 change_window_height (window, -XINT (count), horizontalp, /* inpixels */ 0); | |
428 | 4106 return Qnil; |
4107 } | |
4108 | |
4109 DEFUN ("shrink-window-pixels", Fshrink_window_pixels, 1, 3, "_p", /* | |
444 | 4110 Make the selected window COUNT pixels smaller. |
4111 From program, optional second arg HORIZONTALP non-nil means shrink | |
4112 sideways COUNT pixels, and optional third arg WINDOW specifies the | |
4113 window to change instead of the selected window. | |
428 | 4114 */ |
444 | 4115 (count, horizontalp, window)) |
4116 { | |
4117 CHECK_INT (count); | |
4118 change_window_height (window, -XINT (count), horizontalp, /* inpixels */ 1); | |
428 | 4119 return Qnil; |
4120 } | |
4121 | |
4122 static int | |
4123 window_pixel_height_to_char_height (struct window *w, int pixel_height, | |
4124 int include_gutters_p) | |
4125 { | |
4126 int avail_height; | |
4127 int defheight, defwidth; | |
3687 | 4128 int char_height = 0; |
793 | 4129 Lisp_Object window = wrap_window (w); |
4130 | |
428 | 4131 |
4132 avail_height = (pixel_height - | |
4133 (include_gutters_p ? 0 : | |
442 | 4134 window_top_window_gutter_height (w) + |
4135 window_bottom_window_gutter_height (w))); | |
428 | 4136 |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
4137 default_face_width_and_height (window, &defwidth, &defheight); |
428 | 4138 |
3687 | 4139 if (defheight) |
4140 char_height = avail_height / defheight; | |
428 | 4141 |
4142 /* It's the calling function's responsibility to check these values | |
4143 and make sure they're not out of range. | |
4144 | |
4145 #### We need to go through the calling functions and actually | |
4146 do this. */ | |
4147 return max (0, char_height); | |
4148 } | |
4149 | |
4150 static int | |
4151 window_char_height_to_pixel_height (struct window *w, int char_height, | |
4152 int include_gutters_p) | |
4153 { | |
4154 int avail_height; | |
4155 int defheight, defwidth; | |
4156 int pixel_height; | |
4157 | |
793 | 4158 Lisp_Object window = wrap_window (w); |
4159 | |
428 | 4160 |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
4161 default_face_width_and_height (window, &defwidth, &defheight); |
428 | 4162 |
4163 avail_height = char_height * defheight; | |
4164 pixel_height = (avail_height + | |
4165 (include_gutters_p ? 0 : | |
442 | 4166 window_top_window_gutter_height (w) + |
4167 window_bottom_window_gutter_height (w))); | |
428 | 4168 |
4169 /* It's the calling function's responsibility to check these values | |
4170 and make sure they're not out of range. | |
4171 | |
4172 #### We need to go through the calling functions and actually | |
4173 do this. */ | |
4174 return max (0, pixel_height); | |
4175 } | |
4176 | |
4177 /* Return number of default lines of text can fit in the window W. | |
4178 If INCLUDE_GUTTERS_P is 1, include "gutter" space (modeline plus | |
4179 horizontal scrollbar) in the space that is used for the calculation. | |
442 | 4180 This doesn't include space used by the frame gutters. |
428 | 4181 */ |
4182 int | |
4183 window_char_height (struct window *w, int include_gutters_p) | |
4184 { | |
442 | 4185 return window_pixel_height_to_char_height (w, window_pixel_height (w), |
428 | 4186 include_gutters_p); |
4187 } | |
4188 | |
4189 /* | |
4190 * Return number of lines currently displayed in window w. If | |
4191 * end-of-buffer is displayed then the area below end-of-buffer is assume | |
4192 * to be blank lines of default height. | |
4193 * Does not include the modeline. | |
4194 */ | |
4195 int | |
4196 window_displayed_height (struct window *w) | |
4197 { | |
4198 struct buffer *b = XBUFFER (w->buffer); | |
4199 display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP); | |
4200 int num_lines; | |
4201 Charcount end_pos = (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b) | |
4202 ? -1 | |
4203 : w->window_end_pos[CURRENT_DISP]); | |
4204 | |
4205 if (!Dynarr_length (dla)) | |
4206 return window_char_height (w, 0); | |
4207 | |
4208 num_lines = Dynarr_length (dla); | |
4209 | |
4210 /* #### Document and assert somewhere that w->window_end_pos == -1 | |
4211 indicates that end-of-buffer is being displayed. */ | |
4212 if (end_pos == -1) | |
4213 { | |
4967 | 4214 struct display_line *dl = Dynarr_begin (dla); |
428 | 4215 int ypos1 = dl->ypos + dl->descent; |
4216 int ypos2 = WINDOW_TEXT_BOTTOM (w); | |
4217 Lisp_Object window; | |
4218 int defheight, defwidth; | |
4219 | |
793 | 4220 window = wrap_window (w); |
428 | 4221 |
4222 if (dl->modeline) | |
4223 { | |
4224 num_lines--; | |
4225 | |
4226 if (Dynarr_length (dla) == 1) | |
4227 ypos1 = WINDOW_TEXT_TOP (w); | |
4228 else | |
4229 { | |
4230 dl = Dynarr_atp (dla, Dynarr_length (dla) - 1); | |
4231 /* If this line is clipped then we know that there is no | |
4232 blank room between eob and the modeline. If we are | |
4233 scrolling on clipped lines just know off the clipped | |
4234 line and return .*/ | |
4235 if (scroll_on_clipped_lines && dl->clip) | |
4236 return num_lines - 1; | |
4237 ypos1 = dl->ypos + dl->descent - dl->clip; | |
4238 } | |
4239 } | |
4240 | |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
4241 default_face_width_and_height (window, &defwidth, &defheight); |
428 | 4242 /* #### This probably needs to know about the clipping area once a |
4243 final definition is decided on. */ | |
3707 | 4244 if (defheight) |
4245 num_lines += ((ypos2 - ypos1) / defheight); | |
428 | 4246 } |
4247 else | |
4248 { | |
4967 | 4249 if (num_lines > 1 && Dynarr_begin (dla)->modeline) |
428 | 4250 num_lines--; |
4251 | |
4252 if (scroll_on_clipped_lines | |
4253 && Dynarr_atp (dla, Dynarr_length (dla) - 1)->clip) | |
4254 num_lines--; | |
4255 } | |
4256 | |
4257 return num_lines; | |
4258 } | |
4259 | |
4260 static int | |
4261 window_pixel_width (Lisp_Object window) | |
4262 { | |
4263 return WINDOW_WIDTH (XWINDOW (window)); | |
4264 } | |
4265 | |
442 | 4266 /* Calculate the pixel of a window, optionally including margin space |
4267 but no vertical gutters. */ | |
428 | 4268 static int |
4269 window_pixel_width_to_char_width (struct window *w, int pixel_width, | |
4270 int include_margins_p) | |
4271 { | |
4272 int avail_width; | |
3676 | 4273 int char_width = 0; |
428 | 4274 int defheight, defwidth; |
793 | 4275 Lisp_Object window = wrap_window (w); |
4276 | |
428 | 4277 |
4278 avail_width = (pixel_width - | |
4279 window_left_gutter_width (w, 0) - | |
4280 window_right_gutter_width (w, 0) - | |
4281 (include_margins_p ? 0 : window_left_margin_width (w)) - | |
4282 (include_margins_p ? 0 : window_right_margin_width (w))); | |
4283 | |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
4284 default_face_width_and_height (window, &defwidth, &defheight); |
428 | 4285 |
3676 | 4286 if (defwidth) |
4287 char_width = (avail_width / defwidth); | |
428 | 4288 |
4289 /* It's the calling function's responsibility to check these values | |
4290 and make sure they're not out of range. | |
4291 | |
4292 #### We need to go through the calling functions and actually | |
4293 do this. */ | |
4294 return max (0, char_width); | |
4295 } | |
4296 | |
4297 static int | |
4298 window_char_width_to_pixel_width (struct window *w, int char_width, | |
4299 int include_margins_p) | |
4300 { | |
4301 int avail_width; | |
4302 int pixel_width; | |
4303 int defheight, defwidth; | |
793 | 4304 Lisp_Object window = wrap_window (w); |
4305 | |
428 | 4306 |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
4307 default_face_width_and_height (window, &defwidth, &defheight); |
428 | 4308 |
4309 avail_width = char_width * defwidth; | |
4310 pixel_width = (avail_width + | |
442 | 4311 window_left_window_gutter_width (w, 0) + |
4312 window_right_window_gutter_width (w, 0) + | |
428 | 4313 (include_margins_p ? 0 : window_left_margin_width (w)) + |
4314 (include_margins_p ? 0 : window_right_margin_width (w))); | |
4315 | |
4316 /* It's the calling function's responsibility to check these values | |
4317 and make sure they're not out of range. | |
4318 | |
4319 #### We need to go through the calling functions and actually | |
4320 do this. */ | |
4321 return max (0, pixel_width); | |
4322 } | |
4323 | |
4324 /* This returns the usable space which doesn't include space needed by | |
4325 scrollbars or divider lines. */ | |
4326 int | |
4327 window_char_width (struct window *w, int include_margins_p) | |
4328 { | |
4329 return window_pixel_width_to_char_width (w, WINDOW_WIDTH (w), | |
4330 include_margins_p); | |
4331 } | |
4332 | |
4333 #define MINSIZE(w) \ | |
4334 (widthflag \ | |
4335 ? window_min_width * defwidth \ | |
4336 : (defheight * (MINI_WINDOW_P (XWINDOW (w)) ? 1 : window_min_height))) | |
4337 | |
4338 #define CURBEG(w) \ | |
4339 *(widthflag ? (int *) &WINDOW_LEFT (w) : (int *) &WINDOW_TOP (w)) | |
4340 | |
4341 #define CURSIZE(w) \ | |
4342 *(widthflag ? (int *) &WINDOW_WIDTH (w) : (int *) &WINDOW_HEIGHT (w)) | |
4343 | |
4344 #define CURCHARSIZE(w) \ | |
4345 (widthflag ? window_char_width (w, 0) : window_char_height (w, 1)) | |
4346 | |
4347 #define MINCHARSIZE(window) \ | |
4348 (widthflag ? window_min_width : MINI_WINDOW_P (XWINDOW (window)) \ | |
4349 ? 1 : window_min_height) | |
4350 | |
442 | 4351 static int |
4352 window_pixheight (Lisp_Object w) | |
4353 { | |
4354 return window_pixel_height (XWINDOW (w)); | |
4355 } | |
4356 | |
428 | 4357 /* Unlike set_window_pixheight, this function |
4358 also changes the heights of the siblings so as to | |
4359 keep everything consistent. */ | |
4360 | |
4361 static void | |
444 | 4362 change_window_height (Lisp_Object window, int delta, Lisp_Object horizontalp, |
428 | 4363 int inpixels) |
4364 { | |
444 | 4365 struct window *win = decode_window (window); |
4366 int widthflag = !NILP (horizontalp); | |
428 | 4367 Lisp_Object parent; |
4368 struct window *w; | |
4369 struct frame *f; | |
4370 int *sizep; | |
4371 int (*sizefun) (Lisp_Object) = (widthflag | |
4372 ? window_pixel_width | |
442 | 4373 : window_pixheight); |
428 | 4374 void (*setsizefun) (Lisp_Object, int, int) = (widthflag |
4375 ? set_window_pixwidth | |
4376 : set_window_pixheight); | |
4377 int dim; | |
4378 int defheight, defwidth; | |
4379 | |
4380 if (delta == 0) | |
4381 return; | |
4382 | |
4383 check_min_window_sizes (); | |
4384 | |
793 | 4385 window = wrap_window (win); |
428 | 4386 f = XFRAME (win->frame); |
4387 if (EQ (window, FRAME_ROOT_WINDOW (f))) | |
563 | 4388 invalid_operation ("Won't change only window", Qunbound); |
428 | 4389 |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
4390 default_face_width_and_height (window, &defwidth, &defheight); |
428 | 4391 |
4392 while (1) | |
4393 { | |
4394 w = XWINDOW (window); | |
4395 parent = w->parent; | |
4396 if (NILP (parent)) | |
4397 { | |
4398 if (widthflag) | |
3078 | 4399 { |
4400 int new_pixsize; | |
4401 sizep = &CURSIZE (w); | |
3466 | 4402 dim = CURCHARSIZE (w); |
3078 | 4403 new_pixsize = inpixels?(*sizep + delta):(dim+delta); |
4404 set_window_pixsize (window, new_pixsize, 0, 0); | |
4405 return; | |
4406 } | |
428 | 4407 break; |
4408 } | |
4409 if (widthflag | |
4410 ? !NILP (XWINDOW (parent)->hchild) | |
4411 : !NILP (XWINDOW (parent)->vchild)) | |
4412 break; | |
4413 window = parent; | |
4414 } | |
4415 | |
4416 sizep = &CURSIZE (w); | |
4417 dim = CURCHARSIZE (w); | |
4418 | |
4419 if ((inpixels && (*sizep + delta) < MINSIZE (window)) || | |
4420 (!inpixels && (dim + delta) < MINCHARSIZE (window))) | |
4421 { | |
4422 if (MINI_WINDOW_P (XWINDOW (window))) | |
4423 return; | |
4424 else if (!NILP (parent)) | |
4425 { | |
4426 Fdelete_window (window, Qnil); | |
4427 return; | |
4428 } | |
4429 } | |
4430 | |
4431 if (!inpixels) | |
4432 delta *= (widthflag ? defwidth : defheight); | |
4433 | |
4434 { | |
4435 int maxdelta; | |
4436 | |
4437 maxdelta = ((!NILP (parent)) | |
4438 ? (*sizefun) (parent) - *sizep | |
4439 : ((!NILP (w->next)) | |
4440 ? (*sizefun) (w->next) - MINSIZE (w->next) | |
4441 : ((!NILP (w->prev)) | |
4442 ? (*sizefun) (w->prev) - MINSIZE (w->prev) | |
4443 /* This is a frame with only one window, | |
4444 a minibuffer-only or a minibufferless frame. */ | |
4445 : (delta = 0)))); | |
4446 | |
4447 if (delta > maxdelta) | |
4448 /* This case traps trying to make the minibuffer | |
4449 the full frame, or make the only window aside from the | |
4450 minibuffer the full frame. */ | |
4451 delta = maxdelta; | |
4452 | |
4453 if (delta == 0) | |
4454 return; | |
4455 | |
4456 #if 0 /* FSFmacs */ | |
4457 /* #### Chuck: is this correct? */ | |
4458 if (*sizep + delta < MINSIZE (window)) | |
4459 { | |
4460 Fdelete_window (window); | |
4461 return; | |
4462 } | |
4463 #endif | |
4464 } | |
4465 | |
4466 if (!NILP (w->next) && | |
4467 (*sizefun) (w->next) - delta >= (int) MINSIZE (w->next)) | |
4468 { | |
4469 CURBEG (XWINDOW (w->next)) += delta; | |
4470 (*setsizefun) (w->next, (*sizefun) (w->next) - delta, 0); | |
4471 (*setsizefun) (window, *sizep + delta, 0); | |
4472 } | |
4473 else if (!NILP (w->prev) && | |
4474 (*sizefun) (w->prev) - delta >= (int) MINSIZE (w->prev)) | |
4475 { | |
4476 (*setsizefun) (w->prev, (*sizefun) (w->prev) - delta, 0); | |
4477 CURBEG (w) -= delta; | |
4478 (*setsizefun) (window, *sizep + delta, 0); | |
4479 } | |
4480 else | |
4481 { | |
4482 int delta1; | |
4483 int opht = (*sizefun) (parent); | |
4484 | |
4485 /* If trying to grow this window to or beyond size of the parent, | |
4486 make delta1 so big that, on shrinking back down, | |
4487 all the siblings end up with less than one line and are deleted. */ | |
4488 if (opht <= *sizep + delta) | |
4489 delta1 = opht * opht * 2; | |
4490 /* Otherwise, make delta1 just right so that if we add delta1 | |
4491 lines to this window and to the parent, and then shrink | |
4492 the parent back to its original size, the new proportional | |
4493 size of this window will increase by delta. */ | |
4494 else | |
4495 delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100); | |
4496 | |
4497 /* Add delta1 lines or columns to this window, and to the parent, | |
4498 keeping things consistent while not affecting siblings. */ | |
4499 CURSIZE (XWINDOW (parent)) = opht + delta1; | |
4500 (*setsizefun) (window, *sizep + delta1, 0); | |
4501 | |
4502 /* Squeeze out delta1 lines or columns from our parent, | |
4503 shrinking this window and siblings proportionately. | |
4504 This brings parent back to correct size. | |
4505 Delta1 was calculated so this makes this window the desired size, | |
4506 taking it all out of the siblings. */ | |
4507 (*setsizefun) (parent, opht, 0); | |
4508 } | |
4509 | |
4510 SET_LAST_MODIFIED (w, 0); | |
4511 SET_LAST_FACECHANGE (w); | |
4512 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (f); | |
4513 /* overkill maybe, but better to be correct */ | |
4514 MARK_FRAME_GUTTERS_CHANGED (f); | |
4515 } | |
4516 #undef MINSIZE | |
4517 #undef CURBEG | |
4518 #undef CURSIZE | |
4519 #undef CURCHARSIZE | |
4520 #undef MINCHARSIZE | |
4521 | |
4522 | |
4523 | |
444 | 4524 /* Scroll contents of window WINDOW up COUNT lines. |
4525 If COUNT < (top line height / average line height) then we just adjust | |
4526 the top clip. */ | |
428 | 4527 void |
444 | 4528 window_scroll (Lisp_Object window, Lisp_Object count, int direction, |
578 | 4529 Error_Behavior errb) |
428 | 4530 { |
4531 struct window *w = XWINDOW (window); | |
4532 struct buffer *b = XBUFFER (w->buffer); | |
4533 int selected = EQ (window, Fselected_window (Qnil)); | |
4534 int value = 0; | |
4535 Lisp_Object point, tem; | |
4536 display_line_dynarr *dla; | |
4537 int fheight, fwidth, modeline = 0; | |
4538 struct display_line* dl; | |
4539 | |
4540 if (selected) | |
4541 point = make_int (BUF_PT (b)); | |
4542 else | |
4543 { | |
665 | 4544 Charbpos pos = marker_position (w->pointm[CURRENT_DISP]); |
428 | 4545 |
4546 if (pos < BUF_BEGV (b)) | |
4547 pos = BUF_BEGV (b); | |
4548 else if (pos > BUF_ZV (b)) | |
4549 pos = BUF_ZV (b); | |
4550 | |
4551 point = make_int (pos); | |
4552 } | |
4553 | |
4554 /* Always set force_start so that redisplay_window will run | |
4555 the window-scroll-functions. */ | |
4556 w->force_start = 1; | |
4557 | |
4558 /* #### When the fuck does this happen? I'm so glad that history has | |
4559 completely documented the behavior of the scrolling functions under | |
4560 all circumstances. */ | |
1708 | 4561 tem = Fpos_visible_in_window_p (point, window, Qnil); |
428 | 4562 if (NILP (tem)) |
4563 { | |
4564 Fvertical_motion (make_int (-window_char_height (w, 0) / 2), | |
4565 window, Qnil); | |
4566 Fset_marker (w->start[CURRENT_DISP], point, w->buffer); | |
4567 w->start_at_line_beg = beginning_of_line_p (b, XINT (point)); | |
4568 WINDOW_TEXT_TOP_CLIP (w) = 0; | |
4569 MARK_WINDOWS_CHANGED (w); | |
4570 } | |
4571 | |
444 | 4572 if (!NILP (count)) |
428 | 4573 { |
444 | 4574 if (EQ (count, Qminus)) |
428 | 4575 direction *= -1; |
4576 else | |
4577 { | |
444 | 4578 count = Fprefix_numeric_value (count); |
4579 value = XINT (count) * direction; | |
428 | 4580 |
4581 if (!value) | |
4582 return; /* someone just made a pointless call */ | |
4583 } | |
4584 } | |
4585 | |
4586 /* If the user didn't specify how far to scroll then we have to figure it | |
4587 out by ourselves. */ | |
444 | 4588 if (NILP (count) || EQ (count, Qminus)) |
428 | 4589 { |
4590 /* Going forwards is easy. If that is what we are doing then just | |
4591 set value and the section which handles the user specifying a | |
4592 positive value will work. */ | |
4593 if (direction == 1) | |
4594 { | |
4595 value = window_displayed_height (w) - next_screen_context_lines; | |
4596 value = (value < 1 ? 1 : value); | |
4597 } | |
4598 | |
4599 /* Going backwards is hard. We can't use the same loop used if the | |
4600 user specified a negative value because we care about | |
4601 next_screen_context_lines. In a variable height world you don't | |
4602 know how many lines above you can actually be displayed and still | |
4603 have the context lines appear. So we leave value set to 0 and add | |
4604 a separate section to deal with this. */ | |
4605 | |
4606 } | |
4607 | |
4608 if (direction == 1 && !value) | |
4609 { | |
4610 return; | |
4611 } | |
4612 | |
4613 /* Determine parameters to test for partial line scrolling with. */ | |
4614 dla = window_display_lines (w, CURRENT_DISP); | |
4615 | |
4616 if (INTP (Vwindow_pixel_scroll_increment)) | |
4617 fheight = XINT (Vwindow_pixel_scroll_increment); | |
440 | 4618 else if (!NILP (Vwindow_pixel_scroll_increment)) |
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
5043
diff
changeset
|
4619 default_face_width_and_height (window, &fwidth, &fheight); |
438 | 4620 |
428 | 4621 if (Dynarr_length (dla) >= 1) |
4967 | 4622 modeline = Dynarr_begin (dla)->modeline; |
428 | 4623 |
4624 dl = Dynarr_atp (dla, modeline); | |
438 | 4625 |
428 | 4626 if (value > 0) |
4627 { | |
4628 /* Go for partial display line scrolling. This just means bumping | |
4629 the clip by a reasonable amount and redisplaying, everything else | |
4630 remains unchanged. */ | |
4631 if (!NILP (Vwindow_pixel_scroll_increment) | |
4632 && | |
4633 Dynarr_length (dla) >= (1 + modeline) | |
4634 && | |
458 | 4635 (dl->ascent - dl->top_clip) > fheight * value) |
428 | 4636 { |
4637 WINDOW_TEXT_TOP_CLIP (w) += value * fheight; | |
4638 MARK_WINDOWS_CHANGED (w); | |
4639 } | |
4640 else | |
4641 { | |
4642 int vtarget; | |
665 | 4643 Charbpos startp, old_start; |
438 | 4644 |
428 | 4645 if (WINDOW_TEXT_TOP_CLIP (w)) |
4646 { | |
4647 WINDOW_TEXT_TOP_CLIP (w) = 0; | |
4648 MARK_WINDOWS_CHANGED (w); | |
4649 } | |
4650 | |
4651 old_start = marker_position (w->start[CURRENT_DISP]); | |
4652 startp = vmotion (w, old_start, value, &vtarget); | |
438 | 4653 |
428 | 4654 if (vtarget < value && |
4655 (w->window_end_pos[CURRENT_DISP] == -1 | |
4656 || (BUF_Z (b) - w->window_end_pos[CURRENT_DISP] > BUF_ZV (b)))) | |
4657 { | |
563 | 4658 maybe_signal_error_1 (Qend_of_buffer, Qnil, Qwindow, errb); |
428 | 4659 return; |
4660 } | |
4661 else | |
4662 { | |
4663 set_marker_restricted (w->start[CURRENT_DISP], make_int (startp), | |
4664 w->buffer); | |
4665 w->force_start = 1; | |
4666 w->start_at_line_beg = beginning_of_line_p (b, startp); | |
4667 MARK_WINDOWS_CHANGED (w); | |
438 | 4668 |
1708 | 4669 if (!point_would_be_visible (w, startp, XINT (point), 0)) |
844 | 4670 Fset_window_point (wrap_window (w), make_int (startp)); |
428 | 4671 } |
4672 } | |
4673 } | |
4674 else if (value < 0) | |
4675 { | |
4676 /* Go for partial display line scrolling. This just means bumping | |
4677 the clip by a reasonable amount and redisplaying, everything else | |
4678 remains unchanged. */ | |
4679 if (!NILP (Vwindow_pixel_scroll_increment) | |
4680 && | |
4681 Dynarr_length (dla) >= (1 + modeline) | |
4682 && | |
4683 (dl->ascent - dl->top_clip) - fheight * value < | |
4684 (dl->ascent + dl->descent - dl->clip) | |
4685 && | |
4686 WINDOW_TEXT_TOP_CLIP (w) + value * fheight > 0) | |
4687 { | |
4688 WINDOW_TEXT_TOP_CLIP (w) += value * fheight; | |
4689 MARK_WINDOWS_CHANGED (w); | |
4690 } | |
4691 else | |
4692 { | |
4693 int vtarget; | |
665 | 4694 Charbpos startp, old_start; |
438 | 4695 |
428 | 4696 if (WINDOW_TEXT_TOP_CLIP (w)) |
4697 { | |
4698 WINDOW_TEXT_TOP_CLIP (w) = 0; | |
4699 MARK_WINDOWS_CHANGED (w); | |
4700 } | |
438 | 4701 |
428 | 4702 old_start = marker_position (w->start[CURRENT_DISP]); |
4703 startp = vmotion (w, old_start, value, &vtarget); | |
438 | 4704 |
428 | 4705 if (vtarget > value |
4706 && marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b)) | |
4707 { | |
563 | 4708 maybe_signal_error_1 (Qbeginning_of_buffer, Qnil, Qwindow, errb); |
428 | 4709 return; |
4710 } | |
4711 else | |
4712 { | |
4713 set_marker_restricted (w->start[CURRENT_DISP], make_int (startp), | |
4714 w->buffer); | |
4715 w->force_start = 1; | |
4716 w->start_at_line_beg = beginning_of_line_p (b, startp); | |
4717 MARK_WINDOWS_CHANGED (w); | |
438 | 4718 |
440 | 4719 /* #### Scroll back by less than a line. This code was |
4720 originally for scrolling over large pixmaps and it | |
4721 loses when a line being *exposed* at the top of the | |
4722 window is bigger than the current one. However, for | |
4723 pixel based scrolling in general we can guess that | |
4724 the line we are going to display is probably the same | |
4725 size as the one we are on. In that instance we can | |
4726 have a reasonable stab at a suitable top clip. Fixing | |
4727 this properly is hard (and probably slow) as we would | |
4728 have to call redisplay to figure out the exposed line | |
4729 size. */ | |
4730 if (!NILP (Vwindow_pixel_scroll_increment) | |
4731 && Dynarr_length (dla) >= (1 + modeline) | |
4732 && dl->ascent + fheight * value > 0) | |
4733 { | |
4734 WINDOW_TEXT_TOP_CLIP (w) = (dl->ascent + fheight * value); | |
4735 } | |
4736 | |
1708 | 4737 if (!point_would_be_visible (w, startp, XINT (point), 0)) |
428 | 4738 { |
665 | 4739 Charbpos new_point; |
438 | 4740 |
428 | 4741 if (MINI_WINDOW_P (w)) |
4742 new_point = startp; | |
4743 else | |
4744 new_point = start_of_last_line (w, startp); | |
438 | 4745 |
844 | 4746 Fset_window_point (wrap_window (w), make_int (new_point)); |
428 | 4747 } |
4748 } | |
4749 } | |
4750 } | |
4751 else /* value == 0 && direction == -1 */ | |
4752 { | |
4753 if (WINDOW_TEXT_TOP_CLIP (w)) | |
4754 { | |
4755 WINDOW_TEXT_TOP_CLIP (w) = 0; | |
4756 MARK_WINDOWS_CHANGED (w); | |
4757 } | |
4758 if (marker_position (w->start[CURRENT_DISP]) == BUF_BEGV (b)) | |
4759 { | |
563 | 4760 maybe_signal_error_1 (Qbeginning_of_buffer, Qnil, Qwindow, errb); |
428 | 4761 return; |
4762 } | |
4763 else | |
4764 { | |
4765 int vtarget; | |
4766 int movement = next_screen_context_lines - 1; | |
665 | 4767 Charbpos old_startp = marker_position (w->start[CURRENT_DISP]); |
4768 Charbpos bottom = vmotion (w, old_startp, movement, &vtarget); | |
4769 Charbpos startp = | |
428 | 4770 start_with_point_on_display_line (w, bottom, |
4771 -1 - (movement - vtarget)); | |
4772 | |
4773 if (startp >= old_startp) | |
4774 startp = vmotion (w, old_startp, -1, NULL); | |
4775 | |
4776 set_marker_restricted (w->start[CURRENT_DISP], make_int (startp), | |
4777 w->buffer); | |
4778 w->force_start = 1; | |
4779 w->start_at_line_beg = beginning_of_line_p (b, startp); | |
4780 MARK_WINDOWS_CHANGED (w); | |
4781 | |
1708 | 4782 if (!point_would_be_visible (w, startp, XINT (point), 0)) |
428 | 4783 { |
665 | 4784 Charbpos new_point = start_of_last_line (w, startp); |
428 | 4785 |
844 | 4786 Fset_window_point (wrap_window (w), make_int (new_point)); |
428 | 4787 } |
4788 } | |
4789 } | |
4790 } | |
4791 | |
4792 DEFUN ("scroll-up", Fscroll_up, 0, 1, "_P", /* | |
444 | 4793 Scroll text of current window up COUNT lines; or near full screen if no arg. |
428 | 4794 A near full screen is `next-screen-context-lines' less than a full screen. |
444 | 4795 Negative COUNT means scroll downward. |
428 | 4796 When calling from a program, supply an integer as argument or nil. |
4797 On attempt to scroll past end of buffer, `end-of-buffer' is signaled. | |
4798 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is | |
4799 signaled. | |
462 | 4800 |
4801 The characters that are moved over may be added to the current selection | |
4802 \(i.e. active region) if the Shift key is held down, a motion key is used | |
4803 to invoke this command, and `shifted-motion-keys-select-region' is t; see | |
4804 the documentation for this variable for more details. | |
428 | 4805 */ |
444 | 4806 (count)) |
4807 { | |
4808 window_scroll (Fselected_window (Qnil), count, 1, ERROR_ME); | |
428 | 4809 return Qnil; |
4810 } | |
4811 | |
4812 DEFUN ("scroll-down", Fscroll_down, 0, 1, "_P", /* | |
444 | 4813 Scroll text of current window down COUNT lines; or near full screen if no arg. |
428 | 4814 A near full screen is `next-screen-context-lines' less than a full screen. |
444 | 4815 Negative COUNT means scroll upward. |
428 | 4816 When calling from a program, supply a number as argument or nil. |
4817 On attempt to scroll past end of buffer, `end-of-buffer' is signaled. | |
4818 On attempt to scroll past beginning of buffer, `beginning-of-buffer' is | |
4819 signaled. | |
462 | 4820 |
4821 The characters that are moved over may be added to the current selection | |
4822 \(i.e. active region) if the Shift key is held down, a motion key is used | |
4823 to invoke this command, and `shifted-motion-keys-select-region' is t; see | |
4824 the documentation for this variable for more details. | |
428 | 4825 */ |
444 | 4826 (count)) |
4827 { | |
4828 window_scroll (Fselected_window (Qnil), count, -1, ERROR_ME); | |
428 | 4829 return Qnil; |
4830 } | |
4831 | |
4832 DEFUN ("other-window-for-scrolling", Fother_window_for_scrolling, 0, 0, 0, /* | |
4833 Return the other window for "other window scroll" commands. | |
4834 If in the minibuffer, `minibuffer-scroll-window' if non-nil | |
4835 specifies the window. | |
4836 If `other-window-scroll-buffer' is non-nil, a window | |
4837 showing that buffer is used. | |
4838 */ | |
4839 ()) | |
4840 { | |
4841 Lisp_Object window; | |
4842 Lisp_Object selected_window = Fselected_window (Qnil); | |
4843 | |
4844 if (MINI_WINDOW_P (XWINDOW (selected_window)) | |
4845 && !NILP (Vminibuffer_scroll_window)) | |
4846 window = Vminibuffer_scroll_window; | |
4847 /* If buffer is specified, scroll that buffer. */ | |
4848 else if (!NILP (Vother_window_scroll_buffer)) | |
4849 { | |
4850 window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil, Qnil); | |
4851 if (NILP (window)) | |
4852 window = display_buffer (Vother_window_scroll_buffer, Qt, Qnil); | |
4853 } | |
4854 else | |
4855 { | |
4856 /* Nothing specified; look for a neighboring window on the same | |
4857 frame. */ | |
4858 window = Fnext_window (selected_window, Qnil, Qnil, Qnil); | |
4859 | |
4860 if (EQ (window, selected_window)) | |
4861 /* That didn't get us anywhere; look for a window on another | |
4862 visible frame. */ | |
4863 do | |
4864 window = Fnext_window (window, Qnil, Qt, Qnil); | |
4865 while (! FRAME_VISIBLE_P (XFRAME (WINDOW_FRAME (XWINDOW (window)))) | |
4866 && ! EQ (window, selected_window)); | |
4867 } | |
4868 | |
4869 CHECK_LIVE_WINDOW (window); | |
4870 | |
4871 if (EQ (window, selected_window)) | |
563 | 4872 invalid_operation ("There is no other window", Qunbound); |
428 | 4873 |
4874 return window; | |
4875 } | |
4876 | |
4877 DEFUN ("scroll-other-window", Fscroll_other_window, 0, 1, "_P", /* | |
444 | 4878 Scroll next window upward COUNT lines; or near full frame if no arg. |
428 | 4879 The next window is the one below the current one; or the one at the top |
444 | 4880 if the current one is at the bottom. Negative COUNT means scroll downward. |
428 | 4881 When calling from a program, supply a number as argument or nil. |
4882 | |
4883 If in the minibuffer, `minibuffer-scroll-window' if non-nil | |
4884 specifies the window to scroll. | |
4885 If `other-window-scroll-buffer' is non-nil, scroll the window | |
4886 showing that buffer, popping the buffer up if necessary. | |
4887 */ | |
444 | 4888 (count)) |
4889 { | |
4890 window_scroll (Fother_window_for_scrolling (), count, 1, ERROR_ME); | |
428 | 4891 return Qnil; |
4892 } | |
4893 | |
4894 DEFUN ("scroll-left", Fscroll_left, 0, 1, "_P", /* | |
444 | 4895 Scroll selected window display COUNT columns left. |
4896 Default for COUNT is window width minus 2. | |
462 | 4897 |
4898 The characters that are moved over may be added to the current selection | |
4899 \(i.e. active region) if the Shift key is held down, a motion key is used | |
4900 to invoke this command, and `shifted-motion-keys-select-region' is t; see | |
4901 the documentation for this variable for more details. | |
428 | 4902 */ |
444 | 4903 (count)) |
428 | 4904 { |
4905 Lisp_Object window = Fselected_window (Qnil); | |
4906 struct window *w = XWINDOW (window); | |
444 | 4907 int n = (NILP (count) ? |
4908 window_char_width (w, 0) - 2 : | |
4909 XINT (Fprefix_numeric_value (count))); | |
4910 | |
4911 return Fset_window_hscroll (window, make_int (w->hscroll + n)); | |
428 | 4912 } |
4913 | |
4914 DEFUN ("scroll-right", Fscroll_right, 0, 1, "_P", /* | |
444 | 4915 Scroll selected window display COUNT columns right. |
4916 Default for COUNT is window width minus 2. | |
462 | 4917 |
4918 The characters that are moved over may be added to the current selection | |
4919 \(i.e. active region) if the Shift key is held down, a motion key is used | |
4920 to invoke this command, and `shifted-motion-keys-select-region' is t; see | |
4921 the documentation for this variable for more details. | |
428 | 4922 */ |
444 | 4923 (count)) |
428 | 4924 { |
4925 Lisp_Object window = Fselected_window (Qnil); | |
4926 struct window *w = XWINDOW (window); | |
444 | 4927 int n = (NILP (count) ? |
4928 window_char_width (w, 0) - 2 : | |
4929 XINT (Fprefix_numeric_value (count))); | |
4930 | |
4931 return Fset_window_hscroll (window, make_int (w->hscroll - n)); | |
428 | 4932 } |
4933 | |
4934 DEFUN ("center-to-window-line", Fcenter_to_window_line, 0, 2, "_P", /* | |
4935 Center point in WINDOW. With N, put point on line N. | |
4936 The desired position of point is always relative to the window. | |
4937 If WINDOW is nil, the selected window is used. | |
4938 */ | |
4939 (n, window)) | |
4940 { | |
4941 struct window *w = decode_window (window); | |
4942 struct buffer *b = XBUFFER (w->buffer); | |
665 | 4943 Charbpos opoint = BUF_PT (b); |
4944 Charbpos startp; | |
428 | 4945 |
4946 if (NILP (n)) | |
4947 startp = start_with_line_at_pixpos (w, opoint, window_half_pixpos (w)); | |
4948 else | |
4949 { | |
4950 n = Fprefix_numeric_value (n); | |
4951 CHECK_INT (n); | |
4952 startp = start_with_point_on_display_line (w, opoint, XINT (n)); | |
4953 } | |
4954 | |
4955 Fset_marker (w->start[CURRENT_DISP], make_int (startp), w->buffer); | |
4956 | |
4957 w->start_at_line_beg = beginning_of_line_p (b, startp); | |
4958 w->force_start = 1; | |
4959 MARK_WINDOWS_CHANGED (w); | |
4960 return Qnil; | |
4961 } | |
4962 | |
4963 DEFUN ("move-to-window-line", Fmove_to_window_line, 1, 2, "_P", /* | |
4964 Position point relative to WINDOW. | |
4965 With no argument, position text at center of window. | |
4966 An argument specifies window line; zero means top of window, | |
4967 negative means relative to bottom of window. | |
4968 If WINDOW is nil, the selected window is used. | |
4969 */ | |
4970 (arg, window)) | |
4971 { | |
4972 struct window *w; | |
4973 struct buffer *b; | |
4974 int height; | |
665 | 4975 Charbpos start, new_point; |
428 | 4976 int selected; |
4977 | |
4978 /* Don't use decode_window() because we need the new value of | |
4979 WINDOW. */ | |
4980 if (NILP (window)) | |
4981 window = Fselected_window (Qnil); | |
4982 else | |
4983 CHECK_LIVE_WINDOW (window); | |
4984 w = XWINDOW (window); | |
4985 b = XBUFFER (w->buffer); | |
4986 | |
4987 height = window_displayed_height (w); | |
4988 selected = EQ (window, Fselected_window (w->frame)); | |
4989 | |
4990 if (NILP (arg)) | |
4991 { | |
4992 int retval; | |
4993 | |
4994 if (XINT (w->last_modified[CURRENT_DISP]) >= BUF_MODIFF (b) | |
4995 && XINT (w->last_facechange[CURRENT_DISP]) >= BUF_FACECHANGE (b)) | |
4996 { | |
4997 new_point = point_at_center (w, CURRENT_DISP, 0, 0); | |
4998 | |
844 | 4999 /* #### Here we are checking the selected window of the frame |
5000 instead of the selected window period. Elsewhere we check | |
5001 the selected window of the device. What a mess! */ | |
428 | 5002 if (selected) |
5003 BUF_SET_PT (b, new_point); | |
5004 else | |
5005 Fset_window_point (window, make_int (new_point)); | |
5006 | |
5007 retval = line_at_center (w, CURRENT_DISP, 0, 0); | |
5008 } | |
5009 else | |
5010 { | |
5011 start = marker_position (w->start[CURRENT_DISP]); | |
5012 if (start < BUF_BEGV (b)) | |
5013 start = BUF_BEGV (b); | |
5014 else if (start > BUF_ZV (b)) | |
5015 start = BUF_ZV (b); | |
5016 | |
5017 if (selected) | |
5018 new_point = BUF_PT (b); | |
5019 else | |
5020 new_point = marker_position (w->pointm[CURRENT_DISP]); | |
5021 | |
5022 new_point = point_at_center (w, CMOTION_DISP, start, BUF_PT (b)); | |
5023 | |
5024 if (selected) | |
5025 BUF_SET_PT (b, new_point); | |
5026 else | |
5027 Fset_window_point (window, make_int (new_point)); | |
5028 | |
5029 retval = line_at_center (w, CMOTION_DISP, start, BUF_PT (b)); | |
5030 } | |
5031 | |
5032 return make_int (retval); | |
5033 } | |
5034 else | |
5035 { | |
5036 /* #### Is this going to work right when at eob? */ | |
5037 arg = Fprefix_numeric_value (arg); | |
5038 if (XINT (arg) < 0) | |
793 | 5039 arg = make_int (XINT (arg) + height); |
428 | 5040 } |
5041 | |
5042 start = marker_position (w->start[CURRENT_DISP]); | |
5043 if (start < BUF_BEGV (b) || start > BUF_ZV (b)) | |
5044 { | |
5045 if (selected) | |
5046 new_point = BUF_PT (b); | |
5047 else | |
5048 new_point = marker_position (w->pointm[CURRENT_DISP]); | |
5049 | |
5050 new_point = vmotion (XWINDOW (window), new_point, -height / 2, 0); | |
5051 | |
5052 if (selected) | |
5053 BUF_SET_PT (b, new_point); | |
5054 else | |
5055 Fset_window_point (window, make_int (new_point)); | |
5056 | |
5057 Fset_marker (w->start[CURRENT_DISP], make_int (new_point), | |
5058 w->buffer); | |
5059 w->start_at_line_beg = beginning_of_line_p (b, new_point); | |
5060 w->force_start = 1; | |
5061 } | |
5062 else | |
5063 { | |
5064 if (selected) | |
5065 BUF_SET_PT (b, start); | |
5066 else | |
5067 Fset_window_point (window, make_int (start)); | |
5068 } | |
5069 | |
5070 if (selected) | |
5071 return Fvertical_motion (arg, window, Qnil); | |
5072 else | |
5073 { | |
5074 int vpos; | |
5075 new_point = vmotion (XWINDOW (window), | |
5076 marker_position (w->pointm[CURRENT_DISP]), | |
5077 XINT (arg), &vpos); | |
5078 Fset_window_point (window, make_int (new_point)); | |
5079 return make_int (vpos); | |
5080 } | |
5081 } | |
5082 | |
5083 | |
5084 static int | |
5085 map_windows_1 (Lisp_Object window, | |
5086 int (*mapfun) (struct window *w, void *closure), | |
5087 void *closure) | |
5088 { | |
5089 for (; !NILP (window); window = XWINDOW (window)->next) | |
5090 { | |
5091 int retval; | |
5092 struct window *w = XWINDOW (window); | |
5093 | |
5094 if (!NILP (w->vchild)) | |
5095 retval = map_windows_1 (w->vchild, mapfun, closure); | |
5096 else if (!NILP (w->hchild)) | |
5097 retval = map_windows_1 (w->hchild, mapfun, closure); | |
5098 else | |
5099 retval = (mapfun) (w, closure); | |
5100 | |
5101 if (retval) | |
5102 return retval; | |
5103 } | |
5104 | |
5105 return 0; | |
5106 } | |
5107 | |
5108 /* Map MAPFUN over the windows in F. CLOSURE is passed to each | |
5109 invocation of MAPFUN. If any invocation of MAPFUN returns | |
5110 non-zero, the mapping is halted. Otherwise, map_windows() maps | |
5111 over all windows in F. | |
5112 | |
800 | 5113 If F is null, map over all frames on all devices and consoles. |
5114 | |
428 | 5115 If MAPFUN creates or deletes windows, the behavior is undefined. */ |
5116 | |
5117 int | |
5118 map_windows (struct frame *f, int (*mapfun) (struct window *w, void *closure), | |
5119 void *closure) | |
5120 { | |
5121 if (f) | |
5122 return map_windows_1 (FRAME_ROOT_WINDOW (f), mapfun, closure); | |
5123 else | |
5124 { | |
5125 Lisp_Object frmcons, devcons, concons; | |
5126 | |
5127 FRAME_LOOP_NO_BREAK(frmcons, devcons, concons) | |
5128 { | |
5129 int v = map_windows_1 (FRAME_ROOT_WINDOW (XFRAME (XCAR (frmcons))), | |
5130 mapfun, closure); | |
5131 if (v) | |
5132 return v; | |
5133 } | |
5134 } | |
5135 | |
5136 return 0; | |
5137 } | |
5138 | |
5139 | |
5140 static void | |
2286 | 5141 modeline_shadow_thickness_changed (Lisp_Object UNUSED (specifier), |
5142 struct window *w, | |
5143 Lisp_Object UNUSED (oldval)) | |
428 | 5144 { |
5145 w->shadow_thickness_changed = 1; | |
5146 MARK_WINDOWS_CHANGED (w); | |
5147 } | |
5148 | |
5149 static void | |
2286 | 5150 vertical_divider_changed_in_window (Lisp_Object UNUSED (specifier), |
428 | 5151 struct window *w, |
2286 | 5152 Lisp_Object UNUSED (oldval)) |
428 | 5153 { |
5154 MARK_WINDOWS_CHANGED (w); | |
5155 MARK_FRAME_WINDOWS_STRUCTURE_CHANGED (XFRAME (WINDOW_FRAME (w))); | |
5156 } | |
5157 | |
5158 /* also used in scrollbar.c */ | |
5159 void | |
2286 | 5160 some_window_value_changed (Lisp_Object UNUSED (specifier), |
5161 struct window *w, | |
5162 Lisp_Object UNUSED (oldval)) | |
428 | 5163 { |
5164 MARK_WINDOWS_CHANGED (w); | |
5165 } | |
5166 | |
5167 #ifdef MEMORY_USAGE_STATS | |
5168 | |
5169 struct window_stats | |
5170 { | |
5171 int face; | |
5172 int glyph; | |
5173 #ifdef HAVE_SCROLLBARS | |
5174 int scrollbar; | |
5175 #endif | |
5176 int line_start; | |
5177 int other_redisplay; | |
5178 int other; | |
5179 }; | |
5180 | |
5181 static void | |
5182 compute_window_mirror_usage (struct window_mirror *mir, | |
5183 struct window_stats *stats, | |
5184 struct overhead_stats *ovstats) | |
5185 { | |
5186 if (!mir) | |
5187 return; | |
3024 | 5188 stats->other += LISPOBJ_STORAGE_SIZE (mir, sizeof (*mir), ovstats); |
428 | 5189 #ifdef HAVE_SCROLLBARS |
5190 { | |
5191 struct device *d = XDEVICE (FRAME_DEVICE (mir->frame)); | |
5192 | |
5193 stats->scrollbar += | |
5194 compute_scrollbar_instance_usage (d, mir->scrollbar_vertical_instance, | |
5195 ovstats); | |
5196 stats->scrollbar += | |
5197 compute_scrollbar_instance_usage (d, mir->scrollbar_horizontal_instance, | |
5198 ovstats); | |
5199 } | |
5200 #endif /* HAVE_SCROLLBARS */ | |
5201 stats->other_redisplay += | |
5202 compute_display_line_dynarr_usage (mir->current_display_lines, ovstats); | |
5203 stats->other_redisplay += | |
5204 compute_display_line_dynarr_usage (mir->desired_display_lines, ovstats); | |
5205 } | |
5206 | |
5207 static void | |
5208 compute_window_usage (struct window *w, struct window_stats *stats, | |
5209 struct overhead_stats *ovstats) | |
5210 { | |
5211 xzero (*stats); | |
3024 | 5212 stats->other += LISPOBJ_STORAGE_SIZE (w, sizeof (*w), ovstats); |
428 | 5213 stats->face += compute_face_cachel_usage (w->face_cachels, ovstats); |
5214 stats->glyph += compute_glyph_cachel_usage (w->glyph_cachels, ovstats); | |
5215 stats->line_start += | |
5216 compute_line_start_cache_dynarr_usage (w->line_start_cache, ovstats); | |
5217 compute_window_mirror_usage (find_window_mirror (w), stats, ovstats); | |
5218 } | |
5219 | |
5220 DEFUN ("window-memory-usage", Fwindow_memory_usage, 1, 1, 0, /* | |
5221 Return stats about the memory usage of window WINDOW. | |
5222 The values returned are in the form of an alist of usage types and byte | |
5223 counts. The byte counts attempt to encompass all the memory used | |
5224 by the window (separate from the memory logically associated with a | |
5225 buffer or frame), including internal structures and any malloc() | |
5226 overhead associated with them. In practice, the byte counts are | |
5227 underestimated because certain memory usage is very hard to determine | |
5228 \(e.g. the amount of memory used inside the Xt library or inside the | |
5229 X server) and because there is other stuff that might logically | |
5230 be associated with a window, buffer, or frame (e.g. window configurations, | |
5231 glyphs) but should not obviously be included in the usage counts. | |
5232 | |
5233 Multiple slices of the total memory usage may be returned, separated | |
5234 by a nil. Each slice represents a particular view of the memory, a | |
5235 particular way of partitioning it into groups. Within a slice, there | |
5236 is no overlap between the groups of memory, and each slice collectively | |
5237 represents all the memory concerned. | |
5238 */ | |
5239 (window)) | |
5240 { | |
5241 struct window_stats stats; | |
5242 struct overhead_stats ovstats; | |
5243 Lisp_Object val = Qnil; | |
5244 | |
5245 CHECK_WINDOW (window); /* dead windows should be allowed, no? */ | |
5246 xzero (ovstats); | |
5247 compute_window_usage (XWINDOW (window), &stats, &ovstats); | |
5248 | |
5249 val = acons (Qface_cache, make_int (stats.face), val); | |
5250 val = acons (Qglyph_cache, make_int (stats.glyph), val); | |
5251 #ifdef HAVE_SCROLLBARS | |
5252 val = acons (Qscrollbar_instances, make_int (stats.scrollbar), val); | |
5253 #endif | |
5254 val = acons (Qline_start_cache, make_int (stats.line_start), val); | |
5255 val = acons (Qother_redisplay, make_int (stats.other_redisplay), val); | |
5256 val = acons (Qother, make_int (stats.other), val); | |
5257 val = Fcons (Qnil, val); | |
5258 val = acons (Qactually_requested, make_int (ovstats.was_requested), val); | |
5259 val = acons (Qmalloc_overhead, make_int (ovstats.malloc_overhead), val); | |
5260 val = acons (Qdynarr_overhead, make_int (ovstats.dynarr_overhead), val); | |
5261 | |
5262 return Fnreverse (val); | |
5263 } | |
5264 | |
5265 #endif /* MEMORY_USAGE_STATS */ | |
5266 | |
5267 /* Mark all subwindows of a window as deleted. The argument | |
5268 W is actually the subwindow tree of the window in question. */ | |
5269 | |
5270 void | |
5271 delete_all_subwindows (struct window *w) | |
5272 { | |
5273 if (!NILP (w->next)) delete_all_subwindows (XWINDOW (w->next)); | |
5274 if (!NILP (w->vchild)) delete_all_subwindows (XWINDOW (w->vchild)); | |
5275 if (!NILP (w->hchild)) delete_all_subwindows (XWINDOW (w->hchild)); | |
5276 | |
5277 mark_window_as_deleted (w); | |
5278 } | |
5279 | |
1149 | 5280 |
2289 | 5281 static int |
5282 get_current_pixel_pos (Lisp_Object window, Lisp_Object pos, | |
5283 struct window **w, | |
5284 struct rune **rb, struct display_line **dl) | |
428 | 5285 { |
2289 | 5286 display_line_dynarr *dla; |
5287 struct display_block *db = NULL; | |
5288 int x, y; | |
5289 | |
5290 *rb = NULL; | |
5291 *dl = NULL; | |
5292 *w = decode_window (window); | |
5293 dla = window_display_lines (*w, CURRENT_DISP); | |
5294 x = (*w)->last_point_x[CURRENT_DISP]; | |
5295 y = (*w)->last_point_y[CURRENT_DISP]; | |
5296 if (MINI_WINDOW_P (*w)) | |
5297 return 0; | |
428 | 5298 |
5299 if (y<0 || x<0 || y >= Dynarr_length (dla) || !NILP (pos)) | |
5300 { | |
5301 int first_line, i; | |
665 | 5302 Charbpos point; |
428 | 5303 |
5304 if (NILP (pos)) | |
5305 pos = Fwindow_point (window); | |
438 | 5306 |
428 | 5307 CHECK_INT (pos); |
5308 point = XINT (pos); | |
5309 | |
4967 | 5310 if (Dynarr_length (dla) && Dynarr_begin (dla)->modeline) |
428 | 5311 first_line = 1; |
5312 else | |
5313 first_line = 0; | |
5314 | |
5315 for (i = first_line; i < Dynarr_length (dla); i++) | |
5316 { | |
2289 | 5317 *dl = Dynarr_atp (dla, i); |
428 | 5318 /* find the vertical location first */ |
2289 | 5319 if (point >= (*dl)->charpos && point <= (*dl)->end_charpos) |
428 | 5320 { |
2289 | 5321 db = get_display_block_from_line (*dl, TEXT); |
428 | 5322 for (i = 0; i < Dynarr_length (db->runes); i++) |
5323 { | |
2289 | 5324 *rb = Dynarr_atp (db->runes, i); |
2290 | 5325 if (point <= (*rb)->charpos) |
826 | 5326 goto found_charpos; |
428 | 5327 } |
2289 | 5328 return 0; |
428 | 5329 } |
5330 } | |
2289 | 5331 return 0; |
826 | 5332 found_charpos: |
428 | 5333 ; |
5334 } | |
5335 else | |
5336 { | |
442 | 5337 /* optimized case */ |
2289 | 5338 *dl = Dynarr_atp (dla, y); |
5339 db = get_display_block_from_line (*dl, TEXT); | |
428 | 5340 |
5341 if (x >= Dynarr_length (db->runes)) | |
2289 | 5342 return 0; |
5343 | |
5344 *rb = Dynarr_atp (db->runes, x); | |
428 | 5345 } |
5346 | |
2289 | 5347 return 1; |
5348 } | |
5349 | |
5350 DEFUN ("current-pixel-column", Fcurrent_pixel_column, 0, 2, 0, /* | |
5351 Return the horizontal pixel position of point POS in window. | |
5352 Beginning of line is column 0. If WINDOW is nil, the current window | |
5353 is assumed. If POS is nil, point is assumed. Note that POS must be | |
5354 visible for a non-nil result to be returned. This is calculated using | |
5355 the redisplay display tables; because of this, the returned value will | |
5356 only be correct if the redisplay tables are up-to-date. Use | |
5357 \"(sit-for 0)\" to insure that they are; however, if WINDOW is part of | |
5358 a new frame, use the following instead: | |
5359 (while (not (frame-visible-p frame)) (sleep-for .5)) | |
5360 */ | |
5361 (window, pos)) | |
5362 { | |
5363 struct window* w; | |
5364 struct display_line *dl; | |
5365 struct rune* rb; | |
5366 | |
5367 if (!get_current_pixel_pos(window, pos, &w, &rb, &dl)) | |
5368 return Qnil; | |
5369 | |
428 | 5370 return make_int (rb->xpos - WINDOW_LEFT (w)); |
5371 } | |
5372 | |
2289 | 5373 DEFUN ("current-pixel-row", Fcurrent_pixel_row, 0, 2, 0, /* |
5374 Return the vertical pixel position of point POS in window. Top of | |
5375 window is row 0. If WINDOW is nil, the current window is assumed. If | |
5376 POS is nil, point is assumed. Note that POS must be visible for a | |
5377 non-nil result to be returned. This is calculated using the redisplay | |
5378 display tables; because of this, the returned value will only be | |
5379 correct if the redisplay tables are up-to-date. Use \"(sit-for 0)\" | |
5380 to insure that they are; however, if WINDOW is part of a new frame, | |
5381 use the following instead: | |
5382 (while (not (frame-visible-p frame)) (sleep-for .5)) | |
5383 */ | |
5384 (window, pos)) | |
5385 { | |
5386 struct window* w; | |
5387 struct display_line *dl; | |
5388 struct rune* rb; | |
5389 | |
5390 if (!get_current_pixel_pos(window, pos, &w, &rb, &dl)) | |
5391 return Qnil; | |
5392 | |
5393 return make_int (dl->ypos - dl->ascent - WINDOW_TOP (w)); | |
5394 } | |
5395 | |
428 | 5396 |
5397 #ifdef DEBUG_XEMACS | |
5398 /* This is short and simple in elisp, but... it was written to debug | |
5399 problems purely on the C side. That is where we need to call it so | |
5400 here it is. */ | |
5401 static void | |
5402 debug_print_window (Lisp_Object window, int level) | |
5403 { | |
5404 int i; | |
5405 Lisp_Object child = Fwindow_first_vchild (window); | |
5406 | |
5407 if (NILP (child)) | |
5408 child = Fwindow_first_hchild (window); | |
5409 | |
5410 for (i = level; i > 0; i--) | |
442 | 5411 stderr_out ("\t"); |
5412 | |
5413 stderr_out ("#<window"); | |
428 | 5414 { |
5415 Lisp_Object buffer = XWINDOW (window)->buffer; | |
5416 if (!NILP (buffer) && BUFFERP (buffer)) | |
442 | 5417 stderr_out (" on %s", XSTRING_DATA (XBUFFER (buffer)->name)); |
428 | 5418 } |
442 | 5419 stderr_out (" 0x%x>", XWINDOW (window)->header.uid); |
428 | 5420 |
5421 while (!NILP (child)) | |
5422 { | |
5423 debug_print_window (child, level + 1); | |
5424 child = Fwindow_next_child (child); | |
5425 } | |
5426 } | |
5427 | |
5428 void debug_print_windows (struct frame *f); | |
5429 void | |
5430 debug_print_windows (struct frame *f) | |
5431 { | |
5432 debug_print_window (f->root_window, 0); | |
5433 putc ('\n', stderr); | |
5434 } | |
5435 #endif /* DEBUG_XEMACS */ | |
5436 | |
5437 | |
5438 /************************************************************************/ | |
5439 /* initialization */ | |
5440 /************************************************************************/ | |
5441 | |
5442 void | |
5443 syms_of_window (void) | |
5444 { | |
442 | 5445 INIT_LRECORD_IMPLEMENTATION (window); |
617 | 5446 INIT_LRECORD_IMPLEMENTATION (window_mirror); |
3092 | 5447 #ifdef NEW_GC |
5448 INIT_LRECORD_IMPLEMENTATION (face_cachel); | |
5449 INIT_LRECORD_IMPLEMENTATION (face_cachel_dynarr); | |
5450 INIT_LRECORD_IMPLEMENTATION (glyph_cachel); | |
5451 INIT_LRECORD_IMPLEMENTATION (glyph_cachel_dynarr); | |
5452 #endif /* NEW_GC */ | |
442 | 5453 |
563 | 5454 DEFSYMBOL (Qwindowp); |
5455 DEFSYMBOL (Qwindow_live_p); | |
5456 DEFSYMBOL (Qdisplay_buffer); | |
428 | 5457 |
5458 #ifdef MEMORY_USAGE_STATS | |
563 | 5459 DEFSYMBOL (Qface_cache); |
5460 DEFSYMBOL (Qglyph_cache); | |
5461 DEFSYMBOL (Qline_start_cache); | |
428 | 5462 #ifdef HAVE_SCROLLBARS |
563 | 5463 DEFSYMBOL (Qscrollbar_instances); |
428 | 5464 #endif |
563 | 5465 DEFSYMBOL (Qother_redisplay); |
428 | 5466 /* Qother in general.c */ |
5467 #endif | |
5468 | |
707 | 5469 DEFSYMBOL (Qtruncate_partial_width_windows); |
1149 | 5470 DEFSYMBOL (Qcurrent_window_configuration); |
5471 DEFSYMBOL (Qset_window_configuration); | |
707 | 5472 |
428 | 5473 DEFSUBR (Fselected_window); |
5474 DEFSUBR (Flast_nonminibuf_window); | |
5475 DEFSUBR (Fminibuffer_window); | |
5476 DEFSUBR (Fwindow_minibuffer_p); | |
5477 DEFSUBR (Fwindowp); | |
5478 DEFSUBR (Fwindow_live_p); | |
5479 DEFSUBR (Fwindow_first_hchild); | |
5480 DEFSUBR (Fwindow_first_vchild); | |
5481 DEFSUBR (Fwindow_next_child); | |
5482 DEFSUBR (Fwindow_previous_child); | |
5483 DEFSUBR (Fwindow_parent); | |
5484 DEFSUBR (Fwindow_lowest_p); | |
5485 DEFSUBR (Fwindow_truncated_p); | |
5486 DEFSUBR (Fwindow_highest_p); | |
5487 DEFSUBR (Fwindow_leftmost_p); | |
5488 DEFSUBR (Fwindow_rightmost_p); | |
5489 DEFSUBR (Fpos_visible_in_window_p); | |
5490 DEFSUBR (Fwindow_buffer); | |
5491 DEFSUBR (Fwindow_frame); | |
5492 DEFSUBR (Fwindow_height); | |
5493 DEFSUBR (Fwindow_displayed_height); | |
5494 DEFSUBR (Fwindow_width); | |
442 | 5495 DEFSUBR (Fwindow_full_width); |
428 | 5496 DEFSUBR (Fwindow_pixel_height); |
5497 DEFSUBR (Fwindow_pixel_width); | |
442 | 5498 DEFSUBR (Fwindow_text_area_height); |
428 | 5499 DEFSUBR (Fwindow_text_area_pixel_height); |
5500 DEFSUBR (Fwindow_displayed_text_pixel_height); | |
5501 DEFSUBR (Fwindow_text_area_pixel_width); | |
5502 DEFSUBR (Fwindow_hscroll); | |
438 | 5503 DEFSUBR (Fset_window_hscroll); |
428 | 5504 DEFSUBR (Fmodeline_hscroll); |
5505 DEFSUBR (Fset_modeline_hscroll); | |
5506 DEFSUBR (Fwindow_pixel_edges); | |
5507 DEFSUBR (Fwindow_text_area_pixel_edges); | |
5508 DEFSUBR (Fwindow_point); | |
5509 DEFSUBR (Fwindow_start); | |
5510 DEFSUBR (Fwindow_end); | |
442 | 5511 DEFSUBR (Fwindow_last_line_visible_height); |
428 | 5512 DEFSUBR (Fset_window_point); |
5513 DEFSUBR (Fset_window_start); | |
5514 DEFSUBR (Fwindow_dedicated_p); | |
5515 DEFSUBR (Fset_window_dedicated_p); | |
5516 DEFSUBR (Fnext_window); | |
5517 DEFSUBR (Fprevious_window); | |
5518 DEFSUBR (Fnext_vertical_window); | |
5519 DEFSUBR (Fother_window); | |
5520 DEFSUBR (Fget_lru_window); | |
5521 DEFSUBR (Fget_largest_window); | |
5522 DEFSUBR (Fget_buffer_window); | |
5523 DEFSUBR (Fwindow_left_margin_pixel_width); | |
5524 DEFSUBR (Fwindow_right_margin_pixel_width); | |
5525 DEFSUBR (Fdelete_other_windows); | |
5526 DEFSUBR (Fdelete_windows_on); | |
5527 DEFSUBR (Freplace_buffer_in_windows); | |
5528 DEFSUBR (Fdelete_window); | |
5529 DEFSUBR (Fset_window_buffer); | |
5530 DEFSUBR (Fselect_window); | |
5531 DEFSUBR (Fsplit_window); | |
5532 DEFSUBR (Fenlarge_window); | |
5533 DEFSUBR (Fenlarge_window_pixels); | |
5534 DEFSUBR (Fshrink_window); | |
5535 DEFSUBR (Fshrink_window_pixels); | |
5536 DEFSUBR (Fscroll_up); | |
5537 DEFSUBR (Fscroll_down); | |
5538 DEFSUBR (Fscroll_left); | |
5539 DEFSUBR (Fscroll_right); | |
5540 DEFSUBR (Fother_window_for_scrolling); | |
5541 DEFSUBR (Fscroll_other_window); | |
5542 DEFSUBR (Fcenter_to_window_line); | |
5543 DEFSUBR (Fmove_to_window_line); | |
5544 #ifdef MEMORY_USAGE_STATS | |
5545 DEFSUBR (Fwindow_memory_usage); | |
5546 #endif | |
5547 DEFSUBR (Fcurrent_pixel_column); | |
2289 | 5548 DEFSUBR (Fcurrent_pixel_row); |
428 | 5549 } |
5550 | |
5551 void | |
5552 reinit_vars_of_window (void) | |
5553 { | |
5554 /* Make sure all windows get marked */ | |
5555 minibuf_window = Qnil; | |
5556 staticpro_nodump (&minibuf_window); | |
5557 } | |
5558 | |
5559 void | |
5560 vars_of_window (void) | |
5561 { | |
5562 DEFVAR_BOOL ("scroll-on-clipped-lines", &scroll_on_clipped_lines /* | |
5563 *Non-nil means to scroll if point lands on a line which is clipped. | |
5564 */ ); | |
5565 scroll_on_clipped_lines = 1; | |
5566 | |
5567 DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function /* | |
5568 Non-nil means call as function to display a help buffer. | |
5569 The function is called with one argument, the buffer to be displayed. | |
5570 Used by `with-output-to-temp-buffer'. | |
5571 If this function is used, then it must do the entire job of showing | |
5572 the buffer; `temp-buffer-show-hook' is not run unless this function runs it. | |
442 | 5573 \(`temp-buffer-show-hook' is obsolete. Do not use in new code.) |
428 | 5574 */ ); |
5575 Vtemp_buffer_show_function = Qnil; | |
5576 | |
5577 DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuffer_scroll_window /* | |
5578 Non-nil means it is the window that \\<minibuffer-local-map>\\[scroll-other-window] in minibuffer should scroll. | |
5579 */ ); | |
5580 Vminibuffer_scroll_window = Qnil; | |
5581 | |
5582 DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer /* | |
5583 If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window. | |
5584 */ ); | |
5585 Vother_window_scroll_buffer = Qnil; | |
5586 | |
5587 DEFVAR_LISP ("window-pixel-scroll-increment", &Vwindow_pixel_scroll_increment /* | |
5588 *Number of pixels to scroll by per requested line. | |
5589 If nil then normal line scrolling occurs regardless of line height. | |
5590 If t then scrolling is done in increments equal to the height of the default face. | |
5591 */ ); | |
5592 Vwindow_pixel_scroll_increment = Qt; | |
5593 | |
5594 DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines /* | |
5595 *Number of lines of continuity when scrolling by screenfuls. | |
5596 */ ); | |
5597 next_screen_context_lines = 2; | |
5598 | |
5599 DEFVAR_INT ("window-min-height", &window_min_height /* | |
5600 *Delete any window less than this tall (including its modeline). | |
5601 */ ); | |
5602 window_min_height = 4; | |
5603 | |
5604 DEFVAR_INT ("window-min-width", &window_min_width /* | |
5605 *Delete any window less than this wide. | |
5606 */ ); | |
5607 window_min_width = 10; | |
5608 } | |
5609 | |
5610 void | |
5611 specifier_vars_of_window (void) | |
5612 { | |
5613 DEFVAR_SPECIFIER ("modeline-shadow-thickness", &Vmodeline_shadow_thickness /* | |
5614 *How thick to draw 3D shadows around modelines. | |
5615 If this is set to 0, modelines will be the traditional 2D. Sizes above | |
5616 10 will be accepted but the maximum thickness that will be drawn is 10. | |
5617 This is a specifier; use `set-specifier' to change it. | |
5618 */ ); | |
5619 Vmodeline_shadow_thickness = Fmake_specifier (Qinteger); | |
5620 /* The initial value for modeline-shadow-thickness is 2, but if the | |
5621 user removes all specifications we provide a fallback value of 0, | |
5622 which is probably what was expected. */ | |
5623 set_specifier_fallback (Vmodeline_shadow_thickness, | |
5624 list1 (Fcons (Qnil, Qzero))); | |
5625 Fadd_spec_to_specifier (Vmodeline_shadow_thickness, make_int (2), | |
5626 Qnil, Qnil, Qnil); | |
5627 set_specifier_caching (Vmodeline_shadow_thickness, | |
438 | 5628 offsetof (struct window, modeline_shadow_thickness), |
428 | 5629 modeline_shadow_thickness_changed, |
444 | 5630 0, 0, 0); |
428 | 5631 |
5632 DEFVAR_SPECIFIER ("has-modeline-p", &Vhas_modeline_p /* | |
5633 *Whether the modeline should be displayed. | |
5634 This is a specifier; use `set-specifier' to change it. | |
5635 */ ); | |
5636 Vhas_modeline_p = Fmake_specifier (Qboolean); | |
5637 set_specifier_fallback (Vhas_modeline_p, | |
5638 list1 (Fcons (Qnil, Qt))); | |
5639 set_specifier_caching (Vhas_modeline_p, | |
438 | 5640 offsetof (struct window, has_modeline_p), |
428 | 5641 /* #### It's strange that we need a special |
5642 flag to indicate that the shadow-thickness | |
5643 has changed, but not one to indicate that | |
5644 the modeline has been turned off or on. */ | |
5645 some_window_value_changed, | |
444 | 5646 0, 0, 0); |
428 | 5647 |
5648 DEFVAR_SPECIFIER ("vertical-divider-always-visible-p", | |
5649 &Vvertical_divider_always_visible_p /* | |
5650 *Should XEmacs always display vertical dividers between windows. | |
5651 | |
5652 When this is non-nil, vertical dividers are always shown, and are | |
5653 draggable. When it is nil, vertical dividers are shown only when | |
5654 there are no scrollbars in between windows, and are not draggable. | |
5655 | |
5656 This is a specifier; use `set-specifier' to change it. | |
5657 */ ); | |
5658 Vvertical_divider_always_visible_p = Fmake_specifier (Qboolean); | |
5659 set_specifier_fallback (Vvertical_divider_always_visible_p, | |
5660 list1 (Fcons (Qnil, Qt))); | |
5661 set_specifier_caching (Vvertical_divider_always_visible_p, | |
438 | 5662 offsetof (struct window, |
5663 vertical_divider_always_visible_p), | |
428 | 5664 vertical_divider_changed_in_window, |
444 | 5665 0, 0, 0); |
428 | 5666 |
5667 DEFVAR_SPECIFIER ("vertical-divider-shadow-thickness", &Vvertical_divider_shadow_thickness /* | |
5668 *How thick to draw 3D shadows around vertical dividers. | |
5669 This is a specifier; use `set-specifier' to change it. | |
5670 */ ); | |
5671 Vvertical_divider_shadow_thickness = Fmake_specifier (Qinteger); | |
5672 set_specifier_fallback (Vvertical_divider_shadow_thickness, | |
5673 list1 (Fcons (Qnil, Qzero))); | |
5674 Fadd_spec_to_specifier (Vvertical_divider_shadow_thickness, make_int (2), | |
5675 Qnil, Qnil, Qnil); | |
5676 set_specifier_caching (Vvertical_divider_shadow_thickness, | |
438 | 5677 offsetof (struct window, |
5678 vertical_divider_shadow_thickness), | |
428 | 5679 vertical_divider_changed_in_window, |
444 | 5680 0, 0, 0); |
428 | 5681 DEFVAR_SPECIFIER ("vertical-divider-line-width", &Vvertical_divider_line_width /* |
5682 *The width of the vertical dividers, not including shadows. | |
5683 | |
5684 For TTY windows, divider line is always one character wide. When | |
5685 instance of this specifier is zero in a TTY window, no divider is | |
5686 drawn at all between windows. When non-zero, a one character wide | |
5687 divider is displayed. | |
5688 | |
5689 This is a specifier; use `set-specifier' to change it. | |
5690 */ ); | |
5691 | |
5692 Vvertical_divider_line_width = Fmake_specifier (Qnatnum); | |
5693 { | |
5694 Lisp_Object fb = Qnil; | |
5695 #ifdef HAVE_TTY | |
5696 fb = Fcons (Fcons (list1 (Qtty), make_int (1)), fb); | |
5697 #endif | |
462 | 5698 #ifdef HAVE_GTK |
5699 fb = Fcons (Fcons (list1 (Qgtk), make_int (3)), fb); | |
5700 #endif | |
428 | 5701 #ifdef HAVE_X_WINDOWS |
5702 fb = Fcons (Fcons (list1 (Qx), make_int (3)), fb); | |
5703 #endif | |
5704 #ifdef HAVE_MS_WINDOWS | |
5705 /* #### This should be made magic and made to obey system settings */ | |
5706 fb = Fcons (Fcons (list1 (Qmswindows), make_int (3)), fb); | |
5707 #endif | |
5708 set_specifier_fallback (Vvertical_divider_line_width, fb); | |
5709 } | |
5710 set_specifier_caching (Vvertical_divider_line_width, | |
438 | 5711 offsetof (struct window, |
5712 vertical_divider_line_width), | |
428 | 5713 vertical_divider_changed_in_window, |
444 | 5714 0, 0, 0); |
428 | 5715 |
5716 DEFVAR_SPECIFIER ("vertical-divider-spacing", &Vvertical_divider_spacing /* | |
5717 *How much space to leave around the vertical dividers. | |
5718 | |
5719 In TTY windows, spacing is always zero, and the value of this | |
5720 specifier is ignored. | |
5721 | |
5722 This is a specifier; use `set-specifier' to change it. | |
5723 */ ); | |
5724 Vvertical_divider_spacing = Fmake_specifier (Qnatnum); | |
5725 { | |
5726 Lisp_Object fb = Qnil; | |
5727 #ifdef HAVE_TTY | |
5728 fb = Fcons (Fcons (list1 (Qtty), Qzero), fb); | |
5729 #endif | |
5730 #ifdef HAVE_X_WINDOWS | |
5731 /* #### 3D dividers look great on MS Windows with spacing = 0. | |
5732 Should not the same value be the fallback under X? - kkm */ | |
5733 fb = Fcons (Fcons (list1 (Qx), make_int (2)), fb); | |
5734 #endif | |
462 | 5735 #ifdef HAVE_GTK |
5736 fb = Fcons (Fcons (list1 (Qgtk), Qzero), fb); | |
5737 #endif | |
428 | 5738 #ifdef HAVE_MS_WINDOWS |
5739 fb = Fcons (Fcons (list1 (Qmswindows), Qzero), fb); | |
5740 #endif | |
5741 set_specifier_fallback (Vvertical_divider_spacing, fb); | |
5742 } | |
5743 set_specifier_caching (Vvertical_divider_spacing, | |
438 | 5744 offsetof (struct window, vertical_divider_spacing), |
428 | 5745 vertical_divider_changed_in_window, |
444 | 5746 0, 0, 0); |
5747 } |