diff --git a/include/bar/bar.h b/include/bar/bar.h index c20efc55..a3c511d9 100644 --- a/include/bar/bar.h +++ b/include/bar/bar.h @@ -32,6 +32,9 @@ struct workspace { bool urgent; }; +/** Global bar state */ +extern struct bar swaybar; + /** * Setup bar. */ diff --git a/include/bar/ipc.h b/include/bar/ipc.h index 741c067b..c11931d0 100644 --- a/include/bar/ipc.h +++ b/include/bar/ipc.h @@ -13,5 +13,11 @@ void ipc_bar_init(struct bar *bar, const char *bar_id); */ bool handle_ipc_event(struct bar *bar); + +/** + * Send workspace command to sway + */ +void ipc_send_workspace_command(const char *workspace_name); + #endif /* _SWAYBAR_IPC_H */ diff --git a/include/bar/render.h b/include/bar/render.h index 931a1cdd..114f43f4 100644 --- a/include/bar/render.h +++ b/include/bar/render.h @@ -14,4 +14,9 @@ void render(struct output *output, struct config *config, struct status_line *li */ void set_window_height(struct window *window, int height); +/** + * Compute the size of a workspace name + */ +void workspace_button_size(struct window *window, const char *workspace_name, int *width, int *height); + #endif /* _SWAYBAR_RENDER_H */ diff --git a/include/client/window.h b/include/client/window.h index 7be4fff3..55a12225 100644 --- a/include/client/window.h +++ b/include/client/window.h @@ -28,10 +28,10 @@ struct cursor { }; struct pointer_input { - wl_fixed_t last_x; - wl_fixed_t last_y; + int last_x; + int last_y; - void (*notify)(struct window *window, wl_fixed_t x, wl_fixed_t y, uint32_t button); + void (*notify)(struct window *window, int x, int y, uint32_t button); }; struct window { diff --git a/include/extensions.h b/include/extensions.h index 7c508b5e..d26e95c1 100644 --- a/include/extensions.h +++ b/include/extensions.h @@ -11,8 +11,6 @@ struct background_config { wlc_resource surface; // we need the wl_resource of the surface in the destructor struct wl_resource *wl_surface_res; - // used to determine if client is a background - struct wl_client *client; }; struct panel_config { @@ -25,6 +23,8 @@ struct panel_config { enum desktop_shell_panel_position panel_position; // used to determine if client is a panel struct wl_client *client; + // wlc handle for this panel's surface, not set until panel is created + wlc_handle handle; }; struct desktop_shell_state { diff --git a/sway/extensions.c b/sway/extensions.c index 1fe15ac5..ab425fa7 100644 --- a/sway/extensions.c +++ b/sway/extensions.c @@ -73,7 +73,6 @@ static void set_background(struct wl_client *client, struct wl_resource *resourc } sway_log(L_DEBUG, "Setting surface %p as background for output %d", surface, (int)output); struct background_config *config = malloc(sizeof(struct background_config)); - config->client = client; config->output = output; config->surface = wlc_resource_from_wl_surface_resource(surface); config->wl_surface_res = surface; diff --git a/sway/handlers.c b/sway/handlers.c index 4336b6c7..a7a87564 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -33,6 +33,66 @@ // Event handled by sway and should not be sent to client #define EVENT_HANDLED true +static struct panel_config *if_panel_find_config(struct wl_client *client) { + int i; + for (i = 0; i < desktop_shell.panels->length; i++) { + struct panel_config *config = desktop_shell.panels->items[i]; + if (config->client == client) { + return config; + } + } + return NULL; +} + +static struct wlc_geometry compute_panel_geometry(struct panel_config *config) { + const struct wlc_size resolution = *wlc_output_get_resolution(config->output); + const struct wlc_geometry *old = wlc_view_get_geometry(config->handle); + struct wlc_geometry new; + + switch (config->panel_position) { + case DESKTOP_SHELL_PANEL_POSITION_TOP: + new.origin.x = 0; + new.origin.y = 0; + new.size.w = resolution.w; + new.size.h = old->size.h; + break; + case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: + new.origin.x = 0; + new.origin.y = resolution.h - old->size.h; + new.size.w = resolution.w; + new.size.h = old->size.h; + break; + case DESKTOP_SHELL_PANEL_POSITION_LEFT: + new.origin.x = 0; + new.origin.y = 0; + new.size.w = old->size.w; + new.size.h = resolution.h; + break; + case DESKTOP_SHELL_PANEL_POSITION_RIGHT: + new.origin.x = resolution.w - old->size.w; + new.origin.y = 0; + new.size.w = old->size.w; + new.size.h = resolution.h; + break; + } + + return new; +} + +static void update_panel_geometry(struct panel_config *config) { + struct wlc_geometry geometry = compute_panel_geometry(config); + wlc_view_set_geometry(config->handle, 0, &geometry); +} + +static void update_panel_geometries(wlc_handle output) { + for (int i = 0; i < desktop_shell.panels->length; i++) { + struct panel_config *config = desktop_shell.panels->items[i]; + if (config->output == output) { + update_panel_geometry(config); + } + } +} + /* Handles */ static bool handle_input_created(struct libinput_device *device) { @@ -119,32 +179,6 @@ static void handle_output_pre_render(wlc_handle output) { break; } } - - for (i = 0; i < desktop_shell.panels->length; ++i) { - struct panel_config *config = desktop_shell.panels->items[i]; - if (config->output == output) { - struct wlc_size size = *wlc_surface_get_size(config->surface); - struct wlc_geometry geo = { - .size = size - }; - switch (config->panel_position) { - case DESKTOP_SHELL_PANEL_POSITION_TOP: - geo.origin = (struct wlc_point){ 0, 0 }; - break; - case DESKTOP_SHELL_PANEL_POSITION_BOTTOM: - geo.origin = (struct wlc_point){ 0, resolution.h - size.h }; - break; - case DESKTOP_SHELL_PANEL_POSITION_LEFT: - geo.origin = (struct wlc_point){ 0, 0 }; - break; - case DESKTOP_SHELL_PANEL_POSITION_RIGHT: - geo.origin = (struct wlc_point){ resolution.w - size.w, 0 }; - break; - } - wlc_surface_render(config->surface, &geo); - break; - } - } } static void handle_output_post_render(wlc_handle output) { @@ -158,10 +192,16 @@ static void handle_view_pre_render(wlc_handle view) { static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); + swayc_t *c = swayc_by_handle(output); - if (!c) return; + if (!c) { + return; + } c->width = to->w; c->height = to->h; + + update_panel_geometries(output); + arrange_windows(&root_container, -1, -1); } @@ -176,28 +216,6 @@ static void handle_output_focused(wlc_handle output, bool focus) { } } -static bool client_is_background(struct wl_client *client) { - int i; - for (i = 0; i < desktop_shell.backgrounds->length; i++) { - struct background_config *config = desktop_shell.backgrounds->items[i]; - if (config->client == client) { - return true; - } - } - return false; -} - -static bool client_is_panel(struct wl_client *client) { - int i; - for (i = 0; i < desktop_shell.panels->length; i++) { - struct panel_config *config = desktop_shell.panels->items[i]; - if (config->client == client) { - return true; - } - } - return false; -} - static void ws_cleanup() { swayc_t *op, *ws; int i = 0, j; @@ -228,8 +246,14 @@ static bool handle_view_created(wlc_handle handle) { bool return_to_workspace = false; struct wl_client *client = wlc_view_get_wl_client(handle); pid_t pid; - - if (client_is_background(client) || client_is_panel(client)) { + struct panel_config *panel_config = NULL; + + panel_config = if_panel_find_config(client); + if (panel_config) { + panel_config->handle = handle; + update_panel_geometry(panel_config); + wlc_view_set_mask(handle, VISIBLE); + wlc_view_set_output(handle, panel_config->output); return true; } diff --git a/swaybar/bar.c b/swaybar/bar.c index 6d858f92..4f8063ac 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -58,6 +58,37 @@ struct output *new_output(const char *name) { return output; } +static void mouse_button_notify(struct window *window, int x, int y, uint32_t button) { + sway_log(L_DEBUG, "Mouse button %d clicked at %d %d\n", button, x, y); + + struct output *clicked_output = NULL; + for (int i = 0; i < swaybar.outputs->length; i++) { + struct output *output = swaybar.outputs->items[i]; + if (window == output->window) { + clicked_output = output; + break; + } + } + + if (!sway_assert(clicked_output != NULL, "Got pointer event for non-existing output")) { + return; + } + + double button_x = 0.5; + for (int i = 0; i < clicked_output->workspaces->length; i++) { + struct workspace *workspace = clicked_output->workspaces->items[i]; + int button_width, button_height; + + workspace_button_size(window, workspace->name, &button_width, &button_height); + + button_x += button_width; + if (x <= button_x) { + ipc_send_workspace_command(workspace->name); + break; + } + } +} + void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id) { /* initialize bar with default values */ bar_init(bar); @@ -92,6 +123,9 @@ void bar_setup(struct bar *bar, const char *socket_path, const char *bar_id) { /* set font */ bar_output->window->font = bar->config->font; + /* set font */ + bar_output->window->pointer_input.notify = mouse_button_notify; + /* set window height */ set_window_height(bar_output->window, bar->config->height); } diff --git a/swaybar/ipc.c b/swaybar/ipc.c index dacee4c2..15f40508 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -7,6 +7,15 @@ #include "bar/config.h" #include "bar/ipc.h" +void ipc_send_workspace_command(const char *workspace_name) { + uint32_t size = strlen("workspace ") + strlen(workspace_name) + 1; + + char command[size]; + sprintf(command, "workspace %s", workspace_name); + + ipc_single_command(swaybar.ipc_socketfd, IPC_COMMAND, command, &size); +} + static void ipc_parse_config(struct config *config, const char *payload) { json_object *bar_config = json_tokener_parse(payload); json_object *tray_output, *mode, *hidden_bar, *position, *status_command; diff --git a/swaybar/render.c b/swaybar/render.c index 273bd4f0..cea36f52 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -172,7 +172,7 @@ static void render_block(struct window *window, struct config *config, struct st } -static char *handle_workspace_number(bool strip_num, const char *ws_name) { +static const char *strip_workspace_name(bool strip_num, const char *ws_name) { bool strip = false; int i; @@ -190,18 +190,23 @@ static char *handle_workspace_number(bool strip_num, const char *ws_name) { } if (strip) { - return strdup(ws_name + i); + return ws_name + i; } - return strdup(ws_name); + return ws_name; +} + +void workspace_button_size(struct window *window, const char *workspace_name, int *width, int *height) { + const char *stripped_name = strip_workspace_name(swaybar.config->strip_workspace_numbers, workspace_name); + + get_text_size(window->cairo, window->font, width, height, false, "%s", stripped_name); + *width += 2 * ws_horizontal_padding; + *height += 2 * ws_vertical_padding; } static void render_workspace_button(struct window *window, struct config *config, struct workspace *ws, double *x) { - // strip workspace numbers if required - char *name = handle_workspace_number(config->strip_workspace_numbers, ws->name); + const char *stripped_name = strip_workspace_name(config->strip_workspace_numbers, ws->name); - int width, height; - get_text_size(window->cairo, window->font, &width, &height, false, "%s", name); struct box_colors box_colors; if (ws->urgent) { box_colors = config->colors.urgent_workspace; @@ -213,26 +218,25 @@ static void render_workspace_button(struct window *window, struct config *config box_colors = config->colors.inactive_workspace; } + int width, height; + workspace_button_size(window, stripped_name, &width, &height); + // background cairo_set_source_u32(window->cairo, box_colors.background); - cairo_rectangle(window->cairo, *x, 1.5, width + ws_horizontal_padding * 2 - 1, - height + ws_vertical_padding * 2); + cairo_rectangle(window->cairo, *x, 1.5, width - 1, height); cairo_fill(window->cairo); // border cairo_set_source_u32(window->cairo, box_colors.border); - cairo_rectangle(window->cairo, *x, 1.5, width + ws_horizontal_padding * 2 - 1, - height + ws_vertical_padding * 2); + cairo_rectangle(window->cairo, *x, 1.5, width - 1, height); cairo_stroke(window->cairo); // text cairo_set_source_u32(window->cairo, box_colors.text); cairo_move_to(window->cairo, (int)*x + ws_horizontal_padding, margin); - pango_printf(window->cairo, window->font, false, "%s", name); - - *x += width + ws_horizontal_padding * 2 + ws_spacing; + pango_printf(window->cairo, window->font, false, "%s", stripped_name); - free(name); + *x += width + ws_spacing; } static void render_binding_mode_indicator(struct window *window, struct config *config, double pos) { diff --git a/swaybg/main.c b/swaybg/main.c index 4e0cc4b3..fbd0d16b 100644 --- a/swaybg/main.c +++ b/swaybg/main.c @@ -54,7 +54,6 @@ int main(int argc, const char **argv) { sway_abort("Failed to create surfaces."); } desktop_shell_set_background(registry->desktop_shell, output->output, window->surface); - window_make_shell(window); list_add(surfaces, window); #ifdef WITH_GDK_PIXBUF diff --git a/wayland/window.c b/wayland/window.c index e055e244..9b6e5b00 100644 --- a/wayland/window.c +++ b/wayland/window.c @@ -32,8 +32,8 @@ static void pointer_handle_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) { struct window *window = data; - window->pointer_input.last_x = sx_w; - window->pointer_input.last_y = sy_w; + window->pointer_input.last_x = wl_fixed_to_int(sx_w); + window->pointer_input.last_y = wl_fixed_to_int(sy_w); } static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32_t serial,