mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 09:26:05 +00:00 
			
		
		
		
	Memory could be leaked if a second prompt or message appeared while another was
still present, so add a separate prompt free callback and make the _clear function responsible for calling it if necessary (rather than the individual prompt callbacks). Also make both messages and prompts clear any existing when a new is set. In addition, the screen could be modified while the prompt is there, restore the redraw-entire-screen behaviour on prompt clear; add a comment as a reminder.
This commit is contained in:
		@@ -31,6 +31,7 @@ void	cmd_command_prompt_init(struct cmd *, int);
 | 
				
			|||||||
int	cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
 | 
					int	cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int	cmd_command_prompt_callback(void *, const char *);
 | 
					int	cmd_command_prompt_callback(void *, const char *);
 | 
				
			||||||
 | 
					void	cmd_command_prompt_free(void *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct cmd_entry cmd_command_prompt_entry = {
 | 
					const struct cmd_entry cmd_command_prompt_entry = {
 | 
				
			||||||
	"command-prompt", NULL,
 | 
						"command-prompt", NULL,
 | 
				
			||||||
@@ -96,7 +97,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
 | 
				
			|||||||
		cdata->template = NULL;
 | 
							cdata->template = NULL;
 | 
				
			||||||
		hdr = xstrdup(":");
 | 
							hdr = xstrdup(":");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	status_prompt_set(c, hdr, cmd_command_prompt_callback, cdata, 0);
 | 
						status_prompt_set(c, hdr,
 | 
				
			||||||
 | 
						    cmd_command_prompt_callback, cmd_command_prompt_free, cdata, 0);
 | 
				
			||||||
	xfree(hdr);
 | 
						xfree(hdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (0);
 | 
						return (0);
 | 
				
			||||||
@@ -112,10 +114,8 @@ cmd_command_prompt_callback(void *data, const char *s)
 | 
				
			|||||||
	char				*cause, *ptr, *buf, ch;
 | 
						char				*cause, *ptr, *buf, ch;
 | 
				
			||||||
	size_t				 len, slen;
 | 
						size_t				 len, slen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (s == NULL) {
 | 
						if (s == NULL)
 | 
				
			||||||
		xfree(cdata);
 | 
					 | 
				
			||||||
		return (0);
 | 
							return (0);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	slen = strlen(s);
 | 
						slen = strlen(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	len = 0;
 | 
						len = 0;
 | 
				
			||||||
@@ -139,12 +139,10 @@ cmd_command_prompt_callback(void *data, const char *s)
 | 
				
			|||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		xfree(cdata->template);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		buf[len] = '\0';
 | 
							buf[len] = '\0';
 | 
				
			||||||
		s = buf;
 | 
							s = buf;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	xfree(cdata);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cmd_string_parse(s, &cmdlist, &cause) != 0) {
 | 
						if (cmd_string_parse(s, &cmdlist, &cause) != 0) {
 | 
				
			||||||
		if (cause == NULL)
 | 
							if (cause == NULL)
 | 
				
			||||||
@@ -172,7 +170,17 @@ cmd_command_prompt_callback(void *data, const char *s)
 | 
				
			|||||||
	cmd_list_exec(cmdlist, &ctx);
 | 
						cmd_list_exec(cmdlist, &ctx);
 | 
				
			||||||
	cmd_list_free(cmdlist);
 | 
						cmd_list_free(cmdlist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (c->prompt_callback != (void *) &cmd_command_prompt_callback)
 | 
						if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback)
 | 
				
			||||||
		return (1);
 | 
							return (1);
 | 
				
			||||||
	return (0);
 | 
						return (0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					cmd_command_prompt_free(void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cmd_command_prompt_data	*cdata = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (cdata->template != NULL)
 | 
				
			||||||
 | 
							xfree(cdata->template);
 | 
				
			||||||
 | 
						xfree(cdata);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,11 +29,7 @@ int	cmd_confirm_before_exec(struct cmd *, struct cmd_ctx *);
 | 
				
			|||||||
void	cmd_confirm_before_init(struct cmd *, int);
 | 
					void	cmd_confirm_before_init(struct cmd *, int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int	cmd_confirm_before_callback(void *, const char *);
 | 
					int	cmd_confirm_before_callback(void *, const char *);
 | 
				
			||||||
 | 
					void	cmd_confirm_before_free(void *);
 | 
				
			||||||
struct cmd_confirm_before_data {
 | 
					 | 
				
			||||||
	struct client	*c;
 | 
					 | 
				
			||||||
	char		*cmd;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const struct cmd_entry cmd_confirm_before_entry = {
 | 
					const struct cmd_entry cmd_confirm_before_entry = {
 | 
				
			||||||
	"confirm-before", "confirm",
 | 
						"confirm-before", "confirm",
 | 
				
			||||||
@@ -48,6 +44,11 @@ const struct cmd_entry cmd_confirm_before_entry = {
 | 
				
			|||||||
	cmd_target_print
 | 
						cmd_target_print
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct cmd_confirm_before_data {
 | 
				
			||||||
 | 
						struct client	*c;
 | 
				
			||||||
 | 
						char		*cmd;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
cmd_confirm_before_init(struct cmd *self, int key)
 | 
					cmd_confirm_before_init(struct cmd *self, int key)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -91,8 +92,9 @@ cmd_confirm_before_exec(unused struct cmd *self, struct cmd_ctx *ctx)
 | 
				
			|||||||
	cdata = xmalloc(sizeof *cdata);
 | 
						cdata = xmalloc(sizeof *cdata);
 | 
				
			||||||
	cdata->cmd = xstrdup(data->arg);
 | 
						cdata->cmd = xstrdup(data->arg);
 | 
				
			||||||
	cdata->c = c;
 | 
						cdata->c = c;
 | 
				
			||||||
	status_prompt_set(
 | 
						status_prompt_set(cdata->c, buf,
 | 
				
			||||||
	    cdata->c, buf, cmd_confirm_before_callback, cdata, PROMPT_SINGLE);
 | 
						    cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
 | 
				
			||||||
 | 
						    PROMPT_SINGLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	xfree(buf);
 | 
						xfree(buf);
 | 
				
			||||||
	return (1);
 | 
						return (1);
 | 
				
			||||||
@@ -108,7 +110,7 @@ cmd_confirm_before_callback(void *data, const char *s)
 | 
				
			|||||||
	char				*cause;
 | 
						char				*cause;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (s == NULL || tolower((u_char) s[0]) != 'y' || s[1] != '\0')
 | 
						if (s == NULL || tolower((u_char) s[0]) != 'y' || s[1] != '\0')
 | 
				
			||||||
		goto out;
 | 
							return (0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
 | 
						if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
 | 
				
			||||||
		if (cause != NULL) {
 | 
							if (cause != NULL) {
 | 
				
			||||||
@@ -116,7 +118,7 @@ cmd_confirm_before_callback(void *data, const char *s)
 | 
				
			|||||||
			status_message_set(c, "%s", cause);
 | 
								status_message_set(c, "%s", cause);
 | 
				
			||||||
			xfree(cause);
 | 
								xfree(cause);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		goto out;
 | 
							return (0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.msgdata = NULL;
 | 
						ctx.msgdata = NULL;
 | 
				
			||||||
@@ -132,10 +134,15 @@ cmd_confirm_before_callback(void *data, const char *s)
 | 
				
			|||||||
	cmd_list_exec(cmdlist, &ctx);
 | 
						cmd_list_exec(cmdlist, &ctx);
 | 
				
			||||||
	cmd_list_free(cmdlist);
 | 
						cmd_list_free(cmdlist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
						return (0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					cmd_confirm_before_free(void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cmd_confirm_before_data	*cdata = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cdata->cmd != NULL)
 | 
						if (cdata->cmd != NULL)
 | 
				
			||||||
		xfree(cdata->cmd);
 | 
							xfree(cdata->cmd);
 | 
				
			||||||
	xfree(cdata);
 | 
						xfree(cdata);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	return (0);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,7 +55,7 @@ cmd_select_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
 | 
				
			|||||||
	if (c->prompt_string != NULL)
 | 
						if (c->prompt_string != NULL)
 | 
				
			||||||
		return (0);
 | 
							return (0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status_prompt_set(c, "index ", cmd_select_prompt_callback, c, 0);
 | 
						status_prompt_set(c, "index ", cmd_select_prompt_callback, NULL, c, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (0);
 | 
						return (0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -171,8 +171,8 @@ server_lock(void)
 | 
				
			|||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		status_prompt_clear(c);
 | 
							status_prompt_clear(c);
 | 
				
			||||||
		status_prompt_set(
 | 
							status_prompt_set(c,
 | 
				
			||||||
		    c, "Password: ", server_lock_callback, c, PROMPT_HIDDEN);
 | 
							    "Password: ", server_lock_callback, c, NULL, PROMPT_HIDDEN);
 | 
				
			||||||
  		server_redraw_client(c);
 | 
					  		server_redraw_client(c);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	server_locked = 1;
 | 
						server_locked = 1;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								status.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								status.c
									
									
									
									
									
								
							@@ -468,6 +468,9 @@ status_message_set(struct client *c, const char *fmt, ...)
 | 
				
			|||||||
	va_list		ap;
 | 
						va_list		ap;
 | 
				
			||||||
	int		delay;
 | 
						int		delay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						status_prompt_clear(c);
 | 
				
			||||||
 | 
						status_message_clear(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	delay = options_get_number(&c->session->options, "display-time");
 | 
						delay = options_get_number(&c->session->options, "display-time");
 | 
				
			||||||
	tv.tv_sec = delay / 1000;
 | 
						tv.tv_sec = delay / 1000;
 | 
				
			||||||
	tv.tv_usec = (delay % 1000) * 1000L;
 | 
						tv.tv_usec = (delay % 1000) * 1000L;
 | 
				
			||||||
@@ -493,7 +496,7 @@ status_message_clear(struct client *c)
 | 
				
			|||||||
	c->message_string = NULL;
 | 
						c->message_string = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
 | 
						c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
 | 
				
			||||||
	c->flags |= CLIENT_STATUS;
 | 
						c->flags |= CLIENT_REDRAW; /* screen was frozen and may have changed */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	screen_reinit(&c->status);
 | 
						screen_reinit(&c->status);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -540,15 +543,20 @@ status_message_redraw(struct client *c)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
status_prompt_set(struct client *c,
 | 
					status_prompt_set(struct client *c, const char *msg,
 | 
				
			||||||
    const char *msg, int (*fn)(void *, const char *), void *data, int flags)
 | 
					    int (*callbackfn)(void *, const char *), void (*freefn)(void *),
 | 
				
			||||||
 | 
					    void *data, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						status_message_clear(c);
 | 
				
			||||||
 | 
						status_prompt_clear(c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c->prompt_string = xstrdup(msg);
 | 
						c->prompt_string = xstrdup(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c->prompt_buffer = xstrdup("");
 | 
						c->prompt_buffer = xstrdup("");
 | 
				
			||||||
	c->prompt_index = 0;
 | 
						c->prompt_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c->prompt_callback = fn;
 | 
						c->prompt_callbackfn = callbackfn;
 | 
				
			||||||
 | 
						c->prompt_freefn = freefn;
 | 
				
			||||||
	c->prompt_data = data;
 | 
						c->prompt_data = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c->prompt_hindex = 0;
 | 
						c->prompt_hindex = 0;
 | 
				
			||||||
@@ -569,6 +577,9 @@ status_prompt_clear(struct client *c)
 | 
				
			|||||||
 	if (c->prompt_string == NULL)
 | 
					 	if (c->prompt_string == NULL)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (c->prompt_freefn != NULL && c->prompt_data != NULL)
 | 
				
			||||||
 | 
							c->prompt_freefn(c->prompt_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mode_key_free(&c->prompt_mdata);
 | 
						mode_key_free(&c->prompt_mdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	xfree(c->prompt_string);
 | 
						xfree(c->prompt_string);
 | 
				
			||||||
@@ -580,7 +591,7 @@ status_prompt_clear(struct client *c)
 | 
				
			|||||||
	c->prompt_buffer = NULL;
 | 
						c->prompt_buffer = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
 | 
						c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
 | 
				
			||||||
	c->flags |= CLIENT_STATUS;
 | 
						c->flags |= CLIENT_REDRAW; /* screen was frozen and may have changed */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	screen_reinit(&c->status);
 | 
						screen_reinit(&c->status);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -832,14 +843,14 @@ status_prompt_key(struct client *c, int key)
 | 
				
			|||||||
 	case MODEKEYCMD_CHOOSE:
 | 
					 	case MODEKEYCMD_CHOOSE:
 | 
				
			||||||
		if (*c->prompt_buffer != '\0') {
 | 
							if (*c->prompt_buffer != '\0') {
 | 
				
			||||||
			status_prompt_add_history(c);
 | 
								status_prompt_add_history(c);
 | 
				
			||||||
			if (c->prompt_callback(
 | 
								if (c->prompt_callbackfn(
 | 
				
			||||||
			    c->prompt_data, c->prompt_buffer) == 0)
 | 
								    c->prompt_data, c->prompt_buffer) == 0)
 | 
				
			||||||
				status_prompt_clear(c);
 | 
									status_prompt_clear(c);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* FALLTHROUGH */
 | 
							/* FALLTHROUGH */
 | 
				
			||||||
	case MODEKEYCMD_QUIT:
 | 
						case MODEKEYCMD_QUIT:
 | 
				
			||||||
		if (c->prompt_callback(c->prompt_data, NULL) == 0)
 | 
							if (c->prompt_callbackfn(c->prompt_data, NULL) == 0)
 | 
				
			||||||
			status_prompt_clear(c);
 | 
								status_prompt_clear(c);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case MODEKEYCMD_OTHERKEY:
 | 
						case MODEKEYCMD_OTHERKEY:
 | 
				
			||||||
@@ -858,7 +869,7 @@ status_prompt_key(struct client *c, int key)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (c->prompt_flags & PROMPT_SINGLE) {
 | 
							if (c->prompt_flags & PROMPT_SINGLE) {
 | 
				
			||||||
			if (c->prompt_callback(
 | 
								if (c->prompt_callbackfn(
 | 
				
			||||||
			    c->prompt_data, c->prompt_buffer) == 0)
 | 
								    c->prompt_data, c->prompt_buffer) == 0)
 | 
				
			||||||
				status_prompt_clear(c);
 | 
									status_prompt_clear(c);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								tmux.h
									
									
									
									
									
								
							@@ -802,7 +802,8 @@ struct client {
 | 
				
			|||||||
	char		*prompt_string;
 | 
						char		*prompt_string;
 | 
				
			||||||
	char		*prompt_buffer;
 | 
						char		*prompt_buffer;
 | 
				
			||||||
	size_t		 prompt_index;
 | 
						size_t		 prompt_index;
 | 
				
			||||||
	int		 (*prompt_callback)(void *, const char *);
 | 
						int		 (*prompt_callbackfn)(void *, const char *);
 | 
				
			||||||
 | 
						void		 (*prompt_freefn)(void *);
 | 
				
			||||||
	void		*prompt_data;
 | 
						void		*prompt_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PROMPT_HIDDEN 0x1
 | 
					#define PROMPT_HIDDEN 0x1
 | 
				
			||||||
@@ -1278,8 +1279,8 @@ int	 status_redraw(struct client *);
 | 
				
			|||||||
void printflike2 status_message_set(struct client *, const char *, ...);
 | 
					void printflike2 status_message_set(struct client *, const char *, ...);
 | 
				
			||||||
void	 status_message_clear(struct client *);
 | 
					void	 status_message_clear(struct client *);
 | 
				
			||||||
int	 status_message_redraw(struct client *);
 | 
					int	 status_message_redraw(struct client *);
 | 
				
			||||||
void	 status_prompt_set(struct client *,
 | 
					void	 status_prompt_set(struct client *, const char *,
 | 
				
			||||||
	     const char *, int (*)(void *, const char *), void *, int);
 | 
					    	     int (*)(void *, const char *), void (*)(void *), void *, int);
 | 
				
			||||||
void	 status_prompt_clear(struct client *);
 | 
					void	 status_prompt_clear(struct client *);
 | 
				
			||||||
int	 status_prompt_redraw(struct client *);
 | 
					int	 status_prompt_redraw(struct client *);
 | 
				
			||||||
void	 status_prompt_key(struct client *, int);
 | 
					void	 status_prompt_key(struct client *, int);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user