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