FileDocCategorySizeDatePackage
Metacity.javaAPI DocJava SE 5 API60563Fri Aug 26 14:54:46 BST 2005com.sun.java.swing.plaf.gtk

Metacity

public class Metacity extends Object implements SynthConstants
version
1.23, 08/31/04

Fields Summary
static Metacity
INSTANCE
private static final String[]
themeNames
private static boolean
errorLogged
private static DocumentBuilder
documentBuilder
private static Document
xmlDoc
private static String
userHome
private Node
frame_style_set
private Map
frameGeometry
private Map
frameGeometries
private LayoutManager
titlePaneLayout
private ColorizeImageFilter
imageFilter
private URL
themeDir
private SynthContext
context
private String
themeName
private ArithmeticExpressionEvaluator
aee
private Map
variables
private RoundRectClipShape
roundedClipShape
private HashMap
images
Constructors Summary
protected Metacity(String themeName)


           
	this.themeName = themeName;
	themeDir = getThemeDir(themeName);
	if (themeDir != null) {
	    URL themeURL = new URL(themeDir, "metacity-theme-1.xml");
	    xmlDoc = getXMLDoc(themeURL);
	    if (xmlDoc == null) {
		throw new IOException(themeURL.toString());
	    }
	} else {
	    throw new FileNotFoundException(themeName);
	}

	// Initialize constants
	variables = new HashMap();
	NodeList nodes = xmlDoc.getElementsByTagName("constant");
	int n = nodes.getLength();
	for (int i = 0; i < n; i++) {
	    Node node = nodes.item(i);
	    String name = getStringAttr(node, "name");
	    if (name != null) {
		String value = getStringAttr(node, "value");
		if (value != null) {
		    try {
			variables.put(name, Integer.parseInt(value));
		    } catch (NumberFormatException ex) {
			logError(themeName, ex);
			// Ignore bad value
		    }
		}
	    }
	}

	// Cache frame geometries
	frameGeometries = new HashMap();
	nodes = xmlDoc.getElementsByTagName("frame_geometry");
	n = nodes.getLength();
	for (int i = 0; i < n; i++) {
	    Node node = nodes.item(i);
	    String name = getStringAttr(node, "name");
	    if (name != null) {
		HashMap<String, Object> gm = new HashMap();
		frameGeometries.put(name, gm);

		String parentGM = getStringAttr(node, "parent");
		if (parentGM != null) {
		    gm.putAll(frameGeometries.get(parentGM));
		}

		gm.put("has_title",
		       Boolean.valueOf(getBooleanAttr(node, "has_title",            true)));
		gm.put("rounded_top_left",
		       Boolean.valueOf(getBooleanAttr(node, "rounded_top_left",     false)));
		gm.put("rounded_top_right",
		       Boolean.valueOf(getBooleanAttr(node, "rounded_top_right",    false)));
		gm.put("rounded_bottom_left",
		       Boolean.valueOf(getBooleanAttr(node, "rounded_bottom_left",  false)));
		gm.put("rounded_bottom_right",
		       Boolean.valueOf(getBooleanAttr(node, "rounded_bottom_right", false)));
		
		NodeList childNodes = node.getChildNodes();
		int nc = childNodes.getLength();
		for (int j = 0; j < nc; j++) {
		    Node child = childNodes.item(j);
		    if (child.getNodeType() == Node.ELEMENT_NODE) {
			name = child.getNodeName();
			Object value = null;
			if ("distance".equals(name)) {
			    value = new Integer(getIntAttr(child, "value", 0));
			} else if ("border".equals(name)) {	
			    value = new Insets(getIntAttr(child, "top", 0),
					       getIntAttr(child, "left", 0),
					       getIntAttr(child, "bottom", 0),
					       getIntAttr(child, "right", 0));
			} else if ("aspect_ratio".equals(name)) {
			    value = new Float(getFloatAttr(child, "value", 1.0F));
			} else {
			    logError(themeName, "Unknown Metacity frame geometry value type: "+name);
			}
			String childName = getStringAttr(child, "name");
			if (childName != null && value != null) {
			    gm.put(childName, value);
			}
		    }
		}
	    }
	}
	frameGeometry = frameGeometries.get("normal");
    
Methods Summary
protected java.awt.DimensioncalculateButtonSize(javax.swing.JComponent titlePane)

	int buttonHeight = getInt("button_height");
	if (buttonHeight == 0) {
	    buttonHeight = titlePane.getHeight();
	    if (buttonHeight == 0) {
		buttonHeight = 13;
	    } else {
		Insets button_border = (Insets)frameGeometry.get("button_border");
		if (button_border != null) {
		    buttonHeight -= (button_border.top + button_border.bottom);
		}
	    }
	}
	int buttonWidth = getInt("button_width");
	if (buttonWidth == 0) {
	    buttonWidth = buttonHeight;
	    Float aspect_ratio = (Float)frameGeometry.get("aspect_ratio");
	    if (aspect_ratio != null) {
		buttonWidth = (int)(buttonHeight / aspect_ratio.floatValue());
	    }
	}
	return new Dimension(buttonWidth, buttonHeight);
    
protected java.awt.RectanglecalculateTitleArea(javax.swing.JInternalFrame jif)

	JComponent titlePane = findChild(jif, "InternalFrame.northPane");
	Dimension buttonDim = calculateButtonSize(titlePane);
	Insets title_border = (Insets)frameGeometry.get("title_border");
	Rectangle r = new Rectangle();

	r.x = getInt("left_titlebar_edge") + buttonDim.width;
	r.y = 0;
	r.height = titlePane.getHeight();
	if (title_border != null) {
	    r.x += title_border.left;
	    r.y += title_border.top;
	    r.height -= (title_border.top + title_border.bottom);
	}

	r.width = titlePane.getWidth() - r.x - getInt("right_titlebar_edge");
	if (jif.isClosable()) {
	    r.width -= buttonDim.width;
	}
	if (jif.isMaximizable()) {
	    r.width -= buttonDim.width;
	}
	if (jif.isIconifiable()) {
	    r.width -= buttonDim.width;
	}
	if (title_border != null) {
	    r.width -= title_border.right;
	}
	return r;
    
protected intcalculateTitleTextWidth(java.awt.Graphics g, javax.swing.JInternalFrame jif)

	String title = jif.getTitle();
	if (title != null) {
	    Rectangle r = calculateTitleArea(jif);
	    return Math.min(SwingUtilities2.stringWidth(jif,
                     SwingUtilities2.getFontMetrics(jif, g), title), r.width);
	}
	return 0;
    
protected voiddraw(org.w3c.dom.Node draw_ops, java.awt.Graphics g, javax.swing.JInternalFrame jif)

	if (draw_ops != null) {
	    NodeList nodes = draw_ops.getChildNodes();
	    if (nodes != null) {
		Shape oldClip = g.getClip();
		for (int i = 0; i < nodes.getLength(); i++) {
		    Node child = nodes.item(i);
		    if (child.getNodeType() == Node.ELEMENT_NODE) {
			try {
			    String name = child.getNodeName();
			    if ("include".equals(name)) {
				drawInclude(child, g, jif);
			    } else if ("arc".equals(name)) {
				drawArc(child, g);
			    } else if ("clip".equals(name)) {
				setClip(child, g);
			    } else if ("gradient".equals(name)) {
				drawGradient(child, g);
			    } else if ("gtk_arrow".equals(name)) {
				drawGTKArrow(child, g);
			    } else if ("gtk_box".equals(name)) {
				drawGTKBox(child, g);
			    } else if ("gtk_vline".equals(name)) {
				drawGTKVLine(child, g);
			    } else if ("image".equals(name)) {
				drawImage(child, g);
			    } else if ("icon".equals(name)) {
				drawIcon(child, g, jif);
			    } else if ("line".equals(name)) {
				drawLine(child, g);
			    } else if ("rectangle".equals(name)) {
				drawRectangle(child, g);
			    } else if ("tint".equals(name)) {
				drawTint(child, g);
			    } else if ("tile".equals(name)) {
				drawTile(child, g, jif);
			    } else if ("title".equals(name)) {
				drawTitle(child, g, jif);
			    } else {
				System.err.println("Unknown Metacity drawing op: "+child);
			    }
			} catch (NumberFormatException ex) {
			    logError(themeName, ex);
			}
		    }
		}
		g.setClip(oldClip);
	    }
	}
    
protected voiddrawArc(org.w3c.dom.Node node, java.awt.Graphics g)

	NamedNodeMap attrs = node.getAttributes();
	Color color = parseColor(getStringAttr(attrs, "color"));
	int x = aee.evaluate(getStringAttr(attrs, "x"));
	int y = aee.evaluate(getStringAttr(attrs, "y"));
	int w = aee.evaluate(getStringAttr(attrs, "width"));
	int h = aee.evaluate(getStringAttr(attrs, "height"));
	int start_angle = aee.evaluate(getStringAttr(attrs, "start_angle"));
	int extent_angle = aee.evaluate(getStringAttr(attrs, "extent_angle"));
	boolean filled = getBooleanAttr(node, "filled", false);
	if (getInt("width") == -1) {
	    x -= w;
	}
	if (getInt("height") == -1) {
	    y -= h;
	}
	g.setColor(color);
	if (filled) {
	    g.fillArc(x, y, w, h, start_angle, extent_angle);
	} else {
	    g.drawArc(x, y, w, h, start_angle, extent_angle);
	}
    
protected voiddrawButton(org.w3c.dom.Node frame_style, java.lang.String function, java.lang.String state, java.awt.Graphics g, int w, int h, javax.swing.JInternalFrame jif)

	Node buttonNode = getNode(frame_style, "button",
				  new String[] { "function", function, "state", state });
	if (buttonNode == null && !state.equals("normal")) {
	    buttonNode = getNode(frame_style, "button",
				 new String[] { "function", function, "state", "normal" });
	}
	if (buttonNode != null) {
	    Node draw_ops;
	    String draw_ops_name = getStringAttr(buttonNode, "draw_ops");
	    if (draw_ops_name != null) {
		draw_ops = getNode("draw_ops", new String[] { "name", draw_ops_name });
	    } else {
		draw_ops = getNode(buttonNode, "draw_ops", null);
	    }
	    variables.put("width",  w);
	    variables.put("height", h);
	    draw(draw_ops, g, jif);
	}
    
protected voiddrawGTKArrow(org.w3c.dom.Node node, java.awt.Graphics g)

	NamedNodeMap attrs = node.getAttributes();
	String arrow    = getStringAttr(attrs, "arrow");
	String shadow   = getStringAttr(attrs, "shadow");
	String stateStr = getStringAttr(attrs, "state").toUpperCase();
	int x = aee.evaluate(getStringAttr(attrs, "x"));
	int y = aee.evaluate(getStringAttr(attrs, "y"));
	int w = aee.evaluate(getStringAttr(attrs, "width"));
	int h = aee.evaluate(getStringAttr(attrs, "height"));

	int state = -1;
	if ("NORMAL".equals(stateStr)) {
	    state = ENABLED;
	} else if ("SELECTED".equals(stateStr)) {
	    state = SELECTED;
	} else if ("INSENSITIVE".equals(stateStr)) {
	    state = DISABLED;
	} else if ("PRELIGHT".equals(stateStr)) {
	    state = MOUSE_OVER;
	}

	int shadowType = -1;
	if ("in".equals(shadow)) {
	    shadowType = GTKConstants.SHADOW_IN;
	} else if ("out".equals(shadow)) {
	    shadowType = GTKConstants.SHADOW_OUT;
	} else if ("etched_in".equals(shadow)) {
	    shadowType = GTKConstants.SHADOW_ETCHED_IN;
	} else if ("etched_out".equals(shadow)) {
	    shadowType = GTKConstants.SHADOW_ETCHED_OUT;
	} else if ("none".equals(shadow)) {
	    shadowType = GTKConstants.SHADOW_NONE;
	}
	int direction = -1;
	if ("up".equals(arrow)) {
	    direction = GTKConstants.ARROW_UP;
	} else if ("down".equals(arrow)) {
	    direction = GTKConstants.ARROW_DOWN;
	} else if ("left".equals(arrow)) {
	    direction = GTKConstants.ARROW_LEFT;
	} else if ("right".equals(arrow)) {
	    direction = GTKConstants.ARROW_RIGHT;
	}
	GTKEngine engine = ((GTKStyle)context.getStyle()).getEngine(context);
	engine.paintArrow(context, g, state, shadowType,
			  direction, null, x, y, w, h);
    
protected voiddrawGTKBox(org.w3c.dom.Node node, java.awt.Graphics g)

	NamedNodeMap attrs = node.getAttributes();
	String shadow   = getStringAttr(attrs, "shadow");
	String stateStr = getStringAttr(attrs, "state").toUpperCase();
	int x = aee.evaluate(getStringAttr(attrs, "x"));
	int y = aee.evaluate(getStringAttr(attrs, "y"));
	int w = aee.evaluate(getStringAttr(attrs, "width"));
	int h = aee.evaluate(getStringAttr(attrs, "height"));

	int state = -1;
	if ("NORMAL".equals(stateStr)) {
	    state = ENABLED;
	} else if ("SELECTED".equals(stateStr)) {
	    state = SELECTED;
	} else if ("INSENSITIVE".equals(stateStr)) {
	    state = DISABLED;
	} else if ("PRELIGHT".equals(stateStr)) {
	    state = MOUSE_OVER;
	}

	int shadowType = -1;
	if ("in".equals(shadow)) {
	    shadowType = GTKConstants.SHADOW_IN;
	} else if ("out".equals(shadow)) {
	    shadowType = GTKConstants.SHADOW_OUT;
	} else if ("etched_in".equals(shadow)) {
	    shadowType = GTKConstants.SHADOW_ETCHED_IN;
	} else if ("etched_out".equals(shadow)) {
	    shadowType = GTKConstants.SHADOW_ETCHED_OUT;
	} else if ("none".equals(shadow)) {
	    shadowType = GTKConstants.SHADOW_NONE;
	}
	GTKEngine.INSTANCE.paintBox(context, g, state, shadowType,
				    null, x, y, w, h);
    
protected voiddrawGTKVLine(org.w3c.dom.Node node, java.awt.Graphics g)

	NamedNodeMap attrs = node.getAttributes();
	String stateStr = getStringAttr(attrs, "state").toUpperCase();

	int x  = aee.evaluate(getStringAttr(attrs, "x"));
	int y1 = aee.evaluate(getStringAttr(attrs, "y1"));
	int y2 = aee.evaluate(getStringAttr(attrs, "y2"));

	int state = -1;
	if ("NORMAL".equals(stateStr)) {
	    state = ENABLED;
	} else if ("SELECTED".equals(stateStr)) {
	    state = SELECTED;
	} else if ("INSENSITIVE".equals(stateStr)) {
	    state = DISABLED;
	} else if ("PRELIGHT".equals(stateStr)) {
	    state = MOUSE_OVER;
	}

	GTKEngine.INSTANCE.paintVline(context, g, state, null, x, y1, 1, y2-y1);
    
protected voiddrawGradient(org.w3c.dom.Node node, java.awt.Graphics g)

	NamedNodeMap attrs = node.getAttributes();
	String type = getStringAttr(attrs, "type");
	float alpha = getFloatAttr(node, "alpha", -1F);
	int x = aee.evaluate(getStringAttr(attrs, "x"));
	int y = aee.evaluate(getStringAttr(attrs, "y"));
	int w = aee.evaluate(getStringAttr(attrs, "width"));
	int h = aee.evaluate(getStringAttr(attrs, "height"));
	if (getInt("width") == -1) {
	    x -= w;
	}
	if (getInt("height") == -1) {
	    y -= h;
	}

	// Get colors from child nodes
	Node[] colorNodes = getNodesByName(node, "color");
	Color[] colors = new Color[colorNodes.length];
	for (int i = 0; i < colorNodes.length; i++) {
	    colors[i] = parseColor(getStringAttr(colorNodes[i], "value"));
	}

	boolean horizontal = ("diagonal".equals(type) || "horizontal".equals(type));
	boolean vertical   = ("diagonal".equals(type) || "vertical".equals(type));

	if (g instanceof Graphics2D) {
	    Graphics2D g2 = (Graphics2D)g;
	    Composite oldComp = g2.getComposite();
	    if (alpha >= 0F) {
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
	    }
	    int n = colors.length - 1;
	    for (int i = 0; i < n; i++) {
		g2.setPaint(new GradientPaint(x + (horizontal ? (i*w/n) : 0),
					      y + (vertical   ? (i*h/n) : 0),
					      colors[i],
					      x + (horizontal ? ((i+1)*w/n) : 0),
					      y + (vertical   ? ((i+1)*h/n) : 0),
					      colors[i+1]));
		g2.fillRect(x + (horizontal ? (i*w/n) : 0),
			    y + (vertical   ? (i*h/n) : 0),
			    (horizontal ? (w/n) : w),
			    (vertical   ? (h/n) : h));
	    }
	    g2.setComposite(oldComp);
	}
    
protected voiddrawIcon(org.w3c.dom.Node node, java.awt.Graphics g, javax.swing.JInternalFrame jif)

	Icon icon = jif.getFrameIcon();
	if (icon == null) {
	    return;
	}

	NamedNodeMap attrs = node.getAttributes();
	String alpha = getStringAttr(attrs, "alpha");
	int x = aee.evaluate(getStringAttr(attrs, "x"));
	int y = aee.evaluate(getStringAttr(attrs, "y"));
	int w = aee.evaluate(getStringAttr(attrs, "width"));
	int h = aee.evaluate(getStringAttr(attrs, "height"));
	if (getInt("width") == -1) {
	    x -= w;
	}
	if (getInt("height") == -1) {
	    y -= h;
	}

	if (alpha != null) {
	    float a = Float.parseFloat(alpha);
	    if (g instanceof Graphics2D) {
		Graphics2D g2 = (Graphics2D)g;
		Composite oldComp = g2.getComposite();
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, a));
		icon.paintIcon(jif, g, x, y);
		g2.setComposite(oldComp);
	    }
	} else {
	    icon.paintIcon(jif, g, x, y);
	}
    
protected voiddrawImage(org.w3c.dom.Node node, java.awt.Graphics g)

	NamedNodeMap attrs = node.getAttributes();
	String filename = getStringAttr(attrs, "filename");
	String colorizeStr = getStringAttr(attrs, "colorize");
	Color colorize = (colorizeStr != null) ? parseColor(colorizeStr) : null;
	String alpha = getStringAttr(attrs, "alpha");
	Image object = (colorize != null) ? getImage(filename, colorize) : getImage(filename);
	variables.put("object_width",  object.getWidth(null));
	variables.put("object_height", object.getHeight(null));
	String fill_type = getStringAttr(attrs, "fill_type"); 
	int x = aee.evaluate(getStringAttr(attrs, "x"));
	int y = aee.evaluate(getStringAttr(attrs, "y"));
	int w = aee.evaluate(getStringAttr(attrs, "width"));
	int h = aee.evaluate(getStringAttr(attrs, "height"));
	if (getInt("width") == -1) {
	    x -= w;
	}
	if (getInt("height") == -1) {
	    y -= h;
	}

	if (alpha != null) {
	    if ("tile".equals(fill_type)) {
		StringTokenizer tokenizer = new StringTokenizer(alpha, ":");
		float[] alphas = new float[tokenizer.countTokens()];
		for (int i = 0; i < alphas.length; i++) {
		    alphas[i] = Float.parseFloat(tokenizer.nextToken());
		}
		tileImage(g, object, x, y, w, h, alphas);
	    } else {
		float a = Float.parseFloat(alpha);
		if (g instanceof Graphics2D) {
		    Graphics2D g2 = (Graphics2D)g;
		    Composite oldComp = g2.getComposite();
		    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, a));
		    g2.drawImage(object, x, y, w, h, null);
		    g2.setComposite(oldComp);
		}
	    }
	} else {
	    g.drawImage(object, x, y, w, h, null);
	}
    
protected voiddrawInclude(org.w3c.dom.Node node, java.awt.Graphics g, javax.swing.JInternalFrame jif)

	int oldWidth  = getInt("width");
	int oldHeight = getInt("height");

	NamedNodeMap attrs = node.getAttributes();
	int x = aee.evaluate(getStringAttr(attrs, "x"),       0);
	int y = aee.evaluate(getStringAttr(attrs, "y"),       0);
	int w = aee.evaluate(getStringAttr(attrs, "width"),  -1);
	int h = aee.evaluate(getStringAttr(attrs, "height"), -1);

	if (w != -1) {
	    variables.put("width",  w);
	}
	if (h != -1) {
	    variables.put("height", h);
	}

	Node draw_ops = getNode("draw_ops", new String[] {
	    "name", getStringAttr(node, "name")
	});
	g.translate(x, y);
	draw(draw_ops, g, jif);
	g.translate(-x, -y);

	if (w != -1) {
	    variables.put("width",  oldWidth);
	}
	if (h != -1) {
	    variables.put("height", oldHeight);
	}
    
protected voiddrawLine(org.w3c.dom.Node node, java.awt.Graphics g)

	NamedNodeMap attrs = node.getAttributes();
	Color color = parseColor(getStringAttr(attrs, "color"));
	int x1 = aee.evaluate(getStringAttr(attrs, "x1"));
	int y1 = aee.evaluate(getStringAttr(attrs, "y1"));
	int x2 = aee.evaluate(getStringAttr(attrs, "x2"));
	int y2 = aee.evaluate(getStringAttr(attrs, "y2"));
	int lineWidth = aee.evaluate(getStringAttr(attrs, "width"), 1);
	g.setColor(color);
	if (lineWidth != 1) {
	    Graphics2D g2d = (Graphics2D)g;
	    Stroke stroke = g2d.getStroke();
	    g2d.setStroke(new BasicStroke((float)lineWidth));
	    g2d.drawLine(x1, y1, x2, y2);
	    g2d.setStroke(stroke);
	} else {
	    g.drawLine(x1, y1, x2, y2);
	}
    
protected voiddrawPiece(org.w3c.dom.Node frame_style, java.awt.Graphics g, java.lang.String position, int x, int y, int width, int height, javax.swing.JInternalFrame jif)

	Node piece = getNode(frame_style, "piece", new String[] { "position", position });
	if (piece != null) {
	    Node draw_ops;
	    String draw_ops_name = getStringAttr(piece, "draw_ops");
	    if (draw_ops_name != null) {
		draw_ops = getNode("draw_ops", new String[] { "name", draw_ops_name });
	    } else {
		draw_ops = getNode(piece, "draw_ops", null);
	    }
	    variables.put("width",  width);
	    variables.put("height", height);
	    g.translate(x, y);
	    draw(draw_ops, g, jif);
	    g.translate(-x, -y);
	}
    
protected voiddrawRectangle(org.w3c.dom.Node node, java.awt.Graphics g)

	NamedNodeMap attrs = node.getAttributes();
	Color color = parseColor(getStringAttr(attrs, "color"));
	boolean filled = getBooleanAttr(node, "filled", false);
	int x = aee.evaluate(getStringAttr(attrs, "x"));
	int y = aee.evaluate(getStringAttr(attrs, "y"));
	int w = aee.evaluate(getStringAttr(attrs, "width"));
	int h = aee.evaluate(getStringAttr(attrs, "height"));
	g.setColor(color);
	if (getInt("width") == -1) {
	    x -= w;
	}
	if (getInt("height") == -1) {
	    y -= h;
	}
	if (filled) {
	    g.fillRect(x, y, w, h);
	} else {
	    g.drawRect(x, y, w, h);
	}
    
protected voiddrawTile(org.w3c.dom.Node node, java.awt.Graphics g, javax.swing.JInternalFrame jif)

	NamedNodeMap attrs = node.getAttributes();
	int x0 = aee.evaluate(getStringAttr(attrs, "x"));
	int y0 = aee.evaluate(getStringAttr(attrs, "y"));
	int w = aee.evaluate(getStringAttr(attrs, "width"));
	int h = aee.evaluate(getStringAttr(attrs, "height"));
	int tw = aee.evaluate(getStringAttr(attrs, "tile_width"));
	int th = aee.evaluate(getStringAttr(attrs, "tile_height"));
	int width  = getInt("width");
	int height = getInt("height");
	if (width == -1) {
	    x0 -= w;
	}
	if (height == -1) {
	    y0 -= h;
	}
	Shape oldClip = g.getClip();
	if (g instanceof Graphics2D) {
	    ((Graphics2D)g).clip(new Rectangle(x0, y0, w, h));
	}
	variables.put("width",  tw);
	variables.put("height", th);

	Node draw_ops = getNode("draw_ops", new String[] { "name", getStringAttr(node, "name") });
	
	int y = y0;
	while (y < y0 + h) {
	    int x = x0;
	    while (x < x0 + w) {
		g.translate(x, y);
		draw(draw_ops, g, jif);
		g.translate(-x, -y);
		x += tw;
	    }
	    y += th;
	}

	variables.put("width",  width);
	variables.put("height", height);
	g.setClip(oldClip);
    
protected voiddrawTint(org.w3c.dom.Node node, java.awt.Graphics g)

	NamedNodeMap attrs = node.getAttributes();
	Color color = parseColor(getStringAttr(attrs, "color"));
	float alpha = Float.parseFloat(getStringAttr(attrs, "alpha"));
	int x = aee.evaluate(getStringAttr(attrs, "x"));
	int y = aee.evaluate(getStringAttr(attrs, "y"));
	int w = aee.evaluate(getStringAttr(attrs, "width"));
	int h = aee.evaluate(getStringAttr(attrs, "height"));
	if (getInt("width") == -1) {
	    x -= w;
	}
	if (getInt("height") == -1) {
	    y -= h;
	}
	if (g instanceof Graphics2D) {
	    Graphics2D g2 = (Graphics2D)g;
	    Composite oldComp = g2.getComposite();
	    AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
	    g2.setComposite(ac);
	    g2.setColor(color);
	    g2.fillRect(x, y, w, h);
	    g2.setComposite(oldComp);
	}
    
protected voiddrawTitle(org.w3c.dom.Node node, java.awt.Graphics g, javax.swing.JInternalFrame jif)

	NamedNodeMap attrs = node.getAttributes();
	String colorStr = getStringAttr(attrs, "color");
	int i = colorStr.indexOf("gtk:fg[");
	if (i > 0) {
	    colorStr = colorStr.substring(0, i) + "gtk:text[" + colorStr.substring(i+7);
	}
	Color color = parseColor(colorStr);
	int x = aee.evaluate(getStringAttr(attrs, "x"));
	int y = aee.evaluate(getStringAttr(attrs, "y"));

	String title = jif.getTitle();
        if (title != null) {
            FontMetrics fm = SwingUtilities2.getFontMetrics(jif, g);
	    if (jif.getComponentOrientation().isLeftToRight()) {
		title = SwingUtilities2.clipStringIfNecessary(jif, fm, title,
                             calculateTitleTextWidth(g, jif));
	    }
	    g.setColor(color);
            SwingUtilities2.drawString(jif, g, title, x, y + fm.getAscent());
        }
    
protected static javax.swing.JComponentfindChild(javax.swing.JComponent parent, java.lang.String name)

	int n = parent.getComponentCount();
	for (int i = 0; i < n; i++) {
	    JComponent c = (JComponent)parent.getComponent(i);
	    if (name.equals(c.getName())) {
		return c;
	    }
	}
	return null;
    
protected booleangetBoolean(java.lang.String key, boolean fallback)

	Boolean b = (Boolean)frameGeometry.get(key);
	return (b != null) ? b.booleanValue() : fallback;
    
protected booleangetBooleanAttr(org.w3c.dom.Node node, java.lang.String name, boolean fallback)

	String str = getStringAttr(node, name);
	if (str != null) {
	    return Boolean.valueOf(str).booleanValue();
	}
	return fallback;
    
java.awt.InsetsgetBorderInsets(javax.swing.plaf.synth.SynthContext context, java.awt.Insets insets)

	if (insets == null) {
	    insets = new Insets(0, 0, 0, 0);
	}
	insets.top    = ((Insets)frameGeometry.get("title_border")).top;
	insets.bottom = getInt("bottom_height");
	insets.left   = getInt("left_width");
	insets.right  = getInt("right_width");
	return insets;
    
protected floatgetFloatAttr(org.w3c.dom.Node node, java.lang.String name, float fallback)

	String str = getStringAttr(node, name);
	float value = fallback;
	if (str != null) {
	    try {
		value = Float.parseFloat(str);
	    } catch (NumberFormatException ex) {
		logError(themeName, ex);
	    }
	}
	return value;
    
protected java.util.MapgetFrameGeometry()

	return frameGeometry;
    
protected java.awt.ImagegetImage(java.lang.String key, java.awt.Color c)


          
	Image image = images.get(key+"-"+c.getRGB());
	if (image == null) {
	    image = imageFilter.colorize(getImage(key), c);
	    if (image != null) {
		images.put(key+"-"+c.getRGB(), image);
	    }
	}
	return image;
    
protected java.awt.ImagegetImage(java.lang.String key)

	Image image = images.get(key);
	if (image == null) {
	    if (themeDir != null) {
		try {
		    URL url = new URL(themeDir, key);
		    image = (Image)new Privileged().doPrivileged(Privileged.GET_IMAGE, url);
		} catch (MalformedURLException ex) {
		    //log("Bad image url: "+ themeDir + "/" + key);
		}
	    }
	    if (image != null) {
		images.put(key, image);
	    }
	}
	return image;
    
protected intgetInt(java.lang.String key)

	Integer i = (Integer)frameGeometry.get(key);
	if (i == null) {
	    i = variables.get(key);
	}
	return (i != null) ? i.intValue() : 0;
    
protected intgetIntAttr(org.w3c.dom.Node node, java.lang.String name, int fallback)

	String str = getStringAttr(node, name);
	int value = fallback;
	if (str != null) {
	    try {
		value = Integer.parseInt(str);
	    } catch (NumberFormatException ex) {
		logError(themeName, ex);
	    }
	}
	return value;
    
protected org.w3c.dom.NodegetNode(java.lang.String tagName, java.lang.String[] attrs)

	NodeList nodes = xmlDoc.getElementsByTagName(tagName);
	return (nodes != null) ? getNode(nodes, tagName, attrs) : null;
    
protected org.w3c.dom.NodegetNode(org.w3c.dom.Node parent, java.lang.String name, java.lang.String[] attrs)

	Node node = null;
	NodeList nodes = parent.getChildNodes();
	if (nodes != null) {
	    node = getNode(nodes, name, attrs);
	}
	if (node == null) {
	    String inheritFrom = getStringAttr(parent, "parent");
	    if (inheritFrom != null) {
		Node inheritFromNode = getNode(parent.getParentNode(),
					       parent.getNodeName(),
					       new String[] { "name", inheritFrom });
		if (inheritFromNode != null) {
		    node = getNode(inheritFromNode, name, attrs);
		}
	    }
	}
	return node;
    
protected org.w3c.dom.NodegetNode(org.w3c.dom.NodeList nodes, java.lang.String name, java.lang.String[] attrs)

	int n = nodes.getLength();
	for (int i=0; i < n; i++) {
	    Node node = nodes.item(i);
	    if (name.equals(node.getNodeName())) {
		if (attrs != null) {
		    NamedNodeMap nodeAttrs = node.getAttributes();
		    if (nodeAttrs != null) {
			boolean matches = true;
			int nAttrs = attrs.length / 2;
			for (int a = 0; a < nAttrs; a++) {
			    String aName  = attrs[a * 2];
			    String aValue = attrs[a * 2 + 1];
			    Node attr = nodeAttrs.getNamedItem(aName);
			    if (attr == null || !aValue.equals((String)attr.getNodeValue())) {
				matches = false;
				break;
			    }
			}
			if (matches) {
			    return node;
			}
		    }
		} else {
		    return node;
		}
	    }
	}
	return null;
    
protected org.w3c.dom.Node[]getNodesByName(org.w3c.dom.Node parent, java.lang.String name)

	NodeList nodes = parent.getChildNodes(); // ElementNode
	int n = nodes.getLength();
	ArrayList<Node> list = new ArrayList();
	for (int i=0; i < n; i++) {
	    Node node = nodes.item(i);
	    if (name.equals(node.getNodeName())) {
		list.add(node);
	    }
	}
	return list.toArray(new Node[list.size()]);
    
private java.awt.ShapegetRoundedClipShape(int x, int y, int w, int h, int arcw, int arch, int corners)

	if (roundedClipShape == null) {
	    roundedClipShape = new RoundRectClipShape();
	}
	roundedClipShape.setRoundedRect(x, y, w, h, arcw, arch, corners);

	return roundedClipShape;
    
protected java.lang.StringgetStringAttr(org.w3c.dom.Node node, java.lang.String name)

	String value = null;
	NamedNodeMap attrs = node.getAttributes();
	if (attrs != null) {
	    value = getStringAttr(attrs, name);
	    if (value == null) {
		String inheritFrom = getStringAttr(attrs, "parent");
		if (inheritFrom != null) {
		    Node inheritFromNode = getNode(node.getParentNode(),
						   node.getNodeName(),
						   new String[] { "name", inheritFrom });
		    if (inheritFromNode != null) {
			value = getStringAttr(inheritFromNode, name);
		    }
		}
	    }
	}
	return value;
    
protected java.lang.StringgetStringAttr(org.w3c.dom.NamedNodeMap attrs, java.lang.String name)

	Node item = attrs.getNamedItem(name);
	return (item != null) ? (String)item.getNodeValue() : null;
    
private static java.net.URLgetThemeDir(java.lang.String themeName)

	return (URL)new Privileged().doPrivileged(Privileged.GET_THEME_DIR, themeName);
    
public static java.awt.LayoutManagergetTitlePaneLayout()

	return INSTANCE.titlePaneLayout;
    
private static java.lang.StringgetUserTheme()

	return (String)new Privileged().doPrivileged(Privileged.GET_USER_THEME, null);
    
protected static org.w3c.dom.DocumentgetXMLDoc(java.net.URL xmlFile)

	if (documentBuilder == null) {
	    documentBuilder =
                DocumentBuilderFactory.newInstance().newDocumentBuilder();
	}
	InputStream inputStream =
            (InputStream)AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                    try { 
                        return new BufferedInputStream(xmlFile.openStream());
                    } catch (IOException ex) {
                        return null;
                    }
                }
            });

        Document doc = null;
        if (inputStream != null) {
	    doc = documentBuilder.parse(inputStream);
        }
        return doc;
    
protected static voidlogError(java.lang.String themeName, java.lang.Exception ex)

	logError(themeName, ex.toString());
    
protected static voidlogError(java.lang.String themeName, java.lang.String msg)

	if (!errorLogged) {
	    System.err.println("Exception in Metacity for theme \""+themeName+"\": "+msg);
	    errorLogged = true;
	}
    
voidpaintButtonBackground(javax.swing.plaf.synth.SynthContext context, java.awt.Graphics g, int x, int y, int w, int h)

	this.context = context;
	JButton button = (JButton)context.getComponent();
	String buttonName = button.getName();
	int buttonState = context.getComponentState();

	JComponent titlePane = (JComponent)button.getParent();
	Container titlePaneParent = titlePane.getParent();

	JInternalFrame jif;
	if (titlePaneParent instanceof JInternalFrame) {
	    jif = (JInternalFrame)titlePaneParent;
	} else if (titlePaneParent instanceof JInternalFrame.JDesktopIcon) {
	    jif = ((JInternalFrame.JDesktopIcon)titlePaneParent).getInternalFrame();
	} else {
	    return;
	}

	boolean active = jif.isSelected();
	button.setOpaque(false);

	String state = "normal";
	if ((buttonState & PRESSED) != 0) {
	    state = "pressed";
	} else if ((buttonState & MOUSE_OVER) != 0) {
	    state = "prelight";
	}

	String function = null;
	String location = null;
	boolean left_corner  = false;
	boolean right_corner = false;


	if (buttonName == "InternalFrameTitlePane.menuButton") {
	    function = "menu";
	    location = "left_left";
	    left_corner = true;
	} else if (buttonName == "InternalFrameTitlePane.iconifyButton") {
	    function = "minimize";
	    int nButtons = ((jif.isIconifiable() ? 1 : 0) +
			    (jif.isMaximizable() ? 1 : 0) +
			    (jif.isClosable() ? 1 : 0));
	    right_corner = (nButtons == 1);
	    switch (nButtons) {
	      case 1: location = "right_right"; break;
	      case 2: location = "right_middle"; break;
	      case 3: location = "right_left"; break;
	    }
	} else if (buttonName == "InternalFrameTitlePane.maximizeButton") {
	    function = "maximize";
	    right_corner = !jif.isClosable();
	    location = jif.isClosable() ? "right_middle" : "right_right";
	} else if (buttonName == "InternalFrameTitlePane.closeButton") {
	    function = "close";
	    right_corner = true;
	    location = "right_right";
	}

	Node frame = getNode(frame_style_set, "frame", new String[] {
	    "focus", (active ? "yes" : "no"),
	    "state", (jif.isMaximum() ? "maximized" : "normal")
	});

	if (function != null && frame != null) {
	    Node frame_style = getNode("frame_style", new String[] {
		"name", getStringAttr(frame, "style")
	    });
	    if (frame_style != null) {
		setFrameGeometry(titlePane,
				 frameGeometries.get(getStringAttr(frame_style, "geometry")));


		Shape oldClip = g.getClip();
		if ((right_corner && getBoolean("rounded_top_right", false)) ||
		    (left_corner  && getBoolean("rounded_top_left", false))) { 

		    Point buttonLoc = button.getLocation();
		    if (right_corner) { 
			g.setClip(getRoundedClipShape(0, 0, w, h,
						      12, 12, RoundRectClipShape.TOP_RIGHT));
		    } else {
			g.setClip(getRoundedClipShape(0, 0, w, h,
						      11, 11, RoundRectClipShape.TOP_LEFT));
		    }
		}
		drawButton(frame_style, location+"_background", state, g, w, h, jif);
		drawButton(frame_style, function, state, g, w, h, jif);
		g.setClip(oldClip);
	    }
	}
    
voidpaintFrameBorder(javax.swing.plaf.synth.SynthContext context, java.awt.Graphics g, int x0, int y0, int width, int height)

	this.context = context;
	JComponent comp = context.getComponent();
	JComponent titlePane = findChild(comp, "InternalFrame.northPane");

	if (titlePane == null) {
	    return;
	}

        JInternalFrame jif = null;
        if (comp instanceof JInternalFrame) {
            jif = (JInternalFrame)comp;
	} else if (comp instanceof JInternalFrame.JDesktopIcon) {
	    jif = ((JInternalFrame.JDesktopIcon)comp).getInternalFrame();
	} else {
	    return;
        }

	boolean active = jif.isSelected();
	Font oldFont = g.getFont();
	g.setFont(titlePane.getFont());
	g.translate(x0, y0);

	Rectangle titleRect = calculateTitleArea(jif);
	JComponent menuButton = findChild(titlePane, "InternalFrameTitlePane.menuButton");

	Icon frameIcon = jif.getFrameIcon();
	variables.put("mini_icon_width",
		      (frameIcon != null) ? frameIcon.getIconWidth()  : 0);
	variables.put("mini_icon_height",
		      (frameIcon != null) ? frameIcon.getIconHeight() : 0);
	variables.put("title_width",  calculateTitleTextWidth(g, jif));
	FontMetrics fm = SwingUtilities2.getFontMetrics(jif, g);
	variables.put("title_height", fm.getAscent() + fm.getDescent());

	// These don't seem to apply here, but the Galaxy theme uses them. Not sure why.
	variables.put("icon_width",  32);
	variables.put("icon_height", 32);


	if (frame_style_set == null) {
	    frame_style_set = getNode("frame_style_set", new String[] { "name", "normal" });
	}

	if (frame_style_set != null) {
	    Node frame = getNode(frame_style_set, "frame", new String[] {
		"focus", (active ? "yes" : "no"),
		"state", (jif.isMaximum() ? "maximized" : "normal")
	    });

	    if (frame != null) {
		Node frame_style = getNode("frame_style", new String[] {
		    "name", getStringAttr(frame, "style")
		});
		if (frame_style != null) {
		    Map gm = frameGeometries.get(getStringAttr(frame_style, "geometry"));
		    setFrameGeometry(titlePane, gm);
		    Shape oldClip = g.getClip();
		    boolean roundTopLeft     = getBoolean("rounded_top_left",     false);
		    boolean roundTopRight    = getBoolean("rounded_top_right",    false);
		    boolean roundBottomLeft  = getBoolean("rounded_bottom_left",  false);
		    boolean roundBottomRight = getBoolean("rounded_bottom_right", false);

		    if (roundTopLeft || roundTopRight || roundBottomLeft || roundBottomRight) {
			jif.setOpaque(false);

			g.setClip(getRoundedClipShape(0, 0, width, height, 12, 12,
					(roundTopLeft     ? RoundRectClipShape.TOP_LEFT     : 0) |
					(roundTopRight    ? RoundRectClipShape.TOP_RIGHT    : 0) |
					(roundBottomLeft  ? RoundRectClipShape.BOTTOM_LEFT  : 0) |
					(roundBottomRight ? RoundRectClipShape.BOTTOM_RIGHT : 0)));
		    }

		    int titleHeight = titlePane.getHeight();

		    boolean minimized = jif.isIcon();
		    Insets insets = getBorderInsets(context, null);

		    int leftTitlebarEdge   = getInt("left_titlebar_edge");
		    int rightTitlebarEdge  = getInt("right_titlebar_edge");
		    int topTitlebarEdge    = getInt("top_titlebar_edge");
		    int bottomTitlebarEdge = getInt("bottom_titlebar_edge");

		    if (!minimized) {
			drawPiece(frame_style, g, "entire_background",
				  0, 0, width, height, jif);
		    }
		    drawPiece(frame_style, g, "titlebar",
			      0, 0, width, titleHeight, jif);
		    drawPiece(frame_style, g, "titlebar_middle",
			      leftTitlebarEdge, topTitlebarEdge,
			      width - leftTitlebarEdge - rightTitlebarEdge,
			      titleHeight - topTitlebarEdge - bottomTitlebarEdge,
			      jif);
		    drawPiece(frame_style, g, "left_titlebar_edge",
			      0, 0, leftTitlebarEdge, titleHeight, jif);
		    drawPiece(frame_style, g, "right_titlebar_edge",
			      width - rightTitlebarEdge, 0,
			      rightTitlebarEdge, titleHeight, jif);
		    drawPiece(frame_style, g, "top_titlebar_edge",
			      0, 0, width, topTitlebarEdge, jif);
		    drawPiece(frame_style, g, "bottom_titlebar_edge",
			      0, titleHeight - bottomTitlebarEdge,
			      width, bottomTitlebarEdge, jif);
		    drawPiece(frame_style, g, "title",
			      titleRect.x, titleRect.y, titleRect.width, titleRect.height, jif);
		    if (!minimized) {
			drawPiece(frame_style, g, "left_edge",
				  0, titleHeight, insets.left, height-titleHeight, jif);
			drawPiece(frame_style, g, "right_edge",
				  width-insets.right, titleHeight, insets.right, height-titleHeight, jif);
			drawPiece(frame_style, g, "bottom_edge",
				  0, height - insets.bottom, width, insets.bottom, jif);
			drawPiece(frame_style, g, "overlay",
				  0, 0, width, height, jif);
		    }
		    g.setClip(oldClip);
		}
	    }
	}
	g.translate(-x0, -y0);
	g.setFont(oldFont);
    
protected java.awt.ColorparseColor(java.lang.String str)

	StringTokenizer tokenizer = new StringTokenizer(str, "/");
	int n = tokenizer.countTokens();
	if (n > 1) {
	    String function = tokenizer.nextToken();
	    if ("shade".equals(function)) {
		assert (n == 3);
		Color c = parseColor2(tokenizer.nextToken());
		float alpha = Float.parseFloat(tokenizer.nextToken());
		return GTKColorType.adjustColor(c, 1.0F, alpha, alpha);
	    } else if ("blend".equals(function)) {
		assert (n == 4);
		Color bg = parseColor2(tokenizer.nextToken());
		Color fg = parseColor2(tokenizer.nextToken());
		float alpha = Float.parseFloat(tokenizer.nextToken());
		return new Color((int)(bg.getRed() + ((fg.getRed() - bg.getRed()) * alpha)),
				 (int)(bg.getRed() + ((fg.getRed() - bg.getRed()) * alpha)),
				 (int)(bg.getRed() + ((fg.getRed() - bg.getRed()) * alpha)));
	    } else {
		System.err.println("Unknown Metacity color function="+str);
		return null;
	    }
	} else {
	    return parseColor2(str);
	}
    
protected java.awt.ColorparseColor2(java.lang.String str)

	Color c = null;
	if (str.startsWith("gtk:")) {
	    int i1 = str.indexOf('[");
	    if (i1 > 3) {
		String typeStr = str.substring(4, i1).toLowerCase();
		int i2 = str.indexOf(']");
		if (i2 > i1+1) {
		    String stateStr = str.substring(i1+1, i2).toUpperCase();
		    int state = -1;
		    if ("ACTIVE".equals(stateStr)) {
			state = PRESSED;
		    } else if ("INSENSITIVE".equals(stateStr)) {
			state = DISABLED;
		    } else if ("NORMAL".equals(stateStr)) {
			state = ENABLED;
		    } else if ("PRELIGHT".equals(stateStr)) {
			state = MOUSE_OVER;
		    } else if ("SELECTED".equals(stateStr)) {
			state = SELECTED;
		    }
		    ColorType type = null;
		    if ("fg".equals(typeStr)) {
			type = GTKColorType.FOREGROUND;
		    } else if ("bg".equals(typeStr)) {
			type = GTKColorType.BACKGROUND;
		    } else if ("base".equals(typeStr)) {
			type = GTKColorType.TEXT_BACKGROUND;
		    } else if ("text".equals(typeStr)) {
			type = GTKColorType.TEXT_FOREGROUND;
		    } else if ("dark".equals(typeStr)) {
			type = GTKColorType.DARK;
		    } else if ("light".equals(typeStr)) {
			type = GTKColorType.LIGHT;
		    }
		    if (state >= 0 && type != null) {
			c = ((GTKStyle)context.getStyle()).getGTKColor(context.getComponent(),
								       context.getRegion(),
								       state, type);
		    }
		}
	    }
	}
	if (c == null) {
	    c = GTKParser.parseColorString(str);
	}
	return c;
    
protected voidsetClip(org.w3c.dom.Node node, java.awt.Graphics g)

	NamedNodeMap attrs = node.getAttributes();
	int x = aee.evaluate(getStringAttr(attrs, "x"));
	int y = aee.evaluate(getStringAttr(attrs, "y"));
	int w = aee.evaluate(getStringAttr(attrs, "width"));
	int h = aee.evaluate(getStringAttr(attrs, "height"));
	if (getInt("width") == -1) {
	    x -= w;
	}
	if (getInt("height") == -1) {
	    y -= h;
	}
	if (g instanceof Graphics2D) {
	    ((Graphics2D)g).clip(new Rectangle(x, y, w, h));
	}
    
protected voidsetFrameGeometry(javax.swing.JComponent titlePane, java.util.Map gm)

	this.frameGeometry = gm;
	if (getInt("top_height") == 0) {
	    gm.put("top_height", new Integer(titlePane.getHeight()));
	}
    
protected voidtileImage(java.awt.Graphics g, java.awt.Image image, int x0, int y0, int w, int h, float[] alphas)

	Graphics2D g2 = (Graphics2D)g;
	Composite oldComp = g2.getComposite();

	int sw = image.getWidth(null);
	int sh = image.getHeight(null);
	int y = y0;
	while (y < y0 + h) {
	    sh = Math.min(sh, y0 + h - y);
	    int x = x0;
	    while (x < x0 + w) {
		float f = (alphas.length - 1.0F) * x / (x0 + w);
		int i = (int)f;
		f -= (int)f;
		float alpha = (1-f) * alphas[i];
		if (i+1 < alphas.length) {
		    alpha += f * alphas[i+1];
		}
		g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
		int swm = Math.min(sw, x0 + w - x);
		g.drawImage(image, x, y, x+swm, y+sh, 0, 0, swm, sh, null);
		x += swm;
	    }
	    y += sh;
	}
	g2.setComposite(oldComp);