001: /*
002: * Copyright 1995-2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025: package sun.awt.motif;
026:
027: import java.util.Vector;
028: import java.awt.*;
029: import java.awt.peer.*;
030: import java.awt.event.*;
031: import sun.awt.motif.MInputMethodControl;
032: import sun.awt.im.*;
033: import java.awt.image.ColorModel;
034: import java.awt.image.BufferedImage;
035: import java.awt.image.DataBuffer;
036: import java.awt.image.DataBufferInt;
037: import java.awt.image.DataBufferByte;
038: import java.awt.image.DataBufferUShort;
039: import java.awt.image.ImageObserver;
040: import java.awt.image.WritableRaster;
041: import sun.awt.image.ImageRepresentation;
042: import sun.awt.image.ToolkitImage;
043:
044: class MFramePeer extends MWindowPeer implements FramePeer,
045: MInputMethodControl {
046: static Vector allFrames = new Vector();
047:
048: // XXX: Stub out for now. Need to propagate to normal size hints.
049: public void setMaximizedBounds(Rectangle b) {
050: }
051:
052: public void create(MComponentPeer parent, Object arg) {
053: super .create(parent);
054: }
055:
056: MFramePeer(Frame target) {
057: super ();
058: // set the window attributes for this Frame
059: winAttr.nativeDecor = !target.isUndecorated();
060: winAttr.initialFocus = true;
061: winAttr.isResizable = target.isResizable();
062: winAttr.initialState = target.getState();
063: winAttr.title = target.getTitle();
064: winAttr.icon = target.getIconImage();
065: if (winAttr.nativeDecor) {
066: winAttr.decorations = winAttr.AWT_DECOR_ALL;
067: } else {
068: winAttr.decorations = winAttr.AWT_DECOR_NONE;
069: }
070:
071: // for input method windows, use minimal decorations
072: if (target instanceof InputMethodWindow) {
073: winAttr.initialFocus = false;
074: winAttr.decorations = (winAttr.AWT_DECOR_TITLE | winAttr.AWT_DECOR_BORDER);
075: }
076:
077: // create and init native component
078: init(target);
079: if (winAttr.icon != null) {
080: setIconImage(winAttr.icon);
081: }
082: allFrames.addElement(this );
083: }
084:
085: public void setTitle(String title) {
086: pSetTitle(title);
087: }
088:
089: protected void disposeImpl() {
090: allFrames.removeElement(this );
091: super .disposeImpl();
092: }
093:
094: public void setMenuBar(MenuBar mb) {
095: MMenuBarPeer mbpeer = (MMenuBarPeer) MToolkit.targetToPeer(mb);
096: pSetMenuBar(mbpeer);
097:
098: Rectangle r = target.bounds();
099:
100: pReshape(r.x, r.y, r.width, r.height);
101: if (target.isVisible()) {
102: target.validate();
103: }
104: }
105:
106: public void setIconImage(Image im) {
107: int width;
108: int height;
109: GraphicsConfiguration defaultGC;
110: if (im != null) { // 4633887 Avoid Null pointer exception.
111: if (im instanceof ToolkitImage) {
112: ImageRepresentation ir = ((ToolkitImage) im)
113: .getImageRep();
114: ir.reconstruct(ImageObserver.ALLBITS);
115: width = ir.getWidth();
116: height = ir.getHeight();
117: } else {
118: width = im.getWidth(null);
119: height = im.getHeight(null);
120: }
121: if (pGetIconSize(width, height)) {
122: //Icons are displayed using the default visual, so create image
123: //using default GraphicsConfiguration
124: defaultGC = getGraphicsConfiguration().getDevice()
125: .getDefaultConfiguration();
126: ColorModel model = defaultGC.getColorModel();
127: WritableRaster raster = model
128: .createCompatibleWritableRaster(iconWidth,
129: iconHeight);
130: Image image = new BufferedImage(model, raster, model
131: .isAlphaPremultiplied(), null);
132:
133: // ARGB BufferedImage to hunt for transparent pixels
134: BufferedImage bimage = new BufferedImage(iconWidth,
135: iconHeight, BufferedImage.TYPE_INT_ARGB);
136: ColorModel alphaCheck = bimage.getColorModel();
137: Graphics g = image.getGraphics();
138: Graphics big = bimage.getGraphics();
139: try {
140: g.drawImage(im, 0, 0, iconWidth, iconHeight, null);
141: big
142: .drawImage(im, 0, 0, iconWidth, iconHeight,
143: null);
144: } finally {
145: g.dispose();
146: big.dispose();
147: }
148:
149: DataBuffer db = ((BufferedImage) image).getRaster()
150: .getDataBuffer();
151: DataBuffer bidb = bimage.getRaster().getDataBuffer();
152: byte[] bytedata = null;
153: int[] intdata = null;
154: int bidbLen = bidb.getSize();
155: int imgDataIdx;
156: //Get native RGB value for window background color
157: //Should work for byte as well as int
158: int bgRGB = getNativeColor(SystemColor.window,
159: defaultGC);
160:
161: /* My first attempt at a solution to bug 4175560 was to use
162: * the iconMask and iconPixmap attributes of Windows.
163: * This worked fine on CDE/dtwm, however olwm displayed only
164: * single color icons (white on background). Instead, the
165: * fix gets the default background window color and replaces
166: * transparent pixels in the icon image with this color. This
167: * solutions works well with dtwm as well as olwm.
168: */
169:
170: for (imgDataIdx = 0; imgDataIdx < bidbLen; imgDataIdx++) {
171: if (alphaCheck.getAlpha(bidb.getElem(imgDataIdx)) == 0) {
172: //Assuming single data bank
173: db.setElem(imgDataIdx, bgRGB);
174: }
175: }
176: short[] ushortdata = null;
177: if (db instanceof DataBufferByte) {
178: // Pseudocolor data
179: bytedata = ((DataBufferByte) db).getData();
180: } else if (db instanceof DataBufferInt) {
181: // Truecolor data
182: intdata = ((DataBufferInt) db).getData();
183: } else if (db instanceof DataBufferUShort) {
184: // Truecolor data
185: ushortdata = ((DataBufferUShort) db).getData();
186: }
187: pSetIconImage(bytedata, intdata, ushortdata, iconWidth,
188: iconHeight);
189: }
190: }
191: }
192:
193: native boolean pGetIconSize(int widthHint, int heightHint);
194:
195: // [jk] added ushortData for 16-bpp displays
196: native void pSetIconImage(byte[] byteData, int[] intData,
197: short[] ushortData, int iconWidth, int iconHeight);
198:
199: // NOTE: This method may be called by privileged threads.
200: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
201: public void handleIconify() {
202: postEvent(new WindowEvent((Window) target,
203: WindowEvent.WINDOW_ICONIFIED));
204: }
205:
206: // NOTE: This method may be called by privileged threads.
207: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
208: public void handleDeiconify() {
209: postEvent(new WindowEvent((Window) target,
210: WindowEvent.WINDOW_DEICONIFIED));
211: }
212:
213: /**
214: * Called to inform the Frame that it has moved.
215: */
216: // NOTE: This method may be called by privileged threads.
217: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
218: public void handleMoved(int x, int y) {
219: postEvent(new ComponentEvent(target,
220: ComponentEvent.COMPONENT_MOVED));
221: }
222:
223: static final int CROSSHAIR_INSET = 5;
224:
225: static final int BUTTON_Y = CROSSHAIR_INSET + 1;
226: static final int BUTTON_W = 17;
227: static final int BUTTON_H = 17;
228:
229: static final int SYS_MENU_X = CROSSHAIR_INSET + 1;
230: static final int SYS_MENU_CONTAINED_X = SYS_MENU_X + 5;
231: static final int SYS_MENU_CONTAINED_Y = BUTTON_Y + 7;
232: static final int SYS_MENU_CONTAINED_W = 8;
233: static final int SYS_MENU_CONTAINED_H = 3;
234:
235: static final int MAXIMIZE_X_DIFF = CROSSHAIR_INSET + BUTTON_W;
236: static final int MAXIMIZE_CONTAINED_X_DIFF = MAXIMIZE_X_DIFF - 5;
237: static final int MAXIMIZE_CONTAINED_Y = BUTTON_Y + 5;
238: static final int MAXIMIZE_CONTAINED_W = 8;
239: static final int MAXIMIZE_CONTAINED_H = 8;
240:
241: static final int MINIMIZE_X_DIFF = MAXIMIZE_X_DIFF + BUTTON_W;
242: static final int MINIMIZE_CONTAINED_X_DIFF = MINIMIZE_X_DIFF - 7;
243: static final int MINIMIZE_CONTAINED_Y = BUTTON_Y + 7;
244: static final int MINIMIZE_CONTAINED_W = 3;
245: static final int MINIMIZE_CONTAINED_H = 3;
246:
247: static final int TITLE_X = SYS_MENU_X + BUTTON_W;
248: static final int TITLE_W_DIFF = BUTTON_W * 3 + CROSSHAIR_INSET * 2
249: - 1;
250: static final int TITLE_MID_Y = BUTTON_Y + (BUTTON_H / 2);
251:
252: static final int MENUBAR_X = CROSSHAIR_INSET + 1;
253: static final int MENUBAR_Y = BUTTON_Y + BUTTON_H;
254:
255: static final int HORIZ_RESIZE_INSET = CROSSHAIR_INSET + BUTTON_H;
256: static final int VERT_RESIZE_INSET = CROSSHAIR_INSET + BUTTON_W;
257:
258: /*
259: * Print the native component by rendering the Motif look ourselves.
260: * We also explicitly print the MenuBar since a MenuBar isn't a subclass
261: * of Component (and thus it has no "print" method which gets called by
262: * default).
263: */
264: public void print(Graphics g) {
265: super .print(g);
266:
267: Frame f = (Frame) target;
268: Insets finsets = f.getInsets();
269: Dimension fsize = f.getSize();
270:
271: Color bg = f.getBackground();
272: Color fg = f.getForeground();
273: Color highlight = bg.brighter();
274: Color shadow = bg.darker();
275:
276: // Well, we could query for the currently running window manager
277: // and base the look on that, or we could just always do dtwm.
278: // aim, tball, and levenson all agree we'll just do dtwm.
279:
280: if (hasDecorations(MWindowAttributes.AWT_DECOR_BORDER)) {
281:
282: // top outer -- because we'll most likely be drawing on white paper,
283: // for aesthetic reasons, don't make any part of the outer border
284: // pure white
285: if (highlight.equals(Color.white)) {
286: g.setColor(new Color(230, 230, 230));
287: } else {
288: g.setColor(highlight);
289: }
290: g.drawLine(0, 0, fsize.width, 0);
291: g.drawLine(0, 1, fsize.width - 1, 1);
292:
293: // left outer
294: // if (highlight.equals(Color.white)) {
295: // g.setColor(new Color(230, 230, 230));
296: // }
297: // else {
298: // g.setColor(highlight);
299: // }
300: g.drawLine(0, 0, 0, fsize.height);
301: g.drawLine(1, 0, 1, fsize.height - 1);
302:
303: // bottom cross-hair
304: g.setColor(highlight);
305: g.drawLine(CROSSHAIR_INSET + 1, fsize.height
306: - CROSSHAIR_INSET, fsize.width - CROSSHAIR_INSET,
307: fsize.height - CROSSHAIR_INSET);
308:
309: // right cross-hair
310: // g.setColor(highlight);
311: g.drawLine(fsize.width - CROSSHAIR_INSET,
312: CROSSHAIR_INSET + 1, fsize.width - CROSSHAIR_INSET,
313: fsize.height - CROSSHAIR_INSET);
314:
315: // bottom outer
316: g.setColor(shadow);
317: g.drawLine(1, fsize.height, fsize.width, fsize.height);
318: g.drawLine(2, fsize.height - 1, fsize.width,
319: fsize.height - 1);
320:
321: // right outer
322: // g.setColor(shadow);
323: g.drawLine(fsize.width, 1, fsize.width, fsize.height);
324: g.drawLine(fsize.width - 1, 2, fsize.width - 1,
325: fsize.height);
326:
327: // top cross-hair
328: // g.setColor(shadow);
329: g.drawLine(CROSSHAIR_INSET, CROSSHAIR_INSET, fsize.width
330: - CROSSHAIR_INSET, CROSSHAIR_INSET);
331:
332: // left cross-hair
333: // g.setColor(shadow);
334: g.drawLine(CROSSHAIR_INSET, CROSSHAIR_INSET,
335: CROSSHAIR_INSET, fsize.height - CROSSHAIR_INSET);
336: }
337:
338: if (hasDecorations(MWindowAttributes.AWT_DECOR_TITLE)) {
339:
340: if (hasDecorations(MWindowAttributes.AWT_DECOR_MENU)) {
341:
342: // system menu
343: g.setColor(bg);
344: g.fill3DRect(SYS_MENU_X, BUTTON_Y, BUTTON_W, BUTTON_H,
345: true);
346: g.fill3DRect(SYS_MENU_CONTAINED_X,
347: SYS_MENU_CONTAINED_Y, SYS_MENU_CONTAINED_W,
348: SYS_MENU_CONTAINED_H, true);
349: }
350:
351: // title bar
352: // g.setColor(bg);
353: g.fill3DRect(TITLE_X, BUTTON_Y, fsize.width - TITLE_W_DIFF,
354: BUTTON_H, true);
355:
356: if (hasDecorations(MWindowAttributes.AWT_DECOR_MINIMIZE)) {
357:
358: // minimize button
359: // g.setColor(bg);
360: g.fill3DRect(fsize.width - MINIMIZE_X_DIFF, BUTTON_Y,
361: BUTTON_W, BUTTON_H, true);
362: g.fill3DRect(fsize.width - MINIMIZE_CONTAINED_X_DIFF,
363: MINIMIZE_CONTAINED_Y, MINIMIZE_CONTAINED_W,
364: MINIMIZE_CONTAINED_H, true);
365: }
366:
367: if (hasDecorations(MWindowAttributes.AWT_DECOR_MAXIMIZE)) {
368:
369: // maximize button
370: // g.setColor(bg);
371: g.fill3DRect(fsize.width - MAXIMIZE_X_DIFF, BUTTON_Y,
372: BUTTON_W, BUTTON_H, true);
373: g.fill3DRect(fsize.width - MAXIMIZE_CONTAINED_X_DIFF,
374: MAXIMIZE_CONTAINED_Y, MAXIMIZE_CONTAINED_W,
375: MAXIMIZE_CONTAINED_H, true);
376: }
377:
378: // title bar text
379: g.setColor(fg);
380: Font sysfont = new Font(Font.SANS_SERIF, Font.PLAIN, 10);
381: g.setFont(sysfont);
382: FontMetrics sysfm = g.getFontMetrics();
383: String ftitle = f.getTitle();
384: g
385: .drawString(ftitle, ((TITLE_X + TITLE_X
386: + fsize.width - TITLE_W_DIFF) / 2)
387: - (sysfm.stringWidth(ftitle) / 2),
388: TITLE_MID_Y + sysfm.getMaxDescent());
389: }
390:
391: if (f.isResizable()
392: && hasDecorations(MWindowAttributes.AWT_DECOR_RESIZEH)) {
393:
394: // add resize cross hairs
395:
396: // upper-left horiz (shadow)
397: g.setColor(shadow);
398: g.drawLine(1, HORIZ_RESIZE_INSET, CROSSHAIR_INSET,
399: HORIZ_RESIZE_INSET);
400: // upper-left vert (shadow)
401: // g.setColor(shadow);
402: g.drawLine(VERT_RESIZE_INSET, 1, VERT_RESIZE_INSET,
403: CROSSHAIR_INSET);
404: // upper-right horiz (shadow)
405: // g.setColor(shadow);
406: g
407: .drawLine(fsize.width - CROSSHAIR_INSET + 1,
408: HORIZ_RESIZE_INSET, fsize.width,
409: HORIZ_RESIZE_INSET);
410: // upper-right vert (shadow)
411: // g.setColor(shadow);
412: g.drawLine(fsize.width - VERT_RESIZE_INSET - 1, 2,
413: fsize.width - VERT_RESIZE_INSET - 1,
414: CROSSHAIR_INSET + 1);
415: // lower-left horiz (shadow)
416: // g.setColor(shadow);
417: g.drawLine(1, fsize.height - HORIZ_RESIZE_INSET - 1,
418: CROSSHAIR_INSET, fsize.height - HORIZ_RESIZE_INSET
419: - 1);
420: // lower-left vert (shadow)
421: // g.setColor(shadow);
422: g.drawLine(VERT_RESIZE_INSET, fsize.height
423: - CROSSHAIR_INSET + 1, VERT_RESIZE_INSET,
424: fsize.height);
425: // lower-right horiz (shadow)
426: // g.setColor(shadow);
427: g.drawLine(fsize.width - CROSSHAIR_INSET + 1, fsize.height
428: - HORIZ_RESIZE_INSET - 1, fsize.width, fsize.height
429: - HORIZ_RESIZE_INSET - 1);
430: // lower-right vert (shadow)
431: // g.setColor(shadow);
432: g.drawLine(fsize.width - VERT_RESIZE_INSET - 1,
433: fsize.height - CROSSHAIR_INSET + 1, fsize.width
434: - VERT_RESIZE_INSET - 1, fsize.height);
435:
436: // upper-left horiz (highlight)
437: g.setColor(highlight);
438: g.drawLine(2, HORIZ_RESIZE_INSET + 1, CROSSHAIR_INSET,
439: HORIZ_RESIZE_INSET + 1);
440: // upper-left vert (highlight)
441: // g.setColor(highlight);
442: g.drawLine(VERT_RESIZE_INSET + 1, 2, VERT_RESIZE_INSET + 1,
443: CROSSHAIR_INSET);
444: // upper-right horiz (highlight)
445: // g.setColor(highlight);
446: g.drawLine(fsize.width - CROSSHAIR_INSET + 1,
447: HORIZ_RESIZE_INSET + 1, fsize.width - 1,
448: HORIZ_RESIZE_INSET + 1);
449: // upper-right vert (highlight)
450: // g.setColor(highlight);
451: g.drawLine(fsize.width - VERT_RESIZE_INSET, 2, fsize.width
452: - VERT_RESIZE_INSET, CROSSHAIR_INSET);
453: // lower-left horiz (highlight)
454: // g.setColor(highlight);
455: g.drawLine(2, fsize.height - HORIZ_RESIZE_INSET,
456: CROSSHAIR_INSET, fsize.height - HORIZ_RESIZE_INSET);
457: // lower-left vert (highlight)
458: // g.setColor(highlight);
459: g.drawLine(VERT_RESIZE_INSET + 1, fsize.height
460: - CROSSHAIR_INSET + 1, VERT_RESIZE_INSET + 1,
461: fsize.height - 1);
462: // lower-right horiz (highlight)
463: // g.setColor(highlight);
464: g.drawLine(fsize.width - CROSSHAIR_INSET + 1, fsize.height
465: - HORIZ_RESIZE_INSET, fsize.width - 1, fsize.height
466: - HORIZ_RESIZE_INSET);
467: // lower-right vert (highlight)
468: // g.setColor(highlight);
469: g.drawLine(fsize.width - VERT_RESIZE_INSET, fsize.height
470: - CROSSHAIR_INSET + 1, fsize.width
471: - VERT_RESIZE_INSET, fsize.height - 1);
472: }
473:
474: MenuBar mb = f.getMenuBar();
475: if (mb != null) {
476: MMenuBarPeer peer = (MMenuBarPeer) MToolkit
477: .targetToPeer(mb);
478: if (peer != null) {
479: Insets insets = getInsets();
480: Graphics ng = g.create();
481: int menubarX = 0;
482: int menubarY = 0;
483: if (hasDecorations(MWindowAttributes.AWT_DECOR_BORDER)) {
484: menubarX += CROSSHAIR_INSET + 1;
485: menubarY += CROSSHAIR_INSET + 1;
486: }
487: if (hasDecorations(MWindowAttributes.AWT_DECOR_TITLE)) {
488: menubarY += BUTTON_H;
489: }
490: try {
491: ng.translate(menubarX, menubarY);
492: peer.print(ng);
493: } finally {
494: ng.dispose();
495: }
496: }
497: }
498: }
499:
500: // Saveunders are not done by Frame.
501: void setSaveUnder(boolean state) {
502: }
503:
504: /* Returns the native paint should be posted after setting new size
505: */
506: public boolean checkNativePaintOnSetBounds(int width, int height) {
507: // Fix for 4418155. Undecorated Frame does not repaint
508: // automticaly if shrinking. Should not wait for Expose
509: return ((Frame) target).isUndecorated() ? ((width > oldWidth) || (height > oldHeight))
510: : ((width != oldWidth) || (height != oldHeight));
511: }
512:
513: public void setBoundsPrivate(int x, int y, int width, int height) {
514: setBounds(x, y, width, height);
515: }
516:
517: public Rectangle getBoundsPrivate() {
518: return getBounds();
519: }
520: }
|