]> Pileus Git - ~andy/gtk/blob - gtk/gtktipsquery.c
Define macros GTK_PARAM_READABLE, GTK_PARAM_WRITABLE, GTK_PARAM_READWRITE
[~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 #undef GTK_DISABLE_DEPRECATED
31
32 #include        <config.h>
33 #include        "gtktipsquery.h"
34 #include        "gtksignal.h"
35 #include        "gtktooltips.h"
36 #include        "gtkmain.h"
37 #include        "gtkmarshalers.h"
38 #include        "gtkintl.h"
39 #include        "gtkalias.h"
40
41
42
43 /* --- arguments --- */
44 enum {
45   ARG_0,
46   ARG_EMIT_ALWAYS,
47   ARG_CALLER,
48   ARG_LABEL_INACTIVE,
49   ARG_LABEL_NO_TIP
50 };
51
52
53 /* --- signals --- */
54 enum
55 {
56   SIGNAL_START_QUERY,
57   SIGNAL_STOP_QUERY,
58   SIGNAL_WIDGET_ENTERED,
59   SIGNAL_WIDGET_SELECTED,
60   SIGNAL_LAST
61 };
62
63 /* --- prototypes --- */
64 static void     gtk_tips_query_class_init       (GtkTipsQueryClass      *class);
65 static void     gtk_tips_query_init             (GtkTipsQuery           *tips_query);
66 static void     gtk_tips_query_destroy          (GtkObject              *object);
67 static gint     gtk_tips_query_event            (GtkWidget              *widget,
68                                                  GdkEvent               *event);
69 static void     gtk_tips_query_set_arg          (GtkObject              *object,
70                                                  GtkArg                 *arg,
71                                                  guint                   arg_id);
72 static void     gtk_tips_query_get_arg          (GtkObject              *object,
73                                                  GtkArg                 *arg,
74                                                  guint                  arg_id);
75 static void     gtk_tips_query_real_start_query (GtkTipsQuery           *tips_query);
76 static void     gtk_tips_query_real_stop_query  (GtkTipsQuery           *tips_query);
77 static void     gtk_tips_query_widget_entered   (GtkTipsQuery           *tips_query,
78                                                  GtkWidget              *widget,
79                                                  const gchar            *tip_text,
80                                                  const gchar            *tip_private);
81
82
83 /* --- variables --- */
84 static GtkLabelClass    *parent_class = NULL;
85 static guint             tips_query_signals[SIGNAL_LAST] = { 0 };
86
87
88 /* --- functions --- */
89 GtkType
90 gtk_tips_query_get_type (void)
91 {
92   static GtkType tips_query_type = 0;
93
94   if (!tips_query_type)
95     {
96       static const GtkTypeInfo tips_query_info =
97       {
98         "GtkTipsQuery",
99         sizeof (GtkTipsQuery),
100         sizeof (GtkTipsQueryClass),
101         (GtkClassInitFunc) gtk_tips_query_class_init,
102         (GtkObjectInitFunc) gtk_tips_query_init,
103         /* reserved_1 */ NULL,
104         /* reserved_2 */ NULL,
105         (GtkClassInitFunc) NULL,
106       };
107
108       tips_query_type = gtk_type_unique (gtk_label_get_type (), &tips_query_info);
109     }
110
111   return tips_query_type;
112 }
113
114 static void
115 gtk_tips_query_class_init (GtkTipsQueryClass *class)
116 {
117   GtkObjectClass *object_class;
118   GtkWidgetClass *widget_class;
119
120   object_class = (GtkObjectClass*) class;
121   widget_class = (GtkWidgetClass*) class;
122
123   parent_class = gtk_type_class (gtk_label_get_type ());
124
125
126   object_class->set_arg = gtk_tips_query_set_arg;
127   object_class->get_arg = gtk_tips_query_get_arg;
128   object_class->destroy = gtk_tips_query_destroy;
129
130   widget_class->event = gtk_tips_query_event;
131
132   class->start_query = gtk_tips_query_real_start_query;
133   class->stop_query = gtk_tips_query_real_stop_query;
134   class->widget_entered = gtk_tips_query_widget_entered;
135   class->widget_selected = NULL;
136
137   gtk_object_add_arg_type ("GtkTipsQuery::emit-always", GTK_TYPE_BOOL, GTK_ARG_READWRITE | G_PARAM_STATIC_NAME, ARG_EMIT_ALWAYS);
138   gtk_object_add_arg_type ("GtkTipsQuery::caller", GTK_TYPE_WIDGET, GTK_ARG_READWRITE | G_PARAM_STATIC_NAME, ARG_CALLER);
139   gtk_object_add_arg_type ("GtkTipsQuery::label-inactive", GTK_TYPE_STRING, GTK_ARG_READWRITE | G_PARAM_STATIC_NAME, ARG_LABEL_INACTIVE);
140   gtk_object_add_arg_type ("GtkTipsQuery::label-no-tip", GTK_TYPE_STRING, GTK_ARG_READWRITE | G_PARAM_STATIC_NAME, ARG_LABEL_NO_TIP);
141
142   tips_query_signals[SIGNAL_START_QUERY] =
143     gtk_signal_new ("start_query",
144                     GTK_RUN_FIRST,
145                     GTK_CLASS_TYPE (object_class),
146                     GTK_SIGNAL_OFFSET (GtkTipsQueryClass, start_query),
147                     _gtk_marshal_VOID__VOID,
148                     GTK_TYPE_NONE, 0);
149   tips_query_signals[SIGNAL_STOP_QUERY] =
150     gtk_signal_new ("stop_query",
151                     GTK_RUN_FIRST,
152                     GTK_CLASS_TYPE (object_class),
153                     GTK_SIGNAL_OFFSET (GtkTipsQueryClass, stop_query),
154                     _gtk_marshal_VOID__VOID,
155                     GTK_TYPE_NONE, 0);
156   tips_query_signals[SIGNAL_WIDGET_ENTERED] =
157     gtk_signal_new ("widget_entered",
158                     GTK_RUN_LAST,
159                     GTK_CLASS_TYPE (object_class),
160                     GTK_SIGNAL_OFFSET (GtkTipsQueryClass, widget_entered),
161                     _gtk_marshal_VOID__OBJECT_STRING_STRING,
162                     GTK_TYPE_NONE, 3,
163                     GTK_TYPE_WIDGET,
164                     GTK_TYPE_STRING,
165                     GTK_TYPE_STRING);
166   tips_query_signals[SIGNAL_WIDGET_SELECTED] =
167     g_signal_new ("widget_selected",
168                   G_TYPE_FROM_CLASS(object_class),
169                   G_SIGNAL_RUN_LAST,
170                   G_STRUCT_OFFSET(GtkTipsQueryClass, widget_selected),
171                   _gtk_boolean_handled_accumulator, NULL,
172                   _gtk_marshal_BOOLEAN__OBJECT_STRING_STRING_BOXED,
173                   G_TYPE_BOOLEAN, 4,
174                   GTK_TYPE_WIDGET,
175                   G_TYPE_STRING,
176                   G_TYPE_STRING,
177                   GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
178 }
179
180 static void
181 gtk_tips_query_init (GtkTipsQuery *tips_query)
182 {
183   tips_query->emit_always = FALSE;
184   tips_query->in_query = FALSE;
185   tips_query->label_inactive = g_strdup ("");
186   tips_query->label_no_tip = g_strdup (_("--- No Tip ---"));
187   tips_query->caller = NULL;
188   tips_query->last_crossed = NULL;
189   tips_query->query_cursor = NULL;
190
191   gtk_label_set_text (GTK_LABEL (tips_query), tips_query->label_inactive);
192 }
193
194 static void
195 gtk_tips_query_set_arg (GtkObject              *object,
196                         GtkArg                 *arg,
197                         guint                   arg_id)
198 {
199   GtkTipsQuery *tips_query;
200
201   tips_query = GTK_TIPS_QUERY (object);
202
203   switch (arg_id)
204     {
205     case ARG_EMIT_ALWAYS:
206       tips_query->emit_always = (GTK_VALUE_BOOL (*arg) != FALSE);
207       break;
208     case ARG_CALLER:
209       gtk_tips_query_set_caller (tips_query, GTK_WIDGET (GTK_VALUE_OBJECT (*arg)));
210       break;
211     case ARG_LABEL_INACTIVE:
212       gtk_tips_query_set_labels (tips_query, GTK_VALUE_STRING (*arg), tips_query->label_no_tip);
213       break;
214     case ARG_LABEL_NO_TIP:
215       gtk_tips_query_set_labels (tips_query, tips_query->label_inactive, GTK_VALUE_STRING (*arg));
216       break;
217     default:
218       break;
219     }
220 }
221
222 static void
223 gtk_tips_query_get_arg (GtkObject             *object,
224                         GtkArg                *arg,
225                         guint                  arg_id)
226 {
227   GtkTipsQuery *tips_query;
228
229   tips_query = GTK_TIPS_QUERY (object);
230
231   switch (arg_id)
232     {
233     case ARG_EMIT_ALWAYS:
234       GTK_VALUE_BOOL (*arg) = tips_query->emit_always;
235       break;
236     case ARG_CALLER:
237       GTK_VALUE_OBJECT (*arg) = (GtkObject*) tips_query->caller;
238       break;
239     case ARG_LABEL_INACTIVE:
240       GTK_VALUE_STRING (*arg) = g_strdup (tips_query->label_inactive);
241       break;
242     case ARG_LABEL_NO_TIP:
243       GTK_VALUE_STRING (*arg) = g_strdup (tips_query->label_no_tip);
244       break;
245     default:
246       arg->type = GTK_TYPE_INVALID;
247       break;
248     }
249 }
250
251 static void
252 gtk_tips_query_destroy (GtkObject       *object)
253 {
254   GtkTipsQuery *tips_query;
255
256   g_return_if_fail (GTK_IS_TIPS_QUERY (object));
257
258   tips_query = GTK_TIPS_QUERY (object);
259
260   if (tips_query->in_query)
261     gtk_tips_query_stop_query (tips_query);
262
263   gtk_tips_query_set_caller (tips_query, NULL);
264
265   g_free (tips_query->label_inactive);
266   tips_query->label_inactive = NULL;
267   g_free (tips_query->label_no_tip);
268   tips_query->label_no_tip = NULL;
269
270   if (GTK_OBJECT_CLASS (parent_class)->destroy)
271     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
272 }
273
274 GtkWidget*
275 gtk_tips_query_new (void)
276 {
277   GtkTipsQuery *tips_query;
278
279   tips_query = gtk_type_new (gtk_tips_query_get_type ());
280
281   return GTK_WIDGET (tips_query);
282 }
283
284 void
285 gtk_tips_query_set_labels (GtkTipsQuery   *tips_query,
286                            const gchar    *label_inactive,
287                            const gchar    *label_no_tip)
288 {
289   gchar *old;
290
291   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
292   g_return_if_fail (label_inactive != NULL);
293   g_return_if_fail (label_no_tip != NULL);
294
295   old = tips_query->label_inactive;
296   tips_query->label_inactive = g_strdup (label_inactive);
297   g_free (old);
298   old = tips_query->label_no_tip;
299   tips_query->label_no_tip = g_strdup (label_no_tip);
300   g_free (old);
301 }
302
303 void
304 gtk_tips_query_set_caller (GtkTipsQuery   *tips_query,
305                            GtkWidget       *caller)
306 {
307   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
308   g_return_if_fail (tips_query->in_query == FALSE);
309   if (caller)
310     g_return_if_fail (GTK_IS_WIDGET (caller));
311
312   if (caller)
313     gtk_widget_ref (caller);
314
315   if (tips_query->caller)
316     gtk_widget_unref (tips_query->caller);
317
318   tips_query->caller = caller;
319 }
320
321 void
322 gtk_tips_query_start_query (GtkTipsQuery *tips_query)
323 {
324   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
325   g_return_if_fail (tips_query->in_query == FALSE);
326   g_return_if_fail (GTK_WIDGET_REALIZED (tips_query));
327
328   tips_query->in_query = TRUE;
329   gtk_signal_emit (GTK_OBJECT (tips_query), tips_query_signals[SIGNAL_START_QUERY]);
330 }
331
332 void
333 gtk_tips_query_stop_query (GtkTipsQuery *tips_query)
334 {
335   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
336   g_return_if_fail (tips_query->in_query == TRUE);
337
338   gtk_signal_emit (GTK_OBJECT (tips_query), tips_query_signals[SIGNAL_STOP_QUERY]);
339   tips_query->in_query = FALSE;
340 }
341
342 static void
343 gtk_tips_query_real_start_query (GtkTipsQuery *tips_query)
344 {
345   gint failure;
346   
347   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
348   
349   tips_query->query_cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (tips_query)),
350                                                          GDK_QUESTION_ARROW);
351   failure = gdk_pointer_grab (GTK_WIDGET (tips_query)->window,
352                               TRUE,
353                               GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
354                               GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK,
355                               NULL,
356                               tips_query->query_cursor,
357                               GDK_CURRENT_TIME);
358   if (failure)
359     {
360       gdk_cursor_unref (tips_query->query_cursor);
361       tips_query->query_cursor = NULL;
362     }
363   gtk_grab_add (GTK_WIDGET (tips_query));
364 }
365
366 static void
367 gtk_tips_query_real_stop_query (GtkTipsQuery *tips_query)
368 {
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_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (tips_query)),
375                                   GDK_CURRENT_TIME);
376       gdk_cursor_unref (tips_query->query_cursor);
377       tips_query->query_cursor = NULL;
378     }
379   if (tips_query->last_crossed)
380     {
381       gtk_widget_unref (tips_query->last_crossed);
382       tips_query->last_crossed = NULL;
383     }
384   
385   gtk_label_set_text (GTK_LABEL (tips_query), tips_query->label_inactive);
386 }
387
388 static void
389 gtk_tips_query_widget_entered (GtkTipsQuery   *tips_query,
390                                GtkWidget      *widget,
391                                const gchar    *tip_text,
392                                const gchar    *tip_private)
393 {
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 (GTK_IS_TIPS_QUERY (widget), FALSE);
451
452   tips_query = GTK_TIPS_QUERY (widget);
453   if (!tips_query->in_query)
454     {
455       if (GTK_WIDGET_CLASS (parent_class)->event)
456         return GTK_WIDGET_CLASS (parent_class)->event (widget, event);
457       else
458         return FALSE;
459     }
460
461   event_widget = gtk_get_event_widget (event);
462
463   event_handled = FALSE;
464   switch (event->type)
465     {
466       GdkWindow *pointer_window;
467       
468     case  GDK_LEAVE_NOTIFY:
469       if (event_widget)
470         pointer_window = gdk_window_get_pointer (event_widget->window, NULL, NULL, NULL);
471       else
472         pointer_window = NULL;
473       event_widget = NULL;
474       if (pointer_window)
475         gdk_window_get_user_data (pointer_window, (gpointer*) &event_widget);
476       gtk_tips_query_emit_widget_entered (tips_query, event_widget);
477       event_handled = TRUE;
478       break;
479
480     case  GDK_ENTER_NOTIFY:
481       gtk_tips_query_emit_widget_entered (tips_query, event_widget);
482       event_handled = TRUE;
483       break;
484
485     case  GDK_BUTTON_PRESS:
486     case  GDK_BUTTON_RELEASE:
487       if (event_widget)
488         {
489           if (event_widget == (GtkWidget*) tips_query ||
490               event_widget == tips_query->caller)
491             gtk_tips_query_stop_query (tips_query);
492           else
493             {
494               gint stop;
495               GtkTooltipsData *tdata;
496               
497               stop = TRUE;
498               tdata = gtk_tooltips_data_get (event_widget);
499               if (tdata || tips_query->emit_always)
500                 gtk_signal_emit (GTK_OBJECT (tips_query),
501                                  tips_query_signals[SIGNAL_WIDGET_SELECTED],
502                                  event_widget,
503                                  tdata ? tdata->tip_text : NULL,
504                                  tdata ? tdata->tip_private : NULL,
505                                  event,
506                                  &stop);
507               
508               if (stop)
509                 gtk_tips_query_stop_query (tips_query);
510             }
511         }
512       event_handled = TRUE;
513       break;
514
515     default:
516       break;
517     }
518
519   return event_handled;
520 }
521
522 #define __GTK_TIPS_QUERY_C__
523 #include "gtkaliasdef.c"