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 
26 static gboolean
query_tooltip_cb(GtkWidget * widget,gint x,gint y,gboolean keyboard_tip,GtkTooltip * tooltip,gpointer data)27 query_tooltip_cb (GtkWidget  *widget,
28 		  gint        x,
29 		  gint        y,
30 		  gboolean    keyboard_tip,
31 		  GtkTooltip *tooltip,
32 		  gpointer    data)
33 {
34   gtk_tooltip_set_markup (tooltip, gtk_button_get_label (GTK_BUTTON (widget)));
35   gtk_tooltip_set_icon_from_stock (tooltip, GTK_STOCK_DELETE,
36 				   GTK_ICON_SIZE_MENU);
37 
38   return TRUE;
39 }
40 
41 static gboolean
query_tooltip_custom_cb(GtkWidget * widget,gint x,gint y,gboolean keyboard_tip,GtkTooltip * tooltip,gpointer data)42 query_tooltip_custom_cb (GtkWidget  *widget,
43 			 gint        x,
44 			 gint        y,
45 			 gboolean    keyboard_tip,
46 			 GtkTooltip *tooltip,
47 			 gpointer    data)
48 {
49   GdkColor color = { 0, 0, 65535 };
50   GtkWindow *window = gtk_widget_get_tooltip_window (widget);
51 
52   gtk_widget_modify_bg (GTK_WIDGET (window), GTK_STATE_NORMAL, &color);
53 
54   return TRUE;
55 }
56 
57 static gboolean
query_tooltip_text_view_cb(GtkWidget * widget,gint x,gint y,gboolean keyboard_tip,GtkTooltip * tooltip,gpointer data)58 query_tooltip_text_view_cb (GtkWidget  *widget,
59 			    gint        x,
60 			    gint        y,
61 			    gboolean    keyboard_tip,
62 			    GtkTooltip *tooltip,
63 			    gpointer    data)
64 {
65   GtkTextTag *tag = data;
66   GtkTextIter iter;
67   GtkTextView *text_view = GTK_TEXT_VIEW (widget);
68 
69   if (keyboard_tip)
70     {
71       gint offset;
72 
73       g_object_get (text_view->buffer, "cursor-position", &offset, NULL);
74       gtk_text_buffer_get_iter_at_offset (text_view->buffer, &iter, offset);
75     }
76   else
77     {
78       gint bx, by, trailing;
79 
80       gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_TEXT,
81 					     x, y, &bx, &by);
82       gtk_text_view_get_iter_at_position (text_view, &iter, &trailing, bx, by);
83     }
84 
85   if (gtk_text_iter_has_tag (&iter, tag))
86     gtk_tooltip_set_text (tooltip, "Tooltip on text tag");
87   else
88    return FALSE;
89 
90   return TRUE;
91 }
92 
93 static gboolean
query_tooltip_tree_view_cb(GtkWidget * widget,gint x,gint y,gboolean keyboard_tip,GtkTooltip * tooltip,gpointer data)94 query_tooltip_tree_view_cb (GtkWidget  *widget,
95 			    gint        x,
96 			    gint        y,
97 			    gboolean    keyboard_tip,
98 			    GtkTooltip *tooltip,
99 			    gpointer    data)
100 {
101   GtkTreeIter iter;
102   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
103   GtkTreeModel *model = gtk_tree_view_get_model (tree_view);
104   GtkTreePath *path = NULL;
105   gchar *tmp;
106   gchar *pathstring;
107 
108   char buffer[512];
109 
110   if (!gtk_tree_view_get_tooltip_context (tree_view, &x, &y,
111 					  keyboard_tip,
112 					  &model, &path, &iter))
113     return FALSE;
114 
115   gtk_tree_model_get (model, &iter, 0, &tmp, -1);
116   pathstring = gtk_tree_path_to_string (path);
117 
118   g_snprintf (buffer, 511, "<b>Path %s:</b> %s", pathstring, tmp);
119   gtk_tooltip_set_markup (tooltip, buffer);
120 
121   gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
122 
123   gtk_tree_path_free (path);
124   g_free (pathstring);
125   g_free (tmp);
126 
127   return TRUE;
128 }
129 
130 static GtkTreeModel *
create_model(void)131 create_model (void)
132 {
133   GtkTreeStore *store;
134   GtkTreeIter iter;
135 
136   store = gtk_tree_store_new (1, G_TYPE_STRING);
137 
138   /* A tree store with some random words ... */
139   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
140 				     0, "File Manager", -1);
141   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
142 				     0, "Gossip", -1);
143   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
144 				     0, "System Settings", -1);
145   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
146 				     0, "The GIMP", -1);
147   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
148 				     0, "Terminal", -1);
149   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
150 				     0, "Word Processor", -1);
151 
152   return GTK_TREE_MODEL (store);
153 }
154 
155 static void
selection_changed_cb(GtkTreeSelection * selection,GtkWidget * tree_view)156 selection_changed_cb (GtkTreeSelection *selection,
157 		      GtkWidget        *tree_view)
158 {
159   gtk_widget_trigger_tooltip_query (tree_view);
160 }
161 
162 static struct Rectangle
163 {
164   gint x;
165   gint y;
166   gfloat r;
167   gfloat g;
168   gfloat b;
169   const char *tooltip;
170 }
171 rectangles[] =
172 {
173   { 10, 10, 0.0, 0.0, 0.9, "Blue box!" },
174   { 200, 170, 1.0, 0.0, 0.0, "Red thing" },
175   { 100, 50, 0.8, 0.8, 0.0, "Yellow thing" }
176 };
177 
178 static gboolean
query_tooltip_drawing_area_cb(GtkWidget * widget,gint x,gint y,gboolean keyboard_tip,GtkTooltip * tooltip,gpointer data)179 query_tooltip_drawing_area_cb (GtkWidget  *widget,
180 			       gint        x,
181 			       gint        y,
182 			       gboolean    keyboard_tip,
183 			       GtkTooltip *tooltip,
184 			       gpointer    data)
185 {
186   gint i;
187 
188   if (keyboard_tip)
189     return FALSE;
190 
191   for (i = 0; i < G_N_ELEMENTS (rectangles); i++)
192     {
193       struct Rectangle *r = &rectangles[i];
194 
195       if (r->x < x && x < r->x + 50
196 	  && r->y < y && y < r->y + 50)
197         {
198 	  gtk_tooltip_set_markup (tooltip, r->tooltip);
199 	  return TRUE;
200 	}
201     }
202 
203   return FALSE;
204 }
205 
206 static gboolean
drawing_area_expose(GtkWidget * drawing_area,GdkEventExpose * event,gpointer data)207 drawing_area_expose (GtkWidget      *drawing_area,
208 		     GdkEventExpose *event,
209 		     gpointer        data)
210 {
211   gint i;
212   cairo_t *cr;
213 
214   gdk_window_get_pointer (drawing_area->window, NULL, NULL, NULL);
215 
216   cr = gdk_cairo_create (drawing_area->window);
217 
218   cairo_rectangle (cr, 0, 0,
219 		   drawing_area->allocation.width,
220 		   drawing_area->allocation.height);
221   cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
222   cairo_fill (cr);
223 
224   for (i = 0; i < G_N_ELEMENTS (rectangles); i++)
225     {
226       struct Rectangle *r = &rectangles[i];
227 
228       cairo_rectangle (cr, r->x, r->y, 50, 50);
229       cairo_set_source_rgb (cr, r->r, r->g, r->b);
230       cairo_stroke (cr);
231 
232       cairo_rectangle (cr, r->x, r->y, 50, 50);
233       cairo_set_source_rgba (cr, r->r, r->g, r->b, 0.5);
234       cairo_fill (cr);
235     }
236 
237   cairo_destroy (cr);
238 
239   return FALSE;
240 }
241 
242 static gboolean
query_tooltip_label_cb(GtkWidget * widget,gint x,gint y,gboolean keyboard_tip,GtkTooltip * tooltip,gpointer data)243 query_tooltip_label_cb (GtkWidget  *widget,
244 			gint        x,
245 			gint        y,
246 			gboolean    keyboard_tip,
247 			GtkTooltip *tooltip,
248 			gpointer    data)
249 {
250   GtkWidget *custom = data;
251 
252   gtk_tooltip_set_custom (tooltip, custom);
253 
254   return TRUE;
255 }
256 
257 int
main(int argc,char * argv[])258 main (int argc, char *argv[])
259 {
260   GtkWidget *window;
261   GtkWidget *box;
262   GtkWidget *drawing_area;
263   GtkWidget *button;
264   GtkWidget *label;
265 
266   GtkWidget *tooltip_window;
267   GtkWidget *tooltip_button;
268 
269   GtkWidget *tree_view;
270   GtkTreeViewColumn *column;
271 
272   GtkWidget *text_view;
273   GtkTextBuffer *buffer;
274   GtkTextIter iter;
275   GtkTextTag *tag;
276 
277   gchar *text, *markup;
278 
279   gtk_init (&argc, &argv);
280 
281   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
282   gtk_window_set_title (GTK_WINDOW (window), "Tooltips test");
283   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
284   g_signal_connect (window, "delete_event",
285 		    G_CALLBACK (gtk_main_quit), NULL);
286 
287   box = gtk_vbox_new (FALSE, 3);
288   gtk_container_add (GTK_CONTAINER (window), box);
289 
290   /* A check button using the tooltip-markup property */
291   button = gtk_check_button_new_with_label ("This one uses the tooltip-markup property");
292   gtk_widget_set_tooltip_text (button, "Hello, I am a static tooltip.");
293   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
294 
295   text = gtk_widget_get_tooltip_text (button);
296   markup = gtk_widget_get_tooltip_markup (button);
297   g_assert (g_str_equal ("Hello, I am a static tooltip.", text));
298   g_assert (g_str_equal ("Hello, I am a static tooltip.", markup));
299   g_free (text); g_free (markup);
300 
301   /* A check button using the query-tooltip signal */
302   button = gtk_check_button_new_with_label ("I use the query-tooltip signal");
303   g_object_set (button, "has-tooltip", TRUE, NULL);
304   g_signal_connect (button, "query-tooltip",
305 		    G_CALLBACK (query_tooltip_cb), NULL);
306   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
307 
308   /* A label */
309   button = gtk_label_new ("I am just a label");
310   gtk_label_set_selectable (GTK_LABEL (button), FALSE);
311   gtk_widget_set_tooltip_text (button, "Label & and tooltip");
312   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
313 
314   text = gtk_widget_get_tooltip_text (button);
315   markup = gtk_widget_get_tooltip_markup (button);
316   g_assert (g_str_equal ("Label & and tooltip", text));
317   g_assert (g_str_equal ("Label &amp; and tooltip", markup));
318   g_free (text); g_free (markup);
319 
320   /* A selectable label */
321   button = gtk_label_new ("I am a selectable label");
322   gtk_label_set_selectable (GTK_LABEL (button), TRUE);
323   gtk_widget_set_tooltip_markup (button, "<b>Another</b> Label tooltip");
324   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
325 
326   text = gtk_widget_get_tooltip_text (button);
327   markup = gtk_widget_get_tooltip_markup (button);
328   g_assert (g_str_equal ("Another Label tooltip", text));
329   g_assert (g_str_equal ("<b>Another</b> Label tooltip", markup));
330   g_free (text); g_free (markup);
331 
332   /* Another one, with a custom tooltip window */
333   button = gtk_check_button_new_with_label ("This one has a custom tooltip window!");
334   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
335 
336   tooltip_window = gtk_window_new (GTK_WINDOW_POPUP);
337   tooltip_button = gtk_label_new ("blaat!");
338   gtk_container_add (GTK_CONTAINER (tooltip_window), tooltip_button);
339   gtk_widget_show (tooltip_button);
340 
341   gtk_widget_set_tooltip_window (button, GTK_WINDOW (tooltip_window));
342   g_signal_connect (button, "query-tooltip",
343 		    G_CALLBACK (query_tooltip_custom_cb), NULL);
344   g_object_set (button, "has-tooltip", TRUE, NULL);
345 
346   /* An insensitive button */
347   button = gtk_button_new_with_label ("This one is insensitive");
348   gtk_widget_set_sensitive (button, FALSE);
349   g_object_set (button, "tooltip-text", "Insensitive!", NULL);
350   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
351 
352   /* Testcases from Kris without a tree view don't exist. */
353   tree_view = gtk_tree_view_new_with_model (create_model ());
354   gtk_widget_set_size_request (tree_view, 200, 240);
355 
356   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
357 					       0, "Test",
358 					       gtk_cell_renderer_text_new (),
359 					       "text", 0,
360 					       NULL);
361 
362   g_object_set (tree_view, "has-tooltip", TRUE, NULL);
363   g_signal_connect (tree_view, "query-tooltip",
364 		    G_CALLBACK (query_tooltip_tree_view_cb), NULL);
365   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)),
366 		    "changed", G_CALLBACK (selection_changed_cb), tree_view);
367 
368   /* Set a tooltip on the column */
369   column = gtk_tree_view_get_column (GTK_TREE_VIEW (tree_view), 0);
370   gtk_tree_view_column_set_clickable (column, TRUE);
371   g_object_set (column->button, "tooltip-text", "Header", NULL);
372 
373   gtk_box_pack_start (GTK_BOX (box), tree_view, FALSE, FALSE, 2);
374 
375   /* And a text view for Matthias */
376   buffer = gtk_text_buffer_new (NULL);
377 
378   gtk_text_buffer_get_end_iter (buffer, &iter);
379   gtk_text_buffer_insert (buffer, &iter, "Hello, the text ", -1);
380 
381   tag = gtk_text_buffer_create_tag (buffer, "bold", NULL);
382   g_object_set (tag, "weight", PANGO_WEIGHT_BOLD, NULL);
383 
384   gtk_text_buffer_get_end_iter (buffer, &iter);
385   gtk_text_buffer_insert_with_tags (buffer, &iter, "in bold", -1, tag, NULL);
386 
387   gtk_text_buffer_get_end_iter (buffer, &iter);
388   gtk_text_buffer_insert (buffer, &iter, " has a tooltip!", -1);
389 
390   text_view = gtk_text_view_new_with_buffer (buffer);
391   gtk_widget_set_size_request (text_view, 200, 50);
392 
393   g_object_set (text_view, "has-tooltip", TRUE, NULL);
394   g_signal_connect (text_view, "query-tooltip",
395 		    G_CALLBACK (query_tooltip_text_view_cb), tag);
396 
397   gtk_box_pack_start (GTK_BOX (box), text_view, FALSE, FALSE, 2);
398 
399   /* Drawing area */
400   drawing_area = gtk_drawing_area_new ();
401   gtk_widget_set_size_request (drawing_area, 320, 240);
402   g_object_set (drawing_area, "has-tooltip", TRUE, NULL);
403   g_signal_connect (drawing_area, "expose_event",
404 		    G_CALLBACK (drawing_area_expose), NULL);
405   g_signal_connect (drawing_area, "query-tooltip",
406 		    G_CALLBACK (query_tooltip_drawing_area_cb), NULL);
407   gtk_box_pack_start (GTK_BOX (box), drawing_area, FALSE, FALSE, 2);
408 
409   button = gtk_label_new ("Custom tooltip I");
410   label = gtk_label_new ("See, custom");
411   g_object_ref_sink (label);
412   g_object_set (button, "has-tooltip", TRUE, NULL);
413   g_signal_connect (button, "query-tooltip",
414 		    G_CALLBACK (query_tooltip_label_cb), label);
415   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 2);
416 
417   button = gtk_label_new ("Custom tooltip II");
418   label = gtk_label_new ("See, custom, too");
419   g_object_ref_sink (label);
420   g_object_set (button, "has-tooltip", TRUE, NULL);
421   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 2);
422   g_signal_connect (button, "query-tooltip",
423 		    G_CALLBACK (query_tooltip_label_cb), label);
424 
425   /* Done! */
426   gtk_widget_show_all (window);
427 
428   gtk_main ();
429 
430   return 0;
431 }
432