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