diff --git a/src/java/org/lwjgl/opengl/Display.java b/src/java/org/lwjgl/opengl/Display.java index 25f54915..79b6cb48 100644 --- a/src/java/org/lwjgl/opengl/Display.java +++ b/src/java/org/lwjgl/opengl/Display.java @@ -1202,7 +1202,7 @@ public final class Display { *
  • Linux (and similar platforms) expect one 32x32 icon.
  • *
  • Mac OS X should be supplied one 128x128 icon
  • * - * The implementation will use the supplied ByteBuffers with image data in RGBA and perform any conversions nescesarry for the specific platform. + * The implementation will use the supplied ByteBuffers with image data in RGBA (size must be a power of two) and perform any conversions nescesarry for the specific platform. *

    * NOTE: The display will make a deep copy of the supplied byte buffer array, for the purpose * of recreating the icons when you go back and forth fullscreen mode. You therefore only need to diff --git a/src/java/org/lwjgl/opengl/LinuxDisplay.java b/src/java/org/lwjgl/opengl/LinuxDisplay.java index eb91e3b1..57014175 100644 --- a/src/java/org/lwjgl/opengl/LinuxDisplay.java +++ b/src/java/org/lwjgl/opengl/LinuxDisplay.java @@ -45,6 +45,7 @@ import java.awt.event.FocusEvent; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.nio.ByteOrder; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; @@ -1331,50 +1332,58 @@ final class LinuxDisplay implements DisplayImplementation { public void releaseTexImageFromPbuffer(PeerInfo handle, int buffer) { throw new UnsupportedOperationException(); } - - private static ByteBuffer convertIcon(ByteBuffer icon, int width, int height) { - ByteBuffer icon_rgb = BufferUtils.createByteBuffer(icon.capacity()); - int x; - int y; - byte r,g,b; - - int depth = 4; - - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - r = icon.get((x*4)+(y*width*4)); - g = icon.get((x*4)+(y*width*4)+1); - b = icon.get((x*4)+(y*width*4)+2); - - icon_rgb.put((x*depth)+(y*width*depth), b); // blue - icon_rgb.put((x*depth)+(y*width*depth)+1, g); // green - icon_rgb.put((x*depth)+(y*width*depth)+2, r); + + /** + * This method will convert icon bytebuffers into a single bytebuffer + * as the icon format required by _NET_WM_ICON should be in a cardinal + * 32 bit ARGB format i.e. all icons in a single buffer the data starting + * with 32 bit width & height followed by the color data as 32bit ARGB. + * + * @param icons Array of icons in RGBA format + */ + private static ByteBuffer convertIcons(ByteBuffer[] icons) { + + int bufferSize = 0; + + // calculate size of bytebuffer + for ( ByteBuffer icon : icons ) { + int size = icon.limit() / 4; + int dimension = (int)Math.sqrt(size); + if ( dimension > 0 ) { + bufferSize += 2 * 4; // add 32 bit width & height, 4 bytes each + bufferSize += dimension * dimension * 4; } } - return icon_rgb; - } - - private static ByteBuffer convertIconMask(ByteBuffer icon, int width, int height) { - ByteBuffer icon_mask = BufferUtils.createByteBuffer((icon.capacity()/4)/8); - int x; - int y; - byte a; - - int depth = 4; - - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - a = icon.get((x*4)+(y*width*4)+3); - - int mask_index = x + y*width; - int mask_byte_index = mask_index/8; - int mask_bit_index = mask_index%8; - byte bit = (((int)a) & 0xff) >= 127 ? (byte)1 : (byte)0; - byte new_byte = (byte)((icon_mask.get(mask_byte_index) | (bit< 0 ) { - ByteBuffer icon_rgb = convertIcon(icon, dimension, dimension); - ByteBuffer icon_mask = convertIconMask(icon, dimension, dimension); - nSetWindowIcon(getDisplay(), getWindow(), icon_rgb, icon_rgb.capacity(), icon_mask, icon_mask.capacity(), dimension, dimension); - return 1; - } - } - return 0; + // get icons as cardinal ARGB format + ByteBuffer icons_data = convertIcons(icons); + if (icons_data == null) return 0; + nSetWindowIcon(getDisplay(), getWindow(), icons_data, icons_data.capacity());//, icon_mask, icon_mask.capacity(), dimension, dimension); + return icons.length; } finally { decDisplay(); } @@ -1416,7 +1419,7 @@ final class LinuxDisplay implements DisplayImplementation { } } - private static native void nSetWindowIcon(long display, long window, ByteBuffer icon_rgb, int icon_rgb_size, ByteBuffer icon_mask, int icon_mask_size, int width, int height); + private static native void nSetWindowIcon(long display, long window, ByteBuffer icons_data, int icons_size); public int getX() { return window_x; diff --git a/src/native/linux/opengl/org_lwjgl_opengl_Display.c b/src/native/linux/opengl/org_lwjgl_opengl_Display.c index 8622faec..4a641394 100644 --- a/src/native/linux/opengl/org_lwjgl_opengl_Display.c +++ b/src/native/linux/opengl/org_lwjgl_opengl_Display.c @@ -72,8 +72,6 @@ static GLXWindow glx_window = None; static Colormap cmap; static int current_depth; -static Pixmap current_icon_pixmap; -static Pixmap current_icon_mask_pixmap; static Visual *current_visual; @@ -232,17 +230,6 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetClassHint(JNIEnv * setClassHint(disp, window, wm_name, wm_class); } -static void freeIconPixmap(Display *disp) { - if (current_icon_mask_pixmap != 0) { - XFreePixmap(disp, current_icon_mask_pixmap); - current_icon_mask_pixmap = 0; - } - if (current_icon_pixmap != 0) { - XFreePixmap(disp, current_icon_pixmap); - current_icon_pixmap = 0; - } -} - static void destroyWindow(JNIEnv *env, Display *disp, Window window) { if (glx_window != None) { lwjgl_glXDestroyWindow(disp, glx_window); @@ -250,7 +237,6 @@ static void destroyWindow(JNIEnv *env, Display *disp, Window window) { } XDestroyWindow(disp, window); XFreeColormap(disp, cmap); - freeIconPixmap(disp); } static bool isNetWMFullscreenSupported(JNIEnv *env, Display *disp, int screen) { @@ -372,14 +358,6 @@ static void updateWindowHints(JNIEnv *env, Display *disp, Window window) { win_hints->flags = InputHint; win_hints->input = True; - if (current_icon_pixmap != 0) { - win_hints->flags |= IconPixmapHint; - win_hints->icon_pixmap = current_icon_pixmap; - } - if (current_icon_mask_pixmap != 0) { - win_hints->flags |= IconMaskHint; - win_hints->icon_mask = current_icon_mask_pixmap; - } XSetWMHints(disp, window, win_hints); XFree(win_hints); @@ -599,58 +577,30 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nUnlockAWT(JNIEnv *env jawt.Unlock(env); } -static Pixmap createPixmapFromBuffer(JNIEnv *env, Display *disp, Window window, char *data, int data_size, int width, int height, int format, int depth) { - Pixmap pixmap = XCreatePixmap(disp, window, width, height, depth); - /* We need to copy the image data since XDestroyImage will also free its data buffer, which can't be allowed - * since the data buffer is managed by the jvm (it's the storage for the direct ByteBuffer) - */ - char *icon_copy = (char *)malloc(sizeof(*icon_copy)*data_size); - - if (icon_copy == NULL) { - XFreePixmap(disp, pixmap); - throwException(env, "malloc failed"); - return None; - } - memcpy(icon_copy, data, data_size); - XImage *image = XCreateImage(disp, current_visual, depth, format, 0, icon_copy, width, height, 32, 0); - if (image == NULL) { - XFreePixmap(disp, pixmap); - free(icon_copy); - throwException(env, "XCreateImage failed"); - return None; - } - - GC gc = XCreateGC(disp, pixmap, 0, NULL); - XPutImage(disp, pixmap, gc, image, 0, 0, 0, 0, width, height); - XFreeGC(disp, gc); - XDestroyImage(image); - // We won't free icon_copy because it is freed by XDestroyImage - return pixmap; -} - -static void setIcon(JNIEnv *env, Display *disp, Window window, char *rgb_data, int rgb_size, char *mask_data, int mask_size, int width, int height) { - freeIconPixmap(disp); - current_icon_pixmap = createPixmapFromBuffer(env, disp, window, rgb_data, rgb_size, width, height, ZPixmap, current_depth); - if ((*env)->ExceptionCheck(env)) - return; - current_icon_mask_pixmap = createPixmapFromBuffer(env, disp, window, mask_data, mask_size, width, height, XYPixmap, 1); - if ((*env)->ExceptionCheck(env)) { - freeIconPixmap(disp); - return; - } - - updateWindowHints(env, disp, window); -} - JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetWindowIcon - (JNIEnv *env, jclass clazz, jlong display, jlong window_ptr, jobject icon_rgb_buffer, jint rgb_size, jobject icon_mask_buffer, jint mask_size, jint width, jint height) + (JNIEnv *env, jclass clazz, jlong display, jlong window_ptr, jobject icons_buffer, jint icons_buffer_size) { Display *disp = (Display *)(intptr_t)display; Window window = (Window)window_ptr; - char *rgb_data= (char *)(*env)->GetDirectBufferAddress(env, icon_rgb_buffer); - char *mask_data= (char *)(*env)->GetDirectBufferAddress(env, icon_mask_buffer); + const unsigned char *icons_char_buffer = (const unsigned char *)(*env)->GetDirectBufferAddress(env, icons_buffer); + + int length = icons_buffer_size/4; + unsigned long icons_long_buffer[length]; + int i = 0; - setIcon(env, disp, window, rgb_data, rgb_size, mask_data, mask_size, width, height); + // copy byte array to long array + for (i = 0; i < icons_buffer_size; i += 4) { + unsigned long argb = (icons_char_buffer[i] << 24) | + (icons_char_buffer[i+1] << 16) | + (icons_char_buffer[i+2] << 8) | + (icons_char_buffer[i+3]); + icons_long_buffer[i/4] = argb; + } + + XChangeProperty(disp, window, + XInternAtom(disp, "_NET_WM_ICON", False), + XInternAtom(disp, "CARDINAL", False), + 32, PropModeReplace, (const unsigned char*) icons_long_buffer, length); } JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nUngrabKeyboard(JNIEnv *env, jclass unused, jlong display_ptr) { diff --git a/src/native/linux/opengles/org_lwjgl_opengl_Display.c b/src/native/linux/opengles/org_lwjgl_opengl_Display.c index 8bd9db97..0132bb72 100644 --- a/src/native/linux/opengles/org_lwjgl_opengl_Display.c +++ b/src/native/linux/opengles/org_lwjgl_opengl_Display.c @@ -69,8 +69,6 @@ typedef struct { static Colormap cmap; static int current_depth; -static Pixmap current_icon_pixmap; -static Pixmap current_icon_mask_pixmap; static Visual *current_visual; @@ -226,21 +224,9 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetClassHint(JNIEnv * setClassHint(disp, window, wm_name, wm_class); } -static void freeIconPixmap(Display *disp) { - if (current_icon_mask_pixmap != 0) { - XFreePixmap(disp, current_icon_mask_pixmap); - current_icon_mask_pixmap = 0; - } - if (current_icon_pixmap != 0) { - XFreePixmap(disp, current_icon_pixmap); - current_icon_pixmap = 0; - } -} - static void destroyWindow(JNIEnv *env, Display *disp, Window window) { XDestroyWindow(disp, window); XFreeColormap(disp, cmap); - freeIconPixmap(disp); } static bool isNetWMFullscreenSupported(JNIEnv *env, Display *disp, int screen) { @@ -362,14 +348,6 @@ static void updateWindowHints(JNIEnv *env, Display *disp, Window window) { win_hints->flags = InputHint; win_hints->input = True; - if (current_icon_pixmap != 0) { - win_hints->flags |= IconPixmapHint; - win_hints->icon_pixmap = current_icon_pixmap; - } - if (current_icon_mask_pixmap != 0) { - win_hints->flags |= IconMaskHint; - win_hints->icon_mask = current_icon_mask_pixmap; - } XSetWMHints(disp, window, win_hints); XFree(win_hints); @@ -587,57 +565,30 @@ JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nUnlockAWT(JNIEnv *env jawt.Unlock(env); } -static Pixmap createPixmapFromBuffer(JNIEnv *env, Display *disp, Window window, char *data, int data_size, int width, int height, int format, int depth) { - Pixmap pixmap = XCreatePixmap(disp, window, width, height, depth); - // We need to copy the image data since XDestroyImage will also free its data buffer, which can't be allowed - // since the data buffer is managed by the jvm (it's the storage for the direct ByteBuffer) - char *icon_copy = (char *)malloc(sizeof(*icon_copy)*data_size); - - if (icon_copy == NULL) { - XFreePixmap(disp, pixmap); - throwException(env, "malloc failed"); - return None; - } - memcpy(icon_copy, data, data_size); - XImage *image = XCreateImage(disp, current_visual, depth, format, 0, icon_copy, width, height, 32, 0); - if (image == NULL) { - XFreePixmap(disp, pixmap); - free(icon_copy); - throwException(env, "XCreateImage failed"); - return None; - } - - GC gc = XCreateGC(disp, pixmap, 0, NULL); - XPutImage(disp, pixmap, gc, image, 0, 0, 0, 0, width, height); - XFreeGC(disp, gc); - XDestroyImage(image); - // We won't free icon_copy because it is freed by XDestroyImage - return pixmap; -} - -static void setIcon(JNIEnv *env, Display *disp, Window window, char *rgb_data, int rgb_size, char *mask_data, int mask_size, int width, int height) { - freeIconPixmap(disp); - current_icon_pixmap = createPixmapFromBuffer(env, disp, window, rgb_data, rgb_size, width, height, ZPixmap, current_depth); - if ((*env)->ExceptionCheck(env)) - return; - current_icon_mask_pixmap = createPixmapFromBuffer(env, disp, window, mask_data, mask_size, width, height, XYPixmap, 1); - if ((*env)->ExceptionCheck(env)) { - freeIconPixmap(disp); - return; - } - - updateWindowHints(env, disp, window); -} - JNIEXPORT void JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nSetWindowIcon - (JNIEnv *env, jclass clazz, jlong display, jlong window_ptr, jobject icon_rgb_buffer, jint rgb_size, jobject icon_mask_buffer, jint mask_size, jint width, jint height) + (JNIEnv *env, jclass clazz, jlong display, jlong window_ptr, jobject icons_buffer, jint icons_buffer_size) { Display *disp = (Display *)(intptr_t)display; Window window = (Window)window_ptr; - char *rgb_data= (char *)(*env)->GetDirectBufferAddress(env, icon_rgb_buffer); - char *mask_data= (char *)(*env)->GetDirectBufferAddress(env, icon_mask_buffer); + const unsigned char *icons_char_buffer = (const unsigned char *)(*env)->GetDirectBufferAddress(env, icons_buffer); + + int length = icons_buffer_size/4; + unsigned long icons_long_buffer[length]; + int i = 0; - setIcon(env, disp, window, rgb_data, rgb_size, mask_data, mask_size, width, height); + // copy byte array to long array + for (i = 0; i < icons_buffer_size; i += 4) { + unsigned long argb = (icons_char_buffer[i] << 24) | + (icons_char_buffer[i+1] << 16) | + (icons_char_buffer[i+2] << 8) | + (icons_char_buffer[i+3]); + icons_long_buffer[i/4] = argb; + } + + XChangeProperty(disp, window, + XInternAtom(disp, "_NET_WM_ICON", False), + XInternAtom(disp, "CARDINAL", False), + 32, PropModeReplace, (const unsigned char*) icons_long_buffer, length); } JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_LinuxDisplay_nUngrabKeyboard(JNIEnv *env, jclass unused, jlong display_ptr) {