]> Pileus Git - ~andy/gtk/blob - gtk/gtktipsquery.c
urg, removed implementation of gtk_marshal_VOID__INT_INT_INT_INT. if
[~andy/gtk] / gtk / gtktipsquery.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * GtkQueryTips: Query onscreen widgets for their tooltips
5  * Copyright (C) 1998 Tim Janik
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GTK+ Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
28  */
29
30 #include        "gtktipsquery.h"
31 #include        "gtksignal.h"
32 #include        "gtktooltips.h"
33 #include        "gtkmain.h"
34 #include        "gtkintl.h"
35
36
37
38 /* --- arguments --- */
39 enum {
40   ARG_0,
41   ARG_EMIT_ALWAYS,
42   ARG_CALLER,
43   ARG_LABEL_INACTIVE,
44   ARG_LABEL_NO_TIP
45 };
46
47
48 /* --- signals --- */
49 enum
50 {
51   SIGNAL_START_QUERY,
52   SIGNAL_STOP_QUERY,
53   SIGNAL_WIDGET_ENTERED,
54   SIGNAL_WIDGET_SELECTED,
55   SIGNAL_LAST
56 };
57
58 /* --- prototypes --- */
59 static void     gtk_tips_query_class_init       (GtkTipsQueryClass      *class);
60 static void     gtk_tips_query_init             (GtkTipsQuery           *tips_query);
61 static void     gtk_tips_query_destroy          (GtkObject              *object);
62 static gint     gtk_tips_query_event            (GtkWidget              *widget,
63                                                  GdkEvent               *event);
64 static void     gtk_tips_query_set_arg          (GtkObject              *object,
65                                                  GtkArg                 *arg,
66                                                  guint                   arg_id);
67 static void     gtk_tips_query_get_arg          (GtkObject              *object,
68                                                  GtkArg                 *arg,
69                                                  guint                  arg_id);
70 static void     gtk_tips_query_real_start_query (GtkTipsQuery           *tips_query);
71 static void     gtk_tips_query_real_stop_query  (GtkTipsQuery           *tips_query);
72 static void     gtk_tips_query_widget_entered   (GtkTipsQuery           *tips_query,
73                                                  GtkWidget              *widget,
74                                                  const gchar            *tip_text,
75                                                  const gchar            *tip_private);
76
77
78 /* --- variables --- */
79 static GtkLabelClass    *parent_class = NULL;
80 static guint             tips_query_signals[SIGNAL_LAST] = { 0 };
81
82
83 /* --- functions --- */
84 GtkType
85 gtk_tips_query_get_type (void)
86 {
87   static guint tips_query_type = 0;
88
89   if (!tips_query_type)
90     {
91       static const GtkTypeInfo tips_query_info =
92       {
93         "GtkTipsQuery",
94         sizeof (GtkTipsQuery),
95         sizeof (GtkTipsQueryClass),
96         (GtkClassInitFunc) gtk_tips_query_class_init,
97         (GtkObjectInitFunc) gtk_tips_query_init,
98         /* reserved_1 */ NULL,
99         /* reserved_2 */ NULL,
100         (GtkClassInitFunc) NULL,
101       };
102
103       tips_query_type = gtk_type_unique (gtk_label_get_type (), &tips_query_info);
104     }
105
106   return tips_query_type;
107 }
108
109 static void
110 gtk_tips_query_class_init (GtkTipsQueryClass *class)
111 {
112   GtkObjectClass *object_class;
113   GtkWidgetClass *widget_class;
114
115   object_class = (GtkObjectClass*) class;
116   widget_class = (GtkWidgetClass*) class;
117
118   parent_class = gtk_type_class (gtk_label_get_type ());
119
120   gtk_object_add_arg_type ("GtkTipsQuery::emit_always", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_EMIT_ALWAYS);
121   gtk_object_add_arg_type ("GtkTipsQuery::caller", GTK_TYPE_WIDGET, GTK_ARG_READWRITE, ARG_CALLER);
122   gtk_object_add_arg_type ("GtkTipsQuery::label_inactive", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL_INACTIVE);
123   gtk_object_add_arg_type ("GtkTipsQuery::label_no_tip", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL_NO_TIP);
124
125   tips_query_signals[SIGNAL_START_QUERY] =
126     gtk_signal_new ("start_query",
127                     GTK_RUN_FIRST,
128                     GTK_CLASS_TYPE (object_class),
129                     GTK_SIGNAL_OFFSET (GtkTipsQueryClass, start_query),
130                     gtk_marshal_VOID__VOID,
131                     GTK_TYPE_NONE, 0);
132   tips_query_signals[SIGNAL_STOP_QUERY] =
133     gtk_signal_new ("stop_query",
134                     GTK_RUN_FIRST,
135                     GTK_CLASS_TYPE (object_class),
136                     GTK_SIGNAL_OFFSET (GtkTipsQueryClass, stop_query),
137                     gtk_marshal_VOID__VOID,
138                     GTK_TYPE_NONE, 0);
139   tips_query_signals[SIGNAL_WIDGET_ENTERED] =
140     gtk_signal_new ("widget_entered",
141                     GTK_RUN_LAST,
142                     GTK_CLASS_TYPE (object_class),
143                     GTK_SIGNAL_OFFSET (GtkTipsQueryClass, widget_entered),
144                     gtk_marshal_VOID__POINTER_STRING_STRING,
145                     GTK_TYPE_NONE, 3,
146                     GTK_TYPE_WIDGET,
147                     GTK_TYPE_STRING,
148                     GTK_TYPE_STRING);
149   tips_query_signals[SIGNAL_WIDGET_SELECTED] =
150     gtk_signal_new ("widget_selected",
151                     GTK_RUN_LAST,
152                     GTK_CLASS_TYPE (object_class),
153                     GTK_SIGNAL_OFFSET (GtkTipsQueryClass, widget_selected),
154                     gtk_marshal_BOOLEAN__POINTER_STRING_STRING_POINTER,
155                     GTK_TYPE_BOOL, 4,
156                     GTK_TYPE_WIDGET,
157                     GTK_TYPE_STRING,
158                     GTK_TYPE_STRING,
159                     GTK_TYPE_GDK_EVENT);
160   gtk_object_class_add_signals (object_class, tips_query_signals, SIGNAL_LAST);
161
162   object_class->set_arg = gtk_tips_query_set_arg;
163   object_class->get_arg = gtk_tips_query_get_arg;
164   object_class->destroy = gtk_tips_query_destroy;
165
166   widget_class->event = gtk_tips_query_event;
167
168   class->start_query = gtk_tips_query_real_start_query;
169   class->stop_query = gtk_tips_query_real_stop_query;
170   class->widget_entered = gtk_tips_query_widget_entered;
171   class->widget_selected = NULL;
172 }
173
174 static void
175 gtk_tips_query_init (GtkTipsQuery *tips_query)
176 {
177   tips_query->emit_always = FALSE;
178   tips_query->in_query = FALSE;
179   tips_query->label_inactive = g_strdup ("");
180   tips_query->label_no_tip = g_strdup (_("--- No Tip ---"));
181   tips_query->caller = NULL;
182   tips_query->last_crossed = NULL;
183   tips_query->query_cursor = NULL;
184
185   gtk_label_set_text (GTK_LABEL (tips_query), tips_query->label_inactive);
186 }
187
188 static void
189 gtk_tips_query_set_arg (GtkObject              *object,
190                         GtkArg                 *arg,
191                         guint                   arg_id)
192 {
193   GtkTipsQuery *tips_query;
194
195   tips_query = GTK_TIPS_QUERY (object);
196
197   switch (arg_id)
198     {
199     case ARG_EMIT_ALWAYS:
200       tips_query->emit_always = (GTK_VALUE_BOOL (*arg) != FALSE);
201       break;
202     case ARG_CALLER:
203       gtk_tips_query_set_caller (tips_query, GTK_WIDGET (GTK_VALUE_OBJECT (*arg)));
204       break;
205     case ARG_LABEL_INACTIVE:
206       gtk_tips_query_set_labels (tips_query, GTK_VALUE_STRING (*arg), tips_query->label_no_tip);
207       break;
208     case ARG_LABEL_NO_TIP:
209       gtk_tips_query_set_labels (tips_query, tips_query->label_inactive, GTK_VALUE_STRING (*arg));
210       break;
211     default:
212       break;
213     }
214 }
215
216 static void
217 gtk_tips_query_get_arg (GtkObject             *object,
218                         GtkArg                *arg,
219                         guint                  arg_id)
220 {
221   GtkTipsQuery *tips_query;
222
223   tips_query = GTK_TIPS_QUERY (object);
224
225   switch (arg_id)
226     {
227     case ARG_EMIT_ALWAYS:
228       GTK_VALUE_BOOL (*arg) = tips_query->emit_always;
229       break;
230     case ARG_CALLER:
231       GTK_VALUE_OBJECT (*arg) = (GtkObject*) tips_query->caller;
232       break;
233     case ARG_LABEL_INACTIVE:
234       GTK_VALUE_STRING (*arg) = g_strdup (tips_query->label_inactive);
235       break;
236     case ARG_LABEL_NO_TIP:
237       GTK_VALUE_STRING (*arg) = g_strdup (tips_query->label_no_tip);
238       break;
239     default:
240       arg->type = GTK_TYPE_INVALID;
241       break;
242     }
243 }
244
245 static void
246 gtk_tips_query_destroy (GtkObject       *object)
247 {
248   GtkTipsQuery *tips_query;
249
250   g_return_if_fail (object != NULL);
251   g_return_if_fail (GTK_IS_TIPS_QUERY (object));
252
253   tips_query = GTK_TIPS_QUERY (object);
254
255   if (tips_query->in_query)
256     gtk_tips_query_stop_query (tips_query);
257
258   gtk_tips_query_set_caller (tips_query, NULL);
259
260   g_free (tips_query->label_inactive);
261   tips_query->label_inactive = NULL;
262   g_free (tips_query->label_no_tip);
263   tips_query->label_no_tip = NULL;
264
265   if (GTK_OBJECT_CLASS (parent_class)->destroy)
266     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
267 }
268
269 GtkWidget*
270 gtk_tips_query_new (void)
271 {
272   GtkTipsQuery *tips_query;
273
274   tips_query = gtk_type_new (gtk_tips_query_get_type ());
275
276   return GTK_WIDGET (tips_query);
277 }
278
279 void
280 gtk_tips_query_set_labels (GtkTipsQuery   *tips_query,
281                            const gchar    *label_inactive,
282                            const gchar    *label_no_tip)
283 {
284   gchar *old;
285
286   g_return_if_fail (tips_query != NULL);
287   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
288   g_return_if_fail (label_inactive != NULL);
289   g_return_if_fail (label_no_tip != NULL);
290
291   old = tips_query->label_inactive;
292   tips_query->label_inactive = g_strdup (label_inactive);
293   g_free (old);
294   old = tips_query->label_no_tip;
295   tips_query->label_no_tip = g_strdup (label_no_tip);
296   g_free (old);
297 }
298
299 void
300 gtk_tips_query_set_caller (GtkTipsQuery   *tips_query,
301                            GtkWidget       *caller)
302 {
303   g_return_if_fail (tips_query != NULL);
304   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
305   g_return_if_fail (tips_query->in_query == FALSE);
306   if (caller)
307     g_return_if_fail (GTK_IS_WIDGET (caller));
308
309   if (caller)
310     gtk_widget_ref (caller);
311
312   if (tips_query->caller)
313     gtk_widget_unref (tips_query->caller);
314
315   tips_query->caller = caller;
316 }
317
318 void
319 gtk_tips_query_start_query (GtkTipsQuery *tips_query)
320 {
321   g_return_if_fail (tips_query != NULL);
322   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
323   g_return_if_fail (tips_query->in_query == FALSE);
324   g_return_if_fail (GTK_WIDGET_REALIZED (tips_query));
325
326   tips_query->in_query = TRUE;
327   gtk_signal_emit (GTK_OBJECT (tips_query), tips_query_signals[SIGNAL_START_QUERY]);
328 }
329
330 void
331 gtk_tips_query_stop_query (GtkTipsQuery *tips_query)
332 {
333   g_return_if_fail (tips_query != NULL);
334   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
335   g_return_if_fail (tips_query->in_query == TRUE);
336
337   gtk_signal_emit (GTK_OBJECT (tips_query), tips_query_signals[SIGNAL_STOP_QUERY]);
338   tips_query->in_query = FALSE;
339 }
340
341 static void
342 gtk_tips_query_real_start_query (GtkTipsQuery *tips_query)
343 {
344   gint failure;
345   
346   g_return_if_fail (tips_query != NULL);
347   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
348   
349   tips_query->query_cursor = gdk_cursor_new (GDK_QUESTION_ARROW);
350   failure = gdk_pointer_grab (GTK_WIDGET (tips_query)->window,
351                               TRUE,
352                               GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
353                               GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK,
354                               NULL,
355                               tips_query->query_cursor,
356                               GDK_CURRENT_TIME);
357   if (failure)
358     {
359       gdk_cursor_destroy (tips_query->query_cursor);
360       tips_query->query_cursor = NULL;
361     }
362   gtk_grab_add (GTK_WIDGET (tips_query));
363 }
364
365 static void
366 gtk_tips_query_real_stop_query (GtkTipsQuery *tips_query)
367 {
368   g_return_if_fail (tips_query != NULL);
369   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
370   
371   gtk_grab_remove (GTK_WIDGET (tips_query));
372   if (tips_query->query_cursor)
373     {
374       gdk_pointer_ungrab (GDK_CURRENT_TIME);
375       gdk_cursor_destroy (tips_query->query_cursor);
376       tips_query->query_cursor = NULL;
377     }
378   if (tips_query->last_crossed)
379     {
380       gtk_widget_unref (tips_query->last_crossed);
381       tips_query->last_crossed = NULL;
382     }
383   
384   gtk_label_set_text (GTK_LABEL (tips_query), tips_query->label_inactive);
385 }
386
387 static void
388 gtk_tips_query_widget_entered (GtkTipsQuery   *tips_query,
389                                GtkWidget      *widget,
390                                const gchar    *tip_text,
391                                const gchar    *tip_private)
392 {
393   g_return_if_fail (tips_query != NULL);
394   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
395
396   if (!tip_text)
397     tip_text = tips_query->label_no_tip;
398
399   if (!g_str_equal (GTK_LABEL (tips_query)->label, (gchar*) tip_text))
400     gtk_label_set_text (GTK_LABEL (tips_query), tip_text);
401 }
402
403 static void
404 gtk_tips_query_emit_widget_entered (GtkTipsQuery *tips_query,
405                                     GtkWidget    *widget)
406 {
407   GtkTooltipsData *tdata;
408
409   if (widget == (GtkWidget*) tips_query)
410     widget = NULL;
411
412   if (widget)
413     tdata = gtk_tooltips_data_get (widget);
414   else
415     tdata = NULL;
416
417   if (!widget && tips_query->last_crossed)
418     {
419       gtk_signal_emit (GTK_OBJECT (tips_query),
420                        tips_query_signals[SIGNAL_WIDGET_ENTERED],
421                        NULL,
422                        NULL,
423                        NULL);
424       gtk_widget_unref (tips_query->last_crossed);
425       tips_query->last_crossed = NULL;
426     }
427   else if (widget && widget != tips_query->last_crossed)
428     {
429       gtk_widget_ref (widget);
430       if (tdata || tips_query->emit_always)
431           gtk_signal_emit (GTK_OBJECT (tips_query),
432                            tips_query_signals[SIGNAL_WIDGET_ENTERED],
433                            widget,
434                            tdata ? tdata->tip_text : NULL,
435                            tdata ? tdata->tip_private : NULL);
436       if (tips_query->last_crossed)
437         gtk_widget_unref (tips_query->last_crossed);
438       tips_query->last_crossed = widget;
439     }
440 }
441
442 static gint
443 gtk_tips_query_event (GtkWidget        *widget,
444                       GdkEvent         *event)
445 {
446   GtkTipsQuery *tips_query;
447   GtkWidget *event_widget;
448   gboolean event_handled;
449   
450   g_return_val_if_fail (widget != NULL, FALSE);
451   g_return_val_if_fail (GTK_IS_TIPS_QUERY (widget), FALSE);
452
453   tips_query = GTK_TIPS_QUERY (widget);
454   if (!tips_query->in_query)
455     {
456       if (GTK_WIDGET_CLASS (parent_class)->event)
457         return GTK_WIDGET_CLASS (parent_class)->event (widget, event);
458       else
459         return FALSE;
460     }
461
462   event_widget = gtk_get_event_widget (event);
463
464   event_handled = FALSE;
465   switch (event->type)
466     {
467       GdkWindow *pointer_window;
468       
469     case  GDK_LEAVE_NOTIFY:
470       if (event_widget)
471         pointer_window = gdk_window_get_pointer (event_widget->window, NULL, NULL, NULL);
472       else
473         pointer_window = NULL;
474       event_widget = NULL;
475       if (pointer_window)
476         gdk_window_get_user_data (pointer_window, (gpointer*) &event_widget);
477       gtk_tips_query_emit_widget_entered (tips_query, event_widget);
478       event_handled = TRUE;
479       break;
480
481     case  GDK_ENTER_NOTIFY:
482       gtk_tips_query_emit_widget_entered (tips_query, event_widget);
483       event_handled = TRUE;
484       break;
485
486     case  GDK_BUTTON_PRESS:
487     case  GDK_BUTTON_RELEASE:
488       if (event_widget)
489         {
490           if (event_widget == (GtkWidget*) tips_query ||
491               event_widget == tips_query->caller)
492             gtk_tips_query_stop_query (tips_query);
493           else
494             {
495               gint stop;
496               GtkTooltipsData *tdata;
497               
498               stop = TRUE;
499               tdata = gtk_tooltips_data_get (event_widget);
500               if (tdata || tips_query->emit_always)
501                 gtk_signal_emit (GTK_OBJECT (tips_query),
502                                  tips_query_signals[SIGNAL_WIDGET_SELECTED],
503                                  event_widget,
504                                  tdata ? tdata->tip_text : NULL,
505                                  tdata ? tdata->tip_private : NULL,
506                                  event,
507                                  &stop);
508               
509               if (stop)
510                 gtk_tips_query_stop_query (tips_query);
511             }
512         }
513       event_handled = TRUE;
514       break;
515
516     default:
517       break;
518     }
519
520   return event_handled;
521 }