source: trunk/third/rep-gtk/rep-gtk.c @ 18404

Revision 18404, 60.4 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18403, which included commits to RCS files with non-trunk default branches.
Line 
1/* Copyright (C) 1997, 1998, 1999 Marius Vollmer
2 * Copyright (C) 1999 John Harper <john@dcs.warwick.ac.uk>
3 *
4 * $Id: rep-gtk.c,v 1.1.1.2 2003-01-05 00:30:09 ghudson Exp $
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this software; see the file COPYING.  If not, write to
18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <config.h>
22#include <assert.h>
23#include <gtk/gtk.h>
24#include <gdk/gdkprivate.h>
25#include <gdk/gdkx.h>
26#include "rep-gtk.h"
27#include <string.h>
28#include <limits.h>
29
30#ifdef HAVE_LOCALE_H
31# include <locale.h>
32#endif
33
34/* Define this to enable some output during GC and other interesting
35   actions. */
36#undef DEBUG_PRINT
37
38static int
39list_length (repv list)
40{
41    repv len = Flength (list);
42    return (len && rep_INTP (len)) ? rep_INT (len) : 0;
43}
44
45
46
47/* Associating SCM values with Gtk pointers.
48
49   We keep a hash table that can store a SCM value for an arbitray
50   gpointer.  This is used for the proxies of GObjects and the boxed
51   types.  */
52
53static GHashTable *proxy_tab;
54
55static void
56enter_proxy (gpointer obj, repv proxy)
57{
58  if (proxy_tab == NULL)
59    proxy_tab = g_hash_table_new (NULL, NULL);
60  g_hash_table_insert (proxy_tab, obj, (gpointer)proxy);
61}
62
63static repv
64get_proxy (gpointer obj)
65{
66  if (proxy_tab)
67    {
68      gpointer val = g_hash_table_lookup (proxy_tab, obj);
69      return val? (repv) val : Qnil;
70    }
71  return Qnil;
72}
73
74static void
75forget_proxy (gpointer obj)
76{
77  g_hash_table_remove (proxy_tab, obj);
78}
79
80
81
82/* Storing additional info about a GType.
83
84   We used to use the type's SEQNO, but these aren't globally
85   contiguous anymore, so we use type g_type_set_qdata() instead. */
86
87static GQuark type_info_quark = 0;
88
89static void
90enter_type_info (sgtk_type_info *info)
91{
92  if (!type_info_quark)
93    {
94      type_info_quark = g_quark_from_static_string ("rep-gtk-type-info");
95    }
96
97  g_type_set_qdata (info->type, type_info_quark, info);
98}
99
100sgtk_type_info*
101sgtk_get_type_info (GType type)
102{
103  return (type_info_quark
104          ? g_type_get_qdata (type, type_info_quark)
105          : 0);
106}
107
108static sgtk_type_info*
109must_get_type_info (GType type)
110{
111  sgtk_type_info *info = sgtk_get_type_info (type);
112  if (info == NULL)
113    abort ();
114  return info;
115}
116
117typedef struct _type_infos {
118  struct _type_infos *next;
119  sgtk_type_info **infos;
120} type_infos;
121
122static type_infos *all_type_infos;
123
124/* Find types that are mentioned in our *.defs files but are not
125   provided by the GLib run-time system.  This is only used
126   occasionally to update the table in sgtk_try_missing_type.  */
127#ifdef NEED_UNUSED_CODE
128static void
129sgtk_find_missing_types (type_infos *infos)
130{
131  sgtk_type_info **ip;
132  for (ip = infos->infos; *ip; ip++)
133    {
134      if (g_type_from_name ((*ip)->name) == G_TYPE_INVALID
135          && (*ip)->type != G_TYPE_OBJECT)
136        printf ("missing: %s, %s\n",
137                (*ip)->name, g_type_name ((*ip)->type));
138    }
139}
140#endif
141
142void
143sgtk_register_type_infos (sgtk_type_info **infos)
144{
145  type_infos *t;
146
147  sgtk_init ();
148
149  t = (type_infos *) rep_alloc (sizeof(type_infos));
150  t->infos = infos;
151  t->next = all_type_infos;
152  all_type_infos = t;
153
154#if 0
155  sgtk_find_missing_types (t);
156#endif
157}
158
159/* When INFO refers to one of the known `missing' types, we initialize
160   that type ourselves.  This is used to fix certain discrepancies
161   between old Gtk versions and our *.defs files.  It is not OK to do
162   this in general because we should not assume that we can safely
163   initialize types from other modules.
164
165   XXX this doesn't work at ALL, almost all of these types _do_
166       have corresponding standard types now and we _certainly_
167       can't register them ourselves with an all 0s type info. --owt
168*/
169
170static GType
171sgtk_try_missing_type (char *name)
172{
173  static sgtk_type_info missing[] = {
174    { "GdkGC", G_TYPE_BOXED },
175    { "GdkPixbuf", G_TYPE_BOXED },      /* XXX okay? */
176    { "GtkTextIter", G_TYPE_BOXED },
177    { "GtkToolbarStyle", G_TYPE_ENUM },
178    { "GtkToolbarChildType", G_TYPE_ENUM },
179    { "GtkTreeViewMode", G_TYPE_ENUM },
180    { "GtkSpinButtonUpdatePolicy", G_TYPE_ENUM },
181    { "GtkCellType", G_TYPE_ENUM },
182    { "GdkOverlapType", G_TYPE_ENUM },
183    { "GdkWMDecoration", G_TYPE_FLAGS },
184    { "GdkWMFunction", G_TYPE_FLAGS },
185    { "GdkVisibilityState", G_TYPE_ENUM },
186    { "GdkInputSource", G_TYPE_ENUM },
187    {NULL, G_TYPE_NONE}
188  };
189
190  sgtk_type_info *m;
191  for (m = missing; m->name; m++)
192    if (!strcmp (m->name, name))
193      {
194        GTypeInfo info = { 0 };
195        return g_type_register_static (m->type, m->name, &info, 0);
196      }
197
198  return G_TYPE_INVALID;
199}
200
201static int
202sgtk_fillin_type_info (sgtk_type_info *info)
203{
204  if (info->type != G_TYPE_OBJECT
205      && info->type == G_TYPE_FUNDAMENTAL (info->type)
206      && info->type != G_TYPE_INVALID)
207    {
208      GType parent_type = info->type;
209      GType this_type = g_type_from_name (info->name);
210      if (this_type == G_TYPE_INVALID)
211        this_type = sgtk_try_missing_type (info->name);
212      if (this_type == G_TYPE_INVALID)
213        {
214          if (info->type == G_TYPE_BOXED)
215          fprintf (stderr, "unknown type `%s'.\n", info->name);
216          return 0;
217        }
218      info->type = this_type;
219      if (G_TYPE_FUNDAMENTAL (info->type) != parent_type)
220        {
221          fprintf (stderr, "mismatch for type `%s'.\n", info->name);
222          info->type = G_TYPE_INVALID;
223          return 0;
224        }
225      enter_type_info (info);
226    }
227
228  return 1;
229}     
230     
231sgtk_type_info*
232sgtk_maybe_find_type_info (GType type)
233{
234  sgtk_type_info *info;
235  type_infos *infos;
236  const char *name;
237
238  info = sgtk_get_type_info (type);
239  if (info)
240    return info;
241
242  /* XXX - merge this with the GObject code.  I don't have the brain
243     right now to do it. */
244
245  name = g_type_name (type);
246  for (infos = all_type_infos; infos; infos = infos->next)
247    {
248      sgtk_type_info **ip;
249      for (ip = infos->infos; *ip; ip++)
250        if (!strcmp ((*ip)->name, name))
251          {
252            if (G_TYPE_FUNDAMENTAL (type) != (*ip)->type)
253              {
254                fprintf (stderr, "mismatch for type `%s'.\n", name);
255                info->type = G_TYPE_INVALID;
256                abort ();
257              }
258            (*ip)->type = type;
259            enter_type_info (*ip);
260            return *ip;
261          }
262    }
263
264  /* XXX - should use the GLib type introspection here instead of
265     giving up. */
266
267  return NULL;
268}
269
270sgtk_type_info *
271sgtk_find_type_info (GType type)
272{
273  sgtk_type_info *info = sgtk_maybe_find_type_info (type);
274
275  if (info)
276    return info;
277
278  fprintf (stderr, "unknown type `%s'.\n", g_type_name (type));
279  abort ();
280}
281
282
283
284/* G[tk]Objects.
285
286   GtkObjects are wrapped with a smob.  The smob of a GtkObject is
287   called its proxy.  The proxy and its GtkObject are strongly
288   connected; that is, the GtkObject will stay around as long as the
289   proxy is referenced from Scheme, and the proxy will not be
290   collected as long as the GtkObject is used from outside of Scheme.
291
292   The lifetime of GtkObjects is controlled by a reference count,
293   while Scheme objects are managed by a tracing garbage collector
294   (mark/sweep).  These two techniques are made to cooperate like
295   this: the pointer from the proxy to the GtkObject is reflected in
296   the reference count of the GtkObject.  All proxies are kept in a
297   list and those that point to GtkObjects with a reference count
298   greater than the number of `internal' references are marked during
299   the marking phase of the tracing collector.  An internal reference
300   is one that goes from a GtkObject with a proxy to another GtkObject
301   with a proxy.  We can only find a subset of the true internal
302   references (because Gtk does not yet cooperate), but this should be
303   good enough.
304
305   By using this combination of tracing and reference counting it is
306   possible to break the cycle that is formed by the proxy pointing to
307   the GtkObject and the GtkObject pointing back.  It is
308   straightforward to extend this to other kind of cycles that might
309   occur.  For example, when connecting a Scheme procedure as a signal
310   handler, the procedure is very likely to have the GtkObject that it
311   is connected to in its environment.  This cycle can be broken by
312   including the procedure in the set of Scheme objects that get
313   marked when we are tracing GtkObjects with a reference count
314   greater than 1.
315
316   Therefore, each proxy contains a list of `protects' that are marked
317   when the proxy itself is marked.  In addition to this, there is
318   also a global list of `protects' that is used for Scheme objects
319   that are somewhere in Gtk land but not clearly associated with a
320   particular GtkObject (like timeout callbacks).
321
322  */
323
324struct sgtk_protshell {
325  repv object;
326  struct sgtk_protshell *next;
327  struct sgtk_protshell **prevp;
328};
329
330static GMemChunk *sgtk_protshell_chunk;
331
332/* Analogous to the PROTECTS list of a proxy but for SCM values that
333   are not associated with a particular GObject. */
334
335static struct sgtk_protshell *global_protects;
336
337void
338sgtk_unprotect (sgtk_protshell *prot)
339{
340  if ((*prot->prevp = prot->next) != 0)
341    prot->next->prevp = prot->prevp;
342  g_chunk_free (prot, sgtk_protshell_chunk);
343}
344
345static void
346sgtk_mark_protects (sgtk_protshell *prots)
347{
348  while (prots)
349    {
350      rep_MARKVAL (prots->object);
351      prots = prots->next;
352    }
353}
354
355/* The CDR of a GObject smob points to one of these.  PROTECTS is a
356   Scheme list of all SCM values that need to be protected from the GC
357   because they are in use by OBJ.  PROTECTS includes the smob cell
358   itself.  NEXT and PREVP are used to chain all proxies together for
359   the marking mentioned above.  NEXT simply points to the next proxy
360   struct and PREVP points to the pointer that points to us.  */
361
362typedef struct _sgtk_object_proxy {
363  repv car;
364  GObject *obj;
365  struct sgtk_protshell *protects;
366  int traced_refs;
367  struct _sgtk_object_proxy *next;
368} sgtk_object_proxy;
369
370/* The list of all existing proxies. */
371
372static sgtk_object_proxy *all_proxies = NULL;
373
374/* Insert the list of protshells starting at PROTS into the global
375   protects list.  This is used when a proxy is freed so that we don't
376   forget about its protects. */
377
378static void
379sgtk_move_prots_to_global (sgtk_protshell *prots)
380{
381  if (prots)
382    {
383      sgtk_protshell *g = global_protects;
384      global_protects = prots;
385      global_protects->prevp = &global_protects;
386      if (g)
387        {
388          sgtk_protshell *p;
389          for (p = prots; p->next; p = p->next)
390            ;
391          p->next = g;
392          g->prevp = &p->next;
393        }
394    }
395}
396
397/* The smob for GObjects.  */
398
399static long tc16_gobj;
400
401#define GOBJP(x)       (rep_CELL16_TYPEP(x, tc16_gobj))
402#define GOBJ_PROXY(x)  ((sgtk_object_proxy *)rep_PTR(x))
403
404void
405sgtk_set_protect (repv protector, sgtk_protshell *prot)
406{
407  sgtk_protshell **prevp;
408
409  if (GOBJP (protector))
410    prevp = &(GOBJ_PROXY(protector)->protects);
411  else
412    prevp = &global_protects;
413 
414  if ((prot->next = *prevp) != 0)
415        prot->next->prevp = &prot->next;
416  *prevp = prot;
417  prot->prevp = prevp;
418}
419
420repv
421sgtk_get_protect (sgtk_protshell *prot)
422{
423  return prot->object;
424}
425
426sgtk_protshell *
427sgtk_new_protect (repv obj)
428{
429  sgtk_protshell *prot = g_chunk_new (sgtk_protshell, sgtk_protshell_chunk);
430  prot->object = obj;
431  return prot;
432}
433
434sgtk_protshell *
435sgtk_protect (repv protector, repv obj)
436{
437  sgtk_protshell *prot = sgtk_new_protect (obj);
438  sgtk_set_protect (protector, prot);
439  return prot;
440}
441
442void
443sgtk_set_gclosure (repv protector, GClosure *closure)
444{
445  sgtk_protshell *prot = closure->data;
446  g_assert (prot != NULL);
447  sgtk_set_protect (protector, prot);
448}
449
450repv
451sgtk_get_gclosure (GClosure *closure)
452{
453  sgtk_protshell *prot = closure->data;
454  g_assert (prot != NULL);
455  return sgtk_get_protect (prot);
456}
457
458GClosure *
459sgtk_new_gclosure (repv obj)
460{
461  sgtk_protshell *prot = sgtk_new_protect (obj);
462  GClosure *closure = g_closure_new_simple (sizeof (GClosure), prot);
463  g_closure_add_finalize_notifier (closure, prot,
464                                   sgtk_gclosure_callback_destroy);
465  g_closure_set_marshal (closure, sgtk_gclosure_callback_marshal);
466  return closure;
467}
468
469GClosure *
470sgtk_gclosure (repv protector, repv obj)
471{
472  GClosure *prot = sgtk_new_gclosure (obj);
473  sgtk_set_gclosure (protector, prot);
474  return prot;
475}
476
477static void
478mark_traced_ref (GObject *obj, void *data)
479{
480  repv p = (repv)get_proxy (obj);
481  if (p != Qnil)
482    {
483      sgtk_object_proxy *proxy = GOBJ_PROXY (p);
484#ifdef DEBUG_PRINT
485      fprintf (stderr, "marking trace %p %s\n",
486               proxy->obj, g_type_name (G_OBJECT_TYPE (proxy->obj)));
487#endif
488      sgtk_mark_protects (proxy->protects);
489    }
490}
491
492static void
493gobj_mark (repv obj)
494{
495  sgtk_object_proxy *proxy = GOBJ_PROXY(obj);
496
497#ifdef DEBUG_PRINT
498  fprintf (stderr, "marking %p %s\n",
499           proxy->obj, g_type_name (G_OBJECT_TYPE (proxy->obj)));
500#endif
501
502  if (GTK_IS_CONTAINER (proxy->obj))
503    gtk_container_foreach (GTK_CONTAINER(proxy->obj),
504                           (GtkCallback) mark_traced_ref, NULL);
505
506  sgtk_mark_protects (proxy->protects);
507}
508
509static void
510gobj_print (repv stream, repv obj)
511{
512    char buf[32];
513  sgtk_object_proxy *proxy = GOBJ_PROXY (obj);
514  GType tid = G_OBJECT_TYPE (proxy->obj);
515  const char *type = g_type_name (tid);
516  rep_stream_puts (stream, "#<", -1, rep_FALSE);
517  rep_stream_puts (stream, type ? (char *) type : "<unknown GObject>", -1, rep_FALSE);
518  rep_stream_puts (stream, " ", -1, rep_FALSE);
519  sprintf (buf, "%lx", (long)proxy->obj);
520  rep_stream_puts (stream, buf, -1, rep_FALSE);
521  rep_stream_putc (stream, '>');
522}
523
524static void
525gobj_free (repv obj)
526{
527  sgtk_object_proxy *proxy = GOBJ_PROXY (obj);
528
529#ifdef DEBUG_PRINT
530  fprintf (stderr, "freeing %p %s\n",
531           proxy->obj, g_type_name (G_OBJECT_TYPE (proxy->obj)));
532#endif
533
534  forget_proxy (proxy->obj);
535  g_object_unref (proxy->obj);
536  sgtk_move_prots_to_global (proxy->protects);
537  rep_FREE_CELL ((char *)proxy);
538}
539
540static void
541gobj_sweep (void)
542{
543  sgtk_object_proxy *proxy = all_proxies;
544  all_proxies = 0;
545  while (proxy != 0)
546  {
547      sgtk_object_proxy *next = proxy->next;
548      if (! rep_GC_CELL_MARKEDP(rep_VAL(proxy)))
549          gobj_free (rep_VAL(proxy));
550      else
551      {
552          rep_GC_CLR_CELL (rep_VAL(proxy));
553          proxy->next = all_proxies;
554          all_proxies = proxy;
555      }
556      proxy = next;
557  }
558}
559
560/* Treating GObject proxies right during GC.  We need to run custom
561   code during the mark phase of the Scheme GC.  We do this by
562   creating a new smob type and allocating one actual smob of it.
563   This smob is made permanent and thus its marking function is
564   invoked for every GC.  We hijack this function to do the tracing of
565   all existing proxies as well. */
566
567static void
568count_traced_ref (GObject *obj, void *data)
569{
570  repv p = (repv)get_proxy (obj);
571  if (p != Qnil)
572    {
573      sgtk_object_proxy *proxy = GOBJ_PROXY (p);
574#ifdef DEBUG_PRINT
575      fprintf (stderr, "counting %p %s\n",
576               proxy->obj, g_type_name (G_OBJECT_TYPE (proxy->obj)));
577#endif
578      proxy->traced_refs++;
579    }
580}
581
582static void
583gobj_marker_hook (void)
584{
585  sgtk_object_proxy *proxy;
586
587  /* We do two passes here.  The first pass counts how many references
588     an object has from other objects that have a proxy.  The second
589     pass marks all objects that have more than this number of
590     references.  For the first pass to work, we need to enumerate all
591     references that an object has to other objects.  We can't do that
592     precisely without help from Gtk+ itself.  But luckily, *not*
593     knowing about an `internal' reference is the conservative thing.
594     Missing a reference will make it appear to us that an object has
595     more `external' references to it than it really has, thus making
596     us keep the proxy alive.  Only when these `external' references
597     form a cycle over some Scheme values, we loose.  As a first
598     approximation to the true set of references of a GtkObject, we
599     just traverse its children with gtk_container_foreach.  */
600
601  /* First pass. */
602  for (proxy = all_proxies; proxy; proxy = proxy->next)
603    {
604      GObject *obj = proxy->obj;
605#ifdef DEBUG_PRINT
606      fprintf (stderr, "on %p %p\n", proxy, obj);
607#endif
608      if (GTK_IS_CONTAINER (obj))
609        gtk_container_foreach (GTK_CONTAINER(obj),
610                               (GtkCallback) count_traced_ref, NULL);
611    }
612#ifdef DEBUG_PRINT
613  fprintf (stderr, "done with pass 1.\n");
614#endif
615
616  /* Second pass. */
617  for (proxy = all_proxies; proxy; proxy = proxy->next)
618    {
619      if (proxy->obj->ref_count > proxy->traced_refs + 1)
620        {
621#ifdef DEBUG_PRINT
622          fprintf (stderr, "hooking %p %s\n",
623                   proxy->obj, g_type_name (G_OBJECT_TYPE (proxy->obj)));
624#endif
625          /* mark the proxy itself */
626          rep_MARKVAL (rep_VAL (proxy));
627        }
628      /* always mark the protected objects, since they're moved to
629         the global_protects list if the object is freed */
630      sgtk_mark_protects (proxy->protects);
631      proxy->traced_refs = 0;
632    }
633  sgtk_mark_protects (global_protects);
634}
635
636/* Create a proxy for OBJ. */
637
638static repv
639make_gobj (GObject *obj)
640{
641  sgtk_object_proxy *proxy;
642
643  g_assert (obj->ref_count > 0);
644
645  proxy = (sgtk_object_proxy *)rep_ALLOC_CELL (sizeof(sgtk_object_proxy));
646  if (GTK_IS_OBJECT (obj))
647    {
648      gtk_object_ref (GTK_OBJECT (obj));
649      gtk_object_sink (GTK_OBJECT (obj));
650    }
651  else
652    g_object_ref (obj);                 /* XXX ref may leak? */
653         
654#ifdef DEBUG_PRINT
655  fprintf (stderr, "New proxy %p for %p %s\n", proxy, obj,
656           g_type_name (G_OBJECT_TYPE (obj)));
657#endif
658  proxy->obj = obj;
659  proxy->protects = NULL;
660  proxy->traced_refs = 0;
661  proxy->next = all_proxies;
662  all_proxies = proxy;
663
664  proxy->car = tc16_gobj;
665  enter_proxy (obj, rep_VAL(proxy));
666
667  return rep_VAL(proxy);
668}
669
670/* Return the proxy for OBJ if it already has one, else create a new
671   one.  When OBJ is NULL, return `#f'. */
672
673repv
674sgtk_wrap_gobj (GObject *obj)
675{
676  repv handle;
677
678  if (obj == NULL)
679    return Qnil;
680
681  handle = get_proxy (obj);
682  if (handle == Qnil)
683    handle = make_gobj (obj);
684  return handle;
685}
686
687int
688sgtk_is_a_gobj (guint type, repv obj)
689{
690  if (!GOBJP (obj) || !G_IS_OBJECT (GOBJ_PROXY(obj)->obj))
691    {
692      return 0;
693    }
694
695  return g_type_is_a (G_OBJECT_TYPE(GOBJ_PROXY(obj)->obj), type);
696}
697
698GObject*
699sgtk_get_gobj (repv obj)
700{
701  if (obj == Qnil)
702    return NULL;
703  else
704    return GOBJ_PROXY(obj)->obj;
705}
706
707/* compat */
708
709repv sgtk_wrap_gtkobj (GtkObject *obj)
710{
711  return sgtk_wrap_gobj (G_OBJECT (obj));
712}
713
714int sgtk_is_a_gtkobj (guint type, repv obj)
715{
716  return sgtk_is_a_gobj (type, obj) && GTK_IS_OBJECT (GOBJ_PROXY (obj)->obj);
717}
718
719GtkObject * sgtk_get_gtkobj (repv obj)
720{
721  return GTK_OBJECT (sgtk_get_gobj (obj));
722}
723
724
725/* Enums.
726
727   Enumerations are described by a `sgtk_enum_info' structure.  That
728   structure contains a list of all literals and their respective
729   values.  In Scheme, an enum element is represented by a symbol
730   whose name is the literal. */
731
732int
733sgtk_valid_enum (repv obj, sgtk_enum_info *info)
734{
735  int i;
736  char *obj_name;
737
738  if (!rep_SYMBOLP (obj))
739    return 0;
740
741  obj_name = rep_STR(rep_SYM(obj)->name);
742  for (i = 0; i < info->n_literals; i++)
743    if (!strcmp (info->literals[i].name, obj_name))
744      return 1;
745  return 0;
746}
747
748repv
749sgtk_enum_to_rep (gint val, sgtk_enum_info *info)
750{
751  int i;
752  for (i = 0; i < info->n_literals; i++)
753    if (info->literals[i].value == val)
754      return Fintern (rep_string_dup(info->literals[i].name), Qnil);
755#if 0
756  /* XXX */
757  SCM_ASSERT (0, SCM_MAKINUM (val), SCM_ARG1, "enum->symbol");
758#endif
759  return Qnil;
760}
761
762gint
763sgtk_rep_to_enum (repv obj, sgtk_enum_info *info)
764{
765  int i;
766  char *obj_name = rep_STR(rep_SYM(obj)->name);
767  for (i = 0; i < info->n_literals; i++)
768    if (!strcmp (info->literals[i].name, obj_name))
769      return info->literals[i].value;
770  return -1;
771}
772
773
774/* Flags.
775
776   Like enums, flags are described by a `sgtk_enum_info' structure.
777   In Scheme, flags are represented by a list of symbols, one for each
778   bit that is set in the flags value. */
779
780int
781sgtk_valid_flags (repv obj, sgtk_enum_info *info)
782{
783  while (obj != Qnil)
784    {
785      int i, valid;
786      repv sym;
787      char *sym_name;
788     
789      if (!rep_CONSP (obj))
790        return 0;
791      sym = rep_CAR (obj);
792      if (!rep_SYMBOLP (sym))
793        return 0;
794     
795      sym_name = rep_STR(rep_SYM(sym)->name);
796      for (i = 0, valid = 0; i < info->n_literals; i++)
797        if (!strcmp (info->literals[i].name, sym_name))
798          {
799            valid = 1;
800            break;
801          }
802      if (!valid)
803        return 0;
804
805      obj = rep_CDR (obj);
806    }
807 
808  return 1;
809}
810
811repv
812sgtk_flags_to_rep (gint val, sgtk_enum_info *info)
813{
814  repv ans = Qnil;
815  int i;
816  for (i = 0; i < info->n_literals; i++)
817    if (val & info->literals[i].value)
818      {
819        ans = Fcons (Fintern (rep_string_dup(info->literals[i].name), Qnil),
820                     ans);
821        val &= ~info->literals[i].value;
822      }
823  return ans;
824}
825
826gint
827sgtk_rep_to_flags (repv obj, sgtk_enum_info *info)
828{
829  int ans = 0;
830
831  while (rep_CONSP(obj) && !rep_INTERRUPTP)
832    {
833      int i;
834      repv sym = rep_CAR (obj);
835      char *sym_name = rep_STR(rep_SYM(sym)->name);
836
837      for (i = 0; i < info->n_literals; i++)
838        if (!strcmp (info->literals[i].name, sym_name))
839          {
840            ans |= info->literals[i].value;
841            break;
842          }
843      obj = rep_CDR (obj);
844      rep_TEST_INT;
845    }
846 
847  return ans;
848}
849
850
851/* String enums.
852
853   A string enum is like an enum, but the values are strings.  The
854   range of values can be extended, so anywhere a "string enum" value
855   is accepted, we also accept a string (but not a symbol).  */
856
857int
858sgtk_valid_senum (repv obj, sgtk_senum_info *info)
859{
860  int i;
861  char *obj_name;
862
863  if (rep_STRINGP (obj))
864    return 1;
865  if (! rep_SYMBOLP (obj))
866    return 0;
867
868  obj_name = rep_STR(rep_SYM(obj)->name);
869  for (i = 0; i < info->n_literals; i++)
870    if (! strcmp (info->literals[i].name, obj_name))
871      return 1;
872  return 0;
873}
874
875repv
876sgtk_senum_to_rep (char *val, sgtk_senum_info *info)
877{
878  int i;
879  for (i = 0; i < info->n_literals; i++)
880    if (! strcmp (info->literals[i].value, val))
881      return Fintern (rep_string_dup(info->literals[i].name), Qnil);
882  return rep_string_dup (val);
883}
884
885char *
886sgtk_rep_to_senum (repv obj, sgtk_senum_info *info)
887{
888  int i;
889  char *obj_name;
890
891  if (rep_STRINGP (obj))
892    return rep_STR (obj);
893
894  obj_name = rep_STR (rep_SYM (obj)->name);
895  for (i = 0; i < info->n_literals; i++)
896    if (! strcmp (info->literals[i].name, obj_name))
897      return info->literals[i].value;
898  return NULL;
899}
900
901
902
903/* Boxed Values.
904
905   I'm trying to use the same hash table approach as with the gobj's,
906   but without such complex gc tracing. I'm hoping that the `opaqueness'
907   of the boxed types preclude any internal pointers..  --jsh
908
909 */
910
911typedef struct _sgtk_boxed_proxy {
912  repv car;
913  struct _sgtk_boxed_proxy *next;
914  GType type;
915  gpointer ptr;
916} sgtk_boxed_proxy;
917
918static sgtk_boxed_proxy *all_boxed;
919
920static long tc16_boxed;
921
922#define BOXED_P(x)     (rep_CELL16_TYPEP(x, tc16_boxed))
923#define BOXED_PROXY(x) ((sgtk_boxed_proxy *)rep_PTR(x))
924#define BOXED_TYPE(x)  (BOXED_PROXY(x)->type)
925#define BOXED_PTR(x)   (BOXED_PROXY(x)->ptr)
926#define BOXED_INFO(x)  ((sgtk_boxed_info*)must_get_type_info(BOXED_TYPE(x)))
927
928static void
929boxed_free (repv obj)
930{
931  sgtk_boxed_info *info = BOXED_INFO (obj);
932  info->destroy (BOXED_PTR (obj));
933  forget_proxy (BOXED_PTR (obj));
934  rep_FREE_CELL (rep_PTR(obj));
935}
936
937static void
938boxed_print (repv stream, repv exp)
939{
940  char buf[32];
941  sgtk_boxed_info *info = BOXED_INFO (exp);
942  rep_stream_puts (stream, "#<", -1, rep_FALSE);
943  rep_stream_puts (stream, info->header.name, -1, rep_FALSE);
944  rep_stream_putc (stream, ' ');
945  sprintf (buf, "%lx", (long)BOXED_PTR (exp));
946  rep_stream_puts (stream, buf, -1, rep_FALSE);
947  rep_stream_putc (stream, '>');
948}
949
950static void
951boxed_sweep (void)
952{
953  sgtk_boxed_proxy *proxy = all_boxed;
954  all_boxed = 0;
955  while (proxy != 0)
956  {
957      sgtk_boxed_proxy *next = proxy->next;
958      if (! rep_GC_CELL_MARKEDP(rep_VAL(proxy)))
959          boxed_free (rep_VAL(proxy));
960      else
961      {
962          rep_GC_CLR_CELL (rep_VAL(proxy));
963          proxy->next = all_boxed;
964          all_boxed = proxy;
965      }
966      proxy = next;
967  }
968}
969
970repv
971sgtk_boxed_to_rep (gpointer ptr, sgtk_boxed_info *info, int copyp)
972{
973  repv handle;
974
975  if (ptr == NULL)
976    return Qnil;
977
978  if (!sgtk_fillin_type_info (&info->header))
979    return Qnil;
980
981  handle = get_proxy (ptr);
982  if (handle == Qnil) {
983      /* Allocate a new proxy */
984      sgtk_boxed_proxy *p = rep_ALLOC_CELL (sizeof (sgtk_boxed_proxy));
985      if (copyp)
986          ptr = info->copy (ptr);
987      p->car = tc16_boxed;
988      p->next = all_boxed;
989      all_boxed = p;
990      p->type = info->header.type;
991      p->ptr = ptr;
992      handle = rep_VAL(p);
993  }
994  return handle;
995}
996
997void *
998sgtk_rep_to_boxed (repv obj)
999{
1000  if (obj == Qnil)
1001    return NULL;
1002  return BOXED_PTR (obj);
1003}
1004
1005int
1006sgtk_valid_boxed (repv obj, sgtk_boxed_info *info)
1007{
1008  return (BOXED_P (obj) && BOXED_INFO (obj) == info);
1009}
1010
1011int
1012sgtk_valid_point (repv obj)
1013{
1014  return (rep_CONSP (obj)
1015          && rep_INTP (rep_CAR (obj))    /* too permissive */
1016          && rep_INTP (rep_CDR (obj)));  /* too permissive */
1017}
1018
1019GdkPoint
1020sgtk_rep_to_point (repv obj)
1021{
1022  GdkPoint res;
1023  res.x = rep_INT (rep_CAR (obj));
1024  res.y = rep_INT (rep_CDR (obj));
1025  return res;
1026}
1027
1028repv
1029sgtk_point_to_rep (GdkPoint p)
1030{
1031  return Fcons (sgtk_int_to_rep (p.x),
1032                sgtk_int_to_rep (p.y));
1033}
1034
1035int
1036sgtk_valid_rect (repv obj)
1037{
1038  return rep_CONSP (obj)
1039    && sgtk_valid_point (rep_CAR (obj))
1040    && sgtk_valid_point (rep_CDR (obj));
1041}
1042
1043GdkRectangle
1044sgtk_rep_to_rect (repv obj)
1045{
1046  GdkRectangle res;
1047  res.x = rep_INT (rep_CAAR (obj));
1048  res.y = rep_INT (rep_CDAR (obj));
1049  res.width = rep_INT (rep_CADR (obj));
1050  res.height = rep_INT (rep_CDDR (obj));
1051  return res;
1052}
1053
1054repv
1055sgtk_rect_to_rep (GdkRectangle r)
1056{
1057  return Fcons (Fcons (rep_MAKE_INT (r.x),
1058                       rep_MAKE_INT (r.y)),
1059                Fcons (rep_MAKE_INT (r.width),
1060                       rep_MAKE_INT (r.height)));
1061}
1062
1063
1064
1065/* GType objects
1066
1067   I'm going to be lazy and try to store these in rep's 30-bit
1068   signed integers, let's see if it works...  --jsh
1069
1070   XXX This does not work. GType are now pointers hidden in
1071       size_t sized integers. (Or special integer values in
1072       the first page.) --owt
1073*/
1074
1075#define GTYPEP(x)     (rep_INTP(x))
1076#define GTYPE(x)      ((GType)rep_INT(x))
1077
1078GType
1079sgtk_type_from_name (char *name)
1080{
1081  GType type = g_type_from_name (name);
1082  if (type == G_TYPE_INVALID)
1083    {
1084      sgtk_object_info *info = sgtk_find_object_info (name);
1085      if (info)
1086        type = info->header.type;
1087    }
1088  return type;
1089}
1090
1091int
1092sgtk_valid_type (repv obj)
1093{
1094  return (obj == Qnil || GTYPEP (obj)
1095          || (rep_SYMBOLP (obj)
1096              && sgtk_type_from_name (rep_STR(rep_SYM(obj)->name))));
1097}
1098
1099GType
1100sgtk_rep_to_type (repv obj)
1101{
1102  if (obj == Qnil)
1103    return G_TYPE_INVALID;
1104  else if (GTYPEP (obj))
1105    return GTYPE (obj);
1106  else {
1107      if (rep_SYMBOLP(obj))
1108          obj = rep_SYM(obj)->name;
1109
1110      if (rep_STRINGP(obj))
1111          return sgtk_type_from_name (rep_STR (obj));
1112      else
1113          return G_TYPE_INVALID;
1114  }
1115}
1116
1117repv
1118sgtk_type_to_rep (GType t)
1119{
1120  if (t == G_TYPE_INVALID)
1121    return Qnil;
1122
1123  assert (t <= rep_LISP_MAX_INT);
1124
1125  return sgtk_uint_to_rep (t);
1126}
1127
1128
1129
1130/* Callbacks.
1131
1132   Callbacks are executed within a new dynamic root.  That means that
1133   the flow of control can't leave them without Gtk noticing.  Throws
1134   are catched and briefly reported.  Calls to continuations that have
1135   been made outside the dynamic root can not be activated.
1136
1137   Callbacks are invoked with whatever arguments that are specified by
1138   the Gtk documentation.  They do not, however, receive the GtkObject
1139   that has initiated the callback.
1140
1141   [ actually, they do receive the GtkObject. For rep, there are no
1142     closures, so without the invoking object it's usually necessary
1143     to build ad hoc closures through backquoting..  --jsh ]
1144
1145   When callback_trampoline is non-#f, we treat it as a procedure and
1146   call it as
1147
1148      (trampoline proc args)
1149
1150   PROC is the real callback procedure and ARGS is the list of
1151   arguments that should be passed to it.  */
1152
1153static repv callback_trampoline;
1154
1155DEFUN ("gtk-callback-trampoline", Fgtk_callback_trampoline,
1156       Sgtk_callback_trampoline, (repv new), rep_Subr1)
1157{
1158  repv old = rep_CAR (callback_trampoline);
1159  if (new != Qnil)
1160    rep_CAR (callback_trampoline) = new;
1161  return old;
1162}
1163
1164struct gclosure_callback_info {
1165  repv proc;
1166  guint n_params;
1167  const GValue *params;
1168  GValue *ret;
1169};
1170
1171static repv
1172inner_gclosure_callback_marshal (repv data)
1173{
1174  struct gclosure_callback_info *info = (struct gclosure_callback_info *) rep_PTR (data);
1175  int i;
1176  repv args = Qnil, ans;
1177
1178  for (i = info->n_params-1; i >= 0; i--)
1179    args = Fcons (sgtk_gvalue_to_rep (info->params+i), args);
1180
1181  if (rep_CAR(callback_trampoline) == Qnil)
1182    ans = rep_apply (info->proc, args);
1183  else
1184    ans = rep_apply (rep_CAR(callback_trampoline),
1185                       Fcons (info->proc, Fcons (args, Qnil)));
1186
1187  if (info->ret != NULL)
1188    sgtk_rep_to_gvalue (info->ret, ans);
1189
1190  return Qnil;
1191}
1192
1193void
1194sgtk_gclosure_callback_marshal (GClosure *closure,
1195                                GValue *return_value,
1196                                guint n_param_values,
1197                                const GValue *param_values,
1198                                gpointer invocation_hint,
1199                                gpointer marshal_data)
1200{
1201  struct gclosure_callback_info info;
1202  sgtk_protshell *prot = closure->data;
1203
1204  if (rep_in_gc)
1205    {
1206      /* This should only happen for the "destroy" signal and is then
1207         harmless. */
1208      fprintf (stderr, "callback ignored during GC!\n");
1209      return;
1210    }
1211 
1212  info.proc = prot->object;
1213  info.n_params = n_param_values;
1214  info.params = param_values;
1215  info.ret = return_value;
1216
1217  rep_call_with_barrier (inner_gclosure_callback_marshal,
1218                         rep_VAL(&info), rep_TRUE, 0, 0, 0);
1219
1220  sgtk_callback_postfix ();
1221}
1222
1223void
1224sgtk_gclosure_callback_destroy (gpointer data, GClosure *closure)
1225{
1226  sgtk_unprotect ((sgtk_protshell *)data);
1227}
1228
1229
1230/* converting between SCM and GValue */
1231
1232repv
1233sgtk_gvalue_to_rep (const GValue *a)
1234{
1235  switch (G_TYPE_FUNDAMENTAL (a->g_type))
1236    {
1237      const char *string;
1238      gpointer pointer;
1239    case G_TYPE_NONE:
1240    case G_TYPE_INVALID:
1241      return Qnil;
1242    case G_TYPE_CHAR:
1243      return rep_MAKE_INT (g_value_get_char (a));
1244    case G_TYPE_BOOLEAN:
1245      return g_value_get_boolean (a) ? Qt : Qnil;
1246    case G_TYPE_INT:
1247      return sgtk_int_to_rep (g_value_get_int (a));
1248    case G_TYPE_UINT:
1249      return sgtk_uint_to_rep (g_value_get_uint (a));
1250    case G_TYPE_LONG:
1251      return sgtk_int_to_rep (g_value_get_long (a));
1252    case G_TYPE_ULONG:
1253      return sgtk_uint_to_rep (g_value_get_ulong (a));
1254    case G_TYPE_FLOAT:
1255      return sgtk_float_to_rep (g_value_get_float (a));
1256    case G_TYPE_DOUBLE:
1257      return sgtk_double_to_rep (g_value_get_double (a));
1258    case G_TYPE_STRING:
1259      string = g_value_get_string (a);
1260      return string != 0 ? rep_string_dup (string) : Qnil;
1261    case G_TYPE_ENUM:
1262      return sgtk_enum_to_rep (g_value_get_enum (a),
1263                               (sgtk_enum_info *)sgtk_find_type_info (a->g_type));
1264    case G_TYPE_FLAGS:
1265      return sgtk_flags_to_rep (g_value_get_flags (a),
1266                                (sgtk_enum_info *)sgtk_find_type_info (a->g_type));
1267    case G_TYPE_BOXED:
1268      pointer = g_value_get_boxed (a);
1269      return (pointer != 0
1270              ? sgtk_boxed_to_rep (pointer, (sgtk_boxed_info *)
1271                                   sgtk_find_type_info (a->g_type), TRUE)
1272              : Qnil);
1273    case G_TYPE_POINTER:
1274      pointer = g_value_get_pointer (a);
1275      return pointer != 0 ? sgtk_pointer_to_rep (pointer) : Qnil;
1276    case G_TYPE_OBJECT:
1277      pointer = g_value_get_object (a);
1278      return pointer != 0 ? sgtk_wrap_gtkobj (pointer) : Qnil;
1279    default:
1280      fprintf (stderr, "illegal type %s in arg\n", g_type_name (a->g_type));
1281      return Qnil;
1282    }
1283}
1284
1285int
1286sgtk_valid_gvalue (const GValue *a, repv obj)
1287{
1288  switch (G_TYPE_FUNDAMENTAL (a->g_type))
1289    {
1290    case G_TYPE_NONE:
1291      return TRUE;
1292    case G_TYPE_CHAR:
1293      return sgtk_valid_char(obj);
1294    case G_TYPE_BOOLEAN:
1295      return TRUE;
1296    case G_TYPE_INT:
1297    case G_TYPE_UINT:
1298    case G_TYPE_LONG:
1299    case G_TYPE_ULONG:
1300      return sgtk_valid_int (obj);
1301    case G_TYPE_FLOAT:
1302    case G_TYPE_DOUBLE:
1303      return sgtk_valid_float (obj);
1304    case G_TYPE_STRING:
1305      return rep_STRINGP (obj);
1306    case G_TYPE_ENUM:
1307      return sgtk_valid_enum (obj, ((sgtk_enum_info *)
1308                                    sgtk_find_type_info (a->g_type)));
1309    case G_TYPE_FLAGS:
1310      return sgtk_valid_flags (obj, ((sgtk_enum_info *)
1311                                     sgtk_find_type_info (a->g_type)));
1312    case G_TYPE_BOXED:
1313      return sgtk_valid_boxed (obj, ((sgtk_boxed_info *)
1314                                     sgtk_find_type_info (a->g_type)));
1315      break;
1316    case G_TYPE_POINTER:
1317      return BOXED_P (obj) || GOBJP (obj) || sgtk_valid_pointer (obj);
1318      break;
1319    case G_TYPE_OBJECT:
1320      return sgtk_is_a_gtkobj (a->g_type, obj);
1321    default:
1322      fprintf (stderr, "unhandled arg type %s\n", g_type_name (a->g_type));
1323      return FALSE;
1324    }
1325}
1326
1327void
1328sgtk_rep_to_gvalue (GValue *a, repv obj)
1329{
1330  switch (G_TYPE_FUNDAMENTAL (a->g_type))
1331    {
1332    case G_TYPE_NONE:
1333      return;
1334    case G_TYPE_CHAR:
1335      g_value_set_char (a, rep_INT (obj));
1336      break;
1337    case G_TYPE_BOOLEAN:
1338      g_value_set_boolean (a, obj != Qnil);
1339      break;
1340    case G_TYPE_INT:
1341      g_value_set_int (a, sgtk_rep_to_int (obj));
1342      break;
1343    case G_TYPE_UINT:
1344      g_value_set_uint (a, sgtk_rep_to_uint (obj));
1345      break;
1346    case G_TYPE_LONG:
1347      g_value_set_long (a, sgtk_rep_to_long (obj));
1348      break;
1349    case G_TYPE_ULONG:
1350      g_value_set_ulong (a, sgtk_rep_to_ulong (obj));
1351      break;
1352    case G_TYPE_FLOAT:
1353      g_value_set_float (a, sgtk_rep_to_float (obj));
1354      break;
1355    case G_TYPE_DOUBLE:
1356      g_value_set_double (a, sgtk_rep_to_double (obj));
1357      break;
1358    case G_TYPE_STRING:
1359      g_value_set_string (a, sgtk_rep_to_string (obj));
1360      break;
1361    case G_TYPE_ENUM:                   /* XXX */
1362      g_value_set_enum (a, sgtk_rep_to_enum (obj, (sgtk_enum_info *)sgtk_find_type_info (a->g_type)));
1363      break;
1364    case G_TYPE_FLAGS:
1365      g_value_set_flags (a, sgtk_rep_to_flags (obj, (sgtk_enum_info *)sgtk_find_type_info (a->g_type)));
1366      break;
1367    case G_TYPE_BOXED:
1368      g_value_set_boxed (a, sgtk_rep_to_boxed (obj));
1369      break;
1370    case G_TYPE_POINTER:
1371      if (BOXED_P (obj))
1372          g_value_set_pointer (a, BOXED_PTR (obj));
1373      else if (GOBJP (obj))
1374          g_value_set_pointer (a, GOBJ_PROXY (obj)->obj);
1375      else
1376          g_value_set_pointer (a, sgtk_rep_to_pointer (obj));
1377      break;
1378    case G_TYPE_OBJECT:
1379      g_value_set_object (a, sgtk_get_gobj (obj));
1380      break;
1381    default:
1382      fprintf (stderr, "unhandled arg type %s\n", g_type_name (a->g_type));
1383      break;
1384    }
1385}
1386
1387
1388
1389/* Type conversions */
1390
1391extern sgtk_boxed_info sgtk_gdk_color_info;
1392
1393repv
1394sgtk_color_conversion (repv color)
1395{
1396  repv orig_color = color;
1397
1398  if (rep_STRINGP (color))
1399    {
1400      GdkColor colstruct;
1401      GdkColormap *colmap;
1402
1403      if (!gdk_color_parse (rep_STR (color), &colstruct))
1404        {
1405          Fsignal (Qerror, rep_list_2 (rep_string_dup ("no such color"),
1406                                       orig_color));
1407          return Qnil;
1408        }
1409      colmap = gtk_widget_peek_colormap ();
1410      if (!gdk_color_alloc (colmap, &colstruct))
1411        {
1412          Fsignal (Qerror, rep_list_2 (rep_string_dup ("can't allocate color"),
1413                                       orig_color));
1414          return Qnil;
1415        }
1416      return sgtk_boxed_to_rep (&colstruct, &sgtk_gdk_color_info, 1);
1417    }
1418  return color;
1419}
1420
1421extern repv Fgdk_fontset_load (repv font);
1422
1423repv
1424sgtk_font_conversion (repv font)
1425{
1426  repv orig_font = font;
1427
1428  if (rep_STRINGP (font))
1429    {
1430      font = Fgdk_fontset_load (font);
1431      if (font == Qnil)
1432        Fsignal (Qerror, rep_list_2 (rep_string_dup ("no such font: "),
1433                                     orig_font));
1434    }
1435  return font;
1436}
1437
1438
1439#ifndef NO_GTK1_COMPAT_CODE
1440
1441/* converting between SCM and GtkArg */
1442
1443repv
1444sgtk_arg_to_rep (GtkArg *a, int free_mem)
1445{
1446  if (GTK_TYPE_IS_OBJECT (a->type))
1447  {
1448    return sgtk_wrap_gtkobj (GTK_VALUE_OBJECT(*a));
1449  }
1450
1451  switch (GTK_FUNDAMENTAL_TYPE (a->type))
1452    {
1453    case GTK_TYPE_NONE:
1454      return Qnil;
1455    case GTK_TYPE_CHAR:
1456      return rep_MAKE_INT (GTK_VALUE_CHAR(*a));
1457    case GTK_TYPE_BOOL:
1458      return GTK_VALUE_BOOL(*a)? Qt : Qnil;
1459    case GTK_TYPE_INT:
1460      return sgtk_int_to_rep (GTK_VALUE_INT(*a));
1461    case GTK_TYPE_UINT:
1462      return sgtk_uint_to_rep (GTK_VALUE_UINT(*a));
1463    case GTK_TYPE_LONG:
1464      return sgtk_int_to_rep (GTK_VALUE_LONG(*a));
1465    case GTK_TYPE_ULONG:
1466      return sgtk_uint_to_rep (GTK_VALUE_ULONG(*a));
1467    case GTK_TYPE_FLOAT:
1468      return sgtk_float_to_rep (GTK_VALUE_FLOAT(*a));
1469    case GTK_TYPE_DOUBLE:
1470      return sgtk_double_to_rep (GTK_VALUE_DOUBLE(*a));
1471    case GTK_TYPE_STRING:
1472      {
1473        repv ret = rep_string_dup (GTK_VALUE_STRING(*a));
1474        if (free_mem)
1475          g_free GTK_VALUE_STRING(*a);
1476        return ret;
1477      }
1478    case GTK_TYPE_ENUM:
1479      return sgtk_enum_to_rep (GTK_VALUE_FLAGS(*a),
1480                               (sgtk_enum_info *)sgtk_find_type_info (a->type));
1481    case GTK_TYPE_FLAGS:
1482      return sgtk_flags_to_rep (GTK_VALUE_FLAGS(*a),
1483                                (sgtk_enum_info *)sgtk_find_type_info (a->type));
1484    case GTK_TYPE_BOXED:
1485      return sgtk_boxed_to_rep (GTK_VALUE_BOXED(*a),
1486                                (sgtk_boxed_info *)sgtk_find_type_info (a->type),
1487                                TRUE);
1488    case GTK_TYPE_POINTER:
1489      return sgtk_pointer_to_rep (GTK_VALUE_POINTER(*a));
1490    default:
1491      fprintf (stderr, "illegal type %s in arg\n",
1492               gtk_type_name (a->type));
1493      return Qnil;
1494    }
1495}
1496
1497int
1498sgtk_valid_arg_type (GType type, repv obj)
1499{
1500  if (GTK_TYPE_IS_OBJECT (type))
1501  {
1502    return sgtk_is_a_gtkobj (type, obj);
1503  }
1504  switch (GTK_FUNDAMENTAL_TYPE (type))
1505    {
1506    case GTK_TYPE_NONE:
1507      return TRUE;
1508    case GTK_TYPE_CHAR:
1509      return sgtk_valid_char(obj);
1510    case GTK_TYPE_BOOL:
1511      return TRUE;
1512    case GTK_TYPE_INT:
1513    case GTK_TYPE_UINT:
1514    case GTK_TYPE_LONG:
1515    case GTK_TYPE_ULONG:
1516      return sgtk_valid_int (obj);
1517    case GTK_TYPE_FLOAT:
1518    case GTK_TYPE_DOUBLE:
1519      return sgtk_valid_float (obj);
1520    case GTK_TYPE_STRING:
1521      return rep_STRINGP (obj);
1522    case GTK_TYPE_ENUM:
1523      return sgtk_valid_enum (obj, ((sgtk_enum_info *)
1524                                    sgtk_find_type_info (type)));
1525    case GTK_TYPE_FLAGS:
1526      return sgtk_valid_flags (obj, ((sgtk_enum_info *)
1527                                     sgtk_find_type_info (type)));
1528    case GTK_TYPE_BOXED:
1529      return sgtk_valid_boxed (obj, ((sgtk_boxed_info *)
1530                                     sgtk_find_type_info (type)));
1531      break;
1532    case GTK_TYPE_POINTER:
1533      return BOXED_P (obj) || GOBJP (obj) || sgtk_valid_pointer (obj);
1534      break;
1535    default:
1536      fprintf (stderr, "unhandled arg type %s\n", gtk_type_name (type));
1537      return FALSE;
1538    }
1539}
1540
1541void
1542sgtk_rep_to_arg (GtkArg *a, repv obj, repv protector)
1543{
1544  if (GTK_TYPE_IS_OBJECT (a->type))
1545  {
1546    GTK_VALUE_OBJECT(*a) = sgtk_get_gtkobj (obj);
1547    return;
1548  }
1549  switch (GTK_FUNDAMENTAL_TYPE (a->type))
1550    {
1551    case GTK_TYPE_NONE:
1552      return;
1553    case GTK_TYPE_CHAR:
1554      GTK_VALUE_CHAR(*a) = rep_INT (obj);
1555      break;
1556    case GTK_TYPE_BOOL:
1557      GTK_VALUE_BOOL(*a) = obj != Qnil;
1558      break;
1559    case GTK_TYPE_INT:
1560      GTK_VALUE_INT(*a) = sgtk_rep_to_int (obj);
1561      break;
1562    case GTK_TYPE_UINT:
1563      GTK_VALUE_UINT(*a) = sgtk_rep_to_uint (obj);
1564      break;
1565    case GTK_TYPE_LONG:
1566      GTK_VALUE_LONG(*a) = sgtk_rep_to_long (obj);
1567      break;
1568    case GTK_TYPE_ULONG:
1569      GTK_VALUE_ULONG(*a) = sgtk_rep_to_ulong (obj);
1570      break;
1571    case GTK_TYPE_FLOAT:
1572      GTK_VALUE_FLOAT(*a) = sgtk_rep_to_float (obj);
1573      break;
1574    case GTK_TYPE_DOUBLE:
1575      GTK_VALUE_DOUBLE(*a) = sgtk_rep_to_double (obj);
1576      break;
1577    case GTK_TYPE_STRING:
1578      GTK_VALUE_STRING(*a) = sgtk_rep_to_string (obj);
1579      break;
1580    case GTK_TYPE_ENUM:
1581      GTK_VALUE_ENUM(*a) =
1582        sgtk_rep_to_enum (obj, (sgtk_enum_info *)sgtk_find_type_info (a->type));
1583      break;
1584    case GTK_TYPE_FLAGS:
1585      GTK_VALUE_ENUM(*a) =
1586        sgtk_rep_to_flags (obj, (sgtk_enum_info *)sgtk_find_type_info (a->type));
1587      break;
1588    case GTK_TYPE_BOXED:
1589      GTK_VALUE_BOXED(*a) = sgtk_rep_to_boxed (obj);
1590      break;
1591    case GTK_TYPE_POINTER:
1592      if (BOXED_P (obj))
1593          GTK_VALUE_POINTER(*a) = BOXED_PTR (obj);
1594      else if (GOBJP (obj))
1595          GTK_VALUE_POINTER(*a) = GOBJ_PROXY (obj)->obj;
1596      else
1597          GTK_VALUE_POINTER(*a) = sgtk_rep_to_pointer (obj);
1598      break;
1599    default:
1600      fprintf (stderr, "unhandled arg type %s\n", gtk_type_name (a->type));
1601      break;
1602    }
1603}
1604
1605void
1606sgtk_rep_to_ret (GtkArg *a, repv obj)
1607{
1608  if (GTK_TYPE_IS_OBJECT (a->type))
1609  {
1610    if (sgtk_is_a_gtkobj (a->type, obj))
1611      *GTK_RETLOC_OBJECT(*a) = sgtk_get_gtkobj (obj);
1612    else
1613      *GTK_RETLOC_OBJECT(*a) = NULL;
1614    return;
1615  }
1616  switch (GTK_FUNDAMENTAL_TYPE (a->type))
1617    {
1618    case GTK_TYPE_NONE:
1619      return;
1620    case GTK_TYPE_CHAR:
1621      *GTK_RETLOC_CHAR(*a) = rep_INT (obj);
1622      break;
1623    case GTK_TYPE_BOOL:
1624      *GTK_RETLOC_BOOL(*a) = (obj != Qnil);
1625      break;
1626    case GTK_TYPE_INT:
1627      *GTK_RETLOC_INT(*a) = sgtk_rep_to_int (obj);
1628      break;
1629    case GTK_TYPE_UINT:
1630      *GTK_RETLOC_UINT(*a) = sgtk_rep_to_uint (obj);
1631      break;
1632    case GTK_TYPE_LONG:
1633      *GTK_RETLOC_LONG(*a) = sgtk_rep_to_long (obj);
1634      break;
1635    case GTK_TYPE_ULONG:
1636      *GTK_RETLOC_ULONG(*a) = sgtk_rep_to_ulong (obj);
1637      break;
1638    case GTK_TYPE_FLOAT:
1639      *GTK_RETLOC_FLOAT(*a) = sgtk_rep_to_float (obj);
1640      break;
1641    case GTK_TYPE_DOUBLE:
1642      *GTK_RETLOC_DOUBLE(*a) = sgtk_rep_to_double (obj);
1643      break;
1644    case GTK_TYPE_STRING:
1645      GTK_VALUE_STRING(*a) = g_strdup (rep_STR(obj));
1646      break;
1647    case GTK_TYPE_ENUM:
1648      *GTK_RETLOC_ENUM(*a) =
1649        sgtk_rep_to_enum (obj, (sgtk_enum_info *)sgtk_find_type_info (a->type));
1650      break;
1651    case GTK_TYPE_FLAGS:
1652      *GTK_RETLOC_ENUM(*a) =
1653        sgtk_rep_to_flags (obj, (sgtk_enum_info *)sgtk_find_type_info (a->type));
1654      break;
1655    case GTK_TYPE_BOXED:
1656      *GTK_RETLOC_BOXED(*a) = sgtk_rep_to_boxed (obj);
1657      break;
1658    default:
1659      fprintf (stderr, "unhandled return type %s\n", gtk_type_name (a->type));
1660      break;
1661    }
1662}
1663
1664
1665/* Old callback style */
1666
1667struct callback_info {
1668  GtkObject *obj;
1669  repv proc;
1670  gint n_args;
1671  GtkArg *args;
1672};
1673
1674static repv
1675inner_callback_marshal (repv data)
1676{
1677  struct callback_info *info = (struct callback_info *) rep_PTR (data);
1678  int i;
1679  repv args = Qnil, ans;
1680
1681  for (i = info->n_args-1; i >= 0; i--)
1682    args = Fcons (sgtk_arg_to_rep (info->args+i, 0), args);
1683  args = Fcons (sgtk_wrap_gtkobj (info->obj), args);
1684
1685  if (rep_CAR(callback_trampoline) == Qnil)
1686    ans = rep_apply (info->proc, args);
1687  else
1688    ans = rep_apply (rep_CAR(callback_trampoline),
1689                       Fcons (info->proc, Fcons (args, Qnil)));
1690
1691  if (info->args[info->n_args].type != GTK_TYPE_NONE)
1692    sgtk_rep_to_ret (info->args+info->n_args, ans);
1693
1694  return Qnil;
1695}
1696
1697void
1698sgtk_callback_marshal (GtkObject *obj,
1699                       gpointer data,
1700                       guint n_args,
1701                       GtkArg *args)
1702{
1703  struct callback_info info;
1704
1705  if (rep_in_gc)
1706    {
1707      /* This should only happen for the "destroy" signal and is then
1708         harmless. */
1709      fprintf (stderr, "callback ignored during GC!\n");
1710      return;
1711    }
1712 
1713  info.obj = obj;
1714  info.proc = ((sgtk_protshell *)data)->object;
1715  info.n_args = n_args;
1716  info.args = args;
1717
1718  rep_call_with_barrier (inner_callback_marshal,
1719                         rep_VAL(&info), rep_TRUE, 0, 0, 0);
1720
1721  sgtk_callback_postfix ();
1722}
1723
1724void
1725sgtk_callback_destroy (gpointer data)
1726{
1727  sgtk_unprotect ((sgtk_protshell *)data);
1728}
1729
1730#endif /* NO_GTK1_COMPAT_CODE */
1731
1732
1733/* Support for g_object_new, g_object_set, ... */
1734
1735/* The SCM_PROC for the exported functions is in gtk-support.c to have
1736   it be snarfed for sgtk_init_gtk_support. */
1737
1738sgtk_object_info *
1739sgtk_find_object_info_from_type (GType type)
1740{
1741  sgtk_object_info *info;
1742  if (type == G_TYPE_INVALID)
1743    return NULL;
1744  info = (sgtk_object_info *)sgtk_get_type_info (type);
1745  if (info)
1746    return info;
1747 
1748  return sgtk_find_object_info (g_type_name (type));
1749}
1750
1751sgtk_object_info *
1752sgtk_find_object_info (const char *name)
1753{
1754  GType type, parent;
1755  sgtk_object_info *info;
1756  type_infos *infos;
1757
1758  type = g_type_from_name (name);
1759  if (type != G_TYPE_INVALID)
1760    {
1761      info = (sgtk_object_info *)sgtk_get_type_info (type);
1762      if (info)
1763        return info;
1764    }
1765
1766  for (infos = all_type_infos; infos; infos = infos->next)
1767    {
1768      sgtk_type_info **ip;
1769      for (ip = infos->infos; *ip; ip++)
1770        if (!strcmp ((*ip)->name, name))
1771          {
1772            if (!G_TYPE_IS_OBJECT ((*ip)->type))
1773              return NULL;
1774
1775            info = (sgtk_object_info *)*ip;
1776            info->header.type = (info->init_func
1777                                 ? info->init_func () : G_TYPE_OBJECT);
1778            enter_type_info ((sgtk_type_info*)info);
1779            goto query_args;
1780          }
1781    }
1782
1783  /* Not found among our precompiled types.  Construct a fresh
1784     sgtk_object_info, if it's known to Gtk+. */
1785
1786  if (type != G_TYPE_INVALID)
1787    {
1788      fprintf (stderr, "Fresh info for %s, %lu\n", name, (gulong)type);
1789
1790      info = (sgtk_object_info *)rep_alloc (sizeof(sgtk_object_info));
1791      info->header.type = type;
1792      info->header.name = (char *) name;
1793      info->init_func = NULL;
1794      enter_type_info ((sgtk_type_info*)info);
1795    }
1796  else
1797    return NULL;
1798
1799 query_args:
1800  g_type_class_peek (info->header.type);
1801 
1802  parent = g_type_parent (info->header.type);
1803  if (parent != G_TYPE_INVALID)
1804    info->parent = sgtk_find_object_info_from_type (parent);
1805  else
1806    info->parent = NULL;
1807 
1808  return info;
1809}
1810
1811void
1812sgtk_free_args (GParameter *args, int n_args)
1813{
1814  int i;
1815
1816  for (i = 0; i < n_args; i++)
1817    g_value_unset (&args[i].value);
1818
1819  g_free (args);
1820}
1821
1822GParameter *
1823sgtk_build_args (GObjectClass *objclass, int *n_argsp, repv scm_args, char *subr)
1824{
1825  int i, n_args = *n_argsp;
1826  GParameter *args;
1827  GParamSpec *pspec;
1828  repv kw, val;
1829  sgtk_type_info *type_info;
1830
1831  args = g_new0 (GParameter, n_args);
1832
1833  for (i = 0; i < n_args; i++)
1834    {
1835      kw = rep_CAR (scm_args);
1836      val = rep_CADR (scm_args);
1837      scm_args = rep_CDDR (scm_args);
1838
1839      if (rep_SYMBOLP (kw))
1840        args[i].name = rep_STR(rep_SYM(kw)->name);
1841      else
1842        {
1843          fprintf (stderr, "bad keyword\n");
1844          n_args -= 1;
1845          i -= 1;
1846          continue;
1847        }
1848
1849      pspec = g_object_class_find_property (objclass, args[i].name);
1850      if (!pspec)
1851        {
1852          fprintf (stderr, "no such arg for type `%s': %s\n",
1853                   g_type_name (G_OBJECT_CLASS_TYPE (objclass)), args[i].name);
1854          n_args -= 1;
1855          i -= 1;
1856          continue;
1857        }
1858
1859      /* XXX - rethink type info business.  Avoid double lookups. */
1860
1861      type_info = sgtk_maybe_find_type_info (G_PARAM_SPEC_VALUE_TYPE (pspec));
1862      if (type_info && type_info->conversion)
1863        val = type_info->conversion (val);
1864
1865      g_value_init (&args[i].value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1866
1867      if (!sgtk_valid_gvalue (&args[i].value, val))
1868        {
1869          repv throw_args =
1870            rep_LIST_3 (rep_string_dup ("wrong type for"),
1871                        rep_string_dup (g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec))), val);
1872          sgtk_free_args (args, i);
1873          Fsignal (Qerror, throw_args);
1874        }
1875         
1876      sgtk_rep_to_gvalue (&args[i].value, val);
1877    }
1878
1879  *n_argsp = n_args;
1880  return args;
1881}
1882
1883DEFUN("g-object-new", Fg_object_new, Sg_object_new, (repv scm_args), rep_SubrN)
1884{
1885  repv type_obj;
1886  int n_args;
1887  sgtk_object_info *info;
1888  GParameter *args;
1889  GObjectClass *objclass;
1890  GObject *obj;
1891  repv scm_obj;
1892
1893  if (!rep_CONSP (scm_args))
1894    return rep_signal_missing_arg (1);
1895
1896  type_obj = rep_CAR (scm_args);
1897  scm_args = rep_CDR (scm_args);
1898
1899  rep_DECLARE (1, type_obj, type_obj != Qnil && sgtk_valid_type (type_obj));
1900  n_args = list_length (scm_args);
1901  rep_DECLARE (2, scm_args, n_args >= 0 && (n_args%2) == 0);
1902  n_args = n_args/2;
1903
1904  info = sgtk_find_object_info_from_type (sgtk_rep_to_type (type_obj));
1905  if (info == 0)
1906      return Qnil;
1907
1908  objclass = g_type_class_ref (info->header.type);
1909  args = sgtk_build_args (objclass, &n_args, scm_args, "gtk-object-new");
1910  obj = g_object_newv (info->header.type, n_args, args);
1911  scm_obj = sgtk_wrap_gobj (obj);
1912  sgtk_free_args (args, n_args);
1913  g_type_class_unref (objclass);
1914
1915  return scm_obj;
1916}
1917
1918DEFUN("g-object-set", Fg_object_set, Sg_object_set, (repv scm_args), rep_SubrN)
1919{
1920  repv scm_obj;
1921  int n_args, i;
1922  GParameter *args;
1923  GObject *obj;
1924  GObjectClass *objclass;
1925
1926  if (!rep_CONSP (scm_args))
1927    return rep_signal_missing_arg (1);
1928
1929  scm_obj = rep_CAR (scm_args);
1930  scm_args = rep_CDR (scm_args);
1931
1932  rep_DECLARE (1, scm_obj, GOBJP(scm_obj));
1933  n_args = list_length (scm_args);
1934  rep_DECLARE (2, scm_args, n_args >= 0 && (n_args%2) == 0);
1935  n_args = n_args/2;
1936
1937  obj = GOBJ_PROXY(scm_obj)->obj;
1938
1939  args = sgtk_build_args (G_OBJECT_GET_CLASS (obj),
1940                          &n_args, scm_args, "g-object-set");
1941  for (i = 0; i < n_args; i++)
1942    g_object_set_property (obj, args[i].name, &args[i].value);
1943  sgtk_free_args (args, n_args);
1944
1945  return Qnil;
1946}
1947
1948DEFUN ("g-object-get", Fg_object_get, Sg_object_get,
1949       (repv scm_obj, repv argsym), rep_Subr2)
1950{
1951  GObject *obj;
1952  char *name;
1953  GParamSpec *pspec;
1954  GValue value = {0,};
1955  repv ans;
1956
1957  rep_DECLARE (1, scm_obj, GOBJP(scm_obj));
1958  rep_DECLARE (2, argsym, rep_SYMBOLP(argsym));
1959
1960  obj = GOBJ_PROXY(scm_obj)->obj;
1961
1962  name = rep_STR(rep_SYM(argsym)->name);
1963  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), name);
1964 
1965  if (pspec)
1966    {
1967      g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1968      g_object_get_property (obj, name, &value);
1969
1970      ans = sgtk_gvalue_to_rep (&value);
1971
1972      g_value_unset (&value);
1973
1974      return ans;
1975    }
1976  else
1977    return Qnil;
1978}
1979
1980DEFUN ("g-object-list", Fg_object_list,
1981       Sg_object_list, (repv scm_obj), rep_Subr1)
1982{
1983  GObject *obj;
1984  GParamSpec **props;
1985  int nprops;
1986  GValue value = {0,};
1987
1988  rep_DECLARE (1, scm_obj, GOBJP(scm_obj));
1989
1990  obj = GOBJ_PROXY(scm_obj)->obj;
1991
1992  props = g_object_class_list_properties (G_OBJECT_GET_CLASS (obj), &nprops);
1993 
1994  if (props != 0)
1995    {
1996      int i;
1997      repv lst = Qnil;
1998      for (i = 0; i < nprops; i++)
1999        {
2000          if (props[i]->name != 0)
2001            lst = Fcons (Fintern (rep_string_dup (props[i]->name), Qnil), lst);
2002        }
2003      g_free (props);
2004      return Fnreverse (lst);
2005    }
2006  else
2007    return Qnil;
2008}
2009
2010
2011#ifndef NO_GTK1_COMPAT_CODE
2012
2013/* Creating new object classes */
2014
2015GtkType
2016gtk_class_new (GtkType parent_type, gchar *name)
2017{
2018  GtkTypeInfo info = { 0 };
2019  GtkTypeInfo parent_info;
2020
2021  if (!gtk_type_get_info (parent_type, &parent_info))
2022    return GTK_TYPE_INVALID;
2023
2024  info.type_name = name;
2025  info.object_size = parent_info.object_size;
2026  info.class_size = parent_info.class_size;
2027  info.class_init_func = NULL;
2028  info.object_init_func = NULL;
2029#if GTK_MAJOR_VERSION > 1 || GTK_MINOR_VERSION > 0
2030  info.base_class_init_func = NULL;
2031#endif
2032
2033  return gtk_type_unique (parent_type, &info);
2034}
2035
2036guint
2037gtk_signal_new_generic (const gchar     *name,
2038                        GtkSignalRunType signal_flags,
2039                        GtkType          type,
2040                        GtkType          return_type,
2041                        guint            nparams,
2042                        GtkType         *params)
2043{
2044  guint signal_id;
2045
2046  if (!GTK_TYPE_IS_OBJECT (type))
2047    return 0;
2048
2049  signal_id = gtk_signal_newv (name, signal_flags, type,
2050                               0, NULL,
2051                               return_type, nparams, params);
2052
2053  return signal_id;
2054}
2055
2056void
2057sgtk_signal_emit (GtkObject *obj, char *name, repv scm_args)
2058{
2059  GSignalQuery info;
2060  guint signal_id, i;
2061  GtkArg *args;
2062
2063  signal_id = g_signal_lookup (name, GTK_OBJECT_TYPE (obj));
2064  if (signal_id == 0)
2065    {
2066      Fsignal (Qerror, rep_list_2 (rep_string_dup ("no such signal"),
2067                                   rep_string_dup (name)));
2068      return;
2069    }
2070
2071  g_signal_query (signal_id, &info);
2072  if (!rep_CONSP(scm_args) || list_length (scm_args) != info.n_params)
2073    {
2074      Fsignal (Qerror, Fcons (rep_string_dup ("wrong number of signal arguments"), Qnil));
2075      return;
2076    }
2077
2078  args = g_new (GtkArg, info.n_params+1);
2079  i = 0;
2080  while (rep_CONSP (scm_args))
2081    {
2082      args[i].name = NULL;
2083      args[i].type = info.param_types[i];
2084
2085      if (!sgtk_valid_arg_type (args[i].type, rep_CAR (scm_args)))
2086        {
2087          repv throw_args =
2088            rep_LIST_3 (rep_string_dup ("wrong type for"),
2089                        rep_string_dup (gtk_type_name (args[i].type)),
2090                        rep_CAR (scm_args));
2091          g_free (args);
2092          Fsignal (Qerror, throw_args);
2093          return;
2094        }
2095
2096      sgtk_rep_to_arg (&args[i], rep_CAR(scm_args), Qt);
2097      i++;
2098      scm_args = rep_CDR (scm_args);
2099    }
2100  args[i].type = GTK_TYPE_NONE;
2101
2102  gtk_signal_emitv (obj, signal_id, args);
2103
2104  g_free (args);
2105}
2106
2107#endif /* NO_GTK1_COMPAT_CODE */
2108
2109
2110/* Support rep input handling through gtk_main */
2111
2112/* The input_tags table hashes fds to gdk tags; the input_callbacks
2113   table hashes fds to rep callback function. These should be a single
2114   table really.. */
2115static GHashTable *input_tags, *input_callbacks;
2116
2117struct input_callback_data {
2118    void (*func)(int);
2119    int fd;
2120};
2121
2122struct timeout_data {
2123    struct timeout_data *next;
2124    int timed_out;
2125    int idle_counter;
2126    u_long this_timeout_msecs;
2127    u_long actual_timeout_msecs;
2128    int gtk_tag;
2129};
2130
2131static struct timeout_data *context;
2132
2133static repv
2134inner_input_callback (repv data_)
2135{
2136    struct input_callback_data *data
2137        = (struct input_callback_data *) rep_PTR (data_);
2138    (*data->func) (data->fd);
2139    return Qnil;
2140}
2141
2142static void
2143sgtk_input_callback (gpointer data, gint fd, GdkInputCondition cond)
2144{
2145    struct input_callback_data d;
2146    d.func = g_hash_table_lookup (input_callbacks, GINT_TO_POINTER (fd));
2147    d.fd = fd;
2148    if (d.func != 0)
2149    {
2150        rep_call_with_barrier (inner_input_callback, rep_VAL(&d),
2151                               rep_TRUE, 0, 0, 0);
2152    }
2153    sgtk_callback_postfix ();
2154}
2155
2156static void
2157sgtk_register_input_fd (int fd, void (*callback)(int fd))
2158{
2159    if (callback != 0)
2160    {
2161        int tag;
2162        if (input_tags == 0)
2163        {
2164            input_tags = g_hash_table_new (NULL, NULL);
2165            input_callbacks = g_hash_table_new (NULL, NULL);
2166        }
2167        tag = gdk_input_add (fd, GDK_INPUT_READ,
2168                             (GdkInputFunction) sgtk_input_callback, 0);
2169        g_hash_table_insert (input_tags, GINT_TO_POINTER (fd), GINT_TO_POINTER (tag));
2170        g_hash_table_insert (input_callbacks,
2171                             GINT_TO_POINTER (fd), (gpointer) callback);
2172    }
2173}
2174
2175static void
2176sgtk_deregister_input_fd (int fd)
2177{
2178    if (input_tags != 0)
2179    {
2180        int tag = GPOINTER_TO_INT (g_hash_table_lookup (input_tags, GINT_TO_POINTER (fd)));
2181        gdk_input_remove (tag);
2182        g_hash_table_remove (input_tags, GINT_TO_POINTER (fd));
2183        g_hash_table_remove (input_callbacks, GINT_TO_POINTER (fd));
2184    }
2185}
2186
2187static gboolean
2188timeout_callback (gpointer data)
2189{
2190    struct timeout_data *d = data;
2191
2192    d->gtk_tag = 0;
2193    d->timed_out = 1;
2194
2195    /* Only quit if we'd return to the correct event loop */
2196    if (context == d)
2197        gtk_main_quit ();
2198
2199    return FALSE;
2200}
2201
2202static void
2203unset_timeout (void)
2204{
2205    if (context != 0)
2206    {
2207        if (context->gtk_tag != 0)
2208            gtk_timeout_remove (context->gtk_tag);
2209        context->gtk_tag = 0;
2210    }
2211}
2212
2213static void
2214set_timeout (void)
2215{
2216    if (context != 0 && !context->timed_out && !context->gtk_tag)
2217    {
2218        u_long max_sleep = rep_max_sleep_for ();
2219        context->this_timeout_msecs = rep_input_timeout_secs * 1000;
2220        context->actual_timeout_msecs = MIN (context->this_timeout_msecs,
2221                                             max_sleep);
2222        context->gtk_tag = gtk_timeout_add (context->actual_timeout_msecs,
2223                                            timeout_callback,
2224                                            (gpointer) context);
2225    }
2226}
2227
2228/* Call this after executing any callbacks that could invoke Lisp code */
2229void
2230sgtk_callback_postfix (void)
2231{
2232    unset_timeout ();
2233    if (rep_INTERRUPTP && gtk_main_level () > 0)
2234        gtk_main_quit ();
2235    else if (rep_redisplay_fun != 0)
2236        (*rep_redisplay_fun)();
2237    if (context != 0)
2238    {
2239        context->timed_out = 0;
2240        set_timeout ();
2241        context->idle_counter = 0;
2242    }
2243}
2244
2245/* This function replaces the standard rep event loop. */
2246static repv
2247sgtk_event_loop (void)
2248{
2249    struct timeout_data data;
2250
2251    data.idle_counter = 0;
2252    data.gtk_tag = 0;
2253    data.next = context;
2254    context = &data;
2255
2256    while (1)
2257    {
2258        u_long max_sleep = rep_max_sleep_for ();
2259
2260        if (rep_redisplay_fun != 0)
2261            (*rep_redisplay_fun)();
2262
2263        if (max_sleep == 0)
2264        {
2265            while (gtk_events_pending ())
2266                gtk_main_iteration_do (FALSE);
2267            Fthread_yield ();
2268        }
2269        else
2270        {
2271            data.timed_out = 0;
2272            set_timeout ();
2273            gtk_main ();
2274            unset_timeout ();
2275            if (data.timed_out)
2276            {
2277                if (data.actual_timeout_msecs < data.this_timeout_msecs)
2278                {
2279                    Fthread_suspend (Qnil, rep_MAKE_INT (data.this_timeout_msecs
2280                                                         - data.actual_timeout_msecs));
2281                }
2282                else
2283                    rep_on_idle (data.idle_counter++);
2284            }
2285        }
2286
2287        rep_proc_periodically ();
2288
2289        /* Check for exceptional conditions. */
2290        if(rep_throw_value != rep_NULL)
2291        {
2292            repv result;
2293            if(rep_handle_input_exception (&result))
2294            {
2295                context = data.next;
2296                /* reset the timeout for any containing event loop */
2297                set_timeout ();
2298                return result;
2299            }
2300        }
2301
2302#ifdef C_ALLOCA
2303        /* Using the C implementation of alloca. So garbage collect
2304           anything below the current stack depth. */
2305        alloca(0);
2306#endif
2307    }
2308}
2309
2310/* Called by librep/src/unix_processes.c whenever SIGCHLD is received
2311   (from the signal handler) */
2312static void
2313sgtk_sigchld_callback (void)
2314{
2315    /* XXX I'm hoping that this is safe to call from a signal handler... */
2316
2317    if (gtk_main_level () > 0)
2318        gtk_main_quit ();
2319}
2320
2321
2322
2323/* Initialization */
2324
2325static int standalone_p = 1;
2326
2327void
2328sgtk_set_standalone (int flag)
2329{
2330  standalone_p = flag;
2331}
2332
2333int
2334sgtk_is_standalone (void)
2335{
2336  return standalone_p;
2337}
2338
2339DEFUN ("gtk-standalone-p", Fgtk_standalone_p,
2340       Sgtk_standalone_p, (void), rep_Subr0)
2341{
2342  return standalone_p ? Qt : Qnil;
2343}
2344
2345DEFSYM (gtk_major_version, "gtk-major-version");
2346DEFSYM (gtk_minor_version, "gtk-minor-version");
2347DEFSYM (gtk_micro_version, "gtk-micro-version");
2348DEFSYM (rep_gtk_version, "rep-gtk-version");
2349
2350static void
2351sgtk_init_substrate (void)
2352{
2353  DEFSTRING (ver, REP_GTK_VERSION);
2354
2355  tc16_gobj = rep_register_new_type ("g-object", 0,
2356                                     gobj_print, gobj_print,
2357                                     gobj_sweep, gobj_mark,
2358                                     gobj_marker_hook,
2359                                     0, 0, 0, 0, 0, 0);
2360
2361  tc16_boxed = rep_register_new_type ("gtk-boxed", 0,
2362                                      boxed_print, boxed_print,
2363                                      boxed_sweep, 0, 0,
2364                                      0, 0, 0, 0, 0, 0);
2365
2366  global_protects = NULL;
2367  sgtk_protshell_chunk = g_mem_chunk_create (sgtk_protshell, 128,
2368                                             G_ALLOC_AND_FREE);
2369 
2370  callback_trampoline = Fcons (Qnil, Qnil);
2371  rep_mark_static (&callback_trampoline);
2372
2373  rep_register_input_fd_fun = sgtk_register_input_fd;
2374  rep_deregister_input_fd_fun = sgtk_deregister_input_fd;
2375  rep_map_inputs (sgtk_register_input_fd);
2376  rep_event_loop_fun = sgtk_event_loop;
2377  rep_sigchld_fun = sgtk_sigchld_callback;
2378
2379  /* Need this in case sit-for is called. */
2380  if (GDK_DISPLAY () != 0)
2381      rep_register_input_fd (ConnectionNumber (GDK_DISPLAY ()), 0);
2382
2383  rep_ADD_SUBR (Sgtk_callback_trampoline);
2384  rep_ADD_SUBR (Sgtk_standalone_p);
2385  rep_INTERN (gtk_major_version);
2386  rep_INTERN (gtk_minor_version);
2387  rep_INTERN (gtk_micro_version);
2388  rep_INTERN (rep_gtk_version);
2389  Fset (Qgtk_major_version, rep_MAKE_INT (GTK_MAJOR_VERSION));
2390  Fset (Qgtk_minor_version, rep_MAKE_INT (GTK_MINOR_VERSION));
2391  Fset (Qgtk_micro_version, rep_MAKE_INT (GTK_MICRO_VERSION));
2392  Fset (Qrep_gtk_version, rep_VAL (&ver));
2393  Fexport_bindings (rep_list_4 (Qgtk_major_version,
2394                                Qgtk_minor_version,
2395                                Qgtk_micro_version,
2396                                Qrep_gtk_version));
2397  rep_ADD_SUBR (Sg_object_new);
2398  rep_ADD_SUBR (Sg_object_set);
2399  rep_ADD_SUBR (Sg_object_get);
2400  rep_ADD_SUBR (Sg_object_list);
2401}
2402
2403static int sgtk_inited = 0;
2404
2405void
2406sgtk_init_with_args (int *argcp, char ***argvp)
2407{
2408  if (sgtk_inited)
2409    return;
2410
2411  /* XXX - Initialize Gtk only once.  We assume that Gtk has already
2412     been initialized when Gdk has.  That is not completely correct,
2413     but the best I can do.
2414
2415     Actually it shouldn't matter, gtk_init () won't initialise more
2416     than once.. --jsh */
2417
2418  if (GDK_DISPLAY () == 0)
2419    {
2420      char *tem = getenv ("REP_GTK_DONT_INITIALIZE");
2421      if (tem == 0 || atoi (tem) == 0)
2422        {
2423          gtk_set_locale ();
2424          gtk_init (argcp, argvp);
2425
2426#ifdef HAVE_SETLOCALE
2427          /* XXX remove when no longer needed.. */
2428          setlocale (LC_NUMERIC, "C");
2429#endif
2430        }
2431    }
2432
2433  if (rep_recurse_depth >= 0)
2434    standalone_p = 0;                   /* a reasonable assumption? --jsh */
2435
2436  sgtk_init_substrate ();
2437  sgtk_inited = 1;
2438}
2439
2440static char*
2441xstrdup (char *str)
2442{
2443  if (str)
2444    {
2445      char *newstr = rep_alloc (strlen(str)+1);
2446      strcpy (newstr, str);
2447      return newstr;
2448    }
2449  else
2450    return NULL;
2451}
2452
2453static void
2454make_argv (repv list, int *argc, char ***argv)
2455{
2456  static char *argv_storage[1] = { "rep-gtk" };
2457
2458  int c = list_length (list), i;
2459  char **v;
2460
2461  *argv = argv_storage;
2462  *argc = 1;
2463
2464  if (c < 0)
2465    return;
2466
2467  v = (char **)rep_alloc ((c+1) * sizeof(char**));
2468  for (i = 0; i < c; i++, list = rep_CDR (list))
2469    {
2470      if (!rep_STRINGP (rep_CAR (list)))
2471        {
2472          rep_free ((char *)v);
2473          return;
2474        }
2475      v[i] = xstrdup (rep_STR (rep_CAR (list)));
2476    }
2477  v[c] = NULL;
2478 
2479  *argv = v;
2480  *argc = c;
2481}
2482
2483void
2484sgtk_init (void)
2485{
2486  int argc;
2487  char **argv;
2488  repv head, *last;
2489
2490  if (sgtk_inited)
2491    return;
2492
2493  make_argv (Fcons (Fsymbol_value (Qprogram_name, Qt),
2494                    Fsymbol_value (Qcommand_line_args, Qt)), &argc, &argv);
2495  sgtk_init_with_args (&argc, &argv);
2496
2497  argc--; argv++;
2498  head = Qnil;
2499  last = &head;
2500  while(argc > 0)
2501  {
2502      *last = Fcons(rep_string_dup(*argv), Qnil);
2503      last = &rep_CDR(*last);
2504      argc--;
2505      argv++;
2506  }
2507  Fset (Qcommand_line_args, head);
2508}
2509
2510
2511
2512/* DL hooks */
2513
2514extern void sgtk_init_gtk_gtk_glue (void);
2515
2516repv
2517rep_dl_init (void)
2518{
2519  repv tem = rep_push_structure ("gui.gtk-2.gtk");
2520  sgtk_init_gtk_gtk_glue ();
2521  return rep_pop_structure (tem);
2522}
2523
2524/* This is required mainly since other dls may try to unregister
2525   inputs as they're being deleted. */
2526void
2527rep_dl_kill (void)
2528{
2529    if (rep_register_input_fd_fun == sgtk_register_input_fd)
2530        rep_register_input_fd_fun = 0;
2531    if (rep_deregister_input_fd_fun == sgtk_deregister_input_fd)
2532        rep_deregister_input_fd_fun = 0;
2533    if (rep_event_loop_fun == sgtk_event_loop)
2534        rep_event_loop_fun = 0;
2535    if (rep_sigchld_fun == sgtk_sigchld_callback)
2536        rep_sigchld_fun = 0;
2537    if (GDK_DISPLAY () != 0)
2538        rep_deregister_input_fd (ConnectionNumber (GDK_DISPLAY ()));
2539}
Note: See TracBrowser for help on using the repository browser.