Date: Mon, 29 Jan 2007 15:01:14 +0100 From: Jeremie Le Hen <jeremie@le-hen.org> To: freebsd-ports@FreeBSD.org Cc: jeremie@le-hen.org, cy@FreeBSD.org Subject: Vertical split patch in sysutils/screen Message-ID: <20070129140114.GA64768@obiwan.tataz.chchile.org>
next in thread | raw e-mail | index | archive | help
--CE+1k2dSO48ffgeK Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Hi, (Please Cc: me when you reply.) I've integrated the "vertical split" patch for GNU Screen into the sysutils/screen port, toggled with WITH_VERTICAL_SPLIT knob. The original patch can be found here: http://fungi.yuggoth.org/vsp4s/ I don't know if anyone is interested, so I simply post it here for the record. Regards, -- Jeremie Le Hen < jeremie at le-hen dot org >< ttz at chchile dot org > --CE+1k2dSO48ffgeK Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="screen-vertical_split.diff" ? screen-vertital_split.diff Index: Makefile =================================================================== RCS file: /home/ncvs/ports/sysutils/screen/Makefile,v retrieving revision 1.65 diff -u -p -u -p -r1.65 Makefile --- Makefile 27 Dec 2006 16:51:21 -0000 1.65 +++ Makefile 29 Jan 2007 13:23:17 -0000 @@ -46,6 +46,10 @@ CFLAGS+= -DNONETHACK EXTRA_PATCHES+= ${.CURDIR}/files/opt-cjkwidth .endif +.if defined(WITH_VERTICAL_SPLIT) +EXTRA_PATCHES+= ${PATCHDIR}/opt-vertical_split_0.3.diff +.endif + post-patch: @${RM} ${WRKSRC}/doc/screen.info* Index: files/opt-vertical_split_0.3.diff =================================================================== RCS file: files/opt-vertical_split_0.3.diff diff -N files/opt-vertical_split_0.3.diff --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ files/opt-vertical_split_0.3.diff 29 Jan 2007 13:23:17 -0000 @@ -0,0 +1,1262 @@ +diff -BENbdpru comm.c comm.c +--- comm.c 2003-09-08 14:25:08.000000000 +0000 ++++ comm.c 2006-07-07 02:39:24.000000000 +0000 +@@ -309,6 +309,7 @@ struct comm comms[RC_LAST + 1] = + { "vbellwait", ARGS_1 }, + { "verbose", ARGS_01 }, + { "version", ARGS_0 }, ++ { "vert_split", NEED_DISPLAY|ARGS_0 }, + { "wall", NEED_DISPLAY|ARGS_1}, + { "width", ARGS_0123 }, + { "windowlist", NEED_DISPLAY|ARGS_012 }, +diff -BENbdpru display.c display.c +--- display.c 2003-12-05 13:45:41.000000000 +0000 ++++ display.c 2006-07-07 02:39:26.000000000 +0000 +@@ -476,65 +476,306 @@ struct canvas *cv; + free(cv); + } + ++struct canvas * ++get_new_canvas(target) ++struct canvas *target; ++{ /** Allocate a new canvas, and assign it characteristics ++ equal to those of target. */ ++ struct canvas *cv; ++ ++ if ((cv = (struct canvas *) calloc(1, sizeof *cv)) == 0) ++ return NULL; ++ ++ cv -> c_xs = target -> c_xs; ++ cv -> c_xe = target -> c_xe; ++ cv -> c_ys = target -> c_ys; ++ cv -> c_ye = target -> c_ye; ++ cv -> c_xoff = target -> c_xoff; ++ cv -> c_yoff = target -> c_yoff; ++ cv -> c_display = target -> c_display; ++ cv -> c_vplist = 0; ++ cv -> c_captev.type = EV_TIMEOUT; ++ cv -> c_captev.data = (char *) cv; ++ cv -> c_captev.handler = cv_winid_fn; ++ ++ cv -> c_blank.l_cvlist = cv; ++ cv -> c_blank.l_width = cv->c_xe - cv->c_xs + 1; ++ cv -> c_blank.l_height = cv->c_ye - cv->c_ys + 1; ++ cv -> c_blank.l_x = cv->c_blank.l_y = 0; ++ cv -> c_blank.l_layfn = &BlankLf; ++ cv -> c_blank.l_data = 0; ++ cv -> c_blank.l_next = 0; ++ cv -> c_blank.l_bottom = &cv->c_blank; ++ cv -> c_blank.l_blocking = 0; ++ cv -> c_layer = &cv->c_blank; ++ cv -> c_lnext = 0; ++ ++ cv -> c_left = target -> c_left; ++ cv -> c_right = target -> c_right; ++ cv -> c_above = target -> c_above; ++ cv -> c_below = target -> c_below; ++ ++ return cv; ++} ++ + int +-AddCanvas() +-{ +- int hh, h, i, j; +- struct canvas *cv, **cvpp; ++share_limits( type, cv0, cv1) ++int type; /* HORIZONTAL or VERTICAL */ ++struct canvas *cv0; /* canvas to compare against. */ ++struct canvas *cv1; /* canvas to compare against. */ ++{ /** Return non-zero if the two canvasses share limits. ++ (ie, their horizontal or veritcal boundaries are the same) ++ */ ++ switch (type) { ++ case HORIZONTAL: ++ return cv0 -> c_xs == cv1 -> c_xs && cv0->c_xe == cv1 -> c_xe; ++ case VERTICAL: ++ return cv0 -> c_ys == cv1 -> c_ys && cv0->c_ye == cv1 -> c_ye; ++ } ++ ASSERT(0); ++ return 0; ++} + +- for (cv = D_cvlist, j = 0; cv; cv = cv->c_next) +- j++; +- j++; /* new canvas */ +- h = D_height - (D_has_hstatus == HSTATUS_LASTLINE); +- if (h / j <= 1) +- return -1; ++int ++compute_region(type, a, focus, list) ++int type; /* 0 - horizontal, 1 - vertical */ ++struct screen_region *a; /* Return value. */ ++struct canvas *focus; /* Canvas to compute around. */ ++struct canvas *list; /* List of all canvasses. */ ++{ /** Find the start and end of the screen region.*/ ++ /* ++ I'm using the term 'region' here differently ++ than elsewhere. Elsewhere, 'region' is synonymous ++ with 'canvas', but I am using it to denote ++ a collection of related canvasses. + +- for (cv = D_cvlist; cv; cv = cv->c_next) +- if (cv == D_forecv) ++ Suppose the screen currently looks ++ like this: ++ --------------------------- ++ | 0 | 1 | 2 | ++ --------------------------- ++ | 3 | 4 | 5 | ++ --------------------------- ++ | 6 | ++ --------------------------- ++ | 7 | 8 | 9 | ++ --------------------------- ++ Where there are 10 entries in D_cvlist. ++ Canvasses 0,1,2 are in the same region, as ++ are cavasses 1 and 4. We need to be careful not to ++ lump 1 and 4 together w/8. The ++ type of the region containing 0,1,2 is ++ VERTICAL, since each canvas is created ++ via a vertical split. ++ ++ Throughout, I'm assuming that canvasses ++ are created so that any region will ++ be contiguous in D_cvlist. ++ ++ Note: this was written before the screen ++ orientation members (c_left, c_above, c_below, ++ c_right) were added to the struct canvas. ++ Might want to rewrite this to use those. ++ ++ Written by Bill Pursell, 23/12/2005 ++ */ ++ ++ struct canvas *cv; /* Entry in list. */ ++ int seen_focus; /* Flag used when walking the list. */ ++ ++ seen_focus = 0; ++ a->count = 0; ++ a->type = type; ++ ++ if (type == HORIZONTAL) { ++ a->xs = focus -> c_xs; ++ a->xe = focus -> c_xe; ++ a->ys = -1; ++ } ++ if (type == VERTICAL) { ++ a->ys = focus -> c_ys; ++ a->ye = focus -> c_ye; ++ a->xs = -1; ++ } ++ /* Count the canvasses in the same region as the ++ canvas with the focus, and find the limits of the region. */ ++ for (cv = list; cv; cv = cv->c_next) { ++ if (cv == focus) ++ seen_focus = 1; ++ if (share_limits( type, cv, focus)) { ++ debug2("cv = %x %s\n", cv, (cv == focus)? "FORE":""); ++ debug2("x range: %d - %d\n", cv->c_xs, cv->c_xe); ++ debug2("y range: %d - %d\n", cv->c_ys, cv->c_ye); ++ switch (type) { ++ case HORIZONTAL : ++ if (a->ys == -1) { ++ a->ys = cv -> c_ys; ++ a->start = cv; ++ } ++ a->ye = cv -> c_ye; + break; +- ASSERT(cv); +- cvpp = &cv->c_next; ++ case VERTICAL: ++ if (a->xs == -1) { ++ a->xs = cv -> c_xs; ++ a->start = cv; ++ } ++ a->xe = cv -> c_xe; ++ break; ++ } + +- if ((cv = (struct canvas *)calloc(1, sizeof *cv)) == 0) +- return -1; ++ a->end = cv; ++ a->count++; ++ } ++ if (!share_limits(type, cv, focus) || cv -> c_next == NULL) { ++ if (seen_focus) { ++ debug2("x range of Region: %d-%d\n", a->xs, a->xe); ++ debug2("y range of Region: %d-%d\n", a->ys, a->ye); ++ break; ++ } ++ else { ++ switch(type) { ++ case HORIZONTAL: a->ys = -1; break; ++ case VERTICAL : a->xs = -1; break; ++ } ++ a->count = 0; ++ } ++ } ++ } + +- cv->c_xs = 0; +- cv->c_xe = D_width - 1; +- cv->c_ys = 0; +- cv->c_ye = D_height - 1; +- cv->c_xoff = 0; +- cv->c_yoff = 0; +- cv->c_display = display; +- cv->c_vplist = 0; +- cv->c_captev.type = EV_TIMEOUT; +- cv->c_captev.data = (char *)cv; +- cv->c_captev.handler = cv_winid_fn; ++ switch (type) { ++ case HORIZONTAL: ++ a->expanse = a->ye - a->ys + 1; ++ ASSERT(a->expanse <= D_height - (D_has_hstatus == HSTATUS_LASTLINE)); ++ break; ++ case VERTICAL: ++ a->expanse = a->xe - a->xs + 1; ++ ASSERT(a->expanse <= D_width); ++ break; ++ } ++ ASSERT(seen_focus); ++} + +- cv->c_blank.l_cvlist = cv; +- cv->c_blank.l_width = cv->c_xe - cv->c_xs + 1; +- cv->c_blank.l_height = cv->c_ye - cv->c_ys + 1; +- cv->c_blank.l_x = cv->c_blank.l_y = 0; +- cv->c_blank.l_layfn = &BlankLf; +- cv->c_blank.l_data = 0; +- cv->c_blank.l_next = 0; +- cv->c_blank.l_bottom = &cv->c_blank; +- cv->c_blank.l_blocking = 0; +- cv->c_layer = &cv->c_blank; +- cv->c_lnext = 0; ++void ++reset_region_types(region, type) ++struct screen_region *region; ++int type; ++{ /** Set c_type of all the canvasses in the region to type. */ + +- cv->c_next = *cvpp; +- *cvpp = cv; ++ struct canvas *cv; + +- i = 0; +- for (cv = D_cvlist; cv; cv = cv->c_next) +- { +- hh = h / j-- - 1; +- cv->c_ys = i; +- cv->c_ye = i + hh - 1; +- cv->c_yoff = i; +- i += hh + 1; +- h -= hh + 1; ++ for (cv = region->start; cv != region->end->c_next; cv = cv->c_next) { ++ #ifdef DEBUG ++ switch(type) { ++ case HORIZONTAL: ++ ASSERT (cv->c_xs == region -> xs && cv->c_xe == region -> xe); ++ break; ++ case VERTICAL: ++ ASSERT (cv->c_ys == region -> ys && cv->c_ye == region -> ye); ++ break; ++ default: ++ ASSERT(0); ++ } ++ #endif ++ cv -> c_type = type; + } ++} ++ ++void ++debug_print_canvas(cv) ++struct canvas *cv; ++{ /** Print cv to the debug file. */ ++#ifdef DEBUG ++ debug2("%x %s\n", cv, (cv == D_forecv)?" HAS FOCUS":""); ++ debug2(" above: %x below: %x\n", cv->c_above, cv->c_below); ++ debug2(" left: %x right: %x\n", cv->c_left, cv->c_right); ++ debug3(" x range: %2d-%2d, xoff = %d\n", ++ cv->c_xs, cv->c_xe, cv->c_xoff); ++ debug3(" y range: %2d-%2d yoff = %d\n", ++ cv->c_ys, cv->c_ye, cv->c_yoff); ++ debug2(" next: %x type: %d\n", cv->c_next, cv->c_type); ++#endif ++} ++ ++void ++debug_print_all_canvasses(header) ++char *header; ++{ /** Print the dimensions of all the canvasses ++ in the current display to the debug file. Precede ++ with a line containing the header message. */ ++ #ifdef DEBUG ++ struct canvas *cv; ++ char message[BUFSIZ]; ++ ++ sprintf(message, "%10s %5d: ",__FILE__ , __LINE__); ++ strcat (message, header); ++ fprintf(dfp, message); ++ fflush(dfp); ++ for (cv = D_cvlist; cv; cv = cv->c_next) { ++ debug_print_canvas(cv); ++ } ++ #endif ++ return; ++} ++ ++set_internal_orientation(region) ++struct screen_region *region; ++{ /** Set the orientation for canvasses inside the region. */ ++ ++ struct canvas *cv; ++ ++ for (cv = region -> start; cv != region -> end; cv = cv->c_next) { ++ ASSERT (cv -> c_type == region -> type); ++ switch (region->type) { ++ case VERTICAL: ++ cv -> c_right = cv -> c_next; ++ cv -> c_next -> c_left = cv; ++ break; ++ case HORIZONTAL: ++ cv -> c_below = cv -> c_next; ++ cv -> c_next -> c_above = cv; ++ break; ++ } ++ } ++} ++ ++ ++int ++AddCanvas(type) ++int type; /* Horizontal or Vertical. */ ++{ /** Add a new canvas, via a split. */ ++ ++ struct canvas *cv; /* Index into D_cvlist. */ ++ struct screen_region vr; /* Canvasses in the same row/column as the ++ canvas with the focus. */ ++ ++ compute_region(type, &vr, D_forecv, D_cvlist); ++ ++ /* Return if the region isn't big enough to split. */ ++ if (vr.expanse / vr.count <= 1) ++ return -1; ++ ++ /* Allocate a new canvas. */ ++ if ( (cv = get_new_canvas(D_forecv)) == NULL) ++ return -1; ++ ++ /* Set the type. */ ++ cv -> c_type = D_forecv -> c_type = type; ++ ++ /* Increment the canvas count to account for the one we will add. */ ++ vr.count++; ++ ++ debug_print_all_canvasses("AddCanvas start.\n"); ++ ++ /* Insert the new canvas after the current foreground. */ ++ cv -> c_next = D_forecv->c_next; ++ D_forecv -> c_next = cv; ++ if (vr.end == D_forecv) ++ vr.end = cv; ++ ++ set_internal_orientation(&vr); ++ equalize_canvas_dimensions(&vr); ++ ++ debug_print_all_canvasses("AddCanvas end.\n"); + + RethinkDisplayViewports(); + ResizeLayersToCanvases(); +@@ -542,67 +783,595 @@ AddCanvas() + } + + void +-RemCanvas() ++get_endpoints(cv, start, end, off) ++struct canvas *cv; ++int **start; ++int **end; ++int **off; ++{ /** Set *start, *end, and *off appropriate with cv->c_type. */ ++ switch (cv->c_type) { ++ case HORIZONTAL: ++ if (start) *start = &cv -> c_ys; ++ if (end) *end = &cv -> c_ye; ++ if (off) *off = &cv -> c_yoff; ++ break; ++ case VERTICAL: ++ if (start) *start = &cv -> c_xs; ++ if (end) *end = &cv -> c_xe; ++ if (off) *off = &cv -> c_xoff; ++ break; ++ default: ASSERT(0); ++ } ++} ++ ++#define MIN_HEIGHT 1 ++#define MIN_WIDTH 5 ++ ++int ++adjust_canvas_dimensions(vr, target, amount) ++struct screen_region *vr; ++struct canvas *target; ++int amount; ++{ /** Modify the size of target by amount. */ ++ ++ /* Other canvasses in the region will gain or lose ++ space to accomodate the change. Return ++ the number of rows/columns by which the size ++ of target is succesfully enlarged. (if amount <= 0, ++ return 0) */ ++ ++ struct canvas *this; /* for walking the list. */ ++ struct canvas *prev; /* for walking the list backwards. */ ++ int adjusted; /* Amount already re-allocated. */ ++ int *start, *end, *off; /* c->c_{x,y}s, c->c_{x,y}e, and c->c_{x,y}off */ ++ int minimum, space; ++ ++ debug1("adjust: amount = %d\n", amount); ++ debug_print_all_canvasses("ADJUST \n"); ++ ++ ASSERT(vr->count > 1); ++ ++ if (amount == 0) ++ return 0; ++ ++ switch(vr->type) { ++ case HORIZONTAL: minimum = MIN_HEIGHT; space = 2; break; ++ case VERTICAL: minimum = MIN_WIDTH; space = 1; break; ++ default: ASSERT(0); ++ } ++ ++ if (amount < 0) { ++ debug_print_all_canvasses("PREADJUST\n"); ++ ++ get_endpoints(target, &start, &end, &off); ++ if (target == vr -> start) { ++ *end += amount; ++ ++ if (*end < *start + minimum) ++ *end = *start + minimum; ++ ++ get_endpoints(target->c_next, &start, 0, &off); ++ *start = *off = *end + space; ++ ++ debug_print_all_canvasses("POSTADJUST\n\n"); ++ } ++ else { ++ for (prev = vr->start; prev->c_next != target; prev = prev->c_next) ++ ; ++ ASSERT(prev && prev -> c_next == target); ++ ++ *start -= amount; ++ if (*start > *end - minimum) ++ *start = *end - minimum; ++ get_endpoints(prev, 0, &end, 0); ++ *end = *start - space; ++ } ++ return 0; ++ } ++ ++ ASSERT (amount > 0); ++ ++ /* Reallocate space from canvasses below target. */ ++ this = vr -> end; ++ adjusted = 0; ++ while ( adjusted < amount) { ++ int this_amount; /* amount this canvas can yield. */ ++ struct canvas *cv; /* For walking lists. */ ++ ++ if (this == target) ++ break; ++ ++ get_endpoints(this, &start, &end, 0); ++ switch (vr->type) { ++ case HORIZONTAL: this_amount = *end - *start - MIN_HEIGHT; break; ++ case VERTICAL: this_amount = *end - *start - MIN_WIDTH; break; ++ default: ASSERT(0); ++ } ++ ++ if (this_amount > amount - adjusted) ++ this_amount = amount - adjusted; ++ ++ debug("target:\n"); ++ debug_print_canvas(target); ++ ++ debug("this:\n"); ++ debug_print_canvas(this); ++ ++ /* Move all canvasses between target and this by this_amount. */ ++ for (cv = target; cv != this; cv = cv -> c_next) { ++ debug1("this_amount = %d\n", this_amount); ++ debug_print_canvas(cv); ++ ++ get_endpoints(cv, &start, &end, 0); ++ *end += this_amount; ++ get_endpoints(cv->c_next, &start, &end, &off); ++ *start += this_amount; ++ *off = *start; ++ } ++ adjusted += this_amount; ++ debug1("adjusted: %d\n", adjusted); ++ ++ debug("target:\n"); ++ debug_print_canvas(target); ++ ++ debug("this:\n"); ++ debug_print_canvas(this); ++ ++ ++ /* Get the previous canvas. TODO: include back pointers ++ in struct canvas(?). */ ++ for (prev = vr->start; prev->c_next != this; prev = prev->c_next) ++ ASSERT(prev); ++ this = prev; ++ } ++ debug1("adjusted = %d\n", adjusted); ++ if (adjusted == amount || target == vr->start) ++ return adjusted; ++ ++ /* Re-allocate space from canvasses above target. */ ++ ASSERT(this == target); ++ for (prev = vr->start; prev->c_next != this; prev = prev->c_next) ++ ASSERT(prev); ++ this = prev; ++ ++ while (adjusted < amount) { ++ int this_amount; /* amount this canvas can yield. */ ++ struct canvas *cv; /* For walking lists. */ ++ ++ get_endpoints(this, &start, &end, 0); ++ switch (vr->type) { ++ case HORIZONTAL: this_amount = *end - *start - MIN_HEIGHT; break; ++ case VERTICAL: this_amount = *end - *start - MIN_WIDTH; break; ++ default: ASSERT(0); ++ } ++ ++ if (this_amount > amount - adjusted) ++ this_amount = amount - adjusted; ++ ++ /* Move all canvasses between this and target by this_amount. */ ++ for (cv = this; cv != target; cv = cv -> c_next) { ++ ASSERT(cv); ++ debug1("this_amount = %d\n", this_amount); ++ debug_print_canvas(cv); ++ debug("NEXT:\n"); ++ debug_print_canvas(cv->c_next); ++ ++ debug("getend:\n"); ++ get_endpoints(cv, &start, &end, 0); ++ ASSERT(end && start ); ++ ASSERT(start); ++ ASSERT(*end >= this_amount); ++ *end -= this_amount; ++ ASSERT(*end > *start); ++ ++ debug("getend:\n"); ++ ASSERT(cv->c_next); ++ get_endpoints(cv->c_next, &start, &end, &off); ++ ASSERT(start && off); ++ ASSERT(*start >= this_amount); ++ ASSERT(*start == *off); ++ *start -= this_amount; ++ *off = *start; ++ ++ debug("adjusted\n"); ++ debug_print_canvas(cv); ++ debug("NEXT:\n"); ++ debug_print_canvas(cv->c_next); ++ debug("\n"); ++ } ++ adjusted += this_amount; ++ ++ if (this == vr->start) ++ break; ++ ++ for (prev = vr->start; prev->c_next != this; prev = prev->c_next) ++ ASSERT(prev); ++ this = prev; ++ } ++ debug1("returning: %d\n", adjusted); ++ return adjusted; ++} ++ ++void ++equalize_canvas_dimensions(vr) ++struct screen_region *vr; ++{ /** Reset the size of each canvas in the region. */ ++ ++ struct canvas *cv; /* for walking the list. */ ++ int this_size; /* new size of cv */ ++ int this_start; /* Start coordinate for current canvas. */ ++ ++ debug("equalize\n"); ++ ++ debug2("vr start = %#x, vr end = %#x\n", vr->start, vr->end); ++ ++ switch(vr->type) { ++ case VERTICAL: this_start = vr->xs; break; ++ case HORIZONTAL: this_start = vr->ys; break; ++ } ++ ++ for (cv = vr->start ; ; cv = cv->c_next) { ++ ASSERT(cv); ++ ++ /* For the horizontal split, leave space for a status line. */ ++ this_size = vr->expanse / vr->count - (vr->type == HORIZONTAL); ++ ++ /* Give any additional available rows/columns to the foreground. */ ++ if (cv == D_forecv) ++ this_size += vr->expanse % vr->count; ++ ++ debug_print_canvas(cv); ++ debug2("cv type = %d, vr type = %d\n", cv->c_type, vr->type); ++ ASSERT(cv -> c_type == vr->type); ++ ++ switch(vr->type) { ++ case VERTICAL: ++ cv -> c_xs = cv -> c_xoff = this_start; ++ cv -> c_xe = this_start + this_size - 1; ++ this_start += this_size; ++ break; ++ case HORIZONTAL: ++ if (cv == vr->end && cv->c_ye == D_height-1- ++ (D_has_hstatus == HSTATUS_LASTLINE)) ++ this_size += 1; /* Don't make space for status line ++ in the bottom region (it already has one). */ ++ ++ cv -> c_ys = cv -> c_yoff = this_start; ++ cv -> c_ye = this_start + this_size - 1; ++ this_start += this_size + 1; /* add one for status line. */ ++ break; ++ } ++ if (cv == vr->end) ++ break; ++ } ++} ++ ++void ++remove_canvas_from_list(list, cv) ++struct canvas **list; ++struct canvas *cv; ++{ /** Prune cv from the list. Does not free cv.*/ ++ ++ struct canvas *pred; /* Predecssor of cv in list. */ ++ ++ if (cv == *list ) { ++ *list = cv -> c_next; ++ } ++ else { ++ /* Find the predecessor of cv. */ ++ for (pred = *list; pred->c_next != cv; pred = pred->c_next) ++ ASSERT(pred); ++ ++ pred -> c_next = cv -> c_next; ++ } ++} ++ ++void ++redirect_pointers(list, old, new) ++struct canvas *list; ++struct canvas *old; ++struct canvas *new; ++{ /** For each canvas in the list, change any ++ of its screen orientation pointers from old to new. ++ Canvasses are not allowed to be self-referential, ++ so set such pointers to NULL. ++ */ ++ struct canvas *cv; ++ for (cv=list; cv; cv = cv->c_next) { ++ if (cv -> c_left == old) ++ cv -> c_left = (cv==new)?NULL:new; ++ if (cv -> c_above == old) ++ cv -> c_above = (cv==new)?NULL:new; ++ if (cv -> c_right == old) ++ cv -> c_right = (cv==new)?NULL:new; ++ if (cv -> c_below == old) ++ cv -> c_below = (cv==new)?NULL:new; ++ } ++} ++ ++struct canvas * ++squeeze(list, target, direction, distance) ++struct canvas *list; /* List of canvasses to resize. */ ++struct canvas *target; /* Canvas in the list being removed. */ ++enum directions direction; ++int distance; /* Amount to squeeze. */ ++{ /** Resize canvasses in the list so that target ++ is shrunk by distance and other canvasses are grown in the ++ specified direction. If distance is 0, target ++ is destroyed, and the value returned is ++ the earliest canvas in the list that is grown. ++ ++ If distance > 0, the value returned is an int, ++ giving the amount actually sqeezed. (This needs ++ re-writing!) ++ (This becomes the new region head for the region ++ orphaned by target.) ++ ++ TODO: this currently only implements distance == 0; ++ */ ++ ++ struct canvas *ret; /* The return value.*/ ++ struct canvas *cv; /* For walking the list.*/ ++ ++ ret = NULL; ++ ++ if (distance == 0) { ++ for (cv = list; cv; cv = cv->c_next) { ++ int *cv_coord, *cv_off, targ_coord; ++ struct canvas **cv_orient, *targ_orient; ++ ++ switch (direction) { ++ case RIGHT: ++ cv_orient = &cv->c_right; ++ cv_coord = &cv->c_xe; ++ cv_off = 0; ++ targ_coord = target->c_xe; ++ targ_orient = target->c_right; ++ break; ++ case LEFT: ++ cv_orient = &cv->c_left; ++ cv_coord = &cv->c_xs; ++ cv_off = &cv->c_xoff; ++ targ_coord = target->c_xs; ++ targ_orient = target->c_left; ++ break; ++ case UP: ++ cv_orient = &cv->c_above; ++ cv_coord = &cv->c_ys; ++ cv_off = &cv->c_yoff; ++ targ_coord = target->c_ys; ++ targ_orient = target->c_above; ++ break; ++ case DOWN: ++ cv_orient = &cv->c_below; ++ cv_coord = &cv->c_ye; ++ cv_off = 0; ++ targ_coord = target->c_ye; ++ targ_orient = target->c_below; ++ break; ++ } ++ if (*cv_orient == target) { ++ *cv_coord = targ_coord; ++ if(cv_off) ++ *cv_off = targ_coord; ++ *cv_orient = targ_orient; ++ ret = (ret) ? ret : cv; ++ } ++ } ++ } ++ else { ++ ASSERT(distance > 0); ++ switch (direction) { ++ /* adjust target first. */ ++ case RIGHT: ++ if (target->c_xe - target->c_xs + distance < MIN_WIDTH) ++ distance = target->c_xe - target->c_xs - MIN_WIDTH; ++ target->c_xs += distance; ++ target->c_xoff = target -> c_xs; ++ break; ++ case LEFT: ++ if (target->c_xe - target->c_xs + distance < MIN_WIDTH) ++ distance = target->c_xe - target->c_xs - MIN_WIDTH; ++ target->c_xe -= distance; ++ break; ++ case UP: ++ if (target->c_ye - target->c_ys + distance < MIN_HEIGHT) ++ distance = target->c_ye - target->c_ys - MIN_HEIGHT; ++ target->c_ye -= distance; ++ break; ++ case DOWN: ++ if (target->c_ye - target->c_ys + distance < MIN_HEIGHT) ++ distance = target->c_ye - target->c_ys - MIN_HEIGHT; ++ target->c_ys += distance; ++ target->c_yoff = target -> c_ys; ++ break; ++ } ++ for (cv = list; cv; cv = cv->c_next) { ++ int *cv_coord, *cv_off, new_coord; ++ struct canvas **cv_orient; ++ ++ debug("SQUEEZE\n"); ++ debug_print_canvas(cv); ++ ++ if (cv == target) ++ continue; ++ ++ switch (direction) { ++ case RIGHT: ++ cv_orient = &cv->c_right; ++ cv_coord = &cv->c_xe; ++ cv_off = 0; ++ new_coord = cv->c_xe + distance; ++ break; ++ case LEFT: ++ cv_orient = &cv->c_left; ++ cv_coord = &cv->c_xs; ++ cv_off = &cv->c_xoff; ++ new_coord = cv->c_xs - distance; ++ break; ++ case UP: ++ cv_orient = &cv->c_above; ++ cv_coord = &cv->c_ys; ++ cv_off = &cv->c_yoff; ++ new_coord = cv->c_ys - distance; ++ break; ++ case DOWN: ++ cv_orient = &cv->c_below; ++ cv_coord = &cv->c_ye; ++ cv_off = 0; ++ new_coord = cv->c_ye + distance; ++ break; ++ } ++ if (*cv_orient == target) { ++ *cv_coord = new_coord; ++ if(cv_off) ++ *cv_off = new_coord; ++ } ++ } ++ ret = (struct canvas *) distance; ++ } ++ ++ ++ debug2("squeeze: target = %#x, ret = %#x\n", target, ret); ++ return ret; ++} ++ ++ ++struct canvas * ++grow_surrounding_regions(list, fore, amount) ++ struct canvas *list; ++ struct canvas *fore; ++ int amount; + { +- int hh, h, i, j; +- struct canvas *cv, **cvpp; +- int did = 0; ++ /* Grow all the regions in the list that border ++ fore appropriately. */ ++ struct canvas *cv; /* For walking the list. */ ++ struct canvas *new_fore; /* Replacement for fore. */ + +- h = D_height - (D_has_hstatus == HSTATUS_LASTLINE); +- for (cv = D_cvlist, j = 0; cv; cv = cv->c_next) +- j++; +- if (j == 1) +- return; +- i = 0; +- j--; +- for (cvpp = &D_cvlist; (cv = *cvpp); cvpp = &cv->c_next) +- { +- if (cv == D_forecv && !did) +- { +- *cvpp = cv->c_next; +- FreeCanvas(cv); +- cv = *cvpp; +- D_forecv = cv ? cv : D_cvlist; +- D_fore = Layer2Window(D_forecv->c_layer); +- flayer = D_forecv->c_layer; +- if (cv == 0) ++ debug("grow_surrounding_regions\n"); ++ ++ new_fore = NULL; ++ if (amount == 0) { ++ if (fore != list) { ++ /* Grow the regions from above (the left). */ ++ switch (fore -> c_type) { ++ case HORIZONTAL: ++ if ( !(new_fore = squeeze(list, fore, DOWN, 0))) ++ new_fore = squeeze(list, fore, RIGHT, 0); ++ break; ++ case VERTICAL: ++ if ( !(new_fore = squeeze(list, fore, RIGHT, 0))) ++ new_fore = squeeze(list, fore, DOWN, 0); + break; +- did = 1; + } +- hh = h / j-- - 1; +- if (!captionalways && i == 0 && j == 0) +- hh++; +- cv->c_ys = i; +- cv->c_ye = i + hh - 1; +- cv->c_yoff = i; +- i += hh + 1; +- h -= hh + 1; + } ++ else { /* Grow the regions from below (the right). */ ++ switch (fore -> c_type) { ++ case HORIZONTAL: ++ if ( !(new_fore = squeeze(list, fore, UP, 0))) ++ new_fore = squeeze(list, fore, LEFT, 0); ++ break; ++ case VERTICAL: ++ if ( !(new_fore = squeeze(list, fore, LEFT, 0))) ++ new_fore = squeeze(list, fore, UP, 0); ++ break; ++ } ++ } ++ ASSERT (new_fore); ++ return new_fore; ++ } ++} ++ ++ ++void ++RemCanvas() ++{ /** Remove the foreground canvas. */ ++ ++ struct screen_region vr; /*Canvasses in the same row/column as D_forecv.*/ ++ struct canvas *new_fore; /* Canvas which will replace D_forecv. */ ++ ++ /* Do nothing if the foreground is the only canvas. */ ++ if (D_cvlist->c_next == NULL) ++ return; ++ ++ compute_region(D_forecv->c_type, &vr, D_forecv, D_cvlist); ++ ++ debug1("RemCanvas. count = %d\n",vr.count); ++ debug_print_all_canvasses("RemCanvas() start\n"); ++ ++ if (vr.count > 1) { /* Resize the neighboring canvas in region. */ ++ debug2("D_forecv = %x vr.start = %x\n",D_forecv, vr.start); ++ /* If there is a canvas before D_forecv, then ++ grow that canvas to take up the space. */ ++ if (D_forecv != vr.start) { ++ struct canvas *pred; /* Predecssor of D_forecv. */ ++ for (pred = vr.start; pred->c_next != D_forecv; ) ++ pred = pred->c_next; ++ ++ new_fore = pred; ++ new_fore -> c_ye = D_forecv->c_ye; ++ new_fore -> c_xe = D_forecv->c_xe; ++ ++ } ++ else { ++ new_fore = D_forecv -> c_next; ++ new_fore -> c_ys = D_forecv -> c_ys; ++ new_fore -> c_xs = D_forecv -> c_xs; ++ new_fore -> c_yoff = new_fore -> c_ys; ++ new_fore -> c_xoff = new_fore -> c_xs; ++ } ++ } ++ else { /* Resize all bordering regions. */ ++ new_fore = grow_surrounding_regions( D_cvlist, D_forecv,0); ++ } ++ debug_print_canvas(new_fore); ++ ++ /* Redirect all pointers in the list. */ ++ redirect_pointers(D_cvlist, D_forecv, new_fore); ++ ++ remove_canvas_from_list(&D_cvlist, D_forecv); ++ FreeCanvas(D_forecv); ++ D_forecv = new_fore; ++ D_fore = Layer2Window(D_forecv->c_layer); ++ flayer = D_forecv->c_layer; ++ ++ debug2("RemCanvas. forecv = %#x new_fore = %#x\n", D_forecv, new_fore); ++ debug_print_all_canvasses("RemCanvas() end.\n"); ++ + RethinkDisplayViewports(); + ResizeLayersToCanvases(); + } + + void +-OneCanvas() +-{ +- struct canvas *mycv = D_forecv; +- struct canvas *cv, **cvpp; ++OneCanvas(list, target) ++struct canvas **list; ++struct canvas *target; ++{ /* Free all canvasses in the list except for ++ target. Make *list reference target. */ ++ struct canvas *cv; ++ struct canvas *next; + +- for (cvpp = &D_cvlist; (cv = *cvpp);) +- { +- if (cv == mycv) +- { +- cv->c_ys = 0; +- cv->c_ye = D_height - 1 - (D_has_hstatus == HSTATUS_LASTLINE) - captionalways; +- cv->c_yoff = 0; +- cvpp = &cv->c_next; +- } +- else +- { +- *cvpp = cv->c_next; ++ debug_print_all_canvasses("OneCanvas start.\n"); ++ for (cv = *list; cv; cv = next) { ++ next = cv -> c_next; ++ if (cv == target) { ++ cv -> c_xoff = 0; ++ cv -> c_xs = 0; ++ cv -> c_xe = D_width-1; ++ cv -> c_yoff = 0; ++ cv -> c_ys = 0; ++ cv -> c_ye = D_height - 1 - (D_has_hstatus == ++ HSTATUS_LASTLINE) - captionalways; ++ cv -> c_left = cv->c_right = NULL; ++ cv -> c_above = cv->c_below = NULL; ++ cv -> c_next = NULL; ++ } else { + FreeCanvas(cv); + } + } ++ *list = target; ++ debug_print_all_canvasses("OneCanvas end.\n"); ++ + RethinkDisplayViewports(); + ResizeLayersToCanvases(); + } +diff -BENbdpru display.h display.h +--- display.h 2003-07-01 14:01:42.000000000 +0000 ++++ display.h 2006-07-07 02:39:25.000000000 +0000 +@@ -58,6 +58,11 @@ struct canvas + int c_ys; + int c_ye; + struct event c_captev; /* caption changed event */ ++ int c_type; /* which type of split created the canvas. */ ++ struct canvas *c_right; /* canvas to the right. */ ++ struct canvas *c_left; /* canvas to the left. */ ++ struct canvas *c_above; /* canvas above. */ ++ struct canvas *c_below; /* canvas below. */ + }; + + struct viewport +diff -BENbdpru extern.h extern.h +--- extern.h 2003-08-22 12:27:57.000000000 +0000 ++++ extern.h 2006-07-07 02:39:25.000000000 +0000 +@@ -289,9 +289,9 @@ extern void NukePending __P((void)); + #endif + extern void SetCanvasWindow __P((struct canvas *, struct win *)); + extern int MakeDefaultCanvas __P((void)); +-extern int AddCanvas __P((void)); ++extern int AddCanvas __P((int)); + extern void RemCanvas __P((void)); +-extern void OneCanvas __P((void)); ++extern void OneCanvas __P((struct canvas **, struct canvas *)); + extern int RethinkDisplayViewports __P((void)); + extern void RethinkViewportOffsets __P((struct canvas *)); + #ifdef RXVT_OSC +@@ -490,3 +490,16 @@ extern int PrepareEncodedChar __P((int + # endif + #endif + extern int EncodeChar __P((char *, int, int, int *)); ++extern int compute_region __P((int,struct screen_region *, struct canvas *, struct canvas *)); ++extern void reset_region_types __P((struct screen_region *, int)); ++extern void equalize_canvas_dimensions __P((struct screen_region *)); ++extern int adjust_canvas_dimensions __P((struct screen_region *, struct canvas *, int)); ++enum directions { ++ LEFT, ++ RIGHT, ++ UP, ++ DOWN ++}; ++ ++extern struct canvas * squeeze __P(( struct canvas *, struct canvas *, ++ enum directions, int distance)); +diff -BENbdpru process.c process.c +--- process.c 2003-09-18 12:53:54.000000000 +0000 ++++ process.c 2006-07-07 02:39:26.000000000 +0000 +@@ -548,6 +548,7 @@ InitKeytab() + ktab['B'].nr = RC_POW_BREAK; + ktab['_'].nr = RC_SILENCE; + ktab['S'].nr = RC_SPLIT; ++ ktab['V'].nr = RC_VERT_SPLIT; + ktab['Q'].nr = RC_ONLY; + ktab['X'].nr = RC_REMOVE; + ktab['F'].nr = RC_FIT; +@@ -3649,7 +3650,11 @@ int key; + break; + #endif /* MULTIUSER */ + case RC_SPLIT: +- AddCanvas(); ++ AddCanvas(HORIZONTAL); ++ Activate(-1); ++ break; ++ case RC_VERT_SPLIT: ++ AddCanvas(VERTICAL); + Activate(-1); + break; + case RC_REMOVE: +@@ -3657,7 +3662,7 @@ int key; + Activate(-1); + break; + case RC_ONLY: +- OneCanvas(); ++ OneCanvas(&D_cvlist, D_forecv); + Activate(-1); + break; + case RC_FIT: +@@ -5877,104 +5882,51 @@ static void + ResizeRegions(arg) + char *arg; + { +- struct canvas *cv; +- int nreg, dsize, diff, siz; ++ struct screen_region region; /* Region in which D_forecv resides. */ ++ int adjusted; ++ ++ /* Note: there's a nomenclature problem here. I'm using 'region' ++ to mean a set of canvasses that are related geographically ++ in the display. The documentation uses 'region' to refer to ++ a single canvas (that's the usage in the error message ++ below). */ + + ASSERT(display); +- for (nreg = 0, cv = D_cvlist; cv; cv = cv->c_next) +- nreg++; +- if (nreg < 2) +- { +- Msg(0, "resize: need more than one region"); +- return; +- } +- dsize = D_height - (D_has_hstatus == HSTATUS_LASTLINE); +- if (*arg == '=') +- { +- /* make all regions the same height */ +- int h = dsize; +- int hh, i = 0; +- for (cv = D_cvlist; cv; cv = cv->c_next) +- { +- hh = h / nreg-- - 1; +- cv->c_ys = i; +- cv->c_ye = i + hh - 1; +- cv->c_yoff = i; +- i += hh + 1; +- h -= hh + 1; +- } +- RethinkDisplayViewports(); +- ResizeLayersToCanvases(); ++ if (D_cvlist -> c_next == NULL) { ++ Msg(0, "More than one region required."); + return; + } +- siz = D_forecv->c_ye - D_forecv->c_ys + 1; +- if (*arg == '+') +- diff = atoi(arg + 1); +- else if (*arg == '-') +- diff = -atoi(arg + 1); +- else if (!strcmp(arg, "min")) +- diff = 1 - siz; +- else if (!strcmp(arg, "max")) +- diff = dsize - (nreg - 1) * 2 - 1 - siz; +- else +- diff = atoi(arg) - siz; +- if (diff == 0) +- return; +- if (siz + diff < 1) +- diff = 1 - siz; +- if (siz + diff > dsize - (nreg - 1) * 2 - 1) +- diff = dsize - (nreg - 1) * 2 - 1 - siz; +- if (diff == 0 || siz + diff < 1) +- return; + +- if (diff < 0) +- { +- if (D_forecv->c_next) +- { +- D_forecv->c_ye += diff; +- D_forecv->c_next->c_ys += diff; +- D_forecv->c_next->c_yoff += diff; +- } +- else +- { +- for (cv = D_cvlist; cv; cv = cv->c_next) +- if (cv->c_next == D_forecv) ++ compute_region(D_forecv->c_type, ®ion, D_forecv, D_cvlist); ++ reset_region_types(®ion, D_forecv->c_type); ++ ++ if (region.count > 1) { ++ switch (*arg) { ++ case '=': equalize_canvas_dimensions(®ion); break; ++ case '-': adjust_canvas_dimensions(®ion, D_forecv, -atoi(arg+1)); break; ++ case '+': ++ adjusted = adjust_canvas_dimensions(®ion, D_forecv, atoi(arg+1)); + break; +- ASSERT(cv); +- cv->c_ye -= diff; +- D_forecv->c_ys -= diff; +- D_forecv->c_yoff -= diff; +- } +- } +- else +- { +- int s, i = 0, found = 0, di = diff, d2; +- s = dsize - (nreg - 1) * 2 - 1 - siz; +- for (cv = D_cvlist; cv; i = cv->c_ye + 2, cv = cv->c_next) +- { +- if (cv == D_forecv) +- { +- cv->c_ye = i + (cv->c_ye - cv->c_ys) + diff; +- cv->c_yoff -= cv->c_ys - i; +- cv->c_ys = i; +- found = 1; +- continue; ++ case 'm': ++ if (!strcmp(arg, "min")) ++ adjust_canvas_dimensions(®ion, D_forecv, -region.expanse); ++ else if (!strcmp(arg, "max")) ++ adjust_canvas_dimensions(®ion, D_forecv, region.expanse); ++ break; ++ default: ++ Msg(0, "resize: arguments munged"); + } +- s -= cv->c_ye - cv->c_ys; +- if (!found) +- { +- if (s >= di) +- continue; +- d2 = di - s; + } +- else +- d2 = di > cv->c_ye - cv->c_ys ? cv->c_ye - cv->c_ys : di; +- di -= d2; +- cv->c_ye = i + (cv->c_ye - cv->c_ys) - d2; +- cv->c_yoff -= cv->c_ys - i; +- cv->c_ys = i; ++ else { ++ /*TODO Need to expand this canvas into surrounding regions...*/ ++ switch(*arg) { ++ case '=': Msg(0, "More than one region required."); return; ++ // http://lists.gnu.org/archive/html/screen-users/2006-06/msg00012.html ++ // case '-': squeeze(D_cvlist, D_forecv, RIGHT, atoi(arg+1)); break; ++ default : Msg(0, "More than one region required."); return; + } + } ++ + RethinkDisplayViewports(); + ResizeLayersToCanvases(); + } +diff -BENbdpru screen.h screen.h +--- screen.h 2003-08-22 12:28:43.000000000 +0000 ++++ screen.h 2006-07-07 02:39:26.000000000 +0000 +@@ -288,8 +288,25 @@ struct baud_values + int sym; /* symbol defined in ttydev.h */ + }; + ++struct screen_region { ++ /* This is a group of canvasses that are all in ++ the same column or row. */ ++ struct canvas *start; /* First canvas in the region. */ ++ struct canvas *end; /* Last canvas in the region. */ ++ int expanse; /* Range in the appropriate direction. */ ++ int count; /* Number of canvasses in the region. */ ++ int type; /* HORIZONTAL or VERTICAL. */ ++ int xs; /* starting x coordinate */ ++ int xe; /* ending x coordinate */ ++ int ys; /* starting y coordinate */ ++ int ye; /* ending y coordinate */ ++}; ++ + /* + * windowlist orders + */ + #define WLIST_NUM 0 + #define WLIST_MRU 1 ++ ++#define HORIZONTAL 0 ++#define VERTICAL 1 --CE+1k2dSO48ffgeK--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070129140114.GA64768>