diff options
| author | Jim Blandy | 1991-05-13 16:00:04 +0000 |
|---|---|---|
| committer | Jim Blandy | 1991-05-13 16:00:04 +0000 |
| commit | 7ab12479e9f6d42d45a67bb2be9e4ab8ab438323 (patch) | |
| tree | 68735bc924deb00acf3e6b56086ed1fbf826638d /src/window.c | |
| parent | 77176e738857197923e3083803d0eff7a8b0dfd6 (diff) | |
| download | emacs-7ab12479e9f6d42d45a67bb2be9e4ab8ab438323.tar.gz emacs-7ab12479e9f6d42d45a67bb2be9e4ab8ab438323.zip | |
Initial revision
Diffstat (limited to 'src/window.c')
| -rw-r--r-- | src/window.c | 2720 |
1 files changed, 2720 insertions, 0 deletions
diff --git a/src/window.c b/src/window.c new file mode 100644 index 00000000000..aa1d9b1bcdc --- /dev/null +++ b/src/window.c | |||
| @@ -0,0 +1,2720 @@ | |||
| 1 | /* Window creation, deletion and examination for GNU Emacs. | ||
| 2 | Does not include redisplay. | ||
| 3 | Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software; you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation; either version 1, or (at your option) | ||
| 10 | any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs; see the file COPYING. If not, write to | ||
| 19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
| 20 | |||
| 21 | |||
| 22 | #include "config.h" | ||
| 23 | #include "lisp.h" | ||
| 24 | #include "buffer.h" | ||
| 25 | #include "screen.h" | ||
| 26 | #include "window.h" | ||
| 27 | #include "commands.h" | ||
| 28 | #include "indent.h" | ||
| 29 | #include "termchar.h" | ||
| 30 | #include "disptab.h" | ||
| 31 | |||
| 32 | Lisp_Object Qwindowp; | ||
| 33 | |||
| 34 | Lisp_Object Fnext_window (), Fdelete_window (), Fselect_window (); | ||
| 35 | Lisp_Object Fset_window_buffer (), Fsplit_window (), Frecenter (); | ||
| 36 | |||
| 37 | static void delete_all_subwindows (); | ||
| 38 | static struct window *decode_window(); | ||
| 39 | |||
| 40 | /* This is the window in which the terminal's cursor should | ||
| 41 | be left when nothing is being done with it. This must | ||
| 42 | always be a leaf window, and its buffer is selected by | ||
| 43 | the top level editing loop at the end of each command. | ||
| 44 | |||
| 45 | This value is always the same as | ||
| 46 | SCREEN_SELECTED_WINDOW (selected_screen). */ | ||
| 47 | |||
| 48 | Lisp_Object selected_window; | ||
| 49 | |||
| 50 | #ifndef MULTI_SCREEN | ||
| 51 | |||
| 52 | /* The root window for the screen. | ||
| 53 | This is accessed via SCREEN_ROOT_WINDOW (selected_screen). */ | ||
| 54 | Lisp_Object root_window; | ||
| 55 | |||
| 56 | #endif | ||
| 57 | |||
| 58 | /* The minibuffer window of the selected screen. | ||
| 59 | Note that you cannot test for minibufferness of an arbitrary window | ||
| 60 | by comparing against this; but you can test for minibufferness of | ||
| 61 | the selected window. */ | ||
| 62 | Lisp_Object minibuf_window; | ||
| 63 | |||
| 64 | /* Non-nil means it is the window for C-M-v to scroll | ||
| 65 | when the minibuffer is selected. */ | ||
| 66 | Lisp_Object Vminibuf_scroll_window; | ||
| 67 | |||
| 68 | /* Non-nil means this is the buffer whose window C-M-v should scroll. */ | ||
| 69 | Lisp_Object Vother_window_scroll_buffer; | ||
| 70 | |||
| 71 | /* Window that the mouse is over (nil if no mouse support). */ | ||
| 72 | Lisp_Object Vmouse_window; | ||
| 73 | |||
| 74 | /* Last mouse click data structure (nil if no mouse support). */ | ||
| 75 | Lisp_Object Vmouse_event; | ||
| 76 | |||
| 77 | /* Non-nil means it's function to call to display temp buffers. */ | ||
| 78 | Lisp_Object Vtemp_buffer_show_function; | ||
| 79 | |||
| 80 | /* If a window gets smaller than either of these, it is removed. */ | ||
| 81 | int window_min_height; | ||
| 82 | int window_min_width; | ||
| 83 | |||
| 84 | /* Nonzero implies Fdisplay_buffer should create windows. */ | ||
| 85 | int pop_up_windows; | ||
| 86 | |||
| 87 | /* Nonzero implies make new X screens for Fdisplay_buffer. */ | ||
| 88 | int auto_new_screen; | ||
| 89 | |||
| 90 | /* Non-nil means use this function instead of default */ | ||
| 91 | Lisp_Object Vauto_new_screen_function; | ||
| 92 | |||
| 93 | /* Function to call to handle Fdisplay_buffer. */ | ||
| 94 | Lisp_Object Vdisplay_buffer_function; | ||
| 95 | |||
| 96 | /* Fdisplay_buffer always splits the largest window | ||
| 97 | if that window is more than this high. */ | ||
| 98 | int split_height_threshold; | ||
| 99 | |||
| 100 | /* Number of lines of continuity in scrolling by screenfuls. */ | ||
| 101 | int next_screen_context_lines; | ||
| 102 | |||
| 103 | /* Incremented for each window created. */ | ||
| 104 | static int sequence_number; | ||
| 105 | |||
| 106 | #define min(a, b) ((a) < (b) ? (a) : (b)) | ||
| 107 | |||
| 108 | DEFUN ("windowp", Fwindowp, Swindowp, 1, 1, 0, | ||
| 109 | "Returns t if OBJ is a window.") | ||
| 110 | (obj) | ||
| 111 | Lisp_Object obj; | ||
| 112 | { | ||
| 113 | return XTYPE (obj) == Lisp_Window ? Qt : Qnil; | ||
| 114 | } | ||
| 115 | |||
| 116 | Lisp_Object | ||
| 117 | make_window () | ||
| 118 | { | ||
| 119 | register Lisp_Object val; | ||
| 120 | register struct window *p; | ||
| 121 | |||
| 122 | /* Add sizeof (Lisp_Object) here because sizeof (struct Lisp_Vector) | ||
| 123 | includes the first element. */ | ||
| 124 | val = Fmake_vector ( | ||
| 125 | make_number ((sizeof (struct window) - sizeof (struct Lisp_Vector) | ||
| 126 | + sizeof (Lisp_Object)) | ||
| 127 | / sizeof (Lisp_Object)), | ||
| 128 | Qnil); | ||
| 129 | XSETTYPE (val, Lisp_Window); | ||
| 130 | p = XWINDOW (val); | ||
| 131 | XFASTINT (p->sequence_number) = ++sequence_number; | ||
| 132 | XFASTINT (p->left) = XFASTINT (p->top) | ||
| 133 | = XFASTINT (p->height) = XFASTINT (p->width) | ||
| 134 | = XFASTINT (p->hscroll) = 0; | ||
| 135 | XFASTINT (p->last_point_x) = XFASTINT (p->last_point_y) = 0; | ||
| 136 | p->start = Fmake_marker (); | ||
| 137 | p->pointm = Fmake_marker (); | ||
| 138 | XFASTINT (p->use_time) = 0; | ||
| 139 | p->screen = Qnil; | ||
| 140 | p->display_table = Qnil; | ||
| 141 | p->dedicated = Qnil; | ||
| 142 | return val; | ||
| 143 | } | ||
| 144 | |||
| 145 | DEFUN ("selected-window", Fselected_window, Sselected_window, 0, 0, 0, | ||
| 146 | "Return the window that the cursor now appears in and commands apply to.") | ||
| 147 | () | ||
| 148 | { | ||
| 149 | return selected_window; | ||
| 150 | } | ||
| 151 | |||
| 152 | DEFUN ("minibuffer-window", Fminibuffer_window, Sminibuffer_window, 0, 0, 0, | ||
| 153 | "Return the window used now for minibuffers.") | ||
| 154 | () | ||
| 155 | { | ||
| 156 | #ifdef MULTI_SCREEN | ||
| 157 | if (minibuf_level == 0 | ||
| 158 | && !EQ (minibuf_window, selected_screen->minibuffer_window) | ||
| 159 | && !EQ (Qnil, selected_screen->minibuffer_window)) | ||
| 160 | { | ||
| 161 | Fset_window_buffer (selected_screen->minibuffer_window, | ||
| 162 | XWINDOW (minibuf_window)->buffer); | ||
| 163 | minibuf_window = selected_screen->minibuffer_window; | ||
| 164 | } | ||
| 165 | |||
| 166 | if (SCREENP (Vglobal_minibuffer_screen)) | ||
| 167 | minibuf_window = XSCREEN (Vglobal_minibuffer_screen)->minibuffer_window; | ||
| 168 | else | ||
| 169 | minibuf_window = selected_screen->minibuffer_window; | ||
| 170 | |||
| 171 | #endif /* MULTI_SCREEN */ | ||
| 172 | return minibuf_window; | ||
| 173 | } | ||
| 174 | |||
| 175 | DEFUN ("window-minibuffer-p", Fwindow_minibuffer_p, Swindow_minibuffer_p, 1, 1, 0, | ||
| 176 | "Returns non-nil if WINDOW is a minibuffer window.") | ||
| 177 | (window) | ||
| 178 | Lisp_Object window; | ||
| 179 | { | ||
| 180 | struct window *w = decode_window (window); | ||
| 181 | return (MINI_WINDOW_P (w) ? Qt : Qnil); | ||
| 182 | } | ||
| 183 | |||
| 184 | DEFUN ("pos-visible-in-window-p", Fpos_visible_in_window_p, | ||
| 185 | Spos_visible_in_window_p, 0, 2, 0, | ||
| 186 | "Return t if position POS is currently on the screen in WINDOW.\n\ | ||
| 187 | Returns nil if that position is scrolled vertically out of view.\n\ | ||
| 188 | POS defaults to point; WINDOW, to the selected window.") | ||
| 189 | (pos, window) | ||
| 190 | Lisp_Object pos, window; | ||
| 191 | { | ||
| 192 | register struct window *w; | ||
| 193 | register int top; | ||
| 194 | register int height; | ||
| 195 | register int posint; | ||
| 196 | register struct buffer *buf; | ||
| 197 | struct position posval; | ||
| 198 | |||
| 199 | if (NULL (pos)) | ||
| 200 | posint = point; | ||
| 201 | else | ||
| 202 | { | ||
| 203 | CHECK_NUMBER_COERCE_MARKER (pos, 0); | ||
| 204 | posint = XINT (pos); | ||
| 205 | } | ||
| 206 | |||
| 207 | if (NULL (window)) | ||
| 208 | window = selected_window; | ||
| 209 | else | ||
| 210 | CHECK_WINDOW (window, 1); | ||
| 211 | w = XWINDOW (window); | ||
| 212 | top = marker_position (w->start); | ||
| 213 | |||
| 214 | if (posint < top) | ||
| 215 | return Qnil; | ||
| 216 | |||
| 217 | height = XFASTINT (w->height) - ! MINI_WINDOW_P (w); | ||
| 218 | |||
| 219 | buf = XBUFFER (w->buffer); | ||
| 220 | if (XFASTINT (w->last_modified) >= BUF_MODIFF (buf)) | ||
| 221 | { | ||
| 222 | /* If screen is up to date, | ||
| 223 | use the info recorded about how much text fit on it. */ | ||
| 224 | if (posint < BUF_Z (buf) - XFASTINT (w->window_end_pos) | ||
| 225 | || (XFASTINT (w->window_end_vpos) < height)) | ||
| 226 | return Qt; | ||
| 227 | return Qnil; | ||
| 228 | } | ||
| 229 | else | ||
| 230 | { | ||
| 231 | if (posint > BUF_Z (buf)) | ||
| 232 | return Qnil; | ||
| 233 | |||
| 234 | /* If that info is not correct, calculate afresh */ | ||
| 235 | posval = *compute_motion (top, 0, 0, posint, height, 0, | ||
| 236 | XFASTINT (w->width) - 1 | ||
| 237 | - (XFASTINT (w->width) + XFASTINT (w->left) | ||
| 238 | != XSCREEN (w->screen)->width), | ||
| 239 | XINT (w->hscroll), 0); | ||
| 240 | |||
| 241 | return posval.vpos < height ? Qt : Qnil; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | static struct window * | ||
| 246 | decode_window (window) | ||
| 247 | register Lisp_Object window; | ||
| 248 | { | ||
| 249 | if (NULL (window)) | ||
| 250 | return XWINDOW (selected_window); | ||
| 251 | |||
| 252 | CHECK_WINDOW (window, 0); | ||
| 253 | return XWINDOW (window); | ||
| 254 | } | ||
| 255 | |||
| 256 | DEFUN ("window-buffer", Fwindow_buffer, Swindow_buffer, 0, 1, 0, | ||
| 257 | "Return the buffer that WINDOW is displaying.") | ||
| 258 | (window) | ||
| 259 | Lisp_Object window; | ||
| 260 | { | ||
| 261 | return decode_window (window)->buffer; | ||
| 262 | } | ||
| 263 | |||
| 264 | DEFUN ("window-height", Fwindow_height, Swindow_height, 0, 1, 0, | ||
| 265 | "Return the number of lines in WINDOW (including its mode line).") | ||
| 266 | (window) | ||
| 267 | Lisp_Object window; | ||
| 268 | { | ||
| 269 | return decode_window (window)->height; | ||
| 270 | } | ||
| 271 | |||
| 272 | DEFUN ("window-width", Fwindow_width, Swindow_width, 0, 1, 0, | ||
| 273 | "Return the number of columns in WINDOW.") | ||
| 274 | (window) | ||
| 275 | Lisp_Object window; | ||
| 276 | { | ||
| 277 | register struct window *w = decode_window (window); | ||
| 278 | register int width = w->width; | ||
| 279 | |||
| 280 | /* If this window does not end at the right margin, | ||
| 281 | must deduct one column for the border */ | ||
| 282 | if ((width + w->left) == SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (w)))) | ||
| 283 | return width; | ||
| 284 | return width - 1; | ||
| 285 | } | ||
| 286 | |||
| 287 | DEFUN ("window-hscroll", Fwindow_hscroll, Swindow_hscroll, 0, 1, 0, | ||
| 288 | "Return the number of columns by which WINDOW is scrolled from left margin.") | ||
| 289 | (window) | ||
| 290 | Lisp_Object window; | ||
| 291 | { | ||
| 292 | return decode_window (window)->hscroll; | ||
| 293 | } | ||
| 294 | |||
| 295 | DEFUN ("set-window-hscroll", Fset_window_hscroll, Sset_window_hscroll, 2, 2, 0, | ||
| 296 | "Set number of columns WINDOW is scrolled from left margin to NCOL.\n\ | ||
| 297 | NCOL should be zero or positive.") | ||
| 298 | (window, ncol) | ||
| 299 | register Lisp_Object window, ncol; | ||
| 300 | { | ||
| 301 | register struct window *w; | ||
| 302 | |||
| 303 | CHECK_NUMBER (ncol, 1); | ||
| 304 | if (XINT (ncol) < 0) XFASTINT (ncol) = 0; | ||
| 305 | if (XFASTINT (ncol) >= (1 << (SHORTBITS - 1))) | ||
| 306 | args_out_of_range (ncol, Qnil); | ||
| 307 | w = decode_window (window); | ||
| 308 | if (w->hscroll != ncol) | ||
| 309 | clip_changed = 1; /* Prevent redisplay shortcuts */ | ||
| 310 | w->hscroll = ncol; | ||
| 311 | return ncol; | ||
| 312 | } | ||
| 313 | |||
| 314 | DEFUN ("window-edges", Fwindow_edges, Swindow_edges, 0, 1, 0, | ||
| 315 | "Return a list of the edge coordinates of WINDOW.\n\ | ||
| 316 | \(LEFT TOP RIGHT BOTTOM), all relative to 0, 0 at top left corner of screen.\n\ | ||
| 317 | RIGHT is one more than the rightmost column used by WINDOW,\n\ | ||
| 318 | and BOTTOM is one more than the bottommost row used by WINDOW\n\ | ||
| 319 | and its mode-line.") | ||
| 320 | (window) | ||
| 321 | Lisp_Object window; | ||
| 322 | { | ||
| 323 | register struct window *w = decode_window (window); | ||
| 324 | |||
| 325 | return Fcons (w->left, Fcons (w->top, | ||
| 326 | Fcons (make_number (XFASTINT (w->left) + XFASTINT (w->width)), | ||
| 327 | Fcons (make_number (XFASTINT (w->top) | ||
| 328 | + XFASTINT (w->height)), | ||
| 329 | Qnil)))); | ||
| 330 | } | ||
| 331 | |||
| 332 | /* Find the window containing column x, row y, and return it as a | ||
| 333 | Lisp_Object. If x, y is on the window's modeline, set *modeline_p | ||
| 334 | to 1; otherwise set it to 0. If there is no window under x, y | ||
| 335 | return nil and leave *modeline_p unmodified. */ | ||
| 336 | Lisp_Object | ||
| 337 | window_from_coordinates (screen, x, y, modeline_p) | ||
| 338 | SCREEN_PTR screen; | ||
| 339 | int x, y; | ||
| 340 | int *modeline_p; | ||
| 341 | { | ||
| 342 | register Lisp_Object tem, first; | ||
| 343 | |||
| 344 | first = SCREEN_SELECTED_WINDOW (screen); | ||
| 345 | tem = next_screen_window (screen, first, Qt); | ||
| 346 | |||
| 347 | while (1) | ||
| 348 | { | ||
| 349 | int found = coordinates_in_window (XWINDOW (tem), &x, &y); | ||
| 350 | |||
| 351 | if (found) | ||
| 352 | { | ||
| 353 | |||
| 354 | *modeline_p = (found == -1); | ||
| 355 | return tem; | ||
| 356 | } | ||
| 357 | |||
| 358 | if (EQ (tem, first)) | ||
| 359 | return Qnil; | ||
| 360 | |||
| 361 | tem = next_screen_window (screen, tem, Qt); | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | DEFUN ("locate-window-from-coordinates", | ||
| 366 | Flocate_window_from_coordinates, Slocate_window_from_coordinates, | ||
| 367 | 2, 2, 0, | ||
| 368 | "Return window on SCREEN containing position COORDINATES.\n\ | ||
| 369 | COORDINATES is a list (SCREEN-X SCREEN-Y) of coordinates\n\ | ||
| 370 | which are relative to 0,0 at the top left corner of the screen.") | ||
| 371 | (screen, coordinates) | ||
| 372 | Lisp_Object screen, coordinates; | ||
| 373 | { | ||
| 374 | int part; | ||
| 375 | |||
| 376 | CHECK_SCREEN (screen, 0); | ||
| 377 | CHECK_CONS (coordinates, 1); | ||
| 378 | |||
| 379 | return window_from_coordinates (XSCREEN (screen), | ||
| 380 | XINT (Fcar (coordinates)), | ||
| 381 | XINT (Fcar (Fcdr (coordinates))), | ||
| 382 | &part); | ||
| 383 | } | ||
| 384 | |||
| 385 | DEFUN ("window-point", Fwindow_point, Swindow_point, 0, 1, 0, | ||
| 386 | "Return current value of point in WINDOW.\n\ | ||
| 387 | For a nonselected window, this is the value point would have\n\ | ||
| 388 | if that window were selected.\n\ | ||
| 389 | \n\ | ||
| 390 | Note that, when WINDOW is the selected window and its buffer\n\ | ||
| 391 | is also currently selected, the value returned is the same as (point).\n\ | ||
| 392 | It would be more strictly correct to return the `top-level' value\n\ | ||
| 393 | of point, outside of any save-excursion forms.\n\ | ||
| 394 | But that is hard to define.") | ||
| 395 | (window) | ||
| 396 | Lisp_Object window; | ||
| 397 | { | ||
| 398 | register struct window *w = decode_window (window); | ||
| 399 | |||
| 400 | if (w == XWINDOW (selected_window) | ||
| 401 | && current_buffer == XBUFFER (w->buffer)) | ||
| 402 | return Fpoint (); | ||
| 403 | return Fmarker_position (w->pointm); | ||
| 404 | } | ||
| 405 | |||
| 406 | DEFUN ("window-start", Fwindow_start, Swindow_start, 0, 1, 0, | ||
| 407 | "Return position at which display currently starts in WINDOW.") | ||
| 408 | (window) | ||
| 409 | Lisp_Object window; | ||
| 410 | { | ||
| 411 | return Fmarker_position (decode_window (window)->start); | ||
| 412 | } | ||
| 413 | |||
| 414 | DEFUN ("window-end", Fwindow_end, Swindow_end, 0, 1, 0, | ||
| 415 | "Return position at which display currently ends in WINDOW.") | ||
| 416 | (window) | ||
| 417 | Lisp_Object window; | ||
| 418 | { | ||
| 419 | Lisp_Object value; | ||
| 420 | struct window *w = decode_window (window); | ||
| 421 | |||
| 422 | XSET (value, Lisp_Int, | ||
| 423 | BUF_Z (current_buffer) - XFASTINT (w->window_end_pos)); | ||
| 424 | |||
| 425 | return value; | ||
| 426 | } | ||
| 427 | |||
| 428 | DEFUN ("set-window-point", Fset_window_point, Sset_window_point, 2, 2, 0, | ||
| 429 | "Make point value in WINDOW be at position POS in WINDOW's buffer.") | ||
| 430 | (window, pos) | ||
| 431 | Lisp_Object window, pos; | ||
| 432 | { | ||
| 433 | register struct window *w = decode_window (window); | ||
| 434 | |||
| 435 | CHECK_NUMBER_COERCE_MARKER (pos, 1); | ||
| 436 | if (w == XWINDOW (selected_window)) | ||
| 437 | Fgoto_char (pos); | ||
| 438 | else | ||
| 439 | set_marker_restricted (w->pointm, pos, w->buffer); | ||
| 440 | |||
| 441 | return pos; | ||
| 442 | } | ||
| 443 | |||
| 444 | DEFUN ("set-window-start", Fset_window_start, Sset_window_start, 2, 3, 0, | ||
| 445 | "Make display in WINDOW start at position POS in WINDOW's buffer.\n\ | ||
| 446 | Optional third arg NOFORCE non-nil inhibits next redisplay\n\ | ||
| 447 | from overriding motion of point in order to display at this exact start.") | ||
| 448 | (window, pos, noforce) | ||
| 449 | Lisp_Object window, pos, noforce; | ||
| 450 | { | ||
| 451 | register struct window *w = decode_window (window); | ||
| 452 | |||
| 453 | CHECK_NUMBER_COERCE_MARKER (pos, 1); | ||
| 454 | set_marker_restricted (w->start, pos, w->buffer); | ||
| 455 | /* this is not right, but much easier than doing what is right. */ | ||
| 456 | w->start_at_line_beg = Qnil; | ||
| 457 | if (NULL (noforce)) | ||
| 458 | w->force_start = Qt; | ||
| 459 | w->update_mode_line = Qt; | ||
| 460 | XFASTINT (w->last_modified) = 0; | ||
| 461 | return pos; | ||
| 462 | } | ||
| 463 | |||
| 464 | DEFUN ("window-dedicated-p", Fwindow_dedicated_p, Swindow_dedicated_p, | ||
| 465 | 1, 1, 0, | ||
| 466 | "Return WINDOW's dedicated object, usually t or nil.\n\ | ||
| 467 | See also `set-window-buffer-dedicated'.") | ||
| 468 | (window) | ||
| 469 | Lisp_Object window; | ||
| 470 | { | ||
| 471 | return decode_window (window)->dedicated; | ||
| 472 | } | ||
| 473 | |||
| 474 | DEFUN ("set-window-buffer-dedicated", Fset_window_buffer_dedicated, | ||
| 475 | Sset_window_buffer_dedicated, 2, 2, 0, | ||
| 476 | "Make WINDOW display BUFFER and be dedicated to that buffer.\n\ | ||
| 477 | Then Emacs will not automatically change which buffer appears in WINDOW.\n\ | ||
| 478 | If BUFFER is nil, make WINDOW not be dedicated (but don't change which\n\ | ||
| 479 | buffer appears in it currently).") | ||
| 480 | (window, arg) | ||
| 481 | Lisp_Object window, arg; | ||
| 482 | { | ||
| 483 | register struct window *w = decode_window (window); | ||
| 484 | |||
| 485 | if (NULL (arg)) | ||
| 486 | w->dedicated = Qnil; | ||
| 487 | else | ||
| 488 | { | ||
| 489 | Fset_window_buffer (window, Fget_buffer_create (arg)); | ||
| 490 | w->dedicated = Qt; | ||
| 491 | } | ||
| 492 | |||
| 493 | return w->dedicated; | ||
| 494 | } | ||
| 495 | |||
| 496 | DEFUN ("window-display-table", Fwindow_display_table, Swindow_display_table, | ||
| 497 | 0, 1, 0, | ||
| 498 | "Return the display-table that WINDOW is using.") | ||
| 499 | (window) | ||
| 500 | Lisp_Object window; | ||
| 501 | { | ||
| 502 | return decode_window (window)->display_table; | ||
| 503 | } | ||
| 504 | |||
| 505 | /* Get the display table for use currently on window W. | ||
| 506 | This is either W's display table or W's buffer's display table. | ||
| 507 | Ignore the specified tables if they are not valid; | ||
| 508 | if no valid table is specified, return 0. */ | ||
| 509 | |||
| 510 | struct Lisp_Vector * | ||
| 511 | window_display_table (w) | ||
| 512 | struct window *w; | ||
| 513 | { | ||
| 514 | Lisp_Object tem; | ||
| 515 | tem = w->display_table; | ||
| 516 | if (XTYPE (tem) == Lisp_Vector && XVECTOR (tem)->size == DISP_TABLE_SIZE) | ||
| 517 | return XVECTOR (tem); | ||
| 518 | tem = XBUFFER (w->buffer)->display_table; | ||
| 519 | if (XTYPE (tem) == Lisp_Vector && XVECTOR (tem)->size == DISP_TABLE_SIZE) | ||
| 520 | return XVECTOR (tem); | ||
| 521 | tem = Vstandard_display_table; | ||
| 522 | if (XTYPE (tem) == Lisp_Vector && XVECTOR (tem)->size == DISP_TABLE_SIZE) | ||
| 523 | return XVECTOR (tem); | ||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 527 | DEFUN ("set-window-display-table", | ||
| 528 | Fset_window_display_table, Sset_window_display_table, 2, 2, 0, | ||
| 529 | "Set WINDOW's display-table to TABLE.") | ||
| 530 | (window, table) | ||
| 531 | register Lisp_Object window, table; | ||
| 532 | { | ||
| 533 | register struct window *w; | ||
| 534 | register Lisp_Object z; /* Return value. */ | ||
| 535 | |||
| 536 | w = decode_window (window); | ||
| 537 | w->display_table = table; | ||
| 538 | return table; | ||
| 539 | } | ||
| 540 | |||
| 541 | /* Record info on buffer window w is displaying | ||
| 542 | when it is about to cease to display that buffer. */ | ||
| 543 | static | ||
| 544 | unshow_buffer (w) | ||
| 545 | register struct window *w; | ||
| 546 | { | ||
| 547 | Lisp_Object buf = w->buffer; | ||
| 548 | |||
| 549 | if (XBUFFER (buf) != XMARKER (w->pointm)->buffer) | ||
| 550 | abort (); | ||
| 551 | |||
| 552 | if (w == XWINDOW (selected_window) | ||
| 553 | || ! EQ (buf, XWINDOW (selected_window)->buffer)) | ||
| 554 | /* Do this except when the selected window's buffer | ||
| 555 | is being removed from some other window. */ | ||
| 556 | XBUFFER (buf)->last_window_start = marker_position (w->start); | ||
| 557 | |||
| 558 | /* Point in the selected window's buffer | ||
| 559 | is actually stored in that buffer, and the window's pointm isn't used. | ||
| 560 | So don't clobber point in that buffer. */ | ||
| 561 | if (! EQ (buf, XWINDOW (selected_window)->buffer)) | ||
| 562 | BUF_PT (XBUFFER (buf)) | ||
| 563 | = clip_to_bounds (BUF_BEGV (XBUFFER (buf)), | ||
| 564 | marker_position (w->pointm), | ||
| 565 | BUF_ZV (XBUFFER (buf))); | ||
| 566 | } | ||
| 567 | |||
| 568 | /* Put replacement into the window structure in place of old. */ | ||
| 569 | static | ||
| 570 | replace_window (old, replacement) | ||
| 571 | Lisp_Object old, replacement; | ||
| 572 | { | ||
| 573 | register Lisp_Object tem; | ||
| 574 | register struct window *o = XWINDOW (old), *p = XWINDOW (replacement); | ||
| 575 | |||
| 576 | /* If OLD is its screen's root_window, then replacement is the new | ||
| 577 | root_window for that screen. */ | ||
| 578 | |||
| 579 | if (old == XSCREEN (o->screen)->root_window) | ||
| 580 | XSCREEN (o->screen)->root_window = replacement; | ||
| 581 | |||
| 582 | p->left = o->left; | ||
| 583 | p->top = o->top; | ||
| 584 | p->width = o->width; | ||
| 585 | p->height = o->height; | ||
| 586 | |||
| 587 | p->next = tem = o->next; | ||
| 588 | if (!NULL (tem)) | ||
| 589 | XWINDOW (tem)->prev = replacement; | ||
| 590 | |||
| 591 | p->prev = tem = o->prev; | ||
| 592 | if (!NULL (tem)) | ||
| 593 | XWINDOW (tem)->next = replacement; | ||
| 594 | |||
| 595 | p->parent = tem = o->parent; | ||
| 596 | if (!NULL (tem)) | ||
| 597 | { | ||
| 598 | if (EQ (XWINDOW (tem)->vchild, old)) | ||
| 599 | XWINDOW (tem)->vchild = replacement; | ||
| 600 | if (EQ (XWINDOW (tem)->hchild, old)) | ||
| 601 | XWINDOW (tem)->hchild = replacement; | ||
| 602 | } | ||
| 603 | |||
| 604 | /*** Here, if replacement is a vertical combination | ||
| 605 | and so is its new parent, we should make replacement's | ||
| 606 | children be children of that parent instead. ***/ | ||
| 607 | } | ||
| 608 | |||
| 609 | DEFUN ("delete-window", Fdelete_window, Sdelete_window, 0, 1, "", | ||
| 610 | "Remove WINDOW from the display. Default is selected window.") | ||
| 611 | (window) | ||
| 612 | register Lisp_Object window; | ||
| 613 | { | ||
| 614 | register Lisp_Object tem, parent, sib; | ||
| 615 | register struct window *p; | ||
| 616 | register struct window *par; | ||
| 617 | |||
| 618 | if (NULL (window)) | ||
| 619 | window = selected_window; | ||
| 620 | else | ||
| 621 | CHECK_WINDOW (window, 0); | ||
| 622 | |||
| 623 | p = XWINDOW (window); | ||
| 624 | parent = p->parent; | ||
| 625 | if (NULL (parent)) | ||
| 626 | error ("Attempt to delete minibuffer or sole ordinary window"); | ||
| 627 | par = XWINDOW (parent); | ||
| 628 | |||
| 629 | windows_or_buffers_changed++; | ||
| 630 | |||
| 631 | if (EQ (window, selected_window)) | ||
| 632 | Fselect_window (Fnext_window (window, Qnil, Qnil)); | ||
| 633 | |||
| 634 | tem = p->buffer; | ||
| 635 | /* tem is null for dummy parent windows | ||
| 636 | (which have inferiors but not any contents themselves) */ | ||
| 637 | if (!NULL (tem)) | ||
| 638 | { | ||
| 639 | unshow_buffer (p); | ||
| 640 | unchain_marker (p->pointm); | ||
| 641 | unchain_marker (p->start); | ||
| 642 | p->buffer = Qnil; | ||
| 643 | } | ||
| 644 | |||
| 645 | tem = p->next; | ||
| 646 | if (!NULL (tem)) | ||
| 647 | XWINDOW (tem)->prev = p->prev; | ||
| 648 | |||
| 649 | tem = p->prev; | ||
| 650 | if (!NULL (tem)) | ||
| 651 | XWINDOW (tem)->next = p->next; | ||
| 652 | |||
| 653 | if (EQ (window, par->hchild)) | ||
| 654 | par->hchild = p->next; | ||
| 655 | if (EQ (window, par->vchild)) | ||
| 656 | par->vchild = p->next; | ||
| 657 | |||
| 658 | /* Find one of our siblings to give our space to. */ | ||
| 659 | sib = p->prev; | ||
| 660 | if (NULL (sib)) | ||
| 661 | { | ||
| 662 | /* If p gives its space to its next sibling, that sibling needs | ||
| 663 | to have its top/left side pulled back to where p's is. | ||
| 664 | set_window_{height,width} will re-position the sibling's | ||
| 665 | children. */ | ||
| 666 | sib = p->next; | ||
| 667 | XFASTINT (XWINDOW (sib)->top) = p->top; | ||
| 668 | XFASTINT (XWINDOW (sib)->left) = p->left; | ||
| 669 | } | ||
| 670 | |||
| 671 | /* Stretch that sibling. */ | ||
| 672 | if (!NULL (par->vchild)) | ||
| 673 | set_window_height (sib, | ||
| 674 | XFASTINT (XWINDOW (sib)->height) + XFASTINT (p->height), | ||
| 675 | 1); | ||
| 676 | if (!NULL (par->hchild)) | ||
| 677 | set_window_width (sib, | ||
| 678 | XFASTINT (XWINDOW (sib)->width) + XFASTINT (p->width), | ||
| 679 | 1); | ||
| 680 | |||
| 681 | /* If parent now has only one child, | ||
| 682 | put the child into the parent's place. */ | ||
| 683 | |||
| 684 | tem = par->hchild; | ||
| 685 | if (NULL (tem)) | ||
| 686 | tem = par->vchild; | ||
| 687 | if (NULL (XWINDOW (tem)->next)) | ||
| 688 | replace_window (parent, tem); | ||
| 689 | return Qnil; | ||
| 690 | } | ||
| 691 | |||
| 692 | #ifdef MULTI_SCREEN | ||
| 693 | Lisp_Object | ||
| 694 | next_screen_window (screen, window, mini) | ||
| 695 | SCREEN_PTR screen; | ||
| 696 | Lisp_Object window, mini; | ||
| 697 | { | ||
| 698 | Lisp_Object tem; | ||
| 699 | |||
| 700 | if (NULL (window)) | ||
| 701 | window = SCREEN_SELECTED_WINDOW (screen); | ||
| 702 | |||
| 703 | /* Do this loop at least once, to get the next window, and perhaps | ||
| 704 | again, if we hit the minibuffer and that is not acceptable. */ | ||
| 705 | do | ||
| 706 | { | ||
| 707 | /* Find a window that actually has a next one. This loop | ||
| 708 | climbs up the tree. */ | ||
| 709 | while (tem = XWINDOW (window)->next, NULL (tem)) | ||
| 710 | if (tem = XWINDOW (window)->parent, !NULL (tem)) | ||
| 711 | window = tem; | ||
| 712 | else | ||
| 713 | /* Since window's next and parent are nil, we have found | ||
| 714 | the minibuffer window of this screen. */ | ||
| 715 | { | ||
| 716 | tem = SCREEN_ROOT_WINDOW (screen); | ||
| 717 | break; | ||
| 718 | } | ||
| 719 | |||
| 720 | window = tem; | ||
| 721 | /* If we're in a combination window, find its first child and | ||
| 722 | recurse on that. Otherwise, we've found the window we want. */ | ||
| 723 | while (1) | ||
| 724 | { | ||
| 725 | if (!NULL (XWINDOW (window)->hchild)) | ||
| 726 | window = XWINDOW (window)->hchild; | ||
| 727 | else if (!NULL (XWINDOW (window)->vchild)) | ||
| 728 | window = XWINDOW (window)->vchild; | ||
| 729 | else break; | ||
| 730 | } | ||
| 731 | } | ||
| 732 | /* Exit the loop if | ||
| 733 | this isn't a minibuffer window, or | ||
| 734 | we're accepting all minibuffer windows, even when inactive, or | ||
| 735 | we're accepting active minibuffer windows and this one is. */ | ||
| 736 | while (MINI_WINDOW_P (XWINDOW (window)) | ||
| 737 | && !EQ (mini, Qt) | ||
| 738 | && (!NULL (mini) || !minibuf_level)); | ||
| 739 | |||
| 740 | return window; | ||
| 741 | } | ||
| 742 | #endif | ||
| 743 | |||
| 744 | extern Lisp_Object next_screen (), prev_screen (); | ||
| 745 | |||
| 746 | DEFUN ("next-window", Fnext_window, Snext_window, 0, 3, 0, | ||
| 747 | "Return next window after WINDOW in canonical ordering of windows.\n\ | ||
| 748 | Optional second arg MINIBUF t means count the minibuffer window\n\ | ||
| 749 | even if not active. If MINIBUF is neither t nor nil it means\n\ | ||
| 750 | not to count the minibuffer even if it is active.\n\ | ||
| 751 | Optional third arg ALL-SCREENS t means include all windows in all screens;\n\ | ||
| 752 | otherwise cycle within the selected screen, with the exception that if a\n\ | ||
| 753 | global minibuffer screen is in use and MINIBUF is t, all screens are used.") | ||
| 754 | (window, mini, all_screens) | ||
| 755 | register Lisp_Object window, mini, all_screens; | ||
| 756 | { | ||
| 757 | register Lisp_Object tem; | ||
| 758 | |||
| 759 | if (NULL (window)) | ||
| 760 | window = selected_window; | ||
| 761 | else | ||
| 762 | CHECK_WINDOW (window, 0); | ||
| 763 | |||
| 764 | #ifdef MULTI_SCREEN | ||
| 765 | if (EQ (mini, Qt) | ||
| 766 | || (! NULL (mini) && minibuf_level)) | ||
| 767 | { | ||
| 768 | if (SCREENP (Vglobal_minibuffer_screen)) | ||
| 769 | all_screens = Qt; | ||
| 770 | } | ||
| 771 | #endif | ||
| 772 | |||
| 773 | /* Do this loop at least once, to get the next window, and perhaps | ||
| 774 | again, if we hit the minibuffer and that is not acceptable. */ | ||
| 775 | do | ||
| 776 | { | ||
| 777 | /* Find a window that actually has a next one. This loop | ||
| 778 | climbs up the tree. */ | ||
| 779 | while (tem = XWINDOW (window)->next, NULL (tem)) | ||
| 780 | if (tem = XWINDOW (window)->parent, !NULL (tem)) | ||
| 781 | window = tem; | ||
| 782 | else | ||
| 783 | /* Since window's next and parent are nil, it must be | ||
| 784 | the minibuffer window of this screen. If all_screens, | ||
| 785 | jump to the next screen. */ | ||
| 786 | { | ||
| 787 | tem = WINDOW_SCREEN (XWINDOW (window)); | ||
| 788 | #ifdef MULTI_SCREEN | ||
| 789 | if (! NULL (all_screens)) | ||
| 790 | tem = next_screen (tem, NULL (mini) ? 0 : 1); | ||
| 791 | #endif | ||
| 792 | tem = SCREEN_ROOT_WINDOW (XSCREEN (tem)); | ||
| 793 | break; | ||
| 794 | } | ||
| 795 | |||
| 796 | window = tem; | ||
| 797 | /* If we're in a combination window, find its first child and | ||
| 798 | recurse on that. Otherwise, we've found the window we want. */ | ||
| 799 | while (1) | ||
| 800 | { | ||
| 801 | if (!NULL (XWINDOW (window)->hchild)) | ||
| 802 | window = XWINDOW (window)->hchild; | ||
| 803 | else if (!NULL (XWINDOW (window)->vchild)) | ||
| 804 | window = XWINDOW (window)->vchild; | ||
| 805 | else break; | ||
| 806 | } | ||
| 807 | } | ||
| 808 | /* Exit the loop if | ||
| 809 | this isn't a minibuffer window, or | ||
| 810 | we're accepting all minibuffer windows, even when inactive, or | ||
| 811 | we're accepting active minibuffer windows and this one is, or | ||
| 812 | this is a screen whose only window is a minibuffer window. */ | ||
| 813 | while (MINI_WINDOW_P (XWINDOW (window)) | ||
| 814 | && !EQ (mini, Qt) | ||
| 815 | && (!NULL (mini) || !minibuf_level) | ||
| 816 | && !EQ (SCREEN_ROOT_WINDOW (XSCREEN (XWINDOW (window)->screen)), | ||
| 817 | SCREEN_MINIBUF_WINDOW (XSCREEN (XWINDOW (window)->screen)))); | ||
| 818 | |||
| 819 | return window; | ||
| 820 | } | ||
| 821 | |||
| 822 | DEFUN ("previous-window", Fprevious_window, Sprevious_window, 0, 3, 0, | ||
| 823 | "Return previous window before WINDOW in canonical ordering of windows.\n\ | ||
| 824 | Optional second arg MINIBUF t means count the minibuffer window\n\ | ||
| 825 | even if not active. If MINIBUF is neither t nor nil it means\n\ | ||
| 826 | not to count the minibuffer even if it is active.\n\ | ||
| 827 | Optional third arg ALL-SCREENS t means include all windows in all screens;\n\ | ||
| 828 | otherwise cycle within the selected screen, with the exception that if a\n\ | ||
| 829 | global minibuffer screen is in use and MINIBUF is t, all screens are used.") | ||
| 830 | (window, mini, all_screens) | ||
| 831 | register Lisp_Object window, mini, all_screens; | ||
| 832 | { | ||
| 833 | register Lisp_Object tem; | ||
| 834 | |||
| 835 | if (NULL (window)) | ||
| 836 | window = selected_window; | ||
| 837 | else | ||
| 838 | CHECK_WINDOW (window, 0); | ||
| 839 | |||
| 840 | #ifdef MULTI_SCREEN | ||
| 841 | if (EQ (mini, Qt) | ||
| 842 | || (! NULL (mini) && minibuf_level)) | ||
| 843 | { | ||
| 844 | if (SCREENP (Vglobal_minibuffer_screen)) | ||
| 845 | all_screens = Qt; | ||
| 846 | } | ||
| 847 | #endif | ||
| 848 | |||
| 849 | /* Do this loop at least once, to get the previous window, and perhaps | ||
| 850 | again, if we hit the minibuffer and that is not acceptable. */ | ||
| 851 | do | ||
| 852 | { | ||
| 853 | /* Find a window that actually has a previous one. This loop | ||
| 854 | climbs up the tree. */ | ||
| 855 | while (tem = XWINDOW (window)->prev, NULL (tem)) | ||
| 856 | if (tem = XWINDOW (window)->parent, !NULL (tem)) | ||
| 857 | window = tem; | ||
| 858 | else | ||
| 859 | /* Since window's prev and parent are nil, we have found | ||
| 860 | the root window of this screen. If all_screens, jump | ||
| 861 | to the previous screen. */ | ||
| 862 | { | ||
| 863 | tem = WINDOW_SCREEN (XWINDOW (window)); | ||
| 864 | #ifdef MULTI_SCREEN | ||
| 865 | if (! NULL (all_screens)) | ||
| 866 | tem = prev_screen (tem, NULL (mini) ? 0 : 1); | ||
| 867 | #endif | ||
| 868 | tem = SCREEN_ROOT_WINDOW (XSCREEN (tem)); | ||
| 869 | break; | ||
| 870 | } | ||
| 871 | |||
| 872 | window = tem; | ||
| 873 | /* If we're in a combination window, find its last child and | ||
| 874 | recurse on that. Otherwise, we've found the window we want. */ | ||
| 875 | while (1) | ||
| 876 | { | ||
| 877 | if (!NULL (XWINDOW (window)->hchild)) | ||
| 878 | window = XWINDOW (window)->hchild; | ||
| 879 | else if (!NULL (XWINDOW (window)->vchild)) | ||
| 880 | window = XWINDOW (window)->vchild; | ||
| 881 | else break; | ||
| 882 | while (tem = XWINDOW (window)->next, !NULL (tem)) | ||
| 883 | window = tem; | ||
| 884 | } | ||
| 885 | } | ||
| 886 | /* Exit the loop if | ||
| 887 | this isn't a minibuffer window, or | ||
| 888 | we're accepting all minibuffer windows, even when inactive, or | ||
| 889 | we're accepting active minibuffer windows and this one is, or | ||
| 890 | this is a screen whose only window is a minibuffer window. */ | ||
| 891 | while (MINI_WINDOW_P (XWINDOW (window)) | ||
| 892 | && !EQ (mini, Qt) | ||
| 893 | && (!NULL (mini) || !minibuf_level) | ||
| 894 | && !EQ (SCREEN_ROOT_WINDOW (XSCREEN (XWINDOW (window)->screen)), | ||
| 895 | SCREEN_MINIBUF_WINDOW (XSCREEN (XWINDOW (window)->screen)))); | ||
| 896 | |||
| 897 | return window; | ||
| 898 | } | ||
| 899 | |||
| 900 | DEFUN ("other-window", Fother_window, Sother_window, 1, 1, "p", | ||
| 901 | "Select the ARG'th different window on this screen.\n\ | ||
| 902 | All windows on current screen are arranged in a cyclic order.\n\ | ||
| 903 | This command selects the window ARG steps away in that order.\n\ | ||
| 904 | A negative ARG moves in the opposite order. If the optional second\n\ | ||
| 905 | argument ALL_SCREENS is non-nil, cycle through all screens.") | ||
| 906 | (n, all_screens) | ||
| 907 | register Lisp_Object n, all_screens; | ||
| 908 | { | ||
| 909 | register int i; | ||
| 910 | register Lisp_Object w; | ||
| 911 | |||
| 912 | CHECK_NUMBER (n, 0); | ||
| 913 | w = selected_window; | ||
| 914 | i = XINT (n); | ||
| 915 | |||
| 916 | while (i > 0) | ||
| 917 | { | ||
| 918 | w = Fnext_window (w, Qnil, all_screens); | ||
| 919 | i--; | ||
| 920 | } | ||
| 921 | while (i < 0) | ||
| 922 | { | ||
| 923 | w = Fprevious_window (w, Qnil, all_screens); | ||
| 924 | i++; | ||
| 925 | } | ||
| 926 | Fselect_window (w); | ||
| 927 | return Qnil; | ||
| 928 | } | ||
| 929 | |||
| 930 | /* Look at all windows, performing an operation specified by TYPE | ||
| 931 | with argument OBJ. | ||
| 932 | If SCREENS is Qt, look at all screens, if Qnil, look at just the selected | ||
| 933 | screen. If SCREENS is a screen, just look at windows on that screen. | ||
| 934 | If MINI is non-zero, perform the operation on minibuffer windows too. | ||
| 935 | */ | ||
| 936 | |||
| 937 | enum window_loop | ||
| 938 | { | ||
| 939 | WINDOW_LOOP_UNUSED, | ||
| 940 | GET_BUFFER_WINDOW, /* Arg is buffer */ | ||
| 941 | GET_LRU_WINDOW, /* Arg is t for full-width windows only */ | ||
| 942 | DELETE_OTHER_WINDOWS, /* Arg is window not to delete */ | ||
| 943 | DELETE_BUFFER_WINDOWS, /* Arg is buffer */ | ||
| 944 | GET_LARGEST_WINDOW, | ||
| 945 | UNSHOW_BUFFER, /* Arg is buffer */ | ||
| 946 | }; | ||
| 947 | |||
| 948 | static Lisp_Object | ||
| 949 | window_loop (type, obj, mini, screens) | ||
| 950 | enum window_loop type; | ||
| 951 | register Lisp_Object obj, screens; | ||
| 952 | int mini; | ||
| 953 | { | ||
| 954 | register Lisp_Object w; | ||
| 955 | register Lisp_Object best_window; | ||
| 956 | register Lisp_Object next_window; | ||
| 957 | register Lisp_Object first_window; | ||
| 958 | SCREEN_PTR screen; | ||
| 959 | |||
| 960 | /* If we're only looping through windows on a particular screen, | ||
| 961 | screen points to that screen. If we're looping through windows | ||
| 962 | on all screens, screen is 0. */ | ||
| 963 | if (SCREENP (screens)) | ||
| 964 | screen = XSCREEN (screens); | ||
| 965 | else if (NULL (screens)) | ||
| 966 | screen = selected_screen; | ||
| 967 | else | ||
| 968 | screen = 0; | ||
| 969 | |||
| 970 | /* Pick a window to start with. */ | ||
| 971 | if (XTYPE (obj) == Lisp_Window) | ||
| 972 | first_window = obj; | ||
| 973 | else if (screen) | ||
| 974 | first_window = SCREEN_SELECTED_WINDOW (screen); | ||
| 975 | else | ||
| 976 | first_window = SCREEN_SELECTED_WINDOW (selected_screen); | ||
| 977 | |||
| 978 | w = first_window; | ||
| 979 | best_window = Qnil; | ||
| 980 | do | ||
| 981 | { | ||
| 982 | /* Pick the next window now, since some operations will delete | ||
| 983 | the current window. */ | ||
| 984 | #ifdef MULTI_SCREEN | ||
| 985 | if (screen) | ||
| 986 | next_window = next_screen_window (screen, w, mini ? Qt : Qnil); | ||
| 987 | else | ||
| 988 | #endif /* MULTI_SCREEN */ | ||
| 989 | /* We know screen is 0, so we're looping through all screens. | ||
| 990 | Or we know this isn't a MULTI_SCREEN Emacs, so who cares? */ | ||
| 991 | next_window = Fnext_window (w, mini ? Qt : Qnil, Qt); | ||
| 992 | |||
| 993 | if (!MINI_WINDOW_P (XWINDOW (w)) | ||
| 994 | || (mini && minibuf_level > 0)) | ||
| 995 | switch (type) | ||
| 996 | { | ||
| 997 | case GET_BUFFER_WINDOW: | ||
| 998 | #if 0 | ||
| 999 | /* Ignore invisible and iconified screens. */ | ||
| 1000 | if (! SCREEN_VISIBLE_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w)))) | ||
| 1001 | || SCREEN_ICONIFIED_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w))))) | ||
| 1002 | break; | ||
| 1003 | #endif | ||
| 1004 | if (XBUFFER (XWINDOW (w)->buffer) == XBUFFER (obj)) | ||
| 1005 | return w; | ||
| 1006 | break; | ||
| 1007 | |||
| 1008 | case GET_LRU_WINDOW: | ||
| 1009 | /* t as arg means consider only full-width windows */ | ||
| 1010 | if (!NULL (obj) && XFASTINT (XWINDOW (w)->width) != screen->width) | ||
| 1011 | break; | ||
| 1012 | #if 0 | ||
| 1013 | /* Ignore invisible and iconified screens. */ | ||
| 1014 | if (! SCREEN_VISIBLE_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w)))) | ||
| 1015 | || SCREEN_ICONIFIED_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w))))) | ||
| 1016 | break; | ||
| 1017 | #endif | ||
| 1018 | /* Ignore dedicated windows and minibuffers. */ | ||
| 1019 | if (MINI_WINDOW_P (XWINDOW (w)) | ||
| 1020 | || !NULL (XWINDOW (w)->dedicated)) | ||
| 1021 | break; | ||
| 1022 | if (NULL (best_window) | ||
| 1023 | || (XFASTINT (XWINDOW (best_window)->use_time) | ||
| 1024 | > XFASTINT (XWINDOW (w)->use_time))) | ||
| 1025 | best_window = w; | ||
| 1026 | break; | ||
| 1027 | |||
| 1028 | case DELETE_OTHER_WINDOWS: | ||
| 1029 | if (XWINDOW (w) != XWINDOW (obj)) | ||
| 1030 | Fdelete_window (w); | ||
| 1031 | break; | ||
| 1032 | |||
| 1033 | case DELETE_BUFFER_WINDOWS: | ||
| 1034 | if (EQ (XWINDOW (w)->buffer, obj)) | ||
| 1035 | { | ||
| 1036 | /* If we're deleting the buffer displayed in the only window | ||
| 1037 | on the screen, find a new buffer to display there. */ | ||
| 1038 | if (NULL (XWINDOW (w)->parent)) | ||
| 1039 | { | ||
| 1040 | Lisp_Object new_buffer = Fother_buffer (obj); | ||
| 1041 | if (NULL (new_buffer)) | ||
| 1042 | new_buffer | ||
| 1043 | = Fget_buffer_create (build_string ("*scratch*")); | ||
| 1044 | Fset_window_buffer (w, new_buffer); | ||
| 1045 | Fset_buffer (XWINDOW (w)->buffer); | ||
| 1046 | } | ||
| 1047 | else | ||
| 1048 | Fdelete_window (w); | ||
| 1049 | } | ||
| 1050 | break; | ||
| 1051 | |||
| 1052 | case GET_LARGEST_WINDOW: | ||
| 1053 | #if 0 | ||
| 1054 | /* Ignore invisible and iconified screens. */ | ||
| 1055 | if (! SCREEN_VISIBLE_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w)))) | ||
| 1056 | || SCREEN_ICONIFIED_P (XSCREEN (WINDOW_SCREEN (XWINDOW (w))))) | ||
| 1057 | break; | ||
| 1058 | #endif | ||
| 1059 | /* Ignore dedicated windows and minibuffers. */ | ||
| 1060 | if (MINI_WINDOW_P (XWINDOW (w)) | ||
| 1061 | || !NULL (XWINDOW (w)->dedicated)) | ||
| 1062 | break; | ||
| 1063 | { | ||
| 1064 | struct window *best_window_ptr = XWINDOW (best_window); | ||
| 1065 | struct window *w_ptr = XWINDOW (w); | ||
| 1066 | if (NULL (best_window) || | ||
| 1067 | (XFASTINT (w_ptr->height) * XFASTINT (w_ptr->width)) | ||
| 1068 | > (XFASTINT (best_window_ptr->height) | ||
| 1069 | * XFASTINT (best_window_ptr->width))) | ||
| 1070 | best_window = w; | ||
| 1071 | } | ||
| 1072 | break; | ||
| 1073 | |||
| 1074 | case UNSHOW_BUFFER: | ||
| 1075 | if (EQ (XWINDOW (w)->buffer, obj)) | ||
| 1076 | { | ||
| 1077 | /* Find another buffer to show in this window. */ | ||
| 1078 | Lisp_Object another_buffer = Fother_buffer (obj); | ||
| 1079 | if (NULL (another_buffer)) | ||
| 1080 | another_buffer | ||
| 1081 | = Fget_buffer_create (build_string ("*scratch*")); | ||
| 1082 | Fset_window_buffer (w, another_buffer); | ||
| 1083 | if (EQ (w, selected_window)) | ||
| 1084 | Fset_buffer (XWINDOW (w)->buffer); | ||
| 1085 | } | ||
| 1086 | break; | ||
| 1087 | } | ||
| 1088 | w = next_window; | ||
| 1089 | } | ||
| 1090 | while (! EQ (w, first_window)); | ||
| 1091 | |||
| 1092 | return best_window; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | DEFUN ("get-lru-window", Fget_lru_window, Sget_lru_window, 0, 1, 0, | ||
| 1096 | "Return the window least recently selected or used for display.\n\ | ||
| 1097 | If optional argument SCREENS is t, search all screens. If SCREEN is a\n\ | ||
| 1098 | screen, search only that screen.\n") | ||
| 1099 | (screens) | ||
| 1100 | Lisp_Object screens; | ||
| 1101 | { | ||
| 1102 | register Lisp_Object w; | ||
| 1103 | /* First try for a window that is full-width */ | ||
| 1104 | w = window_loop (GET_LRU_WINDOW, Qt, 0, screens); | ||
| 1105 | if (!NULL (w) && !EQ (w, selected_window)) | ||
| 1106 | return w; | ||
| 1107 | /* If none of them, try the rest */ | ||
| 1108 | return window_loop (GET_LRU_WINDOW, Qnil, 0, screens); | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | DEFUN ("get-largest-window", Fget_largest_window, Sget_largest_window, 0, 1, 0, | ||
| 1112 | "Return the largest window in area.\n\ | ||
| 1113 | If optional argument SCREENS is t, search all screens. If SCREEN is a\n\ | ||
| 1114 | screen, search only that screen.\n") | ||
| 1115 | (screen) | ||
| 1116 | Lisp_Object screen; | ||
| 1117 | { | ||
| 1118 | return window_loop (GET_LARGEST_WINDOW, Qnil, 0, | ||
| 1119 | screen); | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | DEFUN ("get-buffer-window", Fget_buffer_window, Sget_buffer_window, 1, 2, 0, | ||
| 1123 | "Return a window currently displaying BUFFER, or nil if none.\n\ | ||
| 1124 | If optional argument SCREENS is t, search all screens. If SCREEN is a\n\ | ||
| 1125 | screen, search only that screen.\n") | ||
| 1126 | (buffer, screen) | ||
| 1127 | Lisp_Object buffer, screen; | ||
| 1128 | { | ||
| 1129 | buffer = Fget_buffer (buffer); | ||
| 1130 | if (XTYPE (buffer) == Lisp_Buffer) | ||
| 1131 | return window_loop (GET_BUFFER_WINDOW, buffer, 1, screen); | ||
| 1132 | else | ||
| 1133 | return Qnil; | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | DEFUN ("delete-other-windows", Fdelete_other_windows, Sdelete_other_windows, | ||
| 1137 | 0, 1, "", | ||
| 1138 | "Make WINDOW (or the selected window) fill its screen.\n\ | ||
| 1139 | Only the screen WINDOW is on is affected.") | ||
| 1140 | (window) | ||
| 1141 | Lisp_Object window; | ||
| 1142 | { | ||
| 1143 | struct window *w; | ||
| 1144 | int opoint = point; | ||
| 1145 | struct buffer *obuf = current_buffer; | ||
| 1146 | int top; | ||
| 1147 | |||
| 1148 | if (NULL (window)) | ||
| 1149 | window = selected_window; | ||
| 1150 | else | ||
| 1151 | CHECK_WINDOW (window, 0); | ||
| 1152 | |||
| 1153 | w = XWINDOW (window); | ||
| 1154 | top = XFASTINT (w->top); | ||
| 1155 | |||
| 1156 | window_loop (DELETE_OTHER_WINDOWS, window, 0, WINDOW_SCREEN(w)); | ||
| 1157 | |||
| 1158 | Fset_buffer (w->buffer); | ||
| 1159 | SET_PT (marker_position (w->start)); | ||
| 1160 | Frecenter (make_number (top)); | ||
| 1161 | |||
| 1162 | set_buffer_internal (obuf); | ||
| 1163 | SET_PT (opoint); | ||
| 1164 | return Qnil; | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | DEFUN ("delete-windows-on", Fdelete_windows_on, Sdelete_windows_on, | ||
| 1168 | 1, 1, "bDelete windows on (buffer): ", | ||
| 1169 | "Delete all windows showing BUFFER.") | ||
| 1170 | (buffer) | ||
| 1171 | Lisp_Object buffer; | ||
| 1172 | { | ||
| 1173 | if (!NULL (buffer)) | ||
| 1174 | { | ||
| 1175 | buffer = Fget_buffer (buffer); | ||
| 1176 | CHECK_BUFFER (buffer, 0); | ||
| 1177 | window_loop (DELETE_BUFFER_WINDOWS, buffer, 0, Qt); | ||
| 1178 | } | ||
| 1179 | return Qnil; | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | DEFUN ("replace-buffer-in-windows", Freplace_buffer_in_windows, | ||
| 1183 | Sreplace_buffer_in_windows, | ||
| 1184 | 1, 1, "bReplace buffer in windows: ", | ||
| 1185 | "Replace BUFFER with some other buffer in all windows showing it.") | ||
| 1186 | (buffer) | ||
| 1187 | Lisp_Object buffer; | ||
| 1188 | { | ||
| 1189 | if (!NULL (buffer)) | ||
| 1190 | { | ||
| 1191 | buffer = Fget_buffer (buffer); | ||
| 1192 | CHECK_BUFFER (buffer, 0); | ||
| 1193 | window_loop (UNSHOW_BUFFER, buffer, 0, Qt); | ||
| 1194 | } | ||
| 1195 | return Qnil; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | /* Set the height of WINDOW and all its inferiors. */ | ||
| 1199 | /* Normally the window is deleted if it gets too small. | ||
| 1200 | nodelete nonzero means do not do this. | ||
| 1201 | (The caller should check later and do so if appropriate) */ | ||
| 1202 | |||
| 1203 | set_window_height (window, height, nodelete) | ||
| 1204 | Lisp_Object window; | ||
| 1205 | int height; | ||
| 1206 | int nodelete; | ||
| 1207 | { | ||
| 1208 | register struct window *w = XWINDOW (window); | ||
| 1209 | register struct window *c; | ||
| 1210 | int oheight = XFASTINT (w->height); | ||
| 1211 | int top, pos, lastbot, opos, lastobot; | ||
| 1212 | Lisp_Object child; | ||
| 1213 | |||
| 1214 | if (!nodelete | ||
| 1215 | && ! NULL (w->parent) | ||
| 1216 | && height < window_min_height) | ||
| 1217 | { | ||
| 1218 | Fdelete_window (window); | ||
| 1219 | return; | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | XFASTINT (w->last_modified) = 0; | ||
| 1223 | windows_or_buffers_changed++; | ||
| 1224 | XFASTINT (w->height) = height; | ||
| 1225 | if (!NULL (w->hchild)) | ||
| 1226 | { | ||
| 1227 | for (child = w->hchild; !NULL (child); child = XWINDOW (child)->next) | ||
| 1228 | { | ||
| 1229 | XWINDOW (child)->top = w->top; | ||
| 1230 | set_window_height (child, height, nodelete); | ||
| 1231 | } | ||
| 1232 | } | ||
| 1233 | else if (!NULL (w->vchild)) | ||
| 1234 | { | ||
| 1235 | lastbot = top = XFASTINT (w->top); | ||
| 1236 | lastobot = 0; | ||
| 1237 | for (child = w->vchild; !NULL (child); child = c->next) | ||
| 1238 | { | ||
| 1239 | c = XWINDOW (child); | ||
| 1240 | |||
| 1241 | opos = lastobot + XFASTINT (c->height); | ||
| 1242 | |||
| 1243 | XFASTINT (c->top) = lastbot; | ||
| 1244 | |||
| 1245 | pos = (((opos * height) << 1) + oheight) / (oheight << 1); | ||
| 1246 | |||
| 1247 | /* Avoid confusion: inhibit deletion of child if becomes too small */ | ||
| 1248 | set_window_height (child, pos + top - lastbot, 1); | ||
| 1249 | |||
| 1250 | /* Now advance child to next window, | ||
| 1251 | and set lastbot if child was not just deleted. */ | ||
| 1252 | lastbot = pos + top; | ||
| 1253 | lastobot = opos; | ||
| 1254 | } | ||
| 1255 | /* Now delete any children that became too small. */ | ||
| 1256 | if (!nodelete) | ||
| 1257 | for (child = w->vchild; !NULL (child); child = XWINDOW (child)->next) | ||
| 1258 | { | ||
| 1259 | set_window_height (child, XINT (XWINDOW (child)->height), 0); | ||
| 1260 | } | ||
| 1261 | } | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | /* Recursively set width of WINDOW and its inferiors. */ | ||
| 1265 | |||
| 1266 | set_window_width (window, width, nodelete) | ||
| 1267 | Lisp_Object window; | ||
| 1268 | int width; | ||
| 1269 | int nodelete; | ||
| 1270 | { | ||
| 1271 | register struct window *w = XWINDOW (window); | ||
| 1272 | register struct window *c; | ||
| 1273 | int owidth = XFASTINT (w->width); | ||
| 1274 | int left, pos, lastright, opos, lastoright; | ||
| 1275 | Lisp_Object child; | ||
| 1276 | |||
| 1277 | if (!nodelete && width < window_min_width) | ||
| 1278 | { | ||
| 1279 | Fdelete_window (window); | ||
| 1280 | return; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | XFASTINT (w->last_modified) = 0; | ||
| 1284 | windows_or_buffers_changed++; | ||
| 1285 | XFASTINT (w->width) = width; | ||
| 1286 | if (!NULL (w->vchild)) | ||
| 1287 | { | ||
| 1288 | for (child = w->vchild; !NULL (child); child = XWINDOW (child)->next) | ||
| 1289 | { | ||
| 1290 | XWINDOW (child)->left = w->left; | ||
| 1291 | set_window_width (child, width, nodelete); | ||
| 1292 | } | ||
| 1293 | } | ||
| 1294 | else if (!NULL (w->hchild)) | ||
| 1295 | { | ||
| 1296 | lastright = left = XFASTINT (w->left); | ||
| 1297 | lastoright = 0; | ||
| 1298 | for (child = w->hchild; !NULL (child); child = c->next) | ||
| 1299 | { | ||
| 1300 | c = XWINDOW (child); | ||
| 1301 | |||
| 1302 | opos = lastoright + XFASTINT (c->width); | ||
| 1303 | |||
| 1304 | XFASTINT (c->left) = lastright; | ||
| 1305 | |||
| 1306 | pos = (((opos * width) << 1) + owidth) / (owidth << 1); | ||
| 1307 | |||
| 1308 | /* Inhibit deletion for becoming too small */ | ||
| 1309 | set_window_width (child, pos + left - lastright, 1); | ||
| 1310 | |||
| 1311 | /* Now advance child to next window, | ||
| 1312 | and set lastright if child was not just deleted. */ | ||
| 1313 | lastright = pos + left, lastoright = opos; | ||
| 1314 | } | ||
| 1315 | /* Delete children that became too small */ | ||
| 1316 | if (!nodelete) | ||
| 1317 | for (child = w->hchild; !NULL (child); child = XWINDOW (child)->next) | ||
| 1318 | { | ||
| 1319 | set_window_width (child, XINT (XWINDOW (child)->width), 0); | ||
| 1320 | } | ||
| 1321 | } | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | static int window_select_count; | ||
| 1325 | |||
| 1326 | DEFUN ("set-window-buffer", Fset_window_buffer, Sset_window_buffer, 2, 2, 0, | ||
| 1327 | "Make WINDOW display BUFFER as its contents.\n\ | ||
| 1328 | BUFFER can be a buffer or buffer name.") | ||
| 1329 | (window, buffer) | ||
| 1330 | register Lisp_Object window, buffer; | ||
| 1331 | { | ||
| 1332 | register Lisp_Object tem; | ||
| 1333 | register struct window *w = decode_window (window); | ||
| 1334 | |||
| 1335 | buffer = Fget_buffer (buffer); | ||
| 1336 | CHECK_BUFFER (buffer, 1); | ||
| 1337 | |||
| 1338 | if (NULL (XBUFFER (buffer)->name)) | ||
| 1339 | error ("Attempt to display deleted buffer"); | ||
| 1340 | |||
| 1341 | tem = w->buffer; | ||
| 1342 | if (NULL (tem)) | ||
| 1343 | error ("Window is deleted"); | ||
| 1344 | else if (! EQ (tem, Qt)) /* w->buffer is t when the window | ||
| 1345 | is first being set up. */ | ||
| 1346 | { | ||
| 1347 | if (!NULL (w->dedicated) && !EQ (tem, buffer)) | ||
| 1348 | error ("Window is dedicated to %s\n", tem); | ||
| 1349 | |||
| 1350 | unshow_buffer (w); | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | w->buffer = buffer; | ||
| 1354 | Fset_marker (w->pointm, | ||
| 1355 | make_number (BUF_PT (XBUFFER (buffer))), | ||
| 1356 | buffer); | ||
| 1357 | set_marker_restricted (w->start, | ||
| 1358 | make_number (XBUFFER (buffer)->last_window_start), | ||
| 1359 | buffer); | ||
| 1360 | w->start_at_line_beg = Qnil; | ||
| 1361 | XFASTINT (w->last_modified) = 0; | ||
| 1362 | windows_or_buffers_changed++; | ||
| 1363 | if (EQ (window, selected_window)) | ||
| 1364 | Fset_buffer (buffer); | ||
| 1365 | |||
| 1366 | return Qnil; | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | DEFUN ("select-window", Fselect_window, Sselect_window, 1, 1, 0, | ||
| 1370 | "Select WINDOW. Most editing will apply to WINDOW's buffer.\n\ | ||
| 1371 | The main editor command loop selects the buffer of the selected window\n\ | ||
| 1372 | before each command.") | ||
| 1373 | (window) | ||
| 1374 | register Lisp_Object window; | ||
| 1375 | { | ||
| 1376 | register struct window *w; | ||
| 1377 | register struct window *ow = XWINDOW (selected_window); | ||
| 1378 | |||
| 1379 | CHECK_WINDOW (window, 0); | ||
| 1380 | |||
| 1381 | w = XWINDOW (window); | ||
| 1382 | |||
| 1383 | if (NULL (w->buffer)) | ||
| 1384 | error ("Trying to select deleted window or non-leaf window"); | ||
| 1385 | |||
| 1386 | XFASTINT (w->use_time) = ++window_select_count; | ||
| 1387 | if (EQ (window, selected_window)) | ||
| 1388 | return window; | ||
| 1389 | |||
| 1390 | Fset_marker (ow->pointm, make_number (BUF_PT (XBUFFER (ow->buffer))), | ||
| 1391 | ow->buffer); | ||
| 1392 | |||
| 1393 | selected_window = window; | ||
| 1394 | #ifdef MULTI_SCREEN | ||
| 1395 | if (XSCREEN (WINDOW_SCREEN (w)) != selected_screen) | ||
| 1396 | { | ||
| 1397 | XSCREEN (WINDOW_SCREEN (w))->selected_window = window; | ||
| 1398 | Fselect_screen (WINDOW_SCREEN (w), Qnil); | ||
| 1399 | } | ||
| 1400 | else | ||
| 1401 | selected_screen->selected_window = window; | ||
| 1402 | #endif | ||
| 1403 | |||
| 1404 | record_buffer (w->buffer); | ||
| 1405 | Fset_buffer (w->buffer); | ||
| 1406 | |||
| 1407 | /* Go to the point recorded in the window. | ||
| 1408 | This is important when the buffer is in more | ||
| 1409 | than one window. It also matters when | ||
| 1410 | redisplay_window has altered point after scrolling, | ||
| 1411 | because it makes the change only in the window. */ | ||
| 1412 | { | ||
| 1413 | register int new_point = marker_position (w->pointm); | ||
| 1414 | if (new_point < BEGV) | ||
| 1415 | SET_PT (BEGV); | ||
| 1416 | if (new_point > ZV) | ||
| 1417 | SET_PT (ZV); | ||
| 1418 | else | ||
| 1419 | SET_PT (new_point); | ||
| 1420 | } | ||
| 1421 | |||
| 1422 | windows_or_buffers_changed++; | ||
| 1423 | return window; | ||
| 1424 | } | ||
| 1425 | |||
| 1426 | DEFUN ("display-buffer", Fdisplay_buffer, Sdisplay_buffer, 1, 2, 0, | ||
| 1427 | "Make BUFFER appear in some window but don't select it.\n\ | ||
| 1428 | BUFFER can be a buffer or a buffer name.\n\ | ||
| 1429 | If BUFFER is shown already in some window, just use that one,\n\ | ||
| 1430 | unless the window is the selected window and the optional second\n\ | ||
| 1431 | argument NOT_THIS_WINDOW is non-nil.\n\ | ||
| 1432 | Returns the window displaying BUFFER.") | ||
| 1433 | (buffer, not_this_window) | ||
| 1434 | register Lisp_Object buffer, not_this_window; | ||
| 1435 | { | ||
| 1436 | register Lisp_Object window; | ||
| 1437 | |||
| 1438 | buffer = Fget_buffer (buffer); | ||
| 1439 | CHECK_BUFFER (buffer, 0); | ||
| 1440 | |||
| 1441 | if (!NULL (Vdisplay_buffer_function)) | ||
| 1442 | return call2 (Vdisplay_buffer_function, buffer, not_this_window); | ||
| 1443 | |||
| 1444 | if (NULL (not_this_window) | ||
| 1445 | && XBUFFER (XWINDOW (selected_window)->buffer) == XBUFFER (buffer)) | ||
| 1446 | return selected_window; | ||
| 1447 | |||
| 1448 | window = Fget_buffer_window (buffer, Qnil); | ||
| 1449 | if (!NULL (window) | ||
| 1450 | && (NULL (not_this_window) || !EQ (window, selected_window))) | ||
| 1451 | return window; | ||
| 1452 | |||
| 1453 | #ifdef MULTI_SCREEN | ||
| 1454 | if (auto_new_screen) | ||
| 1455 | { | ||
| 1456 | window | ||
| 1457 | = Fscreen_selected_window (NULL (Vauto_new_screen_function) | ||
| 1458 | ? Fx_create_screen (Qnil) | ||
| 1459 | : call0 (Vauto_new_screen_function)); | ||
| 1460 | Fset_window_buffer (window, buffer); | ||
| 1461 | #if 0 | ||
| 1462 | Fselect_screen (XWINDOW (window)->screen, Qnil); | ||
| 1463 | #endif | ||
| 1464 | return window; | ||
| 1465 | } | ||
| 1466 | #endif /* MULTI_SCREEN */ | ||
| 1467 | |||
| 1468 | if (pop_up_windows) | ||
| 1469 | { | ||
| 1470 | #ifdef MULTI_SCREEN | ||
| 1471 | /* When minibuffer screen is used, this is the previous screen. | ||
| 1472 | Declared in minibuffer.c */ | ||
| 1473 | extern struct screen *active_screen; | ||
| 1474 | Lisp_Object screens; | ||
| 1475 | |||
| 1476 | if (active_screen) | ||
| 1477 | XSET (screens, Lisp_Screen, active_screen); | ||
| 1478 | else | ||
| 1479 | screens = Qnil; | ||
| 1480 | |||
| 1481 | #endif | ||
| 1482 | /* Don't try to create a window if would get an error */ | ||
| 1483 | if (split_height_threshold < window_min_height << 1) | ||
| 1484 | split_height_threshold = window_min_height << 1; | ||
| 1485 | |||
| 1486 | window = Fget_largest_window (screens); | ||
| 1487 | |||
| 1488 | if (!NULL (window) | ||
| 1489 | && window_height (window) >= split_height_threshold | ||
| 1490 | && | ||
| 1491 | (XFASTINT (XWINDOW (window)->width) | ||
| 1492 | == SCREEN_WIDTH (XSCREEN (WINDOW_SCREEN (XWINDOW (window)))))) | ||
| 1493 | window = Fsplit_window (window, Qnil, Qnil); | ||
| 1494 | else | ||
| 1495 | { | ||
| 1496 | window = Fget_lru_window (screens); | ||
| 1497 | if ((EQ (window, selected_window) | ||
| 1498 | || EQ (XWINDOW (window)->parent, Qnil)) | ||
| 1499 | && window_height (window) >= window_min_height << 1) | ||
| 1500 | window = Fsplit_window (window, Qnil, Qnil); | ||
| 1501 | } | ||
| 1502 | } | ||
| 1503 | else | ||
| 1504 | window = Fget_lru_window (Qnil); | ||
| 1505 | |||
| 1506 | Fset_window_buffer (window, buffer); | ||
| 1507 | return window; | ||
| 1508 | } | ||
| 1509 | |||
| 1510 | void | ||
| 1511 | temp_output_buffer_show (buf) | ||
| 1512 | register Lisp_Object buf; | ||
| 1513 | { | ||
| 1514 | register struct buffer *old = current_buffer; | ||
| 1515 | register Lisp_Object window; | ||
| 1516 | register struct window *w; | ||
| 1517 | |||
| 1518 | Fset_buffer (buf); | ||
| 1519 | XBUFFER (buf)->save_modified = MODIFF; | ||
| 1520 | BEGV = BEG; | ||
| 1521 | ZV = Z; | ||
| 1522 | SET_PT (BEG); | ||
| 1523 | clip_changed = 1; | ||
| 1524 | set_buffer_internal (old); | ||
| 1525 | |||
| 1526 | if (!EQ (Vtemp_buffer_show_function, Qnil)) | ||
| 1527 | call1 (Vtemp_buffer_show_function, buf); | ||
| 1528 | else | ||
| 1529 | { | ||
| 1530 | window = Fdisplay_buffer (buf, Qnil); | ||
| 1531 | |||
| 1532 | #ifdef MULTI_SCREEN | ||
| 1533 | if (XSCREEN (XWINDOW (window)->screen) != selected_screen) | ||
| 1534 | Fmake_screen_visible (XWINDOW (window)->screen); | ||
| 1535 | #endif /* MULTI_SCREEN */ | ||
| 1536 | Vminibuf_scroll_window = window; | ||
| 1537 | w = XWINDOW (window); | ||
| 1538 | XFASTINT (w->hscroll) = 0; | ||
| 1539 | set_marker_restricted (w->start, make_number (1), buf); | ||
| 1540 | set_marker_restricted (w->pointm, make_number (1), buf); | ||
| 1541 | } | ||
| 1542 | } | ||
| 1543 | |||
| 1544 | static | ||
| 1545 | make_dummy_parent (window) | ||
| 1546 | Lisp_Object window; | ||
| 1547 | { | ||
| 1548 | register Lisp_Object old, new; | ||
| 1549 | register struct window *o, *p; | ||
| 1550 | |||
| 1551 | old = window; | ||
| 1552 | XSETTYPE (old, Lisp_Vector); | ||
| 1553 | new = Fcopy_sequence (old); | ||
| 1554 | XSETTYPE (new, Lisp_Window); | ||
| 1555 | |||
| 1556 | o = XWINDOW (old); | ||
| 1557 | p = XWINDOW (new); | ||
| 1558 | XFASTINT (p->sequence_number) = ++sequence_number; | ||
| 1559 | |||
| 1560 | /* Put new into window structure in place of window */ | ||
| 1561 | replace_window (window, new); | ||
| 1562 | |||
| 1563 | o->next = Qnil; | ||
| 1564 | o->prev = Qnil; | ||
| 1565 | o->vchild = Qnil; | ||
| 1566 | o->hchild = Qnil; | ||
| 1567 | o->parent = new; | ||
| 1568 | |||
| 1569 | p->start = Qnil; | ||
| 1570 | p->pointm = Qnil; | ||
| 1571 | p->buffer = Qnil; | ||
| 1572 | } | ||
| 1573 | |||
| 1574 | DEFUN ("split-window", Fsplit_window, Ssplit_window, 0, 3, "", | ||
| 1575 | "Split WINDOW, putting SIZE lines in the first of the pair.\n\ | ||
| 1576 | WINDOW defaults to selected one and SIZE to half its size.\n\ | ||
| 1577 | If optional third arg HOR-FLAG is non-nil, split side by side\n\ | ||
| 1578 | and put SIZE columns in the first of the pair.") | ||
| 1579 | (window, chsize, horflag) | ||
| 1580 | Lisp_Object window, chsize, horflag; | ||
| 1581 | { | ||
| 1582 | register Lisp_Object new; | ||
| 1583 | register struct window *o, *p; | ||
| 1584 | register int size; | ||
| 1585 | |||
| 1586 | if (NULL (window)) | ||
| 1587 | window = selected_window; | ||
| 1588 | else | ||
| 1589 | CHECK_WINDOW (window, 0); | ||
| 1590 | |||
| 1591 | o = XWINDOW (window); | ||
| 1592 | |||
| 1593 | if (NULL (chsize)) | ||
| 1594 | { | ||
| 1595 | if (!NULL (horflag)) | ||
| 1596 | /* Round odd size up, since this is for the left-hand window, | ||
| 1597 | and it will lose a column for the separators. */ | ||
| 1598 | size = ((XFASTINT (o->width) + 1) & -2) >> 1; | ||
| 1599 | else | ||
| 1600 | size = XFASTINT (o->height) >> 1; | ||
| 1601 | } | ||
| 1602 | else | ||
| 1603 | { | ||
| 1604 | CHECK_NUMBER (chsize, 1); | ||
| 1605 | size = XINT (chsize); | ||
| 1606 | } | ||
| 1607 | |||
| 1608 | if (MINI_WINDOW_P (o)) | ||
| 1609 | error ("Attempt to split minibuffer window"); | ||
| 1610 | else if (SCREEN_NO_SPLIT_P (XSCREEN (WINDOW_SCREEN (o)))) | ||
| 1611 | error ("Attempt to split unsplittable screen"); | ||
| 1612 | |||
| 1613 | /* Smaller values might permit a crash. */ | ||
| 1614 | if (window_min_width < 2) | ||
| 1615 | window_min_width = 2; | ||
| 1616 | if (window_min_height < 2) | ||
| 1617 | window_min_height = 2; | ||
| 1618 | |||
| 1619 | if (NULL (horflag)) | ||
| 1620 | { | ||
| 1621 | if (size < window_min_height | ||
| 1622 | || size + window_min_height > XFASTINT (o->height)) | ||
| 1623 | args_out_of_range_3 (window, chsize, horflag); | ||
| 1624 | if (NULL (o->parent) | ||
| 1625 | || NULL (XWINDOW (o->parent)->vchild)) | ||
| 1626 | { | ||
| 1627 | make_dummy_parent (window); | ||
| 1628 | new = o->parent; | ||
| 1629 | XWINDOW (new)->vchild = window; | ||
| 1630 | } | ||
| 1631 | } | ||
| 1632 | else | ||
| 1633 | { | ||
| 1634 | if (size < window_min_width | ||
| 1635 | || size + window_min_width > XFASTINT (o->width)) | ||
| 1636 | args_out_of_range_3 (window, chsize, horflag); | ||
| 1637 | if (NULL (o->parent) | ||
| 1638 | || NULL (XWINDOW (o->parent)->hchild)) | ||
| 1639 | { | ||
| 1640 | make_dummy_parent (window); | ||
| 1641 | new = o->parent; | ||
| 1642 | XWINDOW (new)->hchild = window; | ||
| 1643 | } | ||
| 1644 | } | ||
| 1645 | |||
| 1646 | /* Now we know that window's parent is a vertical combination | ||
| 1647 | if we are dividing vertically, or a horizontal combination | ||
| 1648 | if we are making side-by-side windows */ | ||
| 1649 | |||
| 1650 | windows_or_buffers_changed++; | ||
| 1651 | new = make_window (); | ||
| 1652 | p = XWINDOW (new); | ||
| 1653 | |||
| 1654 | p->screen = o->screen; | ||
| 1655 | p->next = o->next; | ||
| 1656 | if (!NULL (p->next)) | ||
| 1657 | XWINDOW (p->next)->prev = new; | ||
| 1658 | p->prev = window; | ||
| 1659 | o->next = new; | ||
| 1660 | p->parent = o->parent; | ||
| 1661 | p->buffer = Qt; | ||
| 1662 | |||
| 1663 | Fset_window_buffer (new, o->buffer); | ||
| 1664 | |||
| 1665 | /* Apportion the available screen space among the two new windows */ | ||
| 1666 | |||
| 1667 | if (!NULL (horflag)) | ||
| 1668 | { | ||
| 1669 | p->height = o->height; | ||
| 1670 | p->top = o->top; | ||
| 1671 | XFASTINT (p->width) = XFASTINT (o->width) - size; | ||
| 1672 | XFASTINT (o->width) = size; | ||
| 1673 | XFASTINT (p->left) = XFASTINT (o->left) + size; | ||
| 1674 | } | ||
| 1675 | else | ||
| 1676 | { | ||
| 1677 | p->left = o->left; | ||
| 1678 | p->width = o->width; | ||
| 1679 | XFASTINT (p->height) = XFASTINT (o->height) - size; | ||
| 1680 | XFASTINT (o->height) = size; | ||
| 1681 | XFASTINT (p->top) = XFASTINT (o->top) + size; | ||
| 1682 | } | ||
| 1683 | |||
| 1684 | return new; | ||
| 1685 | } | ||
| 1686 | |||
| 1687 | DEFUN ("enlarge-window", Fenlarge_window, Senlarge_window, 1, 2, "p", | ||
| 1688 | "Make current window ARG lines bigger.\n\ | ||
| 1689 | From program, optional second arg non-nil means grow sideways ARG columns.") | ||
| 1690 | (n, side) | ||
| 1691 | register Lisp_Object n, side; | ||
| 1692 | { | ||
| 1693 | CHECK_NUMBER (n, 0); | ||
| 1694 | change_window_height (XINT (n), !NULL (side)); | ||
| 1695 | return Qnil; | ||
| 1696 | } | ||
| 1697 | |||
| 1698 | DEFUN ("shrink-window", Fshrink_window, Sshrink_window, 1, 2, "p", | ||
| 1699 | "Make current window ARG lines smaller.\n\ | ||
| 1700 | From program, optional second arg non-nil means shrink sideways ARG columns.") | ||
| 1701 | (n, side) | ||
| 1702 | register Lisp_Object n, side; | ||
| 1703 | { | ||
| 1704 | CHECK_NUMBER (n, 0); | ||
| 1705 | change_window_height (-XINT (n), !NULL (side)); | ||
| 1706 | return Qnil; | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | int | ||
| 1710 | window_height (window) | ||
| 1711 | Lisp_Object window; | ||
| 1712 | { | ||
| 1713 | register struct window *p = XWINDOW (window); | ||
| 1714 | return XFASTINT (p->height); | ||
| 1715 | } | ||
| 1716 | |||
| 1717 | int | ||
| 1718 | window_width (window) | ||
| 1719 | Lisp_Object window; | ||
| 1720 | { | ||
| 1721 | register struct window *p = XWINDOW (window); | ||
| 1722 | return XFASTINT (p->width); | ||
| 1723 | } | ||
| 1724 | |||
| 1725 | #define MINSIZE(w) \ | ||
| 1726 | (widthflag ? window_min_width : window_min_height) | ||
| 1727 | |||
| 1728 | #define CURBEG(w) \ | ||
| 1729 | *(widthflag ? (int *) &(w)->left : (int *) &(w)->top) | ||
| 1730 | |||
| 1731 | #define CURSIZE(w) \ | ||
| 1732 | *(widthflag ? (int *) &(w)->width : (int *) &(w)->height) | ||
| 1733 | |||
| 1734 | /* Unlike set_window_height, this function | ||
| 1735 | also changes the heights of the siblings so as to | ||
| 1736 | keep everything consistent. */ | ||
| 1737 | |||
| 1738 | change_window_height (delta, widthflag) | ||
| 1739 | register int delta; | ||
| 1740 | int widthflag; | ||
| 1741 | { | ||
| 1742 | register Lisp_Object parent; | ||
| 1743 | Lisp_Object window; | ||
| 1744 | register struct window *p; | ||
| 1745 | int *sizep; | ||
| 1746 | int (*sizefun) () = widthflag ? window_width : window_height; | ||
| 1747 | register int (*setsizefun) () = (widthflag | ||
| 1748 | ? set_window_width | ||
| 1749 | : set_window_height); | ||
| 1750 | |||
| 1751 | /* Smaller values might permit a crash. */ | ||
| 1752 | if (window_min_width < 2) | ||
| 1753 | window_min_width = 2; | ||
| 1754 | if (window_min_height < 2) | ||
| 1755 | window_min_height = 2; | ||
| 1756 | |||
| 1757 | window = selected_window; | ||
| 1758 | while (1) | ||
| 1759 | { | ||
| 1760 | p = XWINDOW (window); | ||
| 1761 | parent = p->parent; | ||
| 1762 | if (NULL (parent)) | ||
| 1763 | { | ||
| 1764 | if (widthflag) | ||
| 1765 | error ("No other window to side of this one"); | ||
| 1766 | break; | ||
| 1767 | } | ||
| 1768 | if (widthflag ? !NULL (XWINDOW (parent)->hchild) | ||
| 1769 | : !NULL (XWINDOW (parent)->vchild)) | ||
| 1770 | break; | ||
| 1771 | window = parent; | ||
| 1772 | } | ||
| 1773 | |||
| 1774 | sizep = &CURSIZE (p); | ||
| 1775 | |||
| 1776 | if (*sizep + delta < MINSIZE (p) | ||
| 1777 | && !NULL (XWINDOW (window)->parent)) | ||
| 1778 | { | ||
| 1779 | Fdelete_window (window); | ||
| 1780 | return; | ||
| 1781 | } | ||
| 1782 | |||
| 1783 | { | ||
| 1784 | register int maxdelta; | ||
| 1785 | register Lisp_Object tem; | ||
| 1786 | |||
| 1787 | maxdelta = (!NULL (parent) ? (*sizefun) (parent) - *sizep | ||
| 1788 | : (tem = (!NULL (p->next) ? p->next : p->prev), | ||
| 1789 | (*sizefun) (tem) - MINSIZE (tem))); | ||
| 1790 | |||
| 1791 | if (delta > maxdelta) | ||
| 1792 | /* This case traps trying to make the minibuffer | ||
| 1793 | the full screen, or make the only window aside from the | ||
| 1794 | minibuffer the full screen. */ | ||
| 1795 | delta = maxdelta; | ||
| 1796 | } | ||
| 1797 | |||
| 1798 | if (!NULL (p->next) && | ||
| 1799 | (*sizefun) (p->next) - delta >= MINSIZE (p->next)) | ||
| 1800 | { | ||
| 1801 | (*setsizefun) (p->next, (*sizefun) (p->next) - delta, 0); | ||
| 1802 | (*setsizefun) (window, *sizep + delta, 0); | ||
| 1803 | CURBEG (XWINDOW (p->next)) += delta; | ||
| 1804 | /* This does not change size of p->next, | ||
| 1805 | but it propagates the new top edge to its children */ | ||
| 1806 | (*setsizefun) (p->next, (*sizefun) (p->next), 0); | ||
| 1807 | } | ||
| 1808 | else if (!NULL (p->prev) && | ||
| 1809 | (*sizefun) (p->prev) - delta >= MINSIZE (p->prev)) | ||
| 1810 | { | ||
| 1811 | (*setsizefun) (p->prev, (*sizefun) (p->prev) - delta, 0); | ||
| 1812 | CURBEG (p) -= delta; | ||
| 1813 | (*setsizefun) (window, *sizep + delta, 0); | ||
| 1814 | } | ||
| 1815 | else | ||
| 1816 | { | ||
| 1817 | register int delta1; | ||
| 1818 | register int opht = (*sizefun) (parent); | ||
| 1819 | |||
| 1820 | /* If trying to grow this window to or beyond size of the parent, | ||
| 1821 | make delta1 so big that, on shrinking back down, | ||
| 1822 | all the siblings end up with less than one line and are deleted. */ | ||
| 1823 | if (opht <= *sizep + delta) | ||
| 1824 | delta1 = opht * opht * 2; | ||
| 1825 | /* Otherwise, make delta1 just right so that if we add delta1 | ||
| 1826 | lines to this window and to the parent, and then shrink | ||
| 1827 | the parent back to its original size, the new proportional | ||
| 1828 | size of this window will increase by delta. */ | ||
| 1829 | else | ||
| 1830 | delta1 = (delta * opht * 100) / ((opht - *sizep - delta) * 100); | ||
| 1831 | |||
| 1832 | /* Add delta1 lines or columns to this window, and to the parent, | ||
| 1833 | keeping things consistent while not affecting siblings. */ | ||
| 1834 | CURSIZE (XWINDOW (parent)) = opht + delta1; | ||
| 1835 | (*setsizefun) (window, *sizep + delta1, 0); | ||
| 1836 | |||
| 1837 | /* Squeeze out delta1 lines or columns from our parent, | ||
| 1838 | shriking this window and siblings proportionately. | ||
| 1839 | This brings parent back to correct size. | ||
| 1840 | Delta1 was calculated so this makes this window the desired size, | ||
| 1841 | taking it all out of the siblings. */ | ||
| 1842 | (*setsizefun) (parent, opht, 0); | ||
| 1843 | } | ||
| 1844 | |||
| 1845 | XFASTINT (p->last_modified) = 0; | ||
| 1846 | } | ||
| 1847 | #undef MINSIZE | ||
| 1848 | #undef CURBEG | ||
| 1849 | #undef CURSIZE | ||
| 1850 | |||
| 1851 | |||
| 1852 | /* Return number of lines of text (not counting mode line) in W. */ | ||
| 1853 | |||
| 1854 | int | ||
| 1855 | window_internal_height (w) | ||
| 1856 | struct window *w; | ||
| 1857 | { | ||
| 1858 | int ht = XFASTINT (w->height); | ||
| 1859 | |||
| 1860 | if (MINI_WINDOW_P (w)) | ||
| 1861 | return ht; | ||
| 1862 | |||
| 1863 | if (!NULL (w->parent) || !NULL (w->vchild) || !NULL (w->hchild) | ||
| 1864 | || !NULL (w->next) || !NULL (w->prev) | ||
| 1865 | || SCREEN_WANTS_MODELINE_P (XSCREEN (WINDOW_SCREEN (w)))) | ||
| 1866 | return ht - 1; | ||
| 1867 | |||
| 1868 | return ht; | ||
| 1869 | } | ||
| 1870 | |||
| 1871 | /* Scroll contents of window WINDOW up N lines. */ | ||
| 1872 | |||
| 1873 | void | ||
| 1874 | window_scroll (window, n) | ||
| 1875 | Lisp_Object window; | ||
| 1876 | int n; | ||
| 1877 | { | ||
| 1878 | register struct window *w = XWINDOW (window); | ||
| 1879 | register int opoint = point; | ||
| 1880 | register int pos; | ||
| 1881 | register int ht = window_internal_height (w); | ||
| 1882 | register Lisp_Object tem; | ||
| 1883 | int lose; | ||
| 1884 | Lisp_Object bolp, nmoved; | ||
| 1885 | |||
| 1886 | XFASTINT (tem) = point; | ||
| 1887 | tem = Fpos_visible_in_window_p (tem, window); | ||
| 1888 | |||
| 1889 | if (NULL (tem)) | ||
| 1890 | { | ||
| 1891 | Fvertical_motion (make_number (- ht / 2)); | ||
| 1892 | XFASTINT (tem) = point; | ||
| 1893 | Fset_marker (w->start, tem, w->buffer); | ||
| 1894 | w->force_start = Qt; | ||
| 1895 | } | ||
| 1896 | |||
| 1897 | SET_PT (marker_position (w->start)); | ||
| 1898 | lose = n < 0 && point == BEGV; | ||
| 1899 | Fvertical_motion (make_number (n)); | ||
| 1900 | pos = point; | ||
| 1901 | bolp = Fbolp (); | ||
| 1902 | SET_PT (opoint); | ||
| 1903 | |||
| 1904 | if (lose) | ||
| 1905 | Fsignal (Qbeginning_of_buffer, Qnil); | ||
| 1906 | |||
| 1907 | if (pos < ZV) | ||
| 1908 | #if 0 | ||
| 1909 | /* Allow scrolling to an empty screen (end of buffer) | ||
| 1910 | if that is exactly how far we wanted to go. */ | ||
| 1911 | || XINT (nmoved) == n) | ||
| 1912 | #endif | ||
| 1913 | { | ||
| 1914 | set_marker_restricted (w->start, make_number (pos), w->buffer); | ||
| 1915 | w->start_at_line_beg = bolp; | ||
| 1916 | w->update_mode_line = Qt; | ||
| 1917 | XFASTINT (w->last_modified) = 0; | ||
| 1918 | if (pos > opoint) | ||
| 1919 | SET_PT (pos); | ||
| 1920 | if (n < 0) | ||
| 1921 | { | ||
| 1922 | SET_PT (pos); | ||
| 1923 | tem = Fvertical_motion (make_number (ht)); | ||
| 1924 | if (point > opoint || XFASTINT (tem) < ht) | ||
| 1925 | SET_PT (opoint); | ||
| 1926 | else | ||
| 1927 | Fvertical_motion (make_number (-1)); | ||
| 1928 | } | ||
| 1929 | } | ||
| 1930 | else | ||
| 1931 | Fsignal (Qend_of_buffer, Qnil); | ||
| 1932 | } | ||
| 1933 | |||
| 1934 | /* This is the guts of Fscroll_up and Fscroll_down. */ | ||
| 1935 | |||
| 1936 | static void | ||
| 1937 | scroll_command (n, direction) | ||
| 1938 | register Lisp_Object n; | ||
| 1939 | int direction; | ||
| 1940 | { | ||
| 1941 | register int defalt; | ||
| 1942 | int count = specpdl_ptr - specpdl; | ||
| 1943 | |||
| 1944 | /* If selected window's buffer isn't current, make it current for the moment. | ||
| 1945 | But don't screw up if window_scroll gets an error. */ | ||
| 1946 | if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer) | ||
| 1947 | { | ||
| 1948 | record_unwind_protect (save_excursion_restore, save_excursion_save ()); | ||
| 1949 | Fset_buffer (XWINDOW (selected_window)->buffer); | ||
| 1950 | } | ||
| 1951 | |||
| 1952 | defalt = (window_internal_height (XWINDOW (selected_window)) | ||
| 1953 | - next_screen_context_lines); | ||
| 1954 | defalt = direction * (defalt < 1 ? 1 : defalt); | ||
| 1955 | |||
| 1956 | if (NULL (n)) | ||
| 1957 | window_scroll (selected_window, defalt); | ||
| 1958 | else if (EQ (n, Qminus)) | ||
| 1959 | window_scroll (selected_window, - defalt); | ||
| 1960 | else | ||
| 1961 | { | ||
| 1962 | n = Fprefix_numeric_value (n); | ||
| 1963 | window_scroll (selected_window, XINT (n) * direction); | ||
| 1964 | } | ||
| 1965 | |||
| 1966 | unbind_to (count, Qnil); | ||
| 1967 | } | ||
| 1968 | |||
| 1969 | DEFUN ("scroll-up", Fscroll_up, Sscroll_up, 0, 1, "P", | ||
| 1970 | "Scroll text of current window upward ARG lines; or near full screen if no ARG.\n\ | ||
| 1971 | A near full screen is `next-screen-context-lines' less than a full screen.\n\ | ||
| 1972 | When calling from a program, supply a number as argument or nil.") | ||
| 1973 | (n) | ||
| 1974 | Lisp_Object n; | ||
| 1975 | { | ||
| 1976 | scroll_command (n, 1); | ||
| 1977 | return Qnil; | ||
| 1978 | } | ||
| 1979 | |||
| 1980 | DEFUN ("scroll-down", Fscroll_down, Sscroll_down, 0, 1, "P", | ||
| 1981 | "Scroll text of current window downward ARG lines; or near full screen if no ARG.\n\ | ||
| 1982 | A near full screen is `next-screen-context-lines' less than a full screen.\n\ | ||
| 1983 | When calling from a program, supply a number as argument or nil.") | ||
| 1984 | (n) | ||
| 1985 | Lisp_Object n; | ||
| 1986 | { | ||
| 1987 | scroll_command (n, -1); | ||
| 1988 | return Qnil; | ||
| 1989 | } | ||
| 1990 | |||
| 1991 | DEFUN ("scroll-other-window", Fscroll_other_window, Sscroll_other_window, 0, 1, "P", | ||
| 1992 | "Scroll text of next window upward ARG lines; or near full screen if no ARG.\n\ | ||
| 1993 | The next window is the one below the current one; or the one at the top\n\ | ||
| 1994 | if the current one is at the bottom.\n\ | ||
| 1995 | When calling from a program, supply a number as argument or nil.\n\ | ||
| 1996 | \n\ | ||
| 1997 | If in the minibuffer, `minibuf-scroll-window' if non-nil\n\ | ||
| 1998 | specifies the window to scroll.\n\ | ||
| 1999 | If `other-window-scroll-buffer' is non-nil, scroll the window\n\ | ||
| 2000 | showing that buffer, popping the buffer up if necessary.") | ||
| 2001 | (n) | ||
| 2002 | register Lisp_Object n; | ||
| 2003 | { | ||
| 2004 | register Lisp_Object window; | ||
| 2005 | register int ht; | ||
| 2006 | register struct window *w; | ||
| 2007 | register int count = specpdl_ptr - specpdl; | ||
| 2008 | |||
| 2009 | if (MINI_WINDOW_P (XWINDOW (selected_window)) | ||
| 2010 | && !NULL (Vminibuf_scroll_window)) | ||
| 2011 | window = Vminibuf_scroll_window; | ||
| 2012 | /* If buffer is specified, scroll that buffer. */ | ||
| 2013 | else if (!NULL (Vother_window_scroll_buffer)) | ||
| 2014 | { | ||
| 2015 | window = Fget_buffer_window (Vother_window_scroll_buffer, Qnil); | ||
| 2016 | if (NULL (window)) | ||
| 2017 | window = Fdisplay_buffer (Vother_window_scroll_buffer, Qt); | ||
| 2018 | } | ||
| 2019 | else | ||
| 2020 | /* Nothing specified; pick a neighboring window. */ | ||
| 2021 | window = Fnext_window (selected_window, Qnil, Qt); | ||
| 2022 | CHECK_WINDOW (window, 0); | ||
| 2023 | |||
| 2024 | if (EQ (window, selected_window)) | ||
| 2025 | error ("There is no other window"); | ||
| 2026 | |||
| 2027 | w = XWINDOW (window); | ||
| 2028 | ht = window_internal_height (w); | ||
| 2029 | |||
| 2030 | /* Don't screw up if window_scroll gets an error. */ | ||
| 2031 | record_unwind_protect (save_excursion_restore, save_excursion_save ()); | ||
| 2032 | |||
| 2033 | Fset_buffer (w->buffer); | ||
| 2034 | SET_PT (marker_position (w->pointm)); | ||
| 2035 | |||
| 2036 | if (NULL (n)) | ||
| 2037 | window_scroll (window, ht - next_screen_context_lines); | ||
| 2038 | else if (EQ (n, Qminus)) | ||
| 2039 | window_scroll (window, next_screen_context_lines - ht); | ||
| 2040 | else | ||
| 2041 | { | ||
| 2042 | if (XTYPE (n) == Lisp_Cons) | ||
| 2043 | n = Fcar (n); | ||
| 2044 | CHECK_NUMBER (n, 0); | ||
| 2045 | window_scroll (window, XINT (n)); | ||
| 2046 | } | ||
| 2047 | |||
| 2048 | Fset_marker (w->pointm, make_number (point), Qnil); | ||
| 2049 | unbind_to (count); | ||
| 2050 | |||
| 2051 | return Qnil; | ||
| 2052 | } | ||
| 2053 | |||
| 2054 | DEFUN ("scroll-left", Fscroll_left, Sscroll_left, 1, 1, "P", | ||
| 2055 | "Scroll selected window display ARG columns left.\n\ | ||
| 2056 | Default for ARG is window width minus 2.") | ||
| 2057 | (arg) | ||
| 2058 | register Lisp_Object arg; | ||
| 2059 | { | ||
| 2060 | |||
| 2061 | if (NULL (arg)) | ||
| 2062 | XFASTINT (arg) = XFASTINT (XWINDOW (selected_window)->width) - 2; | ||
| 2063 | else | ||
| 2064 | arg = Fprefix_numeric_value (arg); | ||
| 2065 | |||
| 2066 | return | ||
| 2067 | Fset_window_hscroll (selected_window, | ||
| 2068 | make_number (XINT (XWINDOW (selected_window)->hscroll) | ||
| 2069 | + XINT (arg))); | ||
| 2070 | } | ||
| 2071 | |||
| 2072 | DEFUN ("scroll-right", Fscroll_right, Sscroll_right, 1, 1, "P", | ||
| 2073 | "Scroll selected window display ARG columns right.\n\ | ||
| 2074 | Default for ARG is window width minus 2.") | ||
| 2075 | (arg) | ||
| 2076 | register Lisp_Object arg; | ||
| 2077 | { | ||
| 2078 | if (NULL (arg)) | ||
| 2079 | XFASTINT (arg) = XFASTINT (XWINDOW (selected_window)->width) - 2; | ||
| 2080 | else | ||
| 2081 | arg = Fprefix_numeric_value (arg); | ||
| 2082 | |||
| 2083 | return | ||
| 2084 | Fset_window_hscroll (selected_window, | ||
| 2085 | make_number (XINT (XWINDOW (selected_window)->hscroll) | ||
| 2086 | - XINT (arg))); | ||
| 2087 | } | ||
| 2088 | |||
| 2089 | DEFUN ("recenter", Frecenter, Srecenter, 0, 1, "P", | ||
| 2090 | "Center point in window and redisplay screen. With ARG, put point on line ARG.\n\ | ||
| 2091 | The desired position of point is always relative to the current window.\n\ | ||
| 2092 | Just C-u as prefix means put point in the center of the screen.\n\ | ||
| 2093 | No arg (i.e., it is nil) erases the entire screen and then\n\ | ||
| 2094 | redraws with point in the center.") | ||
| 2095 | (n) | ||
| 2096 | register Lisp_Object n; | ||
| 2097 | { | ||
| 2098 | register struct window *w = XWINDOW (selected_window); | ||
| 2099 | register int ht = window_internal_height (w); | ||
| 2100 | register int opoint = point; | ||
| 2101 | |||
| 2102 | if (NULL (n)) | ||
| 2103 | { | ||
| 2104 | extern int screen_garbaged; | ||
| 2105 | |||
| 2106 | SET_SCREEN_GARBAGED (XSCREEN (WINDOW_SCREEN (w))); | ||
| 2107 | XFASTINT (n) = ht / 2; | ||
| 2108 | } | ||
| 2109 | else if (XTYPE (n) == Lisp_Cons) /* Just C-u. */ | ||
| 2110 | { | ||
| 2111 | XFASTINT (n) = ht / 2; | ||
| 2112 | } | ||
| 2113 | else | ||
| 2114 | { | ||
| 2115 | n = Fprefix_numeric_value (n); | ||
| 2116 | CHECK_NUMBER (n, 0); | ||
| 2117 | } | ||
| 2118 | |||
| 2119 | if (XINT (n) < 0) | ||
| 2120 | XSETINT (n, XINT (n) + ht); | ||
| 2121 | |||
| 2122 | XSETINT (n, - XINT (n)); | ||
| 2123 | |||
| 2124 | Fvertical_motion (n); | ||
| 2125 | Fset_marker (w->start, make_number (point), w->buffer); | ||
| 2126 | w->start_at_line_beg = Fbolp (); | ||
| 2127 | |||
| 2128 | SET_PT (opoint); | ||
| 2129 | w->force_start = Qt; | ||
| 2130 | |||
| 2131 | return Qnil; | ||
| 2132 | } | ||
| 2133 | |||
| 2134 | DEFUN ("move-to-window-line", Fmove_to_window_line, Smove_to_window_line, | ||
| 2135 | 1, 1, "P", | ||
| 2136 | "Position point relative to window.\n\ | ||
| 2137 | With no argument, position text at center of window.\n\ | ||
| 2138 | An argument specifies screen line; zero means top of window,\n\ | ||
| 2139 | negative means relative to bottom of window.") | ||
| 2140 | (arg) | ||
| 2141 | register Lisp_Object arg; | ||
| 2142 | { | ||
| 2143 | register struct window *w = XWINDOW (selected_window); | ||
| 2144 | register int height = window_internal_height (w); | ||
| 2145 | register int start; | ||
| 2146 | |||
| 2147 | if (NULL (arg)) | ||
| 2148 | XFASTINT (arg) = height / 2; | ||
| 2149 | else | ||
| 2150 | { | ||
| 2151 | arg = Fprefix_numeric_value (arg); | ||
| 2152 | if (XINT (arg) < 0) | ||
| 2153 | XSETINT (arg, XINT (arg) + height); | ||
| 2154 | } | ||
| 2155 | |||
| 2156 | start = marker_position (w->start); | ||
| 2157 | if (start < BEGV || start > ZV) | ||
| 2158 | { | ||
| 2159 | Fvertical_motion (make_number (- height / 2)); | ||
| 2160 | Fset_marker (w->start, make_number (point), w->buffer); | ||
| 2161 | w->start_at_line_beg = Fbolp (); | ||
| 2162 | w->force_start = Qt; | ||
| 2163 | } | ||
| 2164 | else | ||
| 2165 | SET_PT (start); | ||
| 2166 | |||
| 2167 | return Fvertical_motion (arg); | ||
| 2168 | } | ||
| 2169 | |||
| 2170 | struct save_window_data | ||
| 2171 | { | ||
| 2172 | int size_from_Lisp_Vector_struct; | ||
| 2173 | struct Lisp_Vector *next_from_Lisp_Vector_struct; | ||
| 2174 | Lisp_Object screen_width, screen_height; | ||
| 2175 | Lisp_Object current_window; | ||
| 2176 | Lisp_Object current_buffer; | ||
| 2177 | Lisp_Object minibuf_scroll_window; | ||
| 2178 | Lisp_Object root_window; | ||
| 2179 | /* A vector, interpreted as a struct saved_window */ | ||
| 2180 | Lisp_Object saved_windows; | ||
| 2181 | }; | ||
| 2182 | #define SAVE_WINDOW_DATA_SIZE 7 /* Arg to Fmake_vector */ | ||
| 2183 | |||
| 2184 | /* This is saved as a Lisp_Vector */ | ||
| 2185 | struct saved_window | ||
| 2186 | { | ||
| 2187 | /* these first two must agree with struct Lisp_Vector in lisp.h */ | ||
| 2188 | int size_from_Lisp_Vector_struct; | ||
| 2189 | struct Lisp_Vector *next_from_Lisp_Vector_struct; | ||
| 2190 | |||
| 2191 | Lisp_Object window; | ||
| 2192 | Lisp_Object buffer, start, pointm, mark; | ||
| 2193 | Lisp_Object left, top, width, height, hscroll; | ||
| 2194 | Lisp_Object parent, prev; | ||
| 2195 | Lisp_Object start_at_line_beg; | ||
| 2196 | Lisp_Object display_table; | ||
| 2197 | }; | ||
| 2198 | #define SAVED_WINDOW_VECTOR_SIZE 14 /* Arg to Fmake_vector */ | ||
| 2199 | |||
| 2200 | #define SAVED_WINDOW_N(swv,n) \ | ||
| 2201 | ((struct saved_window *) (XVECTOR ((swv)->contents[(n)]))) | ||
| 2202 | |||
| 2203 | DEFUN ("window-configuration-p", Fwindow_configuration_p, Swindow_configuration_p, 1, 1, 0, | ||
| 2204 | "T if OBJECT is a window-configration object.") | ||
| 2205 | (obj) | ||
| 2206 | Lisp_Object obj; | ||
| 2207 | { | ||
| 2208 | if (XTYPE (obj) == Lisp_Window_Configuration) | ||
| 2209 | return Qt; | ||
| 2210 | return Qnil; | ||
| 2211 | } | ||
| 2212 | |||
| 2213 | |||
| 2214 | DEFUN ("set-window-configuration", | ||
| 2215 | Fset_window_configuration, Sset_window_configuration, | ||
| 2216 | 1, 1, 0, | ||
| 2217 | "Set the configuration of windows and buffers as specified by CONFIGURATION.\n\ | ||
| 2218 | CONFIGURATION must be a value previously returned\n\ | ||
| 2219 | by `current-window-configuration' (which see).") | ||
| 2220 | (arg) | ||
| 2221 | Lisp_Object arg; | ||
| 2222 | { | ||
| 2223 | register struct window *w; | ||
| 2224 | register struct save_window_data *data; | ||
| 2225 | struct Lisp_Vector *saved_windows; | ||
| 2226 | register struct saved_window *p; | ||
| 2227 | register Lisp_Object tem; | ||
| 2228 | Lisp_Object new_current_buffer; | ||
| 2229 | int k; | ||
| 2230 | SCREEN_PTR s, screen_to_select; | ||
| 2231 | |||
| 2232 | while (XTYPE (arg) != Lisp_Window_Configuration) | ||
| 2233 | { | ||
| 2234 | arg = wrong_type_argument (intern ("window-configuration-p"), arg); | ||
| 2235 | } | ||
| 2236 | |||
| 2237 | data = (struct save_window_data *) XVECTOR (arg); | ||
| 2238 | saved_windows = XVECTOR (data->saved_windows); | ||
| 2239 | |||
| 2240 | s = XSCREEN (XWINDOW (SAVED_WINDOW_N (saved_windows, 0)->window)->screen); | ||
| 2241 | |||
| 2242 | if (XFASTINT (data->screen_height) != SCREEN_HEIGHT (s) | ||
| 2243 | || XFASTINT (data->screen_width) != SCREEN_WIDTH (s)) | ||
| 2244 | { | ||
| 2245 | /* Presumably something clever could be done. | ||
| 2246 | However, it doesn't seem worth the effort */ | ||
| 2247 | error ("Screen size %dx%d in saved window configuration mismatches screen.", | ||
| 2248 | XFASTINT (data->screen_height), | ||
| 2249 | XFASTINT (data->screen_width)); | ||
| 2250 | } | ||
| 2251 | |||
| 2252 | windows_or_buffers_changed++; | ||
| 2253 | new_current_buffer = data->current_buffer; | ||
| 2254 | if (NULL (XBUFFER (new_current_buffer)->name)) | ||
| 2255 | new_current_buffer = Qnil; | ||
| 2256 | |||
| 2257 | /* Mark all windows now on screen as "deleted". | ||
| 2258 | Restoring the new configuration "undeletes" any that are in it. */ | ||
| 2259 | |||
| 2260 | delete_all_subwindows (XWINDOW (s->root_window)); | ||
| 2261 | #if 0 | ||
| 2262 | /* This loses when the minibuf screen is not s. */ | ||
| 2263 | delete_all_subwindows (XWINDOW (XWINDOW (minibuf_window)->prev)); | ||
| 2264 | #endif | ||
| 2265 | |||
| 2266 | for (k = 0; k < saved_windows->size; k++) | ||
| 2267 | { | ||
| 2268 | p = SAVED_WINDOW_N (saved_windows, k); | ||
| 2269 | w = XWINDOW (p->window); | ||
| 2270 | w->next = Qnil; | ||
| 2271 | |||
| 2272 | if (!NULL (p->parent)) | ||
| 2273 | w->parent = SAVED_WINDOW_N (saved_windows, XFASTINT (p->parent))->window; | ||
| 2274 | else | ||
| 2275 | w->parent = Qnil; | ||
| 2276 | |||
| 2277 | if (!NULL (p->prev)) | ||
| 2278 | { | ||
| 2279 | w->prev = SAVED_WINDOW_N (saved_windows, XFASTINT (p->prev))->window; | ||
| 2280 | #ifdef MULTI_SCREEN | ||
| 2281 | /* This is true for a minibuffer-only screen. */ | ||
| 2282 | if (w->mini_p && EQ (w->prev, p->window)) | ||
| 2283 | w->next = Qnil; | ||
| 2284 | else | ||
| 2285 | #endif /* MULTI_SCREEN */ | ||
| 2286 | XWINDOW (w->prev)->next = p->window; | ||
| 2287 | } | ||
| 2288 | else | ||
| 2289 | { | ||
| 2290 | w->prev = Qnil; | ||
| 2291 | if (!NULL (w->parent)) | ||
| 2292 | { | ||
| 2293 | if (EQ (p->width, XWINDOW (w->parent)->width)) | ||
| 2294 | { | ||
| 2295 | XWINDOW (w->parent)->vchild = p->window; | ||
| 2296 | XWINDOW (w->parent)->hchild = Qnil; | ||
| 2297 | } | ||
| 2298 | else | ||
| 2299 | { | ||
| 2300 | XWINDOW (w->parent)->hchild = p->window; | ||
| 2301 | XWINDOW (w->parent)->vchild = Qnil; | ||
| 2302 | } | ||
| 2303 | } | ||
| 2304 | } | ||
| 2305 | w->left = p->left; | ||
| 2306 | w->top = p->top; | ||
| 2307 | w->width = p->width; | ||
| 2308 | w->height = p->height; | ||
| 2309 | w->hscroll = p->hscroll; | ||
| 2310 | w->display_table = p->display_table; | ||
| 2311 | XFASTINT (w->last_modified) = 0; | ||
| 2312 | |||
| 2313 | /* Reinstall the saved buffer and pointers into it. */ | ||
| 2314 | if (NULL (p->buffer)) | ||
| 2315 | w->buffer = p->buffer; | ||
| 2316 | else | ||
| 2317 | { | ||
| 2318 | if (!NULL (XBUFFER (p->buffer)->name)) | ||
| 2319 | /* If saved buffer is alive, install it. */ | ||
| 2320 | { | ||
| 2321 | w->buffer = p->buffer; | ||
| 2322 | w->start_at_line_beg = p->start_at_line_beg; | ||
| 2323 | set_marker_restricted (w->start, Fmarker_position (p->start), w->buffer); | ||
| 2324 | set_marker_restricted (w->pointm, Fmarker_position (p->pointm), w->buffer); | ||
| 2325 | Fset_marker (XBUFFER (w->buffer)->mark, | ||
| 2326 | Fmarker_position (p->mark), w->buffer); | ||
| 2327 | |||
| 2328 | if (!EQ (p->buffer, new_current_buffer) && | ||
| 2329 | XBUFFER (p->buffer) == current_buffer) | ||
| 2330 | Fgoto_char (w->pointm); | ||
| 2331 | } | ||
| 2332 | else if (NULL (XBUFFER (w->buffer)->name)) | ||
| 2333 | /* Else if window's old buffer is dead too, get a live one. */ | ||
| 2334 | { | ||
| 2335 | w->buffer = Fcdr (Fcar (Vbuffer_alist)); | ||
| 2336 | /* This will set the markers to beginning of visible range. */ | ||
| 2337 | set_marker_restricted (w->start, make_number (0), w->buffer); | ||
| 2338 | set_marker_restricted (w->pointm, make_number (0), w->buffer); | ||
| 2339 | w->start_at_line_beg = Qt; | ||
| 2340 | } | ||
| 2341 | else | ||
| 2342 | /* Keeping window's old buffer; make sure the markers are real. */ | ||
| 2343 | /* Else if window's old buffer is dead too, get a live one. */ | ||
| 2344 | { | ||
| 2345 | /* Set window markers at start of visible range. */ | ||
| 2346 | if (XMARKER (w->start)->buffer == 0) | ||
| 2347 | set_marker_restricted (w->start, make_number (0), w->buffer); | ||
| 2348 | if (XMARKER (w->pointm)->buffer == 0) | ||
| 2349 | set_marker_restricted (w->pointm, | ||
| 2350 | make_number (BUF_PT (XBUFFER (w->buffer))), | ||
| 2351 | w->buffer); | ||
| 2352 | w->start_at_line_beg = Qt; | ||
| 2353 | } | ||
| 2354 | } | ||
| 2355 | } | ||
| 2356 | |||
| 2357 | SCREEN_ROOT_WINDOW (s) = data->root_window; | ||
| 2358 | |||
| 2359 | #ifdef MULTI_SCREEN | ||
| 2360 | if (s != selected_screen && ! SCREEN_IS_TERMCAP (s)) | ||
| 2361 | Fselect_screen (WINDOW_SCREEN (XWINDOW (data->root_window)), Qnil); | ||
| 2362 | #endif | ||
| 2363 | |||
| 2364 | if (s == selected_screen) | ||
| 2365 | { | ||
| 2366 | Fselect_window (data->current_window); | ||
| 2367 | if (!NULL (new_current_buffer)) | ||
| 2368 | Fset_buffer (new_current_buffer); | ||
| 2369 | else | ||
| 2370 | Fset_buffer (XWINDOW (selected_window)->buffer); | ||
| 2371 | } | ||
| 2372 | |||
| 2373 | Vminibuf_scroll_window = data->minibuf_scroll_window; | ||
| 2374 | return (Qnil); | ||
| 2375 | } | ||
| 2376 | |||
| 2377 | /* Mark all windows now on screen as deleted | ||
| 2378 | by setting their buffers to nil. */ | ||
| 2379 | |||
| 2380 | static void | ||
| 2381 | delete_all_subwindows (w) | ||
| 2382 | register struct window *w; | ||
| 2383 | { | ||
| 2384 | register int count = 1; | ||
| 2385 | w->buffer = Qnil; | ||
| 2386 | if (!NULL (w->next)) | ||
| 2387 | delete_all_subwindows (XWINDOW (w->next)); | ||
| 2388 | if (!NULL (w->vchild)) | ||
| 2389 | delete_all_subwindows (XWINDOW (w->vchild)); | ||
| 2390 | if (!NULL (w->hchild)) | ||
| 2391 | delete_all_subwindows (XWINDOW (w->hchild)); | ||
| 2392 | } | ||
| 2393 | |||
| 2394 | static int | ||
| 2395 | count_windows (window) | ||
| 2396 | register struct window *window; | ||
| 2397 | { | ||
| 2398 | register int count = 1; | ||
| 2399 | if (!NULL (window->next)) | ||
| 2400 | count += count_windows (XWINDOW (window->next)); | ||
| 2401 | if (!NULL (window->vchild)) | ||
| 2402 | count += count_windows (XWINDOW (window->vchild)); | ||
| 2403 | if (!NULL (window->hchild)) | ||
| 2404 | count += count_windows (XWINDOW (window->hchild)); | ||
| 2405 | return count; | ||
| 2406 | } | ||
| 2407 | |||
| 2408 | static int | ||
| 2409 | save_window_save (window, vector, i) | ||
| 2410 | Lisp_Object window; | ||
| 2411 | struct Lisp_Vector *vector; | ||
| 2412 | int i; | ||
| 2413 | { | ||
| 2414 | register struct saved_window *p; | ||
| 2415 | register struct window *w; | ||
| 2416 | register Lisp_Object tem; | ||
| 2417 | |||
| 2418 | for (;!NULL (window); window = w->next) | ||
| 2419 | { | ||
| 2420 | p = SAVED_WINDOW_N (vector, i); | ||
| 2421 | w = XWINDOW (window); | ||
| 2422 | |||
| 2423 | XFASTINT (w->temslot) = i++; | ||
| 2424 | p->window = window; | ||
| 2425 | p->buffer = w->buffer; | ||
| 2426 | p->left = w->left; | ||
| 2427 | p->top = w->top; | ||
| 2428 | p->width = w->width; | ||
| 2429 | p->height = w->height; | ||
| 2430 | p->hscroll = w->hscroll; | ||
| 2431 | p->display_table = w->display_table; | ||
| 2432 | if (!NULL (w->buffer)) | ||
| 2433 | { | ||
| 2434 | /* Save w's value of point in the window configuration. | ||
| 2435 | If w is the selected window, then get the value of point | ||
| 2436 | from the buffer; pointm is garbage in the selected window. */ | ||
| 2437 | if (EQ (window, selected_window)) | ||
| 2438 | { | ||
| 2439 | p->pointm = Fmake_marker (); | ||
| 2440 | Fset_marker (p->pointm, BUF_PT (XBUFFER (w->buffer)), | ||
| 2441 | w->buffer); | ||
| 2442 | } | ||
| 2443 | else | ||
| 2444 | p->pointm = Fcopy_marker (w->pointm); | ||
| 2445 | |||
| 2446 | p->start = Fcopy_marker (w->start); | ||
| 2447 | p->start_at_line_beg = w->start_at_line_beg; | ||
| 2448 | |||
| 2449 | tem = XBUFFER (w->buffer)->mark; | ||
| 2450 | p->mark = Fcopy_marker (tem); | ||
| 2451 | } | ||
| 2452 | else | ||
| 2453 | { | ||
| 2454 | p->pointm = Qnil; | ||
| 2455 | p->start = Qnil; | ||
| 2456 | p->mark = Qnil; | ||
| 2457 | p->start_at_line_beg = Qnil; | ||
| 2458 | } | ||
| 2459 | |||
| 2460 | if (NULL (w->parent)) | ||
| 2461 | p->parent = Qnil; | ||
| 2462 | else | ||
| 2463 | p->parent = XWINDOW (w->parent)->temslot; | ||
| 2464 | |||
| 2465 | if (NULL (w->prev)) | ||
| 2466 | p->prev = Qnil; | ||
| 2467 | else | ||
| 2468 | p->prev = XWINDOW (w->prev)->temslot; | ||
| 2469 | |||
| 2470 | if (!NULL (w->vchild)) | ||
| 2471 | i = save_window_save (w->vchild, vector, i); | ||
| 2472 | if (!NULL (w->hchild)) | ||
| 2473 | i = save_window_save (w->hchild, vector, i); | ||
| 2474 | } | ||
| 2475 | |||
| 2476 | return i; | ||
| 2477 | } | ||
| 2478 | |||
| 2479 | DEFUN ("current-window-configuration", | ||
| 2480 | Fcurrent_window_configuration, Scurrent_window_configuration, 0, 0, 0, | ||
| 2481 | "Return an object representing Emacs' current window configuration.\n\ | ||
| 2482 | This describes the number of windows, their sizes and current buffers,\n\ | ||
| 2483 | and for each displayed buffer, where display starts, and the positions of\n\ | ||
| 2484 | point and mark. An exception is made for point in the current buffer:\n\ | ||
| 2485 | its value is -not- saved.") | ||
| 2486 | () | ||
| 2487 | { | ||
| 2488 | register Lisp_Object tem; | ||
| 2489 | register int n_windows; | ||
| 2490 | register struct save_window_data *data; | ||
| 2491 | register int i; | ||
| 2492 | |||
| 2493 | n_windows = count_windows (XWINDOW (SCREEN_ROOT_WINDOW (selected_screen))); | ||
| 2494 | data = (struct save_window_data *) | ||
| 2495 | XVECTOR (Fmake_vector (make_number (SAVE_WINDOW_DATA_SIZE), | ||
| 2496 | Qnil)); | ||
| 2497 | XFASTINT (data->screen_width) = SCREEN_WIDTH (selected_screen); | ||
| 2498 | XFASTINT (data->screen_height) = SCREEN_HEIGHT (selected_screen); | ||
| 2499 | data->current_window = selected_window; | ||
| 2500 | XSET (data->current_buffer, Lisp_Buffer, current_buffer); | ||
| 2501 | data->minibuf_scroll_window = Vminibuf_scroll_window; | ||
| 2502 | data->root_window = SCREEN_ROOT_WINDOW (selected_screen); | ||
| 2503 | tem = Fmake_vector (make_number (n_windows), Qnil); | ||
| 2504 | data->saved_windows = tem; | ||
| 2505 | for (i = 0; i < n_windows; i++) | ||
| 2506 | XVECTOR (tem)->contents[i] | ||
| 2507 | = Fmake_vector (make_number (SAVED_WINDOW_VECTOR_SIZE), Qnil); | ||
| 2508 | save_window_save (SCREEN_ROOT_WINDOW (selected_screen), | ||
| 2509 | XVECTOR (tem), 0); | ||
| 2510 | XSET (tem, Lisp_Window_Configuration, data); | ||
| 2511 | return (tem); | ||
| 2512 | } | ||
| 2513 | |||
| 2514 | DEFUN ("save-window-excursion", Fsave_window_excursion, Ssave_window_excursion, | ||
| 2515 | 0, UNEVALLED, 0, | ||
| 2516 | "Execute body, preserving window sizes and contents.\n\ | ||
| 2517 | Restores which buffer appears in which window, where display starts,\n\ | ||
| 2518 | as well as the current buffer.\n\ | ||
| 2519 | Does not restore the value of point in current buffer.") | ||
| 2520 | (args) | ||
| 2521 | Lisp_Object args; | ||
| 2522 | { | ||
| 2523 | register Lisp_Object val; | ||
| 2524 | register int count = specpdl_ptr - specpdl; | ||
| 2525 | |||
| 2526 | record_unwind_protect (Fset_window_configuration, | ||
| 2527 | Fcurrent_window_configuration ()); | ||
| 2528 | val = Fprogn (args); | ||
| 2529 | return unbind_to (count, val); | ||
| 2530 | } | ||
| 2531 | |||
| 2532 | init_window_once () | ||
| 2533 | { | ||
| 2534 | #ifdef MULTI_SCREEN | ||
| 2535 | selected_screen = make_terminal_screen (); | ||
| 2536 | minibuf_window = selected_screen->minibuffer_window; | ||
| 2537 | selected_window = selected_screen->selected_window; | ||
| 2538 | #else /* not MULTI_SCREEN */ | ||
| 2539 | extern Lisp_Object get_minibuffer (); | ||
| 2540 | |||
| 2541 | root_window = make_window (0); | ||
| 2542 | minibuf_window = make_window (0); | ||
| 2543 | |||
| 2544 | XWINDOW (root_window)->next = minibuf_window; | ||
| 2545 | XWINDOW (minibuf_window)->prev = root_window; | ||
| 2546 | |||
| 2547 | /* These values 9 and 10 are arbitrary, | ||
| 2548 | just so that there is "something there." | ||
| 2549 | Correct values are put in in init_xdisp */ | ||
| 2550 | |||
| 2551 | XFASTINT (XWINDOW (root_window)->width) = 10; | ||
| 2552 | XFASTINT (XWINDOW (minibuf_window)->width) = 10; | ||
| 2553 | |||
| 2554 | XFASTINT (XWINDOW (root_window)->height) = 9; | ||
| 2555 | XFASTINT (XWINDOW (minibuf_window)->top) = 9; | ||
| 2556 | XFASTINT (XWINDOW (minibuf_window)->height) = 1; | ||
| 2557 | |||
| 2558 | /* Prevent error in Fset_window_buffer. */ | ||
| 2559 | XWINDOW (root_window)->buffer = Qt; | ||
| 2560 | XWINDOW (minibuf_window)->buffer = Qt; | ||
| 2561 | |||
| 2562 | /* Now set them up for real. */ | ||
| 2563 | Fset_window_buffer (root_window, Fcurrent_buffer ()); | ||
| 2564 | Fset_window_buffer (minibuf_window, get_minibuffer (0)); | ||
| 2565 | |||
| 2566 | selected_window = root_window; | ||
| 2567 | #endif /* not MULTI_SCREEN */ | ||
| 2568 | } | ||
| 2569 | |||
| 2570 | syms_of_window () | ||
| 2571 | { | ||
| 2572 | Qwindowp = intern ("windowp"); | ||
| 2573 | staticpro (&Qwindowp); | ||
| 2574 | |||
| 2575 | /* Make sure all windows get marked */ | ||
| 2576 | staticpro (&minibuf_window); | ||
| 2577 | |||
| 2578 | DEFVAR_LISP ("temp-buffer-show-function", &Vtemp_buffer_show_function, | ||
| 2579 | "Non-nil means call as function to display a help buffer.\n\ | ||
| 2580 | Used by `with-output-to-temp-buffer'."); | ||
| 2581 | Vtemp_buffer_show_function = Qnil; | ||
| 2582 | |||
| 2583 | DEFVAR_LISP ("display-buffer-function", &Vdisplay_buffer_function, | ||
| 2584 | "If non-nil, function to call to handle `display-buffer'.\n\ | ||
| 2585 | It will receive two args, the buffer and a flag which if non-nil means\n\ | ||
| 2586 | that the currently selected window is not acceptable.\n\ | ||
| 2587 | Commands such as `switch-to-buffer-other-window' and `find-file-other-window'\n\ | ||
| 2588 | work using this function."); | ||
| 2589 | Vdisplay_buffer_function = Qnil; | ||
| 2590 | |||
| 2591 | DEFVAR_LISP ("mouse-window", &Vmouse_window, | ||
| 2592 | "Window that the last mouse click occurred on."); | ||
| 2593 | Vmouse_window = Qnil; | ||
| 2594 | |||
| 2595 | DEFVAR_LISP ("mouse-event", &Vmouse_event, | ||
| 2596 | "The last mouse-event object. A list of four elements:\n\ | ||
| 2597 | ((X-POS Y-POS) WINDOW SCREEN-PART KEYSEQ).\n\ | ||
| 2598 | KEYSEQ is a string, the key sequence to be looked up in the mouse maps.\n\ | ||
| 2599 | WINDOW is the window that the click applies do.\n\ | ||
| 2600 | If SCREEN-PART is non-nil, the event was on a scrollbar;\n\ | ||
| 2601 | then Y-POS is really the total length of the scrollbar, while X-POS is\n\ | ||
| 2602 | the relative position of the scrollbar's value within that total length.\n\ | ||
| 2603 | SCREEN-PART is one of the following symbols:\n\ | ||
| 2604 | `vertical-scrollbar', `vertical-slider',\n\ | ||
| 2605 | `vertical-thumbup', `vertical-thumbdown',\n\ | ||
| 2606 | `horizontal-scrollbar', `horizontal-slider',\n\ | ||
| 2607 | `horizontal-thumbleft', `horizontal-thumbright'"); | ||
| 2608 | Vmouse_event = Qnil; | ||
| 2609 | |||
| 2610 | DEFVAR_LISP ("minibuffer-scroll-window", &Vminibuf_scroll_window, | ||
| 2611 | "Non-nil means it is the window that C-M-v in minibuffer should scroll."); | ||
| 2612 | Vminibuf_scroll_window = Qnil; | ||
| 2613 | |||
| 2614 | DEFVAR_LISP ("other-window-scroll-buffer", &Vother_window_scroll_buffer, | ||
| 2615 | "If non-nil, this is a buffer and \\[scroll-other-window] should scroll its window."); | ||
| 2616 | Vother_window_scroll_buffer = Qnil; | ||
| 2617 | |||
| 2618 | #ifdef MULTI_SCREEN | ||
| 2619 | DEFVAR_BOOL ("auto-new-screen", &auto_new_screen, | ||
| 2620 | "*Non-nil means `display-buffer' should make a separate X-window."); | ||
| 2621 | auto_new_screen = 0; | ||
| 2622 | |||
| 2623 | DEFVAR_LISP ("auto-new-screen-function", &Vauto_new_screen_function, | ||
| 2624 | "*If non-nil, function to call to handle automatic new screen creation.\n\ | ||
| 2625 | It is called with no arguments and should return a newly created screen.\n\ | ||
| 2626 | nil means call `x-create-screen' with a nil argument.\n\ | ||
| 2627 | \n\ | ||
| 2628 | A typical value might be `(lambda () (x-create-screen auto-screen-parms))'\n\ | ||
| 2629 | where `auto-screen-parms' would hold the default screen parameters."); | ||
| 2630 | Vauto_new_screen_function = Qnil; | ||
| 2631 | #endif | ||
| 2632 | |||
| 2633 | DEFVAR_BOOL ("pop-up-windows", &pop_up_windows, | ||
| 2634 | "*Non-nil means display-buffer should make new windows."); | ||
| 2635 | pop_up_windows = 1; | ||
| 2636 | |||
| 2637 | DEFVAR_INT ("next-screen-context-lines", &next_screen_context_lines, | ||
| 2638 | "*Number of lines of continuity when scrolling by screenfuls."); | ||
| 2639 | next_screen_context_lines = 2; | ||
| 2640 | |||
| 2641 | DEFVAR_INT ("split-height-threshold", &split_height_threshold, | ||
| 2642 | "*display-buffer would prefer to split the largest window if this large.\n\ | ||
| 2643 | If there is only one window, it is split regardless of this value."); | ||
| 2644 | split_height_threshold = 500; | ||
| 2645 | |||
| 2646 | DEFVAR_INT ("window-min-height", &window_min_height, | ||
| 2647 | "*Delete any window less than this tall (including its mode line)."); | ||
| 2648 | window_min_height = 4; | ||
| 2649 | |||
| 2650 | DEFVAR_INT ("window-min-width", &window_min_width, | ||
| 2651 | "*Delete any window less than this wide."); | ||
| 2652 | window_min_width = 10; | ||
| 2653 | |||
| 2654 | defsubr (&Sselected_window); | ||
| 2655 | defsubr (&Sminibuffer_window); | ||
| 2656 | defsubr (&Swindow_minibuffer_p); | ||
| 2657 | defsubr (&Swindowp); | ||
| 2658 | defsubr (&Spos_visible_in_window_p); | ||
| 2659 | defsubr (&Swindow_buffer); | ||
| 2660 | defsubr (&Swindow_height); | ||
| 2661 | defsubr (&Swindow_width); | ||
| 2662 | defsubr (&Swindow_hscroll); | ||
| 2663 | defsubr (&Sset_window_hscroll); | ||
| 2664 | defsubr (&Swindow_edges); | ||
| 2665 | defsubr (&Slocate_window_from_coordinates); | ||
| 2666 | defsubr (&Swindow_point); | ||
| 2667 | defsubr (&Swindow_start); | ||
| 2668 | defsubr (&Swindow_end); | ||
| 2669 | defsubr (&Sset_window_point); | ||
| 2670 | defsubr (&Sset_window_start); | ||
| 2671 | defsubr (&Swindow_dedicated_p); | ||
| 2672 | defsubr (&Sset_window_buffer_dedicated); | ||
| 2673 | defsubr (&Swindow_display_table); | ||
| 2674 | defsubr (&Sset_window_display_table); | ||
| 2675 | defsubr (&Snext_window); | ||
| 2676 | defsubr (&Sprevious_window); | ||
| 2677 | defsubr (&Sother_window); | ||
| 2678 | defsubr (&Sget_lru_window); | ||
| 2679 | defsubr (&Sget_largest_window); | ||
| 2680 | defsubr (&Sget_buffer_window); | ||
| 2681 | defsubr (&Sdelete_other_windows); | ||
| 2682 | defsubr (&Sdelete_windows_on); | ||
| 2683 | defsubr (&Sreplace_buffer_in_windows); | ||
| 2684 | defsubr (&Sdelete_window); | ||
| 2685 | defsubr (&Sset_window_buffer); | ||
| 2686 | defsubr (&Sselect_window); | ||
| 2687 | defsubr (&Sdisplay_buffer); | ||
| 2688 | defsubr (&Ssplit_window); | ||
| 2689 | defsubr (&Senlarge_window); | ||
| 2690 | defsubr (&Sshrink_window); | ||
| 2691 | defsubr (&Sscroll_up); | ||
| 2692 | defsubr (&Sscroll_down); | ||
| 2693 | defsubr (&Sscroll_left); | ||
| 2694 | defsubr (&Sscroll_right); | ||
| 2695 | defsubr (&Sscroll_other_window); | ||
| 2696 | defsubr (&Srecenter); | ||
| 2697 | defsubr (&Smove_to_window_line); | ||
| 2698 | defsubr (&Swindow_configuration_p); | ||
| 2699 | defsubr (&Sset_window_configuration); | ||
| 2700 | defsubr (&Scurrent_window_configuration); | ||
| 2701 | defsubr (&Ssave_window_excursion); | ||
| 2702 | } | ||
| 2703 | |||
| 2704 | keys_of_window () | ||
| 2705 | { | ||
| 2706 | initial_define_key (control_x_map, '1', "delete-other-windows"); | ||
| 2707 | initial_define_key (control_x_map, '2', "split-window"); | ||
| 2708 | initial_define_key (control_x_map, '0', "delete-window"); | ||
| 2709 | initial_define_key (control_x_map, 'o', "other-window"); | ||
| 2710 | initial_define_key (control_x_map, '^', "enlarge-window"); | ||
| 2711 | initial_define_key (control_x_map, '<', "scroll-left"); | ||
| 2712 | initial_define_key (control_x_map, '>', "scroll-right"); | ||
| 2713 | |||
| 2714 | initial_define_key (global_map, Ctl ('V'), "scroll-up"); | ||
| 2715 | initial_define_key (meta_map, Ctl ('V'), "scroll-other-window"); | ||
| 2716 | initial_define_key (meta_map, 'v', "scroll-down"); | ||
| 2717 | |||
| 2718 | initial_define_key (global_map, Ctl('L'), "recenter"); | ||
| 2719 | initial_define_key (meta_map, 'r', "move-to-window-line"); | ||
| 2720 | } | ||