2002/07/01 21:02:57
[org.ibex.core.git] / src / org / xwt / plat / POSIX.java
index f331f9a..f8766ba 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,85 @@ 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 getEnv(String key);
+
+    /** spawns a process which is immune to SIGHUP */
+    private static native void spawnChildProcess(String[] command);
+
+    protected synchronized HTTP.ProxyInfo _detectProxy() {
+
+        HTTP.ProxyInfo ret = new HTTP.ProxyInfo();
+
+        ret.httpProxyHost = getEnv("http_proxy");
+        if (ret.httpProxyHost != null) {
+            if (ret.httpProxyHost.startsWith("http://")) ret.httpProxyHost = ret.httpProxyHost.substring(7);
+            if (ret.httpProxyHost.endsWith("/")) ret.httpProxyHost = ret.httpProxyHost.substring(0, ret.httpProxyHost.length() - 1);
+            if (ret.httpProxyHost.indexOf(':') != -1) {
+                ret.httpProxyPort = Integer.parseInt(ret.httpProxyHost.substring(ret.httpProxyHost.indexOf(':') + 1));
+                ret.httpProxyHost = ret.httpProxyHost.substring(0, ret.httpProxyHost.indexOf(':'));
+            } else {
+                ret.httpProxyPort = 80;
+            }
+        }
+
+        ret.httpsProxyHost = getEnv("https_proxy");
+        if (ret.httpsProxyHost != null) {
+            if (ret.httpsProxyHost.startsWith("https://")) ret.httpsProxyHost = ret.httpsProxyHost.substring(7);
+            if (ret.httpsProxyHost.endsWith("/")) ret.httpsProxyHost = ret.httpsProxyHost.substring(0, ret.httpsProxyHost.length() - 1);
+            if (ret.httpsProxyHost.indexOf(':') != -1) {
+                ret.httpsProxyPort = Integer.parseInt(ret.httpsProxyHost.substring(ret.httpsProxyHost.indexOf(':') + 1));
+                ret.httpsProxyHost = ret.httpsProxyHost.substring(0, ret.httpsProxyHost.indexOf(':'));
+            } else {
+                ret.httpsProxyPort = 80;
+            }
+        }
+
+        ret.socksProxyHost = getEnv("socks_proxy");
+        if (ret.socksProxyHost != null) {
+            if (ret.socksProxyHost.startsWith("socks://")) ret.socksProxyHost = ret.socksProxyHost.substring(7);
+            if (ret.socksProxyHost.endsWith("/")) ret.socksProxyHost = ret.socksProxyHost.substring(0, ret.socksProxyHost.length() - 1);
+            if (ret.socksProxyHost.indexOf(':') != -1) {
+                ret.socksProxyPort = Integer.parseInt(ret.socksProxyHost.substring(ret.socksProxyHost.indexOf(':') + 1));
+                ret.socksProxyHost = ret.socksProxyHost.substring(0, ret.socksProxyHost.indexOf(':'));
+            } else {
+                ret.socksProxyPort = 80;
+            }
+        }
+
+        String noproxy = getEnv("no_proxy");
+        if (noproxy != null) {
+            StringTokenizer st = new StringTokenizer(noproxy, ",");
+            ret.excluded = new String[st.countTokens()];
+            for(int i=0; st.hasMoreTokens(); i++) ret.excluded[i] = st.nextToken();
+        }
+
+        if (ret.httpProxyHost == null && ret.socksProxyHost == null) return null;
+        return ret;
+    }
+
+    protected void _newBrowserWindow(String url) {
+        String browserString = getEnv("BROWSER");
+        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 +148,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 +175,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 +196,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 +237,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;
-
-        /** Graphics Context on pm (never changes, so it's fast) */
-        RawData gc;
+        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, 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 +267,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();
 
     }
 
@@ -213,6 +307,7 @@ public class POSIX extends GCJ {
     public void initFonts() {
         // use the font list to build nativeFontList
         String[] fonts = listNativeFonts();
+
         for(int k=0; k<fonts.length; k++) {
             String s = fonts[k].toLowerCase();
             StringTokenizer st = new StringTokenizer(s, "-", false);
@@ -220,9 +315,16 @@ public class POSIX extends GCJ {
             
             try {
                 for(int i=0; st.hasMoreTokens(); i++) font[i] = st.nextToken();
+
+                // limit to iso8559 until we can do I18N properly....
+                if (font.length > 13) {
+                    if (!font[13].equals("iso8559")) continue;
+                    if (font.length < 15 || !font[14].equals("1")) continue;
+                }
+
                 String name = font[1];
                 String size = font[6];
-                String slant = font[3].equals("i") ? "i" : "";
+                String slant = (font[3].equals("i") || font[3].equals("o")) ? "i" : "";
                 String bold = font[2].equals("bold") ? "b" : "";
                 String tail = s.substring(1 + font[0].length() + 1 + font[1].length() + 1 + font[2].length() + 1 +
                                           font[3].length() + 1 + font[4].length() + 1);