1. /*
  2. * @(#)Metacity.java 1.16 03/05/01
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.gtk;
  8. import java.awt.*;
  9. import java.awt.image.*;
  10. import java.io.*;
  11. import java.net.*;
  12. import java.security.*;
  13. import java.util.*;
  14. import javax.swing.*;
  15. import javax.swing.border.*;
  16. /**
  17. * @version 1.16, 05/01/03
  18. */
  19. abstract class Metacity implements SynthConstants {
  20. static Metacity INSTANCE;
  21. static {
  22. String themeDir = null;
  23. String theme = getUserTheme();
  24. if (theme == null) {
  25. theme = "Bluecurve";
  26. themeDir = getThemeDir(theme);
  27. if (themeDir == null) {
  28. theme = "Crux";
  29. themeDir = getThemeDir(theme);
  30. }
  31. if (themeDir == null) {
  32. theme = null;
  33. }
  34. }
  35. if (theme != null && themeDir == null) {
  36. themeDir = getThemeDir(theme);
  37. }
  38. if (themeDir != null) {
  39. if (theme.equals("Bluecurve")) {
  40. INSTANCE = new MetacityBluecurve(themeDir);
  41. } else if (theme.equals("Crux")) {
  42. INSTANCE = new MetacityCrux(themeDir);
  43. }
  44. }
  45. if (INSTANCE == null) {
  46. INSTANCE = new MetacityCrux(null);
  47. }
  48. }
  49. private FrameGeometry geometry;
  50. private static LayoutManager titlePaneLayout = new TitlePaneLayout();
  51. private ColorizeImageFilter imageFilter = new ColorizeImageFilter();
  52. protected String themeDir = null;
  53. protected SynthContext context;
  54. protected Metacity(String themeDir, FrameGeometry geometry) {
  55. this.themeDir = themeDir;
  56. this.geometry = geometry;
  57. }
  58. public static LayoutManager getTitlePaneLayout() {
  59. return titlePaneLayout;
  60. }
  61. abstract void paintButtonBackground(SynthContext context, Graphics g, int x, int y, int w,int h);
  62. abstract void paintFrameBorder(SynthContext context, Graphics g, int x0, int y0, int width, int height);
  63. abstract Insets getBorderInsets(SynthContext context, Insets insets);
  64. private static String getThemeDir(final String theme) {
  65. return (String)AccessController.doPrivileged(new PrivilegedAction() {
  66. public Object run() {
  67. String[] dirs = new String[] {
  68. "/usr/share/themes/"+theme+"/metacity-1",
  69. "/usr/gnome/share/themes/"+theme+"/metacity-1",
  70. "/opt/gnome2/share/themes/"+theme+"/metacity-1"
  71. };
  72. for (int i = 0; i < dirs.length; i++) {
  73. if (new File(dirs[i], "metacity-theme-1.xml").canRead()) {
  74. return dirs[i];
  75. }
  76. }
  77. return null;
  78. }
  79. });
  80. }
  81. private static String getUserTheme() {
  82. return (String)AccessController.doPrivileged(new PrivilegedAction() {
  83. public Object run() {
  84. try {
  85. String theme = System.getProperty("swing.metacitythemename");
  86. if (theme != null) {
  87. return theme;
  88. }
  89. String home = System.getProperty("user.home");
  90. URL url = new URL("file:"+home+"/.gconf/apps/metacity/general/%25gconf.xml");
  91. Reader reader = new InputStreamReader(url.openStream(), "ISO-8859-1");
  92. char[] buf = new char[1024];
  93. StringBuffer strBuf = new StringBuffer();
  94. int n;
  95. while ((n = reader.read(buf)) >= 0) {
  96. strBuf.append(buf, 0, n);
  97. }
  98. reader.close();
  99. String str = strBuf.toString();
  100. if (str != null) {
  101. int i = str.toLowerCase().indexOf("<entry name=\"theme\"");
  102. if (i >= 0) {
  103. i = str.toLowerCase().indexOf("<stringvalue>", i);
  104. if (i > 0) {
  105. i += "<stringvalue>".length();
  106. int i2 = str.indexOf("<", i);
  107. return str.substring(i, i2);
  108. }
  109. }
  110. }
  111. } catch (Exception ex) {
  112. // OK to just ignore. We'll use a fallback theme.
  113. }
  114. return null;
  115. }
  116. });
  117. }
  118. protected void tileImage(Graphics g, Image image, int x0, int y0, int w, int h, float[] alphas) {
  119. Graphics2D g2 = (Graphics2D)g;
  120. Composite oldComp = g2.getComposite();
  121. int sw = image.getWidth(null);
  122. int sh = image.getHeight(null);
  123. int y = y0;
  124. while (y < y0 + h) {
  125. sh = Math.min(sh, y0 + h - y);
  126. int x = x0;
  127. while (x < x0 + w) {
  128. float f = (alphas.length - 1.0F) * x / (x0 + w);
  129. int i = (int)f;
  130. f -= (int)f;
  131. float alpha = (1-f) * alphas[i] + f * alphas[i+1];
  132. g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
  133. int swm = Math.min(sw, x0 + w - x);
  134. g.drawImage(image, x, y, x+swm, y+sh, 0, 0, swm, sh, null);
  135. x += swm;
  136. }
  137. y += sh;
  138. }
  139. g2.setComposite(oldComp);
  140. }
  141. protected Color getColor(int state, ColorType type) {
  142. return ((GTKStyle)context.getStyle()).getGTKColor(context.getComponent(),
  143. context.getRegion(),
  144. state, type);
  145. }
  146. protected static Color shadeColor(Color c, float f) {
  147. return GTKColorType.adjustColor(c, 1.0F, f, f);
  148. }
  149. protected Color blendColor(Color bg, Color fg, float alpha) {
  150. return new Color((int)(bg.getRed() + ((fg.getRed() - bg.getRed()) * alpha)),
  151. (int)(bg.getRed() + ((fg.getRed() - bg.getRed()) * alpha)),
  152. (int)(bg.getRed() + ((fg.getRed() - bg.getRed()) * alpha)));
  153. }
  154. protected void tintRect(Graphics g, int x, int y, int w, int h, Color c, float alpha) {
  155. if (g instanceof Graphics2D) {
  156. Graphics2D g2 = (Graphics2D)g;
  157. Composite oldComp = g2.getComposite();
  158. AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
  159. g2.setComposite(ac);
  160. g2.setColor(c);
  161. g2.fillRect(x, y, w, h);
  162. g2.setComposite(oldComp);
  163. }
  164. }
  165. protected void drawVerticalGradient(Graphics g, Color color1, Color color2,
  166. int x0, int y0, int width, int height, float alpha) {
  167. if (g instanceof Graphics2D) {
  168. Graphics2D g2 = (Graphics2D)g;
  169. Composite oldComp = g2.getComposite();
  170. AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
  171. g2.setComposite(ac);
  172. g2.setPaint(new GradientPaint(x0, y0, color1, x0, y0 + height, color2));
  173. g2.fillRect(x0, y0, width, height);
  174. g2.setComposite(oldComp);
  175. }
  176. }
  177. protected void drawVerticalGradient(Graphics g, Color color1, Color color2,
  178. int x0, int y0, int width, int height) {
  179. if (g instanceof Graphics2D) {
  180. Graphics2D g2 = (Graphics2D)g;
  181. g2.setPaint(new GradientPaint(x0, y0, color1, x0, y0 + height, color2));
  182. g2.fillRect(x0, y0, width, height);
  183. }
  184. }
  185. protected void drawVerticalGradient(Graphics g, Color color1, Color color2, Color color3,
  186. int x0, int y0, int width, int height) {
  187. if (g instanceof Graphics2D) {
  188. Graphics2D g2 = (Graphics2D)g;
  189. g2.setPaint(new GradientPaint(x0, y0, color1, x0, y0 + height2, color2));
  190. g2.fillRect(x0, y0, width, height2);
  191. g2.setPaint(new GradientPaint(x0, y0 + height2, color2, x0, y0 + height, color3));
  192. g2.fillRect(x0, y0 + height2, width, height2);
  193. }
  194. }
  195. protected void drawDiagonalGradient(Graphics g, Color color1, Color color2,
  196. int x0, int y0, int width, int height, float alpha) {
  197. if (g instanceof Graphics2D) {
  198. Graphics2D g2 = (Graphics2D)g;
  199. Composite oldComp = g2.getComposite();
  200. AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
  201. g2.setComposite(ac);
  202. g2.setPaint(new GradientPaint(x0, y0, color1, x0 + width, y0 + height, color2));
  203. g2.fillRect(x0, y0, width, height);
  204. g2.setComposite(oldComp);
  205. }
  206. }
  207. protected void drawDiagonalGradient(Graphics g, Color color1, Color color2,
  208. int x0, int y0, int width, int height) {
  209. if (g instanceof Graphics2D) {
  210. Graphics2D g2 = (Graphics2D)g;
  211. g2.setPaint(new GradientPaint(x0, y0, color1, x0 + width, y0 + height, color2));
  212. g2.fillRect(x0, y0, width, height);
  213. }
  214. }
  215. protected Image colorizeImage(Image image, Color c) {
  216. return imageFilter.colorize(image, c);
  217. }
  218. private class ColorizeImageFilter extends RGBImageFilter {
  219. double cr, cg, cb;
  220. public ColorizeImageFilter() {
  221. canFilterIndexColorModel = true;
  222. }
  223. public void setColor(Color color) {
  224. cr = color.getRed() / 255.0;
  225. cg = color.getGreen() / 255.0;
  226. cb = color.getBlue() / 255.0;
  227. }
  228. public Image colorize(Image fromImage, Color c) {
  229. setColor(c);
  230. ImageProducer producer = new FilteredImageSource(fromImage.getSource(), this);
  231. return new ImageIcon(context.getComponent().createImage(producer)).getImage();
  232. }
  233. public int filterRGB(int x, int y, int rgb) {
  234. // Assume all rgb values are shades of gray
  235. double grayLevel = 2 * (rgb & 0xff) / 255.0;
  236. double r, g, b;
  237. if (grayLevel <= 1.0) {
  238. r = cr * grayLevel;
  239. g = cg * grayLevel;
  240. b = cb * grayLevel;
  241. } else {
  242. grayLevel -= 1.0;
  243. r = cr + (1.0 - cr) * grayLevel;
  244. g = cg + (1.0 - cg) * grayLevel;
  245. b = cb + (1.0 - cb) * grayLevel;
  246. }
  247. return ((rgb & 0xff000000) +
  248. (((int)(r * 255)) << 16) +
  249. (((int)(g * 255)) << 8) +
  250. (int)(b * 255));
  251. }
  252. }
  253. protected static JComponent findChild(JComponent parent, String name) {
  254. int n = parent.getComponentCount();
  255. for (int i = 0; i < n; i++) {
  256. JComponent c = (JComponent)parent.getComponent(i);
  257. if (name.equals(c.getName())) {
  258. return c;
  259. }
  260. }
  261. return null;
  262. }
  263. protected static class TitlePaneLayout implements LayoutManager {
  264. public void addLayoutComponent(String name, Component c) {}
  265. public void removeLayoutComponent(Component c) {}
  266. public Dimension preferredLayoutSize(Container c) {
  267. return minimumLayoutSize(c);
  268. }
  269. public Dimension minimumLayoutSize(Container c) {
  270. JComponent titlePane = (JComponent)c;
  271. Container titlePaneParent = titlePane.getParent();
  272. JInternalFrame frame;
  273. if (titlePaneParent instanceof JInternalFrame) {
  274. frame = (JInternalFrame)titlePaneParent;
  275. } else if (titlePaneParent instanceof JInternalFrame.JDesktopIcon) {
  276. frame = ((JInternalFrame.JDesktopIcon)titlePaneParent).getInternalFrame();
  277. } else {
  278. return null;
  279. }
  280. FrameGeometry gm = INSTANCE.getFrameGeometry();
  281. // Calculate width.
  282. int width = 22;
  283. if (frame.isClosable()) {
  284. width += 19;
  285. }
  286. if (frame.isMaximizable()) {
  287. width += 19;
  288. }
  289. if (frame.isIconifiable()) {
  290. width += 19;
  291. }
  292. FontMetrics fm = titlePane.getFontMetrics(titlePane.getFont());
  293. String frameTitle = frame.getTitle();
  294. int title_w = frameTitle != null ? fm.stringWidth(frameTitle) : 0;
  295. int title_length = frameTitle != null ? frameTitle.length() : 0;
  296. // Leave room for three characters in the title.
  297. if (title_length > 3) {
  298. int subtitle_w = fm.stringWidth(frameTitle.substring(0, 3) + "...");
  299. width += (title_w < subtitle_w) ? title_w : subtitle_w;
  300. } else {
  301. width += title_w;
  302. }
  303. // Calculate height.
  304. Icon icon = frame.getFrameIcon();
  305. int fontHeight = (fm.getHeight() + gm.title_vertical_pad +
  306. gm.title_border.top + gm.title_border.bottom);
  307. int iconHeight = 0;
  308. if (icon != null) {
  309. // SystemMenuBar forces the icon to be 16x16 or less.
  310. iconHeight = Math.min(icon.getIconHeight(), 16);
  311. }
  312. int height = Math.max(fontHeight, iconHeight+2);
  313. return new Dimension(width, height);
  314. }
  315. public void layoutContainer(Container c) {
  316. JComponent titlePane = (JComponent)c;
  317. Container titlePaneParent = titlePane.getParent();
  318. JInternalFrame frame;
  319. if (titlePaneParent instanceof JInternalFrame) {
  320. frame = (JInternalFrame)titlePaneParent;
  321. } else if (titlePaneParent instanceof JInternalFrame.JDesktopIcon) {
  322. frame = ((JInternalFrame.JDesktopIcon)titlePaneParent).getInternalFrame();
  323. } else {
  324. return;
  325. }
  326. boolean leftToRight = SynthLookAndFeel.isLeftToRight(frame);
  327. FrameGeometry gm = INSTANCE.getFrameGeometry();
  328. int w = titlePane.getWidth();
  329. int h = titlePane.getHeight();
  330. JComponent menuButton =
  331. findChild(titlePane, "InternalFrameTitlePane.menuButton");
  332. JComponent minimizeButton =
  333. findChild(titlePane, "InternalFrameTitlePane.iconifyButton");
  334. JComponent maximizeButton =
  335. findChild(titlePane, "InternalFrameTitlePane.maximizeButton");
  336. JComponent closeButton =
  337. findChild(titlePane, "InternalFrameTitlePane.closeButton");
  338. int buttonGap = 0;
  339. int buttonHeight = h - gm.title_border.top - gm.title_border.bottom;
  340. int buttonWidth = (int)(buttonHeight / gm.aspect_ratio);
  341. Icon icon = frame.getFrameIcon();
  342. int iconHeight = (icon != null) ? icon.getIconHeight() : buttonHeight;
  343. int x = (leftToRight) ? gm.left_titlebar_edge : w - buttonWidth - gm.right_titlebar_edge;
  344. int y = gm.title_border.top;
  345. menuButton.setBounds(x, y, buttonWidth, buttonHeight);
  346. x = (leftToRight) ? w - buttonWidth - gm.right_titlebar_edge : gm.left_titlebar_edge;
  347. if (frame.isClosable()) {
  348. closeButton.setBounds(x, y, buttonWidth, buttonHeight);
  349. x += (leftToRight) ? -(buttonWidth + buttonGap) : buttonWidth + buttonGap;
  350. }
  351. if (frame.isMaximizable()) {
  352. maximizeButton.setBounds(x, y, buttonWidth, buttonHeight);
  353. x += (leftToRight) ? -(buttonWidth + buttonGap) : buttonWidth + buttonGap;
  354. }
  355. if (frame.isIconifiable()) {
  356. minimizeButton.setBounds(x, y, buttonWidth, buttonHeight);
  357. }
  358. }
  359. } // end TitlePaneLayout
  360. protected FrameGeometry getFrameGeometry() {
  361. return geometry;
  362. }
  363. protected void setFrameGeometry(JComponent titlePane, FrameGeometry geometry) {
  364. this.geometry = geometry;
  365. if (geometry.top_height == 0) {
  366. geometry.top_height = titlePane.getHeight();
  367. }
  368. }
  369. protected static class FrameGeometry {
  370. int left_width;
  371. int right_width;
  372. int top_height;
  373. int bottom_height;
  374. int left_titlebar_edge;
  375. int right_titlebar_edge;
  376. float aspect_ratio;
  377. int title_vertical_pad;
  378. Insets title_border;
  379. Insets button_border;
  380. }
  381. }