/* -*-mode:java; c-basic-offset:2; -*- */
/* WeirdX - Guess.
 *
 * Copyright (C) 1999-2004 JCraft, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package com.jcraft.weirdx;
import java.io.*;
import java.awt.*;

//import com.sun.java.swing.*;
//import com.sun.java.swing.border.*;
import javax.swing.*;                                    
import javax.swing.border.*;                             

class Window extends Drawable {

  static Object LOCK=Window.class;

  private static final int CWBackPixmap=(1<<0);
  private static final int CWBackPixel=(1<<1);
  private static final int CWBorderPixmap=(1<<2);
  private static final int CWBorderPixel=(1<<3);
  private static final int CWBitGravity=(1<<4);
  private static final int CWWinGravity=(1<<5);
  private static final int CWBackingStore=(1<<6);
  private static final int CWBackingPlanes=(1<<7);
  private static final int CWBackingPixel=(1<<8);
  private static final int CWOverrideRedirect=(1<<9);
  private static final int CWSaveUnder=(1<<10);
  private static final int CWEventMask=(1<<11);
  private static final int CWDontPropagate=(1<<12);
  private static final int CWColormap=(1<<13);
  private static final int CWCursor=(1<<14);

  private static final int CWX=(1<<0);
  private static final int CWY=(1<<1);
  private static final int CWWidth=(1<<2);
  private static final int CWHeight=(1<<3);
  private static final int CWBorderWidth=(1<<4);
  private static final int CWSibling=(1<<5);
  private static final int CWStackMode=(1<<6);

  private static final int ChangeMask=(CWX | CWY | CWWidth | CWHeight);
  private static final int IllegalInputOnlyConfigureMask=CWBorderWidth;

  private static final int CopyFromParent=0;
  private static final int InputOutput=1;
  private static final int InputOnly=2;

  private static final int NotifyNormal=0;
  private static final int NotifyGrab=1;
  private static final int NotifyUngrab=2;
  private static final int NotifyWhileGrabbed=3;

  private static final int NotifyAncestor=0;
  private static final int NotifyVirtual=1;
  private static final int NotifyInferior=2;
  private static final int NotifyNonlinear=3;
  private static final int NotifyNonlinearVirtual=4;
  private static final int NotifyPointer=5;
  private static final int NotifyPointerRoot=6;
  private static final int NotifyDetailNone=7;

  private static final int RevertToNone=0;
  private static final int RevertToPointerRoot=1;
  private static final int RevertToParent=2;

  private static final int NoneWin=0;
  private static final int PointerRootWin=1;
  private static final int PointerRoot=1;

  private static final int FollowKeyboard=3;
  private static final int FollowKeyboardWin=3;

  private static final int AsyncPointer=0;
  private static final int SyncPointer=1;
  private static final int ReplayPointer=2;
  private static final int AsyncKeyboard=3;
  private static final int SyncKeyboard=4;
  private static final int ReplayKeyboard=5;
  private static final int AsyncBoth=6;
  private static final int SyncBoth=7;

  private static final int GrabModeSync=0;
  private static final int GrabModeAsync=1;

  private static final int GrabSuccess=0;
  private static final int AlreadyGrabbed=1;
  private static final int GrabInvalidTime=2;
  private static final int GrabNotViewable=3;
  private static final int GrabFrozen=4;

  static int deltaSaveUndersViewable=0;
  static int defaultBackingStore=0;

  static int AnyModifier=(1<<15);
  static int AnyKey=0;

  private static final int Above=0;
  private static final int Below=1;
  private static final int TopIf=2;
  private static final int BottomIf=3;
  private static final int Opposite=4;

  private static final int Restack=0;
  private static final int Move=1;
  private static final int Resize=2;
  private static final int Reborder=3;

  private static final int NOT_GRABBED=0;
  private static final int THAWED=1;
  private static final int THAWED_BOTH=2;
  private static final int FREEZE_NEXT_EVENT=3;
  private static final int FREEZE_BOTH_NEXT_EVENT=4;
  private static final int FROZEN=5;
  private static final int FROZEN_NO_EVENT=5;
  private static final int FROZEN_WITH_EVENT=6;
  private static final int THAW_OTHERS=7;

  private static final int backgroundStateOffset=0;
  private static final int backgroundState=(3<<0);
  private static final int ParentRelative=(1<<backgroundStateOffset);
  private static final int BackgroundPixel=(2<<backgroundStateOffset);
  private static final int BackgroundPixmap=(3<<backgroundStateOffset);
  private static final int borderIsPixelOffset=2;
  private static final int borderIsPixel=(1<<borderIsPixelOffset);
  private static final int cursorIsNoneOffset=3;
  private static final int cursorIsNone=(1<<cursorIsNoneOffset);
  private static final int backingStoreOffset=4;
  private static final int backingStore=(3<<backingStoreOffset);
  private static final int saveUnderOffset=6;
  private static final int saveUnder=(1<<saveUnderOffset);
  private static final int DIXsaveUnderOffset=7;
  private static final int DIXsaveUnder=(1<<DIXsaveUnderOffset);
  private static final int bitGravityOffset=8;
  private static final int bitGravity=(15<<bitGravityOffset);
  private static final int ForgetGravity=0;
  private static final int winGravityOffset=12;
  private static final int winGravity=(15<<winGravityOffset);
  private static final int ForegetGravity=0;
  private static final int NorthWestGravity=1;
  private static final int NorthGravity=2;
  private static final int NorthEastGravity=3;
  private static final int WestGravity=4;
  private static final int CenterGravity=5;
  private static final int EastGravity=6;
  private static final int SouthWestGravity=7;
  private static final int SouthGravity=8;
  private static final int SouthEastGravity=9;
  private static final int StaticGravity=10;
  private static final int UnmapGravity=0;
  private static final int overrideRedirectOffset=16;
  private static final int overrideRedirect=(1<<overrideRedirectOffset);
  private static final int visibilityOffset=17;
  private static final int visibility=(3<<visibilityOffset);
  private static final int VisibilityUnobscured=0;
  private static final int VisibilityPartiallyObscured=1;
  private static final int VisibilityFullyObscured=2;
  private static final int VisibilityNotViewable=3;
  private static final int mappedOffset=19;
  private static final int mapped=(1<<mappedOffset);
  private static final int realizedOffset=20;
  private static final int realized=(1<<realizedOffset);
  private static final int viewableOffset=21;
  private static final int viewable=(1<<viewableOffset);
  private static final int dontPropagateOffset=22;
  private static final int dontPropagate=(7<<dontPropagateOffset);
  private static final int forcedBSOffset=25;
  private static final int forcedBS=(1<<forcedBSOffset);

  private static final int DBE_FRONT_BUFFER=1;
  private static final int DBE_BACK_BUFFER=0;
  private static final int dstBufferOffset=26;
  private static final int dstBuffer=(1<<dstBufferOffset);
  private static final int srcBufferOffset=27;
  private static final int srcBuffer=(1<<srcBufferOffset);

  private static final int PlaceOnTop=0;
  private static final int PlaceOnBottom=1;

  private static final int RaiseLowest=0;
  private static final int LowerHighest=1;

  static final Focus focus=new Focus();
  static Sprite sprite=new Sprite();
  static int spriteTraceGood=1;
  static Window[] spriteTrace=new Window[10];
  static Point gpoint=new Point();
  static Grab grab=null;

  static Class dDXWindow=null;
  static{
    try{dDXWindow=Class.forName("com.jcraft.weirdx.DDXWindowImp");}
    catch(Exception e){System.err.println(e);}
  }
  static void installDDXWindow(String name){
    Class c=null;
    try{if(name.startsWith("com.jcraft.weirdx."))c=Class.forName(name);}
    catch(Exception e){System.err.println(e);}
    if(c!=null) dDXWindow=c;
  }

  Client client;
  Window parent;
  Window nextSib;
  Window prevSib;
  Window firstChild;
  Window lastChild;

  Point origin=new Point();
  int borderWidth;
  int deliverableEvents;
  int eventMask;
  Pix background=new Pix();
  Pix border=new Pix();
  WindowOpt optional;
  int attr;
  DDXWindow ddxwindow;

  int frame_x=-1;
  int frame_y=-1;
  int frame_width=-1;
  int frame_height=-1;

  Window(int id){
    super(id, RT_WINDOW);
  }

  Window(int wid, Window prnt,
	 int x, int y, int width, int height, int bwidth,
	 int clss, byte depth, Client client, int visual, int msk)
    throws IOException {
    this(wid);
    WindowOpt opt;
    this.client=client;
    this.parent=prnt;
    screen=prnt.screen;

    if(clss==CopyFromParent) clss=prnt.clss;
    this.clss=clss;

    if((clss!=InputOutput) && (clss!=InputOnly)){
      client.errorValue=clss;
      client.errorReason=2; // BadValue;
      return;
    }

    if((clss!=InputOnly) && (prnt.clss==InputOnly)){
      client.errorValue=clss;
      client.errorReason=8; // BadMatch;
      return;
    }
    if((clss==InputOnly) && ((bwidth!=0) || (depth!=0))){
      client.errorValue=0;
      client.errorReason=8; // BadMatch;
      return;
    }

    if((clss==InputOutput) && (depth==0)){
      depth=prnt.depth;
    }

    opt=prnt.optional;
    if(opt==null){
      opt=prnt.findOptional().optional;
    }
    if(visual==CopyFromParent){
      visual=opt.visual;
    }
    if((visual!=opt.visual) || (depth!=prnt.depth)){
      boolean foo=false;
      Depth pdepth;
      for(int i=0; i<screen.depth.length; i++){
	pdepth=screen.depth[i];
	if(depth==pdepth.depth || depth==0){
          if(pdepth.visual!=null){
	    for(int j=0; j<pdepth.visual.length; j++){
	      if(visual==pdepth.visual[j].id){
		foo=true;
		break;
	      }
	    }
	  }
	}
      }
      if(!foo){
	client.errorValue=0;
	client.errorReason=8; // BadMatch;
	return;
      }
    }
    if(((msk & (CWBorderPixmap | CWBorderPixel))==0) &&
	(clss !=InputOnly) &&
	(depth !=prnt.depth)){
      client.errorValue=0;
      client.errorReason=8; // BadMatch;
      return;
    }

    this.depth=depth;
    if(depth==prnt.depth){
      this.bitsPerPixel=prnt.bitsPerPixel;
    }
    else{
      int ii=0;
      while(ii< Format.format.length){
	if(Format.format[ii].depth==screen.rootDepth)break;
	ii++;
      }
      if(ii==Format.format.length){
	// ???
	ii=0;
      }
      this.bitsPerPixel=Format.format[ii].bpp;
    }

    this.type=prnt.type;
    if(clss==InputOnly) this.type=UNDRAWABLE_WINDOW;

    setDefault();

    if(visual!=opt.visual){
      makeOptional();
      this.optional.visual=visual;
      this.optional.colormap=screen.defaultColormap;
    }
    this.borderWidth=bwidth;
    attr&=~backgroundState;
    attr&=~borderIsPixel;
    attr|=(prnt.attr&borderIsPixel);

    this.border=prnt.border.dup();

    if((attr&borderIsPixel)==0){
      this.border.pixmap.ref();
    }
    this.origin.x=(short)(x+bwidth);
    this.origin.y=(short)(y+bwidth);
    this.width=width;
    this.height=height;
    this.x=(short)(prnt.x+x+bwidth);
    this.y=(short)(prnt.y+y+bwidth);

    synchronized(LOCK){
      this.nextSib=prnt.firstChild;
      if(prnt.firstChild!=null) prnt.firstChild.prevSib=this;
      else  prnt.lastChild=this;
      prnt.firstChild=this;
    }

    if((msk&CWEventMask)==0){
      recalculateDeliverableEvents();
    }

    msk&=0x7fff;
    if(msk!=0){
      changeAttr(client, msk);
    }

    if(client.errorReason!=0){
      this.delete();
      return;
    }

    if((msk&CWBackingStore)!=0 &&
       (defaultBackingStore!=0)){
      attr&=~backingStore;
      attr|=(defaultBackingStore<<backingStoreOffset);
      attr|=forcedBS;
    }

    //  ddxwindow=new DDXWindow();
    try{ ddxwindow=(DDXWindow)dDXWindow.newInstance();}
    catch(Exception e){ System.err.println(e); /*ddxwindow=new DDXWindow();*/ }
    ddxwindow.init(this);

    try{
      if(screen.windowmode!=WeirdX.InBrowser && prnt==screen.root){  
        final java.awt.Window frame=getFrame();
	/*
	if(frame instanceof JFrame){                               
	  ((JFrame)frame).setJMenuBar(null);                       
	  ((JFrame)frame).getContentPane().setLayout(null);        
  	  ((JFrame)frame).setResizable(false);                                 
	}                                                          
	else*/ if(frame instanceof Frame){
	  ((Frame)frame).setMenuBar(null);                                  
  	  ((Frame)frame).setResizable(true);
	}                                                          

	ddxwindow.setLocation(0, 0);                               

//	if(frame instanceof JFrame){                               
//	  ((JFrame)frame).getContentPane().add((java.awt.Component)ddxwindow);
//	}                                                          
//	else{                                                      
	  frame.add((java.awt.Component)ddxwindow);
//	}                                                          

	frame.pack();                                            
	Insets insets=frame.getInsets();                         
	/*
	frame.setSize(this.width+this.borderWidth*2+             
		      insets.left+insets.right,                  
		      this.height+this.borderWidth*2+            
		      insets.bottom+insets.top);                 
	*/
	frame.setLocation(this.origin.x-this.borderWidth+        
			  parent.borderWidth,                    
			  this.origin.y-this.borderWidth+        
			  parent.borderWidth);                   

        if(frame instanceof Frame){
          addWindowListener((java.awt.Frame)frame);
          addComponentListener((java.awt.Frame)frame);
	}
      }                                                            
      else {             
	ddxwindow.setLocation(origin.x-borderWidth+parent.borderWidth,
			      origin.y-borderWidth+parent.borderWidth);
	prnt.ddxwindow.add((java.awt.Component)ddxwindow, 0);
      }                                                            
      if((attr&cursorIsNone)==0){
	Cursor cur=getCursor();
	if(cur!=null){
	  ddxwindow.setCursor(cur.cursor);
	}
      }
      if(bwidth > 0){
	ddxwindow.setBorderPixmap(border.pixmap);
      }
    }
    catch(Exception ee){
      //System.out.println("error: Window?? "+ee);
    }

    if(prnt.subSend()){
      client.cevent.mkCreateNotify(prnt.id, id, x, y, width, height,
				   borderWidth,
				   (attr&overrideRedirect)!=0?0:1);
      prnt.sendEvent(client.cevent, 1, null);
    }
  }

  private final void changeAttr(Client c, int vmask) throws IOException{
    int foo;
    boolean borderRelative=false;
    int index=0;
    int mask=vmask;
    IO io=c.client;

    while(mask!=0 && c.length!=0){
      index=lowbit(mask);
      mask&=~index;
      c.length--;
      switch(index){
      case CWBackPixmap:
	foo=io.readInt();
	if((attr&backgroundState)==ParentRelative) borderRelative=true;
	if(foo==0){
	  if((attr&backgroundState)==BackgroundPixmap){
	    if(background.pixmap==null){
	      //System.err.println("BackPixmap: error!!");
	    }
	    else{
	      try{background.pixmap.delete();}catch(Exception e){}
	      background.pixmap=null;
	    }
	  }
	  attr=attr&(~backgroundState);
	} 
	else if(foo==ParentRelative){
	  if(parent!=null && depth!=parent.depth){
	  }
	  if((attr&backgroundState)==BackgroundPixmap){
	    if(background.pixmap==null){
	      //System.err.println("BackPixmap: error!!");
	    }
	    else{
	      try{background.pixmap.delete();}catch(Exception e){}
	      background.pixmap=null;
	    }
	  }
	  if(parent==null){
	  }
	  else{
	    attr=(attr&~backgroundState)|(backgroundState&ParentRelative);
	  }
	  borderRelative=true;
	}
	else{
	  Pixmap pixmap=(Pixmap)Resource.lookupIDByType(foo, 
							Resource.RT_PIXMAP);
	  if(pixmap!=null){
	    if(pixmap.depth!=depth ||
	       pixmap.screen!=screen){
	      //System.err.println("error!!");
	    }
	    if((attr&backgroundState)==BackgroundPixmap){
	      if(background.pixmap==null){
		//System.err.println("BackPixmap: error!!");
	      }
	      else{
		try{background.pixmap.delete();}catch(Exception e){}
		background.pixmap=null;
	      }
	    }
	    attr=(attr&~backgroundState)|(backgroundState&BackgroundPixmap);
	    background.pixmap=pixmap;
	    background.img=pixmap.getImage(this);

	    pixmap.ref();
	  }
	  else{
	    //System.err.println("error!!");
	  }
	}
	break;
      case CWBackPixel:
	foo=io.readInt();
	if((attr&backgroundState)==ParentRelative){
	  borderRelative=true;
	}
	if((attr&backgroundState)==BackgroundPixmap){
	  if(background.pixmap==null){
	    //System.err.println("BackPixel: error!!");
	  }
	  else{
	    try{background.pixmap.delete();}catch(Exception e){}
	    background.pixmap=null;
	  }
	}
	attr&=~backgroundState;
	attr|=BackgroundPixel;
	background.pixel=foo;
	break;
      case CWBorderPixmap:
	foo=io.readInt();
	if(foo==CopyFromParent){
	  if(parent==null || depth!=parent.depth){
	    //System.err.println("err!!");
	  }
	  if((attr&borderIsPixel)==0){
	    if(border.pixmap==null){
	      //System.err.println("BorderPixmap: error!!");
	    }
	    else{
	      try{border.pixmap.delete();}catch(Exception e){}
	      border.pixmap=null;
	    }
	  }

	  border=parent.border.dup();
	  attr&=~borderIsPixel;
	  attr|=(parent.attr&borderIsPixel);
	  if((attr&borderIsPixel)!=0){
	  }
	  else{
	    if(border.pixmap==null){
	      //System.err.println("BorderPixmap: error!!!");
	    }
	    else{
	      border.pixmap.ref();
	    }
	  }
	}
	else{
	  Pixmap pixmap=(Pixmap)Resource.lookupIDByType(foo, Resource.RT_PIXMAP);
	  if(pixmap!=null){
	    if((pixmap.depth!=depth) || (pixmap.screen!=screen)){
	      //System.err.println("error!!");
	    }
	    if((attr&borderIsPixel)==0){
	      if(border.pixmap==null){
		//System.err.println("BorderPixmap: error!!");
	      }
	      else{
		try{border.pixmap.delete();}catch(Exception e){}
		border.pixmap=null;
	      }
	    }
	    attr&=~borderIsPixel;
	    border.pixmap=pixmap;
	    pixmap.ref();
	  }
	  else{
	    //System.err.println("error!!");
	  }
	}
	break;
      case CWBorderPixel:
	foo=io.readInt();
	if((attr&borderIsPixel)==0){
	  if(border.pixmap==null){
	    //System.err.println("BorderPixmap: error!!");
	  }
	  else{
	    try{border.pixmap.delete();}catch(Exception e){}
	    border.pixmap=null;
	  }
	}
	attr|=borderIsPixel;
	border.pixel=foo;
	break;
      case CWBitGravity:
	foo=io.readInt();
	foo&=0xff;

	if(foo>StaticGravity){
	  //System.err.println("error!!");
	}
	attr&=~bitGravity;
	attr|=(foo<<bitGravityOffset);
	
	break;
      case CWWinGravity:
	foo=io.readInt();
	foo&=0xff;

	if(foo>StaticGravity){
	  //System.err.println("error!!");
	}
	attr&=~winGravity;
	attr|=(foo<<winGravityOffset);

	break;
      case CWBackingStore:
	foo=io.readInt();
	foo&=0xff;

	if(foo!=0 && foo!=1 && foo!=2){
	  //System.err.println("error!!");    
	}
	attr&=~backingStore;
	attr|=(foo<<backingStoreOffset);
	attr&=~forcedBS;
	break;
      case CWBackingPlanes:
	foo=io.readInt();
	if(optional!=null || foo!=~0){
	  makeOptional();
	  optional.backingBitPlanes=foo;
	}
	break;
      case CWBackingPixel:
	foo=io.readInt();
	if(optional!=null || foo!=0){
	  makeOptional();
	  optional.backingPixel=foo;
	}
	break;
      case CWOverrideRedirect:
	foo=io.readInt();
	foo&=0xff;
	if((foo!=0) && (foo!=1)){
	  //System.err.println("error!");
	}
	//if(foo==1){ attr|=overrideRedirect;}
	attr&=~overrideRedirect;
	attr|=(foo<<overrideRedirectOffset);
	break;
      case CWSaveUnder:
	foo=io.readInt();
	foo&=0xff;

	if((foo!=0) && (foo!=1)){
	  //System.err.println("error !!");
	}
	if(parent!=null && ((attr&saveUnder) !=(foo<<saveUnderOffset)) &&
	   (attr&viewable)!=0){
	  if((attr&saveUnder)!=0)  deltaSaveUndersViewable--;
	  else deltaSaveUndersViewable++;
	  attr&=~saveUnder;
	  attr|=(foo<<saveUnderOffset);
	  if(firstChild!=null){
	  }
	  else{
	  }
	}
	else{
	  attr&=~saveUnder;
	  attr|=(foo<<saveUnderOffset);
	}
	break;
      case CWEventMask:
	foo=io.readInt();
	setEventMask(c, foo);
	break;
      case CWDontPropagate:
	foo=io.readInt();
	eventSuppress(foo);
	break;
      case CWColormap:
	foo=io.readInt();
        if(foo==0){  // CopyFromParent
  	  if(parent!=null &&
	     (optional==null || 
              optional.visual==(parent.optional!=null ?
   			        parent.optional.visual :
				parent.findOptional().optional.visual))){
            foo=parent.getColormap().id;
	  }
	}
        if(foo==0){
          c.errorReason=8; //BadMatch
	  c.errorValue=foo;
	  return;
	}
	Colormap cmap=(Colormap)Resource.lookupIDByType(foo, Resource.RT_COLORMAP);
        if(cmap==null){
          c.errorReason=12; // BadColor
	  c.errorValue=foo;
	  return;
	}
	makeOptional();
	optional.colormap=cmap;
	c.cevent.mkColormapNotify(id, foo, 1, 1);
	sendEvent(c.cevent, 1, null);
	break;
      case CWCursor:
	foo=io.readInt();
	Cursor cur=null, old=null;
	if(foo==0){
	  if(this==screen.root){ cur=Cursor.rootCursor; }
	  else{ cur=null; }
	}
	else{
	  cur=(Cursor)Resource.lookupIDByType(foo, Resource.RT_CURSOR);
	  if(cur==null){
	    c.errorReason=6; //BadCursor
	    c.errorValue=foo;
	    return;
	  }
	}
	if(cur!=getCursor()){
	  if(cur==null){
	    attr|=cursorIsNone;
	    if(optional!=null){
	      old=optional.cursor;
	      optional.cursor=null;
	    }
	  }
	  else{
	    makeOptional();
  	    old=optional.cursor;
	    optional.cursor=cur;
	    attr&=~cursorIsNone;
            if(ddxwindow!=null){
  	      ddxwindow.setCursor(cur.cursor);
	    }
	  }
        }
	break;
      default:
	c.length++;
	c.errorValue=vmask;
	c.errorReason=2; // BadValue;
      }
      //try{HexStream.err.hexInt(attr); System.out.println(" <-attr");}
      //catch(Exception e){}
      if(c.errorReason!=0){
	return;
      }
    }

    if(c.length!=0){
      c.errorValue=vmask;
      c.errorReason=2; // BadValue;
    }
    return;
  }

  private int eventSuppress(int mask){
    int i=0, free;
    if((attr&dontPropagate)!=0){
      DontPropagate.refc[(attr&dontPropagate)>>dontPropagateOffset]--;
    }
    if(mask!=0){
      i=DontPropagate.store(mask);
    }
    if(i!=0 || mask==0){
      attr&=~dontPropagate;
      attr|=(i<<dontPropagateOffset);
      if(i!=0){
	DontPropagate.refc[i]++;
      }
      if(optional!=null){
	optional.dontPropagateMask=mask;
      }
    }
    else {
      makeOptional();
      attr&=~dontPropagate;
      optional.dontPropagateMask=mask;
    }
    recalculateDeliverableEvents();
    return 0;
  }

  static final void reqCirculateWindow(Client c) throws IOException{
    int n, foo;
    IO io=c.client;

    int direction=c.data;
    foo=io.readInt();

    c.length-=2;

    Window w=c.lookupWindow(foo);
    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }
    if(direction !=RaiseLowest && direction !=LowerHighest){
      c.errorValue=direction;
      c.errorReason=2; // BadValue
      return;
    }

    synchronized(LOCK){
      Window win=null;
      Window first=w.firstChild;
      if(direction==RaiseLowest){
	win=w.lastChild;
	while((win !=null) && !(win.isMapped())){ win=win.prevSib; }
	if(win==null) return;
      }
      else {
	win=first; 
	while((win!=null) && !(win.isMapped())){ win=win.nextSib; }
	if(win==null) return;
      }
      c.cevent.mkCirculateRequest(w.id, win.id,
				  (direction==RaiseLowest) ? 
				  PlaceOnTop : PlaceOnBottom);
      if(w.redirectSend()){
	if(w.sendEvent(c.cevent, 1, Event.SubstructureRedirectMask, c)==1)
	  return;
      }
      c.cevent.mkCirculateNotify(win.id, w.id, w.id, 
				 (direction==RaiseLowest) ? 
				 PlaceOnTop : PlaceOnBottom);
      win.sendEvent(c.cevent, 1, null);
      win.reflectStackChange((direction==RaiseLowest) ? first : null);
    }
    return;
  }

  static final void reqAllowEvents(Client c) throws IOException{
    int foo, mode;
    IO io=c.client;
    mode=c.data;
    foo=io.readInt();
    switch(mode){
    case AsyncPointer:
      break;
    case SyncPointer:
      break;
    case ReplayPointer:
      break;
    case AsyncKeyboard:
      break;
    case SyncKeyboard:
      break;
    case ReplayKeyboard:
      break;
    case AsyncBoth:
      break;
    case SyncBoth:
      break;
    default:
    }
    Window.sprite.hot.state=0;
  }

  static final void reqGetMotionEvents(Client c) throws IOException{
    int foo, n;
    IO io=c.client;

    foo=io.readInt();
    Window w=c.lookupWindow(foo);
    foo=io.readInt();
    foo=io.readInt();
    c.length-=4;
    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }

    synchronized(io){
      io.writeByte(1);
      io.writePad(1);
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writeInt(0);
      io.writePad(20);
      io.flush();
    }
  }
  static final void reqTranslateCoordinates(Client c) throws IOException{
    int foo;
    IO io=c.client;
    foo=io.readInt();
    Window srcw=c.lookupWindow(foo);
    if(srcw==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow
    }
    foo=io.readInt();
    Window dstw=c.lookupWindow(foo);
    if(dstw==null && c.errorReason==0){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow      
    }
    int x=io.readShort();
    int y=io.readShort(); 
    c.length-=4;
    if(c.errorReason!=0){
      return;
    }

    int gx=x+srcw.x;
    int gy=y+srcw.y;

    int child=0;

    synchronized(LOCK){
      Window win=dstw.firstChild;
      while (win!=null){
	if(((win.attr&mapped)!=0) && win.contains(gx, gy)){
	  child=win.id;
	  win=null;
	}
	else{
	  win=win.nextSib;
	}
      }
    }

    x=gx-dstw.x;
    y=gy-dstw.y;

    synchronized(io){
      io.writeByte(1);
      io.writeByte(1);  // same screen
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writeInt(child);
      io.writeShort(x);
      io.writeShort(y);
      io.writePad(16);
      io.flush();
    }
  }

  static final void reqGetScreenSaver(Client c) throws IOException{
    int foo, n;
    IO io=c.client;

    synchronized(io){
      io.writeByte(1);
      io.writePad(1);
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writeShort(600);
      io.writeShort(600);
      io.writeByte((byte)1);
      io.writeByte((byte)1);
      io.writePad(18);
      io.flush();
    }
  }

  static final void reqQueryBestSize(Client c) throws IOException{
    int foo, clss;
    IO io=c.client;
    clss=c.data;
    foo=io.readInt();
    c.length-=2;
    Drawable d=c.lookupDrawable(foo);
    if((clss !=0 /*CursorShape*/) && 
       (clss !=1 /*TileShape*/) && 
       (clss !=2 /*StippleShape*/)){
      c.errorValue=clss;
      c.errorReason=2; // BadValue;
      return;
    }
    if(d==null){
      c.errorValue=foo;
      c.errorReason=9; // BadDrawable;
      return;
    }
    foo=io.readShort();
    foo=io.readShort();

    synchronized(io){
      io.writeByte(1);
      io.writePad(1);
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writeShort(32);
      io.writeShort(32);
      io.writePad(20);
      io.flush();
    }
  }

  static final void reqDestroySubwindows(Client c) throws IOException{
    int foo;
    IO io=c.client;
    foo=io.readInt();
    c.length-=2;
    Window w=c.lookupWindow(foo);

    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }
    synchronized(LOCK){
      w.unmapSubwindows(c);
      while(w.lastChild!=null){
	Resource.freeResource(w.lastChild.id, Resource.RT_NONE);
      }
    }
  }

  void makeBackgroundTile(int xx, int yy, int w, int h){
    Window win=this;
    int i=(attr&backgroundState);
    if(i==ParentRelative){
      win=parent;
      if(win==null) return;
      i=(win.attr&backgroundState);
    }

    if(i==BackgroundPixmap && win.background.pixmap!=null){
      Image img=win.background.img;
      if(img==null) return;
      if(!win.ddxwindow.isVisible()) return;
      Graphics g=null;
      java.awt.Shape tmp=null;
      if(xx!=0 || yy!=0 || w!=width || h!=height){
	g=getGraphics();
	tmp=g.getClip();
	g.clipRect(xx, yy, w, h);
      }
      if(win==this){
        ddxwindow.fillImage(img, 
			    win.background.pixmap.width, 
			    win.background.pixmap.height);
      }
      else{	
        ddxwindow.fillImage(img, 
                            win.background.pixmap.width, 
                            win.background.pixmap.height,
                            origin.x-borderWidth,
                            origin.y-borderWidth
                            );
      }
      if(g!=null){
	if(tmp==null){ g.setClip(0, 0, width, height); }
        else{g.setClip(tmp);}
      }
    }
    else if(i==BackgroundPixel){
      Colormap cmap=win.getColormap();
      ddxwindow.setBackground(cmap.getColor(win.background.pixel),
                              xx, yy, w, h);
    }
  }

  private void free(){
    SaveSet.delete(this);
    Selection.delete(this);
    try{deleteEvent(true);}
    catch(Exception e){
      //System.out.println(e);
    }

    try{deleteProperties();}
    catch(Exception e){
      //System.out.println(e);
    }

    origin=null;
    if((attr&backgroundState)==BackgroundPixmap){
      if(background.pixmap==null){
	//System.err.println("free: error!!");
      }
      else{
	try{background.pixmap.delete();}catch(Exception e){}
	background.pixmap=null;
      }
    }
    background=null;
    if((attr&borderIsPixel)==0){
      if(border.pixmap==null){
	//System.err.println("free: error!!!");
      }
      else{
	try{border.pixmap.delete();}catch(Exception e){}
	border.pixmap=null;
      }
    }
    border=null;
    optional=null;

    try{ddxwindow.delete();}
    catch(Exception e){}

    if(hasFrame()){
      delFrame();
    }
  }

  private void deleteEvent(boolean freeResources) throws IOException {
    Grab passive;
    if(Window.grab!=null && Window.grab.window==this){
      Window.grab.deactivatePointerGrab();
    }
    if((id==focus.win) && (parent !=null)){
      int focusEventMode=NotifyNormal;
      switch (focus.revert){
      case RevertToNone:
	doFocusEvents(null, id, 0, focusEventMode);
	focus.win=0;
        focus.window=null;
	focus.traceGood=0;
	break;
      case RevertToParent:
	Window win=this;
	do{
	  win=win.parent;
	  focus.traceGood--;
	}
	while (win!=null && !win.isRealized());

	int p=(win==null) ? 0 : win.id;
	doFocusEvents(null, id, p, focusEventMode);
	focus.win=p;
	focus.window=win;
	focus.revert=RevertToNone;
	break;
      case RevertToPointerRoot:
	doFocusEvents(null, id, PointerRootWin, focusEventMode);
	focus.win=PointerRootWin;
        focus.window=null;
	focus.traceGood=0;
	break;
      }
    }

    if(freeResources){
      if((attr&dontPropagate)!=0){
	DontPropagate.refc[(attr&dontPropagate)>>dontPropagateOffset]--;
      }
      OtherClients oc;
      while ((oc=getOtherClients())!=null ){
	Resource.freeResource(oc.id, Resource.RT_NONE);
      }
      while ((passive=getPassiveGrabs())!=null){
	Resource.freeResource(passive.id, Resource.RT_NONE);
      }
    }
  }

  private void deleteProperties() throws IOException{

    Property pProp, pNextProp;
    pProp=getProperty();
    while (pProp!=null){
      client.cevent.mkPropertyNotify(id, 
				     pProp.propertyName,
				     (int)System.currentTimeMillis(),
				     1 //Property.PropertyDelete
				     );
      sendEvent(client.cevent, 1, null);
      pNextProp=pProp.next;
      pProp.data=null;
      pProp=pNextProp;
    }
  }

  private void crushTree() throws IOException {
    Window child, sib, cparent;
    if((child=firstChild)==null) return;
    while (true){
      if(child.firstChild!=null){
	child=child.firstChild;
	continue;
      }
      while (true){
	cparent=child.parent;
	if(child.substrSend()){
	  Event event=new Event();
	  event.mkDestroyNotify(child.id, child.id);
	  try{ child.sendEvent(event, 1, null);}
	  catch(Exception e){
	    //System.out.println("crush: exception -> "+e);
	  }
	}
	try{ Resource.freeResource(child.id, Resource.RT_WINDOW); }
	catch(Exception e){
	  //System.out.println("crush: exception -> "+e);
	}

	sib=child.nextSib;
	child.attr&=~viewable;
	if((child.attr&realized)!=0){
	  child.attr&=~realized;
	  child.attr|=visibility;
	  child.ddxwindow.setVisible(false);

	  if(screen.windowmode!=WeirdX.InBrowser && child.hasFrame()){        
            child.getFrame().setVisible(false);                  
	  }                                                      
	}

	try{child.free();}
	catch(Exception e){
	  //System.out.println("crush: exception -> "+e);
	}

	if((child=sib)!=null) break;

	child=cparent;
	child.firstChild=null;
	child.lastChild=null;
	if(child==this) return;
      }
    }
  }

  void delete() throws IOException{
    synchronized(LOCK){
      try{unmapWindow(false);}
      catch(Exception e){
      }
      try{
        crushTree();
      }
      catch(Exception e){
      }

      if(id!=0 && parent!=null && substrSend()){
        Event event=new Event();
        event.mkDestroyNotify(id, id);
        try{sendEvent(event, 1, null);}
        catch(Exception e){
        }
      }

      if(parent!=null){
	if(parent.firstChild==this) parent.firstChild=nextSib;
	if(parent.lastChild==this) parent.lastChild=prevSib;
	if(nextSib!=null) nextSib.prevSib=prevSib;
	if(prevSib!=null) prevSib.nextSib=nextSib;
      }
      parent=null;
      nextSib=null;
      prevSib=null;
      firstChild=null;
      lastChild=null;
      prevSib=null;

      try{free();}
      catch(Exception e){
      }
    }
  }

  static final void reqDestroyWindow(Client c) throws IOException{
    int foo;
    IO io=c.client;
    foo=io.readInt();
    c.length-=2;
    Window w=c.lookupWindow(foo);
    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }

    if(w.parent!=null){
      Resource.freeResource(w.id, Resource.RT_NONE);
    }
  }

  static final void reqSendEvent(Client c) throws IOException{
    Window win;
    Window effectiveFocus=null;   // only set if dest==InputFocus
    int foo;
    IO io=c.client;
    int prop=c.data;
    int dest=io.readInt();
    int emask=io.readInt();    
    byte[] bb=new byte[32];
    io.readByte(bb, 0, 32);
    c.length=0;
    Event event=new Event(bb);
    if(c.swap){ event.swap(); }

    if(dest==0/*PointerWindow*/){
      win=sprite.win;
    }
    else{
      win=c.lookupWindow(dest);
    }

    if(win==null){
      c.errorValue=dest;
      c.errorReason=3; // BadWindow;
      return;
    }

    if((prop !=0) && (prop !=1)){
      c.errorValue=prop;
      c.errorReason=2; // BadValue;
      return;
    }

    event.setType((byte)(event.getType()|0x80));
    if(prop!=0){
      for(;win!=null; win=win.parent){
	if(win.sendEvent(event, 1, emask, null, 0)!=0)
	  return;
	emask &=~win.getDontPropagateMask();
	if(emask==0)
	  break;
      }
    }
    else{
      win.sendEvent(event, 1, emask, null, 0);
    }

    return;
  }
  static final void reqGetPointerMapping(Client c) throws IOException{
    int foo,n;
    IO io=c.client;

    synchronized(io){
      io.writeByte(1);
      io.writeByte(0);
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writePad(24);
      io.flush();
    }
  }

  static final void reqSetPointerMapping(Client c) throws IOException{
    int foo, n;
    IO io=c.client;
    foo=c.data;                 
    n=c.length;
    n--;
    while(n!=0){
      foo=io.readInt();
      n--;
    }

    synchronized(io){
      io.writeByte(1);
      io.writeByte((byte)1);
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writePad(24);
      io.flush();
    }
  }
  static final void reqGetPointerControl(Client c) throws IOException{
    int foo,n;
    IO io=c.client;

    synchronized(io){
      io.writeByte(1);
      io.writePad(1);
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writeShort(2);
      io.writeShort(1);
      io.writeShort(4);
      io.writePad(18);
      io.flush();
    }
  }

  static final void reqQueryPointer(Client c) throws IOException{
    int n, foo;
    IO io=c.client;
    foo=io.readInt();
    c.length-=2;
    Window w=c.lookupWindow(foo);
    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }

    int hx=Window.sprite.hot.x;
    int hy=Window.sprite.hot.y;

    Window child=null;
    synchronized(LOCK){
      for(Window ww=Window.sprite.win; ww!=null; ww=ww.parent){
        if(ww.parent==w){
          child=ww;
  	  break;
        }
      }

      if(child!=null){
        if(!child.contains(hx, hy)){
          sprite.win=xy2Window(hx, hy, null);
          child=null;
   	  for(Window ww=sprite.win; ww!=null; ww=ww.parent){
            if(ww.parent==w){
	      child=ww;
	      break;
	    }
	  }
        }
      }
    }

    synchronized(io){
      io.writeByte(1);
      io.writeByte(1);
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writeInt(w.screen.rootId);

      io.writeInt((child==null? 0 : child.id));
      io.writeShort(hx);
      io.writeShort(hy);
      io.writeShort(hx-w.x);
      io.writeShort(hy-w.y);
      io.writeShort(Window.sprite.hot.state);
//    io.writeShort(0);  // ?????????
      io.writePad(6);
      io.flush();
    }
  }

  static final void reqGetGeometry(Client c) throws IOException{
    IO io=c.client;
    int foo=io.readInt();

    Drawable d=c.lookupDrawable(foo);
    c.length-=2;
    if(d==null){
      c.errorValue=foo;
      c.errorReason=9; // BadValue;
      return;
    }

    synchronized(io){
      io.writeByte(1);
      io.writeByte(d.depth);
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writeInt(d.screen.rootId);

      if((d.type==UNDRAWABLE_WINDOW)||
         ((d.type==DRAWABLE_WINDOW) && foo==d.id)){
        Window w=(Window)d;
        io.writeShort(w.origin.x-w.borderWidth);
        io.writeShort(w.origin.y-w.borderWidth);
        io.writeShort(w.width);
        io.writeShort(w.height);
        io.writeShort(w.borderWidth);
      }
      else{
        io.writeShort(0);
        io.writeShort(0);
        io.writeShort(d.width);
        io.writeShort(d.height);
        io.writeShort(0);
      }
      io.writePad(10);
      io.flush();
    }
  }

  static final void reqChangeWindowAttributes(Client c) throws IOException{
    int foo;
    IO io=c.client;

    int wid=io.readInt(); 
    int mask=io.readInt(); 

    c.length-=3;

    Window w=c.lookupWindow(wid);
    if(w==null){
      c.errorValue=wid;
      c.errorReason=3; // BadWindow;
      return;
    }

    mask&=0x7fff;
    if(mask!=0){ w.changeAttr(c, mask); }

    if(c.errorReason!=0){
      return;
    }

    if((mask&CWBorderPixmap)!=0 || (mask&CWBorderPixel)!=0){
      w.ddxwindow.setBorderPixmap(w.border.pixmap);
    }
  }

  static final void reqUngrabPointer(Client c) throws IOException{
    int foo, n;
    IO io=c.client;
    foo=io.readInt();
    if((Window.grab!=null) && Window.grab.sameClient(c)){
      Window.grab.deactivatePointerGrab();
    }
  }

  static final void reqUngrabButton(Client c) throws IOException{
    int foo;
    int button, mod;
    IO io=c.client;

    button=c.data;
    foo=io.readInt();

    c.length-=2;
    Window gw=c.lookupWindow(foo);
    if(gw==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }

    mod=io.readShort();
    io.readPad(2);
    c.length--;
    Grab grab=Grab.createGrab(c, gw, 0, 0, 0, 0, mod, 4, button, null);

    if(!grab.deletePassiveGrabFromList()){
      c.errorReason=11; // BadAlloc
    }
  }
  static final void reqGrabButton(Client c) throws IOException{
    int foo, n;
    int pmode, kmode, oe, emask, button, mod;
    IO io=c.client;

    oe=c.data;
    if(oe!=0 && oe!=1){
    }

    foo=io.readInt();
    Window gw=c.lookupWindow(foo);
    if(gw==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
    }
    emask=io.readShort();
    if((emask&~Event.PointerGrabMask)!=0){
    }

    pmode=io.readByte();
    if((pmode!=GrabModeSync) &&
       (pmode!=GrabModeAsync)){
    }

    kmode=io.readByte();
    if((kmode!=GrabModeSync) &&
       (kmode!=GrabModeAsync)){
    }

    foo=io.readInt();
    Window cto=null;
    if(foo!=0){
      cto=c.lookupWindow(foo);
    }

    foo=io.readInt(); 
    button=io.readByte();
    io.readPad(1);
    mod=io.readShort();
    c.length-=6;

    if(c.errorReason!=0){
      return;
    }

    if(gw==null || cto==null){
    }

    Grab grab=Grab.createGrab(c,
				gw, emask,
				oe, kmode, pmode,
				mod, Event.ButtonPress, 
				button, cto);
    grab.addPassiveGrabToList();
  }

  static final void reqGrabPointer(Client c) throws IOException{
    int foo, n;
    int pmode, kmode, oe, emask, time;
    IO io=c.client;

    oe=c.data;
    if(oe!=0 && oe!=1){
      c.errorValue=oe;
      c.errorReason=2; // BadValue;
    }

    foo=io.readInt();
    Window gw=c.lookupWindow(foo);
    if(gw==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow
    }

    emask=io.readShort(); 
    if((emask&~Event.PointerGrabMask)!=0){
      c.errorValue=emask;
      c.errorReason=2; // BadValue;
    }

    pmode=io.readByte();
    if((pmode!=GrabModeSync) && (pmode!=GrabModeAsync)){
      c.errorValue=pmode;
      c.errorReason=2; // BadValue
    }

    kmode=io.readByte();
    if((kmode!=GrabModeSync) && (kmode!=GrabModeAsync)){
      c.errorValue=kmode;
      c.errorReason=2; // BadValue
    }

    foo=io.readInt();
    Window cto=null;
    if(foo!=0){
      cto=c.lookupWindow(foo);
      if(cto==null){
	c.errorValue=foo;
	c.errorReason=3; // BadWindow
      }
    }

    foo=io.readInt();
    Cursor cur=null;
    if(foo!=0){
      cur=(Cursor)Resource.lookupIDByType(foo, Resource.RT_CURSOR);
      if(cur==null){
	c.errorValue=foo;
	c.errorReason=6; //BadCursor
      }
    }

    time=io.readInt();

    c.length-=6;

    if(c.errorReason!=0){
      return;
    }

    int res=0;
    if(Window.grab!=null && c!=Window.grab.getClient()){
      res=AlreadyGrabbed;
    }
    else if((gw.attr&realized)==0||
	    (cto!=null &&
	     !((cto.attr&realized)!=0 &&(cto.width!=0 || cto.height!=0)))){
      res=GrabNotViewable;
    }
    else {
      Grab grab=new Grab(Resource.fakeClientId(c));
      grab.set(c.clientAsMask, gw, oe,
	       emask, kmode, pmode, cto);
      grab.activatePointerGrab((int)System.currentTimeMillis(), true);
      res=GrabSuccess;
    }

    synchronized(io){
      io.writeByte(1);
      io.writeByte(res);
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writePad(24);
      io.flush();
    }
  }

  static final void reqCreateWindow(Client c) throws IOException{
    int foo;

    byte depth;
    int x, y, width, height, bwidth, clss;
    int visual;
    int mask;
    IO io=c.client;

    depth=(byte)c.data;

    int wid=io.readInt();

    foo=io.readInt(); 
    Window prnt=c.lookupWindow(foo);

    x=io.readShort();
    y=io.readShort();
    width=io.readShort();
    height=io.readShort();
    bwidth=io.readShort();
    clss=io.readShort();
    visual=io.readInt(); 
    mask=io.readInt(); 

    c.length-=8;

    if(prnt==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
    }

    if((width==0 || height==0) && c.errorReason==0){
      c.errorValue=0;
      c.errorReason=2; // BadValue;
    }

    Window w=null;
    if(c.errorReason==0){
      w=new Window(wid, prnt, x, y, width, height, bwidth, clss, depth,
		     c, visual, mask);
    }

    if(c.errorReason!=0){
      return;
    }
    Resource.add(w);
  }

  int sendEvent(Event event, int count, int filter,
		Grab grab, int mskidx) throws IOException{
    int deliveries=0, nondeliveries=0;
    int attempt;
    Client c=null;
    int deliveryMask=0;
    int type=event.getType();

    if((filter==Event.CantBeFiltered) || 
	((type & Event.EXTENSION_EVENT_BASE)==0)){
      if((filter !=Event.CantBeFiltered) &&
	  (((getOtherEventMask()|eventMask) & filter)==0)){
	return 0;
      }
      attempt=1;
      try{ attempt=client.sendEvent(event, count, eventMask, filter, grab); }
      catch(Exception e){
      }

      if(attempt !=0 ){
	if(attempt > 0){
	  deliveries++;
	  c=client;
	  deliveryMask=eventMask;
	} 
	else
	  nondeliveries--;
      }
    }

    Clients other;
    if(filter !=Event.CantBeFiltered){
      if((type & Event.EXTENSION_EVENT_BASE)!=0){
	OtherInputMasks inputMasks;

	inputMasks=(optional==null?null:optional.otherInputMasks);
	if((inputMasks==null) ||
	    ((inputMasks.inputEvents[mskidx] & filter)==0)){
	  return 0;
	}
	other=(Clients)(inputMasks.inputClients);
      }
      else{ other=(Clients)(optional==null?null:optional.otherClients); }

      for(; other!=null; other=(OtherClients)other.next){
	attempt=1;
	try{
	  if(other.getClient()!=null){
            int mask=(other instanceof OtherClients) ? 
	            ((OtherClients)other).mask :
	            ((InputClients)other).mask[mskidx];
	    attempt=other.getClient().sendEvent(event, count, mask, 
						filter, grab);
	  }
	  else{
	    attempt=0;
	  }
	}
	catch(Exception e){
	}

	if(attempt!=0){
	  if(attempt > 0){
	    deliveries++;
	    c=other.getClient();
	    deliveryMask=((other instanceof OtherClients) ? 
			   ((OtherClients)other).mask :
			   ((InputClients)other).mask[mskidx]);
	  }
	  else
	    nondeliveries--;
	}
      }
    }


    if(c==null){
      if(deliveries!=0){
	return deliveries;
      }
      return nondeliveries;
    }

    if((type==Event.ButtonPress) && (deliveries!=0) && (grab==null)){
      grab=new Grab(Resource.fakeClientId(c));
      grab.set(c.clientAsMask, this,
	       (deliveryMask & Event.OwnerGrabButtonMask),
	       deliveryMask, GrabModeAsync, GrabModeAsync, null);
      grab.activatePointerGrab((int)System.currentTimeMillis(), true);      
    }
    if(deliveries!=0)
      return deliveries;
    return nondeliveries;
  }

  int sendEvent(Event event, int count, Window otherParent)throws IOException{
    int filter;
    int deliveries;

    if(count==0) return 0;

    filter=Event.filters[event.getType()];
    if(((filter & Event.SubstructureNotifyMask)!=0) && 
	(event.getType() !=Event.CreateNotify)){
      event.putEvent(id);
    }

    if(filter !=Event.StructureAndSubMask){
      return sendEvent(event, count, filter, null, 0);
    }

    deliveries=sendEvent(event, 
			   count, 
			   Event.StructureNotifyMask,  
			   null, 0);

    if(parent!=null){
      event.putEvent(parent.id);
      deliveries +=parent.sendEvent(event, 
				     count,
				     Event.SubstructureNotifyMask, 
				     null, 0);
      if(event.getType()==Event.ReparentNotify){
	event.putEvent(otherParent.id);
	deliveries +=otherParent.sendEvent(event, 
					    count,
					    Event.SubstructureNotifyMask,
					    null, 0);
      }
    }
    return deliveries;
  }

  int sendEvent(Event event, int count, 
		int filter, Client c) throws IOException{
    if((eventMask&filter)!=0){
      if(client==c) return 0;
      return client.sendEvent(event, count, eventMask, filter, null);
    }

    OtherClients other=(optional==null) ? null: optional.otherClients;
    for(; other!=null; other=(OtherClients)other.next){
      if((other.mask & filter)!=0){
	if(other.sameClient(c)) return 0;
	if(other.getClient()==null)
	  return 0;
	return other.getClient().sendEvent(event, 
					   count, 
					   other.mask, 
					   filter, null);
      }
    }
    return 2;
  }

  private Window findOptional(){
    Window w=this;
    do{w=w.parent;}while(w.optional==null);
    return w;
  }

  private void setDefault(){
    prevSib=null;
    firstChild=null;
    lastChild=null;
    optional=null;
    attr=0;

    attr|=cursorIsNone;

    attr|=visibility;
    attr|=(NorthWestGravity<<winGravityOffset);

    eventMask=0;
    attr|=(DBE_FRONT_BUFFER<<srcBufferOffset);
    attr|=(DBE_FRONT_BUFFER<<dstBufferOffset);
  }

  static final void reqUnmapSubWindows(Client c) throws IOException{
    int foo;
    IO io=c.client;
    foo=io.readInt();

    c.length-=2;

    Window w=c.lookupWindow(foo);
    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }
    synchronized(LOCK){
      w.unmapSubwindows(c);
    }
  }

  private void unmapSubwindows(Client c) throws IOException {
    if(firstChild==null) return;

    boolean wasRealized=(attr&realized)!=0;
    boolean wasViewable=(attr&viewable)!=0;
    boolean parentNotify=subSend(); 
    boolean anyMarked=false;

    for(Window child=lastChild; child !=null; child=child.prevSib){
      if((child.attr&mapped)!=0){
	if(parentNotify || child.strSend()){
	  c.cevent.mkUnmapNotify(child.id, 0);
	  child.sendEvent(c.cevent, 1, null);
	}

	child.attr&=~mapped;

	if((child.attr&realized)!=0){
	  child.unrealizeTree(false);
        }
      }
    }

    if(wasRealized){
      restructured ();
    }
  }

  static final void reqMapSubWindows(Client c) throws IOException{
    int foo;
    int mask;
    Window firstMapped=null;
    boolean anyMarked=false;

    IO io=c.client;

    foo=io.readInt();

    c.length-=2;

    Window w=c.lookupWindow(foo);
    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }

    boolean parentRedirect=w.parent.redirectSend();
    boolean parentNotify=w.parent.subSend();

    synchronized(LOCK){
      for(Window tmpw=w.firstChild; tmpw!=null; tmpw=tmpw.nextSib){
	if(w.screen.root!=w && w.parent==null) return;
        if((tmpw.attr&mapped)==0){
	  if(parentRedirect && ((tmpw.attr&overrideRedirect)==0)){
	    c.cevent.mkMapRequest(w.id, tmpw.id);
	    if(w.sendEvent(c.cevent, 1, 
			    Event.SubstructureRedirectMask, c)==1){
	      return;
	    }
	  }

	  tmpw.attr|=mapped;

	  if(parentNotify || w.strSend()){
	    c.cevent.mkMapNotify(tmpw.id, 
				 (tmpw.attr&overrideRedirect)>>overrideRedirectOffset);
	    tmpw.sendEvent(c.cevent, 1, null);
	  }
	  if(firstMapped==null) firstMapped=tmpw;
	  if((w.attr&realized)!=0){
	    tmpw.realizeTree();
	  }
	}
      }

      if(firstMapped!=null){
        restructured ();
      }
    }
  }

  static final void reqUnmapWindow(Client c) throws IOException{
    int foo;
    IO io=c.client;

    foo=io.readInt();

    c.length-=2;

    Window w=c.lookupWindow(foo);
    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }
    synchronized(LOCK){
      w.unmapWindow(false);
    }
  }

  private void unrealizeTree(boolean fromConfigure){
    Window child=this;
    while (true){
      if((child.attr&realized)!=0){
	child.attr&=~realized;
        child.attr|=visibility; //VisibilityNotViewable
	child.ddxwindow.setVisible(false);

        if(screen.windowmode!=WeirdX.InBrowser && child.hasFrame()){          
	  child.getFrame().setVisible(false);                    
	}                                                        

        try{child.deleteEvent(false);}
        catch(Exception e){
	  //System.out.println(e);
	}

	if((child.attr&viewable)!=0){
	  child.attr&=~viewable;
	}
	if(child.firstChild!=null){ 
          child=child.firstChild;
	  continue;
	}
      }
      while (child.nextSib==null && (child !=this))
	child=child.parent;
      if(child==this) break;
      child=child.nextSib;
    }

    if(parent!=null && borderWidth>0){
      parent.ddxwindow.draw(origin.x-borderWidth, origin.y-borderWidth,
			    width+2*borderWidth, height+2*borderWidth);
    }
  }

  private void realizeTree() throws IOException {
    Window child=this;
    while (true){
      if((child.attr&mapped)!=0){
	child.attr|=realized;
	child.attr|=(child.clss==InputOutput) ? viewable : 0;
	child.attr&=~visibility;
	child.attr|=(VisibilityUnobscured<<visibilityOffset);
        if(screen.windowmode!=WeirdX.InBrowser && child.hasFrame()){          
          if((0<=child.x || 0<=child.y ||                        
             0<(child.x+child.width) ||                          
             0<(child.y+child.height)) && clss!=2){              
	    child.getFrame().setVisible(true);                    
          }                                                      
	}                                                        
	child.ddxwindow.setVisible(true);
	child.ddxwindow.draw();
	if(((child.eventMask | child.getOtherEventMask()) & 
	     Event.VisibilityChangeMask)!=0){
          try{child.sendVisibilityNotify();}
          catch(Exception e){}
        }
	if(child.firstChild!=null){
	  child=child.firstChild;
	  continue;
	}
      }
      while (child.nextSib==null && (child !=this)){
	child=child.parent;
      }
      if(child==this){
	return;
      }
      child=child.nextSib;
    }
  }

  private void unmapWindow(boolean fromConfigure) throws IOException{
    Screen screen=this.screen;
    boolean wasRealized=((this.attr&realized)!=0);
    boolean wasViewable=((this.attr&viewable)!=0);
    Window layerWin=this;

    if((this.attr&mapped)==0) return;

    if(parent==null) return;
    if(substrSend()){
      Event event=new Event();
      event.mkUnmapNotify(id, (fromConfigure?1:0));
      try{sendEvent(event, 1, null);}
      catch(Exception e){
      }
    }
    this.attr&=~mapped;
    if(wasRealized){
      this.unrealizeTree(fromConfigure);
    }

    if(wasRealized && !fromConfigure){
      restructured ();
    }
  }

  static final void reqMapWindow(Client c) throws IOException{
    int foo;
    IO io=c.client;

    foo=io.readInt();

    c.length-=2;

    Window w=c.lookupWindow(foo);
    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }
    synchronized(LOCK){
      w.mapWindow(c);
    }
  }

  void mapWindow(Client c) throws IOException{
    if((this.attr&mapped) !=0) return;
    screen=this.screen;    
    if(parent!=null){
      if(((this.attr&overrideRedirect)==0) && (parent.redirectSend())){
	c.cevent.mkMapRequest(parent.id, id);
	int ii=parent.sendEvent(c.cevent, 1, 
				Event.SubstructureRedirectMask, c);
	if(ii==1) return;
      }
      this.attr|=mapped;
      if(substrSend()){
	c.cevent.mkMapNotify(id, 
			     (attr&overrideRedirect)>>overrideRedirectOffset);
	sendEvent(c.cevent, 1, null);
      }
      if((this.parent.attr&realized)==0) return;
      this.realizeTree();
      restructured ();
    }
    else{
      this.attr|=mapped;
      this.attr|=realized;
      this.attr|=(this.clss==InputOutput) ? viewable : 0;
    }
  }

  static void restructured () throws IOException{
    try{checkMotion(null, null);}
    catch(Exception e){
    }
  }

  static boolean checkMotion (Event e, Window hint) throws IOException{
    Window prevSpriteWin=sprite.win;
    sprite.win=xy2Window(sprite.hot.x, sprite.hot.y, hint);
    if(sprite.win !=prevSpriteWin){
      if(prevSpriteWin !=null){
	try{enter_leaveEvent(prevSpriteWin, sprite.win, NotifyNormal);}
	catch(Exception ee){
	  //System.out.println("checkmotion: execption -> "+ee);
	}
      }
      return false;
    }
    return true;
  }

  static void enter_leaveEvent(int type, int mode, int detail,
			       Window win, int child) throws IOException {
    int mask;
    Grab grab=Window.grab;
    if(grab!=null){
      mask=(win==grab.window) ? grab.eventMask : 0;
      if((grab.attr&grab.ownerEvents)!=0){
	mask |=win.getEventMask(grab.getClient());
      }
    }
    else {
      mask=win.eventMask | win.getOtherEventMask();
    }

    if((mask & Event.filters[type])!=0){
      Event event=new Event();
      event.fixUpEventFromWindow(win, 0, sprite.hot.x, sprite.hot.y, false);
      int flags=0;
      flags=(event.getSameScreen()!=0?2:0);

      flags|=1;

      mode=0;
      event.mkPointer(type, detail, (int)System.currentTimeMillis(), child, 
		      sprite.hot.x, sprite.hot.y, sprite.hot.state,
		      mode, flags);
      try{
	if(grab!=null){
	  if(grab.getClient()!=null)
	    grab.getClient().sendEvent(event, 1, mask, Event.filters[type], grab);
	}
	else{
	  win.sendEvent(event, 1, Event.filters[type], null, 0);
	}
      }
      catch(Exception e){
	//System.out.println("enter_leaveEvent: exception -> "+e);
      }

    }
    if((type==Event.EnterNotify) && ((mask & Event.KeymapStateMask)!=0)){
      // KeymapNotify
    }
  }

  private int getEventMask(Client c){
    if(c==null) return 0;
    if(client==c) return eventMask;
    if(client==null) return 0;
    for(OtherClients other=getOtherClients(); 
	 other!=null; 
	 other=(OtherClients)other.next){
      if(other.sameClient(c)) return other.mask;
    }
    return 0;
  }

  private static void enterNotifies(Window ancestor, Window child, 
				    int mode, int detail) throws IOException{
    Window parent=child.parent;
    if(ancestor==parent) return;
    enterNotifies(ancestor, parent, mode, detail);
    enter_leaveEvent(Event.EnterNotify, mode, detail, parent, child.id);
  }

  private static void leaveNotifies(Window child, Window ancestor, 
			    int mode, int detail) throws IOException{
    if(ancestor==child) return;
    for(Window win=child.parent; win !=ancestor; win=win.parent){
      enter_leaveEvent(Event.LeaveNotify, mode, detail, win, child.id);
      child=win;
    }
  }

  static void enter_leaveEvent(Window fromWin, Window toWin, int mode)
    throws IOException{
    if(fromWin==toWin) return;
    if(fromWin.isParent(toWin)){
      try{
	enter_leaveEvent(Event.LeaveNotify, mode, NotifyInferior, fromWin, 0);
      }
      catch(Exception e){
      }
      try{
	enterNotifies(fromWin, toWin, mode, NotifyVirtual);
      }
      catch(Exception e){
      }
      try{
	enter_leaveEvent(Event.EnterNotify, mode, NotifyAncestor, toWin, 0);
      }
      catch(Exception e){
      }
    }
    else if(toWin.isParent(fromWin)){
      try{
	enter_leaveEvent(Event.LeaveNotify, mode, NotifyAncestor, fromWin, 0);
      }
      catch(Exception e){
      }
      try{
	leaveNotifies(fromWin, toWin, mode, NotifyVirtual);
      }
      catch(Exception e){
      }
      try{
	enter_leaveEvent(Event.EnterNotify, mode, NotifyInferior, toWin, 0);
      }
      catch(Exception e){
      }
    }
    else {
      Window common=toWin.commonAncestor(fromWin);
      try{
	enter_leaveEvent(Event.LeaveNotify, mode, NotifyNonlinear, fromWin, 0);
      }
      catch(Exception e){
      }
      try{
	leaveNotifies(fromWin, common, mode, NotifyNonlinearVirtual);
      }
      catch(Exception e){
      }
      try{
	enterNotifies(common, toWin, mode, NotifyNonlinearVirtual);
      }
      catch(Exception e){
      }
      try{
	enter_leaveEvent(Event.EnterNotify, mode, NotifyNonlinear, toWin, 0);
      }
      catch(Exception e){
      }
    }
  }

  boolean contains(int xx, int yy){
    return ddxwindow.contains(xx-x-borderWidth, yy-y-borderWidth);
  }

  static Window xy2Window(int x, int y, Window hint){
    if(hint!=spriteTrace[spriteTraceGood-1]){
      spriteTraceGood=1;
    }
//  else{ System.out.println("skip!!"); }

    Window  win=spriteTrace[spriteTraceGood-1];

    if(((win.attr&mapped)==0) || !win.contains(x, y)){
      win=spriteTrace[0];
      spriteTraceGood=1;
    }

    win=win.firstChild;
    while (win!=null){
      if(((win.attr&mapped)!=0) && win.contains(x, y)){
        if(spriteTraceGood >=spriteTrace.length){
          Window[] foo=new Window[spriteTrace.length+10];
          System.arraycopy(spriteTrace, 0, foo, 0, spriteTrace.length);
	  spriteTrace=foo;
	}
	spriteTrace[spriteTraceGood++]=win;
	win=win.firstChild;
      }
      else{
        win=win.nextSib;
      }
    }

    return spriteTrace[spriteTraceGood-1];
  }

  Cursor getCursor(){
    if(optional!=null) return optional.cursor;
    Window p=findOptional();
    return p.optional.cursor;
  }

  private boolean redirectSend(){
    return ((eventMask|getOtherEventMask()) & Event.SubstructureRedirectMask)!=0;
  }
  private boolean subSend(){
    return ((eventMask|getOtherEventMask()) & Event.SubstructureNotifyMask)!=0;
  }
  private boolean strSend(){
    return ((eventMask|getOtherEventMask()) & Event.StructureNotifyMask)!=0;
  }
  private boolean substrSend(){
    return strSend() || parent.subSend();
  }

  void makeOptional(){
    if(optional!=null) return;
    optional=new WindowOpt();
    optional.dontPropagateMask=DontPropagate.masks[(attr&dontPropagate)>>dontPropagateOffset];
    optional.otherEventMasks=0;
    optional.backingBitPlanes=~0L;
    optional.backingPixel=0;
    if(parent!=null){
      WindowOpt parentOptional=findOptional().optional;
      optional.visual=parentOptional.visual;
      if((attr&cursorIsNone)==0){
	optional.cursor=parentOptional.cursor;
      }
      else {
	optional.cursor=null;
      }
      optional.colormap=parentOptional.colormap;
    }
  }

  private void sendVisibilityNotify() throws IOException{
    Event event=new Event();
    event.mkVisibilityNotify(id, (attr&visibility)>>visibilityOffset);
    sendEvent(event, 1, null);
  }

  static final void reqQueryTree(Client c) throws IOException{
    int foo;
    Window prnt;
    Window w;
    int wid;
    int x, y, width, height, bwidth, clss;
    int visual;
    int mask;
    int rootId;
    IO io=c.client;
    wid=io.readInt(); 
    c.length-=2;
    w=c.lookupWindow(wid);
    if(w==null){
      c.errorValue=wid;
      c.errorReason=3; // BadWindow;
      return;
    }

    synchronized(LOCK){
      int numchild=0;

      for(Window p=w.lastChild; p !=null; p=p.prevSib){
	numchild++;    
      }

      synchronized(io){
        io.writeByte(1);
        io.writePad(1);
        io.writeShort(c.seq);
        io.writeInt(numchild);
        io.writeInt(w.screen.rootId);

        if(w.parent!=null) io.writeInt(w.parent.id);
        else io.writeInt(0);

        io.writeShort(numchild);
        io.writePad(14);

        if(0<numchild){
  	  for(Window p=w.lastChild; p !=null; p=p.prevSib){
	    io.writeInt(p.id);
	  }
        }
	io.flush();
      }
    }
  }

  static final void reqSetInputFocus(Client c) throws IOException{
    int foo, n, reverto;
    IO io=c.client;

    reverto=c.data;
    foo=io.readInt();
    c.length-=2;
    Window win=null;
    if(foo!=0 && foo!=1){
      win=c.lookupWindow(foo);
      if(win==null){
	c.errorValue=foo;
	c.errorReason=3; // BadWindow;
	return;
      }
    }

    int time=io.readInt();
    c.length--;

    setInputFocus(c, foo, reverto, time, false);
  }

  static final void setInputFocus(Client c,
				  int focusId, int revertTo,
				  int time, boolean followOk)
    throws IOException{
    if((revertTo!=RevertToParent) &&
       (revertTo!=RevertToPointerRoot) &&
       (revertTo!=RevertToNone)){
      c.errorValue=revertTo;
      c.errorReason=2; // BadValue
      return;
    }

    int focusWin=0;
    Window win=null;
    if((focusId==0) || (focusId==1)){
      focusWin=focusId;
    }
    else if((win=c.lookupWindow(focusId))==null){
      c.errorValue=focusId;
      c.errorReason=3;
      return;
    }
    else {
      if(!win.isRealized()){
	c.errorReason=8; // BadMatch
 	return;
      }
      focusWin=focusId;
    }

    int mode=grab!=null ? NotifyWhileGrabbed : NotifyNormal;
    doFocusEvents(c, focus.win, focusWin, mode);
    focus.time=time;
    focus.revert=revertTo;
    focus.win=focusWin;
    focus.window=win;

    if((focusWin==0) || (focusWin==1)){
      focus.traceGood=0;
      if(focusWin==1)
	Screen.screen[0].root.ddxwindow.requestFocus();
    }
    else {
      synchronized(LOCK){
        win.ddxwindow.requestFocus();
        int depth=0;
        for(Window tmpw=win; tmpw!=null; tmpw=tmpw.parent) depth++;
        if(depth > focus.traceSize){
  	  focus.traceSize=depth+1;
	  focus.trace=new Window[focus.traceSize];
        }
        focus.traceGood=depth;
        depth--;
        for(Window tmpw=win; tmpw!=null; tmpw=tmpw.parent, depth--){
	  focus.trace[depth]=tmpw;
        }
      }
    }
  }

  static final void reqGetInputFocus(Client c) throws IOException{
    int foo;
    IO io=c.client;

    synchronized(io){
      io.writeByte(1);
      io.writeByte(focus.revert);      // revert-to
      io.writeShort(c.seq);
      io.writeInt(0);
      io.writeInt(focus.win);          // focus
      io.writePad(20);     
      io.flush();
    }
  }

  static final void reqGetWindowAttributes(Client c) throws IOException{
    int foo;
    IO io=c.client;

    foo=io.readInt();
    c.length-=2;
    Window w=c.lookupWindow(foo);
    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow
      return;
    }

    synchronized(io){
      io.writeByte(1);

      if((w.attr&forcedBS)!=0 && (w.attr&backingStore)!=2) 
        io.writeByte(0);  // NotUseful
      else 
        io.writeByte((w.attr&backingStore)>>backingStoreOffset);

      io.writeShort(c.seq);
      io.writeInt(3);
      io.writeInt(w.getVisual());
      io.writeShort(w.clss);
      io.writeByte((w.attr&bitGravity)>>bitGravityOffset);
      io.writeByte((w.attr&winGravity)>>winGravityOffset);
      io.writeInt(w.getBackingBitPlanes());
      io.writeInt(w.getBackingPixel());
      io.writeByte((w.attr&saveUnder)>>saveUnderOffset);
 
      if(w.getColormapId()==0) io.writeByte(0);
      else io.writeByte(Colormap.isMapInstalled(w.getColormapId(), w));

      if((w.attr&mapped)==0) io.writeByte(0);  
      else if((w.attr&realized)!=0) io.writeByte(2);
      else io.writeByte(1);

      io.writeByte((w.attr&overrideRedirect)>>overrideRedirectOffset);
      io.writeInt(w.getColormapId());
      io.writeInt(w.eventMask|w.getOtherEventMask());
      io.writeInt(w.getEventMask(c));
      io.writeShort(w.getDontPropagateMask());
      io.writePad(2);
      io.flush();
    }
  }

  static final void reqCopyPlane(Client c) throws IOException{
    int foo;
    Drawable dsrc=null, ddst=null;
    IO io=c.client;
    foo=io.readInt();
    dsrc=c.lookupDrawable(foo);
    if(dsrc==null){
      c.errorValue=foo;
      c.errorReason=9; // Drawable
    }

    int dest=io.readInt();
    ddst=c.lookupDrawable(dest);
    if(ddst==null && c.errorReason==0){
      c.errorValue=dest;
      c.errorReason=9; // Drawable
    }
    foo=io.readInt();
    GC gc=c.lookupGC(foo);
    if(gc==null && c.errorReason==0){
      c.errorValue=foo;
      c.errorReason=13; // BadGC;
    }
    int sx, sy, dx, dy, width, height;

    sx=(short)io.readShort();
    sy=(short)io.readShort();

    int destx, desty;

    destx=(short)io.readShort();
    dx=destx-sx;

    desty=(short)io.readShort();
    dy=desty-sy;

    width=io.readShort();
    height=io.readShort();

    int bplane=io.readInt();
    c.length-=8;

    if(c.errorReason!=0){
      return;
    }

    Graphics g=ddst.getGraphics();
    if(((dsrc instanceof Window) && !((Window)dsrc).ddxwindow.isVisible())){
      g=null;
    }

    if(dsrc.width<=sx || dsrc.height<=sy ||
       (sx+width)<=0 || (sy+height)<=0 ||
       (destx+width)<=0 || (desty+height)<=0){
      g=null;
    }

    if(g!=null){
      if(dsrc instanceof Window){
        if(ddst instanceof Window){
          ((Window)dsrc).ddxwindow.copyArea(((Window)ddst), gc,
	                                    sx, sy, width, height, destx, desty); 
	}                                                          
      } 
      else {
	Image img=null;
	if(ddst instanceof Pixmap){
	  ((Pixmap)dsrc).copyPlane((Pixmap)ddst, gc, 
				   sx, sy, destx, desty, width, height);
	}
	else{
	  img=((Pixmap)dsrc).getImage((Window)ddst, gc, sx, sy, width, height);
	  Window wdst=(Window)ddst;

 	  if(sx==0 && sy==0 && width==dsrc.width && height==dsrc.height){
	    wdst.ddxwindow.drawImage(gc.clip_mask,
				     img, 
                                     destx, desty, 
                                     width, height);
	  }
	  else{
  	    java.awt.Shape tmp=g.getClip();
	    g.clipRect(destx, desty, width, height);
	    wdst.ddxwindow.drawImage(gc.clip_mask,
				     img, 
                                     destx-sx, desty-sy, 
                                     dsrc.width, dsrc.height);
	    if(tmp==null){ g.setClip(0, 0, wdst.width, wdst.height); }
            else{ g.setClip(tmp); }
	  }
	  wdst.draw(destx, desty, width, height);
	  if(img!=((Pixmap)dsrc).getImage()){
	    img.flush();
	  }
	}
      }
    }
  }

  static final void reqCopyArea(Client c) throws IOException{
    int foo;
    Drawable dsrc=null, ddst=null;
    IO io=c.client;

    foo=io.readInt();
    dsrc=c.lookupDrawable(foo);
    if(dsrc==null){
      c.errorValue=foo;
      c.errorReason=9;  // BadDrawable;
    }

    int dest=io.readInt();
    ddst=c.lookupDrawable(dest);
    if(ddst==null && c.errorReason==0){
      c.errorValue=dest;
      c.errorReason=9; // BadDrawable;
    }

    foo=io.readInt();

    GC gc=c.lookupGC(foo);

    if(gc==null && c.errorReason==0){
      c.errorValue=foo;
      c.errorReason=13; // BadGC;
    }

    int sx, sy;
    sx=(short)io.readShort();
    sy=(short)io.readShort();

    int destx, desty;
    destx=(short)io.readShort();
    desty=(short)io.readShort();

    int width, height;
    width=io.readShort();
    height=io.readShort();

    c.length-=7;

    if(c.errorReason!=0){
      return;
    }

    Graphics g=ddst.getGraphics();
    if(((dsrc instanceof Window) && !((Window)dsrc).ddxwindow.isVisible())){
      g=null;
    }

    if(dsrc.width<=sx || dsrc.height<=sy ||
       (sx+width)<=0 || (sy+height)<=0 ||
       (destx+width)<=0 || (desty+height)<=0){
      g=null;
    }

    /*
    System.out.println("copyArea: "+dsrc+" sx="+sx+",sy="+sy+
                                  ", w="+width+", h="+height+" "+
                                   ddst+" destx="+destx+",desty="+desty);
    */

    if(g!=null){
      if(dsrc instanceof Window){

        if(sx<0){sx=0;}
        if(sy<0){sy=0;}
        if(destx<0){destx=0;}
        if(desty<0){desty=0;}

	if(ddst instanceof Window){
          ((Window)dsrc).ddxwindow.
	    copyArea(((Window)ddst), gc,
		     sx, sy, width, height, destx, desty); 
	}
//      else{
//	  ((Window)dsrc).ddxwindow.
//	    copyArea((Pixmap)ddst, gc,
//		     sx, sy, destx, desty, width, height);
//	}
      }
      else {

	if(ddst instanceof Pixmap){
          if(sx<0){sx=0;}
          if(sy<0){sy=0;}
          if(destx<0){destx=0;}
          if(desty<0){desty=0;}

	  ((Pixmap)dsrc).copyArea((Pixmap)ddst, gc, 
				  sx, sy, destx, desty, width, height);
	}
	else{
	  Image img=((Pixmap)dsrc).getImage((Window)ddst, gc, 
					    sx, sy, width, height);

	  Window wdst=(Window)ddst;

	  if(sx==0 && sy==0 && width==dsrc.width && height==dsrc.height){
	    wdst.ddxwindow.drawImage(gc.clip_mask,
				     img, 
                                     destx, desty, width, height);
	  }
	  else{
  	    java.awt.Shape tmp=g.getClip();
	    if(destx>=0 && desty>=0){
  	      g.clipRect(destx, desty, width, height);
	    }
            else{
  	      g.clipRect((destx<0?0:destx),
			 (desty<0?0:desty),
			 (destx<0?width+destx:width),
			 (desty<0?height+desty:height));
	    }
	    wdst.ddxwindow.drawImage(gc.clip_mask,
				     img, destx-sx, desty-sy, 
				     dsrc.width, dsrc.height);
	    if(tmp==null){ g.setClip(0, 0, wdst.width, wdst.height); }
            else{ g.setClip(tmp); }
	  }
	  wdst.draw(destx, desty, width, height);
	  if(img!=((Pixmap)dsrc).getImage()){
	    img.flush();
	  }
	}
      }
    }

    if((gc.attr&GC.graphicsExposures)!=0){
      c.cevent.mkNoExposure(dest, 0, 62);
      c.sendEvent(c.cevent,
		  1, 
		  0,
		  Event.NoEventMask,
		  null);
    }
  }

  static final void reqClearArea(Client c) throws IOException{
    int foo;
    int exposures=c.data;
    IO io=c.client;
    foo=io.readInt();
    c.length-=2;
    Window w=c.lookupWindow(foo);
    if(w==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
      return;
    }

    int x, y, width, height;

    x=(short)io.readShort();
    y=(short)io.readShort();
    width=io.readShort();
    if(width==0){width=w.width-x;}
    height=io.readShort();
    if(height==0){height=w.height-y;}

    c.length-=2;

    if(c.errorReason!=0){
      return;
    }

    if(w.getGraphics()!=null){  // isMapped??
      w.makeBackgroundTile(x, y, width, height);
      w.draw(x, y, width+1, height+1);    
    }
 
    if(exposures!=0){
      c.cevent.mkExpose(w.id, x, y, width, height, 0);
      c.sendEvent(c.cevent, 1, 
		  Event.filters[Event.Expose],
		  Event.filters[Event.Expose], Window.grab);
    }
  }
  
  void draw(){
    ddxwindow.draw();
  }

  void draw(int x, int y, int width, int height){
    ddxwindow.draw(x, y, width, height);
  }

  private Window trackParent(){
    Window w=this;
    while(true){
      if(w.optional!=null)break;
      w=w.parent;
    }
    return w;
  }

  private Client getClient(){
    return Client.clients[(((id) & Client.CLIENTMASK) >> Client.CLIENTOFFSET)];
  }

  private int getBackingBitPlanes(){
    if(optional==null)return ~0;
    return (int)optional.backingBitPlanes;
  }

  private int getBackingPixel(){
    if(optional==null)return 0;
    return (int)optional.backingPixel;
  }

  OtherClients getOtherClients(){
    if(optional==null)return null;
    return optional.otherClients;
  }

  static java.awt.Frame owner=new java.awt.Frame();          
  java.awt.Window frame=null;                                

  static private final int poolsize=5;                       
  static java.awt.Window[] frames=new java.awt.Window[poolsize]; 

  java.awt.Window getFrame(){
    if(hasFrame()) return optional.frame;
    if(parent!=screen.root){
      return null;
    }

    makeOptional();
    if(screen.windowmode==WeirdX.RootlessWM &&
       !screen.root.redirectSend() &&
       (attr&(1<<16))==0){
      optional.frame=new java.awt.Frame();     
      optional.frame.addMouseListener((java.awt.event.MouseListener)ddxwindow);
      return optional.frame;
    }

    synchronized(Window.class){                           
      java.awt.Window foo=null;                                
      for(int i=0; i<poolsize; i++){                           
        if(frames[i]!=null){                                   
          foo=frames[i];
          frames[i]=null;
          optional.frame=foo;           
          return foo;
        }                                                      
      }                                 
    }                                 
    optional.frame=new java.awt.Window(owner);     
    return optional.frame;                  
  }
  boolean hasFrame(){
    return (optional!=null && optional.frame!=null);
  }

  void delFrame(){
    if(optional==null || optional.frame==null) return;
    optional.frame.setVisible(false);
    if(screen.windowmode==WeirdX.RootlessWM &&
       optional.frame instanceof java.awt.Frame){
      optional.frame.removeMouseListener((java.awt.event.MouseListener)ddxwindow);
//    optional.frame.dispose();
      optional.frame=null;
      return;
    }

    synchronized(Window.class){                           
      for(int i=0; i<poolsize; i++){                           
        if(frames[i]==null){                                   
          frames[i]=optional.frame;
          optional.frame=null;
          return;                               
        }                                                      
      }                                                        
    }
    optional.frame.dispose();
    optional.frame=null;
  }

  void setProperty(Property p){
    makeOptional();
    optional.userProps=p;
  }

  Property getProperty(){
    if(optional==null)return null;
    return optional.userProps;
  }

  static final void reqConfigureWindow(Client c) throws IOException{
    int foo;
    int n;
    IO io=c.client;
    foo=io.readInt();
    Window win=c.lookupWindow(foo);
    if(win==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow
    }

    int mask=io.readShort();
    io.readPad(2);
    c.length-=3;
    if(c.errorReason!=0){ return; }
    if(((win.clss==InputOnly) && 
	 (mask & IllegalInputOnlyConfigureMask)!=0) ||
	((mask & CWSibling)!=0 && (mask & CWStackMode)==0)){
      c.errorReason=8; // BadMatch
      return;
    }

    int index;
    int x,y;
    int w=win.width;
    int h=win.height;
    int bw=win.borderWidth;
    Window sib=null;

    synchronized(LOCK){
      win=c.lookupWindow(win.id);
      if(win==null){
	c.errorValue=win.id;
	c.errorReason=3; // BadWindow
	return;
      }
      if(win.screen.root!=win && win.parent==null) return;
      if(win.parent!=null){
	x=win.x-win.parent.x-bw;
	y=win.y-win.parent.y-bw;
      }
      else{
	x=win.x;
	y=win.y;
      }
      
      mask&=0x7f;

      int beforex=x, beforey=y;

      int smode=0;
      int tmp=mask;
      while(tmp!=0 && c.length!=0){
	index=lowbit(tmp);
	tmp&=~index;
	switch(index){
	case CWX: 
	  foo=io.readInt();
	  foo=(short)(foo&0xffff);
	  if(foo==x){ mask-=CWX; }
	  else{ x=(short)(foo); }
	  break;
	case CWY: 
	  foo=io.readInt();
	  foo=(short)(foo&0xffff);
	  if(foo==y){ mask-=CWY; }
	  else{ y=(short)(foo); }
	  break;
	case CWWidth: 
	  foo=io.readInt();
	  foo=(foo&0xffff);
	  if(w==foo){ mask-=CWWidth; }
	  else{ w=foo; }
	  break;
	case CWHeight: 
	  foo=io.readInt();
	  foo=(foo&0xffff);
	  if(h==foo){ mask-=CWHeight; }
	  else{ h=foo; }
	  break;
	case CWBorderWidth: 
	  foo=io.readInt();
	  foo=(foo&0xffff);
	  bw=foo;
	  break;
	case CWSibling: 
	  foo=io.readInt();
	  sib=c.lookupWindow(foo);
	  if(sib==null){
	    c.errorValue=foo;
	    c.errorReason=3; // BadWindow
	  }
	  else if((sib.parent!=win.parent) || (sib==win)){
	    c.errorReason=8; // BadMatch
	  }
	  break;
	case CWStackMode: 
	  foo=io.readInt();
	  foo&=0xff;
	  smode=foo;
	  if((smode!=TopIf) && (smode!=BottomIf) &&
	     (smode!=Opposite) && (smode!=Above) && (smode!=Below)){
	    c.errorValue=foo;
	    c.errorReason=2; // BadValue
	  }
	  break;
	default:
	  c.errorValue=mask;
	  c.errorReason=2; // BadValue
	  return;
	}
	c.length--;
	if(c.errorReason!=0){
	  return;
	}
      }
      if(c.length!=0){
	c.errorValue=mask;
	c.errorReason=2; // BadValue
      return;
      }
    
      if(mask==0){
	return;
      }

      if(win.parent==null) return;

      if((mask&CWStackMode)!=0){
	sib=win.getPlaceInTheStack(sib, 
				   win.parent.x+x, win.parent.y+y,
				   w+bw*2, h+bw*2, smode);
      }
      else{ sib=win.nextSib; }

      if(((win.attr&overrideRedirect)==0) &&
	 (win.parent.redirectSend())){
	c.cevent.mkConfigureRequest(((mask&CWStackMode)!=0)?smode:Above,
				    win.parent.id, 
				    win.id, 
				    ((mask&CWSibling)!=0)? sib.id : 0,
				    x, y, w, h, bw, mask);
	if(win.parent.sendEvent(c.cevent, 1,
				Event.SubstructureRedirectMask, c)==1){
	  return;
	}

      }

      int action=Restack;
      if((mask & (CWX|CWY))!=0 && (mask & (CWHeight|CWWidth))==0){
	action=Move;
      }
      else if((mask & ChangeMask)!=0){
	if(w==0 || h==0){
	  c.errorValue=0;
	  c.errorReason=2; // BadBalue;
	  return; 
	}
	action=Resize;
      }

      if(action==Resize){
	boolean sizec=((w!=win.width)||(h!=win.height));
	if(sizec && 
	   (((win.eventMask|win.getOtherEventMask())&Event.ResizeRedirectMask)!=0)){
	  c.cevent.mkResizeRequest(win.id, w, h);
	  if(win.sendEvent(c.cevent, 1,
			   Event.ResizeRedirectMask, c)==1){
	    w=win.width;
	    h=win.height;
	    sizec=false;
	  }
	}
	if(!sizec){
	  if((mask&(CWX|CWY))!=0) action=Move;
	  else if((mask&(CWStackMode|CWBorderWidth))!=0){ action=Restack; }
	  else{ return; }
	}
      }

      if((action==Resize)||
	 (((mask&CWX)!=0)&& x!=beforex) ||
	 (((mask&CWY)!=0)&& y!=beforey) ||
	 (((mask&CWBorderWidth)!=0)&& bw!=win.borderWidth) ||
	 (((mask&CWStackMode)!=0) && win.nextSib!=sib)){
	if(win.substrSend()){
	  c.cevent.mkConfigureNotify(win.id,
				     (sib!=null? sib.id:0),
				     x, y, w, h, bw, 
				     (win.attr&overrideRedirect)!=0?0:1);
	  win.sendEvent(c.cevent, 1, null);
	}

	if((mask&CWBorderWidth)!=0){
	  if(action==Restack){
	    action=Move;
	    win.borderWidth=bw;
	    win.ddxwindow.setBorder(bw);
	  }
	  else if((action==Move) &&
		  ((beforex+win.borderWidth)==x+bw) &&
		  ((beforey+win.borderWidth)==y+bw)){
	    action=Reborder;
	  }
	  else{
	    win.borderWidth=bw;
	    win.ddxwindow.setBorder(bw);
	  }
	}

        if((mask&CWStackMode)!=0){           
	  win.reflectStackChange(sib
                                  );
	}

	if(((mask&CWX)!=0) || ((mask&CWY)!=0) ||
	   ((mask&CWWidth)!=0) || ((mask&CWHeight)!=0)
	   ||((mask&CWBorderWidth)!=0)){
	  win.origin.x=x+bw;
	  win.origin.y=y+bw;

	  int dx,dy, dw, dh;
	  dx=dy=dw=dh=0;
	  dw=w-win.width;
	  dh=h-win.height;
	  win.height=h;
	  win.width=w;

	  int newx=win.parent.x+x+bw;
	  int newy=win.parent.y+y+bw;

	  int oldx, oldy;
	  oldx=win.x;
	  oldy=win.y;

	  x=win.x=newx;
	  y=win.y=newy;

          Window wToValidate=win.moveInStack(sib);
	  if(((mask&CWWidth)!=0) || ((mask&CWHeight)!=0)
	     ||((mask&CWBorderWidth)!=0)){
            if(win.screen.windowmode!=WeirdX.InBrowser && win.hasFrame()){  
	      java.awt.Window frame=win.getFrame();                      
              frame.validate();
	      Insets insets=frame.getInsets();                         
   	      frame.setSize(win.width+win.borderWidth*2+             
		            insets.left+insets.right,                  
		            win.height+win.borderWidth*2+            
		            insets.bottom+insets.top);                 
              frame.validate();
            }                                                  

	    win.ddxwindow.setSize(win.width, win.height);
	  }

	  win.resizeChildrenWinSize(x-oldx, y-oldy, dw, dh);
	  win.ddxwindow.setLocation(win.origin.x-win.borderWidth+win.parent.borderWidth,
                                    win.origin.y-win.borderWidth+win.parent.borderWidth);

        }
	return;
      }
      else{
	return;
      }
    }
  }

  private int getDontPropagateMask(){
    if(optional==null)
      return DontPropagate.masks[(attr&dontPropagate)>>dontPropagateOffset];
    return optional.dontPropagateMask;
  }

  Grab getPassiveGrabs(){
    if(optional==null) return null;
    return optional.passiveGrabs;
  }

  int getOtherEventMask(){
    if(optional==null) return 0;
    return optional.otherEventMasks;
  }

  void setColormap(Colormap cmap){
    makeOptional();
    optional.colormap=cmap;
  }
  Colormap getColormap(){
    return trackParent().optional.colormap;
  }
  private int getColormapId(){
    if(clss==InputOnly) return 0;
    return getColormap().id;
  }

  void setVisual(int id){
    makeOptional();
    optional.visual=id;
  }
  private int getVisual(){
    return trackParent().optional.visual;
  }

  boolean isMapped(){ return (attr&mapped)!=0; }
  boolean isRealized(){ return (attr&realized)!=0; }
  boolean isViewable(){ return (attr&viewable)!=0; }
  boolean isBorderPixel(){ return (attr&borderIsPixel)!=0; }
  void setBorderIsPixel(){ attr|=borderIsPixel; }
  void setBackgroundIsPixel(){ 
    attr&=~backgroundState;
    attr|=BackgroundPixel;
  }

  boolean hasParentRelativeBorder(){
    return (attr&borderIsPixel)==0 && 
           hasBorder() &&                               
           (attr&backgroundState)==ParentRelative;
  }

  boolean hasBorder(){ return borderWidth!=0; }

  private void reflectStackChange(Window sib) throws IOException{
    boolean wasViewable=(attr&viewable)!=0;
    if(parent==null) return;

    Window firstChange=moveInStack(sib);
    if((attr&realized)!=0){
      restructured();
    }
  }

  private int isSiblingAboveMe(Window sib){
    Window win=parent.firstChild;
    while (win!=null){
      if(win==sib) return(Above);
      else if(win==this) return(Below);
      win=win.nextSib;
    }
    return(Below);
  }

  private Window getPlaceInTheStack(Window sib, 
				    int x, int y, int w, int h, int smode){
    if((this==parent.firstChild) && (this==parent.lastChild)) return null;

    Window first=parent.firstChild;
    switch (smode){
    case Above:
      if(sib!=null) return(sib);
      else if(this==first) return(nextSib);
      else return(first);
    case Below:
      if(sib!=null)
	if(sib.nextSib !=this) return(sib.nextSib);
	else return(nextSib);
      else
	return null;
    case TopIf:
      if((((attr&mapped)==0) || (sib!=null && (sib.attr&mapped)==0)))
	return(nextSib);
      else if(sib!=null){
	if((isSiblingAboveMe(sib)==Above))
	  return(first);
	else
	  return(nextSib);
      }
      else 
	return(first);
    case BottomIf:
      if((((attr&mapped)==0) || (sib!=null && (sib.attr&mapped)==0)))
	return(nextSib);
      else if(sib!=null){
	if((isSiblingAboveMe(sib)==Below))
	  return null;
	else
	  return(nextSib);
      }
      else 
	return null;
    case Opposite:
      if((((attr&mapped)==0) || (sib!=null && (sib.attr&mapped)==0)))
	return(nextSib);
      else if(sib!=null){
	if(isSiblingAboveMe(sib)==Above)
	  return(first);
	else
	  return null;
      }
      else 
	return(first);
    default:
      return nextSib;
    }
  }

  private Window moveInStack(Window next){
    Window firstChange=this;
    synchronized(LOCK){
      if(nextSib !=next){
	if(next==null){	                  // to bottom 
	  if(parent.firstChild==this) parent.firstChild=nextSib;
	  firstChange=nextSib;
	  nextSib.prevSib=prevSib;
	  if(prevSib!=null) prevSib.nextSib=nextSib;
	  parent.lastChild.nextSib=this;
	  prevSib=parent.lastChild;
	  nextSib=null;
	  parent.lastChild=this;

	  if(screen.windowmode==WeirdX.InBrowser || parent!=screen.root){
            parent.ddxwindow.add((java.awt.Component)(this.ddxwindow), -1); 
	  }                                                        
	}
	else if(parent.firstChild==next){  // to top
	  firstChange=this;
	  if(parent.lastChild==this) parent.lastChild=prevSib;
	  if(nextSib!=null) nextSib.prevSib=prevSib;
	  if(prevSib!=null) prevSib.nextSib=nextSib;
	  nextSib=parent.firstChild;
	  prevSib=null;
	  next.prevSib=this;
	  parent.firstChild=this;

	  if(screen.windowmode==WeirdX.InBrowser || parent!=screen.root){
	    parent.ddxwindow.add((java.awt.Component)(this.ddxwindow), 0); 
	  }                                                     
	}
	else{			                   // in middle
	  Window pOldNext=nextSib;
	  firstChange=null;
	  if(parent.firstChild==this)
	    firstChange=parent.firstChild=nextSib;
	  if(parent.lastChild==this){
	    firstChange=this;
	    parent.lastChild=prevSib;
	  }
	  if(nextSib!=null) nextSib.prevSib=prevSib;
	  if(prevSib!=null) prevSib.nextSib=nextSib;
	  nextSib=next;
	  prevSib=next.prevSib;
	  if(next.prevSib!=null) next.prevSib.nextSib=this;
	  next.prevSib=this;
	  if(firstChange==null){
	    firstChange=parent.firstChild;
	    while ((firstChange !=this) && (firstChange !=pOldNext))
	      firstChange=firstChange.nextSib;
	  }

	  Component[] component=parent.ddxwindow.getComponents();
	  for(int i=0; i<component.length;i++){
	    if(component[i]==next.ddxwindow){
	      if(i!=0)i--;
	      if(screen.windowmode==WeirdX.InBrowser || parent!=screen.root){
		parent.ddxwindow.add((java.awt.Component)(this.ddxwindow), i);
	      }
	      break;
	    }
	  }
	}
      }
    }
    this.draw();
    return firstChange;
  }

  static final void reqReparentWindow(Client c) throws IOException{
    int foo;
    int x,y;
    IO io=c.client;

    foo=io.readInt();
    Window win=c.lookupWindow(foo);
    if(win==null){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
    }

    foo=io.readInt();
    Window parent=c.lookupWindow(foo);
    if(parent==null && c.errorReason==0){
      c.errorValue=foo;
      c.errorReason=3; // BadWindow;
    }

    x=(short)io.readShort();
    y=(short)io.readShort();

    c.length-=4;

    if(c.errorReason!=0) return;
    win.reparent(parent, x, y, c);
  }

  void reparent(Window newparent, int xx, int yy, Client c) 
    throws IOException{
    boolean wasMapped;

    synchronized(LOCK){
      if(parent==null) return;

      int bw=borderWidth;
      wasMapped=((attr&mapped) !=0);
      Window prev;

      makeOptional();

      if(wasMapped){
	unmapWindow(false);
      }

      c.cevent.mkReparentNotify(id, id, newparent.id,
				xx, yy, ((attr&overrideRedirect)!=0 ? 1 : 0));

      sendEvent(c.cevent, 1, newparent);

      prev=parent;
      if(prev.firstChild==this) prev.firstChild=nextSib;
      if(prev.lastChild==this) prev.lastChild=prevSib;

      if(nextSib!=null) nextSib.prevSib=prevSib;
      if(prevSib!=null) prevSib.nextSib=nextSib;

      parent=newparent;

      nextSib=newparent.firstChild;
      prevSib=null;
      if(newparent.firstChild!=null) newparent.firstChild.prevSib=this;
      else newparent.lastChild=this;
      newparent.firstChild=this;

      origin.x=(short)(xx);
      origin.y=(short)(yy);
      x=(short)(xx + newparent.x);
      y=(short)(yy + newparent.y);

      if(screen.windowmode!=WeirdX.InBrowser && hasFrame()){                 
	java.awt.Window frame=getFrame();                                 
        frame.remove((java.awt.Component)ddxwindow);
//	frame.dispose();                                        
	delFrame();                                         
      }                                                         
      if(screen.windowmode!=WeirdX.InBrowser && newparent==screen.root){
        java.awt.Window frame=getFrame();
	/*if(frame instanceof JFrame){                               
	  ((JFrame)frame).setJMenuBar(null);                       
	  ((JFrame)frame).getContentPane().setLayout(null);        
  	  ((JFrame)frame).setResizable(false);                                 
	}                                                          
	else*/ if(frame instanceof Frame){
	  ((Frame)frame).setMenuBar(null);                                  
  	  ((Frame)frame).setResizable(true);
	}                                                          
                                                                
	ddxwindow.setLocation(0, 0);                            
                                    
        frame.add((java.awt.Component)ddxwindow);

        frame.validate();
	Insets insets=frame.getInsets();                      
	frame.setSize(this.width+this.borderWidth*2+          
		      insets.left+insets.right,               
		      this.height+this.borderWidth*2+         
		      insets.bottom+insets.top);              
        frame.validate();

        if(frame instanceof Frame){
          addWindowListener((java.awt.Frame)frame);
          addComponentListener((java.awt.Frame)frame);
	}
      }                                                         
      else{                                                     
	newparent.ddxwindow.add((java.awt.Component)ddxwindow, 0); // ???
	ddxwindow.setLocation(origin.x-borderWidth+parent.borderWidth,
			      origin.y-borderWidth+parent.borderWidth);
      }                                                         

      resizeChildrenWinSize(0, 0, 0, 0);

      if(wasMapped){
	mapWindow(c);
      }

      recalculateDeliverableEvents();
    }
  }

  void recalculateDeliverableEvents(){
    OtherClients others;

    Window child=this;
    while (true){
      if(child.optional!=null){
	child.optional.otherEventMasks=0;
	others=(optional==null)? null: optional.otherClients;
	for(; others!=null; others=(OtherClients)others.next){
	  child.optional.otherEventMasks |=others.mask;
	}
      }

      child.deliverableEvents=child.eventMask|child.getOtherEventMask();
      if(child.parent!=null)
	child.deliverableEvents |=
	  (child.parent.deliverableEvents & Event.PropagateMask 
	   & ~(child.getDontPropagateMask()));

      if(child.firstChild!=null){
	child=child.firstChild;
	continue;
      }

      while (child.nextSib==null && (child !=this))
	child=child.parent;
      if(child==this)
        break;
      child=child.nextSib;
    }
  }

  final Graphics getGraphics(){
    if(clss==InputOnly) return ddxwindow.getGraphics();
    else return ddxwindow.getGraphics2();
  }

  final Graphics getGraphics(GC gc, int mask){   
    if(clss==InputOnly) return ddxwindow.getGraphics();
    else return ddxwindow.getGraphics(gc, mask);
  }

  final Image getImage(){ return ddxwindow.getImage(); }

  final Image getImage(int x, int y, int width, int height){
    return ddxwindow.getImage(null, x, y, width, height);
  }

  final Image getImage(GC gc, int x, int y, int width, int height){
    return ddxwindow.getImage(gc, x, y, width, height);
  }

  private void setEventMask(Client c, int mask){
    int check;
    OtherClients others;
    check=(mask & Event.AtMostOneClient);
    if((check & (eventMask|getOtherEventMask()))!=0){
      if(getClient()!=c && (check & eventMask)!=0){
	c.errorReason=10; // BadAccess
      }
      for(others=getOtherClients(); others!=null; 
	   others=(OtherClients)others.next){
	if(!others.sameClient(c) && (check & others.mask)!=0){
	  c.errorReason=10; // BadAccess
	  return;
	}
      }
    }
    if(client==c){
	check=eventMask;
	eventMask=mask;
    }
    else {
      others=(optional==null)?null: optional.otherClients;
      for( ;others!=null; others=(OtherClients)others.next){
	if(others.sameClient(c)){
	  check=others.mask;
	  if(mask==0){
	    Resource.freeResource(others.id, RT_NONE);
	    return ;
	  }
	  else{
	    others.mask=mask;
	  }
	  recalculateDeliverableEvents();
	  return;
	}
      }
      check=0;
      makeOptional();

      others=new OtherClients(Resource.fakeClientId(c));
      others.mask=mask;
      others.resource=others.id;
      others.window=this;
      others.next=optional.otherClients;
      optional.otherClients=others;
      Resource.add(others);
    }
    recalculateDeliverableEvents();
    return ;
  }

  private static void gravityTranslate (int newx, int newy, 
					int oldx, int oldy, 
					int dw, int dh,
					int gravity, Point point){
    switch (gravity){
    case NorthGravity:
      point.x=newx + dw / 2;
      point.y=newy;
	break;
    case NorthEastGravity:
      point.x=newx + dw;
      point.y=newy;
	break;
    case WestGravity:
      point.x=newx;
      point.y=newy + dh / 2;
	break;
    case CenterGravity:
      point.x=newx + dw / 2;
      point.y=newy + dh / 2;
	break;
    case EastGravity:
      point.x=newx + dw;
      point.y=newy + dh / 2;
	break;
    case SouthWestGravity:
      point.x=newx;
      point.y=newy + dh;
	break;
    case SouthGravity:
      point.x=newx + dw / 2;
      point.y=newy + dh;
	break;
    case SouthEastGravity:
      point.x=newx + dw;
      point.y=newy + dh;
	break;
    case StaticGravity:
      point.x=oldx;
      point.y=oldy;
	break;
    default:
      point.x=newx;
      point.y=newy;
	break;
    }
  }

  private void resizeChildrenWinSize(int dx, int dy, int dw, int dh)
    throws IOException {
    boolean resized=(dw!=0 || dh!=0);
    for(Window sib=firstChild; sib!=null; sib=sib.nextSib){
      if(resized && 
	  (((sib.attr&winGravity)>>winGravityOffset) > NorthWestGravity)){
	int newx=sib.origin.x;
	int newy=sib.origin.y;
	gravityTranslate (newx, newy, newx-dx, newy-dy, dw, dh,
                          (sib.attr&winGravity)>>winGravityOffset,
                          gpoint);
	if(gpoint.x  !=sib.origin.x || gpoint.y !=sib.origin.y){
	  Event event=new Event();
	  event.mkGravityNotify(sib.id, sib.id, 
				gpoint.x - sib.borderWidth,
				gpoint.y - sib.borderWidth
                                );
	  sib.sendEvent(event, 1, null);
          sib.origin.x=gpoint.x;
          sib.origin.y=gpoint.y;
	}
      }
   
      sib.x=x + sib.origin.x;
      sib.y=y + sib.origin.y;
      if(sib.ddxwindow!=null) // ??
      sib.ddxwindow.setLocation(sib.origin.x-sib.borderWidth+sib.parent.borderWidth,
				sib.origin.y-sib.borderWidth+sib.parent.borderWidth);
      Window child=sib.firstChild;
      if(child !=null){
	while (true){
	  child.x=child.parent.x + child.origin.x;
	  child.y=child.parent.y + child.origin.y;
          if(child.ddxwindow!=null) // ??
	  child.ddxwindow.setLocation(child.origin.x-child.borderWidth+child.parent.borderWidth,
				      child.origin.y-child.borderWidth+child.parent.borderWidth);
	  if(child.firstChild!=null){
	    child=child.firstChild;
	    continue;
	  }
	  while (child.nextSib==null && (child !=sib))
	    child=child.parent;
	  if(child==sib) break;
	  child=child.nextSib;
	}
      }
    }
  }

   static boolean checkDeviceGrabs(Event e, int checkFirst, int count)
    throws IOException {

    Window win;
    int i=checkFirst;
    for(; i < spriteTraceGood; i++){
      win=spriteTrace[i];
      if(win.optional!=null &&
	  win.checkPassiveGrabsOnWindow(e, count)){
	return true;
      }
    }
    return false;
  }

  boolean checkPassiveGrabsOnWindow(Event e, int count) throws IOException {
    Grab grab=getPassiveGrabs();

    if(grab==null) return false;

    synchronized(LOCK){
      Grab tempGrab=new Grab(Resource.fakeClientId(client));
      tempGrab.window=this;
      tempGrab.type=e.getType();
      tempGrab.detail.exact=e.getDetail();
      tempGrab.detail.pMask=null;
      tempGrab.modifiersDetail.pMask=null;
      tempGrab.modifiersDetail.exact=e.getState()&0x0f;
      for(; grab!=null; grab=grab.next){
        if(tempGrab.grabMatchesSecond(grab) &&
 	   (grab.confineTo==null ||
	    ((grab.confineTo.attr&realized)!=0 &&
	     (grab.confineTo.x!=0 || grab.confineTo.y!=0)))){
	  grab.activatePointerGrab((int)System.currentTimeMillis(), true);
	  e.fixUpEventFromWindow(grab.window, 0, 
				 Window.sprite.hot.x, Window.sprite.hot.y,
				 true);
	  if(grab.getClient()!=null)
	    grab.getClient().sendEvent(e, count,
				       Event.filters[e.getType()],
				       Event.filters[e.getType()],  grab);
	  return true;
	}
      }
    }
    return false;
  }

  static void sendGrabbedEvent(Event e, boolean deactivateGrab, int count)
    throws IOException{
    Grab grab=Window.grab;
    int deliveries=0;

    if((grab.attr&Grab.ownerEvents)!=0){
      Window focus=null;
      if(focus==null)
	deliveries=sendDeviceEvent(sprite.win, e, grab, null, count);
      else if(focus!=null && 
	       (focus==sprite.win || focus.isParent(sprite.win)))
	deliveries=sendDeviceEvent(sprite.win, e, grab, focus, count);
      else if(focus!=null)
	deliveries=sendDeviceEvent(focus, e, grab, focus, count);
    }

    if(deliveries==0){
      e.fixUpEventFromWindow(grab.window, 0, 
			      sprite.hot.x, sprite.hot.y, true);
      if(grab.getClient()!=null)
	deliveries=grab.getClient().sendEvent(e, count,
						grab.eventMask,
						Event.filters[e.getType()], 
						grab);
    }
  }

  static int sendDeviceEvent(Window win, Event e, 
			     Grab grab, Window stopAt, int count)
    throws IOException {
    int child=0;
    int type=e.getType();
    int filter=Event.filters[type];
    int deliveries=0;

    if((type & Event.EXTENSION_EVENT_BASE)!=0){
      OtherInputMasks inputMasks;
      int mskidx=0;
      inputMasks=(win.optional==null? null: win.optional.otherInputMasks);
      if(inputMasks!=null && 
	  (filter & inputMasks.deliverableEvents[mskidx])==0)
	return 0;
      while (win!=null){
	if(inputMasks!=null && 
	    (inputMasks.inputEvents[mskidx] & filter)!=0){
	  e.fixUpEventFromWindow(win, child, sprite.hot.x, sprite.hot.y, 
				  false);
	  deliveries=win.sendEvent(e, count, filter, grab, mskidx);
	  if(deliveries > 0) return deliveries;
	}
	if((deliveries < 0) ||
	    (win==stopAt) ||
	    (inputMasks!=null &&
	     (filter & inputMasks.dontPropagateMask[mskidx])!=0))
	  return 0;
	child=win.id;
	win=win.parent;
	if(win!=null){
	  inputMasks=(win.optional==null? null : win.optional.otherInputMasks);
	}
      }
    }
    else {
      if((filter & win.deliverableEvents)==0) return 0;

      while (win!=null){
	if(((win.getOtherEventMask()|win.eventMask) & filter)!=0){
	  e.fixUpEventFromWindow(win, child, sprite.hot.x, sprite.hot.y,
				  false);
	  deliveries=win.sendEvent(e, count, filter,  grab, 0);
	  if(deliveries > 0) return deliveries;
	}
	if((deliveries < 0) ||
	    (win==stopAt) || ((filter & win.getDontPropagateMask())!=0))
	  return 0;
	child=win.id;
	win=win.parent;
      }
    }
    return 0;
  }

  boolean isParent(Window w){
    for(w=w.parent; w!=null; w=w.parent){
      if(w==this) return true;
    }
    return false;
  }
  Window commonAncestor(Window w){
    for(w=w.parent; w!=null; w=w.parent){
      if(w.isParent(this)) return w;
    }
    return null;
  }

  private static void doFocusEvents(Client c, int fromWin, int toWin, int mode)
    throws IOException {
    int out, in;

    if(fromWin==toWin) return;

    out=(fromWin==0) ? NotifyDetailNone : NotifyPointerRoot;
    in=(toWin==0) ? NotifyDetailNone : NotifyPointerRoot;

    if((toWin==0) || (toWin==1)){
      if((fromWin==0) || (fromWin==1)){
	if(fromWin==1){
	  focusOutEvents(c, sprite.win, sprite.win.screen.root, 
			 mode, NotifyPointer, true);
	}
      }
      else {
	Window from=(c!=null) ? c.lookupWindow(fromWin) : 
	            (Window)Resource.lookupIDByClass(fromWin, Resource.RC_DRAWABLE);
	if(from==null) return;
	if(from.isParent(sprite.win)){
	  focusOutEvents(c, sprite.win, from, mode, NotifyPointer, false);
	}
	from.sendFocusEvent(c,  Event.FocusOut, mode, NotifyNonlinear);
	focusOutEvents(c, from.parent, null, mode, NotifyNonlinearVirtual, false);
      }

      if(toWin==1){
	focusInEvents(c, sprite.win.screen.root, sprite.win, 
		      null, mode, NotifyPointer, true);
      }
    }
    else {
      if((fromWin==0) || (fromWin==1)){
	if(fromWin==1){
	  focusOutEvents(c, sprite.win, sprite.win.screen.root, 
			 mode, NotifyPointer, true);
	}

	Window to=(c!=null) ? c.lookupWindow(toWin) : 
	            (Window)Resource.lookupIDByClass(toWin, Resource.RC_DRAWABLE);
	if(to==null) return;
	if(to.parent !=null){
	  focusInEvents(c, to.screen.root, to, to, mode,
			NotifyNonlinearVirtual, true);
	}
	to.sendFocusEvent(c, Event.FocusIn, mode, 
		      NotifyNonlinear);
	if(to.isParent(sprite.win)){
	  focusInEvents(c, to, sprite.win, null, mode,
			NotifyPointer, false);
	}
      }
      else {
	Window to=(c!=null) ? c.lookupWindow(toWin) : 
	          (Window)Resource.lookupIDByClass(toWin, Resource.RC_DRAWABLE);
	Window from=(c!=null) ? c.lookupWindow(fromWin) : 
	          (Window)Resource.lookupIDByClass(fromWin, Resource.RC_DRAWABLE);
	if(from==null || to==null) return;
	if(to.isParent(from)){
	  from.sendFocusEvent(c, Event.FocusOut, mode, 
			  NotifyAncestor);
	  focusOutEvents(c, from.parent, to, mode,
			 NotifyVirtual, false);
	  to.sendFocusEvent(c, Event.FocusIn, mode, 
			NotifyInferior);
	  if((to.isParent(sprite.win)) &&
	      (sprite.win !=from) &&
	      (!from.isParent(sprite.win)) &&
	      (!sprite.win.isParent(from))){
	    focusInEvents(c, to, sprite.win, null, mode, NotifyPointer, false);
	  }
	}
	else{
	  if(from.isParent(to)){
	    if((from.isParent(sprite.win)) &&
		(sprite.win !=from) &&
		(!to.isParent(sprite.win)) &&
		(!sprite.win.isParent(to))){
	      focusOutEvents(c, sprite.win, from, mode, NotifyPointer, false);
	    }
	    from.sendFocusEvent(c, Event.FocusOut, mode, NotifyInferior);
	    focusInEvents(c, from, to, to, mode, NotifyVirtual, false);
	    to.sendFocusEvent(c, Event.FocusIn, mode, NotifyAncestor);
	  }
	  else {
	    Window common=to.commonAncestor(from);

	    if(from.isParent(sprite.win)){
	      focusOutEvents(c, sprite.win, from, mode, NotifyPointer, false);
	    }
	    from.sendFocusEvent(c, Event.FocusOut, mode, NotifyNonlinear);
	    if(from.parent !=null){
	      focusOutEvents(c, from.parent, common, mode, NotifyNonlinearVirtual, false);
	    }
	    if(to.parent !=null){
	      focusInEvents(c, common, to, to, mode, NotifyNonlinearVirtual, false);
	    }
	    to.sendFocusEvent(c, Event.FocusIn, mode, NotifyNonlinear);
	    if(to.isParent(sprite.win)){
	      focusInEvents(c, to, sprite.win, null, mode, NotifyPointer, false);
	    }
	  }
	}
      }
    }
  }

  private static void focusOutEvents(Client c, 
				     Window child, Window ancestor,
				     int mode, int detail, boolean doAncestor)
    throws IOException {
    for(Window win=child; win !=ancestor; win=win.parent){
      win.sendFocusEvent(c, Event.FocusOut, mode, detail);
    }
    if(doAncestor){
      ancestor.sendFocusEvent(c, Event.FocusOut, mode, detail);
    }
  }

  private static boolean focusInEvents(Client c,
				       Window ancestor, Window child, Window skipChild,
				       int mode, int detail, boolean doAncestor)
    throws IOException {
    if(child==null){
      return ancestor==null;
    }
    if(ancestor==child){
      if(doAncestor){
	child.sendFocusEvent(c, Event.FocusIn, mode, detail);
      }
      return true;
    }
    if(focusInEvents(c, ancestor, child.parent, skipChild, 
		      mode, detail, doAncestor)){
      if(child !=skipChild){
	child.sendFocusEvent(c, Event.FocusIn, mode, detail);
      }
      return true;
    }
    return false;
  }

  void sendFocusEvent(Client c, int type, int mode, int detail) 
    throws IOException {
    Event event=(c!=null) ? c.cevent : new Event();
    if(type==Event.FocusIn){ event.mkFocusIn(detail, id, mode); }
    else if(type==Event.FocusOut){ event.mkFocusOut(detail, id, mode); }
    else{ return; }
    sendEvent(event, 1, Event.filters[type], null, 0);
  }

  void initAttr(){
    setBackgroundIsPixel();
    background.pixel=screen.white;
    setBorderIsPixel();
    border.pixel=screen.black;
    borderWidth=0;
  }

  void restoreClip(){ ddxwindow.restoreClip(); }

  private static int lowbit(int mask){
    int result=1;
    for(int i=0; i<32; i++){
      if((mask & 1)==1){result=result<<i; break;}
      mask=mask>>1;
    }
    return result;
  }

  static void printWindow(Window p1, int indent){
    for(int i=0; i<indent; i++) System.err.print(" ");
    try{
      System.err.print(Integer.toHexString(p1.id));
//    System.err.print(" mapped: "+p1.isMapped());
//    System.err.print(", realized: "+p1.isRealized());
      System.err.print(" ("+p1.x+","+p1.y+","+p1.width+","+p1.height+")");
//    System.err.print(" location: "+p1.ddxwindow.getLocation());
      System.err.println(" isVisible: "+p1.ddxwindow.isVisible());
    }
    catch(Exception ee){}
  }
  static void printChildren(Window p1, int indent){
    Window p2;
    while (p1!=null){
      p2=p1.firstChild;
      printWindow(p1, indent);
      printChildren(p2, indent+4);
      p1=p1.nextSib;
    }
  }
  static void printWindowTree(Window win){
    System.err.println("printWindowTree");
    printWindow(win, 0);
    Window p1;
    for(int i=0; i<1; i++){
	p1=win.firstChild;
	printChildren(p1, 4);
    }
  }

  private void addWindowListener(java.awt.Frame foo){
    final java.awt.Frame frame=foo; 
    frame.addWindowListener(
      new java.awt.event.WindowAdapter() {                
        public void windowClosed(java.awt.event.WindowEvent e){
        }
  	public void windowClosing(java.awt.event.WindowEvent e){
          int message_type=Atom.find("WM_PROTOCOLS");
          int del=Atom.find("WM_DELETE_WINDOW");

          synchronized(Window.LOCK){
            Property p=getProperty();
            while(p!=null){
              if(p.propertyName==message_type)break;
              p=p.next;
            }

            if(p!=null && p.data!=null){
            }
            else{
              try{
                getClient().closeDown();
              }
	      catch(Exception ee){}
              return;
            }
          }

	  if(message_type==0 || del==0) return;

          Event event=new Event();
          event.mkClientMessage(id, message_type);
          byte[] eb=event.event;
          eb[1]=32;

          eb[12]=(byte)(del>>>24);  //protocol
          eb[13]=(byte)(del>>>16);
          eb[14]=(byte)(del>>>8);
          eb[15]=(byte)(del);

          int tm=(int)System.currentTimeMillis();
          eb[16]=(byte)(tm>>>24);  //time
          eb[17]=(byte)(tm>>>16);
          eb[18]=(byte)(tm>>>8);
          eb[19]=(byte)(tm);

          eb[20]=eb[21]=eb[22]=eb[23]=0; 
          eb[24]=eb[25]=eb[26]=eb[27]=0; 
          eb[28]=eb[29]=eb[30]=eb[31]=0; 

          eb[0]|=0x80;

          try{ sendEvent(event, 1, Event.NoEventMask, null, 0); }
          catch(Exception ee){}
	}
      }
    );
  }

  private void addComponentListener(java.awt.Frame foo){
    final java.awt.Frame frame=foo; 
    frame.addComponentListener(
      new java.awt.event.ComponentAdapter() {                
        public void componentResized(java.awt.event.ComponentEvent e){
         if(parent==null)return;
          Rectangle rectangle=frame.getBounds();
          if(rectangle.width==0 ||rectangle.height==0)return;
	  if(frame_width!=rectangle.width || 
             frame_height!=rectangle.height){
            Insets insets=frame.getInsets();
	    synchronized(Window.LOCK){
   	      try{
                Point point=frame.getLocation();
                int ww=rectangle.width-insets.left-insets.right-borderWidth*2;
                int hh=rectangle.height-insets.top-insets.bottom-borderWidth*2;
	        if(ww>0 && hh>0){
                  ddxwindow.setSize(ww, hh);
                  frame.pack();
                  Event event=new Event();
	          event.mkConfigureNotify(id,
                                          id,
				          (rectangle.x+insets.left),
				          (rectangle.y+insets.top),
				          ww,
  	                                  hh,
				          borderWidth,
				          (attr&(1<<16))!=0?1:0);
	          sendEvent(event, 1, null);
                  frame_x=rectangle.x;
                  frame_y=rectangle.y;
                  frame_width=rectangle.width;
                  frame_height=rectangle.height;
		}
	      }
              catch(Exception ee){
                System.out.println(ee);
              }
            }
          }
        }
      }
    );
  }

}

class InputClients extends Clients{
  int[] mask;
  InputClients(int id){
    super(id);
    mask=new int[9/*EMASKSIZE*/];
  }
}

class OtherInputMasks {
  int[] deliverableEvents;
  int[] inputEvents;
  int[] dontPropagateMask;
  InputClients inputClients;
  OtherInputMasks(){
    deliverableEvents=new int[9/*EMASKSIZE*/];
    inputEvents=new int[9/*EMASKSIZE*/];
    dontPropagateMask=new int[9/*EMASKSIZE*/];
  }
}

class WindowOpt{
  int visual;
  Cursor cursor;
  Colormap colormap;
  int dontPropagateMask;
  int otherEventMasks;
  OtherClients otherClients;
  Grab passiveGrabs;
  Property userProps;
  long backingBitPlanes;
  long backingPixel;
  OtherInputMasks otherInputMasks;
  java.awt.Window frame;
}

class Sprite {
  Window win;
  HotSpot hot;
  Sprite(){
    hot=new HotSpot();
  }
}

final class HotSpot extends Point{
  int state=0;
}

class DontPropagate{
  static int[] masks=new int[8];
  static int[] refc=new int[8];
  static{
    for(int i=0;i<8;i++){
      masks[i]=refc[i]=0;
    }
  }

  static int store(int mask){
    int i=0;
    int free=0;
    for(i=8, free=0; --i > 0; ){
      if(refc[i]==0){free=i;}
      else if(mask==masks[i])
	break;
    }
    if(i==0 && free!=0){
      i=free;
      masks[i]=mask;
    }
    return i;
  }
}

class Focus{
  int win;
  Window window;
  int revert;
  long time;
  Window[] trace;
  int traceSize;
  int traceGood;
}
