2002/06/04 04:46:52
[org.ibex.core.git] / src / org / xwt / plat / POSIX.cc
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 $ */