blob: c59750aec5120b878f57591f523ffdc036760b40 [file] [log] [blame]
/*
* Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package sun.awt.motif;
import java.util.Vector;
import java.awt.*;
import java.awt.peer.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.ImageObserver;
import sun.awt.image.ImageRepresentation;
import sun.awt.motif.MInputMethod;
import sun.awt.motif.MInputMethodControl;
import sun.awt.im.*;
import sun.awt.DisplayChangedListener;
import sun.awt.SunToolkit;
import sun.awt.X11GraphicsDevice;
class MWindowPeer extends MPanelPeer implements WindowPeer,
DisplayChangedListener {
Insets insets = new Insets( 0, 0, 0, 0 );
MWindowAttributes winAttr;
static Vector allWindows = new Vector();
int iconWidth = -1;
int iconHeight = -1;
int dropTargetCount = 0;
boolean alwaysOnTop;
native void pCreate(MComponentPeer parent, String targetClassName, boolean isFocusableWindow);
native void pShow();
native void pToFront();
native void pShowModal(boolean isModal);
native void pHide();
native void pReshape(int x, int y, int width, int height);
native void pDispose();
native void pSetTitle(String title);
public native void setState(int state);
public native int getState();
public native void setResizable(boolean resizable);
native void addTextComponentNative(MComponentPeer tc);
native void removeTextComponentNative();
native void pSetIMMOption(String option);
native void pSetMenuBar(MMenuBarPeer mbpeer);
native void setSaveUnder(boolean state);
native void registerX11DropTarget(Component target);
native void unregisterX11DropTarget(Component target);
native void updateAlwaysOnTop(boolean isAlwaysOnTop);
private static native void initIDs();
static {
initIDs();
}
// this function is privileged! do not change it to public!
private static int getInset(final String name, final int def) {
Integer tmp = (Integer) java.security.AccessController.doPrivileged(
new sun.security.action.GetIntegerAction(name, def));
return tmp.intValue();
}
MWindowPeer() {
insets = new Insets(0,0,0,0);
winAttr = new MWindowAttributes();
}
MWindowPeer(Window target) {
this();
init(target);
allWindows.addElement(this);
}
void create(MComponentPeer parent) {
pCreate(parent, target.getClass().getName(), ((Window)target).isFocusableWindow());
}
void init( Window target ) {
if ( winAttr.nativeDecor == true ) {
insets.top = getInset("awt.frame.topInset", -1);
insets.left = getInset("awt.frame.leftInset", -1);
insets.bottom = getInset("awt.frame.bottomInset", -1);
insets.right = getInset("awt.frame.rightInset", -1);
}
super.init(target);
InputMethodManager imm = InputMethodManager.getInstance();
String menuString = imm.getTriggerMenuString();
if (menuString != null)
{
pSetIMMOption(menuString);
}
pSetTitle(winAttr.title);
/*
* For Windows and undecorated Frames and Dialogs this just
* disables/enables resizing functions in the system menu.
*/
setResizable(winAttr.isResizable);
setSaveUnder(true);
Font f = target.getFont();
if (f == null) {
f = defaultFont;
target.setFont(f);
setFont(f);
}
Color c = target.getBackground();
if (c == null) {
target.setBackground(SystemColor.window);
setBackground(SystemColor.window);
}
c = target.getForeground();
if (c == null) {
target.setForeground(SystemColor.windowText);
setForeground(SystemColor.windowText);
}
alwaysOnTop = ((Window)target).isAlwaysOnTop() && ((Window)target).isAlwaysOnTopSupported();
GraphicsConfiguration gc = getGraphicsConfiguration();
((X11GraphicsDevice)gc.getDevice()).addDisplayChangedListener(this);
}
/* Support for multiple icons is not implemented in MAWT */
public void updateIconImages() {
if (this instanceof MFramePeer) {
((MFramePeer)this).setIconImage(((Frame)target).getIconImage());
}
}
/* Not implemented in MAWT */
public void updateMinimumSize() {
}
protected void disposeImpl() {
allWindows.removeElement(this);
super.disposeImpl();
}
public native void toBack();
public void setAlwaysOnTop(boolean alwaysOnTop) {
this.alwaysOnTop = alwaysOnTop;
updateAlwaysOnTop(alwaysOnTop);
}
public void toFront() {
if (target.isVisible()) {
updateFocusableWindowState();
pToFront();
}
}
public void updateFocusableWindowState() {
setFocusableWindow(((Window)target).isFocusableWindow());
}
native void setFocusableWindow(boolean value);
public void setVisible( boolean b ) {
if (b) {
updateFocusableWindowState();
}
super.setVisible(b);
updateAlwaysOnTop(alwaysOnTop);
}
public Insets getInsets() {
return insets;
}
public void handleQuit() {
postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING));
}
// XXX: nasty WM, foul play. spank WM author.
public void handleDestroy() {
final Window target = (Window)this.target;
SunToolkit.executeOnEventHandlerThread(target,
new Runnable() {
public void run() {
// This seems like the only reasonable thing we
// could do in this situation as the native window
// is already dead.
target.dispose();
}
});
}
// NOTE: This method may be called by privileged threads.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
public void handleIconify() {
postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED));
}
// NOTE: This method may be called by privileged threads.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
public void handleDeiconify() {
postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED));
}
// NOTE: This method may be called by privileged threads.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
public void handleStateChange(int oldState, int newState) {
postEvent(new WindowEvent((Window)target,
WindowEvent.WINDOW_STATE_CHANGED,
oldState, newState));
}
/**
* Called to inform the Window that its size has changed and it
* should layout its children.
*/
// NOTE: This method may be called by privileged threads.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
public void handleResize(int width, int height) {
// REMIND: Is this secure? Can client code subclass input method?
if (!tcList.isEmpty() &&
!imList.isEmpty()){
int i;
for (i = 0; i < imList.size(); i++){
((MInputMethod)imList.elementAt(i)).configureStatus();
}
}
validateSurface(width, height);
postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED));
}
/**
* DEPRECATED: Replaced by getInsets().
*/
public Insets insets() {
return getInsets();
}
public void handleMoved(int x, int y) {
postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED));
}
private native AWTEvent wrapInSequenced(AWTEvent event);
// NOTE: This method may be called by privileged threads.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
public void handleWindowFocusIn() {
WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_GAINED_FOCUS);
/* wrap in Sequenced, then post*/
postEvent(wrapInSequenced((AWTEvent) we));
}
// NOTE: This method may be called by privileged threads.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
public void handleWindowFocusOut(Window oppositeWindow) {
WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_LOST_FOCUS,
oppositeWindow);
/* wrap in Sequenced, then post*/
postEvent(wrapInSequenced((AWTEvent) we));
}
// relocation of Imm stuff
private Vector imList = new Vector();
private Vector tcList = new Vector();
// NOTE: This method is called by privileged threads.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
void notifyIMMOptionChange(){
// REMIND: IS THIS SECURE??? CAN USER CODE SUBCLASS INPUTMETHODMGR???
InputMethodManager.getInstance().notifyChangeRequest(target);
}
public void addInputMethod(MInputMethod im) {
if (!imList.contains(im))
imList.addElement(im);
}
public void removeInputMethod(MInputMethod im) {
if (imList.contains(im))
imList.removeElement(im);
}
public void addTextComponent(MComponentPeer tc) {
if (tcList.contains(tc))
return;
if (tcList.isEmpty()){
addTextComponentNative(tc);
if (!imList.isEmpty()) {
for (int i = 0; i < imList.size(); i++) {
((MInputMethod)imList.elementAt(i)).reconfigureXIC((MInputMethodControl)this);
}
}
MToolkit.executeOnEventHandlerThread(target, new Runnable() {
public void run() {
synchronized(target.getTreeLock()) {
target.doLayout();
}
}
});
}
tcList.addElement(tc);
}
public void removeTextComponent(MComponentPeer tc) {
if (!tcList.contains(tc))
return;
tcList.removeElement(tc);
if (tcList.isEmpty()){
removeTextComponentNative();
if (!imList.isEmpty()) {
for (int i = 0; i < imList.size(); i++) {
((MInputMethod)imList.elementAt(i)).reconfigureXIC((MInputMethodControl)this);
}
}
target.doLayout();
}
}
public MComponentPeer getTextComponent() {
if (!tcList.isEmpty()) {
return (MComponentPeer)tcList.firstElement();
} else {
return null;
}
}
boolean hasDecorations(int decor) {
if (!winAttr.nativeDecor) {
return false;
}
else {
int myDecor = winAttr.decorations;
boolean hasBits = ((myDecor & decor) == decor);
if ((myDecor & MWindowAttributes.AWT_DECOR_ALL) != 0)
return !hasBits;
else
return hasBits;
}
}
/* Returns the native paint should be posted after setting new size
*/
public boolean checkNativePaintOnSetBounds(int width, int height) {
// Fix for 4418155. Window does not repaint
// automticaly if shrinking. Should not wait for Expose
return (width > oldWidth) || (height > oldHeight);
}
/* --- DisplayChangedListener Stuff --- */
native void resetTargetGC(Component target);
/* Xinerama
* called to update our GC when dragged onto another screen
*/
public void draggedToNewScreen(int screenNum) {
final int finalScreenNum = screenNum;
SunToolkit.executeOnEventHandlerThread((Component)target, new Runnable()
{
public void run() {
displayChanged(finalScreenNum);
}
});
}
/* Xinerama
* called to update our GC when dragged onto another screen
*/
public void displayChanged(int screenNum) {
// update our GC
resetLocalGC(screenNum); /* upcall to MCanvasPeer */
resetTargetGC(target); /* call Window.resetGC() via native */
//propagate to children
super.displayChanged(screenNum); /* upcall to MPanelPeer */
}
/**
* Helper method that executes the displayChanged(screen) method on
* the event dispatch thread. This method is used in the Xinerama case
* and after display mode change events.
*/
private void executeDisplayChangedOnEDT(int screenNum) {
final int finalScreenNum = screenNum;
Runnable dc = new Runnable() {
public void run() {
displayChanged(finalScreenNum);
}
};
SunToolkit.executeOnEventHandlerThread((Component)target, dc);
}
/**
* From the DisplayChangedListener interface; called from
* X11GraphicsDevice when the display mode has been changed.
*/
public void displayChanged() {
GraphicsConfiguration gc = getGraphicsConfiguration();
int curScreenNum = ((X11GraphicsDevice)gc.getDevice()).getScreen();
executeDisplayChangedOnEDT(curScreenNum);
}
/**
* From the DisplayChangedListener interface; top-levels do not need
* to react to this event.
*/
public void paletteChanged() {
}
public synchronized void addDropTarget() {
if (dropTargetCount == 0) {
registerX11DropTarget(target);
}
dropTargetCount++;
}
public synchronized void removeDropTarget() {
dropTargetCount--;
if (dropTargetCount == 0) {
unregisterX11DropTarget(target);
}
}
protected synchronized void updateDropTarget() {
if (dropTargetCount > 0) {
unregisterX11DropTarget(target);
registerX11DropTarget(target);
}
}
public boolean requestWindowFocus() {
return false;
}
public void setModalBlocked(Dialog blocker, boolean blocked) {
// do nothing
}
public void postUngrabEvent() {
postEvent(new sun.awt.UngrabEvent((Window)target));
}
boolean isOwnerOf(MComponentPeer child) {
if (child == null) return false;
Component comp = child.target;
while (comp != null && !(comp instanceof Window)) {
comp = getParent_NoClientCode(comp);
}
if (!(comp instanceof Window)) {
return false;
}
while (comp != null && !(comp == target) && !(comp instanceof Dialog)) {
comp = getParent_NoClientCode(comp);
}
return (comp == target);
}
boolean processUngrabMouseEvent(MComponentPeer compPeer, int x_root, int y_root, int type) {
switch (type) {
case 4: // ButtonPress
// Check that the target is the child of the grabbed
// window or the child of one of the owned windows of
// the grabbed window
if (!isOwnerOf(compPeer)) {
postUngrabEvent();
return true;
}
}
return false;
}
}