source: trunk/third/gtk/gtk/gtkmain.c @ 15781

Revision 15781, 35.2 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15780, 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 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20/*
21 * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
22 * file for a list of people on the GTK+ Team.  See the ChangeLog
23 * files for a list of changes.  These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25 */
26
27#include <X11/Xlocale.h>        /* so we get the right setlocale */
28#include <errno.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <sys/types.h>
33#include <unistd.h>             /* For getuid() and friends */
34#include <gmodule.h>
35#include "gtkbutton.h"
36#include "gtkdnd.h"
37#include "gtkfeatures.h"
38#include "gtkhscrollbar.h"
39#include "gtkhseparator.h"
40#include "gtkmain.h"
41#include "gtkpreview.h"
42#include "gtkrc.h"
43#include "gtkscrolledwindow.h"
44#include "gtkselection.h"
45#include "gtksignal.h"
46#include "gtktable.h"
47#include "gtktext.h"
48#include "gtkvbox.h"
49#include "gtkvscrollbar.h"
50#include "gtkwidget.h"
51#include "gtkwindow.h"
52#include "gtkprivate.h"
53#include "gdk/gdki18n.h"
54#include "config.h"
55#include "gtkdebug.h"
56#include "gtkintl.h"
57
58/* Private type definitions
59 */
60typedef struct _GtkInitFunction          GtkInitFunction;
61typedef struct _GtkQuitFunction          GtkQuitFunction;
62typedef struct _GtkClosure               GtkClosure;
63typedef struct _GtkKeySnooperData        GtkKeySnooperData;
64
65struct _GtkInitFunction
66{
67  GtkFunction function;
68  gpointer data;
69};
70
71struct _GtkQuitFunction
72{
73  guint id;
74  guint main_level;
75  GtkCallbackMarshal marshal;
76  GtkFunction function;
77  gpointer data;
78  GtkDestroyNotify destroy;
79};
80
81struct _GtkClosure
82{
83  GtkCallbackMarshal marshal;
84  gpointer data;
85  GtkDestroyNotify destroy;
86};
87
88struct _GtkKeySnooperData
89{
90  GtkKeySnoopFunc func;
91  gpointer func_data;
92  guint id;
93};
94
95static void  gtk_exit_func               (void);
96static gint  gtk_quit_invoke_function    (GtkQuitFunction    *quitf);
97static void  gtk_quit_destroy            (GtkQuitFunction    *quitf);
98static gint  gtk_invoke_key_snoopers     (GtkWidget          *grab_widget,
99                                          GdkEvent           *event);
100
101static void     gtk_destroy_closure      (gpointer            data);
102static gboolean gtk_invoke_idle_timeout  (gpointer            data);
103static void     gtk_invoke_input         (gpointer            data,
104                                          gint                source,
105                                          GdkInputCondition   condition);
106
107#if 0
108static void  gtk_error                   (gchar              *str);
109static void  gtk_warning                 (gchar              *str);
110static void  gtk_message                 (gchar              *str);
111static void  gtk_print                   (gchar              *str);
112#endif
113
114const guint gtk_major_version = GTK_MAJOR_VERSION;
115const guint gtk_minor_version = GTK_MINOR_VERSION;
116const guint gtk_micro_version = GTK_MICRO_VERSION;
117const guint gtk_binary_age = GTK_BINARY_AGE;
118const guint gtk_interface_age = GTK_INTERFACE_AGE;
119
120static guint gtk_main_loop_level = 0;
121static gint gtk_initialized = FALSE;
122static GList *current_events = NULL;
123
124static GSList *main_loops = NULL;      /* stack of currently executing main loops */
125
126static GSList *grabs = NULL;               /* A stack of unique grabs. The grabbing
127                                            *  widget is the first one on the list.
128                                            */
129static GList *init_functions = NULL;       /* A list of init functions.
130                                            */
131static GList *quit_functions = NULL;       /* A list of quit functions.
132                                            */
133static GMemChunk *quit_mem_chunk = NULL;
134
135static GSList *key_snoopers = NULL;
136
137static GdkVisual *gtk_visual;              /* The visual to be used in creating new
138                                            *  widgets.
139                                            */
140static GdkColormap *gtk_colormap;          /* The colormap to be used in creating new
141                                            *  widgets.
142                                            */
143
144guint gtk_debug_flags = 0;                 /* Global GTK debug flag */
145
146#ifdef G_ENABLE_DEBUG
147static const GDebugKey gtk_debug_keys[] = {
148  {"objects", GTK_DEBUG_OBJECTS},
149  {"misc", GTK_DEBUG_MISC},
150  {"signals", GTK_DEBUG_SIGNALS},
151  {"dnd", GTK_DEBUG_DND},
152  {"plugsocket", GTK_DEBUG_PLUGSOCKET}
153};
154
155static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
156
157#endif /* G_ENABLE_DEBUG */
158
159gchar*
160gtk_check_version (guint required_major,
161                   guint required_minor,
162                   guint required_micro)
163{
164  if (required_major > GTK_MAJOR_VERSION)
165    return "Gtk+ version too old (major mismatch)";
166  if (required_major < GTK_MAJOR_VERSION)
167    return "Gtk+ version too new (major mismatch)";
168  if (required_minor > GTK_MINOR_VERSION)
169    return "Gtk+ version too old (minor mismatch)";
170  if (required_minor < GTK_MINOR_VERSION)
171    return "Gtk+ version too new (minor mismatch)";
172  if (required_micro < GTK_MICRO_VERSION - GTK_BINARY_AGE)
173    return "Gtk+ version too new (micro mismatch)";
174  if (required_micro > GTK_MICRO_VERSION)
175    return "Gtk+ version too old (micro mismatch)";
176  return NULL;
177}
178
179/* This checks to see if the process is running suid or sgid
180 * at the current time. If so, we don't allow GTK+ to be initialized.
181 * This is meant to be a mild check - we only error out if we
182 * can prove the programmer is doing something wrong, not if
183 * they could be doing something wrong. For this reason, we
184 * don't use issetugid() on BSD or prctl (PR_GET_DUMPABLE).
185 */
186static gboolean
187check_setugid (void)
188{
189  uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
190  gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
191 
192#ifdef HAVE_GETRESUID
193  /* These aren't in the header files, so we prototype them here.
194   */
195  int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
196  int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
197
198  if (getresuid (&ruid, &euid, &suid) != 0 ||
199      getresgid (&rgid, &egid, &sgid) != 0)
200#endif /* HAVE_GETRESUID */
201    {
202      suid = ruid = getuid ();
203      sgid = rgid = getgid ();
204      euid = geteuid ();
205      egid = getegid ();
206    }
207
208  if (ruid != euid || ruid != suid ||
209      rgid != egid || rgid != sgid)
210    {
211      g_warning ("This process is currently running setuid or setgid.\n"
212                 "This is not a supported use of GTK+. You must create a helper\n"
213                 "program instead. For further details, see:\n\n"
214                 "    http://www.gtk.org/setuid.html\n\n"
215                 "Refusing to initialize GTK+.");
216      exit (1);
217    }
218
219  return TRUE;
220}
221
222gboolean
223gtk_init_check (int      *argc,
224                char   ***argv)
225{
226  extern void gtk_object_post_arg_parsing_init (void);
227  GSList *gtk_modules = NULL;
228  GSList *slist;
229  gchar *env_string = NULL;
230
231  if (gtk_initialized)
232    return TRUE;
233
234  if (!check_setugid ())
235    return FALSE;
236 
237#if     0
238  g_set_error_handler (gtk_error);
239  g_set_warning_handler (gtk_warning);
240  g_set_message_handler (gtk_message);
241  g_set_print_handler (gtk_print);
242#endif
243 
244  /* Initialize "gdk". We pass along the 'argc' and 'argv'
245   *  parameters as they contain information that GDK uses
246   */
247  if (!gdk_init_check (argc, argv))
248    return FALSE;
249
250  gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
251 
252#ifdef G_ENABLE_DEBUG
253  env_string = getenv ("GTK_DEBUG");
254  if (env_string != NULL)
255    {
256      gtk_debug_flags = g_parse_debug_string (env_string,
257                                              gtk_debug_keys,
258                                              gtk_ndebug_keys);
259      env_string = NULL;
260    }
261#endif  /* G_ENABLE_DEBUG */
262
263  env_string = getenv ("GTK_MODULES");
264  if (env_string)
265    {
266      gchar **modules, **as;
267
268      modules = g_strsplit (env_string, ":", -1);
269      for (as = modules; *as; as++)
270        {
271          if (**as)
272            gtk_modules = g_slist_prepend (gtk_modules, *as);
273          else
274            g_free (*as);
275        }
276      g_free (modules);
277      env_string = NULL;
278    }
279
280  if (argc && argv)
281    {
282      gint i, j, k;
283     
284      for (i = 1; i < *argc;)
285        {
286          if (strcmp ("--gtk-module", (*argv)[i]) == 0 ||
287              strncmp ("--gtk-module=", (*argv)[i], 13) == 0)
288            {
289              gchar *module_name = (*argv)[i] + 12;
290             
291              if (*module_name == '=')
292                module_name++;
293              else if (i + 1 < *argc)
294                {
295                  (*argv)[i] = NULL;
296                  i += 1;
297                  module_name = (*argv)[i];
298                }
299              (*argv)[i] = NULL;
300
301              if (module_name && *module_name)
302                gtk_modules = g_slist_prepend (gtk_modules, g_strdup (module_name));
303            }
304          else if (strcmp ("--g-fatal-warnings", (*argv)[i]) == 0)
305            {
306              GLogLevelFlags fatal_mask;
307             
308              fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
309              fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
310              g_log_set_always_fatal (fatal_mask);
311              (*argv)[i] = NULL;
312            }
313#ifdef G_ENABLE_DEBUG
314          else if ((strcmp ("--gtk-debug", (*argv)[i]) == 0) ||
315                   (strncmp ("--gtk-debug=", (*argv)[i], 12) == 0))
316            {
317              gchar *equal_pos = strchr ((*argv)[i], '=');
318             
319              if (equal_pos != NULL)
320                {
321                  gtk_debug_flags |= g_parse_debug_string (equal_pos+1,
322                                                           gtk_debug_keys,
323                                                           gtk_ndebug_keys);
324                }
325              else if ((i + 1) < *argc && (*argv)[i + 1])
326                {
327                  gtk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
328                                                           gtk_debug_keys,
329                                                           gtk_ndebug_keys);
330                  (*argv)[i] = NULL;
331                  i += 1;
332                }
333              (*argv)[i] = NULL;
334            }
335          else if ((strcmp ("--gtk-no-debug", (*argv)[i]) == 0) ||
336                   (strncmp ("--gtk-no-debug=", (*argv)[i], 15) == 0))
337            {
338              gchar *equal_pos = strchr ((*argv)[i], '=');
339             
340              if (equal_pos != NULL)
341                {
342                  gtk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
343                                                            gtk_debug_keys,
344                                                            gtk_ndebug_keys);
345                }
346              else if ((i + 1) < *argc && (*argv)[i + 1])
347                {
348                  gtk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
349                                                            gtk_debug_keys,
350                                                            gtk_ndebug_keys);
351                  (*argv)[i] = NULL;
352                  i += 1;
353                }
354              (*argv)[i] = NULL;
355            }
356#endif /* G_ENABLE_DEBUG */
357          i += 1;
358        }
359     
360      for (i = 1; i < *argc; i++)
361        {
362          for (k = i; k < *argc; k++)
363            if ((*argv)[k] != NULL)
364              break;
365         
366          if (k > i)
367            {
368              k -= i;
369              for (j = i + k; j < *argc; j++)
370                (*argv)[j-k] = (*argv)[j];
371              *argc -= k;
372            }
373        }
374    }
375 
376  /* load gtk modules */
377  gtk_modules = g_slist_reverse (gtk_modules);
378  for (slist = gtk_modules; slist; slist = slist->next)
379    {
380      gchar *module_name;
381      GModule *module = NULL;
382      GtkModuleInitFunc modinit_func = NULL;
383     
384      module_name = slist->data;
385      slist->data = NULL;
386      if (!(module_name[0] == '/' ||
387            (module_name[0] == 'l' &&
388             module_name[1] == 'i' &&
389             module_name[2] == 'b')))
390        {
391          gchar *old = module_name;
392         
393          module_name = g_strconcat ("lib", module_name, ".so", NULL);
394          g_free (old);
395        }
396      if (g_module_supported ())
397        {
398          module = g_module_open (module_name, G_MODULE_BIND_LAZY);
399          if (module &&
400              g_module_symbol (module, "gtk_module_init", (gpointer*) &modinit_func) &&
401              modinit_func)
402            {
403              if (!g_slist_find (gtk_modules, (void *)modinit_func))
404                {
405                  g_module_make_resident (module);
406                  slist->data = (void *)modinit_func;
407                }
408              else
409                {
410                  g_module_close (module);
411                  module = NULL;
412                }
413            }
414        }
415      if (!modinit_func)
416        {
417          g_warning ("Failed to load module \"%s\": %s",
418                     module ? g_module_name (module) : module_name,
419                     g_module_error ());
420          if (module)
421            g_module_close (module);
422        }
423      g_free (module_name);
424    }
425
426#ifdef ENABLE_NLS
427  bindtextdomain("gtk+", GTK_LOCALEDIR);
428#endif 
429
430  /* Initialize the default visual and colormap to be
431   *  used in creating widgets. (We want to use the system
432   *  defaults so as to be nice to the colormap).
433   */
434  gtk_visual = gdk_visual_get_system ();
435  gtk_colormap = gdk_colormap_get_system ();
436
437  gtk_type_init ();
438  gtk_object_post_arg_parsing_init ();
439  gtk_signal_init ();
440  gtk_rc_init ();
441 
442 
443  /* Register an exit function to make sure we are able to cleanup.
444   */
445  g_atexit (gtk_exit_func);
446 
447  /* Set the 'initialized' flag.
448   */
449  gtk_initialized = TRUE;
450
451  /* initialize gtk modules
452   */
453  for (slist = gtk_modules; slist; slist = slist->next)
454    {
455      if (slist->data)
456        {
457          GtkModuleInitFunc modinit;
458         
459          modinit = (GtkModuleInitFunc)slist->data;
460          modinit (argc, argv);
461        }
462    }
463  g_slist_free (gtk_modules);
464
465  return TRUE;
466}
467
468void
469gtk_init (int *argc, char ***argv)
470{
471  if (!gtk_init_check (argc, argv))
472    {
473      g_warning ("cannot open display: %s", gdk_get_display ());
474      exit(1);
475    }
476}
477
478void
479gtk_exit (int errorcode)
480{
481  /* Only if "gtk" has been initialized should we de-initialize.
482   */
483  /* de-initialisation is done by the gtk_exit_funct(),
484   * no need to do this here (Alex J.)
485   */
486  gdk_exit(errorcode);
487}
488
489gchar*
490gtk_set_locale (void)
491{
492  return gdk_set_locale ();
493}
494
495void
496gtk_main (void)
497{
498  GList *tmp_list;
499  GList *functions;
500  GtkInitFunction *init;
501  GMainLoop *loop;
502
503  gtk_main_loop_level++;
504 
505  loop = g_main_new (TRUE);
506  main_loops = g_slist_prepend (main_loops, loop);
507
508  tmp_list = functions = init_functions;
509  init_functions = NULL;
510 
511  while (tmp_list)
512    {
513      init = tmp_list->data;
514      tmp_list = tmp_list->next;
515     
516      (* init->function) (init->data);
517      g_free (init);
518    }
519  g_list_free (functions);
520
521  if (g_main_is_running (main_loops->data))
522    {
523      GDK_THREADS_LEAVE ();
524      g_main_run (loop);
525      GDK_THREADS_ENTER ();
526      gdk_flush ();
527    }
528
529  if (quit_functions)
530    {
531      GList *reinvoke_list = NULL;
532      GtkQuitFunction *quitf;
533
534      while (quit_functions)
535        {
536          quitf = quit_functions->data;
537
538          tmp_list = quit_functions;
539          quit_functions = g_list_remove_link (quit_functions, quit_functions);
540          g_list_free_1 (tmp_list);
541
542          if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) ||
543              gtk_quit_invoke_function (quitf))
544            {
545              reinvoke_list = g_list_prepend (reinvoke_list, quitf);
546            }
547          else
548            {
549              gtk_quit_destroy (quitf);
550            }
551        }
552      if (reinvoke_list)
553        {
554          GList *work;
555         
556          work = g_list_last (reinvoke_list);
557          if (quit_functions)
558            quit_functions->prev = work;
559          work->next = quit_functions;
560          quit_functions = work;
561        }
562
563      gdk_flush ();
564    }
565             
566  main_loops = g_slist_remove (main_loops, loop);
567
568  g_main_destroy (loop);
569
570  gtk_main_loop_level--;
571}
572
573guint
574gtk_main_level (void)
575{
576  return gtk_main_loop_level;
577}
578
579void
580gtk_main_quit (void)
581{
582  g_return_if_fail (main_loops != NULL);
583
584  g_main_quit (main_loops->data);
585}
586
587gint
588gtk_events_pending (void)
589{
590  gboolean result;
591 
592  GDK_THREADS_LEAVE (); 
593  result = g_main_pending();
594  GDK_THREADS_ENTER ();
595
596  return result;
597}
598
599gint
600gtk_main_iteration (void)
601{
602  GDK_THREADS_LEAVE ();
603  g_main_iteration (TRUE);
604  GDK_THREADS_ENTER ();
605
606  if (main_loops)
607    return !g_main_is_running (main_loops->data);
608  else
609    return TRUE;
610}
611
612gint
613gtk_main_iteration_do (gboolean blocking)
614{
615  GDK_THREADS_LEAVE ();
616  g_main_iteration (blocking);
617  GDK_THREADS_ENTER ();
618
619  if (main_loops)
620    return !g_main_is_running (main_loops->data);
621  else
622    return TRUE;
623}
624
625void
626gtk_main_do_event (GdkEvent *event)
627{
628  GtkWidget *event_widget;
629  GtkWidget *grab_widget;
630  GdkEvent *next_event;
631  GList *tmp_list;
632
633  /* If there are any events pending then get the next one.
634   */
635  next_event = gdk_event_peek ();
636 
637  /* Try to compress enter/leave notify events. These event
638   *  pairs occur when the mouse is dragged quickly across
639   *  a window with many buttons (or through a menu). Instead
640   *  of highlighting and de-highlighting each widget that
641   *  is crossed it is better to simply de-highlight the widget
642   *  which contained the mouse initially and highlight the
643   *  widget which ends up containing the mouse.
644   */
645  if (next_event)
646    if (((event->type == GDK_ENTER_NOTIFY) ||
647         (event->type == GDK_LEAVE_NOTIFY)) &&
648        ((next_event->type == GDK_ENTER_NOTIFY) ||
649         (next_event->type == GDK_LEAVE_NOTIFY)) &&
650        (next_event->type != event->type) &&
651        (next_event->any.window == event->any.window))
652      {
653        /* Throw both the peeked copy and the queued copy away
654         */
655        gdk_event_free (next_event);
656        next_event = gdk_event_get ();
657        gdk_event_free (next_event);
658       
659        return;
660      }
661
662  if (next_event)
663    gdk_event_free (next_event);
664
665  /* Find the widget which got the event. We store the widget
666   *  in the user_data field of GdkWindow's.
667   *  Ignore the event if we don't have a widget for it, except
668   *  for GDK_PROPERTY_NOTIFY events which are handled specialy.
669   *  Though this happens rarely, bogus events can occour
670   *  for e.g. destroyed GdkWindows.
671   */
672  event_widget = gtk_get_event_widget (event);
673  if (!event_widget)
674    {
675      /* To handle selection INCR transactions, we select
676       * PropertyNotify events on the requestor window and create
677       * a corresponding (fake) GdkWindow so that events get
678       * here. There won't be a widget though, so we have to handle
679           * them specially
680           */
681      if (event->type == GDK_PROPERTY_NOTIFY)
682        gtk_selection_incr_event (event->any.window,
683                                  &event->property);
684     
685      return;
686    }
687 
688  /* Push the event onto a stack of current events for
689   * gtk_current_event_get().
690   */
691  current_events = g_list_prepend (current_events, event);
692 
693  /* If there is a grab in effect...
694   */
695  if (grabs)
696    {
697      grab_widget = grabs->data;
698     
699      /* If the grab widget is an ancestor of the event widget
700       *  then we send the event to the original event widget.
701       *  This is the key to implementing modality.
702       */
703      if (GTK_WIDGET_IS_SENSITIVE (event_widget) &&
704          gtk_widget_is_ancestor (event_widget, grab_widget))
705        grab_widget = event_widget;
706    }
707  else
708    {
709      grab_widget = event_widget;
710    }
711
712  /* Not all events get sent to the grabbing widget.
713   * The delete, destroy, expose, focus change and resize
714   *  events still get sent to the event widget because
715   *  1) these events have no meaning for the grabbing widget
716   *  and 2) redirecting these events to the grabbing widget
717   *  could cause the display to be messed up.
718   *
719   * Drag events are also not redirected, since it isn't
720   *  clear what the semantics of that would be.
721   */
722  switch (event->type)
723    {
724    case GDK_NOTHING:
725      break;
726     
727    case GDK_DELETE:
728      gtk_widget_ref (event_widget);
729      if ((!grabs || gtk_widget_get_toplevel (grabs->data) == event_widget) &&
730          !gtk_widget_event (event_widget, event))
731        gtk_widget_destroy (event_widget);
732      gtk_widget_unref (event_widget);
733      break;
734     
735    case GDK_DESTROY:
736      /* Unexpected GDK_DESTROY from the outside, ignore for
737       * child windows, handle like a GDK_DELETE for toplevels
738       */
739      if (!event_widget->parent)
740        {
741          gtk_widget_ref (event_widget);
742          if (!gtk_widget_event (event_widget, event) &&
743              !GTK_OBJECT_DESTROYED (event_widget))
744            gtk_widget_destroy (event_widget);
745          gtk_widget_unref (event_widget);
746        }
747      break;
748     
749    case GDK_PROPERTY_NOTIFY:
750    case GDK_EXPOSE:
751    case GDK_NO_EXPOSE:
752    case GDK_FOCUS_CHANGE:
753    case GDK_CONFIGURE:
754    case GDK_MAP:
755    case GDK_UNMAP:
756    case GDK_SELECTION_CLEAR:
757    case GDK_SELECTION_REQUEST:
758    case GDK_SELECTION_NOTIFY:
759    case GDK_CLIENT_EVENT:
760    case GDK_VISIBILITY_NOTIFY:
761      gtk_widget_event (event_widget, event);
762      break;
763
764    case GDK_BUTTON_PRESS:
765    case GDK_2BUTTON_PRESS:
766    case GDK_3BUTTON_PRESS:
767    /* We treat button 4-5 specially, assume we have
768     * a MS-style scrollwheel mouse, and try to find
769     * a plausible widget to scroll. We also trap
770     * button 4-5 double and triple clicks here, since
771     * they will be generated if the user scrolls quickly.
772     */
773      if ((grab_widget == event_widget) &&
774          (event->button.button == 4 || event->button.button == 5))
775        {
776          GtkWidget *range = NULL;
777          GtkWidget *scrollwin;
778         
779          if (GTK_IS_RANGE (event_widget))
780            range = event_widget;
781          else
782            {
783              scrollwin = gtk_widget_get_ancestor (event_widget,
784                                                   GTK_TYPE_SCROLLED_WINDOW);
785              if (scrollwin)
786                range = GTK_SCROLLED_WINDOW (scrollwin)->vscrollbar;
787            }
788         
789          if (range && GTK_WIDGET_VISIBLE (range))
790            {
791              if (event->type == GDK_BUTTON_PRESS)
792                {
793                  GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
794                  gfloat new_value = adj->value + ((event->button.button == 4) ?
795                                                   -adj->page_increment / 2:
796                                                    adj->page_increment / 2);
797                  new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
798                  gtk_adjustment_set_value (adj, new_value);
799                }
800              break;
801            }
802        }
803      gtk_propagate_event (grab_widget, event);
804      break;
805
806    case GDK_KEY_PRESS:
807    case GDK_KEY_RELEASE:
808      if (key_snoopers)
809        {
810          if (gtk_invoke_key_snoopers (grab_widget, event))
811            break;
812        }
813      /* else fall through */
814    case GDK_MOTION_NOTIFY:
815    case GDK_BUTTON_RELEASE:
816    case GDK_PROXIMITY_IN:
817    case GDK_PROXIMITY_OUT:
818      gtk_propagate_event (grab_widget, event);
819      break;
820     
821    case GDK_ENTER_NOTIFY:
822      if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
823        {
824          gtk_widget_event (grab_widget, event);
825          if (event_widget == grab_widget)
826            GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
827        }
828      break;
829     
830    case GDK_LEAVE_NOTIFY:
831      if (GTK_WIDGET_LEAVE_PENDING (event_widget))
832        {
833          GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING);
834          gtk_widget_event (event_widget, event);
835        }
836      else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
837        gtk_widget_event (grab_widget, event);
838      break;
839     
840    case GDK_DRAG_STATUS:
841    case GDK_DROP_FINISHED:
842      gtk_drag_source_handle_event (event_widget, event);
843      break;
844    case GDK_DRAG_ENTER:
845    case GDK_DRAG_LEAVE:
846    case GDK_DRAG_MOTION:
847    case GDK_DROP_START:
848      gtk_drag_dest_handle_event (event_widget, event);
849      break;
850    }
851 
852  tmp_list = current_events;
853  current_events = g_list_remove_link (current_events, tmp_list);
854  g_list_free_1 (tmp_list);
855}
856
857gint
858gtk_true (void)
859{
860  return TRUE;
861}
862
863gint
864gtk_false (void)
865{
866  return FALSE;
867}
868
869void
870gtk_grab_add (GtkWidget *widget)
871{
872  g_return_if_fail (widget != NULL);
873 
874  if (!GTK_WIDGET_HAS_GRAB (widget) && GTK_WIDGET_IS_SENSITIVE (widget))
875    {
876      GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB);
877     
878      grabs = g_slist_prepend (grabs, widget);
879      gtk_widget_ref (widget);
880    }
881}
882
883GtkWidget*
884gtk_grab_get_current (void)
885{
886  if (grabs)
887    return GTK_WIDGET (grabs->data);
888  return NULL;
889}
890
891void
892gtk_grab_remove (GtkWidget *widget)
893{
894  g_return_if_fail (widget != NULL);
895 
896  if (GTK_WIDGET_HAS_GRAB (widget))
897    {
898      GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB);
899     
900      grabs = g_slist_remove (grabs, widget);
901      gtk_widget_unref (widget);
902    }
903}
904
905void
906gtk_init_add (GtkFunction function,
907              gpointer    data)
908{
909  GtkInitFunction *init;
910 
911  init = g_new (GtkInitFunction, 1);
912  init->function = function;
913  init->data = data;
914 
915  init_functions = g_list_prepend (init_functions, init);
916}
917
918guint
919gtk_key_snooper_install (GtkKeySnoopFunc snooper,
920                         gpointer        func_data)
921{
922  GtkKeySnooperData *data;
923  static guint snooper_id = 1;
924
925  g_return_val_if_fail (snooper != NULL, 0);
926
927  data = g_new (GtkKeySnooperData, 1);
928  data->func = snooper;
929  data->func_data = func_data;
930  data->id = snooper_id++;
931  key_snoopers = g_slist_prepend (key_snoopers, data);
932
933  return data->id;
934}
935
936void
937gtk_key_snooper_remove (guint            snooper_id)
938{
939  GtkKeySnooperData *data = NULL;
940  GSList *slist;
941
942  slist = key_snoopers;
943  while (slist)
944    {
945      data = slist->data;
946      if (data->id == snooper_id)
947        break;
948
949      slist = slist->next;
950      data = NULL;
951    }
952  if (data)
953    key_snoopers = g_slist_remove (key_snoopers, data);
954}
955
956static gint
957gtk_invoke_key_snoopers (GtkWidget *grab_widget,
958                         GdkEvent  *event)
959{
960  GSList *slist;
961  gint return_val = FALSE;
962
963  slist = key_snoopers;
964  while (slist && !return_val)
965    {
966      GtkKeySnooperData *data;
967
968      data = slist->data;
969      slist = slist->next;
970      return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
971    }
972
973  return return_val;
974}
975
976guint
977gtk_quit_add_full (guint                main_level,
978                   GtkFunction          function,
979                   GtkCallbackMarshal   marshal,
980                   gpointer             data,
981                   GtkDestroyNotify     destroy)
982{
983  static guint quit_id = 1;
984  GtkQuitFunction *quitf;
985 
986  g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
987
988  if (!quit_mem_chunk)
989    quit_mem_chunk = g_mem_chunk_new ("quit mem chunk", sizeof (GtkQuitFunction),
990                                      512, G_ALLOC_AND_FREE);
991 
992  quitf = g_chunk_new (GtkQuitFunction, quit_mem_chunk);
993 
994  quitf->id = quit_id++;
995  quitf->main_level = main_level;
996  quitf->function = function;
997  quitf->marshal = marshal;
998  quitf->data = data;
999  quitf->destroy = destroy;
1000
1001  quit_functions = g_list_prepend (quit_functions, quitf);
1002 
1003  return quitf->id;
1004}
1005
1006static void
1007gtk_quit_destroy (GtkQuitFunction *quitf)
1008{
1009  if (quitf->destroy)
1010    quitf->destroy (quitf->data);
1011  g_mem_chunk_free (quit_mem_chunk, quitf);
1012}
1013
1014static gint
1015gtk_quit_destructor (GtkObject **object_p)
1016{
1017  if (*object_p)
1018    gtk_object_destroy (*object_p);
1019  g_free (object_p);
1020
1021  return FALSE;
1022}
1023
1024void
1025gtk_quit_add_destroy (guint              main_level,
1026                      GtkObject         *object)
1027{
1028  GtkObject **object_p;
1029
1030  g_return_if_fail (main_level > 0);
1031  g_return_if_fail (object != NULL);
1032  g_return_if_fail (GTK_IS_OBJECT (object));
1033
1034  object_p = g_new (GtkObject*, 1);
1035  *object_p = object;
1036  gtk_signal_connect (object,
1037                      "destroy",
1038                      GTK_SIGNAL_FUNC (gtk_widget_destroyed),
1039                      object_p);
1040  gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
1041}
1042
1043guint
1044gtk_quit_add (guint       main_level,
1045              GtkFunction function,
1046              gpointer    data)
1047{
1048  return gtk_quit_add_full (main_level, function, NULL, data, NULL);
1049}
1050
1051void
1052gtk_quit_remove (guint id)
1053{
1054  GtkQuitFunction *quitf;
1055  GList *tmp_list;
1056 
1057  tmp_list = quit_functions;
1058  while (tmp_list)
1059    {
1060      quitf = tmp_list->data;
1061     
1062      if (quitf->id == id)
1063        {
1064          quit_functions = g_list_remove_link (quit_functions, tmp_list);
1065          g_list_free (tmp_list);
1066          gtk_quit_destroy (quitf);
1067         
1068          return;
1069        }
1070     
1071      tmp_list = tmp_list->next;
1072    }
1073}
1074
1075void
1076gtk_quit_remove_by_data (gpointer data)
1077{
1078  GtkQuitFunction *quitf;
1079  GList *tmp_list;
1080 
1081  tmp_list = quit_functions;
1082  while (tmp_list)
1083    {
1084      quitf = tmp_list->data;
1085     
1086      if (quitf->data == data)
1087        {
1088          quit_functions = g_list_remove_link (quit_functions, tmp_list);
1089          g_list_free (tmp_list);
1090          gtk_quit_destroy (quitf);
1091
1092          return;
1093        }
1094     
1095      tmp_list = tmp_list->next;
1096    }
1097}
1098
1099guint
1100gtk_timeout_add_full (guint32            interval,
1101                      GtkFunction        function,
1102                      GtkCallbackMarshal marshal,
1103                      gpointer           data,
1104                      GtkDestroyNotify   destroy)
1105{
1106  if (marshal)
1107    {
1108      GtkClosure *closure;
1109
1110      closure = g_new (GtkClosure, 1);
1111      closure->marshal = marshal;
1112      closure->data = data;
1113      closure->destroy = destroy;
1114
1115      return g_timeout_add_full (0, interval,
1116                                 gtk_invoke_idle_timeout,
1117                                 closure,
1118                                 gtk_destroy_closure);
1119    }
1120  else
1121    return g_timeout_add_full (0, interval, function, data, destroy);
1122}
1123
1124guint
1125gtk_timeout_add (guint32     interval,
1126                 GtkFunction function,
1127                 gpointer    data)
1128{
1129  return g_timeout_add_full (0, interval, function, data, NULL);
1130}
1131
1132void
1133gtk_timeout_remove (guint tag)
1134{
1135  g_source_remove (tag);
1136}
1137
1138guint
1139gtk_idle_add_full (gint                 priority,
1140                   GtkFunction          function,
1141                   GtkCallbackMarshal   marshal,
1142                   gpointer             data,
1143                   GtkDestroyNotify     destroy)
1144{
1145  if (marshal)
1146    {
1147      GtkClosure *closure;
1148
1149      closure = g_new (GtkClosure, 1);
1150      closure->marshal = marshal;
1151      closure->data = data;
1152      closure->destroy = destroy;
1153
1154      return g_idle_add_full (priority,
1155                              gtk_invoke_idle_timeout,
1156                              closure,
1157                              gtk_destroy_closure);
1158    }
1159  else
1160    return g_idle_add_full (priority, function, data, destroy);
1161}
1162
1163guint
1164gtk_idle_add (GtkFunction function,
1165              gpointer    data)
1166{
1167  return g_idle_add_full (GTK_PRIORITY_DEFAULT, function, data, NULL);
1168}
1169
1170guint       
1171gtk_idle_add_priority   (gint               priority,
1172                         GtkFunction        function,
1173                         gpointer           data)
1174{
1175  return g_idle_add_full (priority, function, data, NULL);
1176}
1177
1178void
1179gtk_idle_remove (guint tag)
1180{
1181  g_source_remove (tag);
1182}
1183
1184void
1185gtk_idle_remove_by_data (gpointer data)
1186{
1187  if (!g_idle_remove_by_data (data))
1188    g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
1189}
1190
1191guint
1192gtk_input_add_full (gint                source,
1193                    GdkInputCondition   condition,
1194                    GdkInputFunction    function,
1195                    GtkCallbackMarshal  marshal,
1196                    gpointer            data,
1197                    GtkDestroyNotify    destroy)
1198{
1199  if (marshal)
1200    {
1201      GtkClosure *closure;
1202
1203      closure = g_new (GtkClosure, 1);
1204      closure->marshal = marshal;
1205      closure->data = data;
1206      closure->destroy = destroy;
1207
1208      return gdk_input_add_full (source,
1209                                 condition,
1210                                 (GdkInputFunction) gtk_invoke_input,
1211                                 closure,
1212                                 (GdkDestroyNotify) gtk_destroy_closure);
1213    }
1214  else
1215    return gdk_input_add_full (source, condition, function, data, destroy);
1216}
1217
1218void
1219gtk_input_remove (guint tag)
1220{
1221  g_source_remove (tag);
1222}
1223
1224static void
1225gtk_destroy_closure (gpointer data)
1226{
1227  GtkClosure *closure = data;
1228
1229  if (closure->destroy)
1230    (closure->destroy) (closure->data);
1231  g_free (closure);
1232}
1233
1234static gboolean
1235gtk_invoke_idle_timeout (gpointer data)
1236{
1237  GtkClosure *closure = data;
1238
1239  GtkArg args[1];
1240  gint ret_val = FALSE;
1241  args[0].name = NULL;
1242  args[0].type = GTK_TYPE_BOOL;
1243  args[0].d.pointer_data = &ret_val;
1244  closure->marshal (NULL, closure->data,  0, args);
1245  return ret_val;
1246}
1247
1248static void
1249gtk_invoke_input (gpointer          data,
1250                  gint              source,
1251                  GdkInputCondition condition)
1252{
1253  GtkClosure *closure = data;
1254
1255  GtkArg args[3];
1256  args[0].type = GTK_TYPE_INT;
1257  args[0].name = NULL;
1258  GTK_VALUE_INT(args[0]) = source;
1259  args[1].type = GTK_TYPE_GDK_INPUT_CONDITION;
1260  args[1].name = NULL;
1261  GTK_VALUE_FLAGS(args[1]) = condition;
1262  args[2].type = GTK_TYPE_NONE;
1263  args[2].name = NULL;
1264
1265  closure->marshal (NULL, closure->data, 2, args);
1266}
1267
1268GdkEvent*
1269gtk_get_current_event (void)
1270{
1271  if (current_events)
1272    return gdk_event_copy ((GdkEvent *) current_events->data);
1273  else
1274    return NULL;
1275}
1276
1277GtkWidget*
1278gtk_get_event_widget (GdkEvent *event)
1279{
1280  GtkWidget *widget;
1281
1282  widget = NULL;
1283  if (event && event->any.window)
1284    gdk_window_get_user_data (event->any.window, (void**) &widget);
1285 
1286  return widget;
1287}
1288
1289static void
1290gtk_exit_func (void)
1291{
1292  if (gtk_initialized)
1293    {
1294      gtk_initialized = FALSE;
1295      gtk_preview_uninit ();
1296    }
1297}
1298
1299
1300static gint
1301gtk_quit_invoke_function (GtkQuitFunction *quitf)
1302{
1303  if (!quitf->marshal)
1304    return quitf->function (quitf->data);
1305  else
1306    {
1307      GtkArg args[1];
1308      gint ret_val = FALSE;
1309
1310      args[0].name = NULL;
1311      args[0].type = GTK_TYPE_BOOL;
1312      args[0].d.pointer_data = &ret_val;
1313      ((GtkCallbackMarshal) quitf->marshal) (NULL,
1314                                             quitf->data,
1315                                             0, args);
1316      return ret_val;
1317    }
1318}
1319
1320void
1321gtk_propagate_event (GtkWidget *widget,
1322                     GdkEvent  *event)
1323{
1324  gint handled_event;
1325 
1326  g_return_if_fail (widget != NULL);
1327  g_return_if_fail (GTK_IS_WIDGET (widget));
1328  g_return_if_fail (event != NULL);
1329 
1330  handled_event = FALSE;
1331
1332  gtk_widget_ref (widget);
1333     
1334  if ((event->type == GDK_KEY_PRESS) ||
1335      (event->type == GDK_KEY_RELEASE))
1336    {
1337      /* Only send key events within Window widgets to the Window
1338       *  The Window widget will in turn pass the
1339       *  key event on to the currently focused widget
1340       *  for that window.
1341       */
1342      GtkWidget *window;
1343
1344      window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
1345
1346      if (window)
1347        {
1348          /* If there is a grab within the window, give the grab widget
1349           * a first crack at the key event
1350           */
1351          if (widget != window && GTK_WIDGET_HAS_GRAB (widget))
1352            handled_event = gtk_widget_event (widget, event);
1353         
1354          if (!handled_event)
1355            {
1356              window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
1357              if (window)
1358                {
1359                  if (GTK_WIDGET_IS_SENSITIVE (window))
1360                    gtk_widget_event (window, event);
1361                }
1362            }
1363                 
1364          handled_event = TRUE; /* don't send to widget */
1365        }
1366    }
1367 
1368  /* Other events get propagated up the widget tree
1369   *  so that parents can see the button and motion
1370   *  events of the children.
1371   */
1372  if (!handled_event)
1373    {
1374      while (TRUE)
1375        {
1376          GtkWidget *tmp;
1377         
1378          handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event);
1379          tmp = widget->parent;
1380          gtk_widget_unref (widget);
1381
1382          widget = tmp;
1383         
1384          if (!handled_event && widget)
1385            gtk_widget_ref (widget);
1386          else
1387            break;
1388        }
1389    }
1390  else
1391    gtk_widget_unref (widget);
1392}
1393
1394#if 0
1395static void
1396gtk_error (gchar *str)
1397{
1398  gtk_print (str);
1399}
1400
1401static void
1402gtk_warning (gchar *str)
1403{
1404  gtk_print (str);
1405}
1406
1407static void
1408gtk_message (gchar *str)
1409{
1410  gtk_print (str);
1411}
1412
1413static void
1414gtk_print (gchar *str)
1415{
1416  static GtkWidget *window = NULL;
1417  static GtkWidget *text;
1418  static int level = 0;
1419  GtkWidget *box1;
1420  GtkWidget *box2;
1421  GtkWidget *table;
1422  GtkWidget *hscrollbar;
1423  GtkWidget *vscrollbar;
1424  GtkWidget *separator;
1425  GtkWidget *button;
1426 
1427  if (level > 0)
1428    {
1429      fputs (str, stdout);
1430      fflush (stdout);
1431      return;
1432    }
1433 
1434  if (!window)
1435    {
1436      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1437     
1438      gtk_signal_connect (GTK_OBJECT (window), "destroy",
1439                          (GtkSignalFunc) gtk_widget_destroyed,
1440                          &window);
1441     
1442      gtk_window_set_title (GTK_WINDOW (window), "Messages");
1443     
1444      box1 = gtk_vbox_new (FALSE, 0);
1445      gtk_container_add (GTK_CONTAINER (window), box1);
1446      gtk_widget_show (box1);
1447     
1448     
1449      box2 = gtk_vbox_new (FALSE, 10);
1450      gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
1451      gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
1452      gtk_widget_show (box2);
1453     
1454     
1455      table = gtk_table_new (2, 2, FALSE);
1456      gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
1457      gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
1458      gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
1459      gtk_widget_show (table);
1460     
1461      text = gtk_text_new (NULL, NULL);
1462      gtk_text_set_editable (GTK_TEXT (text), FALSE);
1463      gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1);
1464      gtk_widget_show (text);
1465      gtk_widget_realize (text);
1466     
1467      hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
1468      gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
1469                        GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
1470      gtk_widget_show (hscrollbar);
1471     
1472      vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
1473      gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
1474                        GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1475      gtk_widget_show (vscrollbar);
1476     
1477      separator = gtk_hseparator_new ();
1478      gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
1479      gtk_widget_show (separator);
1480     
1481     
1482      box2 = gtk_vbox_new (FALSE, 10);
1483      gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
1484      gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
1485      gtk_widget_show (box2);
1486     
1487     
1488      button = gtk_button_new_with_label ("close");
1489      gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
1490                                 (GtkSignalFunc) gtk_widget_hide,
1491                                 GTK_OBJECT (window));
1492      gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
1493      GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
1494      gtk_widget_grab_default (button);
1495      gtk_widget_show (button);
1496    }
1497 
1498  level += 1;
1499  gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1);
1500  level -= 1;
1501 
1502  if (!GTK_WIDGET_VISIBLE (window))
1503    gtk_widget_show (window);
1504}
1505#endif
Note: See TracBrowser for help on using the repository browser.