void *get_swapped_string( struct pike_string *s,int force_wide )
{
  int i;
  unsigned short *res, *tmp;
#if (BYTEORDER!=4321)
  switch(s->size_shift)
  {
   default:
     return 0;
   case 1:
     {
       res= malloc(s->len * 2);
       tmp = (unsigned short *)s->str;
       for(i=0;i<s->len; i++)
	 res[i] = htons( tmp[i] );
       return res;
     }
  }
#endif
  if(force_wide)
  {
    switch(s->size_shift)
    {
     case 0:
       res = malloc(s->len*2);
       for(i=0;i<s->len;i++)
	 res[i] = htons( (short)(((unsigned char *)s->str)[i]) );
       return res;
     case 1: 
       return 0;
     case 2:
       res = malloc(s->len*2);
       for(i=0;i<s->len;i++)
	 res[i] = htons( (short)(((unsigned int *)s->str)[i]) );
       return res;
    }
  }
#ifdef DEBUG
  fatal("not reached\n");
#endif
  return 0;
}

struct object *pikeimage_from_gdkimage( GdkImage *img )
{
}

GdkImage *gdkimage_from_pikeimage( struct object *img, int fast, GdkImage *i )
{
  GdkColormap *col = gdk_colormap_get_system();
  GdkVisual *vis = gdk_visual_get_system();
  int x, y;

  /* 1a: create the actual image... */
  apply(img, "xsize", 0); apply(img, "ysize", 0);
  get_all_args("internal", 2, "%d%d", &x, &y);
  pop_n_elems( 2 );


  if( x==0 || y==0 )
    error("Size of image must be != 0x0\n");
  if(i)
  {
    if(i->width != x || i->height != y)
    {
      gdk_image_destroy((void *)i);
      i= NULL;
    }
  }
  if(!i)
    i = (void *)gdk_image_new(fast, vis, x, y);

  if(!i)
    error("Failed to create gdkimage\n");

  /* 1b: do the work.. */

  if(vis->type == GDK_VISUAL_TRUE_COLOR
     || vis->type == GDK_VISUAL_STATIC_GRAY) /* no colormap.. */
  {
    struct pike_string *s;
    struct object *image_module;
    push_text("Image");
    push_int(0);
    SAFE_APPLY_MASTER("resolv", 2);
    if (sp[-1].type!=T_OBJECT) 
      error("No Image module.\n");
    push_text("X");
    f_index(2);
    if (sp[-1].type!=T_OBJECT) 
      error("No Image.X module.\n");
    push_text("encode_truecolor_masks");
    f_index(2);
    if (sp[-1].type!=T_FUNCTION) 
      error("No Image.X.encode_truecolor_masks function.\n");

    img->refs++;
    push_object( img ); 
    push_int( i->bpp*8 );
    {
      int pad = 0;
      switch(i->bpl - (i->bpp*x))
      {
       case  0: pad = 0; break;
       case  1: pad = 16; break;
       default: pad = 32; break;
      }
      push_int( pad  ); /* extra padding.. */
    }
    push_int( !i->byte_order );
    push_int( vis->red_mask );
    push_int( vis->green_mask );
    push_int( vis->blue_mask );
    apply_svalue( sp-8, 7 );
    if(sp[-1].type != T_STRING)
    {
      gdk_image_destroy((void *)i);
      error("Failed to convert image\n");
    }
    MEMCPY(i->mem, sp[-1].u.string->str, sp[-1].u.string->len);
    pop_stack(); /* string */
    pop_stack(); /* function */
  } else {
    static int colors_allocated = 0;
    static struct object *pike_cmap;
    /* I hate this... colormaps, here we come.. */
    /* This is rather complicated, but: 
       1/ build an array of the colors in the colormap
       2/ use that array to build a pike X-image colormap.
       3/ call Image.X.encode_pseudocolor( img, bpp, lpad, depth, colormp )
       4/ copy the actual data to the image..
    */
    if(!colors_allocated)
    {
      char allocated[256];
      int j, i, r, g, b;
      colors_allocated=1;
      MEMSET(allocated, 0, sizeof(allocated));
      for(r=0; r<6; r++) for(g=0; g<7; g++) for(b=0; b<6; b++)
      {
	GdkColor color;
	color.red = (int)(r * (65535/5.0));
	color.green = (int)(g * (65535/6.0));
	color.blue = (int)(g * (65535/5.0));
	color.pixel = 0;
	if(gdk_color_alloc( col, &color ))
	  allocated[ color.pixel ] = 1;
      }
      
      for(i=0; i<256; i++)
      {
	if( allocated[ i ] )
	{
	  push_int(col->colors[i].red>>8);
	  push_int(col->colors[i].green>>8);
	  push_int(col->colors[i].blue>>8);
	  f_aggregate(3);
	}
	else
	  push_int(0);
      }
      f_aggregate(256);
      /* now on stack: the array with colors. */
      push_text("Image");
      push_int(0);
      SAFE_APPLY_MASTER("resolv", 2);
      if (sp[-1].type!=T_OBJECT) 
	error("No Image module.\n");
      push_text("colortable");
      f_index(2);
      /* on stack: array function */
      sp[0]=sp[-1];
      sp[-1]=sp[-2];
      sp[-2]=sp[0];
      /* on stack: function array */
      apply_svalue( sp-2, 1 );
      /* on stack: function cmap */
      get_all_args("internal", 1, "%o", &pike_cmap);
      pike_cmap->refs+=100; /* lets keep this one.. :-) */
      push_int(20); push_int(20); push_int(20);
      apply(pike_cmap, "cubicles", 3);          pop_stack();
      apply(pike_cmap, "floyd_steinberg", 0);   pop_n_elems(2);
    }
    
    { /* now we have a colormap available. Happy happy joy joy! */
      struct pike_string *s;
      struct object *image_module;
      push_text("Image");
      push_int(0);
      SAFE_APPLY_MASTER("resolv", 2);
      if (sp[-1].type!=T_OBJECT) 
	error("No Image module.\n");
      push_text("X");
      f_index(2);
      if (sp[-1].type!=T_OBJECT) 
	error("No Image.X module.\n");
      push_text("encode_pseudocolor");
      f_index(2);
      if (sp[-1].type!=T_FUNCTION) 
	error("No Image.X.encode_pseudocolor function.\n");
      /* on stack: function */
      img->refs++;
      push_object( img );
      push_int( i->bpp*8 );
      {
	int pad = 0;
	switch(i->bpl - (i->bpp*x))
	{
	 case  0: pad = 0; break;
	 case  1: pad = 16; break;
	 default: pad = 32; break;
	}
	push_int( pad  ); /* extra padding.. */
      }
      push_int( i->depth );
      pike_cmap->refs++;
      push_object( pike_cmap );
      /* on stack: function img bpp linepad depth cmap*/
      /*             6       5    4  3       2     1 */
      apply_svalue( sp-6, 5 );
      if(sp[-1].type != T_STRING)
      {
	gdk_image_destroy((void *)i);
	error("Failed to convert image\n");
      }
      MEMCPY(i->mem, sp[-1].u.string->str, sp[-1].u.string->len);
      pop_stack(); /* string */
      pop_stack(); /* function */
    }
  }
  return i;
}

void push_gtkobjectclass(void *obj, struct program *def)
{
  struct object *o;
  if(!obj)
  {
    push_int(0);
    return;
  }
  if( (o=gtk_object_get_data(GTK_OBJECT(obj), "pike_object")) )
  {
    ref_push_object( o );
    return;
  }
  o = low_clone( def );
  call_c_initializers( o );
  ((struct object_wrapper *)o->storage)->obj = obj;
  pgtk__init_object( o );
  ref_push_object( o );
  return;
}


void push_pgdkobject(void *obj, struct program *def)
{
  struct object *o;
  if(!obj)
  {
    push_int(0);
    return;
  }
/*   if( (o=gtk_object_get_data(GTK_OBJECT(obj), "pike_object")) ) */
/*   { */
/*     ref_push_object( o ); */
/*     return; */
/*   } */
  o = low_clone( def );
  call_c_initializers( o );
  ((struct object_wrapper *)o->storage)->obj = obj;
/*   pgtk__init_object( o ); */
  ref_push_object( o );
  return;
}

GtkObject *get_pgtkobject(struct object *from, struct program *type)
{
  struct object_wrapper * o;
  if(!from) return NULL; /* Convenience stuff.. */
  o=(struct object_wrapper *)get_storage( from, type );
  if(!o) {
    return 0;
#if 0
    error("Incorrect object type argument\n");
#endif
  }
  return o->obj;
}

void *get_pgdkobject(struct object *from, struct program *type)
{
  void *f;
  if(!from) return NULL;
  if(type)
    f = get_storage( from, type );
  else
    f = from->storage;
  if(!f) 
    return 0;
  return (void *)((struct object_wrapper *)f)->obj;
}


void pgtk__init_object( struct object *o )
{
#ifdef DEBUG
  if(!get_gtkobject(o))
    fatal("pgtk__init_object called on a non-pgtk object.!\n");
#endif
  o->refs+=3;
  gtk_object_set_data_full(get_gtkobject(o),
			   "pike_object",
			   (void*)o,
			   (void*)destruct);
}

void pgtk_get_mapping_arg( struct mapping *map,
                           char *name, int type, int madd,
                           void *dest, long *mask )
{
  struct svalue *s;
  if( s = simple_mapping_string_lookup( map, name ) )
  {
    if( s->type == type )
    {
      switch(type)
      {
       case T_STRING:
         *((char **)dest) = s->u.string->str;
         break;
       case T_INT:
         *((int *)dest) = s->u.integer;
         break;
       case T_FLOAT:
         *((float *)dest) = s->u.float_number;
         break;
      }
      *mask |= madd;
    }
  }
}

GdkAtom get_gdkatom( struct object *o )
{
  if(get_gdkobject( o,_Atom ))
    return (GdkAtom)get_gdkobject( o, _Atom );
  apply( o, "get_atom", 0);
  get_all_args( "internal_get_atom", 1, "%o", &o );
  if(get_gdkobject( o,_Atom ))
  {
    GdkAtom r = (GdkAtom)get_gdkobject( o,_Atom );
    pop_stack();
    return r;
  }
  error("Got non GDK.Atom object to get_gdkatom()\n");
}


struct my_pixel pgtk_pixel_from_xpixel( unsigned int pix, GdkImage *i )
{
  static GdkColormap *col;
  GdkColor * c;
  struct my_pixel res;
  int l;
  if(!col) col = gdk_colormap_get_system();
  res.r = res.g= res.b = 0;
  switch(i->visual->type)
  {
   case GDK_VISUAL_GRAYSCALE:
   case GDK_VISUAL_PSEUDO_COLOR:
     for(l=0; l<col->size; l++)
       if(col->colors[l].pixel == pix) /* 76 */
       {
	 res.r = col->colors[l].red/257;
	 res.g = col->colors[l].green/257;
	 res.b = col->colors[l].blue/257;
	 break;
       }
     break;

   case GDK_VISUAL_STATIC_COLOR:
   case GDK_VISUAL_TRUE_COLOR:
   case GDK_VISUAL_DIRECT_COLOR:
     /* Well well well.... */
     res.r = ((pix&i->visual->red_mask) 
	      >> i->visual->red_shift)
	      << (8-i->visual->red_prec);
     res.g = ((pix&i->visual->green_mask) 
	      >> i->visual->green_shift)
	      << (8-i->visual->green_prec);
     res.b = ((pix&i->visual->blue_mask) 
	      >> i->visual->blue_shift)
	      << (8-i->visual->blue_prec);
     break;
   case GDK_VISUAL_STATIC_GRAY:
     res.r = res.g = res.b = (pix*256) / 1<<i->visual->depth;
     break;
  }
  return res;
}


int pgtkbuttonfuncwrapper(GtkObject *obj, struct signal_data *d, void *foo)
{
  int res;
  push_svalue(&d->args);
  apply_svalue(&d->cb, 1);
  res = sp[-1].u.integer;
  pop_stack();
  return res;
}

void push_gdk_event(GdkEvent *e)
{
  struct svalue *osp = sp;
  if(!e)
  {
    push_text("NullEvent"); /* Why, o why? */
    return;
  }
  switch(e->type)
  {
   case GDK_NOTHING:
     push_text("type");  push_text("nothing");
     break;
   case GDK_DELETE:
     push_text("type");  push_text("delete");
     break;
   case GDK_DESTROY:
     push_text("type");  push_text("destroy");
     break;
   case GDK_EXPOSE:
     push_text("type");    push_text("expose");
     push_text("count");   push_int(e->expose.count);
     push_text("x");       push_int(e->expose.area.x);
     push_text("y");       push_int(e->expose.area.y);
     push_text("width");   push_int(e->expose.area.width);
     push_text("height");  push_int(e->expose.area.height);
     break;
   case GDK_MOTION_NOTIFY:
     push_text("type");    push_text("motion");
     push_text("time");    push_int(e->motion.time);
     push_text("x");       push_float(e->motion.x);
     push_text("y");       push_float(e->motion.y);
     push_text("pressure");push_float(e->motion.pressure);
     push_text("xtilt");   push_float(e->motion.xtilt);
     push_text("ytilt");   push_float(e->motion.ytilt);
     push_text("state");   push_int(e->motion.state);
     push_text("time");    push_int(e->motion.time);
     push_text("deviceid");push_int(e->motion.deviceid);
     push_text("x_root");  push_float(e->motion.x_root);
     push_text("y_root");  push_int(e->motion.y_root);
     break;

   case GDK_BUTTON_PRESS:
     push_text("type");    push_text("button_press");
     goto press_event;
   case GDK_2BUTTON_PRESS:
     push_text("type");    push_text("2button_press");
     goto press_event;
   case GDK_3BUTTON_PRESS:
     push_text("type");    push_text("3button_press");
     goto press_event;
   case GDK_BUTTON_RELEASE:
     push_text("type");    push_text("button_release");

  press_event:
     push_text("time");    push_int(e->button.time);
     push_text("x");       push_float(e->button.x);
     push_text("y");       push_float(e->button.y);
     push_text("pressure");push_float(e->button.pressure);
     push_text("xtilt");   push_float(e->button.xtilt);
     push_text("ytilt");   push_float(e->button.ytilt);
     push_text("state");   push_int(e->button.state);
     push_text("button");    push_int(e->button.button);
     push_text("deviceid");push_int(e->button.deviceid);
     push_text("x_root");  push_float(e->button.x_root);
     push_text("y_root");  push_int(e->button.y_root);
     break;
     
   case GDK_KEY_PRESS:
     push_text("type");   push_text("key_press");
     goto key_event;

   case GDK_KEY_RELEASE:
     push_text("type");   push_text("key_release");
  key_event:
     push_text("time");   push_int(e->key.time);
     push_text("state");   push_int(e->key.state);
     push_text("keyval");   push_int(e->key.keyval);
     if(e->key.string)
     {
       push_text("data");     
       push_string(make_shared_binary_string(e->key.string, e->key.length));
     }
     break;

   case GDK_ENTER_NOTIFY:
     push_text("type");   push_text("enter_notify");
     goto enter_event;
   case GDK_LEAVE_NOTIFY:
     push_text("type");   push_text("leave_notify");
  enter_event:
     push_text("detail"); push_int(e->crossing.detail);
     break;

   case GDK_FOCUS_CHANGE:
     push_text("type");   push_text("focus");
     break;

   case GDK_CONFIGURE:
     push_text("type");   push_text("configure");
     push_text("x"); push_int(e->configure.x);
     push_text("y"); push_int(e->configure.x);
     push_text("width"); push_int(e->configure.width);
     push_text("height"); push_int(e->configure.height);
     break;

   case GDK_MAP:
     push_text("type");   push_text("map");
     break;
   case GDK_UNMAP:
     push_text("type");   push_text("unmap");
     break;

   case GDK_PROPERTY_NOTIFY:
     push_text("type");   push_text("property");
     break;

   case GDK_SELECTION_CLEAR:
     push_text("type");   push_text("selection_clear");
     break;

   case GDK_SELECTION_REQUEST:
     push_text("type");   push_text("selection_request");
     break;

   case GDK_SELECTION_NOTIFY:
     push_text("type");   push_text("selection_notify");
     break;

   case GDK_PROXIMITY_IN:
     push_text("type");   push_text("proximity_in");
     break;
   case GDK_PROXIMITY_OUT:
     push_text("type");   push_text("proximity_out");
     break;

   case GDK_CLIENT_EVENT:
     push_text("type"); push_text("client");
     break;

   case GDK_VISIBILITY_NOTIFY:
     push_text("type"); push_text("visibility");
     break;

   case GDK_NO_EXPOSE:
     push_text("type"); push_text("noexpose");
     break;
  }
  f_aggregate_mapping( sp - osp );
}


int pgtk_signal_func_wrapper(GtkObject *obj,struct signal_data *d,
                             int nparams, GtkArg *params)
{
  int i, j=0, res, return_value = 0;
  push_svalue(&d->args);
  push_gtkobject( obj );
  for(i=0; i<nparams; i++)
  {
    switch( params[i].type )
    {
     case GTK_TYPE_INT:
     case GTK_TYPE_ENUM:
     case GTK_TYPE_FLAGS:
       push_int( (INT32)GTK_VALUE_INT(params[i]) );
       break;
     case GTK_TYPE_BOOL:
       push_int( (INT32)GTK_VALUE_BOOL(params[i]) );
       break;
     case GTK_TYPE_UINT:
       push_int( (INT32)GTK_VALUE_UINT(params[i]) );
       break;
     case GTK_TYPE_LONG:
       push_int( (INT32)GTK_VALUE_LONG(params[i]) );
       break;

     case GTK_TYPE_CHAR:
       push_int( (INT32)((unsigned char)GTK_VALUE_CHAR( params[i] )) );
       break;

     case GTK_TYPE_ULONG:
       push_int( (INT32)GTK_VALUE_ULONG(params[i]) );
       break;
     case GTK_TYPE_INVALID:
     case GTK_TYPE_NONE:
       push_int( 0 );
       break;
     case GTK_TYPE_FLOAT:
       push_float( (float)GTK_VALUE_FLOAT(params[i]) );
       break;
     case GTK_TYPE_DOUBLE:
       push_float( (float)GTK_VALUE_DOUBLE(params[i]) );
       break;

     case GTK_TYPE_POINTER: /* These probably need fixing.. / Hubbe */
     case GTK_TYPE_FOREIGN:

     case GTK_TYPE_STRING:
       if(GTK_VALUE_STRING( params[i] ))
	 push_text( GTK_VALUE_STRING( params[i] ) );
       else
	 push_text( "" );
       break;

     case GTK_TYPE_OBJECT:
       push_gtkobject( GTK_VALUE_OBJECT( params[i] ) );
       break;

     default:
       {
	 char *n = gtk_type_name( params[i].type );
         if(n)
         {
           if(!strcmp(n, "GdkEvent"))
           {
             return_value = 1;
             push_gdk_event( GTK_VALUE_POINTER( params[i] ) );
           } 
           else if(!strcmp(n, "GdkModifierType")) 
           {
             push_int( GTK_VALUE_UINT( params[i] ) );
           }
           else if(!strcmp(n, "GtkAccelFlags")) 
           {
             push_int( GTK_VALUE_UINT( params[i] ) );
           }
           else
           {
#ifdef DEBUG
 	 fprintf(stderr,"Unknown param type: %s<value=%p>\n",
                 n, GTK_VALUE_POINTER(params[i]));
#endif
             push_text( n );
           }
         }
	 else
	   push_int( 0 );
       }
    }
    j++;
  }
  apply_svalue(&d->cb, 2+j);
  res = sp[-1].u.integer;
  pop_stack();
  if( return_value )
  { 
    if( params[1].type == GTK_TYPE_POINTER)
    {
      gint *return_val;
      return_val = GTK_RETLOC_BOOL( params[ 1 ] );
      if(return_val)
        *return_val = res;
    }
  }
  return res;
}

void pgtk_free_signal_data( struct signal_data *s)
{
  free_svalue( &s->cb );
  free_svalue( &s->args );
  free(s);
}
