Source for gnu.awt.LightweightRedirector

   1: /* Copyright (C) 2000  Free Software Foundation
   2: 
   3:    This file is part of libgcj.
   4: 
   5: This software is copyrighted work licensed under the terms of the
   6: Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
   7: details.  */
   8: 
   9: package gnu.awt;
  10: 
  11: import java.awt.AWTEvent;
  12: import java.awt.AWTError;
  13: import java.awt.Component;
  14: import java.awt.Container;
  15: import java.awt.event.MouseEvent;
  16: import java.awt.event.InputEvent;
  17: 
  18: /**
  19:  * Encapsulates the logic required to dispatch events to the correct
  20:  * component in a component tree that may contain lightweight
  21:  * components. Toolkits typically only identify heavyweight components
  22:  * as the source of events. This class redirects the events to the
  23:  * appropriate lightweight children of the heavyweight component.
  24:  */
  25: public class LightweightRedirector
  26: {
  27:   final static int LAST_BUTTON_NUMBER = 3;
  28: 
  29:   /* We sacrifice one array element to allow the button number to 
  30:      match the index of this array. */
  31:   Component[] releaseTargets = new Component[LAST_BUTTON_NUMBER+1];
  32: 
  33:   /** 
  34:    *
  35:    * Modifies or replaces the given event with an event that has been
  36:    * properly redirected.  State of button presses are kept so that
  37:    * button releases can be redirected to the same component as the
  38:    * button press.  It is required that all events are sent through
  39:    * this method in chronological order.
  40:    */
  41:   public AWTEvent redirect(AWTEvent event)
  42:   {
  43:     if (event instanceof MouseEvent)
  44:       return redirectMouse((MouseEvent) event);
  45: 
  46:     /* In case we don't know how to redirect the event, simply return
  47:        the event unchanged. */
  48:     return event;
  49:   }
  50: 
  51:   MouseEvent redirectMouse(MouseEvent event)
  52:   {
  53:     int button = getButtonNumber(event);
  54:     int id = event.getID();
  55: 
  56:     Component heavySource = (Component) event.getSource();
  57:     Component source = heavySource;
  58:     int x = event.getX();
  59:     int y = event.getY();
  60: 
  61:     if (id == MouseEvent.MOUSE_RELEASED)
  62:       {
  63:     Component target = releaseTargets[button];
  64: 
  65:     if (target != null)
  66:       {
  67:         releaseTargets[button] = null;
  68:         source = target;
  69: 
  70:         Component child = source;
  71:         while (child != heavySource)
  72:           {
  73:         x -= child.getX();
  74:         y -= child.getY();
  75:         child = child.getParent();
  76:         if (child == null)
  77:           System.err.println("warning, orphaned release target");
  78:           }
  79:       }
  80:       }
  81:     else
  82:       {
  83:     /* Find real component, and adjust source, x and y
  84:        accordingly. */
  85:     
  86:     while (true)
  87:       {
  88:         Component parent = source;
  89:         
  90:         Component child = parent.getComponentAt(x, y);
  91:         
  92:         if (parent == child)
  93:           break;
  94:         
  95:         // maybe ignoring would be better?
  96:         if (child == null)
  97:           {
  98:         String msg = "delivered event not within component. " +
  99:           "Heavyweight source was " + heavySource + ". " +
 100:           "Component was " + parent;
 101:         throw new AWTError(msg);
 102:           }
 103:         if (child.isLightweight())
 104:           {
 105:         // descend down to child
 106:         source = child;
 107:         x -= child.getX();
 108:         y -= child.getY();
 109:           }
 110:         else
 111:           {
 112:         System.err.println("warning: event delivered to wrong " +
 113:                    "heavyweight component. Was " +
 114:                    "delivered to " + source + ". " +
 115:                    "Should have been delivered to " +
 116:                    child + ". Maybe the native window " +
 117:                    "system is bubbling events up the " +
 118:                    "containment hierarchy.");
 119:         break;
 120:           }
 121:       }
 122:     
 123:     /* ensure that the release event is delivered to the same
 124:        component as the press event. For most toolkits this is
 125:        only necessary for lightweight components, since the
 126:        underlying windowing system takes care of its heavyweight
 127:        components. */
 128:     if (id == MouseEvent.MOUSE_PRESSED)
 129:       releaseTargets[button] = source;
 130:       }
 131:     
 132:     
 133:     if (source == heavySource)
 134:       return event; // no change in event
 135:     
 136:     // print warning for heavyweights
 137:     /* this warning can safely be removed if a toolkit that
 138:        needs heavyweight redirection support is ever created. */
 139:     if (!source.isLightweight())
 140:       System.err.println("warning: redirecting to heavyweight");
 141:     
 142:     MouseEvent redirected = new MouseEvent(source, event.getID(),
 143:                        event.getWhen(),
 144:                        event.getModifiersEx(),
 145:                        x, y,
 146:                        event.getClickCount(),
 147:                        event.isPopupTrigger());
 148:     
 149:     return redirected;
 150:   }
 151:   
 152:   /**
 153:    * Identifies the button number for an input event.
 154:    * 
 155:    * @returns the button number, or 0 if no button modifier was set
 156:    * for the event.
 157:    */
 158:   int getButtonNumber(InputEvent event)
 159:   {
 160:     int modifiers = event.getModifiersEx();
 161:     
 162:     modifiers &=
 163:       InputEvent.BUTTON1_DOWN_MASK |
 164:       InputEvent.BUTTON2_DOWN_MASK |
 165:       InputEvent.BUTTON3_DOWN_MASK;
 166:     
 167:     switch (modifiers)
 168:       {
 169:       case InputEvent.BUTTON1_DOWN_MASK:
 170:     return 1;
 171:       case InputEvent.BUTTON2_DOWN_MASK:
 172:     return 2;
 173:       case InputEvent.BUTTON3_DOWN_MASK:
 174:     return 3;
 175:       case 0:
 176:     return 0;
 177: 
 178:       default:
 179:     System.err.println("FIXME: multibutton event");
 180:     return 0;
 181:       }
 182:   }
 183: }