This commit is contained in:
progandy 2016-01-08 22:18:36 +00:00
commit 8350cf51de
3 changed files with 80 additions and 42 deletions

View file

@ -76,20 +76,26 @@ void free_ipc_response(struct ipc_response *response) {
free(response); free(response);
} }
char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len) { void ipc_send_command(int socketfd, uint32_t type, const char *payload, uint32_t len) {
char data[ipc_header_size]; char data[ipc_header_size];
uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic)); uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic));
memcpy(data, ipc_magic, sizeof(ipc_magic)); memcpy(data, ipc_magic, sizeof(ipc_magic));
data32[0] = *len; data32[0] = len;
data32[1] = type; data32[1] = type;
if (write(socketfd, data, ipc_header_size) == -1) { if (write(socketfd, data, ipc_header_size) == -1) {
sway_abort("Unable to send IPC header"); sway_abort("Unable to send IPC header");
} }
if (write(socketfd, payload, *len) == -1) { if (write(socketfd, payload, len) == -1) {
sway_abort("Unable to send IPC payload"); sway_abort("Unable to send IPC payload");
} }
}
char *ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len) {
ipc_send_command(socketfd, type, payload, *len);
struct ipc_response *resp = ipc_recv_response(socketfd); struct ipc_response *resp = ipc_recv_response(socketfd);
char *response = resp->payload; char *response = resp->payload;

View file

@ -21,6 +21,11 @@ char *get_socketpath(void);
* Opens the sway socket. * Opens the sway socket.
*/ */
int ipc_open_socket(const char *socket_path); int ipc_open_socket(const char *socket_path);
/**
* Issues a single IPC command without waiting for a response.
* Useful if events are sent on the same socket.
*/
void ipc_send_command(int socketfd, uint32_t type, const char *payload, uint32_t len);
/** /**
* Issues a single IPC command and returns the buffer. len will be updated with * Issues a single IPC command and returns the buffer. len will be updated with
* the length of the buffer returned from sway. * the length of the buffer returned from sway.

View file

@ -66,7 +66,7 @@ struct status_block {
list_t *status_line = NULL; list_t *status_line = NULL;
list_t *workspaces = NULL; list_t *workspaces = NULL;
int ipc_socketfd, ipc_event_socketfd; int ipc_socketfd;
pid_t pid; pid_t pid;
int status_read_fd; int status_read_fd;
char line[1024]; char line[1024];
@ -158,10 +158,6 @@ void swaybar_teardown() {
if (ipc_socketfd) { if (ipc_socketfd) {
close(ipc_socketfd); close(ipc_socketfd);
} }
if (ipc_event_socketfd) {
close(ipc_event_socketfd);
}
} }
void sway_terminate(void) { void sway_terminate(void) {
@ -193,18 +189,15 @@ void free_workspace(void *item) {
free(ws); free(ws);
} }
void ipc_update_workspaces() { void ipc_update_workspaces(char *payload) {
if (workspaces) { if (workspaces) {
list_foreach(workspaces, free_workspace); list_foreach(workspaces, free_workspace);
list_free(workspaces); list_free(workspaces);
} }
workspaces = create_list(); workspaces = create_list();
uint32_t len = 0; json_object *results = json_tokener_parse(payload);
char *res = ipc_single_command(ipc_socketfd, IPC_GET_WORKSPACES, NULL, &len);
json_object *results = json_tokener_parse(res);
if (!results) { if (!results) {
free(res);
return; return;
} }
@ -234,7 +227,6 @@ void ipc_update_workspaces() {
} }
json_object_put(results); json_object_put(results);
free(res);
} }
uint32_t parse_color(const char *color) { uint32_t parse_color(const char *color) {
@ -421,10 +413,10 @@ void bar_ipc_init(int outputi, const char *bar_id) {
const char *subscribe_json = "[ \"workspace\", \"mode\" ]"; const char *subscribe_json = "[ \"workspace\", \"mode\" ]";
len = strlen(subscribe_json); len = strlen(subscribe_json);
res = ipc_single_command(ipc_event_socketfd, IPC_SUBSCRIBE, subscribe_json, &len); res = ipc_single_command(ipc_socketfd, IPC_SUBSCRIBE, subscribe_json, &len);
free(res); free(res);
ipc_update_workspaces(); ipc_send_command(ipc_socketfd, IPC_GET_WORKSPACES, NULL, 0);
} }
/** /**
@ -705,7 +697,7 @@ void render() {
double x = 0.5; double x = 0.5;
// Workspaces // Workspaces
if (workspace_buttons) { if (workspace_buttons && workspaces) {
for (i = 0; i < workspaces->length; ++i) { for (i = 0; i < workspaces->length; ++i) {
struct workspace *ws = workspaces->items[i]; struct workspace *ws = workspaces->items[i];
render_workspace_button(ws, &x); render_workspace_button(ws, &x);
@ -1076,10 +1068,13 @@ int i3json_handle_fd(int fd) {
} }
bool handle_ipc_event() { bool handle_ipc_event() {
struct ipc_response *resp = ipc_recv_response(ipc_event_socketfd); struct ipc_response *resp = ipc_recv_response(ipc_socketfd);
switch (resp->type) { switch (resp->type) {
case IPC_GET_WORKSPACES:
ipc_update_workspaces(resp->payload);
break;
case IPC_EVENT_WORKSPACE: case IPC_EVENT_WORKSPACE:
ipc_update_workspaces(); ipc_send_command(ipc_socketfd, IPC_GET_WORKSPACES, NULL, 0);
break; break;
case IPC_EVENT_MODE: { case IPC_EVENT_MODE: {
json_object *result = json_tokener_parse(resp->payload); json_object *result = json_tokener_parse(resp->payload);
@ -1129,7 +1124,7 @@ void poll_for_update() {
dirty = false; dirty = false;
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_SET(ipc_event_socketfd, &readfds); FD_SET(ipc_socketfd, &readfds);
FD_SET(status_read_fd, &readfds); FD_SET(status_read_fd, &readfds);
activity = select(FD_SETSIZE, &readfds, NULL, NULL, NULL); activity = select(FD_SETSIZE, &readfds, NULL, NULL, NULL);
@ -1137,7 +1132,7 @@ void poll_for_update() {
sway_log(L_ERROR, "polling failed: %d", errno); sway_log(L_ERROR, "polling failed: %d", errno);
} }
if (FD_ISSET(ipc_event_socketfd, &readfds)) { if (FD_ISSET(ipc_socketfd, &readfds)) {
sway_log(L_DEBUG, "Got IPC event."); sway_log(L_DEBUG, "Got IPC event.");
dirty = handle_ipc_event(); dirty = handle_ipc_event();
} }
@ -1184,6 +1179,55 @@ void poll_for_update() {
} }
} }
/*
* spawn_sh_cmd forks and executes the specified shell command.
* If infd is set, it receives the fd for the shell's stdin.
* If outfd is set, it recieves the fd for the shell's stdout.
*/
int spawn_sh_cmd(char *command, int *infd, int *outfd) {
int pipeout[2];
int pipein[2];
pid_t pid;
if (infd) {
pipe(pipein);
}
if (outfd) {
pipe(pipeout);
}
pid = fork();
if (pid == 0) {
if (outfd) {
close(pipeout[0]);
dup2(pipeout[1], STDOUT_FILENO);
close(pipeout[1]);
}
if (infd) {
close(pipeout[1]);
dup2(pipeout[0], STDIN_FILENO);
close(pipeout[0]);
}
char *const cmd[] = {
"sh",
"-c",
command,
NULL,
};
execvp(cmd[0], cmd);
return 0;
}
close(pipeout[1]);
close(pipein[0]);
if (outfd) {
*outfd = pipeout[0];
}
if (infd) {
*infd = pipein[1];
}
return pid;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
char *socket_path = NULL; char *socket_path = NULL;
@ -1251,7 +1295,6 @@ int main(int argc, char **argv) {
} }
} }
ipc_socketfd = ipc_open_socket(socket_path); ipc_socketfd = ipc_open_socket(socket_path);
ipc_event_socketfd = ipc_open_socket(socket_path);
if (argc == optind) { if (argc == optind) {
@ -1270,28 +1313,12 @@ int main(int argc, char **argv) {
bar_ipc_init(desired_output, bar_id); bar_ipc_init(desired_output, bar_id);
if (status_command) { if (status_command) {
int pipefd[2]; pid = spawn_sh_cmd(status_command, NULL, &status_read_fd);
pipe(pipefd); if (pid > 0) {
pid = fork();
if (pid == 0) {
close(pipefd[0]);
dup2(pipefd[1], STDOUT_FILENO);
close(pipefd[1]);
char *const cmd[] = {
"sh",
"-c",
status_command,
NULL,
};
execvp(cmd[0], cmd);
return 0;
}
close(pipefd[1]);
status_read_fd = pipefd[0];
fcntl(status_read_fd, F_SETFL, O_NONBLOCK); fcntl(status_read_fd, F_SETFL, O_NONBLOCK);
line[0] = '\0'; line[0] = '\0';
} }
}
signal(SIGTERM, sig_handler); signal(SIGTERM, sig_handler);