FileDocCategorySizeDatePackage
Canvas.javaAPI DocJ2ME MIDP 2.046300Thu Nov 07 12:02:26 GMT 2002javax.microedition.lcdui

Canvas.java

/*
 * @(#)Canvas.java	1.49 02/09/10 @(#)
 *
 * Copyright (c) 1999-2002 Sun Microsystems, Inc.  All rights reserved.
 * PROPRIETARY/CONFIDENTIAL
 * Use is subject to license terms.
 */

package javax.microedition.lcdui;

/**
 * The <code>Canvas</code> class is a base class for writing
 * applications that need to
 * handle low-level events and to issue graphics calls for drawing to the
 * display. Game applications will likely make heavy use of the
 * <code>Canvas</code> class.
 * From an application development perspective, the <code>Canvas</code> class is
 * interchangeable with standard <code>Screen</code> classes, so an
 * application may mix and
 * match <code>Canvas</code> with high-level screens as needed. For
 * example, a List screen
 * may be used to select the track for a racing game, and a
 * <code>Canvas</code> subclass
 * would implement the actual game.
 *
 * <P>The <code>Canvas</code> provides the developer with methods to
 * handle game actions,
 * key events, and
 * pointer events (if supported by the device).  Methods are
 * also provided to identify the device's capabilities and mapping of
 * keys to game actions.
 * The key events are reported with respect to <em>key codes</em>, which
 * are directly bound to concrete keys on the device, use of which may hinder
 * portability.  Portable applications should use game actions instead of key 
 * codes.</p>
 * 
 * <p> Like other subclasses of <code>Displayable</code>, the
 * <code>Canvas</code> class allows the
 * application to register a listener for commands.  Unlike other
 * <code>Displayables</code>,
 * however, the <code>Canvas</code> class requires applications to
 * subclass it in order to
 * use it. The <code>paint()</code> method is declared
 * <code>abstract</code>, and so the
 * application <em>must</em> provide an implementation in its subclass. Other
 * event-reporting methods are not declared <code>abstract,</code> and their
 * default implementations are empty (that is, they do nothing). This allows
 * the application to override only the methods that report events in which the
 * application has interest.  </p>
 *
 * <p> This is in contrast to the {@link Screen Screen} classes, which allow
 * the application to define listeners and to register them with instances of
 * the <code>Screen</code> classes. This style is not used for the
 * <code>Canvas</code> class, because
 * several new listener interfaces would need to be created, one for each kind
 * of event that might be delivered. An alternative would be to have fewer
 * listener interfaces, but this would require listeners to filter out events
 * in which they had no interest. </p>
 *
 * <a name="keyevents"></a>
 * <h3>Key Events</h3>
 *
 * <p> Applications receive keystroke events in which the individual keys are
 * named within a space of <em>key codes</em>. Every key for which events are
 * reported to MIDP applications is assigned a key code.
 * The key code values are unique for each hardware key unless two keys are
 * obvious synonyms for each other.
 * MIDP defines the following key codes:
 * {@link #KEY_NUM0 KEY_NUM0},
 * {@link #KEY_NUM1 KEY_NUM1},
 * {@link #KEY_NUM2 KEY_NUM2},
 * {@link #KEY_NUM3 KEY_NUM3},
 * {@link #KEY_NUM4 KEY_NUM4},
 * {@link #KEY_NUM5 KEY_NUM5},
 * {@link #KEY_NUM6 KEY_NUM6},
 * {@link #KEY_NUM7 KEY_NUM7},
 * {@link #KEY_NUM8 KEY_NUM8},
 * {@link #KEY_NUM9 KEY_NUM9},
 * {@link #KEY_STAR KEY_STAR}, and
 * {@link #KEY_POUND KEY_POUND}.
 * 
 * (These key codes correspond to keys on a ITU-T standard telephone keypad.)
 * Other keys may be present on the keyboard, and they will generally have key
 * codes distinct from those list above.  In order to guarantee portability,
 * applications should use only the standard key codes. </p>
 * 
 * <p>The standard key codes' values are equal to the Unicode encoding for the
 * character that represents the key.  If the device includes any other keys
 * that have an obvious correspondence to a Unicode character, their key code
 * values should equal the Unicode encoding for that character.  For keys that
 * have no corresponding Unicode character, the implementation must use
 * negative values.  Zero is defined to be an invalid key code.  It is thus
 * possible for an application to convert a keyCode into a Unicode character
 * using the following code: </p>
 * 
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    if (keyCode > 0) {
 *        char ch = (char)keyCode;    
 *        // ...
 *    }    </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <p>This technique is useful only in certain limited cases.  In particular,
 * it is not sufficient for full textual input, because it does not handle
 * upper and lower case, keyboard shift states, and characters that require
 * more than one keystroke to enter.  For textual input, applications should
 * always use {@link TextBox TextBox} or {@link TextField TextField}
 * objects.</p>
 *
 * <p> It is sometimes useful to find the <em>name</em> of a key in order to
 * display a message about this key. In this case the application may use the
 * {@link #getKeyName(int) getKeyName()} method to find a key's name. </p>
 *
 * <a name="gameactions"></a>
 * <h3>Game Actions</h3>
 * <p>
 * Portable applications that need arrow key events and gaming-related events 
 * should use <em>game actions</em> in preference to key codes and key names.  
 * MIDP defines the following game actions:
 * {@link #UP UP},
 * {@link #DOWN DOWN},
 * {@link #LEFT LEFT},
 * {@link #RIGHT RIGHT},
 * {@link #FIRE FIRE},
 * {@link #GAME_A GAME_A},
 * {@link #GAME_B GAME_B},
 * {@link #GAME_C GAME_C}, and
 * {@link #GAME_D GAME_D}.
 * </P>
 * 
 * <P> Each key code may be mapped to at most one game action.  However, a game
 * action may be associated with more than one key code.  The application can
 * translate a key code into a game action using the {@link #getGameAction(int)
 * getGameAction(int keyCode)} method, and it can translate a game action into
 * a key code using the {@link #getKeyCode(int) getKeyCode(int gameAction)}
 * method.  There may be multiple keycodes associated with a particular game 
 * action, but <code>getKeyCode</code> returns only one of them.  Supposing
 * that <code>g</code> is a valid game action and <code>k</code>
 * is a valid key code for a key associated with a game action, consider
 * the following expressions:</p>
 *
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    g == getGameAction(getKeyCode(g))     // (1)
 *    k == getKeyCode(getGameAction(k))     // (2)    </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <p>Expression (1) is <em>always</em> true.  However, expression (2) 
 * might be true but is <em>not necessarily</em> true.</p>
 *
 * <P>The implementation is not allowed to change the mapping of game
 * actions and key codes during execution of the application.</P>
 *
 * <p> Portable applications that are interested in using game actions should
 * translate every key event into a game action by calling the {@link
 * #getGameAction getGameAction()} method and then testing the result.  For
 * example, on some devices the game actions <code>UP</code>,
 * <code>DOWN</code>, <code>LEFT</code> and <code>RIGHT</code> may be
 * mapped to 4-way navigation arrow keys. In this case,<code>
 * getKeyCode(UP)</code> would
 * return a device-dependent code for the up-arrow key.  On other devices, a
 * possible mapping would be on the number keys <code>2</code>,
 * <code>4</code>, <code>6</code> and <code>8</code>. In this case,
 * <code>getKeyCode(UP)</code> would return <code>KEY_NUM2</code>.  In
 * both cases, the <code>getGameAction()</code>
 * method would return the <code>LEFT</code> game action when the user
 * presses the key that
 * is a "natural left" on her device.  </P>
 *
 * <a name="commands"></a>
 * <h3>Commands</h3>
 * 
 * <p> It is also possible for the user to issue {@link Command commands} when
 * a canvas is current. <code>Commands</code> are mapped to keys and menus in a
 * device-specific fashion. For some devices the keys used for commands may
 * overlap with the keys that will deliver key code events to the canvas. If
 * this is the case, the device will provide a means transparent to the
 * application that enables the user to select a mode that determines whether
 * these keys will deliver commands or key code events to the application.
 * When the <code>Canvas</code> is in normal mode (see <a
 * href="#fullscreen">below</a>),
 * the set of key code events available to a canvas will not change depending
 * upon the number of commands present or the presence of a command listener.
 * When the <code>Canvas</code> is in full-screen mode, if there is no
 * command listener
 * present, the device may choose to deliver key code events for keys that
 * would otherwise be reserved for delivery of commands.  Game developers
 * should be aware that access to commands will vary greatly across devices,
 * and that requiring the user to issue commands during game play may have a
 * great impact on the ease with which the game can be played. </p>
 *
 * <a name="eventdelivery"></a>
 * <h3>Event Delivery</h3>
 *
 * <P> The <code>Canvas</code> object defines several methods that are
 * called by the
 * implementation. These methods are primarily for the purpose of delivering
 * events to the application, and so they are referred to as
 * <em>event delivery</em> methods. The set of methods is: </p>
 *
 * <ul>
 * <li> <code>showNotify()</code> </li>
 * <li> <code>hideNotify()</code> </li>
 * <li> <code>keyPressed()</code> </li>
 * <li> <code>keyRepeated()</code> </li>
 * <li> <code>keyReleased()</code> </li>
 * <li> <code>pointerPressed()</code> </li>
 * <li> <code>pointerDragged()</code> </li>
 * <li> <code>pointerReleased()</code> </li>
 * <li> <code>paint()</code> </li>
 * </ul>
 *
 * <p> These methods are all called serially. That is, the implementation will
 * never call an event delivery method before a prior call to <em>any</em> of
 * the event delivery methods has returned.  The
 * <code>serviceRepaints()</code> method is an exception to this rule, as it
 * blocks until <code>paint()</code> is called and returns. This will occur
 * even if the application is in the midst of one of the event delivery
 * methods when it calls <code>serviceRepaints()</code>.  </p>
 *
 * <p>The {@link Display#callSerially Display.callSerially()} method can be
 * used to serialize some application-defined work with the event stream.
 * For further information, see the
 * <a href="./package-summary.html#events">Event Handling</a> and
 * <a href="./package-summary.html#concurrency">Concurrency</a>
 * sections of the package summary. </p>
 *
 * <p> The key-related, pointer-related, and <code>paint()</code> methods
 * will only be called while the <code>Canvas</code> is actually
 * visible on the output
 * device. These methods will therefore only be called on this
 * <code>Canvas</code> object
 * only after a call to <code>showNotify()</code> and before a call to
 * <code>hideNotify()</code>. After
 * <code>hideNotify()</code> has been called, none of the key,
 * pointer, and <code>paint</code>
 * methods will be called until after a
 * subsequent call to
 * <code>showNotify()</code> has returned.  A call to a
 * <code>run()</code> method resulting from
 * <code>callSerially()</code> may occur irrespective of calls to
 * <code>showNotify()</code> and
 * <code>hideNotify()</code>.  </p>
 *
 * <p> The {@link #showNotify() showNotify()} method is called prior to the
 * <code>Canvas</code> actually being made visible on the display, and
 * the {@link
 * #hideNotify() hideNotify()} method is called after the
 * <code>Canvas</code> has been
 * removed from the display.  The visibility state of a
 * <code>Canvas</code> (or any other
 * <code>Displayable</code> object) may be queried through the use of the {@link
 * Displayable#isShown() Displayable.isShown()} method.  The change in
 * visibility state of a <code>Canvas</code> may be caused by the
 * application management
 * software moving <code>MIDlets</code> between foreground and
 * background states, or by the
 * system obscuring the <code>Canvas</code> with system screens.
 * Thus, the calls to
 * <code>showNotify()</code> and <code>hideNotify()</code> are not
 * under the control of the <code>MIDlet</code> and
 * may occur fairly frequently.  Application developers are encouraged to
 * perform expensive setup and teardown tasks outside the
 * <code>showNotify()</code> and
 * <code>hideNotify()</code> methods in order to make them as
 * lightweight as possible. </p>
 *
 * <a name="fullscreen"></a>
 * <P>A <code>Canvas</code> can be in normal mode or in full-screen
 * mode.  In normal mode,
 * space on the display may be occupied by command labels, a title, and a
 * ticker.  By setting a <code>Canvas</code> into full-screen mode,
 * the application is
 * requesting that the <code>Canvas</code> occupy as much of the
 * display space as is
 * possible.  In full-screen mode, the title and ticker are not displayed even
 * if they are present on the <code>Canvas</code>, and
 * <code>Commands</code> may be presented using some
 * alternative means (such as through a pop-up menu).  Note that the
 * implementation may still consume a portion of the display for things like
 * status indicators, even if the displayed <code>Canvas</code> is in
 * full-screen mode.  In
 * full-screen mode, although the title is not displayed, its text may still 
 * be used for other purposes, such as for the title of a pop-up menu of 
 * <code>Commands</code>.</P>
 *
 * <P><code>Canvas</code> objects are in normal mode by default.  The normal vs.
 * full-screen mode setting is controlled through the use of the {@link
 * #setFullScreenMode} method.</P>
 * 
 * <P>Calling {@link #setFullScreenMode} may result in 
 * {@link #sizeChanged(int, int) sizeChanged()} being called.
 * The default implementation of this method does nothing.
 * The application can override this method to handle changes 
 * in size of available drawing area.
 * </p>
 *
 * <P><strong>Note:</strong> As mentioned in the "Specification
 * Requirements" section
 * of the overview, implementations must provide the user with an indication
 * of network usage. If the indicator is rendered on screen,
 * it must be visible when network activity occurs, even when
 * the <code>Canvas</code> is in full-screen mode.</P>
 *
 * @since MIDP 1.0
 */

public abstract class Canvas extends Displayable {
    
    /**
     * Constant for the <code>UP</code> game action.
     *
     * <P>Constant value <code>1</code> is set to <code>UP</code>.</P>
     */
    public static final int UP = 1;
    
    /**
     * Constant for the <code>DOWN</code> game action.
     *
     * <P>Constant value <code>6</code> is set to <code>DOWN</code>.</P>
     */
    public static final int DOWN = 6;
    
    
    /**
     * Constant for the <code>LEFT</code> game action.
     *
     * <P>Constant value <code>2</code> is set to <code>LEFT</code>.</P>
     */
    public static final int LEFT = 2;
    
    /**
     * Constant for the <code>RIGHT</code> game action.
     *
     * <P>Constant value <code>5</code> is set to <code>RIGHT</code>.</P>
     */
    public static final int RIGHT = 5;
    
    /**
     * Constant for the <code>FIRE</code> game action.
     *
     * <P>Constant value <code>8</code> is set to <code>FIRE</code>.</P>
     */
    public static final int FIRE = 8;
    
    
    /**
     * Constant for the general purpose "<code>A</code>" game action.
     *
     * <P>Constant value <code>9</code> is set to <code>GAME_A</code>.</P>
     */
    public static final int GAME_A = 9;
    
    /**
     * Constant for the general purpose "<code>B</code>" game action.
     *
     * <P>Constant value <code>10</code> is set to <code>GAME_B</code>.</P>
     */
    public static final int GAME_B = 10;
  
    /**
     * Constant for the general purpose "<code>C</code>" game action.
     *
     * <P>Constant value <code>11</code> is set to <code>GAME_C</code>.</P>
     */
    public static final int GAME_C = 11;
  
    /**
     * Constant for the general purpose "<code>D</code>" game action.
     *
     * <P>Constant value <code>12</code> is set to <code>GAME_D</code>.</P>
     */
    public static final int GAME_D = 12;
    
    /**
     * keyCode for ITU-T key <code>0</code>.
     *
     * <P>Constant value <code>48</code> is set to <code>KEY_NUM0</code>.</P>
     */
    public static final int KEY_NUM0 = 48;
    
    /**
     * keyCode for ITU-T key <code>1</code>.
     *
     * <P>Constant value <code>49</code> is set to <code>KEY_NUM1</code>.</P>
     */
    public static final int KEY_NUM1 = 49;
    
    /**
     * keyCode for ITU-T key <code>2</code>.
     *
     * <P>Constant value <code>50</code> is set to <code>KEY_NUM2</code>.</P>
     */
    public static final int KEY_NUM2 = 50;
    
    /**
     * keyCode for ITU-T key <code>3</code>.
     *
     * <P>Constant value <code>51</code> is set to <code>KEY_NUM3</code>.</P>
     */
    public static final int KEY_NUM3 = 51;
    
    /**
     * keyCode for ITU-T key <code>4</code>.
     *
     * <P>Constant value <code>52</code> is set to <code>KEY_NUM4</code>.</P>
     */
    public static final int KEY_NUM4 = 52;
    
    /**
     * keyCode for ITU-T key <code>5</code>.
     *
     * <P>Constant value <code>53</code> is set to <code>KEY_NUM5</code>.</P>
     */
    public static final int KEY_NUM5 = 53;
    
    /**
     * keyCode for ITU-T key <code>6</code>.
     *
     * <P>Constant value <code>54</code> is set to <code>KEY_NUM6</code>.</P>
     */
    public static final int KEY_NUM6 = 54;
    
    /**
     * keyCode for ITU-T key <code>7</code>.
     *
     * <P>Constant value <code>55</code> is set to <code>KEY_NUM7</code>.</P>
     */
    public static final int KEY_NUM7 = 55;
    
    /**
     * keyCode for ITU-T key <code>8</code>.
     *
     * <P>Constant value <code>56</code> is set to <code>KEY_NUM8</code>.</P>
     */
    public static final int KEY_NUM8 = 56;
    
    /**
     * keyCode for ITU-T key <code>9</code>.
     *
     * <P>Constant value <code>57</code> is set to <code>KEY_NUM09</code>.</P>
     */
    public static final int KEY_NUM9 = 57;
    
    /**
     * keyCode for ITU-T key "star" (<code>*</code>).
     *
     * <P>Constant value <code>42</code> is set to <code>KEY_STAR</code>.</P>
     */
    public static final int KEY_STAR = 42;
    
    /**
     * keyCode for ITU-T key "pound" (<code>#</code>).
     *
     * <P>Constant value <code>35</code> is set to <code>KEY_POUND</code>.</P>
     */
    public static final int KEY_POUND = 35;

    /**
     * Constructs a new <code>Canvas</code> object.
     */
    protected Canvas()  { }
    
    /**
     * Used by GameCanvas to suppress Game action key events
     */
    private boolean suppressKeyEvents; // = false

    /**
     * Checks if the <code>Canvas</code> is double buffered by the
     * implementation.
     * @return <code>true</code> if double buffered,
     * <code>false</code> otherwise
     */
    public boolean isDoubleBuffered() {
        // SYNC NOTE: return of atomic value, no locking necessary
        return Display.IS_DOUBLE_BUFFERED;
    }

    /**
     * Checks if the platform supports pointer press and release events.
     * @return <code>true</code> if the device supports pointer events
     */
    public boolean hasPointerEvents() {
        // SYNC NOTE: return of atomic value, no locking necessary
        return Display.POINTER_SUPPORTED;
    }
    
    /**
     * Checks if the platform supports pointer motion events (pointer dragged).
     * Applications may use this method to determine if the platform is capable
     * of supporting motion events.
     * @return <code>true</code> if the device supports pointer motion events
     */
    public boolean hasPointerMotionEvents() {
        // SYNC NOTE: return of atomic value, no locking necessary
        return Display.MOTION_SUPPORTED;
    }
    
    /**
     * Checks if the platform can generate repeat events when key
     * is kept down.
     * @return <code>true</code> if the device supports repeat events
     */
    public boolean hasRepeatEvents() { 
        // SYNC NOTE: return of atomic value, no locking necessary
        return Display.REPEAT_SUPPORTED;
    }
    
    /**
     * Gets a key code that corresponds to the specified game action on the
     * device.  The implementation is required to provide a mapping for every
     * game action, so this method will always return a valid key code for
     * every game action.  See <a href="#gameactions">above</a> for further
     * discussion of game actions.  There may be multiple keys associated
     * with the same game action; however, this method will return only one of
     * them.  Applications should translate the key code of every key event
     * into a game action using {@link #getGameAction} and then interpret the 
     * resulting game action, instead of generating a table of key codes at 
     * using this method during initialization.
     * 
     * <P>The mapping between key codes and game actions
     * will not change during the execution of the application.</P>
     *
     * @param gameAction the game action
     * @return a key code corresponding to this game action
     * @throws IllegalArgumentException if <code>gameAction</code> 
     * is not a valid game action
     */
    public int getKeyCode(int gameAction) {
        // SYNC NOTE: no locking necessary as we are doing a static
        // table lookup and getKeyCode() is implemented natively
        int n = Display.getKeyCode(gameAction);

        if (n == 0) {
            throw new IllegalArgumentException();
        }

        return n;
    }
    
    /**
     * Gets an informative key string for a key. The string returned will
     * resemble the text physically printed on the key.  This string is 
     * suitable for displaying to the user.  For example, on a device
     * with function keys <code>F1</code> through <code>F4</code>,
     * calling this method on the <code>keyCode</code> for
     * the <code>F1</code> key will return the string
     * "<code>F1</code>". A typical use for this string
     * will be to compose help text such as "Press
     * <code>F1</code> to proceed."
     *
     * <p> This method will return a non-empty string for every valid key code.
     * </p>
     *
     * <p> There is no direct mapping from game actions to key names. To get
     * the string name for a game action <code>GAME_A</code>, the
     * application must call </p>
     *
     * <TABLE BORDER="2">
     * <TR>
     * <TD ROWSPAN="1" COLSPAN="1">
     *    <pre><code>
     *    getKeyName(getKeyCode(GAME_A));    </code></pre>
     * </TD>
     * </TR>
     * </TABLE>
     * @param keyCode the key code being requested
     * @return a string name for the key
     * @throws IllegalArgumentException if <code>keyCode</code> 
     * is not a valid key code
     */
    public String getKeyName(int keyCode) {
        // SYNC NOTE: no locking necessary as we are doing a static
        // table lookup and getKeyName() is implemented natively
        String s = Display.getKeyName(keyCode);

        if (s == null) {
            throw new IllegalArgumentException();
        }

        return s;
    }

    /**
     * Gets the game action associated with the given key code of the
     * device.  Returns zero if no game action is associated with this key
     * code.  See <a href="#gameactions">above</a> for further discussion of
     * game actions. 
     *
     * <P>The mapping between key codes and game actions
     * will not change during the execution of the application.</P>
     * 
     * @param keyCode the key code
     * @return the game action corresponding to this key, or 
     * <code>0</code> if none
     * @throws IllegalArgumentException if <code>keyCode</code> 
     * is not a valid key code
     */
    public int getGameAction(int keyCode) {
        // SYNC NOTE: no locking necessary as we are doing a static
        // table lookup and getGameAction() is implemented natively
        int n = Display.getGameAction(keyCode);

        if (n == -1) {
            throw new IllegalArgumentException();
        }

        return n;
    }

    /**
     * Controls whether the <code>Canvas</code> is in full-screen mode
     * or in normal mode.
     *
     * @param mode <code>true</code> if the <code>Canvas</code>
     * is to be in full screen mode, <code>false</code> otherwise
     *
     * @since MIDP 2.0
     */
    public void setFullScreenMode(boolean mode) {

        if (mode == super.fullScreenMode) {
            return;
        }

        super.grabFullScreen(mode);

        synchronized (Display.LCDUILock) {
            super.fullScreenMode(mode);
        }
    }

    /**
     * Called when a key is pressed.
     *
     * <P>The <code>getGameAction()</code> method can be called to
     * determine what game action, if any, is mapped to the key.
     * Class <code>Canvas</code> has an empty implementation of this method, and
     * the subclass has to redefine it if it wants to listen this method.
     * @param keyCode the key code of the key that was pressed
     */
    protected void keyPressed(int keyCode) {
    }

    /**
     * Called when a key is repeated (held down). 
     *
     * <P>The <code>getGameAction()</code> method can
     * be called to determine what game action,
     * if any, is mapped to the key.
     * Class <code>Canvas</code> has an empty implementation of this method, and
     * the subclass has to redefine it if it wants to listen this method.
     * </P>
     * @param keyCode the key code of the key that was repeated
     * @see #hasRepeatEvents()
     */
    protected void keyRepeated(int keyCode) {
    }

    /**
     * Called when a key is released.
     * <P>
     * The <code>getGameAction()</code> method can be called to
     * determine what game action, if any, is mapped to the key.
     * Class <code>Canvas</code> has an empty implementation of this method, and
     * the subclass has to redefine it if it wants to listen this method.
     * </P>
     * @param keyCode the key code of the key that was released
     */
    protected void keyReleased(int keyCode) {
    }
    
    /**
     * Called when the pointer is pressed. 
     *
     * <P>
     * The {@link #hasPointerEvents() hasPointerEvents()}
     * method may be called to determine if the device supports pointer events.
     * Class <code>Canvas</code> has an empty implementation of this method, and
     * the subclass has to redefine it if it wants to listen this method.
     * </P>
     * @param x the horizontal location where the pointer was pressed (relative
     * to the <code>Canvas</code>)
     * @param y the vertical location where the pointer was pressed
     * (relative to the <code>Canvas</code>)
     */
    protected void pointerPressed(int x, int y) {
    }
    
    /**
     * Called when the pointer is released. 
     *
     * <P>
     * The {@link #hasPointerEvents() hasPointerEvents()}
     * method may be called to determine if the device supports pointer events.
     * Class <code>Canvas</code> has an empty implementation of this method, and
     * the subclass has to redefine it if it wants to listen this method.
     * </P>
     * @param x the horizontal location where the pointer was released
     * (relative to the <code>Canvas</code>)
     * @param y the vertical location where the pointer was released
     * (relative to the <code>Canvas</code>)
     */
    protected void pointerReleased(int x, int y) {
    }
    
    /**
     * Called when the pointer is dragged.
     *
     * <P>
     * The {@link #hasPointerMotionEvents() hasPointerMotionEvents()}
     * method may be called to determine if the device supports pointer events.
     * Class <code>Canvas</code> has an empty implementation of this method, and
     * the subclass has to redefine it if it wants to listen this method.
     * </P>
     * @param x the horizontal location where the pointer was dragged
     * (relative to the <code>Canvas</code>)
     * @param y the vertical location where the pointer was dragged
     * (relative to the <code>Canvas</code>)
     */
    protected void pointerDragged(int x, int y) {
    }
    
    /**
     * Requests a repaint for the specified region of the
     * <code>Canvas</code>. Calling
     * this method may result in subsequent call to
     * <code>paint()</code>, where the passed
     * <code>Graphics</code> object's clip region will include at
     * least the specified
     * region.
     *
     * <p> If the canvas is not visible, or if width and height are zero or 
     * less, or if the rectangle does not specify a visible region of 
     * the display, this call has no effect. </p>
     *
     * <p> The call to <code>paint()</code> occurs asynchronously of
     * the call to <code>repaint()</code>.
     * That is, <code>repaint()</code> will not block waiting for
     * <code>paint()</code> to finish. The
     * <code>paint()</code> method will either be called after the
     * caller of <code>repaint(</code>)
     * returns
     * to the implementation (if the caller is a callback) or on another thread
     * entirely. </p>
     *
     * <p> To synchronize with its <code>paint()</code> routine,
     * applications can use either
     * {@link Display#callSerially(Runnable) Display.callSerially()} or
     * {@link #serviceRepaints() serviceRepaints()}, or they can code explicit
     * synchronization into their <code>paint()</code> routine. </p>
     *
     * <p> The origin of the coordinate system is above and to the left of the
     * pixel in the upper left corner of the displayable area of the
     * <code>Canvas</code>.
     * The X-coordinate is positive right and the Y-coordinate is 
     * positive downwards.
     * </p>
     *
     * @param x the x coordinate of the rectangle to be repainted
     * @param y the y coordinate of the rectangle to be repainted
     * @param width the width of the rectangle to be repainted
     * @param height the height of the rectangle to be repainted
     *
     * @see Display#callSerially(Runnable)
     * @see #serviceRepaints()
     */
    public final void repaint(int x, int y, int width, int height) {
        synchronized (Display.LCDUILock) {
            callRepaint(x + viewport[X], y + viewport[Y], width, height, null);
        }
    }

    /**
     * Requests a repaint for the entire <code>Canvas</code>. The
     * effect is identical to
     * <p> <code> repaint(0, 0, getWidth(), getHeight()); </code>
     */
    public final void repaint() {
        synchronized (Display.LCDUILock) {
            callRepaint(viewport[X], viewport[Y], 
                        viewport[WIDTH], viewport[HEIGHT], null);
        }
    }
    
    /**
     * Forces any pending repaint requests to be serviced immediately. This
     * method blocks until the pending requests have been serviced. If 
     * there are
     * no pending repaints, or if this canvas is not visible on the display,
     * this call does nothing and returns immediately. 
     *
     * <p><strong>Warning:</strong> This method blocks until the call to the
     * application's <code>paint()</code> method returns. The
     * application has no
     * control over
     * which thread calls <code>paint()</code>; it may vary from
     * implementation to
     * implementation. If the caller of <code>serviceRepaints()</code>
     * holds a lock that the
     * <code>paint()</code> method acquires, this may result in
     * deadlock. Therefore, callers
     * of <code>serviceRepaints()</code> <em>must not</em> hold any
     * locks that might be
     * acquired within the <code>paint()</code> method. The
     * {@link Display#callSerially(Runnable) Display.callSerially()}
     * method provides a facility where an application can be called back after
     * painting has completed, avoiding the danger of deadlock.
     * </p>
     *
     * @see Display#callSerially(Runnable)
     */
    public final void serviceRepaints() {
        // SYNC NOTE: unlike most public API methods, no locking is done
        // here.  This is necessary because Display.serviceRepaints()
        // needs to handle its own locking.  We avoid locking by making
        // a copy of currentDisplay -- an atomic operation -- before
        // testing and using it.

        Display d = currentDisplay;

        if (d != null) {
            d.serviceRepaints(this);
        }
    }

    /**
     * The implementation calls <code>showNotify()</code>
     * immediately prior to this <code>Canvas</code> being made
     * visible on the display.
     * Canvas subclasses may override
     * this method to perform tasks before being shown, such
     * as setting up animations, starting timers, etc.
     * The default implementation of this method in class
     * <code>Canvas</code> is empty.
     */
    protected void showNotify() {
    }
    
    /**
     * The implementation calls <code>hideNotify()</code> shortly
     * after the <code>Canvas</code> has been
     * removed from the display.
     * <code>Canvas</code> subclasses may override this method in
     * order to pause
     * animations, 
     * revoke timers, etc.  The default implementation of this 
     * method in class <code>Canvas</code> is empty.
     */
    protected void hideNotify()  {
    }

    /**
     * Renders the <code>Canvas</code>. The application must implement
     * this method in
     * order to paint any graphics.
     *
     * <p>The <code>Graphics</code> object's clip region defines the
     * area of the screen
     * that is considered to be invalid. A correctly-written
     * <code>paint()</code> routine
     * must paint <em>every</em> pixel within this region. This is necessary
     * because the implementation is not required to clear the region prior to
     * calling <code>paint()</code> on it.  Thus, failing to paint
     * every pixel may result
     * in a portion of the previous screen image remaining visible. </p>
     *
     * <p>Applications <em>must not</em> assume that
     * they know the underlying source of the <code>paint()</code>
     * call and use this
     * assumption
     * to paint only a subset of the pixels within the clip region. The 
     * reason is
     * that this particular <code>paint()</code> call may have
     * resulted from multiple
     * <code>repaint()</code>
     * requests, some of which may have been generated from outside the
     * application. An application that paints only what it thinks is 
     * necessary to
     * be painted may display incorrectly if the screen contents had been
     * invalidated by, for example, an incoming telephone call. </p>
     *
     * <p>Operations on this graphics object after the <code>paint()
     * </code>call returns are
     * undefined. Thus, the application <em>must not</em> cache this
     * <code>Graphics</code>
     * object for later use or use by another thread. It must only be 
     * used within
     * the scope of this method. </p>
     *
     * <p>The implementation may postpone visible effects of
     * graphics operations until the end of the paint method.</p>
     *
     * <p> The contents of the <code>Canvas</code> are never saved if
     * it is hidden and then
     * is made visible again. Thus, shortly after
     * <code>showNotify()</code> is called,
     * <code>paint()</code> will always be called with a
     * <code>Graphics</code> object whose clip region
     * specifies the entire displayable area of the
     * <code>Canvas</code>.  Applications
     * <em>must not</em> rely on any contents being preserved from a previous
     * occasion when the <code>Canvas</code> was current. This call to
     * <code>paint()</code> will not
     * necessarily occur before any other key or pointer
     * methods are called on the <code>Canvas</code>.  Applications
     * whose repaint
     * recomputation is expensive may create an offscreen
     * <code>Image</code>, paint into it,
     * and then draw this image on the <code>Canvas</code> when
     * <code>paint()</code> is called. </p>
     *
     * <P>The application code must never call <code>paint()</code>;
     * it is called only by
     * the implementation.</P>
     *
     * <P>The <code>Graphics</code> object passed to the
     * <code>paint()</code> method has the following
     * properties:</P>
     * <UL>
     * <LI>the destination is the actual display, or if double buffering is in 
     * effect, a back buffer for the display;</LI>
     * <LI>the clip region includes at least one pixel
     * within this <code>Canvas</code>;</LI>
     * <LI>the current color is black;</LI>
     * <LI>the font is the same as the font returned by
     * {@link Font#getDefaultFont() Font.getDefaultFont()};</LI>
     * <LI>the stroke style is {@link Graphics#SOLID SOLID};</LI>
     * <LI>the origin of the coordinate system is located at the upper-left
     * corner of the <code>Canvas</code>; and</LI>
     * <LI>the <code>Canvas</code> is visible, that is, a call to
     * <code>isShown()</code> will return
     * <code>true</code>.</LI>
     * </UL>
     *
     * @param g the <code>Graphics</code> object to be used for
     * rendering the <code>Canvas</code>
     */
    protected abstract void paint(Graphics g);

    /**
     * Called when the drawable area of the <code>Canvas</code> has
     * been changed.  This
     * method has augmented semantics compared to {@link
     * Displayable#sizeChanged(int, int) Displayable.sizeChanged}.
     * 
     * <p>In addition to the causes listed in
     * <code>Displayable.sizeChanged</code>, a size change can occur on a
     * <code>Canvas</code> because of a change between normal and
     * full-screen modes.</p>
     *
     * <p>If the size of a <code>Canvas</code> changes while it is
     * actually visible on the
     * display, it may trigger an automatic repaint request.  If this occurs,
     * the call to <code>sizeChanged</code> will occur prior to the call to
     * <code>paint</code>.  If the <code>Canvas</code> has become smaller, the
     * implementation may choose not to trigger a repaint request if the
     * remaining contents of the <code>Canvas</code> have been
     * preserved.  Similarly, if
     * the <code>Canvas</code> has become larger, the implementation
     * may choose to trigger
     * a repaint only for the new region.  In both cases, the preserved
     * contents must remain stationary with respect to the origin of the
     * <code>Canvas</code>.  If the size change is significant to the
     * contents of the
     * <code>Canvas</code>, the application must explicitly issue a
     * repaint request for the
     * changed areas.  Note that the application's repaint request should not
     * cause multiple repaints, since it can be coalesced with repaint
     * requests that are already pending.</p>
     * 
     * <p>If the size of a <code>Canvas</code> changes while it is not
     * visible, the
     * implementation may choose to delay calls to <code>sizeChanged</code>
     * until immediately prior to the call to <code>showNotify</code>.  In
     * that case, there will be only one call to <code>sizeChanged</code>,
     * regardless of the number of size changes.</p>
     * 
     * <p>An application that is sensitive to size changes can update instance
     * variables in its implementation of <code>sizeChanged</code>.  These
     * updated values will be available to the code in the
     * <code>showNotify</code>, <code>hideNotify</code>, and
     * <code>paint</code> methods.</p>
     * 
     * @param w the new width in pixels of the drawable area of the
     * <code>Canvas</code>
     * @param h the new height in pixels of the drawable area of
     * the <code>Canvas</code>
     * @since MIDP 2.0
     */ 
    protected void sizeChanged(int w, int h) {
	// this method is intended to be overridden by the application
    }

    /**
     * Notify this Canvas it is being shown on the given Display
     *
     * @param d the Display the Canvas is being shown on
     */
    void callShowNotify(Display d) {
        super.callShowNotify(d);
        super.layout();

        synchronized (Display.calloutLock) {
            try {
                this.showNotify();
            } catch (Throwable t) {
                Display.handleThrowable(t);
            }
        }
    }

    /**
     * Notify this Canvas it is being hidden on the given Display
     *
     * @param d the Display the Canvas is being hidden on
     */
    void callHideNotify(Display d) {
        synchronized (Display.calloutLock) {
            try {
                this.hideNotify();
            } catch (Throwable t) {
                Display.handleThrowable(t);
            }
        }
    }

    /**
     * Paint this Canvas
     *
     * @param g the Graphics to paint to
     * @param target the target Object of this repaint
     */
    void callPaint(Graphics g, Object target) {
        super.callPaint(g, target);

        if (g.getClipY() + g.getClipHeight() <= viewport[Y]) {
            return;
        }

        // We prevent the Canvas from drawing outside of the
        // allowable viewport - such as over the command labels
        g.clipRect(viewport[X], viewport[Y],
                   viewport[WIDTH],
                   viewport[HEIGHT]);

        synchronized (Display.calloutLock) {
            g.translate(viewport[X], viewport[Y]);
            try {
                paint(g);
            } catch (Throwable t) {
                Display.handleThrowable(t);
            }
            g.translate(-viewport[X], -viewport[Y]);
        }
    }

    /**
     * Handle a size change notification.
     *
     * @param w the new width of this Canvas
     * @param h the new height of this Canvas
     */
    void callSizeChanged(int w, int h) {
        super.callSizeChanged(w, h);

        /*
         * sizeChangeOccurred is a boolean which (when true) indicates
         * that sizeChanged() will be called at a later time. So, if it
         * is false after calling super(), we go ahead and notify the
         * Canvas now, rather than later
         */

        if (!super.sizeChangeOccurred) {
            synchronized (Display.calloutLock) {
                try {
                    this.sizeChanged(w, h);
                } catch (Throwable t) {
                    Display.handleThrowable(t);
                }
            }
        }
    }

    /**
     * Handle a key press
     *
     * @param keyCode The key that was pressed
     */
    void callKeyPressed(int keyCode) {
        if (allowKey(keyCode)) {
            synchronized (Display.calloutLock) {
                try {
                    this.keyPressed(keyCode);
                } catch (Throwable t) {
                    Display.handleThrowable(t);
                }
            }
        }
    }

    /**
     * Handle a key release
     *
     * @param keyCode The key that was released
     */
    void callKeyReleased(int keyCode) {
        if (allowKey(keyCode)) {
            synchronized (Display.calloutLock) {
                try {
                    this.keyReleased(keyCode);
                } catch (Throwable t) {
                    Display.handleThrowable(t);
                }
            }
        }
    }

    /**
     * Handle a repeated key press
     *
     * @param keyCode The key that was pressed
     */
    void callKeyRepeated(int keyCode) {
        if (allowKey(keyCode)) {
            synchronized (Display.calloutLock) {
                try {
                    this.keyRepeated(keyCode);
                } catch (Throwable t) {
                    Display.handleThrowable(t);
                }
            }
        }
    }

    /**
     * Test to see if the given keyCode should be sent to
     * the application
     *
     * @param keyCode the key code to pass to the application
     * @return true if the key should be allowed
     */
    private boolean allowKey(int keyCode) {
        if (!suppressKeyEvents) {
            return true;
        }

        // NOTE: we're using Canvas's public getGameAction()
        // method here
        switch (getGameAction(keyCode)) {
            case Canvas.UP:
            case Canvas.DOWN:
            case Canvas.LEFT:
            case Canvas.RIGHT:
            case Canvas.FIRE:
            case Canvas.GAME_A:
            case Canvas.GAME_B:
            case Canvas.GAME_C:
            case Canvas.GAME_D :
                // don't generate key events for
                // the defined game keys
                return false;
            default:
                return true;
        }
    }

    /**
     * Handle a pointer press event
     *
     * @param x The x coordinate of the press
     * @param y The y coordinate of the press
     */
    void callPointerPressed(int x, int y) {
        synchronized (Display.calloutLock) {
            try {
                this.pointerPressed(x - viewport[X], y - viewport[Y]);
            } catch (Throwable t) {
                Display.handleThrowable(t);
            }
        }
    }

    /**
     * Handle a pointer release event
     *
     * @param x The x coordinate of the release
     * @param y The y coordinate of the release
     */
    void callPointerReleased(int x, int y) {
        synchronized (Display.calloutLock) {
            try {
                this.pointerReleased(x - viewport[X], y - viewport[Y]);
            } catch (Throwable t) {
                Display.handleThrowable(t);
            }
        }
    }

    /**
     * Handle a pointer drag event
     *
     * @param x The x coordinate of the drag
     * @param y The y coordinate of the drag
     */
    void callPointerDragged(int x, int y) {
        synchronized (Display.calloutLock) {
            try {
                this.pointerDragged(x - viewport[X], y - viewport[Y]);
            } catch (Throwable t) {
                Display.handleThrowable(t);
            }
        }
    }

}