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