Ticket #16535: patch-wrp_vertical_split

File patch-wrp_vertical_split, 38.3 KB (added by macports@…, 16 years ago)

Patch to sources to enable vertical split in screen

Line 
1--- comm.c.orig 2003-09-08 14:25:08.000000000 +0000
2+++ comm.c      2006-07-07 02:39:24.000000000 +0000
3@@ -309,6 +309,7 @@ struct comm comms[RC_LAST + 1] =
4   { "vbellwait",       ARGS_1 },
5   { "verbose",         ARGS_01 },
6   { "version",         ARGS_0 },
7+  { "vert_split",              NEED_DISPLAY|ARGS_0 },
8   { "wall",            NEED_DISPLAY|ARGS_1},
9   { "width",           ARGS_0123 },
10   { "windowlist",      NEED_DISPLAY|ARGS_012 },
11--- display.c.orig      2003-12-05 13:45:41.000000000 +0000
12+++ display.c   2006-07-07 02:39:26.000000000 +0000
13@@ -476,65 +476,306 @@ struct canvas *cv;
14   free(cv);
15 }
16 
17+struct canvas *
18+get_new_canvas(target)
19+struct canvas *target;
20+{   /** Allocate a new canvas, and assign it characteristics
21+    equal to those of target. */
22+    struct canvas *cv;
23+
24+    if ((cv = (struct canvas *) calloc(1, sizeof *cv)) == 0)
25+        return NULL;
26+
27+    cv -> c_xs               = target -> c_xs;
28+    cv -> c_xe               = target -> c_xe;
29+    cv -> c_ys               = target -> c_ys;
30+    cv -> c_ye               = target -> c_ye;
31+    cv -> c_xoff             = target -> c_xoff;
32+    cv -> c_yoff             = target -> c_yoff;
33+    cv -> c_display          = target -> c_display;
34+    cv -> c_vplist           = 0;
35+    cv -> c_captev.type      = EV_TIMEOUT;
36+    cv -> c_captev.data      = (char *) cv;
37+    cv -> c_captev.handler   = cv_winid_fn;
38+
39+    cv -> c_blank.l_cvlist   = cv;
40+    cv -> c_blank.l_width    = cv->c_xe - cv->c_xs + 1;
41+    cv -> c_blank.l_height   = cv->c_ye - cv->c_ys + 1;
42+    cv -> c_blank.l_x        = cv->c_blank.l_y = 0;
43+    cv -> c_blank.l_layfn    = &BlankLf;
44+    cv -> c_blank.l_data     = 0;
45+    cv -> c_blank.l_next     = 0;
46+    cv -> c_blank.l_bottom   = &cv->c_blank;
47+    cv -> c_blank.l_blocking = 0;
48+    cv -> c_layer            = &cv->c_blank;
49+    cv -> c_lnext            = 0;
50+
51+    cv -> c_left  = target -> c_left;
52+    cv -> c_right = target -> c_right;
53+    cv -> c_above = target -> c_above;
54+    cv -> c_below = target -> c_below;
55+
56+    return cv;
57+}
58+
59 int
60-AddCanvas()
61-{
62-  int hh, h, i, j;
63-  struct canvas *cv, **cvpp;
64+share_limits( type, cv0, cv1)
65+int type;       /* HORIZONTAL or VERTICAL */
66+struct canvas *cv0;  /* canvas to compare against. */
67+struct canvas *cv1;  /* canvas to compare against. */
68+{   /** Return non-zero if the two canvasses share limits.
69+    (ie, their horizontal or veritcal boundaries are the same)
70+    */
71+    switch (type) {
72+    case HORIZONTAL:
73+        return cv0 -> c_xs == cv1 -> c_xs && cv0->c_xe == cv1 -> c_xe;
74+    case VERTICAL:
75+        return cv0 -> c_ys == cv1 -> c_ys && cv0->c_ye == cv1 -> c_ye;
76+    }
77+    ASSERT(0);
78+    return 0;
79+}
80 
81-  for (cv = D_cvlist, j = 0; cv; cv = cv->c_next)
82-    j++;
83-  j++; /* new canvas */
84-  h = D_height - (D_has_hstatus == HSTATUS_LASTLINE);
85-  if (h / j <= 1)
86-    return -1;
87+int
88+compute_region(type, a, focus, list)
89+int type;  /* 0 - horizontal, 1 - vertical */
90+struct screen_region *a;  /* Return value. */
91+struct canvas *focus;  /* Canvas to compute around. */
92+struct canvas *list;   /* List of all canvasses. */
93+{   /** Find the start and end of the screen region.*/
94+    /*
95+    I'm using the term 'region' here differently
96+    than elsewhere.  Elsewhere, 'region' is synonymous
97+    with 'canvas', but I am using it to denote
98+    a collection of related canvasses.
99 
100-  for (cv = D_cvlist; cv; cv = cv->c_next)
101-    if (cv == D_forecv)
102+    Suppose the screen currently looks
103+    like this:
104+    ---------------------------
105+    |  0   |   1    |    2    |
106+    ---------------------------
107+    |  3   |   4    |    5    |
108+    ---------------------------
109+    |          6              |
110+    ---------------------------
111+    |   7  |   8    |    9    |
112+    ---------------------------
113+    Where there are 10 entries in D_cvlist.
114+    Canvasses 0,1,2 are in the same region, as
115+    are cavasses 1 and 4.  We need to be careful not to
116+    lump 1 and 4 together w/8.  The
117+    type of the region containing 0,1,2 is
118+    VERTICAL, since each canvas is created
119+    via a vertical split.
120+
121+    Throughout, I'm assuming that canvasses
122+    are created so that any region will
123+    be contiguous in D_cvlist.
124+
125+    Note: this was written before the screen
126+    orientation members (c_left, c_above, c_below,
127+    c_right) were added to the struct canvas.
128+    Might want to rewrite this to use those.
129+
130+    Written by Bill Pursell, 23/12/2005
131+    */
132+
133+    struct canvas *cv;  /* Entry in list. */
134+    int seen_focus;     /* Flag used when walking the list. */
135+
136+    seen_focus = 0;
137+    a->count = 0;
138+    a->type  = type;
139+
140+    if (type == HORIZONTAL) {
141+        a->xs = focus -> c_xs;
142+        a->xe = focus -> c_xe;
143+        a->ys = -1;
144+    }
145+    if (type == VERTICAL) {
146+        a->ys = focus -> c_ys;
147+        a->ye = focus -> c_ye;
148+        a->xs = -1;
149+    }
150+    /* Count the canvasses in the same region as the
151+    canvas with the focus, and find the limits of the region. */
152+    for (cv = list; cv; cv = cv->c_next) {
153+        if (cv == focus)
154+            seen_focus = 1;
155+        if (share_limits( type, cv, focus)) {
156+            debug2("cv = %x  %s\n", cv, (cv == focus)? "FORE":"");
157+            debug2("x range: %d - %d\n", cv->c_xs, cv->c_xe);
158+            debug2("y range: %d - %d\n", cv->c_ys, cv->c_ye);
159+            switch (type) {
160+            case HORIZONTAL  :
161+                if (a->ys == -1) {
162+                    a->ys = cv -> c_ys;
163+                    a->start = cv;
164+                }
165+                a->ye = cv -> c_ye;
166       break;
167-  ASSERT(cv);
168-  cvpp = &cv->c_next;
169+            case VERTICAL:
170+                if (a->xs == -1) {
171+                    a->xs = cv -> c_xs;
172+                    a->start = cv;
173+                }
174+                a->xe = cv -> c_xe;
175+                break;
176+            }
177 
178-  if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0)
179-    return -1;
180+            a->end = cv;
181+            a->count++;
182+        }
183+        if (!share_limits(type, cv, focus) || cv -> c_next == NULL) {
184+            if (seen_focus) {
185+                debug2("x range of Region: %d-%d\n", a->xs, a->xe);
186+                debug2("y range of Region: %d-%d\n", a->ys, a->ye);
187+                break;
188+            }
189+            else {
190+                switch(type) {
191+                case HORIZONTAL: a->ys = -1; break;
192+                case VERTICAL  : a->xs = -1; break;
193+                }
194+                a->count = 0;
195+            }
196+        }
197+    }
198 
199-  cv->c_xs      = 0;
200-  cv->c_xe      = D_width - 1;
201-  cv->c_ys      = 0;
202-  cv->c_ye      = D_height - 1;
203-  cv->c_xoff    = 0;
204-  cv->c_yoff    = 0;
205-  cv->c_display = display;
206-  cv->c_vplist  = 0;
207-  cv->c_captev.type = EV_TIMEOUT;
208-  cv->c_captev.data = (char *)cv;
209-  cv->c_captev.handler = cv_winid_fn;
210+    switch (type) {
211+    case HORIZONTAL:
212+        a->expanse  = a->ye - a->ys + 1; 
213+        ASSERT(a->expanse <=  D_height - (D_has_hstatus == HSTATUS_LASTLINE));
214+        break;
215+    case VERTICAL:   
216+        a->expanse  = a->xe - a->xs + 1; 
217+        ASSERT(a->expanse <=  D_width);
218+        break;
219+    }
220+    ASSERT(seen_focus);
221+}
222 
223-  cv->c_blank.l_cvlist = cv;
224-  cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1;
225-  cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1;
226-  cv->c_blank.l_x = cv->c_blank.l_y = 0;
227-  cv->c_blank.l_layfn = &BlankLf;
228-  cv->c_blank.l_data = 0;
229-  cv->c_blank.l_next = 0;
230-  cv->c_blank.l_bottom = &cv->c_blank;
231-  cv->c_blank.l_blocking = 0;
232-  cv->c_layer = &cv->c_blank;
233-  cv->c_lnext = 0;
234+void
235+reset_region_types(region, type)
236+struct screen_region *region;
237+int type;
238+{   /** Set c_type of all the canvasses in the region to type. */
239 
240-  cv->c_next    = *cvpp;
241-  *cvpp = cv;
242+    struct canvas *cv;
243 
244-  i = 0;
245-  for (cv = D_cvlist; cv; cv = cv->c_next)
246-    {
247-      hh = h / j-- - 1;
248-      cv->c_ys = i;
249-      cv->c_ye = i + hh - 1;
250-      cv->c_yoff = i;
251-      i += hh + 1;
252-      h -= hh + 1;
253+    for (cv = region->start; cv != region->end->c_next; cv = cv->c_next) {
254+        #ifdef DEBUG
255+        switch(type) {
256+        case HORIZONTAL:
257+            ASSERT (cv->c_xs == region -> xs && cv->c_xe == region -> xe);
258+            break;
259+        case VERTICAL:
260+            ASSERT (cv->c_ys == region -> ys && cv->c_ye == region -> ye);
261+            break;
262+        default:
263+            ASSERT(0);
264+    }
265+        #endif
266+        cv -> c_type = type;
267     }
268+}
269+
270+void
271+debug_print_canvas(cv)
272+struct canvas *cv;
273+{   /** Print cv to the debug file. */
274+#ifdef DEBUG
275+    debug2("%x %s\n", cv, (cv == D_forecv)?"  HAS FOCUS":"");
276+    debug2("    above: %x    below: %x\n", cv->c_above, cv->c_below);
277+    debug2("    left: %x     right: %x\n", cv->c_left,  cv->c_right);
278+    debug3("    x range: %2d-%2d, xoff = %d\n",
279+        cv->c_xs, cv->c_xe, cv->c_xoff);
280+    debug3("    y range: %2d-%2d yoff = %d\n",
281+        cv->c_ys, cv->c_ye, cv->c_yoff);
282+    debug2("    next: %x   type: %d\n", cv->c_next, cv->c_type);
283+#endif
284+}
285+
286+void
287+debug_print_all_canvasses(header)
288+char *header;
289+{   /** Print the dimensions of all the canvasses
290+    in the current display to the debug file.  Precede
291+    with a line containing the header message. */
292+    #ifdef DEBUG
293+    struct canvas *cv;
294+    char message[BUFSIZ];
295+
296+    sprintf(message,  "%10s %5d: ",__FILE__ , __LINE__);
297+    strcat (message, header);
298+    fprintf(dfp, message);
299+    fflush(dfp);
300+    for (cv = D_cvlist; cv; cv = cv->c_next) {
301+        debug_print_canvas(cv);
302+    }
303+    #endif
304+    return;
305+}
306+
307+set_internal_orientation(region)
308+struct screen_region *region;
309+{   /** Set the orientation for canvasses inside the region. */
310+
311+    struct canvas *cv;
312+
313+    for (cv = region -> start; cv != region -> end; cv = cv->c_next) {
314+        ASSERT (cv -> c_type == region -> type);
315+        switch (region->type) {
316+        case VERTICAL:
317+            cv -> c_right           = cv -> c_next;
318+            cv -> c_next -> c_left  = cv;
319+            break;
320+        case HORIZONTAL:
321+            cv -> c_below           = cv -> c_next;
322+            cv -> c_next -> c_above = cv;
323+            break;
324+        }
325+    }
326+}
327+
328+
329+int
330+AddCanvas(type)
331+int type;  /* Horizontal or Vertical. */
332+{   /** Add a new canvas, via a split. */
333+
334+    struct canvas  *cv;        /* Index into D_cvlist. */
335+    struct screen_region  vr;  /* Canvasses in the same row/column as the
336+                                  canvas with the focus.   */
337+
338+    compute_region(type, &vr, D_forecv, D_cvlist);
339+
340+    /* Return if the region isn't big enough to split. */
341+    if (vr.expanse / vr.count <= 1)
342+        return -1;
343+
344+    /* Allocate a new canvas. */
345+    if ( (cv = get_new_canvas(D_forecv)) == NULL)
346+        return -1;
347+
348+    /* Set the type. */
349+    cv -> c_type = D_forecv -> c_type = type;
350+
351+    /* Increment the canvas count to account for the one we will add. */
352+    vr.count++;
353+
354+    debug_print_all_canvasses("AddCanvas start.\n");
355+
356+    /* Insert the new canvas after the current foreground. */
357+    cv -> c_next = D_forecv->c_next;
358+    D_forecv -> c_next = cv;
359+    if (vr.end == D_forecv)
360+        vr.end = cv;
361+
362+    set_internal_orientation(&vr);
363+    equalize_canvas_dimensions(&vr);
364+
365+    debug_print_all_canvasses("AddCanvas end.\n");
366 
367   RethinkDisplayViewports();
368   ResizeLayersToCanvases();
369@@ -542,67 +783,595 @@ AddCanvas()
370 }
371 
372 void
373-RemCanvas()
374+get_endpoints(cv, start, end, off)
375+struct canvas *cv;
376+int **start;
377+int **end;
378+int **off;
379+{   /** Set *start, *end, and *off appropriate with cv->c_type. */
380+    switch (cv->c_type) {
381+    case HORIZONTAL:
382+        if (start) *start = &cv -> c_ys;
383+        if (end)   *end   = &cv -> c_ye;
384+        if (off)   *off   = &cv -> c_yoff;
385+        break;
386+    case VERTICAL:
387+        if (start) *start = &cv -> c_xs;
388+        if (end)   *end   = &cv -> c_xe;
389+        if (off)   *off   = &cv -> c_xoff;
390+        break;
391+    default: ASSERT(0);
392+    }
393+}
394+
395+#define MIN_HEIGHT 1
396+#define MIN_WIDTH 5
397+
398+int
399+adjust_canvas_dimensions(vr, target, amount)
400+struct screen_region *vr;
401+struct canvas *target;
402+int amount;
403+{   /** Modify the size of target by amount. */
404+   
405+    /* Other canvasses in the region will gain or lose
406+    space to accomodate the change.  Return
407+    the number of rows/columns by which the size
408+    of target is succesfully enlarged. (if amount <= 0,
409+    return 0) */
410+
411+    struct canvas *this;    /* for walking the list. */
412+    struct canvas *prev;    /* for walking the list backwards. */
413+    int adjusted;           /* Amount already re-allocated. */
414+    int *start, *end, *off; /* c->c_{x,y}s, c->c_{x,y}e, and c->c_{x,y}off */
415+    int minimum, space;
416+
417+    debug1("adjust: amount = %d\n", amount);
418+    debug_print_all_canvasses("ADJUST \n");
419+
420+    ASSERT(vr->count > 1);
421+
422+    if (amount == 0)
423+        return 0;
424+
425+    switch(vr->type) {
426+    case HORIZONTAL:  minimum = MIN_HEIGHT; space = 2; break;
427+    case VERTICAL:    minimum = MIN_WIDTH; space = 1; break;
428+    default: ASSERT(0);
429+    }
430+
431+    if (amount < 0) {
432+        debug_print_all_canvasses("PREADJUST\n");
433+
434+        get_endpoints(target, &start, &end, &off);
435+        if (target == vr -> start) {
436+            *end += amount;
437+
438+            if (*end < *start + minimum)
439+                *end = *start + minimum;
440+
441+            get_endpoints(target->c_next, &start, 0, &off);
442+            *start = *off = *end + space;
443+
444+        debug_print_all_canvasses("POSTADJUST\n\n");
445+        }
446+        else {
447+            for (prev = vr->start; prev->c_next != target; prev = prev->c_next)
448+                ;
449+            ASSERT(prev && prev -> c_next == target);
450+
451+            *start -= amount;
452+            if (*start > *end - minimum)
453+                *start = *end - minimum;
454+            get_endpoints(prev, 0, &end, 0);
455+            *end = *start - space;
456+        }
457+        return 0;
458+    }
459+
460+    ASSERT (amount > 0);
461+
462+    /* Reallocate space from canvasses below target. */
463+    this = vr -> end;
464+    adjusted = 0;
465+    while ( adjusted < amount) {
466+        int this_amount;   /* amount this canvas can yield. */
467+        struct canvas *cv; /* For walking lists. */
468+
469+        if (this == target)
470+            break;
471+
472+        get_endpoints(this, &start, &end, 0);
473+        switch (vr->type) {
474+        case HORIZONTAL: this_amount = *end - *start - MIN_HEIGHT; break;
475+        case VERTICAL:   this_amount = *end - *start - MIN_WIDTH;  break;
476+        default: ASSERT(0);
477+        }
478+
479+        if (this_amount > amount - adjusted)
480+            this_amount = amount - adjusted;
481+
482+        debug("target:\n");
483+        debug_print_canvas(target);
484+
485+        debug("this:\n");
486+        debug_print_canvas(this);
487+
488+        /* Move all canvasses between target and this by this_amount. */
489+        for (cv = target; cv != this; cv = cv -> c_next) {
490+            debug1("this_amount = %d\n", this_amount);
491+            debug_print_canvas(cv);
492+
493+            get_endpoints(cv, &start, &end, 0);
494+            *end += this_amount;
495+            get_endpoints(cv->c_next, &start, &end, &off);
496+            *start += this_amount;
497+            *off = *start;
498+        }
499+        adjusted += this_amount;
500+        debug1("adjusted: %d\n", adjusted);
501+
502+        debug("target:\n");
503+        debug_print_canvas(target);
504+
505+        debug("this:\n");
506+        debug_print_canvas(this);
507+
508+
509+        /* Get the previous canvas.  TODO: include back pointers
510+        in struct canvas(?). */
511+        for (prev = vr->start; prev->c_next != this; prev = prev->c_next)
512+            ASSERT(prev);
513+        this = prev;
514+    }
515+    debug1("adjusted = %d\n", adjusted);
516+    if (adjusted == amount || target == vr->start)
517+        return adjusted;
518+
519+    /* Re-allocate space from canvasses above target. */
520+    ASSERT(this == target);
521+    for (prev = vr->start; prev->c_next != this; prev = prev->c_next)
522+        ASSERT(prev);
523+    this = prev;
524+
525+    while (adjusted < amount) {
526+        int this_amount;   /* amount this canvas can yield. */
527+        struct canvas *cv; /* For walking lists. */
528+
529+        get_endpoints(this, &start, &end, 0);
530+        switch (vr->type) {
531+        case HORIZONTAL: this_amount = *end - *start - MIN_HEIGHT; break;
532+        case VERTICAL:   this_amount = *end - *start - MIN_WIDTH;  break;
533+        default: ASSERT(0);
534+        }
535+
536+        if (this_amount > amount - adjusted)
537+            this_amount = amount - adjusted;
538+
539+        /* Move all canvasses between this and target by this_amount. */
540+        for (cv = this; cv != target; cv = cv -> c_next) {
541+            ASSERT(cv);
542+            debug1("this_amount = %d\n", this_amount);
543+            debug_print_canvas(cv);
544+            debug("NEXT:\n");
545+            debug_print_canvas(cv->c_next);
546+
547+            debug("getend:\n");
548+            get_endpoints(cv, &start, &end, 0);
549+            ASSERT(end && start );
550+            ASSERT(start);
551+            ASSERT(*end >= this_amount);
552+            *end -= this_amount;
553+            ASSERT(*end > *start);
554+
555+            debug("getend:\n");
556+            ASSERT(cv->c_next);
557+            get_endpoints(cv->c_next, &start, &end, &off);
558+            ASSERT(start && off);
559+            ASSERT(*start >= this_amount);
560+            ASSERT(*start == *off);
561+            *start -= this_amount;
562+            *off = *start;
563+
564+            debug("adjusted\n");
565+            debug_print_canvas(cv);
566+            debug("NEXT:\n");
567+            debug_print_canvas(cv->c_next);
568+            debug("\n");
569+        }
570+        adjusted += this_amount;
571+
572+        if (this == vr->start)
573+            break;
574+
575+        for (prev = vr->start; prev->c_next != this; prev = prev->c_next)
576+            ASSERT(prev);
577+        this = prev;
578+    }
579+    debug1("returning: %d\n", adjusted);
580+    return adjusted;
581+}
582+
583+void
584+equalize_canvas_dimensions(vr)
585+struct screen_region *vr;
586+{   /** Reset the size of each canvas in the region. */
587+
588+    struct canvas *cv;  /* for walking the list. */
589+    int this_size; /* new size of cv */
590+    int this_start;  /* Start coordinate for current canvas. */
591+
592+    debug("equalize\n");
593+
594+    debug2("vr start = %#x, vr end = %#x\n", vr->start, vr->end);
595+
596+    switch(vr->type) {
597+    case VERTICAL:   this_start = vr->xs; break;
598+    case HORIZONTAL: this_start = vr->ys; break;
599+    }
600+
601+    for (cv = vr->start ; ; cv = cv->c_next) {
602+        ASSERT(cv);
603+
604+        /* For the horizontal split, leave space for a status line. */
605+        this_size = vr->expanse / vr->count - (vr->type == HORIZONTAL);
606+
607+        /* Give any additional available rows/columns to the foreground. */
608+        if (cv == D_forecv)
609+            this_size += vr->expanse % vr->count;
610+
611+        debug_print_canvas(cv);
612+        debug2("cv type = %d, vr type = %d\n", cv->c_type, vr->type);
613+        ASSERT(cv -> c_type == vr->type);
614+
615+        switch(vr->type) {
616+        case VERTICAL:
617+            cv -> c_xs = cv -> c_xoff = this_start;
618+            cv -> c_xe = this_start + this_size - 1;
619+            this_start += this_size;
620+            break;
621+        case HORIZONTAL:
622+            if (cv == vr->end && cv->c_ye == D_height-1-
623+                (D_has_hstatus == HSTATUS_LASTLINE))
624+                this_size += 1;  /* Don't make space for status line
625+                    in the bottom region (it already has one). */
626+
627+            cv -> c_ys = cv -> c_yoff = this_start;
628+            cv -> c_ye = this_start + this_size - 1;
629+            this_start += this_size + 1;  /* add one for status line. */
630+            break;
631+        }
632+        if (cv == vr->end)
633+            break;
634+    }
635+}
636+
637+void
638+remove_canvas_from_list(list, cv)
639+struct canvas **list;
640+struct canvas *cv;
641+{   /** Prune cv from the list.  Does not free cv.*/
642+
643+    struct canvas *pred;  /* Predecssor of cv in list. */
644+
645+    if (cv == *list ) {
646+        *list = cv -> c_next;
647+    }
648+    else {
649+        /* Find the predecessor of cv. */
650+        for (pred = *list; pred->c_next != cv; pred = pred->c_next)
651+            ASSERT(pred);
652+
653+        pred -> c_next = cv -> c_next;
654+    }
655+}
656+
657+void
658+redirect_pointers(list, old, new)
659+struct canvas *list;
660+struct canvas *old;
661+struct canvas *new;
662+{  /** For each canvas in the list, change any
663+    of its screen orientation pointers from old to new.
664+    Canvasses are not allowed to be self-referential,
665+    so set such pointers to NULL.
666+    */
667+    struct canvas *cv;
668+    for (cv=list; cv; cv = cv->c_next) {
669+        if (cv -> c_left == old)
670+            cv -> c_left = (cv==new)?NULL:new;
671+        if (cv -> c_above == old)
672+            cv -> c_above = (cv==new)?NULL:new;
673+        if (cv -> c_right == old)
674+            cv -> c_right = (cv==new)?NULL:new;
675+        if (cv -> c_below == old)
676+            cv -> c_below = (cv==new)?NULL:new;
677+    }
678+}
679+
680+struct canvas *
681+squeeze(list, target, direction, distance)
682+struct canvas *list;    /* List of canvasses to resize. */
683+struct canvas *target;  /* Canvas in the list being removed. */
684+enum directions direction;         
685+int  distance;  /* Amount to squeeze. */
686+{   /** Resize canvasses in the list so that target
687+    is shrunk by distance and other canvasses are grown in the
688+    specified direction.  If distance is 0, target
689+    is destroyed, and the value returned is
690+    the earliest canvas in the list that is grown.
691+
692+    If distance > 0, the value returned is an int,
693+    giving the amount actually sqeezed.  (This needs
694+    re-writing!)
695+    (This becomes the new region head for the region
696+    orphaned by target.)
697+
698+    TODO: this currently only implements distance == 0;
699+    */
700+
701+    struct canvas *ret;  /* The return value.*/
702+    struct canvas *cv;   /* For walking the list.*/
703+
704+    ret = NULL;
705+
706+    if (distance == 0) {
707+        for (cv = list; cv; cv = cv->c_next) {
708+            int *cv_coord, *cv_off, targ_coord;
709+            struct canvas **cv_orient, *targ_orient;
710+
711+            switch (direction) {
712+            case RIGHT:
713+                cv_orient   = &cv->c_right;
714+                cv_coord    = &cv->c_xe;
715+                cv_off      = 0;
716+                targ_coord  = target->c_xe;
717+                targ_orient = target->c_right;
718+                break;
719+            case LEFT:
720+                cv_orient   = &cv->c_left;
721+                cv_coord    = &cv->c_xs;
722+                cv_off      = &cv->c_xoff;
723+                targ_coord  = target->c_xs;
724+                targ_orient = target->c_left;
725+                break;
726+            case UP:
727+                cv_orient   = &cv->c_above;
728+                cv_coord    = &cv->c_ys;
729+                cv_off      = &cv->c_yoff;
730+                targ_coord  = target->c_ys;
731+                targ_orient = target->c_above;
732+                break;
733+            case DOWN:
734+                cv_orient   = &cv->c_below;
735+                cv_coord    = &cv->c_ye;
736+                cv_off      = 0;
737+                targ_coord  = target->c_ye;
738+                targ_orient = target->c_below;
739+                break;
740+            }
741+            if (*cv_orient == target) {
742+                *cv_coord = targ_coord;
743+                if(cv_off)
744+                    *cv_off = targ_coord;
745+                *cv_orient = targ_orient;
746+                ret = (ret) ? ret : cv;
747+            }
748+        }
749+    }
750+    else {
751+        ASSERT(distance > 0);
752+        switch (direction) {
753+        /* adjust target first. */
754+        case RIGHT:
755+            if (target->c_xe - target->c_xs + distance < MIN_WIDTH)
756+                distance = target->c_xe - target->c_xs - MIN_WIDTH;
757+            target->c_xs += distance;
758+            target->c_xoff = target -> c_xs;
759+            break;
760+        case LEFT:
761+            if (target->c_xe - target->c_xs + distance < MIN_WIDTH)
762+                distance = target->c_xe - target->c_xs - MIN_WIDTH;
763+            target->c_xe -= distance;
764+            break;
765+        case UP:
766+            if (target->c_ye - target->c_ys + distance < MIN_HEIGHT)
767+                distance = target->c_ye - target->c_ys - MIN_HEIGHT;
768+            target->c_ye -= distance;
769+            break;
770+        case DOWN:
771+            if (target->c_ye - target->c_ys + distance < MIN_HEIGHT)
772+                distance = target->c_ye - target->c_ys - MIN_HEIGHT;
773+            target->c_ys += distance;
774+            target->c_yoff = target -> c_ys;
775+            break;
776+        }
777+        for (cv = list; cv; cv = cv->c_next) {
778+            int *cv_coord, *cv_off, new_coord;
779+            struct canvas **cv_orient;
780+
781+            debug("SQUEEZE\n");
782+            debug_print_canvas(cv);
783+
784+            if (cv == target)
785+                continue;
786+
787+            switch (direction) {
788+            case RIGHT:
789+                cv_orient   = &cv->c_right;
790+                cv_coord    = &cv->c_xe;
791+                cv_off      = 0;
792+                new_coord   = cv->c_xe + distance;
793+                break;
794+            case LEFT:
795+                cv_orient   = &cv->c_left;
796+                cv_coord    = &cv->c_xs;
797+                cv_off      = &cv->c_xoff;
798+                new_coord   = cv->c_xs - distance;
799+                break;
800+            case UP:
801+                cv_orient   = &cv->c_above;
802+                cv_coord    = &cv->c_ys;
803+                cv_off      = &cv->c_yoff;
804+                new_coord   = cv->c_ys - distance;
805+                break;
806+            case DOWN:
807+                cv_orient   = &cv->c_below;
808+                cv_coord    = &cv->c_ye;
809+                cv_off      = 0;
810+                new_coord   = cv->c_ye + distance;
811+                break;
812+            }
813+            if (*cv_orient == target) {
814+                *cv_coord = new_coord;
815+                if(cv_off)
816+                    *cv_off = new_coord;
817+            }
818+        }
819+        ret = (struct canvas *) distance;
820+    }
821+
822+
823+    debug2("squeeze: target = %#x, ret = %#x\n", target, ret);
824+    return ret;
825+}
826+
827+
828+struct canvas *
829+grow_surrounding_regions(list, fore, amount)
830+    struct canvas *list;
831+    struct canvas *fore;
832+    int amount;
833 {
834-  int hh, h, i, j;
835-  struct canvas *cv, **cvpp;
836-  int did = 0;
837+    /* Grow all the regions in the list that border
838+    fore appropriately.  */
839+    struct canvas *cv;        /* For walking the list. */
840+    struct canvas *new_fore;  /* Replacement for fore. */
841 
842-  h = D_height - (D_has_hstatus == HSTATUS_LASTLINE);
843-  for (cv = D_cvlist, j = 0; cv; cv = cv->c_next)
844-    j++;
845-  if (j == 1)
846-    return;
847-  i = 0;
848-  j--;
849-  for (cvpp = &D_cvlist; (cv = *cvpp); cvpp = &cv->c_next)
850-    {
851-      if (cv == D_forecv && !did)
852-       {
853-         *cvpp = cv->c_next;
854-         FreeCanvas(cv);
855-         cv = *cvpp;
856-         D_forecv = cv ? cv : D_cvlist;
857-         D_fore = Layer2Window(D_forecv->c_layer);
858-         flayer = D_forecv->c_layer;
859-         if (cv == 0)
860+    debug("grow_surrounding_regions\n");
861+
862+    new_fore = NULL;
863+    if (amount == 0) {
864+        if (fore != list) {
865+            /* Grow the regions from above (the left). */
866+            switch (fore -> c_type) {
867+            case HORIZONTAL:
868+                if ( !(new_fore = squeeze(list, fore, DOWN, 0)))
869+                    new_fore = squeeze(list, fore, RIGHT, 0);
870+                break;
871+            case VERTICAL:   
872+                if ( !(new_fore = squeeze(list, fore, RIGHT, 0)))
873+                    new_fore = squeeze(list, fore, DOWN, 0);
874            break;
875-         did = 1;
876        }
877-      hh = h / j-- - 1;
878-      if (!captionalways && i == 0 && j == 0)
879-       hh++;
880-      cv->c_ys = i;
881-      cv->c_ye = i + hh - 1;
882-      cv->c_yoff = i;
883-      i += hh + 1;
884-      h -= hh + 1;
885     }
886+        else {  /* Grow the regions from below (the right). */
887+            switch (fore -> c_type) {
888+            case HORIZONTAL:
889+                if ( !(new_fore = squeeze(list, fore, UP, 0)))
890+                    new_fore = squeeze(list, fore, LEFT, 0);
891+                break;
892+            case VERTICAL:   
893+                if ( !(new_fore = squeeze(list, fore, LEFT, 0)))
894+                    new_fore = squeeze(list, fore, UP, 0);
895+           break;
896+       }
897+    }
898+        ASSERT (new_fore);
899+        return new_fore;
900+    }
901+}
902+
903+
904+void
905+RemCanvas()
906+{   /** Remove the foreground canvas. */
907+
908+    struct screen_region  vr; /*Canvasses in the same row/column as D_forecv.*/
909+    struct canvas *new_fore;  /* Canvas which will replace D_forecv. */
910+
911+    /* Do nothing if the foreground is the only canvas. */
912+    if (D_cvlist->c_next == NULL)
913+        return;
914+
915+    compute_region(D_forecv->c_type, &vr, D_forecv, D_cvlist);
916+
917+    debug1("RemCanvas. count = %d\n",vr.count);
918+    debug_print_all_canvasses("RemCanvas() start\n");
919+
920+    if (vr.count > 1) {  /* Resize the neighboring canvas in region. */
921+        debug2("D_forecv = %x  vr.start = %x\n",D_forecv, vr.start);
922+        /* If there is a canvas before D_forecv, then
923+        grow that canvas to take up the space. */
924+        if (D_forecv != vr.start) {
925+            struct canvas *pred;  /* Predecssor of D_forecv. */
926+            for (pred = vr.start; pred->c_next != D_forecv; )
927+                pred = pred->c_next;
928+
929+            new_fore         = pred;
930+            new_fore -> c_ye = D_forecv->c_ye;
931+            new_fore -> c_xe = D_forecv->c_xe;
932+
933+        }
934+        else {
935+            new_fore           = D_forecv -> c_next;
936+            new_fore -> c_ys   = D_forecv -> c_ys;
937+            new_fore -> c_xs   = D_forecv -> c_xs;
938+            new_fore -> c_yoff = new_fore -> c_ys;
939+            new_fore -> c_xoff = new_fore -> c_xs;
940+        }
941+    }
942+    else { /* Resize all bordering regions. */
943+        new_fore = grow_surrounding_regions( D_cvlist, D_forecv,0);
944+    }
945+    debug_print_canvas(new_fore);
946+
947+    /* Redirect all pointers in the list. */
948+    redirect_pointers(D_cvlist, D_forecv, new_fore);
949+
950+    remove_canvas_from_list(&D_cvlist, D_forecv);
951+    FreeCanvas(D_forecv);
952+    D_forecv = new_fore;
953+    D_fore   = Layer2Window(D_forecv->c_layer);
954+    flayer   = D_forecv->c_layer;
955+
956+    debug2("RemCanvas. forecv = %#x  new_fore = %#x\n", D_forecv, new_fore);
957+    debug_print_all_canvasses("RemCanvas() end.\n");
958+
959   RethinkDisplayViewports();
960   ResizeLayersToCanvases();
961 }
962 
963 void
964-OneCanvas()
965-{
966-  struct canvas *mycv = D_forecv;
967-  struct canvas *cv, **cvpp;
968+OneCanvas(list, target)
969+struct canvas **list;
970+struct canvas  *target;
971+{   /* Free all canvasses in the list except for
972+    target.  Make *list reference target. */
973+    struct canvas  *cv;
974+    struct canvas *next;
975 
976-  for (cvpp = &D_cvlist; (cv = *cvpp);)
977-    {
978-      if (cv == mycv)
979-        {
980-         cv->c_ys = 0;
981-         cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways;
982-         cv->c_yoff = 0;
983-         cvpp = &cv->c_next;
984-        }
985-      else
986-        {
987-         *cvpp = cv->c_next;
988+    debug_print_all_canvasses("OneCanvas start.\n");
989+    for (cv = *list; cv; cv = next) {
990+        next = cv -> c_next;
991+        if (cv == target) {
992+            cv -> c_xoff  = 0;
993+            cv -> c_xs    = 0;
994+            cv -> c_xe    = D_width-1;
995+            cv -> c_yoff  = 0;
996+            cv -> c_ys    = 0;
997+            cv -> c_ye    = D_height - 1 - (D_has_hstatus ==
998+                HSTATUS_LASTLINE) - captionalways;
999+            cv -> c_left  = cv->c_right = NULL;
1000+            cv -> c_above = cv->c_below = NULL;
1001+            cv -> c_next    = NULL;
1002+        } else {
1003          FreeCanvas(cv);
1004         }
1005     }
1006+    *list = target;
1007+    debug_print_all_canvasses("OneCanvas end.\n");
1008+
1009   RethinkDisplayViewports();
1010   ResizeLayersToCanvases();
1011 }
1012--- display.h.orig      2003-07-01 14:01:42.000000000 +0000
1013+++ display.h   2006-07-07 02:39:25.000000000 +0000
1014@@ -58,6 +58,11 @@ struct canvas
1015   int              c_ys;
1016   int              c_ye;
1017   struct event     c_captev;   /* caption changed event */
1018+  int              c_type;     /* which type of split created the canvas. */
1019+  struct canvas   *c_right;    /* canvas to the right. */
1020+  struct canvas   *c_left;     /* canvas to the left.  */
1021+  struct canvas   *c_above;    /* canvas above. */
1022+  struct canvas   *c_below;    /* canvas below. */
1023 };
1024 
1025 struct viewport
1026--- extern.h.orig       2003-08-22 12:27:57.000000000 +0000
1027+++ extern.h    2006-07-07 02:39:25.000000000 +0000
1028@@ -289,9 +289,9 @@ extern void  NukePending __P((void));
1029 #endif
1030 extern void  SetCanvasWindow __P((struct canvas *, struct win *));
1031 extern int   MakeDefaultCanvas __P((void));
1032-extern int   AddCanvas __P((void));
1033+extern int   AddCanvas __P((int));
1034 extern void  RemCanvas __P((void));
1035-extern void  OneCanvas __P((void));
1036+extern void  OneCanvas __P((struct canvas **, struct canvas *));
1037 extern int   RethinkDisplayViewports __P((void));
1038 extern void  RethinkViewportOffsets __P((struct canvas *));
1039 #ifdef RXVT_OSC
1040@@ -490,3 +490,16 @@ extern int   PrepareEncodedChar __P((int
1041 # endif
1042 #endif
1043 extern int   EncodeChar __P((char *, int, int, int *));
1044+extern int   compute_region __P((int,struct screen_region *, struct canvas *, struct canvas *));
1045+extern void  reset_region_types __P((struct screen_region *, int));
1046+extern void  equalize_canvas_dimensions __P((struct screen_region *));
1047+extern int   adjust_canvas_dimensions __P((struct screen_region *, struct canvas *, int));
1048+enum directions {
1049+    LEFT,
1050+    RIGHT,
1051+    UP,
1052+    DOWN
1053+};
1054+
1055+extern struct canvas * squeeze __P(( struct canvas *, struct canvas *,
1056+    enum directions, int  distance));
1057--- process.c.orig      2003-09-18 12:53:54.000000000 +0000
1058+++ process.c   2006-07-07 02:39:26.000000000 +0000
1059@@ -548,6 +548,7 @@ InitKeytab()
1060   ktab['B'].nr = RC_POW_BREAK;
1061   ktab['_'].nr = RC_SILENCE;
1062   ktab['S'].nr = RC_SPLIT;
1063+  ktab['V'].nr = RC_VERT_SPLIT;
1064   ktab['Q'].nr = RC_ONLY;
1065   ktab['X'].nr = RC_REMOVE;
1066   ktab['F'].nr = RC_FIT;
1067@@ -3649,7 +3650,11 @@ int key;
1068       break;
1069 #endif /* MULTIUSER */
1070     case RC_SPLIT:
1071-      AddCanvas();
1072+        AddCanvas(HORIZONTAL);
1073+        Activate(-1);
1074+        break;
1075+    case RC_VERT_SPLIT:
1076+        AddCanvas(VERTICAL);
1077       Activate(-1);
1078       break;
1079     case RC_REMOVE:
1080@@ -3657,7 +3662,7 @@ int key;
1081       Activate(-1);
1082       break;
1083     case RC_ONLY:
1084-      OneCanvas();
1085+      OneCanvas(&D_cvlist, D_forecv);
1086       Activate(-1);
1087       break;
1088     case RC_FIT:
1089@@ -5877,104 +5882,51 @@ static void
1090 ResizeRegions(arg)
1091 char *arg;
1092 {
1093-  struct canvas *cv;
1094-  int nreg, dsize, diff, siz;
1095+    struct screen_region  region;  /* Region in which D_forecv resides. */
1096+    int    adjusted;
1097+
1098+    /* Note: there's a nomenclature problem here.  I'm using 'region'
1099+    to mean a set of canvasses that are related geographically
1100+    in the display.  The documentation uses 'region' to refer to
1101+    a single canvas (that's the usage in the error message
1102+    below). */
1103 
1104   ASSERT(display);
1105-  for (nreg = 0, cv = D_cvlist; cv; cv = cv->c_next)
1106-    nreg++;
1107-  if (nreg < 2)
1108-    {
1109-      Msg(0, "resize: need more than one region");
1110-      return;
1111-    }
1112-  dsize = D_height - (D_has_hstatus == HSTATUS_LASTLINE);
1113-  if (*arg == '=')
1114-    {
1115-      /* make all regions the same height */
1116-      int h = dsize;
1117-      int hh, i = 0;
1118-      for (cv = D_cvlist; cv; cv = cv->c_next)
1119-       {
1120-         hh = h / nreg-- - 1;
1121-         cv->c_ys = i;
1122-         cv->c_ye = i + hh - 1;
1123-         cv->c_yoff = i;
1124-         i += hh + 1;
1125-         h -= hh + 1;
1126-        }
1127-      RethinkDisplayViewports();
1128-      ResizeLayersToCanvases();
1129+    if (D_cvlist -> c_next == NULL) {
1130+        Msg(0, "More than one region required.");
1131       return;
1132     }
1133-  siz = D_forecv->c_ye - D_forecv->c_ys + 1;
1134-  if (*arg == '+')
1135-    diff = atoi(arg + 1);
1136-  else if (*arg == '-')
1137-    diff = -atoi(arg + 1);
1138-  else if (!strcmp(arg, "min"))
1139-    diff = 1 - siz;
1140-  else if (!strcmp(arg, "max"))
1141-    diff = dsize - (nreg - 1) * 2 - 1 - siz;
1142-  else
1143-    diff = atoi(arg) - siz;
1144-  if (diff == 0)
1145-    return;
1146-  if (siz + diff < 1)
1147-    diff = 1 - siz;
1148-  if (siz + diff > dsize - (nreg - 1) * 2 - 1)
1149-    diff = dsize - (nreg - 1) * 2 - 1 - siz;
1150-  if (diff == 0 || siz + diff < 1)
1151-    return;
1152 
1153-  if (diff < 0)
1154-    {
1155-      if (D_forecv->c_next)
1156-       {
1157-         D_forecv->c_ye += diff;
1158-         D_forecv->c_next->c_ys += diff;
1159-         D_forecv->c_next->c_yoff += diff;
1160-       }
1161-      else
1162-       {
1163-         for (cv = D_cvlist; cv; cv = cv->c_next)
1164-           if (cv->c_next == D_forecv)
1165+    compute_region(D_forecv->c_type, &region, D_forecv, D_cvlist);
1166+    reset_region_types(&region, D_forecv->c_type);
1167+
1168+    if (region.count > 1) {
1169+        switch (*arg) {
1170+        case '=': equalize_canvas_dimensions(&region); break;
1171+        case '-': adjust_canvas_dimensions(&region, D_forecv, -atoi(arg+1)); break;
1172+        case '+':
1173+            adjusted = adjust_canvas_dimensions(&region, D_forecv, atoi(arg+1));
1174              break;
1175-         ASSERT(cv);
1176-         cv->c_ye -= diff;
1177-         D_forecv->c_ys -= diff;
1178-         D_forecv->c_yoff -= diff;
1179-       }
1180-    }
1181-  else
1182-    {
1183-      int s, i = 0, found = 0, di = diff, d2;
1184-      s = dsize - (nreg - 1) * 2 - 1 - siz;
1185-      for (cv = D_cvlist; cv; i = cv->c_ye + 2, cv = cv->c_next)
1186-       {
1187-         if (cv == D_forecv)
1188-           {
1189-             cv->c_ye = i + (cv->c_ye - cv->c_ys) + diff;
1190-             cv->c_yoff -= cv->c_ys - i;
1191-             cv->c_ys = i;
1192-             found = 1;
1193-             continue;
1194+        case 'm':
1195+            if (!strcmp(arg, "min"))
1196+                adjust_canvas_dimensions(&region, D_forecv, -region.expanse);
1197+            else if (!strcmp(arg, "max"))
1198+                adjust_canvas_dimensions(&region, D_forecv, region.expanse);
1199+             break;
1200+        default:
1201+            Msg(0, "resize: arguments munged");
1202            }
1203-         s -= cv->c_ye - cv->c_ys;
1204-         if (!found)
1205-           {
1206-             if (s >= di)
1207-               continue;
1208-             d2 = di - s;
1209            }
1210-         else
1211-           d2 = di > cv->c_ye - cv->c_ys ? cv->c_ye - cv->c_ys : di;
1212-         di -= d2;
1213-         cv->c_ye = i + (cv->c_ye - cv->c_ys) - d2;
1214-         cv->c_yoff -= cv->c_ys - i;
1215-         cv->c_ys = i;
1216+    else {
1217+        /*TODO Need to expand this canvas into surrounding regions...*/
1218+        switch(*arg) {
1219+        case '=': Msg(0, "More than one region required."); return;
1220+        // http://lists.gnu.org/archive/html/screen-users/2006-06/msg00012.html
1221+        // case '-': squeeze(D_cvlist, D_forecv, RIGHT, atoi(arg+1)); break;
1222+        default : Msg(0, "More than one region required."); return;
1223         }
1224     }
1225+
1226   RethinkDisplayViewports();
1227   ResizeLayersToCanvases();
1228 }
1229--- screen.h.orig       2003-08-22 12:28:43.000000000 +0000
1230+++ screen.h    2006-07-07 02:39:26.000000000 +0000
1231@@ -288,8 +288,25 @@ struct baud_values
1232   int sym;     /* symbol defined in ttydev.h */
1233 };
1234 
1235+struct screen_region {
1236+    /* This is a group of canvasses that are all in
1237+    the same column or row. */
1238+    struct canvas *start;   /* First canvas in the region. */
1239+    struct canvas *end;     /* Last canvas in the region. */
1240+    int            expanse; /* Range in the appropriate direction. */
1241+    int            count;   /* Number of canvasses in the region. */
1242+    int            type;    /* HORIZONTAL or VERTICAL. */
1243+    int            xs;      /* starting x coordinate */
1244+    int            xe;      /* ending   x coordinate */
1245+    int            ys;      /* starting y coordinate */
1246+    int            ye;      /* ending   y coordinate */
1247+};
1248+
1249 /*
1250  * windowlist orders
1251  */
1252 #define WLIST_NUM 0
1253 #define WLIST_MRU 1
1254+
1255+#define HORIZONTAL 0
1256+#define VERTICAL 1