// 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;
// 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); }
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();
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);
// 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;
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;
/** 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();
}
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();
}
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);
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);