1/* testtooltips.c: Test application for GTK >= 2.12 tooltips code
2 *
3 * Copyright (C) 2006-2007 Imendio AB
4 * Contact: Kristian Rietveld <kris@imendio.com>
5 *
6 * This work is provided "as is"; redistribution and modification
7 * in whole or in part, in any medium, physical or electronic is
8 * permitted without restriction.
9 *
10 * This work is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 *
14 * In no event shall the authors or contributors be liable for any
15 * direct, indirect, incidental, special, exemplary, or consequential
16 * damages (including, but not limited to, procurement of substitute
17 * goods or services; loss of use, data, or profits; or business
18 * interruption) however caused and on any theory of liability, whether
19 * in contract, strict liability, or tort (including negligence or
20 * otherwise) arising in any way out of the use of this software, even
21 * if advised of the possibility of such damage.
22 */
23
24#include <gtk/gtk.h>
25
26typedef struct _MyTooltip MyTooltip;
27typedef struct _MyTooltipClass MyTooltipClass;
28
29
30struct _MyTooltip
31{
32 GtkWidget parent_instance;
33};
34
35struct _MyTooltipClass
36{
37 GtkWidgetClass parent_class;
38};
39
40static GType my_tooltip_get_type (void);
41G_DEFINE_TYPE (MyTooltip, my_tooltip, GTK_TYPE_WIDGET)
42
43static void
44my_tooltip_init (MyTooltip *tt)
45{
46 GtkWidget *label = gtk_label_new (str: "Some text in a tooltip");
47
48 gtk_widget_set_parent (widget: label, GTK_WIDGET (tt));
49
50 gtk_widget_add_css_class (GTK_WIDGET (tt), css_class: "background");
51}
52
53static void
54my_tooltip_class_init (MyTooltipClass *tt_class)
55{
56 gtk_widget_class_set_layout_manager_type (GTK_WIDGET_CLASS (tt_class), GTK_TYPE_BIN_LAYOUT);
57 gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (tt_class), name: "tooltip");
58}
59
60static gboolean
61query_tooltip_cb (GtkWidget *widget,
62 int x,
63 int y,
64 gboolean keyboard_tip,
65 GtkTooltip *tooltip,
66 gpointer data)
67{
68 gtk_tooltip_set_markup (tooltip, markup: gtk_button_get_label (GTK_BUTTON (widget)));
69 gtk_tooltip_set_icon_from_icon_name (tooltip, icon_name: "edit-delete");
70
71 return TRUE;
72}
73
74static gboolean
75query_tooltip_text_view_cb (GtkWidget *widget,
76 int x,
77 int y,
78 gboolean keyboard_tip,
79 GtkTooltip *tooltip,
80 gpointer data)
81{
82 GtkTextTag *tag = data;
83 GtkTextIter iter;
84 GtkTextView *text_view = GTK_TEXT_VIEW (widget);
85 GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
86
87 if (keyboard_tip)
88 {
89 int offset;
90
91 g_object_get (object: buffer, first_property_name: "cursor-position", &offset, NULL);
92 gtk_text_buffer_get_iter_at_offset (buffer, iter: &iter, char_offset: offset);
93 }
94 else
95 {
96 int bx, by, trailing;
97
98 gtk_text_view_window_to_buffer_coords (text_view, win: GTK_TEXT_WINDOW_TEXT,
99 window_x: x, window_y: y, buffer_x: &bx, buffer_y: &by);
100 gtk_text_view_get_iter_at_position (text_view, iter: &iter, trailing: &trailing, x: bx, y: by);
101 }
102
103 if (gtk_text_iter_has_tag (iter: &iter, tag))
104 gtk_tooltip_set_text (tooltip, text: "Tooltip on text tag");
105 else
106 return FALSE;
107
108 return TRUE;
109}
110
111static gboolean
112query_tooltip_tree_view_cb (GtkWidget *widget,
113 int x,
114 int y,
115 gboolean keyboard_tip,
116 GtkTooltip *tooltip,
117 gpointer data)
118{
119 GtkTreeIter iter;
120 GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
121 GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
122 GtkTreePath *path = NULL;
123 char *tmp;
124 char *pathstring;
125
126 char buffer[512];
127
128 if (!gtk_tree_view_get_tooltip_context (tree_view, x, y,
129 keyboard_tip,
130 model: &model, path: &path, iter: &iter))
131 return FALSE;
132
133 gtk_tree_model_get (tree_model: model, iter: &iter, 0, &tmp, -1);
134 pathstring = gtk_tree_path_to_string (path);
135
136 g_snprintf (string: buffer, n: 511, format: "<b>Path %s:</b> %s", pathstring, tmp);
137 gtk_tooltip_set_markup (tooltip, markup: buffer);
138
139 gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
140
141 gtk_tree_path_free (path);
142 g_free (mem: pathstring);
143 g_free (mem: tmp);
144
145 return TRUE;
146}
147
148static GtkTreeModel *
149create_model (void)
150{
151 GtkTreeStore *store;
152 GtkTreeIter iter;
153
154 store = gtk_tree_store_new (n_columns: 1, G_TYPE_STRING);
155
156 /* A tree store with some random words ... */
157 gtk_tree_store_insert_with_values (tree_store: store, iter: &iter, NULL, position: 0,
158 0, "File Manager", -1);
159 gtk_tree_store_insert_with_values (tree_store: store, iter: &iter, NULL, position: 0,
160 0, "Gossip", -1);
161 gtk_tree_store_insert_with_values (tree_store: store, iter: &iter, NULL, position: 0,
162 0, "System Settings", -1);
163 gtk_tree_store_insert_with_values (tree_store: store, iter: &iter, NULL, position: 0,
164 0, "The GIMP", -1);
165 gtk_tree_store_insert_with_values (tree_store: store, iter: &iter, NULL, position: 0,
166 0, "Terminal", -1);
167 gtk_tree_store_insert_with_values (tree_store: store, iter: &iter, NULL, position: 0,
168 0, "Word Processor", -1);
169
170 return GTK_TREE_MODEL (store);
171}
172
173static void
174selection_changed_cb (GtkTreeSelection *selection,
175 GtkWidget *tree_view)
176{
177 gtk_widget_trigger_tooltip_query (widget: tree_view);
178}
179
180static struct Rectangle
181{
182 int x;
183 int y;
184 float r;
185 float g;
186 float b;
187 const char *tooltip;
188}
189rectangles[] =
190{
191 { 10, 10, 0.0, 0.0, 0.9, "Blue box!" },
192 { 200, 170, 1.0, 0.0, 0.0, "Red thing" },
193 { 100, 50, 0.8, 0.8, 0.0, "Yellow thing" }
194};
195
196static gboolean
197query_tooltip_drawing_area_cb (GtkWidget *widget,
198 int x,
199 int y,
200 gboolean keyboard_tip,
201 GtkTooltip *tooltip,
202 gpointer data)
203{
204 int i;
205
206 if (keyboard_tip)
207 return FALSE;
208
209 for (i = 0; i < G_N_ELEMENTS (rectangles); i++)
210 {
211 struct Rectangle *r = &rectangles[i];
212
213 if (r->x < x && x < r->x + 50
214 && r->y < y && y < r->y + 50)
215 {
216 gtk_tooltip_set_markup (tooltip, markup: r->tooltip);
217 return TRUE;
218 }
219 }
220
221 return FALSE;
222}
223
224static void
225drawing_area_draw (GtkDrawingArea *drawing_area,
226 cairo_t *cr,
227 int width,
228 int height,
229 gpointer data)
230{
231 int i;
232
233 cairo_set_source_rgb (cr, red: 1.0, green: 1.0, blue: 1.0);
234 cairo_paint (cr);
235
236 for (i = 0; i < G_N_ELEMENTS (rectangles); i++)
237 {
238 struct Rectangle *r = &rectangles[i];
239
240 cairo_rectangle (cr, x: r->x, y: r->y, width: 50, height: 50);
241 cairo_set_source_rgb (cr, red: r->r, green: r->g, blue: r->b);
242 cairo_stroke (cr);
243
244 cairo_rectangle (cr, x: r->x, y: r->y, width: 50, height: 50);
245 cairo_set_source_rgba (cr, red: r->r, green: r->g, blue: r->b, alpha: 0.5);
246 cairo_fill (cr);
247 }
248}
249
250static gboolean
251query_tooltip_label_cb (GtkWidget *widget,
252 int x,
253 int y,
254 gboolean keyboard_tip,
255 GtkTooltip *tooltip,
256 gpointer data)
257{
258 GtkWidget *custom = data;
259
260 gtk_tooltip_set_custom (tooltip, custom_widget: custom);
261
262 return TRUE;
263}
264
265static void
266quit_cb (GtkWidget *widget,
267 gpointer data)
268{
269 gboolean *done = data;
270
271 *done = TRUE;
272
273 g_main_context_wakeup (NULL);
274}
275
276int
277main (int argc, char *argv[])
278{
279 GtkWidget *window;
280 GtkWidget *box;
281 GtkWidget *drawing_area;
282 GtkWidget *button;
283 GtkWidget *tooltip;
284 GtkWidget *popover;
285 GtkWidget *box2;
286 GtkWidget *custom;
287
288 GtkWidget *tree_view;
289 GtkTreeViewColumn *column;
290
291 GtkWidget *text_view;
292 GtkTextBuffer *buffer;
293 GtkTextIter iter;
294 GtkTextTag *tag;
295
296 const char *text, *markup;
297 gboolean done = FALSE;
298
299 gtk_init ();
300
301 window = gtk_window_new ();
302 gtk_window_set_title (GTK_WINDOW (window), title: "Tooltips test");
303 g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
304
305 box = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 3);
306 gtk_window_set_child (GTK_WINDOW (window), child: box);
307
308 tooltip = g_object_new (object_type: my_tooltip_get_type (), NULL);
309 gtk_widget_set_margin_top (widget: tooltip, margin: 20);
310 gtk_widget_set_margin_bottom (widget: tooltip, margin: 20);
311 gtk_widget_set_halign (widget: tooltip, align: GTK_ALIGN_CENTER);
312 gtk_box_append (GTK_BOX (box), child: tooltip);
313
314
315 /* A check button using the tooltip-markup property */
316 button = gtk_check_button_new_with_label (label: "This one uses the tooltip-markup property");
317 gtk_widget_set_tooltip_text (widget: button, text: "Hello, I am a static tooltip.");
318 gtk_box_append (GTK_BOX (box), child: button);
319
320 text = gtk_widget_get_tooltip_text (widget: button);
321 markup = gtk_widget_get_tooltip_markup (widget: button);
322 g_assert_true (g_str_equal ("Hello, I am a static tooltip.", text));
323 g_assert_true (g_str_equal ("Hello, I am a static tooltip.", markup));
324
325 /* A check button using the query-tooltip signal */
326 button = gtk_check_button_new_with_label (label: "I use the query-tooltip signal");
327 g_object_set (object: button, first_property_name: "has-tooltip", TRUE, NULL);
328 g_signal_connect (button, "query-tooltip",
329 G_CALLBACK (query_tooltip_cb), NULL);
330 gtk_box_append (GTK_BOX (box), child: button);
331
332 /* A label */
333 button = gtk_label_new (str: "I am just a label");
334 gtk_label_set_selectable (GTK_LABEL (button), FALSE);
335 gtk_widget_set_tooltip_text (widget: button, text: "Label & and tooltip");
336 gtk_box_append (GTK_BOX (box), child: button);
337
338 text = gtk_widget_get_tooltip_text (widget: button);
339 markup = gtk_widget_get_tooltip_markup (widget: button);
340 g_assert_true (g_str_equal ("Label & and tooltip", text));
341 g_assert_true (g_str_equal ("Label &amp; and tooltip", markup));
342
343 /* A selectable label */
344 button = gtk_label_new (str: "I am a selectable label");
345 gtk_label_set_selectable (GTK_LABEL (button), TRUE);
346 gtk_widget_set_tooltip_markup (widget: button, markup: "<b>Another</b> Label tooltip");
347 gtk_box_append (GTK_BOX (box), child: button);
348
349 text = gtk_widget_get_tooltip_text (widget: button);
350 markup = gtk_widget_get_tooltip_markup (widget: button);
351 g_assert_true (g_str_equal ("Another Label tooltip", text));
352 g_assert_true (g_str_equal ("<b>Another</b> Label tooltip", markup));
353
354 /* An insensitive button */
355 button = gtk_button_new_with_label (label: "This one is insensitive");
356 gtk_widget_set_sensitive (widget: button, FALSE);
357 g_object_set (object: button, first_property_name: "tooltip-text", "Insensitive!", NULL);
358 gtk_box_append (GTK_BOX (box), child: button);
359
360 /* Testcases from Kris without a tree view don't exist. */
361 tree_view = gtk_tree_view_new_with_model (model: create_model ());
362 gtk_widget_set_size_request (widget: tree_view, width: 200, height: 240);
363
364 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
365 position: 0, title: "Test",
366 cell: gtk_cell_renderer_text_new (),
367 "text", 0,
368 NULL);
369
370 g_object_set (object: tree_view, first_property_name: "has-tooltip", TRUE, NULL);
371 g_signal_connect (tree_view, "query-tooltip",
372 G_CALLBACK (query_tooltip_tree_view_cb), NULL);
373 g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)),
374 "changed", G_CALLBACK (selection_changed_cb), tree_view);
375
376 /* Set a tooltip on the column */
377 column = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), n: 0);
378 gtk_tree_view_column_set_clickable (tree_column: column, TRUE);
379 g_object_set (object: gtk_tree_view_column_get_button (tree_column: column), first_property_name: "tooltip-text", "Header", NULL);
380
381 gtk_box_append (GTK_BOX (box), child: tree_view);
382
383 /* And a text view for Matthias */
384 buffer = gtk_text_buffer_new (NULL);
385
386 gtk_text_buffer_get_end_iter (buffer, iter: &iter);
387 gtk_text_buffer_insert (buffer, iter: &iter, text: "Hello, the text ", len: -1);
388
389 tag = gtk_text_buffer_create_tag (buffer, tag_name: "bold", NULL);
390 g_object_set (object: tag, first_property_name: "weight", PANGO_WEIGHT_BOLD, NULL);
391
392 gtk_text_buffer_get_end_iter (buffer, iter: &iter);
393 gtk_text_buffer_insert_with_tags (buffer, iter: &iter, text: "in bold", len: -1, first_tag: tag, NULL);
394
395 gtk_text_buffer_get_end_iter (buffer, iter: &iter);
396 gtk_text_buffer_insert (buffer, iter: &iter, text: " has a tooltip!", len: -1);
397
398 text_view = gtk_text_view_new_with_buffer (buffer);
399 gtk_widget_set_size_request (widget: text_view, width: 200, height: 50);
400
401 g_object_set (object: text_view, first_property_name: "has-tooltip", TRUE, NULL);
402 g_signal_connect (text_view, "query-tooltip",
403 G_CALLBACK (query_tooltip_text_view_cb), tag);
404
405 gtk_box_append (GTK_BOX (box), child: text_view);
406
407 /* Drawing area */
408 drawing_area = gtk_drawing_area_new ();
409 gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (drawing_area), width: 320);
410 gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (drawing_area), height: 240);
411 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area),
412 draw_func: drawing_area_draw, NULL, NULL);
413 g_object_set (object: drawing_area, first_property_name: "has-tooltip", TRUE, NULL);
414 g_signal_connect (drawing_area, "query-tooltip",
415 G_CALLBACK (query_tooltip_drawing_area_cb), NULL);
416 gtk_box_append (GTK_BOX (box), child: drawing_area);
417
418 button = gtk_menu_button_new ();
419 gtk_widget_set_halign (widget: button, align: GTK_ALIGN_CENTER);
420 gtk_menu_button_set_label (GTK_MENU_BUTTON (button), label: "Custom tooltip I");
421 gtk_box_append (GTK_BOX (box), child: button);
422 popover = gtk_popover_new ();
423 gtk_menu_button_set_popover (GTK_MENU_BUTTON (button), popover);
424 box2 = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 0);
425 gtk_popover_set_child (GTK_POPOVER (popover), child: box2);
426
427 button = gtk_label_new (str: "Hidden here");
428 custom = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 5);
429 gtk_box_append (GTK_BOX (custom), child: gtk_label_new (str: "See, custom"));
430 gtk_box_append (GTK_BOX (custom), child: g_object_new (GTK_TYPE_SPINNER, first_property_name: "spinning", TRUE, NULL));
431 g_object_ref_sink (custom);
432 g_object_set (object: button, first_property_name: "has-tooltip", TRUE, NULL);
433 gtk_box_append (GTK_BOX (box2), child: button);
434 g_signal_connect (button, "query-tooltip",
435 G_CALLBACK (query_tooltip_label_cb), custom);
436
437 button = gtk_label_new (str: "Custom tooltip II");
438 custom = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 5);
439 gtk_box_append (GTK_BOX (custom), child: gtk_label_new (str: "See, custom too"));
440 gtk_box_append (GTK_BOX (custom), child: g_object_new (GTK_TYPE_SPINNER, first_property_name: "spinning", TRUE, NULL));
441 g_object_ref_sink (custom);
442 g_object_set (object: button, first_property_name: "has-tooltip", TRUE, NULL);
443 g_signal_connect (button, "query-tooltip",
444 G_CALLBACK (query_tooltip_label_cb), custom);
445 gtk_box_append (GTK_BOX (box), child: button);
446
447 /* Done! */
448 gtk_widget_show (widget: window);
449
450 while (!done)
451 g_main_context_iteration (NULL, TRUE);
452
453 return 0;
454}
455

source code of gtk/tests/testtooltips.c