1 /* Public Domain Curses */
2 
3 #include <curspriv.h>
4 
5 /*man-start**************************************************************
6 
7 window
8 ------
9 
10 ### Synopsis
11 
12     WINDOW *newwin(int nlines, int ncols, int begy, int begx);
13     WINDOW *derwin(WINDOW* orig, int nlines, int ncols,
14                    int begy, int begx);
15     WINDOW *subwin(WINDOW* orig, int nlines, int ncols,
16                    int begy, int begx);
17     WINDOW *dupwin(WINDOW *win);
18     int delwin(WINDOW *win);
19     int mvwin(WINDOW *win, int y, int x);
20     int mvderwin(WINDOW *win, int pary, int parx);
21     int syncok(WINDOW *win, bool bf);
22     void wsyncup(WINDOW *win);
23     void wcursyncup(WINDOW *win);
24     void wsyncdown(WINDOW *win);
25 
26     WINDOW *resize_window(WINDOW *win, int nlines, int ncols);
27     int wresize(WINDOW *win, int nlines, int ncols);
28     WINDOW *PDC_makelines(WINDOW *win);
29     WINDOW *PDC_makenew(int nlines, int ncols, int begy, int begx);
30     void PDC_sync(WINDOW *win);
31 
32 ### Description
33 
34    newwin() creates a new window with the given number of lines,
35    nlines and columns, ncols. The upper left corner of the window
36    is at line begy, column begx. If nlines is zero, it defaults to
37    LINES - begy; ncols to COLS - begx. Create a new full-screen
38    window by calling newwin(0, 0, 0, 0).
39 
40    delwin() deletes the named window, freeing all associated
41    memory. In the case of overlapping windows, subwindows should be
42    deleted before the main window.
43 
44    mvwin() moves the window so that the upper left-hand corner is
45    at position (y,x). If the move would cause the window to be off
46    the screen, it is an error and the window is not moved. Moving
47    subwindows is allowed.
48 
49    subwin() creates a new subwindow within a window.  The
50    dimensions of the subwindow are nlines lines and ncols columns.
51    The subwindow is at position (begy, begx) on the screen.  This
52    position is relative to the screen, and not to the window orig.
53    Changes made to either window will affect both.  When using this
54    routine, you will often need to call touchwin() before calling
55    wrefresh().
56 
57    derwin() is the same as subwin(), except that begy and begx are
58    relative to the origin of the window orig rather than the
59    screen.  There is no difference between subwindows and derived
60    windows.
61 
62    mvderwin() moves a derived window (or subwindow) inside its
63    parent window.  The screen-relative parameters of the window are
64    not changed.  This routine is used to display different parts of
65    the parent window at the same physical position on the screen.
66 
67    dupwin() creates an exact duplicate of the window win.
68 
69    wsyncup() causes a touchwin() of all of the window's parents.
70 
71    If wsyncok() is called with a second argument of TRUE, this
72    causes a wsyncup() to be called every time the window is
73    changed.
74 
75    wcursyncup() causes the current cursor position of all of a
76    window's ancestors to reflect the current cursor position of the
77    current window.
78 
79    wsyncdown() causes a touchwin() of the current window if any of
80    its parent's windows have been touched.
81 
82    resize_window() allows the user to resize an existing window. It
83    returns the pointer to the new window, or NULL on failure.
84 
85    wresize() is an ncurses-compatible wrapper for resize_window().
86    Note that, unlike ncurses, it will NOT process any subwindows of
87    the window. (However, you still can call it _on_ subwindows.) It
88    returns OK or ERR.
89 
90    PDC_makenew() allocates all data for a new WINDOW * except the
91    actual lines themselves. If it's unable to allocate memory for
92    the window structure, it will free all allocated memory and
93    return a NULL pointer.
94 
95    PDC_makelines() allocates the memory for the lines.
96 
97    PDC_sync() handles wrefresh() and wsyncup() calls when a window
98    is changed.
99 
100 ### Return Value
101 
102    newwin(), subwin(), derwin() and dupwin() return a pointer
103    to the new window, or NULL on failure. delwin(), mvwin(),
104    mvderwin() and syncok() return OK or ERR. wsyncup(),
105    wcursyncup() and wsyncdown() return nothing.
106 
107 ### Errors
108 
109    It is an error to call resize_window() before calling initscr().
110    Also, an error will be generated if we fail to create a newly
111    sized replacement window for curscr, or stdscr. This could
112    happen when increasing the window size. NOTE: If this happens,
113    the previously successfully allocated windows are left alone;
114    i.e., the resize is NOT cancelled for those windows.
115 
116 ### Portability
117                              X/Open    BSD    SYS V
118     newwin                      Y       Y       Y
119     delwin                      Y       Y       Y
120     mvwin                       Y       Y       Y
121     subwin                      Y       Y       Y
122     derwin                      Y       -       Y
123     mvderwin                    Y       -       Y
124     dupwin                      Y       -      4.0
125     wsyncup                     Y       -      4.0
126     syncok                      Y       -      4.0
127     wcursyncup                  Y       -      4.0
128     wsyncdown                   Y       -      4.0
129     resize_window               -       -       -
130     wresize                     -       -       -
131     PDC_makelines               -       -       -
132     PDC_makenew                 -       -       -
133     PDC_sync                    -       -       -
134 
135 **man-end****************************************************************/
136 
137 #include <stdlib.h>
138 
PDC_makenew(int nlines,int ncols,int begy,int begx)139 WINDOW *PDC_makenew(int nlines, int ncols, int begy, int begx)
140 {
141     WINDOW *win;
142 
143     PDC_LOG(("PDC_makenew() - called: lines %d cols %d begy %d begx %d\n",
144              nlines, ncols, begy, begx));
145 
146     /* allocate the window structure itself */
147 
148     if ((win = calloc(1, sizeof(WINDOW))) == (WINDOW *)NULL)
149         return win;
150 
151     /* allocate the line pointer array */
152 
153     if ((win->_y = malloc(nlines * sizeof(chtype *))) == NULL)
154     {
155         free(win);
156         return (WINDOW *)NULL;
157     }
158 
159     /* allocate the minchng and maxchng arrays */
160 
161     if ((win->_firstch = malloc(nlines * sizeof(int))) == NULL)
162     {
163         free(win->_y);
164         free(win);
165         return (WINDOW *)NULL;
166     }
167 
168     if ((win->_lastch = malloc(nlines * sizeof(int))) == NULL)
169     {
170         free(win->_firstch);
171         free(win->_y);
172         free(win);
173         return (WINDOW *)NULL;
174     }
175 
176     /* initialize window variables */
177 
178     win->_maxy = nlines;  /* real max screen size */
179     win->_maxx = ncols;   /* real max screen size */
180     win->_begy = begy;
181     win->_begx = begx;
182     win->_bkgd = ' ';     /* wrs 4/10/93 -- initialize background to blank */
183     win->_clear = (bool) ((nlines == LINES) && (ncols == COLS));
184     win->_bmarg = nlines - 1;
185     win->_parx = win->_pary = -1;
186 
187     /* init to say window all changed */
188 
189     touchwin(win);
190 
191     return win;
192 }
193 
PDC_makelines(WINDOW * win)194 WINDOW *PDC_makelines(WINDOW *win)
195 {
196     int i, j, nlines, ncols;
197 
198     PDC_LOG(("PDC_makelines() - called\n"));
199 
200     if (!win)
201         return (WINDOW *)NULL;
202 
203     nlines = win->_maxy;
204     ncols = win->_maxx;
205 
206     for (i = 0; i < nlines; i++)
207     {
208         if ((win->_y[i] = malloc(ncols * sizeof(chtype))) == NULL)
209         {
210             /* if error, free all the data */
211 
212             for (j = 0; j < i; j++)
213                 free(win->_y[j]);
214 
215             free(win->_firstch);
216             free(win->_lastch);
217             free(win->_y);
218             free(win);
219 
220             return (WINDOW *)NULL;
221         }
222     }
223 
224     return win;
225 }
226 
PDC_sync(WINDOW * win)227 void PDC_sync(WINDOW *win)
228 {
229     PDC_LOG(("PDC_sync() - called:\n"));
230 
231     if (win->_immed)
232         wrefresh(win);
233     if (win->_sync)
234         wsyncup(win);
235 }
236 
newwin(int nlines,int ncols,int begy,int begx)237 WINDOW *newwin(int nlines, int ncols, int begy, int begx)
238 {
239     WINDOW *win;
240 
241     PDC_LOG(("newwin() - called:lines=%d cols=%d begy=%d begx=%d\n",
242              nlines, ncols, begy, begx));
243 
244     if (!nlines)
245         nlines = LINES - begy;
246     if (!ncols)
247         ncols  = COLS  - begx;
248 
249     if ( (begy + nlines > SP->lines || begx + ncols > SP->cols)
250         || !(win = PDC_makenew(nlines, ncols, begy, begx))
251         || !(win = PDC_makelines(win)) )
252         return (WINDOW *)NULL;
253 
254     werase(win);
255 
256     return win;
257 }
258 
delwin(WINDOW * win)259 int delwin(WINDOW *win)
260 {
261     int i;
262 
263     PDC_LOG(("delwin() - called\n"));
264 
265     if (!win)
266         return ERR;
267 
268     /* subwindows use parents' lines */
269 
270     if (!(win->_flags & (_SUBWIN|_SUBPAD)))
271         for (i = 0; i < win->_maxy && win->_y[i]; i++)
272             if (win->_y[i])
273                 free(win->_y[i]);
274 
275     free(win->_firstch);
276     free(win->_lastch);
277     free(win->_y);
278     free(win);
279 
280     return OK;
281 }
282 
mvwin(WINDOW * win,int y,int x)283 int mvwin(WINDOW *win, int y, int x)
284 {
285     PDC_LOG(("mvwin() - called\n"));
286 
287     if (!win || (y + win->_maxy > LINES || y < 0)
288              || (x + win->_maxx > COLS || x < 0))
289         return ERR;
290 
291     win->_begy = y;
292     win->_begx = x;
293     touchwin(win);
294 
295     return OK;
296 }
297 
subwin(WINDOW * orig,int nlines,int ncols,int begy,int begx)298 WINDOW *subwin(WINDOW *orig, int nlines, int ncols, int begy, int begx)
299 {
300     WINDOW *win;
301     int i;
302     int j = begy - orig->_begy;
303     int k = begx - orig->_begx;
304 
305     PDC_LOG(("subwin() - called: lines %d cols %d begy %d begx %d\n",
306              nlines, ncols, begy, begx));
307 
308     /* make sure window fits inside the original one */
309 
310     if (!orig || (begy < orig->_begy) || (begx < orig->_begx) ||
311         (begy + nlines) > (orig->_begy + orig->_maxy) ||
312         (begx + ncols) > (orig->_begx + orig->_maxx))
313         return (WINDOW *)NULL;
314 
315     if (!nlines)
316         nlines = orig->_maxy - 1 - j;
317     if (!ncols)
318         ncols  = orig->_maxx - 1 - k;
319 
320     if ( !(win = PDC_makenew(nlines, ncols, begy, begx)) )
321         return (WINDOW *)NULL;
322 
323     /* initialize window variables */
324 
325     win->_attrs = orig->_attrs;
326     win->_bkgd = orig->_bkgd;
327     win->_leaveit = orig->_leaveit;
328     win->_scroll = orig->_scroll;
329     win->_nodelay = orig->_nodelay;
330     win->_delayms = orig->_delayms;
331     win->_use_keypad = orig->_use_keypad;
332     win->_immed = orig->_immed;
333     win->_sync = orig->_sync;
334     win->_pary = j;
335     win->_parx = k;
336     win->_parent = orig;
337 
338     for (i = 0; i < nlines; i++, j++)
339         win->_y[i] = orig->_y[j] + k;
340 
341     win->_flags |= _SUBWIN;
342 
343     return win;
344 }
345 
derwin(WINDOW * orig,int nlines,int ncols,int begy,int begx)346 WINDOW *derwin(WINDOW *orig, int nlines, int ncols, int begy, int begx)
347 {
348     return subwin(orig, nlines, ncols, begy + orig->_begy, begx + orig->_begx);
349 }
350 
mvderwin(WINDOW * win,int pary,int parx)351 int mvderwin(WINDOW *win, int pary, int parx)
352 {
353     int i, j;
354     WINDOW *mypar;
355 
356     if (!win || !(win->_parent))
357         return ERR;
358 
359     mypar = win->_parent;
360 
361     if (pary < 0 || parx < 0 || (pary + win->_maxy) > mypar->_maxy ||
362                                 (parx + win->_maxx) > mypar->_maxx)
363         return ERR;
364 
365     j = pary;
366 
367     for (i = 0; i < win->_maxy; i++)
368         win->_y[i] = (mypar->_y[j++]) + parx;
369 
370     win->_pary = pary;
371     win->_parx = parx;
372 
373     return OK;
374 }
375 
dupwin(WINDOW * win)376 WINDOW *dupwin(WINDOW *win)
377 {
378     WINDOW *new;
379     chtype *ptr, *ptr1;
380     int nlines, ncols, begy, begx, i;
381 
382     if (!win)
383         return (WINDOW *)NULL;
384 
385     nlines = win->_maxy;
386     ncols = win->_maxx;
387     begy = win->_begy;
388     begx = win->_begx;
389 
390     if ( !(new = PDC_makenew(nlines, ncols, begy, begx))
391         || !(new = PDC_makelines(new)) )
392         return (WINDOW *)NULL;
393 
394     /* copy the contents of win into new */
395 
396     for (i = 0; i < nlines; i++)
397     {
398         for (ptr = new->_y[i], ptr1 = win->_y[i];
399              ptr < new->_y[i] + ncols; ptr++, ptr1++)
400             *ptr = *ptr1;
401 
402         new->_firstch[i] = 0;
403         new->_lastch[i] = ncols - 1;
404     }
405 
406     new->_curx = win->_curx;
407     new->_cury = win->_cury;
408     new->_maxy = win->_maxy;
409     new->_maxx = win->_maxx;
410     new->_begy = win->_begy;
411     new->_begx = win->_begx;
412     new->_flags = win->_flags;
413     new->_attrs = win->_attrs;
414     new->_clear = win->_clear;
415     new->_leaveit = win->_leaveit;
416     new->_scroll = win->_scroll;
417     new->_nodelay = win->_nodelay;
418     new->_delayms = win->_delayms;
419     new->_use_keypad = win->_use_keypad;
420     new->_tmarg = win->_tmarg;
421     new->_bmarg = win->_bmarg;
422     new->_parx = win->_parx;
423     new->_pary = win->_pary;
424     new->_parent = win->_parent;
425     new->_bkgd = win->_bkgd;
426     new->_flags = win->_flags;
427 
428     return new;
429 }
430 
resize_window(WINDOW * win,int nlines,int ncols)431 WINDOW *resize_window(WINDOW *win, int nlines, int ncols)
432 {
433     WINDOW *new;
434     int i, save_cury, save_curx, new_begy, new_begx;
435 
436     PDC_LOG(("resize_window() - called: nlines %d ncols %d\n",
437              nlines, ncols));
438 
439     if (!win)
440         return (WINDOW *)NULL;
441 
442     if (win->_flags & _SUBPAD)
443     {
444         if ( !(new = subpad(win->_parent, nlines, ncols,
445                             win->_begy, win->_begx)) )
446             return (WINDOW *)NULL;
447     }
448     else if (win->_flags & _SUBWIN)
449     {
450         if ( !(new = subwin(win->_parent, nlines, ncols,
451                             win->_begy, win->_begx)) )
452             return (WINDOW *)NULL;
453     }
454     else
455     {
456         if (win == SP->slk_winptr)
457         {
458             new_begy = SP->lines - SP->slklines;
459             new_begx = 0;
460         }
461         else
462         {
463             new_begy = win->_begy;
464             new_begx = win->_begx;
465         }
466 
467         if ( !(new = PDC_makenew(nlines, ncols, new_begy, new_begx)) )
468             return (WINDOW *)NULL;
469     }
470 
471     save_curx = min(win->_curx, (new->_maxx - 1));
472     save_cury = min(win->_cury, (new->_maxy - 1));
473 
474     if (!(win->_flags & (_SUBPAD|_SUBWIN)))
475     {
476         if ( !(new = PDC_makelines(new)) )
477             return (WINDOW *)NULL;
478 
479         werase(new);
480 
481         copywin(win, new, 0, 0, 0, 0, min(win->_maxy, new->_maxy) - 1,
482                 min(win->_maxx, new->_maxx) - 1, FALSE);
483 
484         for (i = 0; i < win->_maxy && win->_y[i]; i++)
485             if (win->_y[i])
486                 free(win->_y[i]);
487     }
488 
489     new->_flags = win->_flags;
490     new->_attrs = win->_attrs;
491     new->_clear = win->_clear;
492     new->_leaveit = win->_leaveit;
493     new->_scroll = win->_scroll;
494     new->_nodelay = win->_nodelay;
495     new->_delayms = win->_delayms;
496     new->_use_keypad = win->_use_keypad;
497     new->_tmarg = (win->_tmarg > new->_maxy - 1) ? 0 : win->_tmarg;
498     new->_bmarg = (win->_bmarg == win->_maxy - 1) ?
499                   new->_maxy - 1 : min(win->_bmarg, (new->_maxy - 1));
500     new->_parent = win->_parent;
501     new->_immed = win->_immed;
502     new->_sync = win->_sync;
503     new->_bkgd = win->_bkgd;
504 
505     new->_curx = save_curx;
506     new->_cury = save_cury;
507 
508     free(win->_firstch);
509     free(win->_lastch);
510     free(win->_y);
511 
512     *win = *new;
513     free(new);
514 
515     return win;
516 }
517 
wresize(WINDOW * win,int nlines,int ncols)518 int wresize(WINDOW *win, int nlines, int ncols)
519 {
520     return (resize_window(win, nlines, ncols) ? OK : ERR);
521 }
522 
wsyncup(WINDOW * win)523 void wsyncup(WINDOW *win)
524 {
525     WINDOW *tmp;
526 
527     PDC_LOG(("wsyncup() - called\n"));
528 
529     for (tmp = win; tmp; tmp = tmp->_parent)
530         touchwin(tmp);
531 }
532 
syncok(WINDOW * win,bool bf)533 int syncok(WINDOW *win, bool bf)
534 {
535     PDC_LOG(("syncok() - called\n"));
536 
537     if (!win)
538         return ERR;
539 
540     win->_sync = bf;
541 
542     return OK;
543 }
544 
wcursyncup(WINDOW * win)545 void wcursyncup(WINDOW *win)
546 {
547     WINDOW *tmp;
548 
549     PDC_LOG(("wcursyncup() - called\n"));
550 
551     for (tmp = win; tmp && tmp->_parent; tmp = tmp->_parent)
552         wmove(tmp->_parent, tmp->_pary + tmp->_cury, tmp->_parx + tmp->_curx);
553 }
554 
wsyncdown(WINDOW * win)555 void wsyncdown(WINDOW *win)
556 {
557     WINDOW *tmp;
558 
559     PDC_LOG(("wsyncdown() - called\n"));
560 
561     for (tmp = win; tmp; tmp = tmp->_parent)
562     {
563         if (is_wintouched(tmp))
564         {
565             touchwin(win);
566             break;
567         }
568     }
569 }
570