001: /*
002: * Copyright 1996-2007 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.windows;
026:
027: import java.awt.*;
028: import java.awt.event.*;
029: import java.awt.image.*;
030: import java.awt.peer.*;
031:
032: import java.beans.*;
033:
034: import java.lang.ref.*;
035: import java.lang.reflect.*;
036:
037: import java.security.*;
038:
039: import java.util.*;
040: import java.util.List;
041: import java.util.logging.*;
042:
043: import sun.awt.*;
044: import sun.awt.image.*;
045:
046: public class WWindowPeer extends WPanelPeer implements WindowPeer {
047: private static final DebugHelper dbg = DebugHelper
048: .create(WWindowPeer.class);
049:
050: private static final Logger log = Logger
051: .getLogger("sun.awt.windows.WWindowPeer");
052:
053: // we can't use WDialogPeer as blocker may be an instance of WPrintDialogPeer that
054: // extends WWindowPeer, not WDialogPeer
055: private WWindowPeer modalBlocker = null;
056:
057: /*
058: * A key used for storing a list of active windows in AppContext. The value
059: * is a list of windows, sorted by the time of activation: later a window is
060: * activated, greater its index is in the list.
061: */
062: private final static StringBuffer ACTIVE_WINDOWS_KEY = new StringBuffer(
063: "active_windows_list");
064:
065: /*
066: * Listener for 'activeWindow' KFM property changes. It is added to each
067: * AppContext KFM. See ActiveWindowListener inner class below.
068: */
069: private static PropertyChangeListener activeWindowListener = new ActiveWindowListener();
070:
071: /*
072: * Contains all the AppContexts where activeWindowListener is added to.
073: */
074: private static Set<AppContext> trackedAppContexts = new HashSet<AppContext>();
075:
076: /**
077: * Initialize JNI field IDs
078: */
079: private static native void initIDs();
080:
081: static {
082: initIDs();
083: }
084:
085: // WComponentPeer overrides
086:
087: protected void disposeImpl() {
088: AppContext appContext = SunToolkit.targetToAppContext(target);
089: synchronized (appContext) {
090: List<WWindowPeer> l = (List<WWindowPeer>) appContext
091: .get(ACTIVE_WINDOWS_KEY);
092: if (l != null) {
093: l.remove(this );
094: }
095: }
096: // Remove ourself from the Map of DisplayChangeListeners
097: GraphicsConfiguration gc = getGraphicsConfiguration();
098: ((Win32GraphicsDevice) gc.getDevice())
099: .removeDisplayChangedListener(this );
100: super .disposeImpl();
101: }
102:
103: // WindowPeer implementation
104:
105: public void toFront() {
106: updateFocusableWindowState();
107: _toFront();
108: }
109:
110: native void _toFront();
111:
112: public native void toBack();
113:
114: public native void setAlwaysOnTopNative(boolean value);
115:
116: public void setAlwaysOnTop(boolean value) {
117: if ((value && ((Window) target).isVisible()) || !value) {
118: setAlwaysOnTopNative(value);
119: }
120: }
121:
122: public void updateFocusableWindowState() {
123: setFocusableWindow(((Window) target).isFocusableWindow());
124: }
125:
126: native void setFocusableWindow(boolean value);
127:
128: // FramePeer & DialogPeer partial shared implementation
129:
130: public void setTitle(String title) {
131: // allow a null title to pass as an empty string.
132: if (title == null) {
133: title = new String("");
134: }
135: _setTitle(title);
136: }
137:
138: native void _setTitle(String title);
139:
140: public void setResizable(boolean resizable) {
141: _setResizable(resizable);
142: }
143:
144: public native void _setResizable(boolean resizable);
145:
146: // Toolkit & peer internals
147:
148: WWindowPeer(Window target) {
149: super (target);
150: }
151:
152: void initialize() {
153: super .initialize();
154:
155: updateInsets(insets_);
156:
157: Font f = ((Window) target).getFont();
158: if (f == null) {
159: f = defaultFont;
160: ((Window) target).setFont(f);
161: setFont(f);
162: }
163: // Express our interest in display changes
164: GraphicsConfiguration gc = getGraphicsConfiguration();
165: ((Win32GraphicsDevice) gc.getDevice())
166: .addDisplayChangedListener(this );
167:
168: AppContext appContext = AppContext.getAppContext();
169: synchronized (appContext) {
170: if (!trackedAppContexts.contains(appContext)) {
171: KeyboardFocusManager kfm = KeyboardFocusManager
172: .getCurrentKeyboardFocusManager();
173: kfm.addPropertyChangeListener("activeWindow",
174: activeWindowListener);
175: trackedAppContexts.add(appContext);
176: }
177: }
178:
179: updateIconImages();
180: }
181:
182: native void createAwtWindow(WComponentPeer parent);
183:
184: void create(WComponentPeer parent) {
185: createAwtWindow(parent);
186: }
187:
188: // should be overriden in WDialogPeer
189: protected void realShow() {
190: super .show();
191: }
192:
193: public void show() {
194: updateFocusableWindowState();
195:
196: boolean alwaysOnTop = ((Window) target).isAlwaysOnTop();
197:
198: // Fix for 4868278.
199: // If we create a window with a specific GraphicsConfig, and then move it with
200: // setLocation() or setBounds() to another one before its peer has been created,
201: // then calling Window.getGraphicsConfig() returns wrong config. That may lead
202: // to some problems like wrong-placed tooltips. It is caused by calling
203: // super.displayChanged() in WWindowPeer.displayChanged() regardless of whether
204: // GraphicsDevice was really changed, or not. So we need to track it here.
205: updateGC();
206: resetTargetGC();
207:
208: realShow();
209: updateMinimumSize();
210:
211: if (((Window) target).isAlwaysOnTopSupported() && alwaysOnTop) {
212: setAlwaysOnTop(alwaysOnTop);
213: }
214: }
215:
216: // Synchronize the insets members (here & in helper) with actual window
217: // state.
218: native void updateInsets(Insets i);
219:
220: static native int getSysMinWidth();
221:
222: static native int getSysMinHeight();
223:
224: static native int getSysIconWidth();
225:
226: static native int getSysIconHeight();
227:
228: static native int getSysSmIconWidth();
229:
230: static native int getSysSmIconHeight();
231:
232: /**
233: * Creates native icon from specified raster data and updates
234: * icon for window and all descendant windows that inherit icon.
235: * Raster data should be passed in the ARGB form.
236: * Note that raster data format was changed to provide support
237: * for XP icons with alpha-channel
238: */
239: native void setIconImagesData(int[] iconRaster, int w, int h,
240: int[] smallIconRaster, int smw, int smh);
241:
242: synchronized native void reshapeFrame(int x, int y, int width,
243: int height);
244:
245: public boolean requestWindowFocus() {
246: // Win32 window doesn't need this
247: return false;
248: }
249:
250: public boolean focusAllowedFor() {
251: Window target = (Window) this .target;
252: if (!target.isVisible() || !target.isEnabled()
253: || !target.isFocusable()) {
254: return false;
255: }
256:
257: if (isModalBlocked()) {
258: return false;
259: }
260:
261: return true;
262: }
263:
264: public void updateMinimumSize() {
265: Dimension minimumSize = null;
266: if (((Component) target).isMinimumSizeSet()) {
267: minimumSize = ((Component) target).getMinimumSize();
268: }
269: if (minimumSize != null) {
270: int msw = getSysMinWidth();
271: int msh = getSysMinHeight();
272: int w = (minimumSize.width >= msw) ? minimumSize.width
273: : msw;
274: int h = (minimumSize.height >= msh) ? minimumSize.height
275: : msh;
276: setMinSize(w, h);
277: } else {
278: setMinSize(0, 0);
279: }
280: }
281:
282: public void updateIconImages() {
283: java.util.List<Image> imageList = ((Window) target)
284: .getIconImages();
285: if (imageList == null || imageList.size() == 0) {
286: setIconImagesData(null, 0, 0, null, 0, 0);
287: } else {
288: int w = getSysIconWidth();
289: int h = getSysIconHeight();
290: int smw = getSysSmIconWidth();
291: int smh = getSysSmIconHeight();
292: DataBufferInt iconData = SunToolkit.getScaledIconData(
293: imageList, w, h);
294: DataBufferInt iconSmData = SunToolkit.getScaledIconData(
295: imageList, smw, smh);
296: if (iconData != null && iconSmData != null) {
297: setIconImagesData(iconData.getData(), w, h, iconSmData
298: .getData(), smw, smh);
299: } else {
300: setIconImagesData(null, 0, 0, null, 0, 0);
301: }
302: }
303: }
304:
305: native void setMinSize(int width, int height);
306:
307: /*
308: * ---- MODALITY SUPPORT ----
309: */
310:
311: /**
312: * Some modality-related code here because WFileDialogPeer, WPrintDialogPeer and
313: * WPageDialogPeer are descendants of WWindowPeer, not WDialogPeer
314: */
315:
316: public boolean isModalBlocked() {
317: return modalBlocker != null;
318: }
319:
320: public void setModalBlocked(Dialog dialog, boolean blocked) {
321: synchronized (((Component) getTarget()).getTreeLock()) // State lock should always be after awtLock
322: {
323: // use WWindowPeer instead of WDialogPeer because of FileDialogs and PrintDialogs
324: WWindowPeer blockerPeer = (WWindowPeer) dialog.getPeer();
325: if (blocked) {
326: modalBlocker = blockerPeer;
327: // handle native dialogs separately, as they may have not
328: // got HWND yet; modalEnable/modalDisable is called from
329: // their setHWnd() methods
330: if (blockerPeer instanceof WFileDialogPeer) {
331: ((WFileDialogPeer) blockerPeer).blockWindow(this );
332: } else if (blockerPeer instanceof WPrintDialogPeer) {
333: ((WPrintDialogPeer) blockerPeer).blockWindow(this );
334: } else {
335: modalDisable(dialog, blockerPeer.getHWnd());
336: }
337: } else {
338: modalBlocker = null;
339: if (blockerPeer instanceof WFileDialogPeer) {
340: ((WFileDialogPeer) blockerPeer).unblockWindow(this );
341: } else if (blockerPeer instanceof WPrintDialogPeer) {
342: ((WPrintDialogPeer) blockerPeer)
343: .unblockWindow(this );
344: } else {
345: modalEnable(dialog);
346: }
347: }
348: }
349: }
350:
351: native void modalDisable(Dialog blocker, long blockerHWnd);
352:
353: native void modalEnable(Dialog blocker);
354:
355: /*
356: * Returns all the ever active windows from the current AppContext.
357: * The list is sorted by the time of activation, so the latest
358: * active window is always at the end.
359: */
360: public static long[] getActiveWindowHandles() {
361: AppContext appContext = AppContext.getAppContext();
362: synchronized (appContext) {
363: List<WWindowPeer> l = (List<WWindowPeer>) appContext
364: .get(ACTIVE_WINDOWS_KEY);
365: if (l == null) {
366: return null;
367: }
368: long[] result = new long[l.size()];
369: for (int j = 0; j < l.size(); j++) {
370: result[j] = l.get(j).getHWnd();
371: }
372: return result;
373: }
374: }
375:
376: /*
377: * ----DISPLAY CHANGE SUPPORT----
378: */
379:
380: /*
381: * Called from native code when we have been dragged onto another screen.
382: */
383: void draggedToNewScreen() {
384: SunToolkit.executeOnEventHandlerThread((Component) target,
385: new Runnable() {
386: public void run() {
387: displayChanged();
388: }
389: });
390: }
391:
392: /*
393: * Called from WCanvasPeer.displayChanged().
394: * Override to do nothing - Window and WWindowPeer GC must never be set to
395: * null!
396: */
397: void clearLocalGC() {
398: }
399:
400: public void updateGC() {
401: int scrn = getScreenImOn();
402:
403: // get current GD
404: Win32GraphicsDevice oldDev = (Win32GraphicsDevice) winGraphicsConfig
405: .getDevice();
406:
407: Win32GraphicsDevice newDev;
408: GraphicsDevice devs[] = GraphicsEnvironment
409: .getLocalGraphicsEnvironment().getScreenDevices();
410: // Occasionally during device addition/removal getScreenImOn can return
411: // a non-existing screen number. Use the default device in this case.
412: if (scrn >= devs.length) {
413: newDev = (Win32GraphicsDevice) GraphicsEnvironment
414: .getLocalGraphicsEnvironment()
415: .getDefaultScreenDevice();
416: } else {
417: newDev = (Win32GraphicsDevice) devs[scrn];
418: }
419:
420: // Set winGraphicsConfig to the default GC for the monitor this Window
421: // is now mostly on.
422: winGraphicsConfig = (Win32GraphicsConfig) newDev
423: .getDefaultConfiguration();
424: if (dbg.on) {
425: dbg.assertion(winGraphicsConfig != null);
426: }
427:
428: // if on a different display, take off old GD and put on new GD
429: if (oldDev != newDev) {
430: oldDev.removeDisplayChangedListener(this );
431: newDev.addDisplayChangedListener(this );
432: }
433: }
434:
435: /*
436: * From the DisplayChangedListener interface
437: *
438: * This method handles a display change - either when the display settings
439: * are changed, or when the window has been dragged onto a different
440: * display.
441: */
442: public void displayChanged() {
443: updateGC();
444: super .displayChanged();
445: }
446:
447: private native int getScreenImOn();
448:
449: /*
450: * ----END DISPLAY CHANGE SUPPORT----
451: */
452:
453: public void grab() {
454: nativeGrab();
455: }
456:
457: public void ungrab() {
458: nativeUngrab();
459: }
460:
461: private native void nativeGrab();
462:
463: private native void nativeUngrab();
464:
465: /*
466: * Static inner class, listens for 'activeWindow' KFM property changes and
467: * updates the list of active windows per AppContext, so the latest active
468: * window is always at the end of the list. The list is stored in AppContext.
469: */
470: private static class ActiveWindowListener implements
471: PropertyChangeListener {
472: public void propertyChange(PropertyChangeEvent e) {
473: Window w = (Window) e.getNewValue();
474: if (w == null) {
475: return;
476: }
477: AppContext appContext = SunToolkit.targetToAppContext(w);
478: synchronized (appContext) {
479: List<WWindowPeer> l = (List<WWindowPeer>) appContext
480: .get(ACTIVE_WINDOWS_KEY);
481: if (l == null) {
482: l = new LinkedList<WWindowPeer>();
483: appContext.put(ACTIVE_WINDOWS_KEY, l);
484: }
485: WWindowPeer wp = (WWindowPeer) w.getPeer();
486: // add/move wp to the end of the list
487: l.remove(wp);
488: l.add(wp);
489: }
490: }
491: }
492: }
|