[PATCH 2/3] window: add simple text tooltip handlers
Tiago Vignatti
tiago.vignatti at intel.com
Wed May 23 12:06:27 PDT 2012
Using set_transient.
Signed-off-by: Tiago Vignatti <tiago.vignatti at intel.com>
---
clients/window.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
clients/window.h | 7 ++
2 files changed, 195 insertions(+)
diff --git a/clients/window.c b/clients/window.c
index 489c35a..9e9b209 100644
--- a/clients/window.c
+++ b/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;
@@ -1000,6 +1020,174 @@ window_get_wl_shell_surface(struct window *window)
}
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 db232e0..bc0e43a 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
--
1.7.9.5
More information about the wayland-devel
mailing list