/**
 * Sets this to a scaled version of the original pixbuf
 * width and height of the destination GtkImage must be set.
 */
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkImage_createScaledPixbuf(JNIEnv *env,
        jobject destination,
        jobject source,
        jint hints)
{
    GdkPixbuf* dst;
    int width, height;
    jclass cls;
    jfieldID field;

    GdkPixbuf *pixbuf;

    cls = (*env)->GetObjectClass (env, destination);
    field = (*env)->GetFieldID (env, cls, "width", "I");
    g_assert (field != 0);
    width = (*env)->GetIntField (env, destination, field);

    field = (*env)->GetFieldID (env, cls, "height", "I");
    g_assert (field != 0);
    height = (*env)->GetIntField (env, destination, field);

    pixbuf = cp_gtk_image_get_pixbuf (env, source);

    dst = gdk_pixbuf_scale_simple(pixbuf,
                                  width, height,
                                  mapHints(hints));

    createRawData (env, destination, (void *)dst);
}
/**
 * Returns a copy of the pixel data as a java array.
 * (GdkPixbuf only)
 */
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkImage_setPixels(JNIEnv *env, jobject obj,
        jintArray pixels)
{
    GdkPixbuf *pixbuf = cp_gtk_image_get_pixbuf (env, obj);
    int width, height, rowstride;
    guchar *pixeldata;
    jint *src_array_iter, *src;
    int i;

    width =  gdk_pixbuf_get_width (pixbuf);
    height = gdk_pixbuf_get_height (pixbuf);
    rowstride = gdk_pixbuf_get_rowstride (pixbuf);

    src = src_array_iter =
              (*env)->GetIntArrayElements (env, pixels, NULL);

    pixeldata = gdk_pixbuf_get_pixels (pixbuf);
    for(i = 0 ; i < height; i++)
    {
        memcpy((void *)pixeldata, (void *)src, width * 4);
        src += width;
        pixeldata += rowstride;
    }

    (*env)->ReleaseIntArrayElements (env, pixels, src_array_iter, 0);
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkImage_createFromPixbuf
(JNIEnv *env, jobject obj)
{
    int width, heigth;
    GdkPixbuf *pixbuf = cp_gtk_image_get_pixbuf (env, obj);
    width =  gdk_pixbuf_get_width (pixbuf);
    heigth = gdk_pixbuf_get_height (pixbuf);
    setWidthHeight(env, obj, width, heigth);
}
JNIEXPORT void JNICALL 
Java_gnu_java_awt_dnd_peer_gtk_GtkDragSourceContextPeer_nativeStartDrag
  (JNIEnv *env, jobject obj, jobject img, jint x, jint y, jint act,
   jstring target)
{
  void *ptr;
  const gchar *data;
  GtkTargetEntry tar[1];
  GdkEvent *event;
  GdkPixbuf *image = NULL;
  GdkDragContext *context = NULL;
  GdkDragAction action = GDK_ACTION_DEFAULT;
  
  gdk_threads_enter ();

  ptr = NSA_GET_GLOBAL_REF (env, obj);

  data = (*env)->GetStringUTFChars (env, target, NULL);
  tar[0].target = (gchar *) data;  
  event = gdk_event_new (GDK_ALL_EVENTS_MASK);
  
  switch (act)
    {
    case ACTION_COPY:
      action = GDK_ACTION_COPY;
      break;
    case ACTION_MOVE:
      action = GDK_ACTION_MOVE;
      break;
    case ACTION_COPY_OR_MOVE:
      action = GDK_ACTION_COPY | GDK_ACTION_MOVE;
      break;
    case ACTION_LINK:
      action = GDK_ACTION_LINK;
      break;
    default:
      action = GDK_ACTION_DEFAULT;
    }

  gtk_drag_highlight (widget);
  context = gtk_drag_begin (widget, 
             gtk_target_list_new (tar, sizeof (tar) / sizeof (GtkTargetEntry)), 
             action, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK, event);

  if (img != NULL)
  {
    image = cp_gtk_image_get_pixbuf (env, img);
    gtk_drag_set_icon_pixbuf (context, image, x, y);
  }

  gdk_event_free (event);
  (*env)->ReleaseStringUTFChars (env, target, data);  
  
  gdk_threads_leave ();
}
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkFramePeer_nativeSetIconImage
(JNIEnv *env, jobject obj, jobject gtkimage)
{
    void *ptr;
    GdkPixbuf *pixbuf = NULL;

    gdk_threads_enter ();

    pixbuf = cp_gtk_image_get_pixbuf (env, gtkimage);
    g_assert (pixbuf != NULL);

    ptr = gtkpeer_get_widget (env, obj);

    gtk_window_set_icon (GTK_WINDOW (ptr), pixbuf);

    gdk_threads_leave ();
}
JNIEXPORT void JNICALL 
Java_gnu_java_awt_peer_gtk_ComponentGraphicsCopy_copyPixbuf
  (JNIEnv *env, jobject obj __attribute__((unused)),
   jobject peer, jobject image,
   jint x __attribute__((unused)), jint y __attribute__((unused)),
   jint width __attribute__((unused)), jint height __attribute__((unused)))
{
  gint pwidth, pheight;
  GdkPixbuf *pixbuf;
  GdkDrawable *drawable;
  GdkWindow *win;
  GtkWidget *widget = NULL;
  void *ptr = NULL;

  gdk_threads_enter();

  ptr = gtkpeer_get_widget (env, peer);
  g_assert (ptr != NULL);

  widget = GTK_WIDGET (ptr);
  g_assert (widget != NULL);

  cp_gtk_grab_current_drawable (widget, &drawable, &win);
  g_assert (drawable != NULL);

  pixbuf = cp_gtk_image_get_pixbuf( env, image );
  g_assert( pixbuf != NULL);

  pwidth = gdk_pixbuf_get_width( pixbuf );
  pheight = gdk_pixbuf_get_height( pixbuf );

  gdk_draw_pixbuf (drawable, NULL, pixbuf,
		   0, 0, 0, 0, 
		   pwidth, pheight, 
		   GDK_RGB_DITHER_NORMAL, 0, 0);

  gdk_threads_leave();
}
JNIEXPORT void JNICALL 
Java_gnu_java_awt_peer_gtk_ComponentGraphicsCopy_getPixbuf
   (JNIEnv *env, jobject obj __attribute__((unused)),
    jobject peer, jobject image)
{
  gint width, height;
  GdkPixbuf *pixbuf;
  GdkDrawable *drawable;
  GdkWindow *win;
  GtkWidget *widget = NULL;
  void *ptr = NULL;

  gdk_threads_enter();

  ptr = gtkpeer_get_widget (env, peer);
  g_assert (ptr != NULL);

  widget = GTK_WIDGET (ptr);
  g_assert (widget != NULL);

  cp_gtk_grab_current_drawable (widget, &drawable, &win);
  g_assert (drawable != NULL);

  pixbuf = cp_gtk_image_get_pixbuf( env, image );
  g_assert( pixbuf != NULL);

  width = gdk_pixbuf_get_width( pixbuf );
  height = gdk_pixbuf_get_height( pixbuf );

  gdk_pixbuf_get_from_drawable( pixbuf, /* destination pixbuf */
				drawable, 
				NULL, /* colormap */
				0, 0, 0, 0,
				width, height );
  gdk_threads_leave();
}
/**
 * Frees the Gtk Pixbuf.
 */
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkImage_freePixbuf(JNIEnv *env, jobject obj)
{
    gdk_pixbuf_unref (cp_gtk_image_get_pixbuf (env, obj));
}
/**
 * Returns a copy of the pixel data as a java array.
 */
JNIEXPORT jintArray JNICALL
Java_gnu_java_awt_peer_gtk_GtkImage_getPixels(JNIEnv *env, jobject obj)
{
    GdkPixbuf *pixbuf;
    int width, height, rowstride;
    guchar *pixeldata;
    jintArray result_array;
    jint *result_array_iter, *dst;
    int i,j;

    gdk_threads_enter ();

    pixbuf = cp_gtk_image_get_pixbuf (env, obj);
    width =  gdk_pixbuf_get_width (pixbuf);
    height = gdk_pixbuf_get_height (pixbuf);
    rowstride = gdk_pixbuf_get_rowstride (pixbuf);

    result_array = (*env)->NewIntArray (env, (width * height));
    if (result_array == NULL)
    {
        gdk_threads_leave ();
        return NULL;
    }

    dst = result_array_iter =
              (*env)->GetIntArrayElements (env, result_array, NULL);


    pixeldata = gdk_pixbuf_get_pixels (pixbuf);

    g_assert (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);

    if (gdk_pixbuf_get_has_alpha (pixbuf))
    {
        for(i = 0 ; i < height; i++)
        {
            memcpy(dst, (void *)pixeldata, width * 4);
            dst += width;
            pixeldata += rowstride;
        }
    } else {

        /* Add a default alpha value of 0xFF to the pixeldata without alpha
           information and keep it in the same format as the pixeldata with alpha
           information. On Little Endian systems: AABBGGRR and on Big Endian
           systems: RRGGBBAA.  */

        for(i = 0; i < height; i++)
        {
            for(j = 0; j < width; j++)

#ifndef WORDS_BIGENDIAN
                dst[j] = 0xFF000000
                         | (pixeldata[j*3 + 2] & 0xFF) << 16
                         | (pixeldata[j*3 + 1] & 0xFF) << 8
                         | (pixeldata[j*3] & 0xFF);
#else
                dst[j] = (pixeldata[j*3] & 0xFF) << 24
                         | (pixeldata[j*3 + 1] & 0xFF) << 16
                         | (pixeldata[j*3 + 2] & 0xFF) << 8
                         | 0xFF;
#endif
            dst += width;
            pixeldata += rowstride;
        }
    }

    (*env)->ReleaseIntArrayElements (env, result_array, result_array_iter, 0);

    gdk_threads_leave ();
    return result_array;
}
JNIEXPORT void JNICALL 
Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetCursorUnlocked
  (JNIEnv *env, jobject obj, jint type, jobject image, jint x, jint y) 
{
  void *ptr;
  GtkWidget *widget;
  GdkWindow *win;
  GdkCursorType gdk_cursor_type;
  GdkCursor *gdk_cursor;

  ptr = gtkpeer_get_widget (env, obj);

  switch (type)
    {
    case AWT_CROSSHAIR_CURSOR:
      gdk_cursor_type = GDK_CROSSHAIR;
      break;
    case AWT_TEXT_CURSOR:
      gdk_cursor_type = GDK_XTERM;
      break;
    case AWT_WAIT_CURSOR:
      gdk_cursor_type = GDK_WATCH;
      break;
    case AWT_SW_RESIZE_CURSOR:
      gdk_cursor_type = GDK_BOTTOM_LEFT_CORNER;
      break;
    case AWT_SE_RESIZE_CURSOR:
      gdk_cursor_type = GDK_BOTTOM_RIGHT_CORNER;
      break;
    case AWT_NW_RESIZE_CURSOR:
      gdk_cursor_type = GDK_TOP_LEFT_CORNER;
      break;
    case AWT_NE_RESIZE_CURSOR:
      gdk_cursor_type = GDK_TOP_RIGHT_CORNER;
      break;
    case AWT_N_RESIZE_CURSOR:
      gdk_cursor_type = GDK_TOP_SIDE;
      break;
    case AWT_S_RESIZE_CURSOR:
      gdk_cursor_type = GDK_BOTTOM_SIDE;
      break;
    case AWT_W_RESIZE_CURSOR:
      gdk_cursor_type = GDK_LEFT_SIDE;
      break;
    case AWT_E_RESIZE_CURSOR:
      gdk_cursor_type = GDK_RIGHT_SIDE;
      break;
    case AWT_HAND_CURSOR:
      gdk_cursor_type = GDK_HAND2;
      break;
    case AWT_MOVE_CURSOR:
      gdk_cursor_type = GDK_FLEUR;
      break;
    default:
      gdk_cursor_type = GDK_LEFT_PTR;
    }
      
  widget = get_widget(GTK_WIDGET(ptr));
  
  win = widget->window;
  if ((widget->window) == NULL)
    win = GTK_WIDGET(ptr)->window;
    
  if (image == NULL)
    gdk_cursor = gdk_cursor_new (gdk_cursor_type);
  else
    gdk_cursor
      = gdk_cursor_new_from_pixbuf (gdk_drawable_get_display (win),
				    cp_gtk_image_get_pixbuf (env, image),
				    x, y);

  gdk_window_set_cursor (win, gdk_cursor);
  gdk_cursor_unref (gdk_cursor);

  /* Make sure the cursor is replaced on screen. */
  gdk_flush();
}