| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <sys/wait.h>
 | 
					
						
							| 
									
										
										
										
											2016-02-24 13:30:54 +01:00
										 |  |  | #include <poll.h>
 | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "ipc-client.h"
 | 
					
						
							|  |  |  | #include "list.h"
 | 
					
						
							|  |  |  | #include "log.h"
 | 
					
						
							| 
									
										
										
										
											2016-01-24 15:55:58 +01:00
										 |  |  | #include "bar/ipc.h"
 | 
					
						
							|  |  |  | #include "bar/render.h"
 | 
					
						
							|  |  |  | #include "bar/config.h"
 | 
					
						
							|  |  |  | #include "bar/status_line.h"
 | 
					
						
							|  |  |  | #include "bar/bar.h"
 | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void bar_init(struct bar *bar) { | 
					
						
							|  |  |  | 	bar->config = init_config(); | 
					
						
							|  |  |  | 	bar->status = init_status_line(); | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | 	bar->outputs = create_list(); | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void spawn_status_cmd_proc(struct bar *bar) { | 
					
						
							|  |  |  | 	if (bar->config->status_command) { | 
					
						
							|  |  |  | 		int pipefd[2]; | 
					
						
							| 
									
										
										
										
											2016-04-29 11:04:21 -04:00
										 |  |  | 		if (pipe(pipefd) != 0) { | 
					
						
							|  |  |  | 			sway_log(L_ERROR, "Unable to create pipe for status_command fork"); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 		bar->status_command_pid = fork(); | 
					
						
							|  |  |  | 		if (bar->status_command_pid == 0) { | 
					
						
							|  |  |  | 			close(pipefd[0]); | 
					
						
							|  |  |  | 			dup2(pipefd[1], STDOUT_FILENO); | 
					
						
							|  |  |  | 			close(pipefd[1]); | 
					
						
							|  |  |  | 			char *const cmd[] = { | 
					
						
							|  |  |  | 				"sh", | 
					
						
							|  |  |  | 				"-c", | 
					
						
							|  |  |  | 				bar->config->status_command, | 
					
						
							|  |  |  | 				NULL, | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 			execvp(cmd[0], cmd); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		close(pipefd[1]); | 
					
						
							|  |  |  | 		bar->status_read_fd = pipefd[0]; | 
					
						
							|  |  |  | 		fcntl(bar->status_read_fd, F_SETFL, O_NONBLOCK); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | struct output *new_output(const char *name) { | 
					
						
							|  |  |  | 	struct output *output = malloc(sizeof(struct output)); | 
					
						
							|  |  |  | 	output->name = strdup(name); | 
					
						
							|  |  |  | 	output->window = NULL; | 
					
						
							|  |  |  | 	output->registry = NULL; | 
					
						
							|  |  |  | 	output->workspaces = create_list(); | 
					
						
							|  |  |  | 	return output; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id) { | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 	/* initialize bar with default values */ | 
					
						
							|  |  |  | 	bar_init(bar); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* connect to sway ipc */ | 
					
						
							|  |  |  | 	bar->ipc_socketfd = ipc_open_socket(socket_path); | 
					
						
							|  |  |  | 	bar->ipc_event_socketfd = ipc_open_socket(socket_path); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | 	ipc_bar_init(bar, bar_id); | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 	for (i = 0; i < bar->outputs->length; ++i) { | 
					
						
							|  |  |  | 		struct output *bar_output = bar->outputs->items[i]; | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | 		bar_output->registry = registry_poll(); | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | 		if (!bar_output->registry->desktop_shell) { | 
					
						
							|  |  |  | 			sway_abort("swaybar requires the compositor to support the desktop-shell extension."); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | 		struct output_state *output = bar_output->registry->outputs->items[bar_output->idx]; | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | 		bar_output->window = window_setup(bar_output->registry, output->width, 30, false); | 
					
						
							|  |  |  | 		if (!bar_output->window) { | 
					
						
							|  |  |  | 			sway_abort("Failed to create window."); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		desktop_shell_set_panel(bar_output->registry->desktop_shell, output->output, bar_output->window->surface); | 
					
						
							|  |  |  | 		desktop_shell_set_panel_position(bar_output->registry->desktop_shell, bar->config->position); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* set font */ | 
					
						
							|  |  |  | 		bar_output->window->font = bar->config->font; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* set window height */ | 
					
						
							|  |  |  | 		set_window_height(bar_output->window, bar->config->height); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 	/* spawn status command */ | 
					
						
							|  |  |  | 	spawn_status_cmd_proc(bar); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void bar_run(struct bar *bar) { | 
					
						
							| 
									
										
										
										
											2016-02-24 13:30:54 +01:00
										 |  |  | 	int pfds = bar->outputs->length + 2; | 
					
						
							|  |  |  | 	struct pollfd *pfd = malloc(pfds * sizeof(struct pollfd)); | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 	bool dirty = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-24 13:30:54 +01:00
										 |  |  | 	pfd[0].fd = bar->ipc_event_socketfd; | 
					
						
							|  |  |  | 	pfd[0].events = POLLIN; | 
					
						
							|  |  |  | 	pfd[1].fd = bar->status_read_fd; | 
					
						
							|  |  |  | 	pfd[1].events = POLLIN; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	for (i = 0; i < bar->outputs->length; ++i) { | 
					
						
							|  |  |  | 		struct output *output = bar->outputs->items[i]; | 
					
						
							|  |  |  | 		pfd[i+2].fd = wl_display_get_fd(output->registry->display); | 
					
						
							|  |  |  | 		pfd[i+2].events = POLLIN; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 	while (1) { | 
					
						
							|  |  |  | 		if (dirty) { | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | 			int i; | 
					
						
							|  |  |  | 			for (i = 0; i < bar->outputs->length; ++i) { | 
					
						
							|  |  |  | 				struct output *output = bar->outputs->items[i]; | 
					
						
							|  |  |  | 				if (window_prerender(output->window) && output->window->cairo) { | 
					
						
							|  |  |  | 					render(output, bar->config, bar->status); | 
					
						
							|  |  |  | 					window_render(output->window); | 
					
						
							| 
									
										
										
										
											2016-02-24 13:30:54 +01:00
										 |  |  | 					wl_display_flush(output->registry->display); | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dirty = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-24 13:30:54 +01:00
										 |  |  | 		poll(pfd, pfds, -1); | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-24 13:30:54 +01:00
										 |  |  | 		if (pfd[0].revents & POLLIN) { | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 			sway_log(L_DEBUG, "Got IPC event."); | 
					
						
							|  |  |  | 			dirty = handle_ipc_event(bar); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-24 13:30:54 +01:00
										 |  |  | 		if (bar->config->status_command && pfd[1].revents & POLLIN) { | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 			sway_log(L_DEBUG, "Got update from status command."); | 
					
						
							|  |  |  | 			dirty = handle_status_line(bar); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-02-24 13:30:54 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// dispatch wl_display events
 | 
					
						
							|  |  |  | 		for (i = 0; i < bar->outputs->length; ++i) { | 
					
						
							|  |  |  | 			struct output *output = bar->outputs->items[i]; | 
					
						
							|  |  |  | 			if (pfd[i+2].revents & POLLIN) { | 
					
						
							|  |  |  | 				if (wl_display_dispatch(output->registry->display) == -1) { | 
					
						
							|  |  |  | 					sway_log(L_ERROR, "failed to dispatch wl: %d", errno); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				wl_display_dispatch_pending(output->registry->display); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void free_workspaces(list_t *workspaces) { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	for (i = 0; i < workspaces->length; ++i) { | 
					
						
							|  |  |  | 		struct workspace *ws = workspaces->items[i]; | 
					
						
							|  |  |  | 		free(ws->name); | 
					
						
							|  |  |  | 		free(ws); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	list_free(workspaces); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void free_output(struct output *output) { | 
					
						
							|  |  |  | 	window_teardown(output->window); | 
					
						
							|  |  |  | 	if (output->registry) { | 
					
						
							|  |  |  | 		registry_teardown(output->registry); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	free(output->name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (output->workspaces) { | 
					
						
							|  |  |  | 		free_workspaces(output->workspaces); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	free(output); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 17:27:17 +01:00
										 |  |  | static void free_outputs(list_t *outputs) { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	for (i = 0; i < outputs->length; ++i) { | 
					
						
							|  |  |  | 		free_output(outputs->items[i]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	list_free(outputs); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | static void terminate_status_command(pid_t pid) { | 
					
						
							|  |  |  | 	if (pid) { | 
					
						
							|  |  |  | 		// terminate status_command process
 | 
					
						
							|  |  |  | 		int ret = kill(pid, SIGTERM); | 
					
						
							|  |  |  | 		if (ret != 0) { | 
					
						
							|  |  |  | 			sway_log(L_ERROR, "Unable to terminate status_command [pid: %d]", pid); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			int status; | 
					
						
							|  |  |  | 			waitpid(pid, &status, 0); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void bar_teardown(struct bar *bar) { | 
					
						
							| 
									
										
										
										
											2016-03-31 20:50:07 +11:00
										 |  |  | 	if (bar->config) { | 
					
						
							|  |  |  | 		free_config(bar->config); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (bar->outputs) { | 
					
						
							|  |  |  | 		free_outputs(bar->outputs); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (bar->status) { | 
					
						
							|  |  |  | 		free_status_line(bar->status); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-24 02:34:20 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* close sockets/pipes */ | 
					
						
							|  |  |  | 	if (bar->status_read_fd) { | 
					
						
							|  |  |  | 		close(bar->status_read_fd); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (bar->ipc_socketfd) { | 
					
						
							|  |  |  | 		close(bar->ipc_socketfd); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (bar->ipc_event_socketfd) { | 
					
						
							|  |  |  | 		close(bar->ipc_event_socketfd); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* terminate status command process */ | 
					
						
							|  |  |  | 	terminate_status_command(bar->status_command_pid); | 
					
						
							|  |  |  | } |