Package com.sun.java.swing.plaf.gtk

Source Code of com.sun.java.swing.plaf.gtk.Metacity$RoundRectClipShape$RoundishRectIterator

/*
* @(#)Metacity.java  1.37 06/07/19
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.sun.java.swing.plaf.gtk;

import sun.swing.SwingUtilities2;
import com.sun.java.swing.plaf.gtk.GTKConstants.ArrowType;
import com.sun.java.swing.plaf.gtk.GTKConstants.ShadowType;

import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.synth.*;

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import java.net.*;
import java.security.*;
import java.util.*;

import javax.swing.*;
import javax.swing.border.*;

import javax.xml.parsers.*;
import org.xml.sax.SAXException;
import org.w3c.dom.*;

/**
* @version 1.37, 07/19/06
*/
class Metacity implements SynthConstants {
    // Tutorial:
    // http://developer.gnome.org/doc/tutorials/metacity/metacity-themes.html

    // Themes:
    // http://art.gnome.org/theme_list.php?category=metacity

    static Metacity INSTANCE;

    private static final String[] themeNames = {
        getUserTheme(),
        "blueprint",
      "Bluecurve",
        "Crux",
        "SwingFallbackTheme"
    };

    static {
        for (String themeName : themeNames) {
            if (themeName != null) {
            try {
                INSTANCE = new Metacity(themeName);
            } catch (FileNotFoundException ex) {
            } catch (IOException ex) {
                logError(themeName, ex);
            } catch (ParserConfigurationException ex) {
                logError(themeName, ex);
            } catch (SAXException ex) {
                logError(themeName, ex);
            }
            }
            if (INSTANCE != null) {
            break;
            }
        }
        if (INSTANCE == null) {
            throw new Error("Could not find any installed metacity theme, and fallback failed");
        }
    }

    private static boolean errorLogged = false;
    private static DocumentBuilder documentBuilder;
    private static Document xmlDoc;
    private static String userHome;

    private Node frame_style_set;
    private Map<String, Object> frameGeometry;
    private Map<String, Map<String, Object>> frameGeometries;

    private LayoutManager titlePaneLayout = new TitlePaneLayout();

    private ColorizeImageFilter imageFilter = new ColorizeImageFilter();
    private URL themeDir = null;
    private SynthContext context;
    private String themeName;

    private ArithmeticExpressionEvaluator aee = new ArithmeticExpressionEvaluator();
    private Map<String, Integer> variables;

    // Reusable clip shape object
    private RoundRectClipShape roundedClipShape;

    protected Metacity(String themeName) throws IOException, ParserConfigurationException, SAXException {
  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");
    }


    public static LayoutManager getTitlePaneLayout() {
  return INSTANCE.titlePaneLayout;
    }

    private Shape getRoundedClipShape(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;
    }

    void paintButtonBackground(SynthContext context, Graphics g, int x, int y, int w, int h) {
  updateFrameGeometry(context);

  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) {
    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));
        }

                    Rectangle clipBounds = oldClip.getBounds();
                    g.clipRect(clipBounds.x, clipBounds.y,
                               clipBounds.width, clipBounds.height);
    }
    drawButton(frame_style, location+"_background", state, g, w, h, jif);
    drawButton(frame_style, function, state, g, w, h, jif);
    g.setClip(oldClip);
      }
  }
    }

    protected void drawButton(Node frame_style, String function, String state,
          Graphics g, int w, int h, 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);
  }
    }

    void paintFrameBorder(SynthContext context, Graphics g, int x0, int y0, int width, int height) {
  updateFrameGeometry(context);

  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 {
      assert false : "component is not JInternalFrame or JInternalFrame.JDesktopIcon";
      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) {
      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) {
        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)));
        }
               
                    Rectangle clipBounds = oldClip.getBounds();
                    g.clipRect(clipBounds.x, clipBounds.y,
                               clipBounds.width, clipBounds.height);

        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);
    }



    private static class Privileged implements PrivilegedAction {
  private static int GET_THEME_DIR  = 0;
  private static int GET_USER_THEME = 1;
  private static int GET_IMAGE      = 2;
  private int type;
  private Object arg;

  public Object doPrivileged(int type, Object arg) {
      this.type = type;
      this.arg = arg;
      return AccessController.doPrivileged(this);
  }

  public Object run() {
      if (type == GET_THEME_DIR) {
    String sep = File.separator;
    String[] dirs = new String[] {
        userHome + sep + ".themes",
        System.getProperty("swing.metacitythemedir"),
        "/usr/share/themes",
        "/usr/gnome/share/themes"// Debian/Redhat/Solaris
                    "/opt/gnome2/share/themes"  // SuSE
    };

    URL themeDir = null;
    for (int i = 0; i < dirs.length; i++) {
                    // System property may not be set so skip null directories.
                    if (dirs[i] == null) {
                        continue;
                    }
                    File dir =
                        new File(dirs[i] + sep + arg + sep + "metacity-1");
        if (new File(dir, "metacity-theme-1.xml").canRead()) {
      try {
          themeDir = dir.toURL();
      } catch (MalformedURLException ex) {
          themeDir = null;
      }
      break;
        }
    }
    if (themeDir == null) {
        String filename = "resources/metacity/" + arg +
                        "/metacity-1/metacity-theme-1.xml";
        URL url = getClass().getResource(filename);
        if (url != null) {
      String str = url.toString();
      try {
          themeDir = new URL(str.substring(0, str.lastIndexOf('/'))+"/");
      } catch (MalformedURLException ex) {
          themeDir = null;
      }
        }
    }
    return themeDir;
      } else if (type == GET_USER_THEME) {
    try {
        // Set userHome here because we need the privilege
        userHome = System.getProperty("user.home");

        String theme = System.getProperty("swing.metacitythemename");
        if (theme != null) {
      return theme;
        }
        // Note: this is a small file (< 1024 bytes) so it's not worth
        // starting an XML parser or even to use a buffered reader.
        URL url = new URL(new File(userHome).toURL(),
              ".gconf/apps/metacity/general/%25gconf.xml");
        // Pending: verify character encoding spec for gconf
        Reader reader = new InputStreamReader(url.openStream(), "ISO-8859-1");
        char[] buf = new char[1024];
        StringBuffer strBuf = new StringBuffer();
        int n;
        while ((n = reader.read(buf)) >= 0) {
      strBuf.append(buf, 0, n);
        }     
        reader.close();
        String str = strBuf.toString();
        if (str != null) {
      String strLowerCase = str.toLowerCase();
      int i = strLowerCase.indexOf("<entry name=\"theme\"");
      if (i >= 0) {
          i = strLowerCase.indexOf("<stringvalue>", i);
          if (i > 0) {
        i += "<stringvalue>".length();
        int i2 = str.indexOf("<", i);
        return str.substring(i, i2);
          }
      }
        }
    } catch (MalformedURLException ex) {
        // OK to just ignore. We'll use a fallback theme.
    } catch (IOException ex) {
        // OK to just ignore. We'll use a fallback theme.
    }
    return null;
      } else if (type == GET_IMAGE) {
    return new ImageIcon((URL)arg).getImage();
      } else {
    return null;
      }
  }
    }

    private static URL getThemeDir(String themeName) {
  return (URL)new Privileged().doPrivileged(Privileged.GET_THEME_DIR, themeName);
    }

    private static String getUserTheme() {
  return (String)new Privileged().doPrivileged(Privileged.GET_USER_THEME, null);
    }

    protected void tileImage(Graphics g, 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);
    }

    private HashMap<String, Image> images = new HashMap();

    protected Image getImage(String key, 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 Image getImage(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;
    }

    private class ColorizeImageFilter extends RGBImageFilter {
  double cr, cg, cb;

  public ColorizeImageFilter() {
      canFilterIndexColorModel = true;
  }

  public void setColor(Color color) {
      cr = color.getRed()   / 255.0;
      cg = color.getGreen() / 255.0;
      cb = color.getBlue()  / 255.0;
  }

  public Image colorize(Image fromImage, Color c) {
      setColor(c);
      ImageProducer producer = new FilteredImageSource(fromImage.getSource(), this);
      return new ImageIcon(context.getComponent().createImage(producer)).getImage();
  }

  public int filterRGB(int x, int y, int rgb) {
      // Assume all rgb values are shades of gray
      double grayLevel = 2 * (rgb & 0xff) / 255.0;
      double r, g, b;

      if (grayLevel <= 1.0) {
    r = cr * grayLevel;
    g = cg * grayLevel;
    b = cb * grayLevel;
            } else {
    grayLevel -= 1.0;
    r = cr + (1.0 - cr) * grayLevel;
    g = cg + (1.0 - cg) * grayLevel;
    b = cb + (1.0 - cb) * grayLevel;
            }

      return ((rgb & 0xff000000) +
        (((int)(r * 255)) << 16) +
        (((int)(g * 255)) << 8) +
        (int)(b * 255));
  }
    }

    protected static JComponent findChild(JComponent parent, 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 class TitlePaneLayout implements LayoutManager {
        public void addLayoutComponent(String name, Component c) {}
        public void removeLayoutComponent(Component c) {}   
        public Dimension preferredLayoutSize(Container c)  {
      return minimumLayoutSize(c);
  }
   
        public Dimension minimumLayoutSize(Container c) {
      JComponent titlePane = (JComponent)c;
      Container titlePaneParent = titlePane.getParent();
      JInternalFrame frame;
      if (titlePaneParent instanceof JInternalFrame) {
    frame = (JInternalFrame)titlePaneParent;
      } else if (titlePaneParent instanceof JInternalFrame.JDesktopIcon) {
    frame = ((JInternalFrame.JDesktopIcon)titlePaneParent).getInternalFrame();
      } else {
    return null;
      }

      Dimension buttonDim = calculateButtonSize(titlePane);
      Insets title_border  = (Insets)getFrameGeometry().get("title_border");
      Insets button_border = (Insets)getFrameGeometry().get("button_border");

            // Calculate width.
            int width = getInt("left_titlebar_edge") + buttonDim.width + getInt("right_titlebar_edge");
      if (title_border != null) {
    width += title_border.left + title_border.right;
      }
            if (frame.isClosable()) {
                width += buttonDim.width;
            }
            if (frame.isMaximizable()) {
                width += buttonDim.width;
            }
            if (frame.isIconifiable()) {
                width += buttonDim.width;
            }
            FontMetrics fm = frame.getFontMetrics(titlePane.getFont());
            String frameTitle = frame.getTitle();
            int title_w = frameTitle != null ? SwingUtilities2.stringWidth(
                               frame, fm, frameTitle) : 0;
            int title_length = frameTitle != null ? frameTitle.length() : 0;

            // Leave room for three characters in the title.
            if (title_length > 3) {
                int subtitle_w = SwingUtilities2.stringWidth(
                    frame, fm, frameTitle.substring(0, 3) + "...");
                width += (title_w < subtitle_w) ? title_w : subtitle_w;
            } else {
                width += title_w;
            }

            // Calculate height.
      int titleHeight = fm.getHeight() + getInt("title_vertical_pad");
      if (title_border != null) {
    titleHeight += title_border.top + title_border.bottom;
      }
      int buttonHeight = buttonDim.height;
      if (button_border != null) {
    buttonHeight += button_border.top + button_border.bottom;
      }
            int height = Math.max(buttonHeight, titleHeight);

            return new Dimension(width, height);
  }
   
        public void layoutContainer(Container c) {
      JComponent titlePane = (JComponent)c;
      Container titlePaneParent = titlePane.getParent();
      JInternalFrame frame;
      if (titlePaneParent instanceof JInternalFrame) {
    frame = (JInternalFrame)titlePaneParent;
      } else if (titlePaneParent instanceof JInternalFrame.JDesktopIcon) {
    frame = ((JInternalFrame.JDesktopIcon)titlePaneParent).getInternalFrame();
      } else {
    return;
      }
      Map gm = getFrameGeometry();

            int w = titlePane.getWidth();
            int h = titlePane.getHeight();

      JComponent menuButton     = findChild(titlePane, "InternalFrameTitlePane.menuButton");
      JComponent minimizeButton = findChild(titlePane, "InternalFrameTitlePane.iconifyButton");
      JComponent maximizeButton = findChild(titlePane, "InternalFrameTitlePane.maximizeButton");
      JComponent closeButton    = findChild(titlePane, "InternalFrameTitlePane.closeButton");

      int buttonGap = 0;

      Insets button_border = (Insets)gm.get("button_border");
      Dimension buttonDim = calculateButtonSize(titlePane);

            int x = getInt("left_titlebar_edge");
      int y = (button_border != null) ? button_border.top : 0;

            menuButton.setBounds(x, y, buttonDim.width, buttonDim.height);

            x = w - buttonDim.width - getInt("right_titlebar_edge");
      if (button_border != null) {
    x -= button_border.right;
      }

            if (frame.isClosable()) {
                closeButton.setBounds(x, y, buttonDim.width, buttonDim.height);
                x -= (buttonDim.width + buttonGap);
            }

            if (frame.isMaximizable()) {
                maximizeButton.setBounds(x, y, buttonDim.width, buttonDim.height);
                x -= (buttonDim.width + buttonGap);
            }

            if (frame.isIconifiable()) {
                minimizeButton.setBounds(x, y, buttonDim.width, buttonDim.height);
            }
        }
    } // end TitlePaneLayout

    protected Map getFrameGeometry() {
  return frameGeometry;
    }

    protected void setFrameGeometry(JComponent titlePane, Map gm) {
  this.frameGeometry = gm;
        if (getInt("top_height") == 0 && titlePane != null) {
      gm.put("top_height", new Integer(titlePane.getHeight()));
  }
    }

    protected int getInt(String key) {
  Integer i = (Integer)frameGeometry.get(key);
  if (i == null) {
      i = variables.get(key);
  }
  return (i != null) ? i.intValue() : 0;
    }

    protected boolean getBoolean(String key, boolean fallback) {
  Boolean b = (Boolean)frameGeometry.get(key);
  return (b != null) ? b.booleanValue() : fallback;
    }


    protected void drawArc(Node node, 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 void drawLine(Node node, 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 void drawRectangle(Node node, 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 void drawTile(Node node, Graphics g, 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 void drawTint(Node node, 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 void drawTitle(Node node, Graphics g, 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 Dimension calculateButtonSize(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 Rectangle calculateTitleArea(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 int calculateTitleTextWidth(Graphics g, 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 void setClip(Node node, 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 void drawGTKArrow(Node node, 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;
  }

  ShadowType shadowType = null;
  if ("in".equals(shadow)) {
      shadowType = ShadowType.IN;
  } else if ("out".equals(shadow)) {
      shadowType = ShadowType.OUT;
  } else if ("etched_in".equals(shadow)) {
      shadowType = ShadowType.ETCHED_IN;
  } else if ("etched_out".equals(shadow)) {
      shadowType = ShadowType.ETCHED_OUT;
  } else if ("none".equals(shadow)) {
      shadowType = ShadowType.NONE;
  }

  ArrowType direction = null;
  if ("up".equals(arrow)) {
      direction = ArrowType.UP;
  } else if ("down".equals(arrow)) {
      direction = ArrowType.DOWN;
  } else if ("left".equals(arrow)) {
      direction = ArrowType.LEFT;
  } else if ("right".equals(arrow)) {
      direction = ArrowType.RIGHT;
  }

        GTKPainter.INSTANCE.paintMetacityElement(context, g, state,
                "metacity-arrow", x, y, w, h, shadowType, direction);
    }

    protected void drawGTKBox(Node node, 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;
  }

  ShadowType shadowType = null;
  if ("in".equals(shadow)) {
      shadowType = ShadowType.IN;
  } else if ("out".equals(shadow)) {
      shadowType = ShadowType.OUT;
  } else if ("etched_in".equals(shadow)) {
      shadowType = ShadowType.ETCHED_IN;
  } else if ("etched_out".equals(shadow)) {
      shadowType = ShadowType.ETCHED_OUT;
  } else if ("none".equals(shadow)) {
      shadowType = ShadowType.NONE;
  }
        GTKPainter.INSTANCE.paintMetacityElement(context, g, state,
                "metacity-box", x, y, w, h, shadowType, null);
    }

    protected void drawGTKVLine(Node node, 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;
  }

        GTKPainter.INSTANCE.paintMetacityElement(context, g, state,
                "metacity-vline", x, y1, 1, y2 - y1, null, null);
    }

    protected void drawGradient(Node node, 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 void drawImage(Node node, 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 void drawIcon(Node node, Graphics g, 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 void drawInclude(Node node, Graphics g, 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 void draw(Node draw_ops, Graphics g, 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 void drawPiece(Node frame_style, Graphics g, String position, int x, int y,
           int width, int height, 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);
  }
    }


    Insets getBorderInsets(SynthContext context, Insets insets) {
  updateFrameGeometry(context);

  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;
    }


    private void updateFrameGeometry(SynthContext context) {
        this.context = context;
        JComponent comp = context.getComponent();
        JComponent titlePane = findChild(comp, "InternalFrame.northPane");

        JInternalFrame jif = null;
        if (comp instanceof JInternalFrame) {
            jif = (JInternalFrame)comp;
        } else if (comp instanceof JInternalFrame.JDesktopIcon) {
            jif = ((JInternalFrame.JDesktopIcon)comp).getInternalFrame();
        } else {
      assert false : "component is not JInternalFrame or JInternalFrame.JDesktopIcon";
            return;
        }

        if (frame_style_set == null) {
            Node window = getNode("window", new String[]{"type", "normal"});
            
            if (window != null) {
                frame_style_set = getNode("frame_style_set",
                        new String[] {"name", getStringAttr(window, "style_set")});
            }
           
            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", (jif.isSelected() ? "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);
                }
            }
        }
    }


    protected static void logError(String themeName, Exception ex) {
  logError(themeName, ex.toString());
    }

    protected static void logError(String themeName, String msg) {
  if (!errorLogged) {
      System.err.println("Exception in Metacity for theme \""+themeName+"\": "+msg);
      errorLogged = true;
  }
    }


    // XML Parsing


    protected static Document getXMLDoc(final URL xmlFile)
        throws IOException,
                                       ParserConfigurationException,
                                       SAXException {
  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 Node[] getNodesByName(Node parent, 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()]);
    }



    protected Node getNode(String tagName, String[] attrs) {
  NodeList nodes = xmlDoc.getElementsByTagName(tagName);
  return (nodes != null) ? getNode(nodes, tagName, attrs) : null;
    }

    protected Node getNode(Node parent, String name, 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 Node getNode(NodeList nodes, String name, 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 != null && !aValue.equals((String)attr.getNodeValue())) {
        matches = false;
        break;
          }
      }
      if (matches) {
          return node;
      }
        }
    } else {
        return node;
    }
      }
  }
  return null;
    }

    protected String getStringAttr(Node node, 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 String getStringAttr(NamedNodeMap attrs, String name) {
  Node item = attrs.getNamedItem(name);
  return (item != null) ? (String)item.getNodeValue() : null;
    }

    protected boolean getBooleanAttr(Node node, String name, boolean fallback) {
  String str = getStringAttr(node, name);
  if (str != null) {
      return Boolean.valueOf(str).booleanValue();
  }
  return fallback;
    }

    protected int getIntAttr(Node node, 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 float getFloatAttr(Node node, 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 Color parseColor(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());
                if (alpha > 1.0f) {
                    alpha = 1.0f / alpha;
                }
               
    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 Color parseColor2(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, state, type);
        }
    }
      }
  }
  if (c == null) {
      c = parseColorString(str);
  }
  return c;
    }

    private static Color parseColorString(String str) {
        if (str.charAt(0) == '#') {
            str = str.substring(1);
           
            int i = str.length();
           
            if (i < 3 || i > 12 || (i % 3) != 0) {
                return null;
            }
           
            i /= 3;
           
            int r;
            int g;
            int b;
           
            try {
                r = Integer.parseInt(str.substring(0, i), 16);
                g = Integer.parseInt(str.substring(i, i * 2), 16);
                b = Integer.parseInt(str.substring(i * 2, i * 3), 16);
            } catch (NumberFormatException nfe) {
                return null;
            }
           
            if (i == 4) {
                return new ColorUIResource(r / 65535.0f, g / 65535.0f, b / 65535.0f);
            } else if (i == 1) {
                return new ColorUIResource(r / 15.0f, g / 15.0f, b / 15.0f);
            } else if (i == 2) {
                return new ColorUIResource(r, g, b);
            } else {
                return new ColorUIResource(r / 4095.0f, g / 4095.0f, b / 4095.0f);
            }
        } else {
            return XColors.lookupColor(str);
        }
    }

    class ArithmeticExpressionEvaluator {
  private PeekableStringTokenizer tokenizer;

  int evaluate(String expr) {
      tokenizer = new PeekableStringTokenizer(expr, " \t+-*/%()", true);
      return Math.round(expression());
  }

  int evaluate(String expr, int fallback) {
      return (expr != null) ? evaluate(expr) : fallback;
  }

  public float expression() {
      float value = getTermValue();
      boolean done = false;
      while (!done && tokenizer.hasMoreTokens()) {
    String next = tokenizer.peek();
    if ("+".equals(next) ||
        "-".equals(next) ||
        "`max`".equals(next) ||
        "`min`".equals(next)) {
        tokenizer.nextToken();
        float value2 = getTermValue();
        if ("+".equals(next)) {
      value += value2;
        } else if ("-".equals(next)) {
      value -= value2;
        } else if ("`max`".equals(next)) {
      value = Math.max(value, value2);
        } else if ("`min`".equals(next)) {
      value = Math.min(value, value2);
        }
    } else {
        done = true;
    }
      }
      return value;
  }

  public float getTermValue() {
      float value = getFactorValue();
      boolean done = false;
      while (!done && tokenizer.hasMoreTokens()) {
    String next = tokenizer.peek();
    if ("*".equals(next) || "/".equals(next) || "%".equals(next)) {
        tokenizer.nextToken();
        float value2 = getFactorValue();
        if ("*".equals(next)) {
      value *= value2;
        } else if ("/".equals(next)) {
      value /= value2;
        } else {
      value %= value2;
        }
    } else {
        done = true;
    }
      }
      return value;
  }

  public float getFactorValue() {
      float value;
      if ("(".equals(tokenizer.peek())) {
    tokenizer.nextToken();
    value = expression();
    tokenizer.nextToken(); // skip right paren
      } else {
    String token = tokenizer.nextToken();
    if (Character.isDigit(token.charAt(0))) {
        value = Float.parseFloat(token);
    } else {
        Integer i = variables.get(token);
        if (i == null) {
      i = (Integer)getFrameGeometry().get(token);
        }
        if (i == null) {
      logError(themeName, "Variable \"" + token + "\" not defined");
      return 0;
        }
        value = (i != null) ? i.intValue() : 0F;
    }
      }
      return value;
  }


    }

    static class PeekableStringTokenizer extends StringTokenizer {
  String token = null;

  public PeekableStringTokenizer(String str, String delim,
               boolean returnDelims) {
      super(str, delim, returnDelims);
      peek();
  }

  public String peek() {
      if (token == null) {
    token = nextToken();
      }
      return token;
  }

  public boolean hasMoreTokens() {
      return (token != null || super.hasMoreTokens());
  }

  public String nextToken() {
      if (token != null) {
    String t = token;
    token = null;
    if (hasMoreTokens()) {
        peek();
    }
    return t;
      } else {
    String token = super.nextToken();
    while ((token.equals(" ") || token.equals("\t"))
           && hasMoreTokens()) {
        token = super.nextToken();
    }
    return token;
      }
  }
    }


    static class RoundRectClipShape extends RectangularShape {
  static final int TOP_LEFT = 1;
  static final int TOP_RIGHT = 2;
  static final int BOTTOM_LEFT = 4;
  static final int BOTTOM_RIGHT = 8;

  int x;
  int y;
  int width;
  int height;
  int arcwidth;
  int archeight;
  int corners;

  public RoundRectClipShape() {
  }

  public RoundRectClipShape(int x, int y, int w, int h,
          int arcw, int arch, int corners) {
      setRoundedRect(x, y, w, h, arcw, arch, corners);
  }

  public void setRoundedRect(int x, int y, int w, int h,
           int arcw, int arch, int corners) {
      this.corners = corners;
      this.x = x;
      this.y = y;
      this.width = w;
      this.height = h;
      this.arcwidth = arcw;
      this.archeight = arch;
  }

  public double getX() {
      return (double)x;
  }

  public double getY() {
      return (double)y;
  }

  public double getWidth() {
      return (double)width;
  }

  public double getHeight() {
      return (double)height;
  }

  public double getArcWidth() {
      return (double)arcwidth;
  }

  public double getArcHeight() {
      return (double)archeight;
  }

  public boolean isEmpty() {
      return false// Not called
  }

  public Rectangle2D getBounds2D() {
      return null// Not called
  }

  public int getCornerFlags() {
      return corners;
  }

  public void setFrame(double x, double y, double w, double h) {
      // Not called
  }

  public boolean contains(double x, double y) {
      return false// Not called
  }

  private int classify(double coord, double left, double right, double arcsize) {
      return 0// Not called
  }

  public boolean intersects(double x, double y, double w, double h) {
      return false// Not called
  }

  public boolean contains(double x, double y, double w, double h) {
      return false// Not called
  }

  public PathIterator getPathIterator(AffineTransform at) {
      return new RoundishRectIterator(this, at);
  }


  static class RoundishRectIterator implements PathIterator {
      double x, y, w, h, aw, ah;
      AffineTransform affine;
      int index;

      double ctrlpts[][];
      int types[];

      private static final double angle = Math.PI / 4.0;
      private static final double a = 1.0 - Math.cos(angle);
      private static final double b = Math.tan(angle);
      private static final double c = Math.sqrt(1.0 + b * b) - 1 + a;
      private static final double cv = 4.0 / 3.0 * a * b / c;
      private static final double acv = (1.0 - cv) / 2.0;

      // For each array:
      //     4 values for each point {v0, v1, v2, v3}:
      //         point = (x + v0 * w + v1 * arcWidth,
      //                  y + v2 * h + v3 * arcHeight);
      private static final double CtrlPtTemplate[][] = {
    {  0.00.01.00.0 }/* BOTTOM LEFT corner */
    0.00.01.0, -0.5 }/* BOTTOM LEFT arc start */
    0.00.01.0, -acv,  /* BOTTOM LEFT arc curve */
       0.0,  acv,  1.00.0,
       0.00.51.00.0 },
    1.00.01.00.0 }/* BOTTOM RIGHT corner */
    1.0, -0.51.00.0 }/* BOTTOM RIGHT arc start */
    1.0, -acv,  1.00.0/* BOTTOM RIGHT arc curve */
       1.00.01.0, -acv,
       1.00.01.0, -0.5 },
    1.00.00.00.0 }/* TOP RIGHT corner */
    1.00.00.00.5 }/* TOP RIGHT arc start */
    1.00.00.0,  acv,  /* TOP RIGHT arc curve */
       1.0, -acv,  0.00.0,
       1.0, -0.50.00.0 },
    0.00.00.00.0 }/* TOP LEFT corner */
    0.00.50.00.0 }/* TOP LEFT arc start */
    0.0,  acv,  0.00.0/* TOP LEFT arc curve */
       0.00.00.0,  acv,
       0.00.00.00.5 },
    {},        /* Closing path element */
      };
      private static final int CornerFlags[] = {
    RoundRectClipShape.BOTTOM_LEFT,
    RoundRectClipShape.BOTTOM_RIGHT,
    RoundRectClipShape.TOP_RIGHT,
    RoundRectClipShape.TOP_LEFT,
      };

      RoundishRectIterator(RoundRectClipShape rr, AffineTransform at) {
    this.x = rr.getX();
    this.y = rr.getY();
    this.w = rr.getWidth();
    this.h = rr.getHeight();
    this.aw = Math.min(w, Math.abs(rr.getArcWidth()));
    this.ah = Math.min(h, Math.abs(rr.getArcHeight()));
    this.affine = at;
    if (w < 0 || h < 0) {
        // Don't draw anything...
        ctrlpts = new double[0][];
        types = new int[0];
    } else {
        int corners = rr.getCornerFlags();
        int numedges = 5// 4xCORNER_POINT, CLOSE
        for (int i = 1; i < 0x10; i <<= 1) {
      // Add one for each corner that has a curve
      if ((corners & i) != 0) numedges++;
        }
        ctrlpts = new double[numedges][];
        types = new int[numedges];
        int j = 0;
        for (int i = 0; i < 4; i++) {
      types[j] = SEG_LINETO;
      if ((corners & CornerFlags[i]) == 0) {
          ctrlpts[j++] = CtrlPtTemplate[i*3+0];
      } else {
          ctrlpts[j++] = CtrlPtTemplate[i*3+1];
          types[j] = SEG_CUBICTO;
          ctrlpts[j++] = CtrlPtTemplate[i*3+2];
      }
        }
        types[j] = SEG_CLOSE;
        ctrlpts[j++] = CtrlPtTemplate[12];
        types[0] = SEG_MOVETO;
    }
      }

      public int getWindingRule() {
    return WIND_NON_ZERO;
      }

      public boolean isDone() {
    return index >= ctrlpts.length;
      }

      public void next() {
    index++;
      }

      public int currentSegment(float[] coords) {
    if (isDone()) {
        throw new NoSuchElementException("roundrect iterator out of bounds");
    }
    double ctrls[] = ctrlpts[index];
    int nc = 0;
    for (int i = 0; i < ctrls.length; i += 4) {
        coords[nc++] = (float) (x + ctrls[i + 0] * w + ctrls[i + 1] * aw);
        coords[nc++] = (float) (y + ctrls[i + 2] * h + ctrls[i + 3] * ah);
    }
    if (affine != null) {
        affine.transform(coords, 0, coords, 0, nc / 2);
    }
    return types[index];
      }

      public int currentSegment(double[] coords) {
                if (isDone()) {
                    throw new NoSuchElementException("roundrect iterator out of bounds");
                }
                double ctrls[] = ctrlpts[index];
                int nc = 0;
                for (int i = 0; i < ctrls.length; i += 4) {
                    coords[nc++] = x + ctrls[i + 0] * w + ctrls[i + 1] * aw;
                    coords[nc++] = y + ctrls[i + 2] * h + ctrls[i + 3] * ah;
                }
                if (affine != null) {
                    affine.transform(coords, 0, coords, 0, nc / 2);
                }
                return types[index];
            }
  }
    }
}
TOP

Related Classes of com.sun.java.swing.plaf.gtk.Metacity$RoundRectClipShape$RoundishRectIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.