Implement 8 bit Icon transparency support on Linux, now using the modern
_NET_WM_ICON method to set the icon, removed legacy method and associated code.
This commit is contained in:
parent
4d0aebb39d
commit
98f8bddce3
|
@ -1202,7 +1202,7 @@ public final class Display {
|
|||
* <li>Linux (and similar platforms) expect one 32x32 icon.</li>
|
||||
* <li>Mac OS X should be supplied one 128x128 icon</li>
|
||||
* </ul>
|
||||
* 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.
|
||||
* <p/>
|
||||
* <b>NOTE:</b> 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
|
||||
|
|
|
@ -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<<mask_bit_index)) & 0xff);
|
||||
icon_mask.put(mask_byte_index, new_byte);
|
||||
|
||||
if (bufferSize == 0) return null;
|
||||
|
||||
ByteBuffer icon_argb = BufferUtils.createByteBuffer(bufferSize);//icon.capacity()+(2*4));
|
||||
icon_argb.order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
for ( ByteBuffer icon : icons ) {
|
||||
int size = icon.limit() / 4;
|
||||
int dimension = (int)Math.sqrt(size);
|
||||
|
||||
icon_argb.putInt(dimension); // width
|
||||
icon_argb.putInt(dimension); // height
|
||||
|
||||
for (int y = 0; y < dimension; y++) {
|
||||
for (int x = 0; x < dimension; x++) {
|
||||
|
||||
byte r = icon.get((x*4)+(y*dimension*4));
|
||||
byte g = icon.get((x*4)+(y*dimension*4)+1);
|
||||
byte b = icon.get((x*4)+(y*dimension*4)+2);
|
||||
byte a = icon.get((x*4)+(y*dimension*4)+3);
|
||||
|
||||
icon_argb.put(a);
|
||||
icon_argb.put(r);
|
||||
icon_argb.put(g);
|
||||
icon_argb.put(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
return icon_mask;
|
||||
|
||||
return icon_argb;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1394,17 +1403,11 @@ final class LinuxDisplay implements DisplayImplementation {
|
|||
try {
|
||||
incDisplay();
|
||||
try {
|
||||
for ( ByteBuffer icon : icons ) {
|
||||
int size = icon.limit() / 4;
|
||||
int dimension = (int)Math.sqrt(size);
|
||||
if ( dimension > 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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue