window: add simple text tooltip handlers
Using set_transient. Signed-off-by: Tiago Vignatti <tiago.vignatti@intel.com>
This commit is contained in:
parent
99aeb1e72d
commit
82db9d80e6
188
clients/window.c
188
clients/window.c
@ -36,6 +36,7 @@
|
||||
#include <cairo.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
#include <pixman.h>
|
||||
|
||||
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user