1 /* -*- mode: C; mode: fold; -*- */
2 /* Copyright (c) 1992, 1998, 2000, 2002-2009 John E. Davis
3 * This file is part of JED editor library source.
4 *
5 * You may distribute this file under the terms the GNU General Public
6 * License. See the file COPYING for more information.
7 */
8 #include "config.h"
9 #include "jed-feat.h"
10
11 /*{{{ Include Files */
12
13 #include <stdio.h>
14 #include <string.h>
15
16 #include "buffer.h"
17 #include "window.h"
18 #include "screen.h"
19 #include "misc.h"
20 #include "ledit.h"
21 #include "sysdep.h"
22 #include "display.h"
23 #include "paste.h"
24
25 /*}}}*/
26
27 Window_Type *JMiniWindow;
28 Window_Type *JWindow;
29
30 int Top_Window_SY = 1;
31
alloc_window(int sy,int sx,int rows,int col,int width)32 static Window_Type *alloc_window(int sy, int sx, int rows, int col, int width)
33 {
34 Window_Type *w;
35
36 if (NULL == (w = (Window_Type *) jed_malloc0 (sizeof(Window_Type))))
37 {
38 exit_error("create_window: malloc error.", 0);
39 }
40
41 if (sy < 0) sy = 0;
42 if (sx < 0) sx = 0;
43 w->sx = sx;
44 w->sy = sy;
45 if (rows < 1) rows = 1;
46 w->rows = rows;
47 if (width < 1) width = 1;
48 w->width = width;
49 w->hscroll_column = col;
50
51 return w;
52 }
53
new_window(int sy,int sx,int rows,int col,int width)54 static Window_Type *new_window (int sy, int sx, int rows, int col, int width)
55 {
56 Window_Type *w = alloc_window (sy, sx, rows, col, width);
57
58 if (w == NULL)
59 return w;
60
61 if ((jed_new_window_cb != NULL)
62 && (-1 == (*jed_new_window_cb)(w)))
63 exit_error ("The new_window callback function failed", 0);
64
65 return w;
66 }
67
jed_create_minibuffer_window(void)68 Window_Type *jed_create_minibuffer_window (void)
69 {
70 Window_Type *w;
71 w = alloc_window (Jed_Num_Screen_Rows-1, 0, 1, 1, Jed_Num_Screen_Cols);
72 if (w == NULL)
73 return NULL;
74
75 w->flags |= MINIBUFFER_WINDOW;
76
77 if ((jed_create_mini_window_cb != NULL)
78 && (*jed_create_mini_window_cb)(w))
79 exit_error ("Unable to create a mini-buffer window", 0);
80
81 return w;
82 }
83
free_window(Window_Type * w)84 static void free_window (Window_Type *w)
85 {
86 if (w == NULL)
87 return;
88
89 if (Mini_Info.action_window == w)
90 Mini_Info.action_window = NULL;
91
92 if (jed_free_window_cb != NULL)
93 (*jed_free_window_cb)(w);
94
95 SLfree ((char *) w);
96 }
97
98
window_buffer(Buffer * b)99 void window_buffer(Buffer *b) /*{{{*/
100 {
101 if (JWindow == NULL)
102 {
103 JWindow = new_window (Top_Window_SY, 0,
104 Jed_Num_Screen_Rows - 2 - Top_Window_SY,
105 1, Jed_Num_Screen_Cols);
106 JWindow->next = JWindow;
107 }
108
109 touch_window();
110
111 jed_init_mark_for_buffer (&JWindow->beg, b, 0);
112 jed_init_mark_for_buffer (&JWindow->mark, b, 0);
113 JWindow->hscroll_column = 1;
114 JWindow->buffer = b;
115 JWindow->trashed = 1;
116 }
117
118 /*}}}*/
119
120 #if JED_HAS_SUBPROCESSES
move_window_marks(int all)121 void move_window_marks (int all) /*{{{*/
122 {
123 Window_Type *w = JWindow;
124 if (w == NULL) return;
125 do
126 {
127 if (w->buffer == CBuf)
128 {
129 jed_init_mark (&w->mark, 0);
130 if (all == 0) break;
131 }
132 w = w->next;
133 }
134 while (w != JWindow);
135 }
136
137 /*}}}*/
138 #endif
139
other_window(void)140 int other_window (void) /*{{{*/
141 {
142 switch_to_buffer(JWindow->buffer);
143 jed_init_mark (&JWindow->mark,0);
144 if (JWindow->next == JWindow)
145 return 1;
146
147 if (jed_leave_window_cb != NULL)
148 (void) (*jed_leave_window_cb)(JWindow);
149
150 JWindow = JWindow->next;
151 switch_to_buffer(JWindow->buffer);
152 if (JWindow->mark.line != NULL)
153 (void) jed_goto_mark (&JWindow->mark);
154
155 if (jed_enter_window_cb != NULL)
156 (void) (*jed_enter_window_cb)(JWindow);
157
158 return 1;
159 }
160
161 /*}}}*/
162
split_window(void)163 int split_window (void) /*{{{*/
164 {
165 int n, sy, width, row;
166 Window_Type *w, *neew;
167 /* Line *l, cline; */
168
169 if (JWindow->rows < 5)
170 {
171 msg_error("Window too small.");
172 return(0);
173 }
174
175 switch_to_buffer(JWindow->buffer);
176 n = JWindow->rows / 2;
177 sy = JWindow->sy + n + 1;
178 width = JWindow->width;
179 n = JWindow->rows - n - 1;
180 JWindow->rows = JWindow->rows / 2;
181
182 jed_init_mark (&JWindow->beg, 0);
183
184 w = JWindow->next;
185 JWindow->next = neew = new_window (sy, JWindow->sx, n, JWindow->hscroll_column, width);
186
187 neew->next = w;
188 neew->buffer = CBuf;
189 jed_init_mark (&neew->mark, 0);
190 jed_copy_mark (&neew->beg, &JWindow->beg);
191
192 if (jed_split_window_cb != NULL)
193 {
194 (void) (*jed_split_window_cb)(JWindow, neew);
195 }
196
197 n = JWindow->sy;
198
199 other_window();
200 touch_window();
201
202 if (-1 != (row = jed_find_line_on_screen (CLine, n)))
203 {
204 /* The screen row below (not above) the current window containing
205 * the current line was found. Switch to that buffer to avoid
206 * the cursor jumping. This is not necessary but it has a more
207 * appealing visual effect.
208 */
209 row += 1;
210
211 w = JWindow;
212 do
213 {
214 if ((JWindow->buffer == CBuf) && (JWindow->sy < row)
215 && (JWindow->sy + JWindow->rows >= row)) break;
216 other_window();
217 }
218 while (w != JWindow);
219 }
220 return 1;
221 }
222
223 /*}}}*/
224
one_window(void)225 int one_window (void) /*{{{*/
226 {
227 Window_Type *w, *next, *mini;
228 Buffer *b;
229 mini = NULL;
230 if (IN_MINI_WINDOW) return 0;
231 w = JWindow->next;
232 b = JWindow->buffer;
233 while (w != JWindow)
234 {
235 next = w->next;
236 if (w != JMiniWindow)
237 {
238 if (w->buffer != b) touch_window_hard (w, 0);
239 free_window (w);
240 }
241 else mini = w;
242 w = next;
243 }
244 if (mini == NULL) mini = JWindow;
245 JWindow->next = mini;
246 mini->next = JWindow;
247 JWindow->sy = Top_Window_SY;
248 JWindow->sx = 0;
249 JWindow->width = Jed_Num_Screen_Cols;
250 JWindow->rows = Jed_Num_Screen_Rows - 2 - Top_Window_SY;
251 touch_window();
252 return(1);
253 }
254 /*}}}*/
255
enlarge_window(void)256 int enlarge_window (void) /*{{{*/
257 {
258 Window_Type *w, *w1;
259 int min = 2;
260
261 if (IN_MINI_WINDOW) return 0;
262
263 if (JWindow == JWindow->next) return(0);
264 w = JWindow->next;
265 while(w->rows <= min) w = w->next;
266 if (w == JWindow) return(0);
267
268 if (w->sy < JWindow->sy)
269 {
270 w->rows -= 1;
271 JWindow->rows += 1;
272 do
273 {
274 w = w->next;
275 w->sy -= 1;
276 }
277 while (w != JWindow);
278 }
279 else
280 {
281 JWindow->rows += 1;
282 w1 = JWindow;
283 while(w1 != w)
284 {
285 w1 = w1->next;
286 w1->sy += 1;
287 }
288 w->rows -= 1;
289 }
290 w = JWindow;
291 do
292 {
293 touch_window();
294 JWindow = JWindow->next;
295 }
296 while (w != JWindow);
297
298 if ((jed_window_geom_change_cb != NULL)
299 && (-1 == (*jed_window_geom_change_cb) ()))
300 exit_error ("window_geom_change callback failed", 0);
301
302 return 1;
303 }
304
305 /*}}}*/
adjust_windows(int height)306 static void adjust_windows (int height) /*{{{*/
307 {
308 Window_Type *w = JWindow;
309 int rows;
310
311 do
312 {
313 if (w->rows + w->sy + 2 == Jed_Num_Screen_Rows)
314 {
315 /* bottom window */
316 rows = height - 2 - w->sy;
317 if (rows > 1)
318 {
319 w->rows = rows;
320 return;
321 }
322
323 while (JWindow->sy != Top_Window_SY) other_window();
324
325 one_window();
326 JWindow->rows = height - 2 - Top_Window_SY;
327 if (JWindow->rows < 1) JWindow->rows = 1;
328 return;
329 }
330 w = w->next;
331 }
332 while (w != JWindow);
333 /* not reached! */
334 }
335
336 /*}}}*/
337
338
jed_update_window_sizes(int height,int width)339 void jed_update_window_sizes (int height, int width) /*{{{*/
340 {
341 Window_Type *w;
342
343 if (JWindow == NULL) return;
344
345 if (height < 5) height = 5;
346 if (width < 5) width = 5;
347
348 if (height != Jed_Num_Screen_Rows)
349 adjust_windows(height);
350
351 w = JWindow;
352 do
353 {
354 JWindow->trashed = 1;
355 JWindow->width = width;
356 JWindow = JWindow->next;
357 }
358 while (w != JWindow);
359
360 if (JMiniWindow != NULL)
361 {
362 JMiniWindow->sy = height-1;
363 JMiniWindow->width = width;
364 }
365
366 if ((jed_window_geom_change_cb != NULL)
367 && (-1 == (*jed_window_geom_change_cb) ()))
368 exit_error ("window_geom_change callback failed", 0);
369 }
370
371 /*}}}*/
buffer_visible(Buffer * b)372 int buffer_visible(Buffer *b) /*{{{*/
373 {
374 Window_Type *w = JWindow;
375 int n;
376
377 if ((b == NULL) || (w == NULL))
378 return 0;
379
380 n = 0;
381 do
382 {
383 if (w->buffer == b) n++;
384 w = w->next;
385 }
386 while (w != JWindow);
387 return n;
388 }
389
390 /*}}}*/
391
delete_window(void)392 int delete_window (void) /*{{{*/
393 {
394 Window_Type *tthis, *prev, *next;
395 int nr1;
396
397 tthis = JWindow;
398 next = tthis->next;
399 if ((MiniBuffer_Active && ((tthis == JMiniWindow) || (tthis == next->next)))
400 || (tthis == next)) return(0);
401
402 nr1 = tthis->sy + tthis->rows + 2;
403 if (nr1 != Jed_Num_Screen_Rows)
404 {
405 /* Not the bottom window. Move to the window below this one */
406 while (JWindow->sy + 1 != nr1)
407 other_window();
408 JWindow->sy = tthis->sy;
409 }
410 else
411 {
412 /* The bottom window. Move to the window above this one. */
413 while (JWindow->sy + JWindow->rows + 1 != tthis->sy)
414 other_window();
415 }
416
417 JWindow->rows += tthis->rows + 1;
418 touch_window();
419
420 prev = next;
421 while(prev->next != tthis) prev = prev->next;
422 prev->next = next;
423
424 free_window (tthis);
425 return(1);
426 }
427
428 /*}}}*/
429
touch_screen_for_buffer(Buffer * b)430 void touch_screen_for_buffer(Buffer *b) /*{{{*/
431 {
432 Window_Type *w;
433
434 w = JWindow;
435 do
436 {
437 if (w->buffer == b)
438 {
439 touch_window_hard (w, 0);
440 }
441 w = w->next;
442 }
443 while(w != JWindow);
444 }
445
446 /*}}}*/
is_line_visible(int lnum)447 int is_line_visible (int lnum) /*{{{*/
448 {
449 int n = JWindow->rows;
450 Line *l, *beg = JWindow->beg.line;
451
452 push_spot ();
453 goto_line (&lnum);
454 l = CLine;
455 pop_spot ();
456
457 #if JED_HAS_LINE_ATTRIBUTES
458 if (l->flags & JED_LINE_HIDDEN) return 0;
459 #endif
460
461 while (n && (beg != NULL))
462 {
463 if (l == beg) return 1;
464
465 #if JED_HAS_LINE_ATTRIBUTES
466 if (0 == (beg->flags & JED_LINE_HIDDEN))
467 #endif
468 n--;
469
470 beg = beg->next;
471 }
472 return 0;
473 }
474
475 /*}}}*/
476
jed_num_windows(void)477 int jed_num_windows (void)
478 {
479 Window_Type *w = JWindow;
480 int n = 0;
481 do
482 {
483 n++;
484 w = w->next;
485 }
486 while (w != JWindow);
487 return n;
488 }
489
jed_set_scroll_column(int sc)490 void jed_set_scroll_column (int sc)
491 {
492 if (sc < 1) sc = 1;
493 JWindow->hscroll_column = sc;
494 touch_window();
495 }
496
jed_scroll_right(int dn)497 void jed_scroll_right (int dn)
498 {
499 jed_set_scroll_column (JWindow->hscroll_column - dn);
500 }
501
jed_scroll_left(int dn)502 void jed_scroll_left (int dn)
503 {
504 jed_set_scroll_column (JWindow->hscroll_column + dn);
505 }
506
jed_get_scroll_column(void)507 int jed_get_scroll_column (void)
508 {
509 return JWindow->hscroll_column;
510 }
511
set_scroll_column_intrin(int * sc)512 static void set_scroll_column_intrin (int *sc)
513 {
514 jed_set_scroll_column (*sc);
515 }
516
window_info_intrin(int * what)517 static int window_info_intrin(int *what)
518 {
519 register int n = 0;
520 switch (*what)
521 {
522 case 'x': n = JWindow->sx; break;
523 case 'y': n = JWindow->sy; break;
524 case 'r': n = JWindow->rows; break;
525 case 'c': n = JWindow->hscroll_column; break;
526 case 't': n = JWindow->sy + 1; break;
527 case 'w': n = JWindow->width; break;
528 default:
529 SLang_set_error (SL_INVALID_PARM);
530 }
531 return (n);
532 }
533
534 static SLang_Intrin_Fun_Type Window_Intrinsics [] =
535 {
536 MAKE_INTRINSIC_0("enlargewin", enlarge_window, SLANG_VOID_TYPE),
537 MAKE_INTRINSIC_0("splitwindow", split_window, SLANG_VOID_TYPE),
538 MAKE_INTRINSIC_0("window_line", window_line, INT_TYPE),
539 MAKE_INTRINSIC_0("nwindows", jed_num_windows, SLANG_INT_TYPE),
540 MAKE_INTRINSIC_0("otherwindow", other_window, SLANG_VOID_TYPE),
541 MAKE_INTRINSIC_0("onewindow", one_window, SLANG_VOID_TYPE),
542 MAKE_INTRINSIC_I("window_info", window_info_intrin, SLANG_INT_TYPE),
543 MAKE_INTRINSIC_I("set_scroll_column", set_scroll_column_intrin, SLANG_VOID_TYPE),
544 MAKE_INTRINSIC_0("get_scroll_column", jed_get_scroll_column, SLANG_INT_TYPE),
545 SLANG_END_INTRIN_FUN_TABLE
546 };
547
jed_init_window_intrinsics(void)548 int jed_init_window_intrinsics (void)
549 {
550 if (-1 == SLadd_intrin_fun_table (Window_Intrinsics, NULL))
551 return -1;
552
553 return 0;
554 }
555
556