diff_set_topline(win_T *fromwin, win_T *towin)
{
    buf_T	*frombuf = fromwin->w_buffer;
    linenr_T	lnum = fromwin->w_topline;
    int		fromidx;
    int		toidx;
    diff_T	*dp;
    int		max_count;
    int		i;

    fromidx = diff_buf_idx(frombuf);
    if (fromidx == DB_COUNT)
	return;		// safety check

    if (curtab->tp_diff_invalid)
	ex_diffupdate(NULL);		// update after a big change

    towin->w_topfill = 0;

    // search for a change that includes "lnum" in the list of diffblocks.
    FOR_ALL_DIFFBLOCKS_IN_TAB(curtab, dp)
	if (lnum <= dp->df_lnum[fromidx] + dp->df_count[fromidx])
	    break;
    if (dp == NULL)
    {
	// After last change, compute topline relative to end of file; no
	// filler lines.
	towin->w_topline = towin->w_buffer->b_ml.ml_line_count
				       - (frombuf->b_ml.ml_line_count - lnum);
    }
    else
    {
	// Find index for "towin".
	toidx = diff_buf_idx(towin->w_buffer);
	if (toidx == DB_COUNT)
	    return;		// safety check

	towin->w_topline = lnum + (dp->df_lnum[toidx] - dp->df_lnum[fromidx]);
	if (lnum >= dp->df_lnum[fromidx])
	{
	    // Inside a change: compute filler lines. With three or more
	    // buffers we need to know the largest count.
	    max_count = 0;
	    for (i = 0; i < DB_COUNT; ++i)
		if (curtab->tp_diffbuf[i] != NULL
					       && max_count < dp->df_count[i])
		    max_count = dp->df_count[i];

	    if (dp->df_count[toidx] == dp->df_count[fromidx])
	    {
		// same number of lines: use same filler count
		towin->w_topfill = fromwin->w_topfill;
	    }
	    else if (dp->df_count[toidx] > dp->df_count[fromidx])
	    {
		if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx])
		{
		    // more lines in towin and fromwin doesn't show diff
		    // lines, only filler lines
		    if (max_count - fromwin->w_topfill >= dp->df_count[toidx])
		    {
			// towin also only shows filler lines
			towin->w_topline = dp->df_lnum[toidx]
						       + dp->df_count[toidx];
			towin->w_topfill = fromwin->w_topfill;
		    }
		    else
			// towin still has some diff lines to show
			towin->w_topline = dp->df_lnum[toidx]
					     + max_count - fromwin->w_topfill;
		}
	    }
	    else if (towin->w_topline >= dp->df_lnum[toidx]
							+ dp->df_count[toidx])
	    {
		// less lines in towin and no diff lines to show: compute
		// filler lines
		towin->w_topline = dp->df_lnum[toidx] + dp->df_count[toidx];
		if (diff_flags & DIFF_FILLER)
		{
		    if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx])
			// fromwin is also out of diff lines
			towin->w_topfill = fromwin->w_topfill;
		    else
			// fromwin has some diff lines
			towin->w_topfill = dp->df_lnum[fromidx]
							   + max_count - lnum;
		}
	    }
	}
    }

    // safety check (if diff info gets outdated strange things may happen)
    towin->w_botfill = FALSE;
    if (towin->w_topline > towin->w_buffer->b_ml.ml_line_count)
    {
	towin->w_topline = towin->w_buffer->b_ml.ml_line_count;
	towin->w_botfill = TRUE;
    }
    if (towin->w_topline < 1)
    {
	towin->w_topline = 1;
	towin->w_topfill = 0;
    }

    // When w_topline changes need to recompute w_botline and cursor position
    invalidate_botline_win(towin);
    changed_line_abv_curs_win(towin);

    check_topfill(towin, FALSE);
#ifdef FEAT_FOLDING
    (void)hasFoldingWin(towin, towin->w_topline, &towin->w_topline,
							    NULL, TRUE, NULL);
#endif
}