From 82db9d80e6d02279d4a974b8ab0cd76b37280550 Mon Sep 17 00:00:00 2001 From: Tiago Vignatti Date: Wed, 23 May 2012 22:06:27 +0300 Subject: [PATCH] window: add simple text tooltip handlers Using set_transient. Signed-off-by: Tiago Vignatti --- clients/window.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++ clients/window.h | 7 ++ 2 files changed, 195 insertions(+) diff --git a/clients/window.c b/clients/window.c index 489c35ac..9e9b2099 100644 --- a/clients/window.c +++ b/clients/window.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -169,6 +170,7 @@ struct window { struct widget { struct window *window; + struct tooltip *tooltip; struct wl_list child_list; struct wl_list link; struct rectangle allocation; @@ -180,6 +182,7 @@ struct widget { widget_button_handler_t button_handler; void *user_data; int opaque; + int tooltip_count; }; struct input { @@ -266,6 +269,16 @@ struct menu { menu_func_t func; }; +struct tooltip { + struct widget *parent; + struct window *window; + struct widget *widget; + char *entry; + struct task tooltip_task; + int tooltip_fd; + float x, y; +}; + struct shm_pool { struct wl_shm_pool *pool; size_t size; @@ -862,6 +875,8 @@ widget_create(struct window *window, void *data) widget->allocation = window->allocation; wl_list_init(&widget->child_list); widget->opaque = 0; + widget->tooltip = NULL; + widget->tooltip_count = 0; return widget; } @@ -892,6 +907,11 @@ widget_destroy(struct widget *widget) struct display *display = widget->window->display; struct input *input; + if (widget->tooltip) { + free(widget->tooltip); + widget->tooltip = NULL; + } + wl_list_for_each(input, &display->input_list, link) { if (input->focus_widget == widget) input->focus_widget = NULL; @@ -999,6 +1019,174 @@ window_get_wl_shell_surface(struct window *window) return window->shell_surface; } +static void +tooltip_redraw_handler(struct widget *widget, void *data) +{ + cairo_t *cr; + const int32_t r = 3; + struct tooltip *tooltip = data; + int32_t width, height; + struct window *window = widget->window; + + cr = cairo_create(window->cairo_surface); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0); + cairo_paint(cr); + + width = window->allocation.width; + height = window->allocation.height; + rounded_rect(cr, 0, 0, width, height, r); + + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.4, 0.8); + cairo_fill(cr); + + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_move_to(cr, 10, 16); + cairo_show_text(cr, tooltip->entry); + cairo_destroy(cr); +} + +static cairo_text_extents_t +get_text_extents(struct tooltip *tooltip) +{ + struct window *window; + cairo_t *cr; + cairo_text_extents_t extents; + + /* we borrow cairo_surface from the parent cause tooltip's wasn't + * created yet */ + window = tooltip->widget->window->parent; + cr = cairo_create(window->cairo_surface); + cairo_text_extents(cr, tooltip->entry, &extents); + cairo_destroy(cr); + + return extents; +} + +static int +window_create_tooltip(struct tooltip *tooltip) +{ + struct widget *parent = tooltip->parent; + struct display *display = parent->window->display; + struct window *window; + const int offset_y = 27; + const int margin = 3; + cairo_text_extents_t extents; + + if (tooltip->widget) + return 0; + + window = window_create_transient(display, parent->window, tooltip->x, + tooltip->y + offset_y, + WL_SHELL_SURFACE_TRANSIENT_INACTIVE); + if (!window) + return -1; + + tooltip->window = window; + tooltip->widget = window_add_widget(tooltip->window, tooltip); + + extents = get_text_extents(tooltip); + widget_set_redraw_handler(tooltip->widget, tooltip_redraw_handler); + window_schedule_resize(window, extents.width + 20, 20 + margin * 2); + + return 0; +} + +void +widget_destroy_tooltip(struct widget *parent) +{ + struct tooltip *tooltip = parent->tooltip; + + parent->tooltip_count = 0; + if (!tooltip) + return; + + if (tooltip->widget) { + widget_destroy(tooltip->widget); + window_destroy(tooltip->window); + tooltip->widget = NULL; + tooltip->window = NULL; + } + + close(tooltip->tooltip_fd); + free(tooltip->entry); + free(tooltip); + parent->tooltip = NULL; +} + +static void +tooltip_func(struct task *task, uint32_t events) +{ + struct tooltip *tooltip = + container_of(task, struct tooltip, tooltip_task); + uint64_t exp; + + read(tooltip->tooltip_fd, &exp, sizeof (uint64_t)); + window_create_tooltip(tooltip); +} + +#define TOOLTIP_TIMEOUT 500 +static int +tooltip_timer_reset(struct tooltip *tooltip) +{ + struct itimerspec its; + + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = TOOLTIP_TIMEOUT / 1000; + its.it_value.tv_nsec = (TOOLTIP_TIMEOUT % 1000) * 1000 * 1000; + if (timerfd_settime(tooltip->tooltip_fd, 0, &its, NULL) < 0) { + fprintf(stderr, "could not set timerfd\n: %m"); + return -1; + } + + return 0; +} + +int +widget_set_tooltip(struct widget *parent, char *entry, float x, float y) +{ + struct tooltip *tooltip = parent->tooltip; + + parent->tooltip_count++; + if (tooltip) { + tooltip->x = x; + tooltip->y = y; + tooltip_timer_reset(tooltip); + return 0; + } + + /* the handler might be triggered too fast via input device motion, so + * we need this check here to make sure tooltip is fully initialized */ + if (parent->tooltip_count > 1) + return 0; + + tooltip = malloc(sizeof *tooltip); + if (!tooltip) + return -1; + + parent->tooltip = tooltip; + tooltip->parent = parent; + tooltip->widget = NULL; + tooltip->window = NULL; + tooltip->x = x; + tooltip->y = y; + tooltip->entry = strdup(entry); + tooltip->tooltip_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); + if (tooltip->tooltip_fd < 0) { + fprintf(stderr, "could not create timerfd\n: %m"); + return -1; + } + + tooltip->tooltip_task.run = tooltip_func; + display_watch_fd(parent->window->display, tooltip->tooltip_fd, + EPOLLIN, &tooltip->tooltip_task); + tooltip_timer_reset(tooltip); + + return 0; +} + static void frame_resize_handler(struct widget *widget, int32_t width, int32_t height, void *data) diff --git a/clients/window.h b/clients/window.h index db232e0f..bc0e43a5 100644 --- a/clients/window.h +++ b/clients/window.h @@ -306,8 +306,15 @@ window_set_title(struct window *window, const char *title); const char * window_get_title(struct window *window); +int +widget_set_tooltip(struct widget *parent, char *entry, float x, float y); + +void +widget_destroy_tooltip(struct widget *parent); + struct widget * widget_add_widget(struct widget *parent, void *data); + void widget_destroy(struct widget *widget); void