]> Pileus Git - ~andy/gtk/blob - gtk/gtktipsquery.c
Deprecate widget flag: GTK_WIDGET_REALIZED
[~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
40 #include "gtkalias.h"
41
42
43
44 /* --- arguments --- */
45 enum {
46   ARG_0,
47   ARG_EMIT_ALWAYS,
48   ARG_CALLER,
49   ARG_LABEL_INACTIVE,
50   ARG_LABEL_NO_TIP
51 };
52
53
54 /* --- signals --- */
55 enum
56 {
57   SIGNAL_START_QUERY,
58   SIGNAL_STOP_QUERY,
59   SIGNAL_WIDGET_ENTERED,
60   SIGNAL_WIDGET_SELECTED,
61   SIGNAL_LAST
62 };
63
64 /* --- prototypes --- */
65 static void     gtk_tips_query_class_init       (GtkTipsQueryClass      *class);
66 static void     gtk_tips_query_init             (GtkTipsQuery           *tips_query);
67 static void     gtk_tips_query_destroy          (GtkObject              *object);
68 static gint     gtk_tips_query_event            (GtkWidget              *widget,
69                                                  GdkEvent               *event);
70 static void     gtk_tips_query_set_arg          (GtkObject              *object,
71                                                  GtkArg                 *arg,
72                                                  guint                   arg_id);
73 static void     gtk_tips_query_get_arg          (GtkObject              *object,
74                                                  GtkArg                 *arg,
75                                                  guint                  arg_id);
76 static void     gtk_tips_query_real_start_query (GtkTipsQuery           *tips_query);
77 static void     gtk_tips_query_real_stop_query  (GtkTipsQuery           *tips_query);
78 static void     gtk_tips_query_widget_entered   (GtkTipsQuery           *tips_query,
79                                                  GtkWidget              *widget,
80                                                  const gchar            *tip_text,
81                                                  const gchar            *tip_private);
82
83
84 /* --- variables --- */
85 static GtkLabelClass    *parent_class = NULL;
86 static guint             tips_query_signals[SIGNAL_LAST] = { 0 };
87
88
89 /* --- functions --- */
90 GtkType
91 gtk_tips_query_get_type (void)
92 {
93   static GtkType tips_query_type = 0;
94
95   if (!tips_query_type)
96     {
97       static const GtkTypeInfo tips_query_info =
98       {
99         "GtkTipsQuery",
100         sizeof (GtkTipsQuery),
101         sizeof (GtkTipsQueryClass),
102         (GtkClassInitFunc) gtk_tips_query_class_init,
103         (GtkObjectInitFunc) gtk_tips_query_init,
104         /* reserved_1 */ NULL,
105         /* reserved_2 */ NULL,
106         (GtkClassInitFunc) NULL,
107       };
108
109       I_("GtkTipsQuery");
110       tips_query_type = gtk_type_unique (gtk_label_get_type (), &tips_query_info);
111     }
112
113   return tips_query_type;
114 }
115
116 static void
117 gtk_tips_query_class_init (GtkTipsQueryClass *class)
118 {
119   GtkObjectClass *object_class;
120   GtkWidgetClass *widget_class;
121
122   object_class = (GtkObjectClass*) class;
123   widget_class = (GtkWidgetClass*) class;
124
125   parent_class = gtk_type_class (gtk_label_get_type ());
126
127
128   object_class->set_arg = gtk_tips_query_set_arg;
129   object_class->get_arg = gtk_tips_query_get_arg;
130   object_class->destroy = gtk_tips_query_destroy;
131
132   widget_class->event = gtk_tips_query_event;
133
134   class->start_query = gtk_tips_query_real_start_query;
135   class->stop_query = gtk_tips_query_real_stop_query;
136   class->widget_entered = gtk_tips_query_widget_entered;
137   class->widget_selected = NULL;
138
139   gtk_object_add_arg_type ("GtkTipsQuery::emit-always", GTK_TYPE_BOOL, GTK_ARG_READWRITE | G_PARAM_STATIC_NAME, ARG_EMIT_ALWAYS);
140   gtk_object_add_arg_type ("GtkTipsQuery::caller", GTK_TYPE_WIDGET, GTK_ARG_READWRITE | G_PARAM_STATIC_NAME, ARG_CALLER);
141   gtk_object_add_arg_type ("GtkTipsQuery::label-inactive", GTK_TYPE_STRING, GTK_ARG_READWRITE | G_PARAM_STATIC_NAME, ARG_LABEL_INACTIVE);
142   gtk_object_add_arg_type ("GtkTipsQuery::label-no-tip", GTK_TYPE_STRING, GTK_ARG_READWRITE | G_PARAM_STATIC_NAME, ARG_LABEL_NO_TIP);
143
144   tips_query_signals[SIGNAL_START_QUERY] =
145     gtk_signal_new (I_("start-query"),
146                     GTK_RUN_FIRST,
147                     GTK_CLASS_TYPE (object_class),
148                     GTK_SIGNAL_OFFSET (GtkTipsQueryClass, start_query),
149                     _gtk_marshal_VOID__VOID,
150                     GTK_TYPE_NONE, 0);
151   tips_query_signals[SIGNAL_STOP_QUERY] =
152     gtk_signal_new (I_("stop-query"),
153                     GTK_RUN_FIRST,
154                     GTK_CLASS_TYPE (object_class),
155                     GTK_SIGNAL_OFFSET (GtkTipsQueryClass, stop_query),
156                     _gtk_marshal_VOID__VOID,
157                     GTK_TYPE_NONE, 0);
158   tips_query_signals[SIGNAL_WIDGET_ENTERED] =
159     gtk_signal_new (I_("widget-entered"),
160                     GTK_RUN_LAST,
161                     GTK_CLASS_TYPE (object_class),
162                     GTK_SIGNAL_OFFSET (GtkTipsQueryClass, widget_entered),
163                     _gtk_marshal_VOID__OBJECT_STRING_STRING,
164                     GTK_TYPE_NONE, 3,
165                     GTK_TYPE_WIDGET,
166                     GTK_TYPE_STRING,
167                     GTK_TYPE_STRING);
168   tips_query_signals[SIGNAL_WIDGET_SELECTED] =
169     g_signal_new (I_("widget-selected"),
170                   G_TYPE_FROM_CLASS(object_class),
171                   G_SIGNAL_RUN_LAST,
172                   G_STRUCT_OFFSET(GtkTipsQueryClass, widget_selected),
173                   _gtk_boolean_handled_accumulator, NULL,
174                   _gtk_marshal_BOOLEAN__OBJECT_STRING_STRING_BOXED,
175                   G_TYPE_BOOLEAN, 4,
176                   GTK_TYPE_WIDGET,
177                   G_TYPE_STRING,
178                   G_TYPE_STRING,
179                   GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
180 }
181
182 static void
183 gtk_tips_query_init (GtkTipsQuery *tips_query)
184 {
185   tips_query->emit_always = FALSE;
186   tips_query->in_query = FALSE;
187   tips_query->label_inactive = g_strdup ("");
188   tips_query->label_no_tip = g_strdup (_("--- No Tip ---"));
189   tips_query->caller = NULL;
190   tips_query->last_crossed = NULL;
191   tips_query->query_cursor = NULL;
192
193   gtk_label_set_text (GTK_LABEL (tips_query), tips_query->label_inactive);
194 }
195
196 static void
197 gtk_tips_query_set_arg (GtkObject              *object,
198                         GtkArg                 *arg,
199                         guint                   arg_id)
200 {
201   GtkTipsQuery *tips_query;
202
203   tips_query = GTK_TIPS_QUERY (object);
204
205   switch (arg_id)
206     {
207     case ARG_EMIT_ALWAYS:
208       tips_query->emit_always = (GTK_VALUE_BOOL (*arg) != FALSE);
209       break;
210     case ARG_CALLER:
211       gtk_tips_query_set_caller (tips_query, GTK_WIDGET (GTK_VALUE_OBJECT (*arg)));
212       break;
213     case ARG_LABEL_INACTIVE:
214       gtk_tips_query_set_labels (tips_query, GTK_VALUE_STRING (*arg), tips_query->label_no_tip);
215       break;
216     case ARG_LABEL_NO_TIP:
217       gtk_tips_query_set_labels (tips_query, tips_query->label_inactive, GTK_VALUE_STRING (*arg));
218       break;
219     default:
220       break;
221     }
222 }
223
224 static void
225 gtk_tips_query_get_arg (GtkObject             *object,
226                         GtkArg                *arg,
227                         guint                  arg_id)
228 {
229   GtkTipsQuery *tips_query;
230
231   tips_query = GTK_TIPS_QUERY (object);
232
233   switch (arg_id)
234     {
235     case ARG_EMIT_ALWAYS:
236       GTK_VALUE_BOOL (*arg) = tips_query->emit_always;
237       break;
238     case ARG_CALLER:
239       GTK_VALUE_OBJECT (*arg) = (GtkObject*) tips_query->caller;
240       break;
241     case ARG_LABEL_INACTIVE:
242       GTK_VALUE_STRING (*arg) = g_strdup (tips_query->label_inactive);
243       break;
244     case ARG_LABEL_NO_TIP:
245       GTK_VALUE_STRING (*arg) = g_strdup (tips_query->label_no_tip);
246       break;
247     default:
248       arg->type = GTK_TYPE_INVALID;
249       break;
250     }
251 }
252
253 static void
254 gtk_tips_query_destroy (GtkObject       *object)
255 {
256   GtkTipsQuery *tips_query = GTK_TIPS_QUERY (object);
257
258   if (tips_query->in_query)
259     gtk_tips_query_stop_query (tips_query);
260
261   gtk_tips_query_set_caller (tips_query, NULL);
262
263   g_free (tips_query->label_inactive);
264   tips_query->label_inactive = NULL;
265   g_free (tips_query->label_no_tip);
266   tips_query->label_no_tip = NULL;
267
268   GTK_OBJECT_CLASS (parent_class)->destroy (object);
269 }
270
271 GtkWidget*
272 gtk_tips_query_new (void)
273 {
274   GtkTipsQuery *tips_query;
275
276   tips_query = gtk_type_new (gtk_tips_query_get_type ());
277
278   return GTK_WIDGET (tips_query);
279 }
280
281 void
282 gtk_tips_query_set_labels (GtkTipsQuery   *tips_query,
283                            const gchar    *label_inactive,
284                            const gchar    *label_no_tip)
285 {
286   gchar *old;
287
288   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
289   g_return_if_fail (label_inactive != NULL);
290   g_return_if_fail (label_no_tip != NULL);
291
292   old = tips_query->label_inactive;
293   tips_query->label_inactive = g_strdup (label_inactive);
294   g_free (old);
295   old = tips_query->label_no_tip;
296   tips_query->label_no_tip = g_strdup (label_no_tip);
297   g_free (old);
298 }
299
300 void
301 gtk_tips_query_set_caller (GtkTipsQuery   *tips_query,
302                            GtkWidget       *caller)
303 {
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     g_object_ref (caller);
311
312   if (tips_query->caller)
313     g_object_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 (GTK_IS_TIPS_QUERY (tips_query));
322   g_return_if_fail (tips_query->in_query == FALSE);
323   g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tips_query)));
324
325   tips_query->in_query = TRUE;
326   gtk_signal_emit (GTK_OBJECT (tips_query), tips_query_signals[SIGNAL_START_QUERY]);
327 }
328
329 void
330 gtk_tips_query_stop_query (GtkTipsQuery *tips_query)
331 {
332   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
333   g_return_if_fail (tips_query->in_query == TRUE);
334
335   gtk_signal_emit (GTK_OBJECT (tips_query), tips_query_signals[SIGNAL_STOP_QUERY]);
336   tips_query->in_query = FALSE;
337 }
338
339 static void
340 gtk_tips_query_real_start_query (GtkTipsQuery *tips_query)
341 {
342   gint failure;
343   
344   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
345   
346   tips_query->query_cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (tips_query)),
347                                                          GDK_QUESTION_ARROW);
348   failure = gdk_pointer_grab (GTK_WIDGET (tips_query)->window,
349                               TRUE,
350                               GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
351                               GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK,
352                               NULL,
353                               tips_query->query_cursor,
354                               GDK_CURRENT_TIME);
355   if (failure)
356     {
357       gdk_cursor_unref (tips_query->query_cursor);
358       tips_query->query_cursor = NULL;
359     }
360   gtk_grab_add (GTK_WIDGET (tips_query));
361 }
362
363 static void
364 gtk_tips_query_real_stop_query (GtkTipsQuery *tips_query)
365 {
366   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
367   
368   gtk_grab_remove (GTK_WIDGET (tips_query));
369   if (tips_query->query_cursor)
370     {
371       gdk_display_pointer_ungrab (gtk_widget_get_display (GTK_WIDGET (tips_query)),
372                                   GDK_CURRENT_TIME);
373       gdk_cursor_unref (tips_query->query_cursor);
374       tips_query->query_cursor = NULL;
375     }
376   if (tips_query->last_crossed)
377     {
378       g_object_unref (tips_query->last_crossed);
379       tips_query->last_crossed = NULL;
380     }
381   
382   gtk_label_set_text (GTK_LABEL (tips_query), tips_query->label_inactive);
383 }
384
385 static void
386 gtk_tips_query_widget_entered (GtkTipsQuery   *tips_query,
387                                GtkWidget      *widget,
388                                const gchar    *tip_text,
389                                const gchar    *tip_private)
390 {
391   g_return_if_fail (GTK_IS_TIPS_QUERY (tips_query));
392
393   if (!tip_text)
394     tip_text = tips_query->label_no_tip;
395
396   if (!g_str_equal (GTK_LABEL (tips_query)->label, (gchar*) tip_text))
397     gtk_label_set_text (GTK_LABEL (tips_query), tip_text);
398 }
399
400 static void
401 gtk_tips_query_emit_widget_entered (GtkTipsQuery *tips_query,
402                                     GtkWidget    *widget)
403 {
404   GtkTooltipsData *tdata;
405
406   if (widget == (GtkWidget*) tips_query)
407     widget = NULL;
408
409   if (widget)
410     tdata = gtk_tooltips_data_get (widget);
411   else
412     tdata = NULL;
413
414   if (!widget && tips_query->last_crossed)
415     {
416       gtk_signal_emit (GTK_OBJECT (tips_query),
417                        tips_query_signals[SIGNAL_WIDGET_ENTERED],
418                        NULL,
419                        NULL,
420                        NULL);
421       g_object_unref (tips_query->last_crossed);
422       tips_query->last_crossed = NULL;
423     }
424   else if (widget && widget != tips_query->last_crossed)
425     {
426       g_object_ref (widget);
427       if (tdata || tips_query->emit_always)
428           gtk_signal_emit (GTK_OBJECT (tips_query),
429                            tips_query_signals[SIGNAL_WIDGET_ENTERED],
430                            widget,
431                            tdata ? tdata->tip_text : NULL,
432                            tdata ? tdata->tip_private : NULL);
433       if (tips_query->last_crossed)
434         g_object_unref (tips_query->last_crossed);
435       tips_query->last_crossed = widget;
436     }
437 }
438
439 static gint
440 gtk_tips_query_event (GtkWidget        *widget,
441                       GdkEvent         *event)
442 {
443   GtkTipsQuery *tips_query;
444   GtkWidget *event_widget;
445   gboolean event_handled;
446   
447   g_return_val_if_fail (GTK_IS_TIPS_QUERY (widget), FALSE);
448
449   tips_query = GTK_TIPS_QUERY (widget);
450   if (!tips_query->in_query)
451     {
452       if (GTK_WIDGET_CLASS (parent_class)->event)
453         return GTK_WIDGET_CLASS (parent_class)->event (widget, event);
454       else
455         return FALSE;
456     }
457
458   event_widget = gtk_get_event_widget (event);
459
460   event_handled = FALSE;
461   switch (event->type)
462     {
463       GdkWindow *pointer_window;
464       
465     case  GDK_LEAVE_NOTIFY:
466       if (event_widget)
467         pointer_window = gdk_window_get_pointer (event_widget->window, NULL, NULL, NULL);
468       else
469         pointer_window = NULL;
470       event_widget = NULL;
471       if (pointer_window)
472         {
473           gpointer event_widget_ptr;
474           gdk_window_get_user_data (pointer_window, &event_widget_ptr);
475           event_widget = event_widget_ptr;
476         }
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 }
522
523 #define __GTK_TIPS_QUERY_C__
524 #include "gtkaliasdef.c"