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