Home » openjdk-7 » java » awt » [javadoc | source]

    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   /**
   18    * @author Michael Danilov, Dmitry A. Durnev
   19    */
   20   package java.awt;
   21   
   22   import java.awt.event.ComponentEvent;
   23   import java.awt.event.FocusEvent;
   24   import java.awt.event.InputEvent;
   25   import java.awt.event.KeyEvent;
   26   import java.awt.event.MouseEvent;
   27   import java.awt.event.PaintEvent;
   28   import java.awt.event.WindowEvent;
   29   
   30   import org.apache.harmony.awt.internal.nls.Messages;
   31   import org.apache.harmony.awt.wtk.NativeEvent;
   32   import org.apache.harmony.awt.wtk.NativeWindow;
   33   
   34   
   35   /**
   36    * Helper package-private class for managing lightweight components &
   37    * dispatching events from heavyweight source
   38    */
   39   class Dispatcher {
   40   
   41       final PopupDispatcher popupDispatcher = new PopupDispatcher();
   42   
   43       final FocusDispatcher focusDispatcher;
   44   
   45       final MouseGrabManager mouseGrabManager = new MouseGrabManager();
   46   
   47       final MouseDispatcher mouseDispatcher;
   48   
   49       private final ComponentDispatcher componentDispatcher = new ComponentDispatcher();
   50   
   51       private final KeyDispatcher keyDispatcher = new KeyDispatcher();
   52   
   53       private final Toolkit toolkit;
   54   
   55       int clickInterval = 250;
   56   
   57       /**
   58        * @param toolkit - AWT toolkit
   59        */
   60       Dispatcher(Toolkit toolkit) {
   61           this.toolkit = toolkit;
   62   
   63           focusDispatcher = new FocusDispatcher(toolkit);
   64           mouseDispatcher = new MouseDispatcher(mouseGrabManager, toolkit);
   65       }
   66   
   67       /**
   68        * Dispatch native event: produce appropriate AWT events, 
   69        * update component's fields when needed
   70        * @param event - native event to dispatch
   71        * @return - true means default processing by OS is not needed
   72        */
   73       public boolean onEvent(NativeEvent event) {
   74           int eventId = event.getEventId();
   75   
   76           if (eventId == NativeEvent.ID_CREATED) {
   77               return toolkit.onWindowCreated(event.getWindowId());
   78           } else if (eventId == NativeEvent.ID_MOUSE_GRAB_CANCELED) {
   79               return mouseGrabManager.onGrabCanceled();
   80           } else if (popupDispatcher.onEvent(event)) {
   81               return false;
   82           } else {
   83               Component src = toolkit.getComponentById(event.getWindowId());
   84   
   85               if (src != null) {
   86                   if (((eventId >= ComponentEvent.COMPONENT_FIRST) && (eventId <= ComponentEvent.COMPONENT_LAST))
   87                           || ((eventId >= WindowEvent.WINDOW_FIRST) && (eventId <= WindowEvent.WINDOW_LAST))
   88                           || (eventId == NativeEvent.ID_INSETS_CHANGED)
   89                           || (eventId == NativeEvent.ID_BOUNDS_CHANGED)
   90                           || (eventId == NativeEvent.ID_THEME_CHANGED)) {
   91                       return componentDispatcher.dispatch(src, event);
   92                   } else if ((eventId >= MouseEvent.MOUSE_FIRST)
   93                           && (eventId <= MouseEvent.MOUSE_LAST)) {
   94                       return mouseDispatcher.dispatch(src, event);
   95                   } else if (eventId == PaintEvent.PAINT) {
   96                       src.redrawManager.addPaintRegion(src, event.getClipRects());
   97                       return true;
   98                   }
   99               }
  100               if ((eventId >= FocusEvent.FOCUS_FIRST)
  101                       && (eventId <= FocusEvent.FOCUS_LAST)) {
  102   
  103                   return focusDispatcher.dispatch(src, event);
  104               } else if ((eventId >= KeyEvent.KEY_FIRST)
  105                       && (eventId <= KeyEvent.KEY_LAST)) {
  106                   return keyDispatcher.dispatch(src, event);
  107               }
  108           }
  109   
  110           return false;
  111       }
  112   
  113       /**
  114        * The dispatcher of native events that affect 
  115        * component's state or bounds
  116        */
  117       final class ComponentDispatcher {
  118   
  119           /**
  120            * Handle native event that affects component's state or bounds
  121            * @param src - the component updated by the event
  122            * @param event - the native event
  123            * @return - as in Dispatcher.onEvent()
  124            * @see Dispatcher#onEvent(NativeEvent)
  125            */
  126           boolean dispatch(Component src, NativeEvent event) {
  127               int id = event.getEventId();
  128   
  129               if ((id == NativeEvent.ID_INSETS_CHANGED)
  130                       || (id == NativeEvent.ID_THEME_CHANGED)) {
  131                   return dispatchInsets(event, src);
  132               } else if ((id >= WindowEvent.WINDOW_FIRST)
  133                       && (id <= WindowEvent.WINDOW_LAST)) {
  134                   return dispatchWindow(event, src);
  135               } else {
  136                   return dispatchPureComponent(event, src);
  137               }
  138           }
  139   
  140           /**
  141            * Handle the change of top-level window's native decorations 
  142            * @param event - the native event
  143            * @param src - the component updated by the event
  144            * @return - as in Dispatcher.onEvent()
  145            * @see Dispatcher#onEvent(NativeEvent)
  146            */
  147           boolean dispatchInsets(NativeEvent event, Component src) {
  148               if (src instanceof Window) {
  149                   ((Window) src).setNativeInsets(event.getInsets());
  150               }
  151               return false;
  152           }
  153   
  154           /**
  155            * Handle the change of top-level window's state
  156            * @param event - the native event
  157            * @param src - the component updated by the event
  158            * @return - as in Dispatcher.onEvent()
  159            * @see Dispatcher#onEvent(NativeEvent)
  160            */
  161           boolean dispatchWindow(NativeEvent event, Component src) {
  162               Window window = (Window) src;
  163               int id = event.getEventId();
  164   
  165               if (id == WindowEvent.WINDOW_CLOSING) {
  166                   toolkit.getSystemEventQueueImpl().postEvent(
  167                             new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
  168   
  169                   return true;
  170               } else if (id == WindowEvent.WINDOW_STATE_CHANGED) {
  171                   if (window instanceof Frame) {
  172                       ((Frame) window)
  173                               .updateExtendedState(event.getWindowState());
  174                   }
  175               }
  176   
  177               return false;
  178           }
  179   
  180           /**
  181            * Handle the change of component's size and/or position
  182            * @param event - the native event
  183            * @param src - the component updated by the event
  184            * @return - as in Dispatcher.onEvent()
  185            * @see Dispatcher#onEvent(NativeEvent)
  186            */
  187           private boolean dispatchPureComponent(NativeEvent event, Component src) {
  188               Rectangle rect = event.getWindowRect();
  189               Point loc = rect.getLocation();
  190               int mask;
  191   
  192               switch (event.getEventId()) {
  193               case NativeEvent.ID_BOUNDS_CHANGED:
  194                   mask = 0;
  195                   break;
  196               case ComponentEvent.COMPONENT_MOVED:
  197                   mask = NativeWindow.BOUNDS_NOSIZE;
  198                   break;
  199               case ComponentEvent.COMPONENT_RESIZED:
  200                   mask = NativeWindow.BOUNDS_NOMOVE;
  201                   break;
  202               default:
  203                   // awt.12E=Unknown component event id.
  204                   throw new RuntimeException(Messages.getString("awt.12E")); //$NON-NLS-1$
  205               }
  206   
  207               if (!(src instanceof Window)) {
  208                   Component compTo = src.getParent();
  209                   Component compFrom = src.getHWAncestor();
  210   
  211                   if ((compTo != null) && (compFrom != null)) {
  212                       loc = MouseDispatcher.convertPoint(compFrom, loc, compTo);
  213                   }
  214               } else {
  215                   int windowState = event.getWindowState();
  216   
  217                   if ((windowState >= 0) && (src instanceof Frame)) {
  218                       ((Frame) src).updateExtendedState(windowState);
  219                   }
  220               }
  221               src.setBounds(loc.x, loc.y, rect.width, rect.height, mask, false);
  222   
  223               return false;
  224           }
  225   
  226       }
  227   
  228       /**
  229        * The dispatcher of the keyboard events
  230        */
  231       final class KeyDispatcher {
  232   
  233           /**
  234            * Handle the keyboard event using the KeyboardFocusManager
  235            * @param src - the component receiving the event
  236            * @param event - the native event
  237            * @return - as in Dispatcher.onEvent()
  238            * @see Dispatcher#onEvent(NativeEvent)
  239            */
  240           boolean dispatch(Component src, NativeEvent event) {
  241               int id = event.getEventId();
  242               int modifiers = event.getInputModifiers();
  243               int location = event.getKeyLocation();
  244               int code = event.getVKey();
  245               StringBuffer chars = event.getKeyChars();
  246               int charsLength = chars.length();
  247               long time = event.getTime();
  248               char keyChar = event.getLastChar();
  249   
  250               if (src == null) {
  251                   //retarget focus proxy key events to focusOwner:
  252                   Window focusProxyOwner = toolkit.getFocusProxyOwnerById(event
  253                           .getWindowId());
  254                   if (focusProxyOwner == null) {
  255                       return false;
  256                   }
  257                   src = KeyboardFocusManager.actualFocusOwner;
  258               }
  259   
  260               EventQueue eventQueue = toolkit.getSystemEventQueueImpl();
  261               
  262               if (src != null) {
  263                   eventQueue.postEvent(new KeyEvent(src, id, time, modifiers,
  264                           code, keyChar, location));
  265                   // KEY_TYPED goes after KEY_PRESSED
  266                   if (id == KeyEvent.KEY_PRESSED) {
  267                       for (int i = 0; i < charsLength; i++) {
  268                           keyChar = chars.charAt(i);
  269                           if (keyChar != KeyEvent.CHAR_UNDEFINED) {
  270                               eventQueue.postEvent(new KeyEvent(src,
  271                                       KeyEvent.KEY_TYPED, time, modifiers,
  272                                       KeyEvent.VK_UNDEFINED, keyChar,
  273                                       KeyEvent.KEY_LOCATION_UNKNOWN));
  274                           }
  275                       }
  276                   }
  277               }
  278   
  279               return false;
  280           }
  281   
  282       }
  283   
  284       /**
  285        * Retargets the mouse events to the grab owner when mouse is grabbed,
  286        * grab and ungrab mouse when mouse buttons are pressed and released
  287        */
  288       static final class MouseGrabManager {
  289   
  290           /** 
  291            * The top-level window holding the mouse grab 
  292            * that was explicitly started by startGrab() method
  293            */
  294           private Window nativeGrabOwner = null;
  295           /** 
  296            * The component that owns the synthetic 
  297            * mouse grab while at least one of the
  298            * mouse buttons is pressed
  299            */
  300           private Component syntheticGrabOwner = null;
  301   
  302           /**
  303            * Previous value of syntheticGrabOwner
  304            */
  305           private Component lastSyntheticGrabOwner = null;
  306   
  307           /**
  308            * Number of mouse buttons currently pressed
  309            */
  310           private int syntheticGrabDepth = 0;
  311   
  312           /**
  313            * The callback to be called when the explicit mouse grab ends
  314            */
  315           private Runnable whenCanceled;
  316   
  317           /**
  318            * Explicitly start the mouse grab
  319            * @param grabWindow - the window that will own the grab
  320            * @param whenCanceled - the callback to call when the grab ends. 
  321            * This parameter can be null
  322            */
  323           void startGrab(Window grabWindow, Runnable whenCanceled) {
  324               if (nativeGrabOwner != null) {
  325                   // awt.12F=Attempt to start nested mouse grab
  326                   throw new RuntimeException(Messages.getString("awt.12F")); //$NON-NLS-1$
  327               }
  328   
  329               NativeWindow win = grabWindow.getNativeWindow();
  330               if (win == null) {
  331                   // awt.130=Attempt to grab mouse in not displayable window
  332                   throw new RuntimeException(Messages.getString("awt.130")); //$NON-NLS-1$
  333               }
  334   
  335               nativeGrabOwner = grabWindow;
  336               this.whenCanceled = whenCanceled;
  337               win.grabMouse();
  338           }
  339   
  340           /**
  341            * Ends the explicit mouse grab. If the non-null callback was provided
  342            * in the startGrab() method, this callback is called 
  343            */
  344           void endGrab() {
  345               if (nativeGrabOwner == null) {
  346                   return;
  347               }
  348   
  349               Window grabWindow = nativeGrabOwner;
  350               nativeGrabOwner = null;
  351               NativeWindow win = grabWindow.getNativeWindow();
  352   
  353               if (win != null) {
  354                   win.ungrabMouse();
  355                   if (whenCanceled != null) {
  356                       whenCanceled.run();
  357                       whenCanceled = null;
  358                   }
  359               }
  360           }
  361   
  362           /**
  363            * Ends both explicit and synthetic grans 
  364            * @return - always returns false
  365            */
  366           boolean onGrabCanceled() {
  367               endGrab();
  368               resetSyntheticGrab();
  369   
  370               return false;
  371           }
  372   
  373           /**
  374            * Starts the synthetic mouse grab, increases the counter 
  375            * of currently pressed mouse buttons
  376            * @param source - the component where mouse press event occured
  377            * @return - the component that owns the synthetic grab
  378            */
  379           Component onMousePressed(Component source) {
  380               if (syntheticGrabDepth == 0) {
  381                   syntheticGrabOwner = source;
  382                   lastSyntheticGrabOwner = source;
  383               }
  384               syntheticGrabDepth++;
  385   
  386               return syntheticGrabOwner;
  387           }
  388   
  389           /**
  390            * Decreases the counter of currently pressed mouse buttons,
  391            * ends the synthetic mouse grab, when this counter becomes zero
  392            * @param source - the component where mouse press event occured
  393            * @return - the component that owns the synthetic grab, 
  394            * or source parameter if mouse grab was released
  395            */
  396           Component onMouseReleased(Component source) {
  397               Component ret = source;
  398   
  399               if (syntheticGrabOwner != null && nativeGrabOwner == null) {
  400                   ret = syntheticGrabOwner;
  401               }
  402               syntheticGrabDepth--;
  403               if (syntheticGrabDepth <= 0) {
  404                   resetSyntheticGrab();
  405                   lastSyntheticGrabOwner = null;
  406               }
  407   
  408               return ret;
  409           }
  410   
  411           /**
  412            * Update the state of synthetic ouse gram 
  413            * when the mouse is moved/dragged
  414            * @param event - the native event
  415            */
  416           void preprocessEvent(NativeEvent event) {
  417               int id = event.getEventId();
  418               switch (id) {
  419               case MouseEvent.MOUSE_MOVED:
  420                   if (syntheticGrabOwner != null) {
  421                       syntheticGrabOwner = null;
  422                       syntheticGrabDepth = 0;
  423                   }
  424                   if (lastSyntheticGrabOwner != null) {
  425                       lastSyntheticGrabOwner = null;
  426                   }
  427               case MouseEvent.MOUSE_DRAGGED:
  428                   if (syntheticGrabOwner == null
  429                           && lastSyntheticGrabOwner != null) {
  430                       syntheticGrabOwner = lastSyntheticGrabOwner;
  431                       syntheticGrabDepth = 0;
  432                       int mask = event.getInputModifiers();
  433                       syntheticGrabDepth += (mask & InputEvent.BUTTON1_DOWN_MASK) != 0 ? 1
  434                               : 0;
  435                       syntheticGrabDepth += (mask & InputEvent.BUTTON2_DOWN_MASK) != 0 ? 1
  436                               : 0;
  437                       syntheticGrabDepth += (mask & InputEvent.BUTTON3_DOWN_MASK) != 0 ? 1
  438                               : 0;
  439                   }
  440               }
  441           }
  442   
  443           /**
  444            * @return the component that currently owns the synthetic grab 
  445            */
  446           Component getSyntheticGrabOwner() {
  447               return syntheticGrabOwner;
  448           }
  449   
  450           /**
  451            * ends synthetic grab
  452            */
  453           private void resetSyntheticGrab() {
  454               syntheticGrabOwner = null;
  455               syntheticGrabDepth = 0;
  456           }
  457   
  458       }
  459   
  460       /**
  461        * Dispatches native events related to the pop-up boxes 
  462        * (the non-component windows such as menus and drop lists)
  463        */
  464       final class PopupDispatcher {
  465   
  466           private PopupBox activePopup;
  467   
  468           private PopupBox underCursor;
  469   
  470           private final MouseGrab grab = new MouseGrab();
  471   
  472           /**
  473            * Handles the mouse grab for pop-up boxes
  474            */
  475           private final class MouseGrab {
  476               private int depth;
  477   
  478               private PopupBox owner;
  479   
  480               private final Point start = new Point();
  481   
  482               /**
  483                * Starts the grab when mouse is pressed
  484                * @param src - the pop-up box where mouse event has occured
  485                * @param where - the mouse pointer location
  486                * @return - the grab owner
  487                */
  488               PopupBox mousePressed(PopupBox src, Point where) {
  489                   if (depth == 0) {
  490                       owner = src;
  491                       start.setLocation(where);
  492                   }
  493                   depth++;
  494                   return owner;
  495               }
  496   
  497               /**
  498                * Ends the grab when all mousebuttons are released
  499                * @param src - the pop-up box where mouse event has occured
  500                * @param where - the mouse pointer location
  501                * @return - the grab owner, or src parameter if the grab has ended
  502                */
  503               PopupBox mouseReleased(PopupBox src, Point where) {
  504                   PopupBox ret = (owner != null) ? owner : src;
  505                   if (depth == 0) {
  506                       return ret;
  507                   }
  508                   depth--;
  509                   if (depth == 0) {
  510                       PopupBox tgt = owner;
  511                       owner = null;
  512                       if (tgt != null && src == null) {
  513                           Point a = new Point(start);
  514                           Point b = new Point(where);
  515                           Point pos = tgt.getScreenLocation();
  516                           a.translate(-pos.x, -pos.y);
  517                           b.translate(-pos.x, -pos.y);
  518                           if (tgt.closeOnUngrab(a, b)) {
  519                               return null;
  520                           }
  521                       }
  522                   }
  523                   return ret;
  524               }
  525   
  526               /**
  527                * Set the grab owner to null
  528                */
  529               void reset() {
  530                   depth = 0;
  531                   owner = null;
  532                   start.setLocation(0, 0);
  533               }
  534   
  535               /**
  536                * @return - the pop-up box currently owning the grab
  537                */
  538               public PopupBox getOwner() {
  539                   return owner;
  540               }
  541           }
  542   
  543           /**
  544            * Call the mouse event handler of the pop-up box
  545            * @param src - the pop-up box where the mouse event occured
  546            * @param eventId - the event ID, one of MouseEvent.MOUSE_* constants
  547            * @param where - the mouse pointer location
  548            * @param event - native event
  549            */
  550           private void mouseEvent(PopupBox src, int eventId, Point where,
  551                   NativeEvent event) {
  552               Point pos = src.getScreenLocation();
  553               pos.setLocation(where.x - pos.x, where.y - pos.y);
  554   
  555               src.onMouseEvent(eventId, pos, event.getMouseButton(), event
  556                       .getTime(), event.getInputModifiers(), event
  557                       .getWheelRotation());
  558           }
  559   
  560           /**
  561            * Handle the native event targeted by a pop-up box. This could be 
  562            * paint event, mouse or keyboard event.
  563            * @param event - the native event
  564            * @return - false if the event was handled and doesn't 
  565            * need the further processing; true when the further 
  566            * processing is needed
  567            */
  568           boolean onEvent(NativeEvent event) {
  569               PopupBox src = toolkit.getPopupBoxById(event.getWindowId());
  570               int id = event.getEventId();
  571   
  572               if ((id == PaintEvent.PAINT)) {
  573                   if (src != null) {
  574                       src.paint(event.getClipRects());
  575                       return true;
  576                   }
  577                   Component c = toolkit.getComponentById(event.getWindowId());
  578                   if ((c != null) && (c instanceof Frame)) {
  579                       ((Frame) c).paintMenuBar(event.getClipRects());
  580                   }
  581                   return false;
  582               }
  583   
  584               if ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST)) {
  585                   Point where = event.getScreenPos();
  586   
  587                   if (src != underCursor) {
  588                       if (underCursor != null) {
  589                           mouseEvent(underCursor, MouseEvent.MOUSE_EXITED, where,
  590                                   event);
  591                       }
  592                       underCursor = src;
  593                       if (underCursor != null) {
  594                           mouseEvent(underCursor, MouseEvent.MOUSE_ENTERED,
  595                                   where, event);
  596                           underCursor.setDefaultCursor();
  597                       }
  598                   }
  599                   if (id == MouseEvent.MOUSE_EXITED) {
  600                       underCursor = null;
  601                   }
  602   
  603                   if ((activePopup == null) && (src == null || !src.isMenuBar())) {
  604                       return false;
  605                   }
  606   
  607                   if (id == MouseEvent.MOUSE_PRESSED) {
  608                       src = grab.mousePressed(src, where);
  609                   } else if (id == MouseEvent.MOUSE_RELEASED) {
  610                       src = grab.mouseReleased(src, where);
  611                   } else if (src == null) {
  612                       src = grab.getOwner();
  613                   }
  614   
  615                   PopupBox wasActive = activePopup;
  616   
  617                   if (src != null) {
  618                       mouseEvent(src, id, where, event);
  619                       return src.isMenu() || src.contains(where);
  620                   }
  621   
  622                   if (wasActive != null && activePopup == null) {
  623                       return wasActive.isMenu();
  624                   }
  625   
  626                   if ((id == MouseEvent.MOUSE_PRESSED)
  627                           || (id == MouseEvent.MOUSE_RELEASED)) {
  628                       boolean isMenu = activePopup.isMenu();
  629                       deactivateAll();
  630                       return !isMenu;
  631                   }
  632                   return true;
  633               }
  634   
  635               if (activePopup == null) {
  636                   return false;
  637               }
  638   
  639               if ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST)) {
  640                   boolean isMenu = activePopup.isMenu();
  641                   activePopup.dispatchKeyEvent(id, event.getVKey(), event
  642                           .getTime(), event.getInputModifiers());
  643   
  644                   return isMenu;
  645               }
  646   
  647               return false;
  648           }
  649   
  650           /**
  651            * Remember the pop-up as active and grab the mouse on it
  652            * @param popup - the pop-up box to activate
  653            */
  654           void activate(final PopupBox popup) {
  655               if (activePopup == null) {
  656   
  657                   activePopup = popup;
  658                   mouseGrabManager.startGrab(popup.getOwner(), new Runnable() {
  659                       public void run() {
  660                           deactivate(popup);
  661                       }
  662                   });
  663               }
  664           }
  665   
  666           /**
  667            * Deactivate the currently active pop-up box
  668            */
  669           void deactivateAll() {
  670               deactivate(activePopup);
  671           }
  672   
  673           /**
  674            * Deactivate the pop-up box, end the mouse grab
  675            */
  676           void deactivate(PopupBox popup) {
  677               grab.reset();
  678   
  679               if (activePopup != null && activePopup == popup) {
  680                   activePopup = null;
  681                   mouseGrabManager.endGrab();
  682                   popup.hide();
  683                   underCursor = null;
  684               }
  685           }
  686   
  687           /**
  688            * Check that the pop-up box is currently active
  689            * @param popup - the pop-up box to check
  690            * @return - true if active
  691            */
  692           boolean isActive(PopupBox popup) {
  693               return (popup == activePopup) && (popup != null);
  694           }
  695       }
  696   
  697   }

Home » openjdk-7 » java » awt » [javadoc | source]