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