4 * (C) 1992 Joseph H. Allen
6 * This file is part of JOE (Joe's Own Editor)
11 __RCSID("$MirOS: contrib/code/jupp/w.c,v 1.8 2017/12/02 02:07:38 tg Exp $");
27 extern int dspasis; /* Set to display chars above 127 as-is */
28 extern int staen; /* 0 if top-most status line not displayed */
30 /* Count no. of main windows */
32 int countmain(SCREEN *t)
35 W *m = t->curwin->main;
38 for (q = t->curwin->link.next; q != t->curwin; q = q->link.next)
50 msetI(w->t->t->updtab + w->y, 1, w->h);
51 msetI(w->t->t->syntab + w->y, -1, w->h);
54 /* Find first window in a group */
60 for (x = w; x->link.prev->main == w->main && x->link.prev != w; x = x->link.prev) ;
64 /* Determine height of a window. Returns reqh if it is set, otherwise
65 * used fixed or hh scaled to the current screen size */
74 return (((long) w->t->h - w->t->wind) * w->hh) / 1000;
77 /* Set the height of a window */
79 static void seth(W *w, int h)
86 tmpb = w->t->h - w->t->wind;
87 w->hh = (tmp + (tmpb - 1)) / tmpb;
90 /* Determine height of a family of windows. Uses 'reqh' if it's set */
97 /* Find first window in family */
100 /* Add heights of all windows in family */
101 for (w = x, h = geth(w); w->link.next != x && w->link.next->main == x->main; w = w->link.next, h += geth(w)) ;
106 /* Determine minimum height of a family */
108 static int getminh(W *w)
114 for (w = x, h = (w->fixed ? w->fixed : 2); w->link.next != x && w->link.next->main == x->main; w = w->link.next, h += (w->fixed ? w->fixed : 2)) ;
119 /* Find last window in a group */
125 for (x = w; x->link.next->main == w->main && x->link.next != w; x = x->link.next) ;
129 /* Demote group of window to end of window list. Returns true if top window
132 int demotegroup(W *w)
134 W *top = findtopw(w);
135 W *bot = findbotw(w);
139 for (w = top; w != bot; w = next) {
141 if (w == w->t->topwin) {
145 demote(W, link, w->t->topwin, w);
148 if (w == w->t->topwin)
151 demote(W, link, w->t->topwin, w);
156 /* Find last window on the screen */
162 for (x = t->topwin; x->link.next != t->topwin && x->link.next->y >= 0; x = x->link.next) ;
166 /* Create a screen object */
170 SCREEN *screate(SCRN *scrn)
172 SCREEN *t = (SCREEN *) joe_malloc(sizeof(SCREEN));
184 void sresize(SCREEN *t)
191 if (t->h - t->wind < FITHEIGHT)
192 t->wind = t->h - FITHEIGHT;
200 } while (w != t->topwin);
209 for (y = 0; y != scr->h; ++y) {
210 scr->t->updtab[y] = 1;
211 scr->t->syntab[y] = -1;
215 void scrins(B *b, long l, long n, int flg)
219 if ((w = scr->topwin) != NULL) {
222 if (w->object && w->watom->ins)
223 w->watom->ins(w->object, b, l, n, flg);
226 } while (w != scr->topwin);
230 void scrdel(B *b, long l, long n, int flg)
234 if ((w = scr->topwin) != NULL) {
237 if (w->object && w->watom->del)
238 w->watom->del(w->object, b, l, n, flg);
241 } while (w != scr->topwin);
245 /* Fit as many windows on the screen as is possible beginning with the window
246 * at topwin. Give any extra space which couldn't be used to fit in another
247 * window to the last text window on the screen. This function guarentees
248 * to fit on the window with the cursor in it (moves topwin to next group
249 * of windows until window with cursor fits on screen).
252 static int doabort(W *w, int *ret);
253 extern volatile int dostaupd;
257 int y; /* Where next window goes */
258 int left; /* Lines left on screen */
259 W *w; /* Current window we're fitting */
260 W *pw; /* Main window of previous family */
261 int req; /* Amount this family needs */
262 int adj; /* Amount family needs to be adjusted */
263 int flg = 0; /* Set if cursor window was placed on screen */
278 } while (w != t->topwin);
280 /* Fit a group of windows on the screen */
284 if (req > left) /* If group is taller than lines left */
285 adj = req - left; /* then family gets shorter */
289 /* Fit a family of windows on the screen */
291 w->ny = y; /* Set window's y position */
294 w->nh -= adj; /* Adjust main window of the group */
296 if (!w->win && w->nh < 2)
298 w->nh += doabort(w->link.next, &ret);
300 flg = 1; /* Set if we got window with cursor */
302 left -= w->nh; /* Increment y value by height of window */
303 w = w->link.next; /* Next window */
304 } while (w != t->topwin && w->main == w->link.prev->main);
305 } while (w != t->topwin && left >= FITHEIGHT);
310 /* We can't use extra space to fit a new family on, so give space to parent of
314 /* Adjust that family's children which are below the parent */
315 while ((pw = pw->link.next) != w)
318 /* Make sure the cursor window got on the screen */
320 t->topwin = findbotw(t->topwin)->link.next;
324 /* All of the windows are now on the screen. Scroll the screen to reflect what
329 if (w->y >= 0 && w->ny >= 0)
333 while (pw->link.next != t->topwin && (pw->link.next->y < 0 || pw->link.next->ny < 0 || pw->link.next->ny > pw->link.next->y)) {
335 if (pw->ny >= 0 && pw->y >= 0)
338 /* Scroll windows between l and w */
340 if (l->ny >= 0 && l->y >= 0)
341 nscrldn(t->t, l->y, l->ny + uns_min(l->h, l->nh), l->ny - l->y);
347 } else if (w->ny < w->y) {
350 while (pw->link.next != t->topwin && (pw->link.next->y < 0 || pw->link.next->ny < 0 || pw->link.next->ny < pw->link.next->y)) {
352 if (pw->ny >= 0 && pw->y >= 0)
355 /* Scroll windows between l and w */
357 if (w->ny >= 0 && w->y >= 0)
358 nscrlup(t->t, w->ny, w->y + uns_min(w->h, w->nh), w->y - w->ny);
368 } while (w != t->topwin);
370 /* Update current height and position values */
376 w->watom->move(w->object, w->x, w->ny);
377 if (w->watom->resize)
378 w->watom->resize(w->object, w->w, w->nh);
381 msetI(t->t->updtab + w->ny, 1, w->nh);
382 msetI(t->t->syntab + w->ny, -1, w->nh);
390 } while (w != t->topwin);
393 /* Goto next window */
397 if (t->curwin->link.next != t->curwin) {
398 t->curwin = t->curwin->link.next;
399 if (t->curwin->y == -1)
406 /* Goto previous window */
410 if (t->curwin->link.prev != t->curwin) {
411 t->curwin = t->curwin->link.prev;
412 if (t->curwin->y == -1) {
413 t->topwin = findtopw(t->curwin);
427 /* If we're the last window on the screen, shrink the previous window */
428 if ((w->link.next == w->t->topwin || w->link.next->y == -1) && w != w->t->topwin)
429 return wshrink(w->link.prev->main);
431 /* Get to next variable size window */
432 for (nextw = w->link.next; nextw->fixed && nextw != w->t->topwin; nextw = nextw->link.next) ;
434 /* Is it below us, on screen and big enough to take space from? */
435 if (nextw == w->t->topwin || nextw->y == -1 || nextw->h <= FITHEIGHT)
438 /* Increase this window's height */
441 /* Decrease next window's height */
442 seth(nextw, nextw->h - 1);
456 /* If we're the last window on the screen, grow the previous window */
457 if ((w->link.next == w->t->topwin || w->link.next->y == -1) && w != w->t->topwin)
458 return wgrow(w->link.prev->main);
460 /* Is this window too small already? */
461 if (w->h <= FITHEIGHT)
464 /* Get to window below us */
465 for (nextw = w->link.next; nextw != w->t->topwin && nextw->fixed; nextw = nextw->link.next) ;
466 if (nextw == w->t->topwin)
469 /* Decrease the size of this window */
472 /* Increase the size of next window */
473 seth(nextw, nextw->h + 1);
481 /* Show all windows */
483 void wshowall(SCREEN *t)
489 /* Count no. of main windows */
495 } while (w != t->topwin);
497 /* Compute size to set each window */
498 if ((set = (t->h - t->wind) / (n ? n : 1)) < FITHEIGHT)
501 /* Set size of each variable size window */
510 seth(w, set - (h - 2));
514 } while (w != t->topwin);
520 static void wspread(SCREEN *t)
526 if (w->y >= 0 && !w->win)
529 } while (w != t->topwin);
534 if ((t->h - t->wind) / n >= FITHEIGHT)
535 n = (t->h - t->wind) / n;
546 seth(w, n - (h - 2));
550 } while (w != t->topwin);
554 /* Show just one family of windows */
562 seth(q, w->t->h - w->t->wind - (getminh(q) - 2));
566 } while (q != w->t->topwin);
570 /* Create a window */
572 W *wcreate(SCREEN *t, WATOM *watom, W *where, W *target, W *original, int height, const unsigned char *huh, int *notify)
579 /* Create the window */
580 new = (W *) joe_malloc(sizeof(W));
581 new->notify = notify;
591 new->orgwin = original;
596 /* Set window's target and family */
597 /* was: if (new->win = target) { which may be mistyped == */
598 if ((new->win = target) != NULL) { /* A subwindow */
599 new->main = target->main;
601 } else { /* A parent window */
606 /* Get space for window */
608 if (original->h - height <= 2) {
609 /* Not enough space for window */
613 seth(original, original->h - height);
616 /* Create new keyboard handler for window */
618 new->kbd = mkkbd(kmap_getcontext(watom->context, 1));
622 /* Put window on the screen */
624 enquef(W, link, where, new);
627 enqueb(W, link, t->topwin, new);
630 t->curwin = t->topwin = new;
637 /* Abort group of windows */
639 static int doabort(W *w, int *ret)
645 if (w->t->topwin == w)
646 w->t->topwin = w->link.next;
652 if ((z->win == w || z->main == w) && z->y != -2) {
653 amnt += doabort(z, ret);
656 } while (z = z->link.next, z != w->t->topwin);
658 seth(w->orgwin, geth(w->orgwin) + geth(w));
659 if (w->t->curwin == w) {
660 if (w->t->curwin->win)
661 w->t->curwin = w->t->curwin->win;
663 w->t->curwin = w->orgwin;
665 w->t->curwin = w->link.next;
667 if (qempty(W, link, w)) {
672 if (w->watom->abort && w->object) {
673 *ret = w->watom->abort(w->object);
687 /* Abort a window and its children */
701 if (lastw(t)->link.next != t->topwin)
710 /* Display a message and skip the next key */
712 static void mdisp(SCRN *t, int y, const unsigned char *s)
718 if (len <= (t->co - 1))
721 ofst = len - (t->co - 1);
722 genfmt(t, 0, y, ofst, s, 1);
731 mdisp(t, w->y + w->h - 1, w->msgb);
735 mdisp(t, w->y + ((w->h > 1 && (w->y || !staen)) ? 1 : 0), w->msgt);
740 /* Set temporary message */
742 unsigned char msgbuf[JOE_MSGBUFSIZE];
744 /* display message on bottom line of window */
745 void msgnw(W *w, const unsigned char *s)
750 void msgnwt(W *w, const unsigned char *s)
755 int urtn(BASE *b, int k)
757 if (b->parent->watom->rtn)
758 return b->parent->watom->rtn(b, k);
763 int utype(BASE *b, int k)
765 if (b->parent->watom->type)
766 return b->parent->watom->type(b, k);
771 /* Window user commands */
775 return wprev(bw->parent->t);
780 return wnext(bw->parent->t);
785 return wgrow(bw->parent);
790 return wshrink(bw->parent);
795 if (bw->parent->t->h - bw->parent->t->wind == getgrouph(bw->parent))
796 wshowall(bw->parent->t);
798 wshowone(bw->parent);
804 nredraw(bw->parent->t->t);