From e4f5e7ec9005ac2f74b14ef544707285b2ee6394 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Sat, 3 Oct 2020 15:51:12 -0500 Subject: [PATCH 1/5] swaybar: fix typo in comment --- swaybar/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swaybar/input.c b/swaybar/input.c index 4fe6dd93..1cb1f7a4 100644 --- a/swaybar/input.c +++ b/swaybar/input.c @@ -303,7 +303,7 @@ static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) { for (uint32_t axis = 0; axis < 2; ++axis) { if (seat->axis[axis].discrete_steps) { for (uint32_t step = 0; step < seat->axis[axis].discrete_steps; ++step) { - // Honestly, it would probabyl make sense to pass in + // Honestly, it would probably make sense to pass in // 'seat->axis[axis].value / seat->axis[axi].discrete_steps' here, // but it's only used to check whether it's positive or negative // so I don't think it's worth the risk of rounding errors. From e478df41848a01f885054b4c7e7b4db235cd7d97 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Mon, 5 Oct 2020 01:09:09 -0500 Subject: [PATCH 2/5] swaybar: improve read_pixmap routine --- swaybar/tray/item.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index a5660f62..49102fcc 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -43,12 +43,13 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, if (sd_bus_message_at_end(msg, 0)) { sway_log(SWAY_DEBUG, "%s %s no. of icons = 0", sni->watcher_id, prop); - return ret; + goto finish; } list_t *pixmaps = create_list(); if (!pixmaps) { - return -12; // -ENOMEM + ret = -12; // -ENOMEM + goto finish; } while (!sd_bus_message_at_end(msg, 0)) { @@ -93,7 +94,7 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, } if (pixmaps->length < 1) { - sway_log(SWAY_DEBUG, "%s %s no. of icons = 0", sni->watcher_id, prop); + sway_log(SWAY_ERROR, "%s %s no. of icons = 0", sni->watcher_id, prop); goto error; } @@ -102,9 +103,11 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, sway_log(SWAY_DEBUG, "%s %s no. of icons = %d", sni->watcher_id, prop, pixmaps->length); - return ret; + goto finish; error: list_free_items_and_destroy(pixmaps); +finish: + sd_bus_message_exit_container(msg); return ret; } From 0626e975fa02ba889ef2920aa86da8f53638ca8e Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Sat, 3 Oct 2020 15:57:41 -0500 Subject: [PATCH 3/5] swaybar: add SNI ToolTip support --- include/swaybar/tray/item.h | 8 +++++ swaybar/tray/item.c | 63 ++++++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/include/swaybar/tray/item.h b/include/swaybar/tray/item.h index c02a5582..a7a7ab2a 100644 --- a/include/swaybar/tray/item.h +++ b/include/swaybar/tray/item.h @@ -14,6 +14,13 @@ struct swaybar_pixmap { unsigned char pixels[]; }; +struct swaybar_sni_tool_tip { + char *icon_name; + list_t *icon_pixmap; // struct swaybar_pixmap * + char *title; + char *description; // can contain HTML subset , see https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/Markup/ +}; + struct swaybar_sni_slot { struct wl_list link; // swaybar_sni::slots struct swaybar_sni *sni; @@ -44,6 +51,7 @@ struct swaybar_sni { list_t *attention_icon_pixmap; // struct swaybar_pixmap * bool item_is_menu; char *menu; + struct swaybar_sni_tool_tip *tool_tip; char *icon_theme_path; // non-standard KDE property struct wl_list slots; // swaybar_sni_slot::link diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 49102fcc..7faa14a8 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -111,6 +111,50 @@ finish: return ret; } +static int read_sni_tool_tip(sd_bus_message *msg, struct swaybar_sni *sni, + const char *prop, struct swaybar_sni_tool_tip *tool_tip) { + int ret = sd_bus_message_enter_container(msg, 'r', "sa(iiay)ss"); + if (ret < 0) { + sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); + return ret; + } + + free(tool_tip->icon_name); + ret = sd_bus_message_read(msg, "s", &tool_tip->icon_name); + if (ret < 0) { + sway_log(SWAY_ERROR, "%s %s IconName: %s", sni->watcher_id, prop, strerror(-ret)); + goto error; + } + tool_tip->icon_name = strdup(tool_tip->icon_name); + sway_log(SWAY_DEBUG, "%s %s IconName = '%s'", sni->watcher_id, prop, tool_tip->icon_name); + // free(tool_tip->icon_pixmap); // need to free pixmaps first?? + ret = read_pixmap(msg, sni, prop, &tool_tip->icon_pixmap); + if (ret < 0) { + goto error; + } + free(tool_tip->title); + free(tool_tip->description); + ret = sd_bus_message_read(msg, "ss", &tool_tip->title, &tool_tip->description); + if (ret < 0) { + sway_log(SWAY_ERROR, "%s %s Title and Description: %s", sni->watcher_id, prop, strerror(-ret)); + goto error; + } + tool_tip->title = strdup(tool_tip->title); + tool_tip->description = strdup(tool_tip->description); + sway_log(SWAY_DEBUG, "%s %s Title = '%s'", sni->watcher_id, prop, tool_tip->title); + sway_log(SWAY_DEBUG, "%s %s Description = '%s'", sni->watcher_id, prop, tool_tip->description); + + // list_free_items_and_destroy(*dest); + // *dest = pixmaps; + + goto finish; +error: + // list_free_items_and_destroy(pixmaps); +finish: + sd_bus_message_exit_container(msg); + return ret; +} + static int get_property_callback(sd_bus_message *msg, void *data, sd_bus_error *error) { struct swaybar_sni_slot *d = data; @@ -134,9 +178,16 @@ static int get_property_callback(sd_bus_message *msg, void *data, } if (!type) { - ret = read_pixmap(msg, sni, prop, dest); - if (ret < 0) { - goto cleanup; + if (strcmp(prop, "ToolTip") == 0) { + ret = read_sni_tool_tip(msg, sni, prop, dest); + if (ret < 0) { + goto cleanup; + } + } else { + ret = read_pixmap(msg, sni, prop, dest); + if (ret < 0) { + goto cleanup; + } } } else { if (*type == 's' || *type == 'o') { @@ -164,6 +215,7 @@ static int get_property_callback(sd_bus_message *msg, void *data, set_sni_dirty(sni); } cleanup: + // sd_bus_message_exit_container(msg); wl_list_remove(&d->link); free(data); return ret; @@ -289,7 +341,7 @@ struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray) { } // Ignored: Category, Id, Title, WindowId, OverlayIconName, - // OverlayIconPixmap, AttentionMovieName, ToolTip + // OverlayIconPixmap, AttentionMovieName sni_get_property_async(sni, "Status", "s", &sni->status); sni_get_property_async(sni, "IconName", "s", &sni->icon_name); sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); @@ -297,10 +349,12 @@ struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray) { sni_get_property_async(sni, "AttentionIconPixmap", NULL, &sni->attention_icon_pixmap); sni_get_property_async(sni, "ItemIsMenu", "b", &sni->item_is_menu); sni_get_property_async(sni, "Menu", "o", &sni->menu); + sni_get_property_async(sni, "ToolTip", NULL, &sni->tool_tip); sni_match_signal_async(sni, "NewIcon", handle_new_icon); sni_match_signal_async(sni, "NewAttentionIcon", handle_new_attention_icon); sni_match_signal_async(sni, "NewStatus", handle_new_status); + //sni_match_signal_async(sni, "NewToolTip", handle_new_tool_tip); return sni; } @@ -320,6 +374,7 @@ void destroy_sni(struct swaybar_sni *sni) { free(sni->attention_icon_name); list_free_items_and_destroy(sni->attention_icon_pixmap); free(sni->menu); + free(sni->tool_tip); free(sni->icon_theme_path); struct swaybar_sni_slot *slot, *slot_tmp; From 5820299278eee0db4a77c5eeba4eb7308a7ca666 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Sat, 3 Oct 2020 15:59:39 -0500 Subject: [PATCH 4/5] swaybar: add SNI Title, Category, Id support --- include/swaybar/tray/item.h | 3 +++ swaybar/tray/item.c | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/include/swaybar/tray/item.h b/include/swaybar/tray/item.h index a7a7ab2a..df4f9a87 100644 --- a/include/swaybar/tray/item.h +++ b/include/swaybar/tray/item.h @@ -52,6 +52,9 @@ struct swaybar_sni { bool item_is_menu; char *menu; struct swaybar_sni_tool_tip *tool_tip; + char *title; + char *category; + char *id; char *icon_theme_path; // non-standard KDE property struct wl_list slots; // swaybar_sni_slot::link diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 7faa14a8..a91054c4 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -306,6 +306,29 @@ static int handle_new_status(sd_bus_message *msg, void *data, sd_bus_error *erro return ret; } +static int handle_new_title(sd_bus_message *msg, void *data, sd_bus_error *error) { + // NOTE(nms): unsure if sni_check_msg_sender is valid (I assume this is to check if title property is sent with the + // NewTitle message) + struct swaybar_sni *sni = data; + int ret = sni_check_msg_sender(sni, msg, "title"); + if (ret == 1) { + char *title; + int r = sd_bus_message_read(msg, "s", &title); + if (r < 0) { + sway_log(SWAY_ERROR, "%s new title error: %s", sni->watcher_id, strerror(-ret)); + ret = r; + } else { + free(sni->title); + sni->title = strdup(title); + sway_log(SWAY_DEBUG, "%s has new title = '%s'", sni->watcher_id, title); + set_sni_dirty(sni); + } + } else { + sni_get_property_async(sni, "Title", "s", &sni->title); + } + return ret; +} + static void sni_match_signal_async(struct swaybar_sni *sni, char *signal, sd_bus_message_handler_t callback) { struct swaybar_sni_slot *slot = calloc(1, sizeof(struct swaybar_sni_slot)); @@ -340,8 +363,7 @@ struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray) { sni_get_property_async(sni, "IconThemePath", "s", &sni->icon_theme_path); } - // Ignored: Category, Id, Title, WindowId, OverlayIconName, - // OverlayIconPixmap, AttentionMovieName + // Ignored: WindowId, OverlayIconName, OverlayIconPixmap, AttentionMovieName sni_get_property_async(sni, "Status", "s", &sni->status); sni_get_property_async(sni, "IconName", "s", &sni->icon_name); sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); @@ -349,11 +371,15 @@ struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray) { sni_get_property_async(sni, "AttentionIconPixmap", NULL, &sni->attention_icon_pixmap); sni_get_property_async(sni, "ItemIsMenu", "b", &sni->item_is_menu); sni_get_property_async(sni, "Menu", "o", &sni->menu); + sni_get_property_async(sni, "Title", "s", &sni->title); sni_get_property_async(sni, "ToolTip", NULL, &sni->tool_tip); + sni_get_property_async(sni, "Category", "s", &sni->category); + sni_get_property_async(sni, "Id", "s", &sni->id); sni_match_signal_async(sni, "NewIcon", handle_new_icon); sni_match_signal_async(sni, "NewAttentionIcon", handle_new_attention_icon); sni_match_signal_async(sni, "NewStatus", handle_new_status); + sni_match_signal_async(sni, "NewTitle", handle_new_title); //sni_match_signal_async(sni, "NewToolTip", handle_new_tool_tip); return sni; @@ -374,7 +400,10 @@ void destroy_sni(struct swaybar_sni *sni) { free(sni->attention_icon_name); list_free_items_and_destroy(sni->attention_icon_pixmap); free(sni->menu); + free(sni->title); free(sni->tool_tip); + free(sni->category); + free(sni->id); free(sni->icon_theme_path); struct swaybar_sni_slot *slot, *slot_tmp; From 6edab9023038432905f185a0849d9080f9f71aa0 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Sun, 18 Oct 2020 19:16:35 -0500 Subject: [PATCH 5/5] WIP render hotspot tooltip on pointer motion does not work. due to rendering outside render loop / rendering to previous buffer/surface? --- swaybar/input.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/swaybar/input.c b/swaybar/input.c index 1cb1f7a4..333f31a1 100644 --- a/swaybar/input.c +++ b/swaybar/input.c @@ -5,6 +5,7 @@ #include #include "list.h" #include "log.h" +#include "pango.h" #include "swaybar/bar.h" #include "swaybar/config.h" #include "swaybar/input.h" @@ -121,8 +122,68 @@ static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { struct swaybar_seat *seat = data; - seat->pointer.x = wl_fixed_to_double(surface_x); - seat->pointer.y = wl_fixed_to_double(surface_y); + struct swaybar_pointer *pointer = &seat->pointer; + struct swaybar_output *output = pointer->current; + + pointer->x = wl_fixed_to_double(surface_x); + pointer->y = wl_fixed_to_double(surface_y); + + double px = pointer->x * output->scale; + double py = pointer->y * output->scale; + + sway_log(SWAY_DEBUG, "wl_pointer_motion"); + struct swaybar_hotspot *hotspot; + wl_list_for_each(hotspot, &output->hotspots, link) { + if (px >= hotspot->x && py >= hotspot->y + && px < hotspot->x + hotspot->width + && py < hotspot->y + hotspot->height) { + // cursor in hotspot + sway_log(SWAY_DEBUG, "wl_pointer_motion cursor in hotspot %d %d", surface_x, surface_y); + + //struct swaybar *bar = seat->bar; + struct swaybar *bar = output->bar; + struct swaybar_config *config = bar->config; + + // create cairo/pango graphics + cairo_surface_t *recorder = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA, NULL); + cairo_t *cairo = cairo_create(recorder); + + cairo_set_source_u32(cairo, config->colors.focused_statusline); + + //pango_printf(cairo, config->font, output->scale, false, "%s", (struct swaybar_sni *)(hotspot->data)->watcher_id); + pango_printf(cairo, config->font, output->scale, false, "%d %d pointer is hovering", surface_x, surface_y); + + // draw icon or menu indicator if needed + int text_width, text_height; + get_text_size(cairo, config->font, &text_width, &text_height, NULL, + output->scale, false, "%d %d pointer is hovering", px ,py); + //int padding = config->tray_padding * output->scale; + //int width = 2 * padding + text_width; + //int height = 2 * padding + text_height; + + //int size = 16; + //int x = -2 * padding - size; + //int y = height + padding + (text_height - size + 1) / 2; + + cairo_t *shm = output->current_buffer->cairo; + + cairo_save(shm); + cairo_set_operator(shm, CAIRO_OPERATOR_CLEAR); + cairo_paint(shm); + cairo_restore(shm); + + cairo_set_source_surface(shm, recorder, surface_x, surface_y); + cairo_paint(shm); + + wl_surface_damage(output->surface, surface_x, surface_y, text_width, text_height); + wl_surface_commit(output->surface); + + cairo_surface_destroy(recorder); + cairo_destroy(cairo); + + return; + } + } } static bool check_bindings(struct swaybar *bar, uint32_t button,