maketitle(void)
{
    char_u	*p;
    char_u	*title_str = NULL;
    char_u	*icon_str = NULL;
    int		maxlen = 0;
    int		len;
    int		mustset;
    char_u	buf[IOSIZE];
    int		off;

    if (!redrawing())
    {
	// Postpone updating the title when 'lazyredraw' is set.
	need_maketitle = TRUE;
	return;
    }

    need_maketitle = FALSE;
    if (!p_title && !p_icon && lasttitle == NULL && lasticon == NULL)
	return;  // nothing to do

    if (p_title)
    {
	if (p_titlelen > 0)
	{
	    maxlen = p_titlelen * Columns / 100;
	    if (maxlen < 10)
		maxlen = 10;
	}

	title_str = buf;
	if (*p_titlestring != NUL)
	{
#ifdef FEAT_STL_OPT
	    if (stl_syntax & STL_IN_TITLE)
	    {
		int	use_sandbox = FALSE;
		int	called_emsg_before = called_emsg;

# ifdef FEAT_EVAL
		use_sandbox = was_set_insecurely((char_u *)"titlestring", 0);
# endif
		build_stl_str_hl(curwin, title_str, sizeof(buf),
					      p_titlestring, use_sandbox,
					      0, maxlen, NULL, NULL);
		if (called_emsg > called_emsg_before)
		    set_string_option_direct((char_u *)"titlestring", -1,
					   (char_u *)"", OPT_FREE, SID_ERROR);
	    }
	    else
#endif
		title_str = p_titlestring;
	}
	else
	{
	    // format: "fname + (path) (1 of 2) - VIM"

#define SPACE_FOR_FNAME (IOSIZE - 100)
#define SPACE_FOR_DIR   (IOSIZE - 20)
#define SPACE_FOR_ARGNR (IOSIZE - 10)  // at least room for " - VIM"
	    if (curbuf->b_fname == NULL)
		vim_strncpy(buf, (char_u *)_("[No Name]"), SPACE_FOR_FNAME);
#ifdef FEAT_TERMINAL
	    else if (curbuf->b_term != NULL)
	    {
		vim_strncpy(buf, term_get_status_text(curbuf->b_term),
							      SPACE_FOR_FNAME);
	    }
#endif
	    else
	    {
		p = transstr(gettail(curbuf->b_fname));
		vim_strncpy(buf, p, SPACE_FOR_FNAME);
		vim_free(p);
	    }

#ifdef FEAT_TERMINAL
	    if (curbuf->b_term == NULL)
#endif
		switch (bufIsChanged(curbuf)
			+ (curbuf->b_p_ro * 2)
			+ (!curbuf->b_p_ma * 4))
		{
		    case 1: STRCAT(buf, " +"); break;
		    case 2: STRCAT(buf, " ="); break;
		    case 3: STRCAT(buf, " =+"); break;
		    case 4:
		    case 6: STRCAT(buf, " -"); break;
		    case 5:
		    case 7: STRCAT(buf, " -+"); break;
		}

	    if (curbuf->b_fname != NULL
#ifdef FEAT_TERMINAL
		    && curbuf->b_term == NULL
#endif
		    )
	    {
		// Get path of file, replace home dir with ~
		off = (int)STRLEN(buf);
		buf[off++] = ' ';
		buf[off++] = '(';
		home_replace(curbuf, curbuf->b_ffname,
					buf + off, SPACE_FOR_DIR - off, TRUE);
#ifdef BACKSLASH_IN_FILENAME
		// avoid "c:/name" to be reduced to "c"
		if (isalpha(buf[off]) && buf[off + 1] == ':')
		    off += 2;
#endif
		// remove the file name
		p = gettail_sep(buf + off);
		if (p == buf + off)
		{
		    // must be a help buffer
		    vim_strncpy(buf + off, (char_u *)_("help"),
					   (size_t)(SPACE_FOR_DIR - off - 1));
		}
		else
		    *p = NUL;

		// Translate unprintable chars and concatenate.  Keep some
		// room for the server name.  When there is no room (very long
		// file name) use (...).
		if (off < SPACE_FOR_DIR)
		{
		    p = transstr(buf + off);
		    vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - off));
		    vim_free(p);
		}
		else
		{
		    vim_strncpy(buf + off, (char_u *)"...",
					     (size_t)(SPACE_FOR_ARGNR - off));
		}
		STRCAT(buf, ")");
	    }

	    append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE);

#if defined(FEAT_CLIENTSERVER)
	    if (serverName != NULL)
	    {
		STRCAT(buf, " - ");
		vim_strcat(buf, serverName, IOSIZE);
	    }
	    else
#endif
		STRCAT(buf, " - VIM");

	    if (maxlen > 0)
	    {
		// make it shorter by removing a bit in the middle
		if (vim_strsize(buf) > maxlen)
		    trunc_string(buf, buf, maxlen, IOSIZE);
	    }
	}
    }
    mustset = value_changed(title_str, &lasttitle);

    if (p_icon)
    {
	icon_str = buf;
	if (*p_iconstring != NUL)
	{
#ifdef FEAT_STL_OPT
	    if (stl_syntax & STL_IN_ICON)
	    {
		int	use_sandbox = FALSE;
		int	called_emsg_before = called_emsg;

# ifdef FEAT_EVAL
		use_sandbox = was_set_insecurely((char_u *)"iconstring", 0);
# endif
		build_stl_str_hl(curwin, icon_str, sizeof(buf),
						    p_iconstring, use_sandbox,
						    0, 0, NULL, NULL);
		if (called_emsg > called_emsg_before)
		    set_string_option_direct((char_u *)"iconstring", -1,
					   (char_u *)"", OPT_FREE, SID_ERROR);
	    }
	    else
#endif
		icon_str = p_iconstring;
	}
	else
	{
	    if (buf_spname(curbuf) != NULL)
		p = buf_spname(curbuf);
	    else		    // use file name only in icon
		p = gettail(curbuf->b_ffname);
	    *icon_str = NUL;
	    // Truncate name at 100 bytes.
	    len = (int)STRLEN(p);
	    if (len > 100)
	    {
		len -= 100;
		if (has_mbyte)
		    len += (*mb_tail_off)(p, p + len) + 1;
		p += len;
	    }
	    STRCPY(icon_str, p);
	    trans_characters(icon_str, IOSIZE);
	}
    }

    mustset |= value_changed(icon_str, &lasticon);

    if (mustset)
	resettitle();
}