window: add simple text tooltip handlers

Using set_transient.

Signed-off-by: Tiago Vignatti <tiago.vignatti@intel.com>
This commit is contained in:
Tiago Vignatti 2012-05-23 22:06:27 +03:00 committed by Kristian Høgsberg
parent 99aeb1e72d
commit 82db9d80e6
2 changed files with 195 additions and 0 deletions

View File

@ -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)

View File

@ -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