2002/06/04 04:46:52
authormegacz <megacz@xwt.org>
Fri, 30 Jan 2004 06:47:48 +0000 (06:47 +0000)
committermegacz <megacz@xwt.org>
Fri, 30 Jan 2004 06:47:48 +0000 (06:47 +0000)
darcs-hash:20040130064748-2ba56-c927cb81cccae3aa7de57aeda25d84b082ec655f.gz

CHANGES
src/org/xwt/plat/POSIX.cc
src/org/xwt/plat/POSIX.java

diff --git a/CHANGES b/CHANGES
index b78b203..c15cc96 100644 (file)
--- a/CHANGES
+++ b/CHANGES
 
 01-Jun megacz Main.java: custom splash screen support
 
+01-Jun megacz POSIX.cc, POSIX.java: finally completed POSIX support
+
index b5d4662..c07ec1c 100644 (file)
@@ -1,3 +1,6 @@
+// Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
+// see below for copyright information on the second portion of this file
+
 #include <sys/ipc.h>
 #include <sys/shm.h>
 #include <X11/Xlib.h>
@@ -13,6 +16,7 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <gcj/cni.h>
+#include <signal.h>
 
 #include <java/lang/String.h>
 #include <org/xwt/Surface.h>
@@ -38,131 +42,91 @@ static XStandardColormap* colormap_info;
 static XShmSegmentInfo shm_info;
 static Window selectionWindow;
 static int shm_supported;
+static int shm_pixmaps_supported;
 static int screen_num;
 static int colorDepth = 0;
 static Display* display;
+static int shm_size = 0;
 
-#define min(a, b) (a < b ? a : b)
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) < (b) ? (b) : (a))
 
 // X11DoubleBuffer //////////////////////////////////////////////////////////////////////
 
-void org::xwt::plat::POSIX$X11DoubleBuffer::drawPicture(org::xwt::Picture* s,
-                                                        jint dx1, jint dy1, jint dx2, jint dy2, jint sx1, jint sy1, jint sx2, jint sy2) {
-    
-    if (pm == NULL) return;
+// ensures that the shared memory is at least size bytes; if not, allocates 3/2 * size
+static void ensureShmSize(int size) {
+    if (size > shm_size) {
+        if (shm_size > 0) {
+            XShmDetach(display, &shm_info);
+            shmdt(shm_info.shmaddr);
+            shmctl(shm_info.shmid, IPC_RMID, 0);
+        }
+        shm_size = 3 * size / 2;
+        shm_info.shmid = shmget(IPC_PRIVATE, shm_size, IPC_CREAT | 0777 | IPC_EXCL);
+        shm_info.shmaddr = (char*)shmat(shm_info.shmid, 0, 0);
+        shm_info.readOnly = False;
+        XSync(display, False);
+        shmctl(shm_info.shmid, IPC_RMID, 0);
+        XShmAttach(display, &shm_info);
+        XSync(display, False);
+    }
+}
+
+void org::xwt::plat::POSIX$X11DoubleBuffer::fastDrawPicture(org::xwt::Picture* s,
+                                                            jint dx1, jint dy1, jint dx2, jint dy2, jint sx1, jint sy1, jint sx2, jint sy2) {
     org::xwt::plat::POSIX$X11Picture* source = (org::xwt::plat::POSIX$X11Picture*)s;
-    
-    int scaling = dx2 - dx1 != sx2 - sx1 || dy2 - dy1 != sy2 - sy1;
-    
-    // FIXME: this needs to be moved into the fastpath-only to prevent image wriggling
+
+    // it's safe to clip manually since we no that no scaling will be done
     if (dx1 < clipx) { sx1 += ((clipx - dx1) * (sx2 - sx1)) / (dx2 - dx1); dx1 = clipx; }
     if (dy1 < clipy) { sy1 += ((clipy - dy1) * (sy2 - sy1)) / (dy2 - dy1); dy1 = clipy; }
     if (dx2 > clipx + clipw) { sx2 -= ((dx2 - clipx - clipw) * (sx2 - sx1)) / (dx2 - dx1); dx2 = clipx + clipw; }
     if (dy2 > clipy + cliph) { sy2 -= ((dy2 - clipy - cliph) * (sy2 - sy1)) / (dy2 - dy1); dy2 = clipy + cliph; }
     if (dx1 > clipx + clipw) return;
     if (dy1 > clipy + cliph) return;
-
     if (dx2 - dx1 <= 0 || dy2 - dy1 <= 0) return;
-
-    // fastpath: if the X11Picture has a pixmap, and no scaling, and all-or-nothing alpha
-    if (!scaling && source->doublebuf != NULL) {
-        if (source->doublebuf->stipple != NULL) {
-            XSetClipMask(display, (*((GC*)clipped_gc)), *((Pixmap*)source->doublebuf->stipple));
-            XSetClipOrigin(display, (*((GC*)clipped_gc)), dx1 - sx1, dy1 - sy1);
-        } else {
-            XSetClipMask(display, (*((GC*)clipped_gc)), None);
-        }
-        XCopyArea(display, *((Pixmap*)source->doublebuf->pm), (*((Pixmap*)pm)), (*((GC*)clipped_gc)), sx1, sy1, sx2 - sx1, sy2 - sy1, dx1, dy1);
-        return;
+    
+    if (source->doublebuf->stipple != NULL) {
+        XSetClipMask(display, (*((GC*)clipped_gc)), *((Pixmap*)source->doublebuf->stipple));
+        XSetClipOrigin(display, (*((GC*)clipped_gc)), dx1 - sx1, dy1 - sy1);
+    } else {
+        XSetClipMask(display, (*((GC*)clipped_gc)), None);
     }
+    XCopyArea(display, *((Pixmap*)source->doublebuf->pm), (*((Pixmap*)pm)), (*((GC*)clipped_gc)), sx1, sy1, sx2 - sx1, sy2 - sy1, dx1, dy1);
+}
 
-    // slowpath: true alpha or scaling
-    
-    // the following optimizations were abandoned because they don't
-    // improve performance in the presence of XSHM extensions, and
-    // therefore aren't worth the code-bloat:
-    // - scaling clipmask bitmaps (and caching them)
-    // - caching pre-scaled XImages
-    
-    // ximage from our destination -- if true_alpha is false, we can use malloc() instead of XGetImage
+void org::xwt::plat::POSIX$X11DoubleBuffer::slowDrawPicture(org::xwt::Picture* s,
+                                                            jint dx1, jint dy1, jint dx2, jint dy2, jint sx1, jint sy1, jint sx2, jint sy2) {
+
+    org::xwt::plat::POSIX$X11Picture* source = (org::xwt::plat::POSIX$X11Picture*)s;
     XImage* xi; 
-    
-    if (force_slowpath && shm_supported) {
-        
-        // if the shared memory area is unsuitable, destroy it
-        
-        if (((XImage*)shm_ximage) != NULL && (dx2 - dx1 != ((XImage*)shm_ximage)->width || dy2 - dy1 != ((XImage*)shm_ximage)->height)) {
-            XShmDetach(display, &shm_info);
-            XDestroyImage(((XImage*)shm_ximage));
-        }
-        
-        // FIXME: replace 4 with something sensible
-        if (((XImage*)shm_ximage) != NULL && (dx2 - dx1) * (dy2 - dy1) * 4 < old_shmsize) {
-            shmdt(shm_info.shmaddr);
-            shmctl(shm_info.shmid, IPC_RMID, 0);
-            memset(&shm_info, 0, sizeof(XShmSegmentInfo));
-            shm_info.shmaddr = NULL;
-        }
-        
-        // if we need to recreate the shared memory area
-        if (shm_info.shmaddr == NULL) {
-            old_shmsize = xi->bytes_per_line * xi->height;
-            memset(&shm_info, 0, sizeof(XShmSegmentInfo));
-            shm_info.shmid = shmget(IPC_PRIVATE, xi->bytes_per_line * xi->height, IPC_CREAT | 0777 | IPC_EXCL);
-            shm_info.shmaddr = xi->data = (char*)shmat(shm_info.shmid, 0, 0);
-            shm_info.readOnly = False;
-            
-            XSync(display, False);
-            shmctl(shm_info.shmid, IPC_RMID, 0);
-            XShmAttach(display, &shm_info);
-            XSync(display, False);
-        }
-        
-        xi = ((XImage*)shm_ximage) = XShmCreateImage(display, visual, colorDepth, ZPixmap, shm_info.shmaddr, &shm_info, dx2 - dx1, dy2 - dy1);
-        
-    } else if (shared_pixmap && shm_supported) {
-        xi = ((XImage*)mxi);
+
+    // FASTEST: shared pixmap; twiddle bits in video ram directly
+    if (shared_pixmap) {
+        XSync(display, False);  // ensure that all pending operations have rendered
+        xi = (XImage*)fake_ximage;
+
+    // MEDIUM: write to a shared ximage, then ask the server to do the blit
+    } else if (shm_supported) {
+        xi = XShmCreateImage(display, visual, colorDepth, ZPixmap, NULL, &shm_info, dx2 - dx1, dy2 - dy1);
+        ensureShmSize(xi->bytes_per_line * xi->height);
+        xi->data = shm_info.shmaddr;
+        XShmGetImage(display, (*((Pixmap*)pm)), xi, dx1, dy1, AllPlanes);
         
+    // SLOWEST: write to an ximage, copy it through the TCP connection, ask the server to do the blit
     } else {
         xi = XGetImage(display, (*((Pixmap*)pm)), dx1, dy1, dx2 - dx1, dy2 - dy1, AllPlanes, ZPixmap);
-        
     }
     
-    // FIXME: xoffset?
-    // FIXME: optimize pixels that have 0xFF or 0x00 alpha
-    // endian issues
-    
-    
-    // further assumption: the only time source->data will be null is
-    // if we're drawing from a bordercache -- but those don't get
-    // stretched.
-    if (source->data == NULL || elements(source->data) == NULL) {
-        printf("AIEEEEE %i %i %i %i\n", dx2 - dx1, dy2 - dy1, sx2 - sx1, sy2 - sy1);
-        return;
-    }
     int* sourcedata = (int*)elements(source->data);
-    
-    for(int y=dy1; y<dy2; y++) {
+    for(int y=max(dy1, clipy); y<min(dy2, clipy + cliph); y++) {
         
-        if (y < clipy || y >= clipy + cliph) continue;
+        char* current_pixel = (xi->data + y * xi->bytes_per_line) +
+            (shared_pixmap ? max(dx1, clipx) * (xi->bits_per_pixel / 8) : - 1 * dy1 * xi->bytes_per_line);
         
-        char* bitstart;
-        if (shared_pixmap && shm_supported) {
-            // FIXME: not sure if bitmap_unit is the right thing
-            bitstart = xi->data + y * xi->bytes_per_line + dx1 * (xi->bits_per_pixel / 8);
-        } else {
-            bitstart = xi->data + (y - dy1) * xi->bytes_per_line;
-        } 
-        
-        for(int x=dx1; x<dx2; x++, bitstart += xi->bits_per_pixel / 8) {
-            
-            if (x < clipx || x >= clipx + clipw) continue;
-            
+        for(int x=max(dx1, clipx); x<min(dx2, clipx + clipw); x++, current_pixel += xi->bits_per_pixel / 8) {
             int source_x = ((x - dx1) * (sx2 - sx1)) / (dx2 - dx1) + sx1;
             int source_y = ((y - dy1) * (sy2 - sy1)) / (dy2 - dy1) + sy1;
             
-            // note that we can assume that source->data exists here, since writeable PixelGrids (ie
-            // doublebuffers) never have true_alpha, and are never scaled.
             int sourcepixel = sourcedata[source_x + source_y * source->getWidth()];
             int alpha = (sourcepixel & 0xFF000000) >> 24;
             int source_red = (sourcepixel & 0x00FF0000) >> 16;
@@ -170,13 +134,14 @@ void org::xwt::plat::POSIX$X11DoubleBuffer::drawPicture(org::xwt::Picture* s,
             int source_blue = (sourcepixel & 0x000000FF);
             int red = 0, blue = 0, green = 0;
             
+            if (alpha == 0x00) continue;
             if (alpha != 0xFF) {
                 int targetpixel;
                 switch (xi->bits_per_pixel) {
-                case 8: targetpixel = (int)(*bitstart); break;
-                case 16: targetpixel = (int)(*((u_int16_t*)bitstart)); break;
-                case 24: targetpixel = (((int)*bitstart) << 16) | (((int)*(bitstart + 1)) << 8) | (((int)*(bitstart + 2))); break;
-                case 32: targetpixel = *((int*)bitstart); break;
+                case 8: targetpixel = (int)(*current_pixel); break;
+                case 16: targetpixel = (int)(*((u_int16_t*)current_pixel)); break;
+                case 24: targetpixel = (((int)*current_pixel) << 16) | (((int)*(current_pixel + 1)) << 8) | (((int)*(current_pixel + 2))); break;
+                case 32: targetpixel = *((int*)current_pixel); break;
                 default: org::xwt::Platform::criticalAbort(JvNewStringLatin1("ERROR: bpp not a multiple of 8!"));
                 }
                 
@@ -197,27 +162,32 @@ void org::xwt::plat::POSIX$X11DoubleBuffer::drawPicture(org::xwt::Picture* s,
             red = ((source_red * colormap_info->red_max * alpha) + (red * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
             green = ((source_green * colormap_info->green_max * alpha) + (green * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
             blue = ((source_blue * colormap_info->blue_max * alpha) + (blue * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
-            
-            int destpixel = red * colormap_info->red_mult + green * colormap_info->green_mult +
+            u_int32_t destpixel = red * colormap_info->red_mult + green * colormap_info->green_mult +
                 blue * colormap_info->blue_mult + colormap_info->base_pixel;
-            
+
             switch (xi->bits_per_pixel) {
-            case 8: *bitstart = (char)(destpixel & 0xFF); break;
-            case 16: *((u_int16_t*)bitstart) = (u_int16_t)destpixel; break;
-            case 24: break; // FIXME, unimplemented
-            case 32: *((int*)bitstart) = destpixel; break;
+            case 8: *current_pixel = (char)(destpixel & 0xFF); break;
+            case 16: *((u_int16_t*)current_pixel) = (u_int16_t)destpixel; break;
+            case 24: {
+                int offset = (int)current_pixel & 0x3;
+                u_int64_t dest = ((u_int64_t)destpixel) << (8 * offset);
+                u_int64_t mask = ((u_int64_t)0xffffff) << (8 * offset);
+                u_int64_t* base = (u_int64_t*)(current_pixel - offset);
+                *base = (*base & ~mask) | dest;
+                break;
+            }
+            case 32: *((u_int32_t*)current_pixel) = destpixel; break;
             default: org::xwt::Platform::criticalAbort(JvNewStringLatin1("ERROR: bpp not a multiple of 8!"));
             }
-            
         }
     }
     
-    if (force_slowpath && shm_supported) {
-        // watch for concurrency issues if we're going to keep the shm region around
-        XShmPutImage(display, (*((Pixmap*)pm)), (*((GC*)gc)), xi, 0, 0, dx1, dy1, dx2 - dx1, dy2 - dy1, False);
+    if (shared_pixmap) {
+        // do nothing, we wrote directly to video memory
         
-    } if (shared_pixmap && shm_supported) {
-        // do nothing, it's all taken care of
+    } else if (shm_supported) {
+        XShmPutImage(display, (*((Pixmap*)pm)), (*((GC*)gc)), xi, 0, 0, dx1, dy1, dx2 - dx1, dy2 - dy1, False);
+        XDestroyImage(xi);
         
     } else {
         XPutImage(display, (*((Pixmap*)pm)), (*((GC*)gc)), xi, 0, 0, dx1, dy1, dx2 - dx1, dy2 - dy1);
@@ -225,37 +195,46 @@ void org::xwt::plat::POSIX$X11DoubleBuffer::drawPicture(org::xwt::Picture* s,
     }
 }
 
+void org::xwt::plat::POSIX$X11DoubleBuffer::finalize() {
+    if (shared_pixmap) {
+        XShmSegmentInfo *sinfo = (XShmSegmentInfo*)shm_segment;
+        XShmDetach(display, sinfo);
+        shmdt(sinfo->shmaddr);
+        shmctl(sinfo->shmid, IPC_RMID, 0);
+        XDestroyImage((XImage*)fake_ximage);
+        free(sinfo);
+    }
+    if (stipple) {
+        XFreePixmap(display, *((Pixmap*)stipple));
+        free(stipple);
+    }
+    XFreePixmap(display, *((Pixmap*)pm));
+    XFreeGC(display, *((GC*)gc));
+    XFreeGC(display, *((GC*)clipped_gc));
+}
+
 void org::xwt::plat::POSIX$X11DoubleBuffer::natInit() {
     
     if (width == 0 || height == 0) return;
-
+    shared_pixmap &= shm_supported & shm_pixmaps_supported; // refuse to use shared pixmaps if we don't have shm
     pm = (gnu::gcj::RawData*)malloc(sizeof(Pixmap));
 
-    if (shared_pixmap && shm_supported) {
-        
-        // FIXME: check if server pixmaps are XYPixmaps
-        printf("CREATING SHARED (*((Pixmap*)pm)) %i %i\n", width, height);
-        
+    if (!shared_pixmap)
+        (*((Pixmap*)pm)) = XCreatePixmap(display, RootWindow(display, screen_num), width, height, colorDepth);
+    else {
         XShmSegmentInfo *sinfo = (XShmSegmentInfo*)malloc(sizeof(XShmSegmentInfo));
-        ((XImage*)mxi) = XShmCreateImage(display, visual, colorDepth, ZPixmap, NULL, sinfo, width, height);
-        
-        memset(sinfo, 0, sizeof(XShmSegmentInfo));
-        
-        sinfo->shmid = shmget(IPC_PRIVATE, ((XImage*)mxi)->bytes_per_line * height, IPC_CREAT | 0777 | IPC_EXCL);
-        ((XImage*)mxi)->data = sinfo->shmaddr = (char*)shmat(sinfo->shmid, 0, 0);
+        shm_segment = (gnu::gcj::RawData*)sinfo;
+        ((XImage*)fake_ximage) = XShmCreateImage(display, visual, colorDepth, ZPixmap, NULL, sinfo, width, height);
+        sinfo->shmid = shmget(IPC_PRIVATE, ((XImage*)fake_ximage)->bytes_per_line * height, IPC_CREAT | 0777 | IPC_EXCL);
+        ((XImage*)fake_ximage)->data = sinfo->shmaddr = (char*)shmat(sinfo->shmid, 0, 0);
         sinfo->readOnly = False;
         XShmAttach(display, sinfo);
-        
         XSync(display, False);
         shmctl(sinfo->shmid, IPC_RMID, 0);
-        
-        (*((Pixmap*)pm)) = XShmCreatePixmap(display, RootWindow(display, 0), sinfo->shmaddr, sinfo, width, height, colorDepth);
+        (*((Pixmap*)pm)) = XShmCreatePixmap(display, RootWindow(display, screen_num), sinfo->shmaddr, sinfo, width, height, colorDepth);
         XSync(display, False);
-        
-    } else {
-        (*((Pixmap*)pm)) = XCreatePixmap(display, RootWindow(display, 0), width, height, colorDepth);
-        
     }
+
     gc = (gnu::gcj::RawData*)malloc(sizeof(GC));
     clipped_gc = (gnu::gcj::RawData*)malloc(sizeof(GC));
     (*((GC*)gc)) = XCreateGC(display, (*((Pixmap*)pm)), 0, 0);
@@ -270,7 +249,7 @@ void org::xwt::plat::POSIX$X11DoubleBuffer::natInit() {
 void org::xwt::plat::POSIX$X11DoubleBuffer::createStipple(org::xwt::plat::POSIX$X11Picture* xpi) {
 
     stipple = (gnu::gcj::RawData*)malloc(sizeof(Pixmap));
-    (*((Pixmap*)stipple)) = XCreatePixmap(display, RootWindow(display, 0), width, height, 1);
+    (*((Pixmap*)stipple)) = XCreatePixmap(display, RootWindow(display, screen_num), width, height, 1);
 
     XImage xi;
     xi.data = (char*)malloc((width + 1) * height);
@@ -295,7 +274,7 @@ void org::xwt::plat::POSIX$X11DoubleBuffer::createStipple(org::xwt::plat::POSIX$
 
     XGCValues vm;
     vm.graphics_exposures = 0;
-    XChangeGC(display, (*((GC*)stipple_gc)), GCGraphicsExposures, &vm);
+    XChangeGC(display, stipple_gc, GCGraphicsExposures, &vm);
 
     XPutImage(display, (*((Pixmap*)stipple)), stipple_gc, &xi, 0, 0, 0, 0, width, height);
 }
@@ -315,7 +294,7 @@ void org::xwt::plat::POSIX$X11DoubleBuffer::fillRect (jint x, jint y, jint x2, j
     if (y < clipy) { h -= (clipy - y); y = clipy; }
     if (x + w > clipx + clipw) w = (clipx + clipw - x);
     if (y + h > clipy + cliph) h = (cliph + clipy - y);
-    
+
     XSetForeground(display, (*((GC*)gc)),
                    ((((argb & 0x00FF0000) >> 16) * colormap_info->red_max) / 0xFF) * colormap_info->red_mult + 
                    ((((argb & 0x0000FF00) >> 8) * colormap_info->green_max) / 0xFF) * colormap_info->green_mult + 
@@ -324,7 +303,6 @@ void org::xwt::plat::POSIX$X11DoubleBuffer::fillRect (jint x, jint y, jint x2, j
                    );
     
     XFillRectangle(display, (*((Pixmap*)pm)), (*((GC*)gc)), x, y, w, h);
-    
 }
 
 void org::xwt::plat::POSIX$X11DoubleBuffer::drawString(::java::lang::String* font, ::java::lang::String* text, jint x, jint y, jint argb) {
@@ -341,14 +319,15 @@ void org::xwt::plat::POSIX$X11DoubleBuffer::drawString(::java::lang::String* fon
                    );
     
     // Grab the string
-    char buf[text->length() + 1];
-    JvGetStringUTFRegion(text, 0, text->length(), buf);
-    buf[text->length()] = '\0';
+    int len = min(1024, JvGetStringUTFLength(text));
+    char buf[len + 1];
+    JvGetStringUTFRegion(text, 0, len, buf);
+    buf[len] = '\0';
     
     // Build the XTextItem structure
     XTextItem textitem;
     textitem.chars = buf;
-    textitem.nchars = text->length();
+    textitem.nchars = len;
     textitem.delta = 0;
     textitem.font = ((XFontStruct*)org::xwt::plat::POSIX::fontToXFont(font))->fid;
     
@@ -359,6 +338,19 @@ void org::xwt::plat::POSIX$X11DoubleBuffer::drawString(::java::lang::String* fon
 
 // X11Surface //////////////////////////////////////////////////////////////////////
 
+void org::xwt::plat::POSIX$X11Surface::setIcon(org::xwt::Picture* pic) {
+    org::xwt::plat::POSIX$X11Picture* p = ((org::xwt::plat::POSIX$X11Picture*)pic);
+    org::xwt::plat::POSIX$X11DoubleBuffer* old_dbuf = p->doublebuf;
+    p->buildDoubleBuffer(1);
+    XWMHints xwmh;
+    memset(&xwmh, 0, sizeof(XWMHints));
+    xwmh.flags |= IconPixmapHint | IconMaskHint;
+    xwmh.icon_pixmap = *((Pixmap*)p->doublebuf->pm);
+    xwmh.icon_mask = *((Pixmap*)p->doublebuf->stipple);
+    XSetWMHints(display, (*((Window*)window)), &xwmh);
+    p->doublebuf = old_dbuf;
+}
+
 void org::xwt::plat::POSIX$X11Surface::setTitleBarText(java::lang::String* s) {
     int len = min(JvGetStringUTFLength(s), 1024);
     char buf[len + 1];
@@ -395,9 +387,16 @@ void org::xwt::plat::POSIX$X11Surface::setLocation (jint x, jint y) { XMoveWindo
 void org::xwt::plat::POSIX$X11Surface::toFront() { XRaiseWindow(display, (*((Window*)window))); }
 void org::xwt::plat::POSIX$X11Surface::toBack() { XLowerWindow(display, (*((Window*)window))); }
 
+void org::xwt::plat::POSIX$X11Surface::setInvisible(jboolean i) {
+    if (i) XUnmapWindow(display, (*((Window*)window)));
+    else XMapRaised(display, (*((Window*)window)));
+    XFlush(display);
+}
+
 void org::xwt::plat::POSIX$X11Surface::_setMinimized(jboolean b) {
     if (b) XIconifyWindow(display, (*((Window*)window)), screen_num);
     else XMapRaised(display, (*((Window*)window)));
+    XFlush(display);
 }
 
 void org::xwt::plat::POSIX$X11Surface::natInit() {
@@ -409,12 +408,12 @@ void org::xwt::plat::POSIX$X11Surface::natInit() {
         KeyPressMask | KeyReleaseMask | ButtonPressMask |
         ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
         PointerMotionMask | ButtonMotionMask | ConfigureNotify | FocusChangeMask;
-    *((Window*)window) = XCreateWindow(display, DefaultRootWindow(display), 10, 10, 500, 300, 0,
+    *((Window*)window) = XCreateWindow(display, RootWindow(display, screen_num), 10, 10, 500, 300, 0,
                                        colorDepth, InputOutput, CopyFromParent,
                                        CWColormap | CWBitGravity | CWEventMask, &xswa);
     
     if (!framed) {
-        // FIXME: figure out why this works and make it elegant
+        // I don't know why this works....
         int dat[5] = { 0x2, 0xbffff804, 0x0, 0x817f560, 0x8110694 };
         XChangeProperty(display, (*((Window*)window)),
                         XInternAtom(display, "_MOTIF_WM_HINTS", False),
@@ -615,7 +614,7 @@ void org::xwt::plat::POSIX$X11Surface::dispatchEvent(gnu::gcj::RawData* ev) {
         Window child;
         int x_out, y_out;
         XConfigureEvent* xce = (XConfigureEvent*)(e);
-        XTranslateCoordinates(display, (*((Window*)window)), DefaultRootWindow(display), 0, 0, &x_out, &y_out, &child);
+        XTranslateCoordinates(display, (*((Window*)window)), RootWindow(display, screen_num), 0, 0, &x_out, &y_out, &child);
         if (xce->width != width || xce->height != height) SizeChange(xce->width, xce->height);
         if (x_out != root->abs(0) || y_out != root->abs(1)) PosChange(x_out, y_out);
         
@@ -656,6 +655,29 @@ void org::xwt::plat::POSIX$X11Surface::syncCursor() {
 jint org::xwt::plat::POSIX::_getScreenWidth() { return WidthOfScreen(DefaultScreenOfDisplay(display)); }
 jint org::xwt::plat::POSIX::_getScreenHeight() { return HeightOfScreen(DefaultScreenOfDisplay(display)); }
 
+jstring org::xwt::plat::POSIX::getBrowserEnvString() {
+    char* envstr = getenv("BROWSER");
+    return envstr == NULL ? NULL : JvNewStringLatin1(envstr);
+}
+
+void org::xwt::plat::POSIX::spawnChildProcess(JArray<jstring>* cmd) {
+    jstring* cmdstrings = elements(cmd);
+    char* cmd2[cmd->length + 1];
+    cmd2[cmd->length] = NULL;
+    for(int i=0; i<cmd->length; i++) {
+        cmd2[i] = (char*)malloc(JvGetStringUTFLength(cmdstrings[i]));
+        JvGetStringUTFRegion(cmdstrings[i], 0, JvGetStringUTFLength(cmdstrings[i]), cmd2[i]);
+    }
+
+    if (!fork()) {
+        signal(SIGHUP, SIG_IGN);
+        signal(SIGQUIT, SIG_IGN);
+        signal(SIGINT, SIG_IGN);
+        signal(SIGTERM, SIG_IGN);
+        execvp(cmd2[0], cmd2);
+    }
+}
+
 void org::xwt::plat::POSIX::eventThread() {
     XEvent e;
     while(true) {
@@ -682,6 +704,14 @@ void org::xwt::plat::POSIX::_setClipBoard(jstring s) {
     XSetSelectionOwner(display, XInternAtom(display, "PRIMARY", 0), selectionWindow, CurrentTime);
 }
 
+typedef int (X11ErrorHandler)(Display*, XErrorEvent*);
+int errorHandler(Display* d, XErrorEvent* e) {
+    // this error handler is only installed during the initial
+    // test to see if shm is present
+    java::lang::System::out->println(JvNewStringLatin1("here"));
+    shm_supported = 0;
+}
+
 void org::xwt::plat::POSIX::natInit() {
 
     if (!XInitThreads())
@@ -691,8 +721,21 @@ void org::xwt::plat::POSIX::natInit() {
     screen_num = XDefaultScreen(display);
     colorDepth = (jint)(DefaultDepth(((Display*)display), 0));
     shm_info.shmaddr = NULL;
+
     shm_supported = (XShmQueryExtension(display) == True);
-    //shm_supported = 0;
+    if (shm_supported) {
+        X11ErrorHandler* oldHandler = XSetErrorHandler(errorHandler);
+        XShmSegmentInfo sinfo;
+        sinfo.shmid = shmget(IPC_PRIVATE, 1, IPC_CREAT | 0777 | IPC_EXCL);
+        sinfo.readOnly = False;
+        // if the server is remote, this will trigger the error handler
+        XShmAttach(display, &sinfo);
+        XSync(display, False);
+        XSetErrorHandler(oldHandler);
+    }
+
+    if (shm_supported)
+        shm_pixmaps_supported = (XShmPixmapFormat(display) == ZPixmap);
     
     crosshair = JvNewStringLatin1("crosshair");
     east = JvNewStringLatin1("east");
@@ -722,7 +765,7 @@ void org::xwt::plat::POSIX::natInit() {
     wait_cursor = XCreateFontCursor(display, XC_watch);
     default_cursor = XCreateFontCursor(display, XC_left_ptr);
 
-    selectionWindow = XCreateWindow(display, DefaultRootWindow(display), 0, 0, 1, 1, 0, colorDepth, InputOutput, CopyFromParent, 0, NULL);
+    selectionWindow = XCreateWindow(display, RootWindow(display, screen_num), 0, 0, 1, 1, 0, colorDepth, InputOutput, CopyFromParent, 0, NULL);
     visual = DefaultVisual(display, screen_num);
     char buf[255];
     sprintf(buf, "X11 SHM:    %s", shm_supported ? "enabled" : "disabled");
@@ -786,6 +829,18 @@ jint org::xwt::plat::POSIX::_stringWidth(::java::lang::String* font, ::java::lan
 
 
 //////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//                                                                          //
+// Everything below this point was taken, cut-and-paste, from the           //
+// source for libXmu. It implements the official 'standard colormap         //
+// creation algorithm.                                                      //
+//                                                                          //
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
 
 /* $Xorg: LookupCmap.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */
 
index f331f9a..0be6ced 100644 (file)
@@ -1,15 +1,6 @@
 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
 package org.xwt.plat;
 
-// FIXME: protected void _newBrowserWindow(String url)
-// FIXME: When should I use RootWindow versus DefaultRootWindow?
-// FIXME: Solaris: xwt.altKeyName -> "Meta"
-// FIXME: minimize/taskbar icon
-// FIXME: 15bpp? can't assume depth/8 == bytespp
-// FIXME: check for x resource / memory leaks
-// FIXME: WM_HINTS flags: icon pixmap, icon window [[ have to wait until we have gnome/kde wm's installed ]]
-// FIXME: code-review POSIX.cc
-
 import java.awt.*;
 import java.awt.image.*;
 import gnu.gcj.RawData;
@@ -43,6 +34,7 @@ public class POSIX extends GCJ {
 
     // General Methods ///////////////////////////////////////////////////////
 
+    protected String _getAltKeyName() { return System.getProperty("os.name", "").indexOf("SunOS") != -1 ? "Meta" : "Alt"; }
     protected String[] _listFonts() { return fontList; }
     protected String getDescriptiveName() { return "GCJ Linux Binary"; }
     protected Picture _createPicture(int[] data, int w, int h) { return new POSIX.X11Picture(data, w, h); }
@@ -60,6 +52,34 @@ public class POSIX extends GCJ {
     protected native void eventThread();
     private native void natInit();
 
+    /** returns the $BROWSER environment variable, since System.getenv() is useless */
+    private static native String getBrowserEnvString();
+
+    /** spawns a process which is immune to SIGHUP */
+    private static native void spawnChildProcess(String[] command);
+
+    protected void _newBrowserWindow(String url) {
+        String browserString = getBrowserEnvString();
+        if (browserString == null) {
+            browserString = "netscape " + url;
+        } else if (browserString.indexOf("%s") != -1) {
+            browserString =
+                browserString.substring(0, browserString.indexOf("%s")) +
+                url + browserString.substring(browserString.indexOf("%s") + 2);
+        } else {
+            browserString += " " + url;
+        }
+
+        StringTokenizer st = new StringTokenizer(browserString, " ");
+        String[] cmd = new String[st.countTokens()];
+        for(int i=0; st.hasMoreTokens(); i++) {
+            cmd[i] = st.nextToken();
+            System.out.println(i + ":" + cmd[i]);
+        }
+
+        spawnChildProcess(cmd);
+    }
+
     public POSIX() { }
     public void init() {
         natInit();
@@ -77,9 +97,9 @@ public class POSIX extends GCJ {
         boolean framed = false;
         Semaphore waitForCreation = new Semaphore();
         
-        public void setIcon(Picture p) { /* FIXME */ }
-        public void setInvisible(boolean i) { /* FIXME */ }
+        public native void setInvisible(boolean i);
         public void _setMaximized(boolean m) { if (Log.on) Log.log(this, "POSIX/X11 can't maximize windows"); }
+        public native void setIcon(Picture p);
         public native void _setMinimized(boolean b);
         public native void setTitleBarText(String s);
         public native void setSize(int w, int h);
@@ -104,9 +124,13 @@ public class POSIX extends GCJ {
 
     // Our Subclass of Picture ///////////////////////////////////////////////
 
-    // FIXME: what if display server runs out of pixmap space? Think resource conservation...
-
-    /** Implements a Picture as an X11 Pixmap */
+    /**
+     *  Implements a Picture. No special X11 structure is created
+     *  unless the image has no alpha (in which case a
+     *  non-shared-pixmap DoubleBuffer is created), or all-or-nothing
+     *  alpha (in which case a non-shared-pixmap DoubleBuffer with a
+     *  stipple bitmap is created).
+     */
     public static class X11Picture implements Picture {
         
         int width;
@@ -121,21 +145,36 @@ public class POSIX extends GCJ {
             this.data = data;
             this.width = w;
             this.height = h;
+            boolean needsStipple = false;
 
             // if we have any non-0x00, non-0xFF alphas, we can't double buffer ourselves
             for(int i=0; i<w*h; i++)
-                if ((data[i] & 0xFF000000) != 0xFF000000 && (data[i] & 0xFF000000) != 0x00)
+                if ((data[i] & 0xFF000000) == 0xFF000000)
+                    needsStipple = true;
+                else if ((data[i] & 0xFF000000) != 0x00)
                     return;
 
-            X11DoubleBuffer b = new X11DoubleBuffer(w, h);
+            buildDoubleBuffer(needsStipple);
+        }
+
+        void buildDoubleBuffer(boolean needsStipple) {
+            if (doublebuf != null) return;
+            // no point in using a shared pixmap since we'll only write to this image once
+            X11DoubleBuffer b = new X11DoubleBuffer(width, height, false);
             b.drawPicture(this, 0, 0);
-            b.createStipple(this);
+            if (needsStipple) b.createStipple(this);
             doublebuf = b;
         }
 
     }
 
-    // FIXME: finalizer to free X resources
+    /**
+     *  An X11DoubleBuffer is implemented as an X11 pixmap. "Normal"
+     *  DoubleBuffers will use XShm shared pixmaps if
+     *  available. X11DoubleBuffers created to accelerate Pictures
+     *  with all-or-nothing alpha will not use shared pixmaps, however
+     *  (since they are only written to once.
+     */
     public static class X11DoubleBuffer implements DoubleBuffer {
 
         int clipx, clipy, clipw, cliph;
@@ -147,31 +186,22 @@ public class POSIX extends GCJ {
 
         /** Sets the DoubleBuffer's internal stipple to the alpha==0x00 regions of xpi */
         public native void createStipple(X11Picture xpi);
-
-        static int old_shmsize = 0;
-        static RawData shm_ximage;
-        static int shmsegs = 0;
-        int force_slowpath = 0;
-        RawData mxi = null;
-        int shared_pixmap = 0;
-
-        boolean usePixmap = false;
         
-        /** Pixmap (if any) representing this Picture */
-        RawData pm;
+        RawData pm;                    // Pixmap (if any) representing this Picture
+        boolean shared_pixmap = false; // true if pm is a ShmPixmap
+        RawData fake_ximage = null;    // a 'fake' XImage corresponding to the shared pixmap; gives us the address and depth parameters
+        RawData shm_segment = null;    // XShmSegmentInfo
 
-        /** Graphics Context on pm (never changes, so it's fast) */
-        RawData gc;
-
-        /** Graphics Context on pm, use this one if you need a clip/stipple */
-        RawData clipped_gc;
+        RawData gc;                    // Graphics Context on pm (never changes, so it's fast)
+        RawData clipped_gc;            // Graphics Context on pm, use this one if you need a clip/stipple
 
         /** DoubleBuffer mode */
-        public X11DoubleBuffer(int w, int h) {
+        public X11DoubleBuffer(int w, int h) { this(w, h, true); }
+        public X11DoubleBuffer(int w, int h, boolean shared_pixmap) {
             width = clipw = w;
             height = cliph = h;
             clipx = clipy = 0;
-            shared_pixmap = 1;
+            this.shared_pixmap = shared_pixmap;
             natInit();
         }
 
@@ -186,12 +216,25 @@ public class POSIX extends GCJ {
             drawPicture(source, x, y, x + source.getWidth(), y + source.getHeight(), 0, 0, source.getWidth(), source.getHeight());
         }
 
+        public void drawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2) {
+            if (!(dx2 - dx1 != sx2 - sx1 || dy2 - dy1 != sy2 - sy1) && ((X11Picture)source).doublebuf != null)
+                fastDrawPicture(source, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
+            else 
+                slowDrawPicture(source, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
+        }
+
+        /** fast path for image drawing (no scaling, all-or-nothing alpha) */
+        public native void fastDrawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2);
+
+        /** slow path for image drawing */
+        public native void slowDrawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2);
+
         public int getWidth() { return width; }
         public int getHeight() { return height; }
         public native void natInit();
-        public native void drawPicture(Picture source, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2);
         public native void fillRect(int x, int y, int x2, int y2, int color);
         public native void drawString(String font, String text, int x, int y, int color);
+        public native void finalize();
 
     }