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