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