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

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