diff options
| author | Martin Rudalics | 2025-10-18 10:33:10 +0200 |
|---|---|---|
| committer | Martin Rudalics | 2025-10-18 10:33:10 +0200 |
| commit | ef2b0325677286373980f7d641576253b4f1cf41 (patch) | |
| tree | b7c9f0c1d75f84a5f740dfe83d145df1cd525dfb /src | |
| parent | 81bc83c1a57999a1ff0584c605e7e13b4a9f7cbb (diff) | |
| download | emacs-ef2b0325677286373980f7d641576253b4f1cf41.tar.gz emacs-ef2b0325677286373980f7d641576253b4f1cf41.zip | |
Add functions 'combine-windows' and 'uncombine-window'
* src/window.c (make_parent_window, Fcombine_windows)
(Funcombine_window): New functions.
(Fsplit_window_internal): Use make_parent_window.
* doc/lispref/windows.texi (Recombining Windows): Describe new
functions 'combine-windows' and 'uncombine-window'.
(Window Configurations): Explain "window clones".
* etc/NEWS: Mention new functions 'combine-windows' and
'uncombine-window'.
Diffstat (limited to 'src')
| -rw-r--r-- | src/window.c | 203 |
1 files changed, 198 insertions, 5 deletions
diff --git a/src/window.c b/src/window.c index dee17ae445a..f19f2041c77 100644 --- a/src/window.c +++ b/src/window.c | |||
| @@ -5133,6 +5133,200 @@ resize_frame_windows (struct frame *f, int size, bool horflag) | |||
| 5133 | } | 5133 | } |
| 5134 | 5134 | ||
| 5135 | 5135 | ||
| 5136 | /** Make parent window on FRAME and return its object. */ | ||
| 5137 | static Lisp_Object | ||
| 5138 | make_parent_window (Lisp_Object frame) | ||
| 5139 | { | ||
| 5140 | Lisp_Object parent; | ||
| 5141 | struct window *p = allocate_window (); | ||
| 5142 | |||
| 5143 | p->sequence_number = ++sequence_number; | ||
| 5144 | wset_frame (p, frame); | ||
| 5145 | XSETWINDOW (parent, p); | ||
| 5146 | |||
| 5147 | return parent; | ||
| 5148 | } | ||
| 5149 | |||
| 5150 | |||
| 5151 | DEFUN ("combine-windows", Fcombine_windows, Scombine_windows, 2, 2, 0, | ||
| 5152 | doc: /* Combine windows from FIRST to LAST. | ||
| 5153 | FIRST and LAST must be valid windows in the same combination, that is, | ||
| 5154 | windows with the same parent window. If neither FIRST has a previous | ||
| 5155 | nor LAST has a next sibling, return that parent window. Otherwise, make | ||
| 5156 | a new parent window whose first child window becomes FIRST and whose | ||
| 5157 | last child window becomes LAST, insert that parent window in the window | ||
| 5158 | tree in lieu of the windows starting with FIRST and ending with LAST and | ||
| 5159 | return the new parent window. */) | ||
| 5160 | (Lisp_Object first, Lisp_Object last) | ||
| 5161 | { | ||
| 5162 | struct window *f = decode_valid_window (first); | ||
| 5163 | struct window *l = decode_valid_window (last); | ||
| 5164 | struct window *w = f; | ||
| 5165 | |||
| 5166 | if (f == l) | ||
| 5167 | /* Don't make a matryoshka window. */ | ||
| 5168 | error ("Invalid window to parentify"); | ||
| 5169 | |||
| 5170 | while (w != l && !NILP (w->next)) | ||
| 5171 | w = XWINDOW (w->next); | ||
| 5172 | |||
| 5173 | if (w != l) | ||
| 5174 | { | ||
| 5175 | w = l; | ||
| 5176 | |||
| 5177 | while (w != f && !NILP (w->next)) | ||
| 5178 | w = XWINDOW (w->next); | ||
| 5179 | |||
| 5180 | if (w == f) | ||
| 5181 | /* Invert FIRST and LAST. */ | ||
| 5182 | { | ||
| 5183 | f = l; | ||
| 5184 | l = w; | ||
| 5185 | XSETWINDOW (first, f); | ||
| 5186 | XSETWINDOW (last, l); | ||
| 5187 | } | ||
| 5188 | else | ||
| 5189 | error ("Invalid window to parentify"); | ||
| 5190 | } | ||
| 5191 | |||
| 5192 | if (NILP (f->prev) && NILP (l->next)) | ||
| 5193 | return f->parent; | ||
| 5194 | |||
| 5195 | /* Make new parent window PARENT. */ | ||
| 5196 | Lisp_Object parent = make_parent_window (f->frame); | ||
| 5197 | struct window *p = XWINDOW (parent); | ||
| 5198 | double normal_size = 0.0; | ||
| 5199 | |||
| 5200 | /* Splice in PARENT into the window tree. */ | ||
| 5201 | p->parent = f->parent; | ||
| 5202 | p->horizontal = XWINDOW (p->parent)->horizontal; | ||
| 5203 | p->contents = first; | ||
| 5204 | |||
| 5205 | if (NILP (f->prev)) | ||
| 5206 | /* FIRST has no previous sibling. */ | ||
| 5207 | XWINDOW (p->parent)->contents = parent; | ||
| 5208 | else | ||
| 5209 | /* FIRST has a previous sibling. */ | ||
| 5210 | { | ||
| 5211 | XWINDOW (f->prev)->next = parent; | ||
| 5212 | p->prev = f->prev; | ||
| 5213 | f->prev = Qnil; | ||
| 5214 | } | ||
| 5215 | |||
| 5216 | if (!NILP (l->next)) | ||
| 5217 | /* LAST has a next sibling. */ | ||
| 5218 | { | ||
| 5219 | XWINDOW (l->next)->prev = parent; | ||
| 5220 | p->next = l->next; | ||
| 5221 | l->next = Qnil; | ||
| 5222 | } | ||
| 5223 | |||
| 5224 | /* Fix parent slots for PARENT's new children. */ | ||
| 5225 | w = f; | ||
| 5226 | |||
| 5227 | while (w) | ||
| 5228 | { | ||
| 5229 | w->parent = parent; | ||
| 5230 | if (w == l) | ||
| 5231 | break; | ||
| 5232 | else | ||
| 5233 | { | ||
| 5234 | if (p->horizontal) | ||
| 5235 | normal_size = normal_size + XFLOAT_DATA (f->normal_cols); | ||
| 5236 | else | ||
| 5237 | normal_size = normal_size + XFLOAT_DATA (f->normal_lines); | ||
| 5238 | |||
| 5239 | w = XWINDOW (w->next); | ||
| 5240 | } | ||
| 5241 | } | ||
| 5242 | |||
| 5243 | /* Set up PARENT's positions and sizes. */ | ||
| 5244 | p->pixel_left = f->pixel_left; | ||
| 5245 | p->left_col = f->left_col; | ||
| 5246 | p->pixel_top = f->pixel_top; | ||
| 5247 | p->top_line = f->top_line; | ||
| 5248 | |||
| 5249 | if (p->horizontal) | ||
| 5250 | { | ||
| 5251 | p->pixel_width = l->pixel_left + l->pixel_width - f->pixel_left; | ||
| 5252 | p->total_cols = l->left_col + l->total_cols - f->left_col; | ||
| 5253 | p->pixel_height = f->pixel_height; | ||
| 5254 | p->total_lines = f->total_lines; | ||
| 5255 | } | ||
| 5256 | else | ||
| 5257 | { | ||
| 5258 | p->pixel_height = l->pixel_top + l->pixel_height - f->pixel_top; | ||
| 5259 | p->total_lines = l->top_line + l->total_lines - f->top_line; | ||
| 5260 | p->pixel_width = f->pixel_width; | ||
| 5261 | p->total_cols = f->total_cols; | ||
| 5262 | } | ||
| 5263 | |||
| 5264 | if (p->horizontal) | ||
| 5265 | { | ||
| 5266 | p->normal_cols = make_float (normal_size); | ||
| 5267 | p->normal_lines = f->normal_lines; | ||
| 5268 | } | ||
| 5269 | else | ||
| 5270 | { | ||
| 5271 | p->normal_cols = f->normal_cols; | ||
| 5272 | p->normal_lines = make_float (normal_size); | ||
| 5273 | } | ||
| 5274 | |||
| 5275 | return parent; | ||
| 5276 | } | ||
| 5277 | |||
| 5278 | DEFUN ("uncombine-window", Funcombine_window, Suncombine_window, 1, 1, 0, | ||
| 5279 | doc: /* Uncombine specified WINDOW. | ||
| 5280 | WINDOW should be an internal window whose parent window is an internal | ||
| 5281 | window of the same type. This means, that WINDOW and its parent should | ||
| 5282 | be either both horizontal or both vertical window combinations. If this | ||
| 5283 | is the case, make the child windows of WINDOW child windows of WINDOW's | ||
| 5284 | parent and return t. Otherwise, leave the current configuration of | ||
| 5285 | WINDOW's frame unchanged and return nil. */) | ||
| 5286 | (Lisp_Object window) | ||
| 5287 | { | ||
| 5288 | struct window *w = decode_valid_window (window); | ||
| 5289 | Lisp_Object parent = w->parent; | ||
| 5290 | |||
| 5291 | if (MINI_WINDOW_P (w)) | ||
| 5292 | error ("Cannot uncombine a mini window"); | ||
| 5293 | |||
| 5294 | if (WINDOW_INTERNAL_P (w) && !NILP (parent) | ||
| 5295 | && w->horizontal == XWINDOW (parent)->horizontal) | ||
| 5296 | { | ||
| 5297 | struct window *p = XWINDOW (w->parent); | ||
| 5298 | /* WINDOW's first child. */ | ||
| 5299 | Lisp_Object first = w->contents; | ||
| 5300 | struct window *f = XWINDOW (first); | ||
| 5301 | /* WINDOW's last child. */ | ||
| 5302 | Lisp_Object last = Qnil; | ||
| 5303 | struct window *l = f; | ||
| 5304 | |||
| 5305 | /* Make WINDOW's parent new parent of WINDOW's children. */ | ||
| 5306 | while (!NILP (l->next)) | ||
| 5307 | { | ||
| 5308 | wset_parent (l, parent); | ||
| 5309 | l = XWINDOW (l->next); | ||
| 5310 | } | ||
| 5311 | wset_parent (l, parent); | ||
| 5312 | XSETWINDOW (last, l); | ||
| 5313 | |||
| 5314 | wset_prev (f, w->prev); | ||
| 5315 | if (NILP (f->prev)) | ||
| 5316 | wset_combination (p, p->horizontal, first); | ||
| 5317 | else | ||
| 5318 | wset_next (XWINDOW (f->prev), first); | ||
| 5319 | |||
| 5320 | wset_next (l, w->next); | ||
| 5321 | if (!NILP (l->next)) | ||
| 5322 | wset_prev (XWINDOW (w->next), last); | ||
| 5323 | |||
| 5324 | return Qt; | ||
| 5325 | } | ||
| 5326 | else | ||
| 5327 | return Qnil; | ||
| 5328 | } | ||
| 5329 | |||
| 5136 | DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 5, 0, | 5330 | DEFUN ("split-window-internal", Fsplit_window_internal, Ssplit_window_internal, 4, 5, 0, |
| 5137 | doc: /* Split window OLD. | 5331 | doc: /* Split window OLD. |
| 5138 | Second argument PIXEL-SIZE specifies the number of pixels of the | 5332 | Second argument PIXEL-SIZE specifies the number of pixels of the |
| @@ -5302,12 +5496,9 @@ set correctly. See the code of `split-window' for how this is done. */) | |||
| 5302 | = horflag ? o->normal_cols : o->normal_lines; | 5496 | = horflag ? o->normal_cols : o->normal_lines; |
| 5303 | 5497 | ||
| 5304 | if (NILP (parent)) | 5498 | if (NILP (parent)) |
| 5305 | /* This is the crux of the old make_parent_window. */ | ||
| 5306 | { | 5499 | { |
| 5307 | p = allocate_window (); | 5500 | parent = make_parent_window (frame); |
| 5308 | XSETWINDOW (parent, p); | 5501 | p = XWINDOW (parent); |
| 5309 | p->sequence_number = ++sequence_number; | ||
| 5310 | wset_frame (p, frame); | ||
| 5311 | } | 5502 | } |
| 5312 | else | 5503 | else |
| 5313 | /* Pacify GCC. */ | 5504 | /* Pacify GCC. */ |
| @@ -9345,6 +9536,8 @@ name to `'ignore'. */); | |||
| 9345 | defsubr (&Sselect_window); | 9536 | defsubr (&Sselect_window); |
| 9346 | defsubr (&Sforce_window_update); | 9537 | defsubr (&Sforce_window_update); |
| 9347 | defsubr (&Ssplit_window_internal); | 9538 | defsubr (&Ssplit_window_internal); |
| 9539 | defsubr (&Scombine_windows); | ||
| 9540 | defsubr (&Suncombine_window); | ||
| 9348 | defsubr (&Sscroll_up); | 9541 | defsubr (&Sscroll_up); |
| 9349 | defsubr (&Sscroll_down); | 9542 | defsubr (&Sscroll_down); |
| 9350 | defsubr (&Sscroll_left); | 9543 | defsubr (&Sscroll_left); |