Merge pull request #1336 from akokshar/master

click_events
This commit is contained in:
Drew DeVault 2017-08-30 17:45:43 -05:00 committed by GitHub
commit 82d6afc91d
5 changed files with 137 additions and 10 deletions

View file

@ -14,6 +14,7 @@ struct bar {
int ipc_event_socketfd; int ipc_event_socketfd;
int ipc_socketfd; int ipc_socketfd;
int status_read_fd; int status_read_fd;
int status_write_fd;
pid_t status_command_pid; pid_t status_command_pid;
}; };

View file

@ -13,6 +13,7 @@ struct status_line {
list_t *block_line; list_t *block_line;
const char *text_line; const char *text_line;
command_protocol protocol; command_protocol protocol;
bool click_events;
}; };
struct status_block { struct status_block {
@ -31,6 +32,10 @@ struct status_block {
int border_bottom; int border_bottom;
int border_left; int border_left;
int border_right; int border_right;
// Set during rendering
int x;
int width;
}; };
/** /**
@ -43,6 +48,11 @@ struct status_line *init_status_line();
*/ */
bool handle_status_line(struct bar *bar); bool handle_status_line(struct bar *bar);
/**
* Handle mouse clicks.
*/
bool status_line_mouse_event(struct bar *bar, int x, int y, uint32_t button);
/** /**
* Free status line struct. * Free status line struct.
*/ */

View file

@ -7,6 +7,7 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <signal.h> #include <signal.h>
#include <poll.h> #include <poll.h>
#include <linux/input-event-codes.h>
#ifdef ENABLE_TRAY #ifdef ENABLE_TRAY
#include <dbus/dbus.h> #include <dbus/dbus.h>
#include "swaybar/tray/sni_watcher.h" #include "swaybar/tray/sni_watcher.h"
@ -31,16 +32,30 @@ static void bar_init(struct bar *bar) {
static void spawn_status_cmd_proc(struct bar *bar) { static void spawn_status_cmd_proc(struct bar *bar) {
if (bar->config->status_command) { if (bar->config->status_command) {
int pipefd[2]; int pipe_read_fd[2];
if (pipe(pipefd) != 0) { int pipe_write_fd[2];
sway_log(L_ERROR, "Unable to create pipe for status_command fork");
if (pipe(pipe_read_fd) != 0) {
sway_log(L_ERROR, "Unable to create pipes for status_command fork");
return; return;
} }
if (pipe(pipe_write_fd) != 0) {
sway_log(L_ERROR, "Unable to create pipe for status_command fork (write)");
close(pipe_read_fd[0]);
close(pipe_read_fd[1]);
return;
}
bar->status_command_pid = fork(); bar->status_command_pid = fork();
if (bar->status_command_pid == 0) { if (bar->status_command_pid == 0) {
close(pipefd[0]); close(pipe_read_fd[0]);
dup2(pipefd[1], STDOUT_FILENO); dup2(pipe_read_fd[1], STDOUT_FILENO);
close(pipefd[1]); close(pipe_read_fd[1]);
dup2(pipe_write_fd[0], STDIN_FILENO);
close(pipe_write_fd[0]);
close(pipe_write_fd[1]);
char *const cmd[] = { char *const cmd[] = {
"sh", "sh",
"-c", "-c",
@ -51,9 +66,13 @@ static void spawn_status_cmd_proc(struct bar *bar) {
return; return;
} }
close(pipefd[1]); close(pipe_read_fd[1]);
bar->status_read_fd = pipefd[0]; bar->status_read_fd = pipe_read_fd[0];
fcntl(bar->status_read_fd, F_SETFL, O_NONBLOCK); fcntl(bar->status_read_fd, F_SETFL, O_NONBLOCK);
close(pipe_write_fd[0]);
bar->status_write_fd = pipe_write_fd[1];
fcntl(bar->status_write_fd, F_SETFL, O_NONBLOCK);
} }
} }
@ -103,9 +122,22 @@ static void mouse_button_notify(struct window *window, int x, int y,
} }
} }
switch (button) {
case BTN_LEFT:
status_line_mouse_event(&swaybar, x, y, 1);
break;
case BTN_MIDDLE:
status_line_mouse_event(&swaybar, x, y, 2);
break;
case BTN_RIGHT:
status_line_mouse_event(&swaybar, x, y, 3);
break;
}
#ifdef ENABLE_TRAY #ifdef ENABLE_TRAY
tray_mouse_event(clicked_output, x, y, button, state_w); tray_mouse_event(clicked_output, x, y, button, state_w);
#endif #endif
} }
static void mouse_scroll_notify(struct window *window, enum scroll_direction direction) { static void mouse_scroll_notify(struct window *window, enum scroll_direction direction) {
@ -318,6 +350,10 @@ void bar_teardown(struct bar *bar) {
close(bar->status_read_fd); close(bar->status_read_fd);
} }
if (bar->status_write_fd) {
close(bar->status_write_fd);
}
if (bar->ipc_socketfd) { if (bar->ipc_socketfd) {
close(bar->ipc_socketfd); close(bar->ipc_socketfd);
} }

View file

@ -94,6 +94,9 @@ static void render_block(struct window *window, struct config *config, struct st
double pos = *x; double pos = *x;
block->x = (int)pos;
block->width = (int)block_width;
// render background // render background
if (block->background != 0x0) { if (block->background != 0x0) {
cairo_set_source_u32(window->cairo, block->background); cairo_set_source_u32(window->cairo, block->background);

View file

@ -27,6 +27,8 @@ struct {
static char line[1024]; static char line[1024];
static char line_rest[1024]; static char line_rest[1024];
static char event_buff[1024];
static void free_status_block(void *item) { static void free_status_block(void *item) {
if (!item) { if (!item) {
return; return;
@ -391,6 +393,66 @@ static int i3json_handle_fd(struct bar *bar) {
return i3json_parse(bar); return i3json_parse(bar);
} }
bool status_line_mouse_event(struct bar *bar, int x, int y, uint32_t button) {
sway_log(L_DEBUG, "status_line_mouse_event.");
if (!bar->status->click_events) {
sway_log(L_DEBUG, "click_events are not enabled.");
return false;
}
if (bar->status->protocol == I3BAR) {
sway_log(L_DEBUG, "Sending click event.");
// find clicked block
struct status_block *clicked_block = NULL;
struct status_block *current_block = NULL;
int num_blocks = bar->status->block_line->length;
if (num_blocks == 0) {
return false;
} else {
current_block = bar->status->block_line->items[0];
if (x < current_block->x) {
return false;
}
}
for (int i = 0; i < num_blocks; i++) {
current_block = bar->status->block_line->items[i];
if (x < (current_block->x + current_block->width)) {
clicked_block = current_block;
break;
}
}
if (!clicked_block || !clicked_block->name) {
return false;
}
// event example {"name":"capture","instance":"label","button":1,"x":3431,"y":18}
struct json_object *event_json = json_object_new_object();
json_object_object_add(event_json, "name", json_object_new_string(clicked_block->name));
if (clicked_block->instance) {
json_object_object_add(event_json, "instance", json_object_new_string(clicked_block->instance));
}
json_object_object_add(event_json, "button", json_object_new_int(button));
json_object_object_add(event_json, "x", json_object_new_int(x));
json_object_object_add(event_json, "y", json_object_new_int(y));
int len = snprintf(event_buff, sizeof(event_buff), "%s,\n", json_object_to_json_string(event_json));
json_object_put(event_json);
if (len <= (int)sizeof(event_buff)) { // if not truncated
write(bar->status_write_fd, event_buff, len);
return true;
}
}
return false;
}
bool handle_status_line(struct bar *bar) { bool handle_status_line(struct bar *bar) {
bool dirty = false; bool dirty = false;
@ -418,15 +480,29 @@ bool handle_status_line(struct bar *bar) {
if (line[0] == '{') { if (line[0] == '{') {
// detect i3bar json protocol // detect i3bar json protocol
json_object *proto = json_tokener_parse(line); json_object *proto = json_tokener_parse(line);
json_object *version;
if (proto) { if (proto) {
json_object *version;
if (json_object_object_get_ex(proto, "version", &version) if (json_object_object_get_ex(proto, "version", &version)
&& json_object_get_int(version) == 1 && json_object_get_int(version) == 1
) { ) {
sway_log(L_DEBUG, "Switched to i3bar protocol."); sway_log(L_DEBUG, "Switched to i3bar protocol.");
bar->status->protocol = I3BAR; bar->status->protocol = I3BAR;
i3json_handle_data(bar, line_rest);
} }
json_object *click_events;
if (json_object_object_get_ex(proto, "click_events", &click_events)
&& json_object_get_boolean(click_events)) {
sway_log(L_DEBUG, "Enabling click events.");
bar->status->click_events = true;
const char *events_array = "[\n";
write(bar->status_write_fd, events_array, strlen(events_array));
}
i3json_handle_data(bar, line_rest);
json_object_put(proto); json_object_put(proto);
} }
} }
@ -441,6 +517,7 @@ struct status_line *init_status_line() {
line->block_line = create_list(); line->block_line = create_list();
line->text_line = NULL; line->text_line = NULL;
line->protocol = UNDEF; line->protocol = UNDEF;
line->click_events = false;
return line; return line;
} }