+ AndroidBitmapInfo bmp_info;
+ AndroidBitmap_getInfo (env, jbitmap, &bmp_info);
+
+ XImage *img = XCreateImage (dpy, NULL, visual_depth(NULL, NULL),
+ ZPixmap, 0, NULL,
+ bmp_info.width, bmp_info.height, 0,
+ bmp_info.stride);
+
+ AndroidBitmap_lockPixels (env, jbitmap, (void **) &img->data);
+
+ XPutImage (dpy, drawable, gc, img, 0, 0,
+ (drawable->frame.width - bmp_info.width) / 2,
+ (drawable->frame.height - bmp_info.height) / 2,
+ bmp_info.width, bmp_info.height);
+
+ AndroidBitmap_unlockPixels (env, jbitmap);
+ img->data = NULL;
+ XDestroyImage (img);
+
+ return jstring_dup (env, (*env)->GetObjectArrayElement (env, img_name, 1));
+}
+
+
+XImage *
+jwxyz_png_to_ximage (Display *dpy, Visual *visual,
+ const unsigned char *png_data, unsigned long data_size)
+{
+ Window window = RootWindow (dpy, 0);
+ struct running_hack *rh = window->window.rh;
+ JNIEnv *env = rh->jni_env;
+ jobject obj = rh->jobject;
+ jclass c = (*env)->GetObjectClass (env, obj);
+ jmethodID m = (*env)->GetMethodID (env, c, "decodePNG",
+ "([B)Landroid/graphics/Bitmap;");
+ if ((*env)->ExceptionOccurred(env)) abort();
+ jbyteArray jdata = (*env)->NewByteArray (env, data_size);
+ (*env)->SetByteArrayRegion (env, jdata, 0,
+ data_size, (const jbyte *) png_data);
+ jobject jbitmap = (
+ m
+ ? (*env)->CallObjectMethod (env, obj, m, jdata)
+ : NULL);
+ if ((*env)->ExceptionOccurred(env)) abort();
+ (*env)->DeleteLocalRef (env, c);
+ (*env)->DeleteLocalRef (env, jdata);
+ if (!jbitmap)
+ return NULL;
+
+ AndroidBitmapInfo bmp_info;
+ AndroidBitmap_getInfo (env, jbitmap, &bmp_info);
+
+ XImage *img = XCreateImage (dpy, NULL, 32, ZPixmap, 0, NULL,
+ bmp_info.width, bmp_info.height, 8,
+ bmp_info.stride);
+ char *bits = 0;
+ AndroidBitmap_lockPixels (env, jbitmap, (void **) &bits);
+ img->data = (char *) calloc (img->bytes_per_line, img->height);
+ memcpy (img->data, bits, img->bytes_per_line * img->height);
+ AndroidBitmap_unlockPixels (env, jbitmap);
+
+ // Java should have returned ARGB data.
+ // WTF, why isn't ANDROID_BITMAP_FORMAT_ARGB_8888 defined?
+ if (bmp_info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) abort();
+# ifndef __BYTE_ORDER__ // A GCC (and Clang)-ism.
+# error Need a __BYTE_ORDER__.
+# elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ img->byte_order = img->bitmap_bit_order = LSBFirst;
+# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ img->byte_order = img->bitmap_bit_order = MSBFirst;
+# else
+# error Need a __BYTE_ORDER__.
+# endif
+
+ static const union {
+ uint8_t bytes[4];
+ uint32_t pixel;
+ } c0 = {{0xff, 0x00, 0x00, 0x00}}, c1 = {{0x00, 0xff, 0x00, 0x00}},
+ c2 = {{0x00, 0x00, 0xff, 0x00}};
+
+ img->red_mask = c0.pixel;
+ img->green_mask = c1.pixel;
+ img->blue_mask = c2.pixel;
+
+ return img;