/* $OpenBSD$ */
/*
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <pwd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <vis.h>
#include "tmux.h"
/* Command queue flags. */
#define CMDQ_FIRED 0x1
#define CMDQ_WAITING 0x2
/* Command queue item type. */
enum cmdq_type {
CMDQ_COMMAND,
CMDQ_CALLBACK,
};
/* Command queue item. */
struct cmdq_item {
char *name;
struct cmdq_list *queue;
struct cmdq_item *next;
struct client *client;
struct client *target_client;
enum cmdq_type type;
u_int group;
u_int number;
time_t time;
int flags;
struct cmdq_state *state;
struct cmd_find_state source;
struct cmd_find_state target;
struct cmd_list *cmdlist;
struct cmd *cmd;
cmdq_cb cb;
void *data;
TAILQ_ENTRY(cmdq_item) entry;
};
TAILQ_HEAD(cmdq_item_list, cmdq_item);
/*
* Command queue state. This is the context for commands on the command queue.
* It holds information about how the commands were fired (the key and flags),
* any additional formats for the commands, and the current default target.
* Multiple commands can share the same state and a command may update the
* default target.
*/
struct cmdq_state {
int references;
int flags;
struct format_tree *formats;
struct key_event event;
struct cmd_find_state current;
};
/* Command queue. */
struct cmdq_list {
struct cmdq_item *item;
struct cmdq_item_list list;
};
/* Get command queue name. */
static const char *
cmdq_name(struct client *c)
{
static char s[256];
if (c == NULL)
return ("<global>");
if (c->name != NULL)
xsnprintf(s, sizeof s, "<%s>", c->name);
else
xsnprintf(s, sizeof s, "<%p>", c);
return (s);
}
/* Get command queue from client. */
static struct cmdq_list *
cmdq_get(struct client *c)
{
static struct cmdq_list *global_queue;
if (c == NULL) {
if (global_queue == NULL)
global_queue = cmdq_new();
return (global_queue);
}
return (c->queue);
}
/* Create a queue. */
struct cmdq_list *
cmdq_new(void)
{
struct cmdq_list *queue;
queue = xcalloc(1, sizeof *queue);
TAILQ_INIT (&queue->list);
return (queue);
}
/* Free a queue. */
void
cmdq_free(struct cmdq_list *queue)
{
if (!TAILQ_EMPTY(&queue->list))
fatalx("queue not empty");
free(queue);
}
/* Get item name. */
const char *
cmdq_get_name(struct cmdq_item *item)
{
return (item->name);
}
/* Get item client. */
struct client *
cmdq_get_client(struct cmdq_item *item)
{
return (item->client);
}
/* Get item target client. */
struct client *
cmdq_get_target_client(struct cmdq_item *item)
{
return (item->target_client);
}
/* Get item state. */
struct cmdq_state *
cmdq_get_state(struct cmdq_item *item)
{
return (item->state);
}
/* Get item target. */
struct cmd_find_state *
cmdq_get_target(struct cmdq_item *item)
{
return (&item->target);
}
/* Get item source. */
struct cmd_find_state *
cmdq_get_source(struct cmdq_item *item)
{
return (&item->source);
}
/* Get state event. */
struct key_event *
cmdq_get_event(struct cmdq_item *item)
{
return (&item->state->event);
}
/* Get state current target. */
struct cmd_find_state *
cmdq_get_current(struct cmdq_item *item)
{
return (&item->state->current);
}
/* Get state flags. */
int
cmdq_get_flags(struct cmdq_item *item)
{
return (item->state->flags);
}
/* Create a new state. */
struct cmdq_state *
cmdq_new_state(struct cmd_find_state *current, struct key_event *event,
int flags)
{
struct cmdq_state *state;
state = xcalloc(1, sizeof *state);
state->references = 1;
state->flags = flags;
if (event != NULL)
memcpy(&state->event, event, sizeof state->event);
else
state->event.key = KEYC_NONE;
if (current != NULL && cmd_find_valid_state(current))
cmd_find_