source: trunk/third/gtk/gtk/gtktipsquery.c @ 14482

Revision 14482, 14.3 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
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 Library 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 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library 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-1999.  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 --- */
39enum {
40  ARG_0,
41  ARG_EMIT_ALWAYS,
42  ARG_CALLER,
43  ARG_LABEL_INACTIVE,
44  ARG_LABEL_NO_TIP
45};
46
47
48/* --- signals --- */
49enum
50{
51  SIGNAL_START_QUERY,
52  SIGNAL_STOP_QUERY,
53  SIGNAL_WIDGET_ENTERED,
54  SIGNAL_WIDGET_SELECTED,
55  SIGNAL_LAST
56};
57
58/* --- prototypes --- */
59static void     gtk_tips_query_class_init       (GtkTipsQueryClass      *class);
60static void     gtk_tips_query_init             (GtkTipsQuery           *tips_query);
61static void     gtk_tips_query_destroy          (GtkObject              *object);
62static gint     gtk_tips_query_event            (GtkWidget              *widget,
63                                                 GdkEvent               *event);
64static void     gtk_tips_query_set_arg          (GtkObject              *object,
65                                                 GtkArg                 *arg,
66                                                 guint                   arg_id);
67static void     gtk_tips_query_get_arg          (GtkObject              *object,
68                                                 GtkArg                 *arg,
69                                                 guint                  arg_id);
70static void     gtk_tips_query_real_start_query (GtkTipsQuery           *tips_query);
71static void     gtk_tips_query_real_stop_query  (GtkTipsQuery           *tips_query);
72static 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 --- */
79static GtkLabelClass    *parent_class = NULL;
80static guint             tips_query_signals[SIGNAL_LAST] = { 0 };
81
82
83/* --- functions --- */
84guint
85gtk_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
109static void
110gtk_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                    object_class->type,
129                    GTK_SIGNAL_OFFSET (GtkTipsQueryClass, start_query),
130                    gtk_marshal_NONE__NONE,
131                    GTK_TYPE_NONE, 0);
132  tips_query_signals[SIGNAL_STOP_QUERY] =
133    gtk_signal_new ("stop_query",
134                    GTK_RUN_FIRST,
135                    object_class->type,
136                    GTK_SIGNAL_OFFSET (GtkTipsQueryClass, stop_query),
137                    gtk_marshal_NONE__NONE,
138                    GTK_TYPE_NONE, 0);
139  tips_query_signals[SIGNAL_WIDGET_ENTERED] =
140    gtk_signal_new ("widget_entered",
141                    GTK_RUN_LAST,
142                    object_class->type,
143                    GTK_SIGNAL_OFFSET (GtkTipsQueryClass, widget_entered),
144                    gtk_marshal_NONE__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                    object_class->type,
153                    GTK_SIGNAL_OFFSET (GtkTipsQueryClass, widget_selected),
154                    gtk_marshal_BOOL__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
174static void
175gtk_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
188static void
189gtk_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
216static void
217gtk_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
245static void
246gtk_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
269GtkWidget*
270gtk_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
279void
280gtk_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
299void
300gtk_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
318void
319gtk_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
330void
331gtk_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
341static void
342gtk_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
365static void
366gtk_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
387static void
388gtk_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
403static void
404gtk_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
442static gint
443gtk_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}
Note: See TracBrowser for help on using the repository browser.