Source for gnu.java.awt.peer.x.XEventPump

   1: /* XEventPump.java -- Pumps events from X to AWT
   2:    Copyright (C) 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.java.awt.peer.x;
  40: 
  41: import java.awt.Graphics;
  42: import java.awt.Rectangle;
  43: import java.awt.Toolkit;
  44: import java.awt.Window;
  45: import java.awt.event.ComponentEvent;
  46: import java.awt.event.KeyEvent;
  47: import java.awt.event.MouseEvent;
  48: import java.awt.event.PaintEvent;
  49: import java.util.HashMap;
  50: 
  51: import gnu.x11.Display;
  52: import gnu.x11.event.ButtonPress;
  53: import gnu.x11.event.ButtonRelease;
  54: import gnu.x11.event.ConfigureNotify;
  55: import gnu.x11.event.Event;
  56: import gnu.x11.event.Expose;
  57: import gnu.x11.event.Input;
  58: import gnu.x11.event.KeyPress;
  59: import gnu.x11.event.KeyRelease;
  60: import gnu.x11.event.MotionNotify;
  61: 
  62: /**
  63:  * Fetches events from X, translates them to AWT events and pumps them up
  64:  * into the AWT event queue.
  65:  *
  66:  * @author Roman Kennke (kennke@aicas.com)
  67:  */
  68: public class XEventPump
  69:   implements Runnable
  70: {
  71: 
  72:   /**
  73:    * The X Display from which we fetch and pump up events.
  74:    */
  75:   private Display display;
  76: 
  77:   /**
  78:    * Maps X Windows to AWT Windows to be able to correctly determine the
  79:    * event targets.
  80:    */
  81:   private HashMap windows;
  82: 
  83:   /**
  84:    * Indicates if we are currently inside a drag operation. This is
  85:    * set to the button ID when a button is pressed and to -1 (indicating
  86:    * that no drag is active) when the mouse is released.
  87:    */
  88:   private int drag;
  89: 
  90:   /**
  91:    * Creates a new XEventPump for the specified X Display.
  92:    *
  93:    * @param d the X Display
  94:    */
  95:   XEventPump(Display d)
  96:   {
  97:     display = d;
  98:     windows = new HashMap();
  99:     drag = -1;
 100:     Thread t = new Thread(this);
 101:     t.start();
 102:   }
 103: 
 104:   /**
 105:    * The main event pump loop. This basically fetches events from the
 106:    * X Display and pumps them into the system event queue.
 107:    */
 108:   public void run()
 109:   {
 110:     while (display.connected)
 111:       {
 112:         try
 113:           {
 114:             Event xEvent = display.next_event();
 115:             handleEvent(xEvent);
 116:           }
 117:         catch (ThreadDeath death)
 118:           {
 119:             // If someone wants to kill us, let them.
 120:             return;
 121:           }
 122:         catch (Throwable x)
 123:           {
 124:             System.err.println("Exception during event dispatch:");
 125:             x.printStackTrace(System.err);
 126:           }
 127:       }
 128:   }
 129: 
 130:   /**
 131:    * Adds an X Window to AWT Window mapping. This is required so that the
 132:    * event pump can correctly determine the event targets.
 133:    *
 134:    * @param xWindow the X Window
 135:    * @param awtWindow the AWT Window
 136:    */
 137:   void registerWindow(gnu.x11.Window xWindow, Window awtWindow)
 138:   {
 139:     if (XToolkit.DEBUG)
 140:       System.err.println("registering window id: " + xWindow.id);
 141:     windows.put(new Integer(xWindow.id), awtWindow);
 142:   }
 143: 
 144:   void unregisterWindow(gnu.x11.Window xWindow)
 145:   {
 146:     windows.remove(new Integer(xWindow.id));
 147:   }
 148: 
 149:   private void handleEvent(Event xEvent)
 150:   {
 151:     Integer key = new Integer(xEvent.window_id());;
 152:     Window awtWindow = (Window) windows.get(key);
 153: 
 154:     if (XToolkit.DEBUG)
 155:       System.err.println("fetched event: " + xEvent);
 156:     switch (xEvent.code())
 157:     {
 158:     case ButtonPress.CODE:
 159:       ButtonPress bp = (ButtonPress) xEvent;
 160:       // Create and post the mouse event.
 161:       int button = bp.detail();
 162:       drag = button;
 163:       MouseEvent mp = new MouseEvent(awtWindow, MouseEvent.MOUSE_PRESSED,
 164:                                      System.currentTimeMillis(), 0,
 165:                                      bp.event_x(), bp.event_y(),
 166:                                      1, false, button);
 167:       Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mp);
 168:       break;
 169:     case ButtonRelease.CODE:
 170:       ButtonRelease br = (ButtonRelease) xEvent;
 171:       drag = -1;
 172:       MouseEvent mr = new MouseEvent(awtWindow, MouseEvent.MOUSE_RELEASED,
 173:                                      System.currentTimeMillis(), 0,
 174:                                      br.event_x(), br.event_y(),
 175:                                      1, false, br.detail());
 176:       Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mr);
 177:       break;
 178:     case MotionNotify.CODE:
 179:       MotionNotify mn = (MotionNotify) xEvent;
 180:       MouseEvent mm;
 181:       if (drag == -1)
 182:         {
 183:           mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_MOVED,
 184:                               System.currentTimeMillis(), 0,
 185:                               mn.event_x(), mn.event_y(),
 186:                               1, false);
 187:         }
 188:       else
 189:         {
 190:           mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_DRAGGED,
 191:                               System.currentTimeMillis(), 0,
 192:                               mn.event_x(), mn.event_y(),
 193:                               1, false);
 194:         }
 195:       Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mm);
 196:       break;
 197:     case ConfigureNotify.CODE:
 198:       ConfigureNotify c = (ConfigureNotify) xEvent;
 199:       if (XToolkit.DEBUG)
 200:         System.err.println("resize request for window id: " + key);
 201: 
 202:       // Detect and report size changes.
 203:       if (c.width() != awtWindow.getWidth()
 204:           || c.height() != awtWindow.getHeight())
 205:         {
 206:           if (XToolkit.DEBUG)
 207:             System.err.println("Setting size on AWT window: " + c.width()
 208:                              + ", " + c.height() + ", " + awtWindow.getWidth()
 209:                              + ", " + awtWindow.getHeight());
 210:           ((XWindowPeer) awtWindow.getPeer()).callback = true;
 211:           awtWindow.setSize(c.width(), c.height());
 212:           ((XWindowPeer) awtWindow.getPeer()).callback = false;
 213:         }
 214:       break;
 215:     case Expose.CODE:
 216:       Expose exp = (Expose) xEvent;
 217:       if (XToolkit.DEBUG)
 218:         System.err.println("expose request for window id: " + key);
 219:       Rectangle r = new Rectangle(exp.x(), exp.y(), exp.width(),
 220:                                   exp.height());
 221:       //System.err.println("expose paint: " + r);
 222:       // We need to clear the background of the exposed rectangle.
 223:       Graphics g = awtWindow.getGraphics();
 224:       g.clearRect(r.x, r.y, r.width, r.height);
 225:       g.dispose();
 226:       PaintEvent pev = new PaintEvent(awtWindow, PaintEvent.PAINT, r);
 227:       Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(pev);
 228:       break;
 229:     case KeyPress.CODE:
 230:     case KeyRelease.CODE:
 231:       handleKeyEvent(xEvent, awtWindow);
 232:       break;
 233:     default:
 234:       if (XToolkit.DEBUG)
 235:         System.err.println("Unhandled X event: " + xEvent);
 236:     }
 237:   }
 238: 
 239:   /**
 240:    * Handles key events from X.
 241:    *
 242:    * @param xEvent the X event
 243:    * @param awtWindow the AWT window to which the event gets posted
 244:    */
 245:   private void handleKeyEvent(Event xEvent, Window awtWindow)
 246:   {
 247:     Input keyEvent = (Input) xEvent;
 248:     int xKeyCode = keyEvent.detail();
 249:     int xMods = keyEvent.state();
 250:     int keyCode = KeyboardMapping.mapToKeyCode(xEvent.display.input, xKeyCode,
 251:                                                xMods);
 252:     char keyChar = KeyboardMapping.mapToKeyChar(xEvent.display.input, xKeyCode,
 253:                                                 xMods);
 254:     if (XToolkit.DEBUG)
 255:       System.err.println("XEventPump.handleKeyEvent: " + xKeyCode + ", "
 256:                          + xMods + ": " + ((int) keyChar) + ", " + keyCode);
 257:     int awtMods = KeyboardMapping.mapModifiers(xMods);
 258:     long when = System.currentTimeMillis();
 259:     KeyEvent ke;
 260:     if (keyEvent.code() == KeyPress.CODE)
 261:       {
 262:         ke = new KeyEvent(awtWindow, KeyEvent.KEY_PRESSED, when,
 263:                           awtMods, keyCode,
 264:                           KeyEvent.CHAR_UNDEFINED);
 265:         Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke);
 266:         if (keyChar != KeyEvent.CHAR_UNDEFINED)
 267:           {
 268:             ke = new KeyEvent(awtWindow, KeyEvent.KEY_TYPED, when,
 269:                               awtMods, KeyEvent.VK_UNDEFINED,
 270:                               keyChar);
 271:             Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke);
 272:           }
 273:           
 274:       }
 275:     else
 276:       {
 277:         ke = new KeyEvent(awtWindow, KeyEvent.KEY_RELEASED, when,
 278:                           awtMods, keyCode,
 279:                           KeyEvent.CHAR_UNDEFINED);
 280:         Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke);
 281:       }
 282: 
 283:   }
 284: 
 285: 
 286: }