javauis/lcdui_qt/src/javax/microedition/lcdui/Canvas.java
branchRCL_3
changeset 65 ae942d28ec0e
equal deleted inserted replaced
60:6c158198356e 65:ae942d28ec0e
       
     1 /*
       
     2 * Copyright (c) 2009, 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 package javax.microedition.lcdui;
       
    18 
       
    19 import java.util.Enumeration;
       
    20 import java.util.Vector;
       
    21 import java.util.Timer;
       
    22 import java.util.TimerTask;
       
    23 import javax.microedition.lcdui.game.GameCanvas;
       
    24 import javax.microedition.lcdui.EventDispatcher.LCDUIEvent;
       
    25 import org.eclipse.ercp.swt.mobile.MobileShell;
       
    26 import org.eclipse.swt.SWT;
       
    27 import org.eclipse.swt.events.*;
       
    28 import org.eclipse.swt.widgets.*;
       
    29 import org.eclipse.swt.widgets.Display;
       
    30 import org.eclipse.swt.graphics.*;
       
    31 import org.eclipse.swt.internal.qt.graphics.WindowSurface;
       
    32 import org.eclipse.swt.internal.extension.MobileShellExtension;
       
    33 import org.eclipse.swt.internal.qt.SymbianWindowVisibilityListener;
       
    34 
       
    35 
       
    36 /**
       
    37  * The abstract <code>Canvas</code> class is designed to handle low-level
       
    38  * graphical operations as well as low-level key and pointer events. Canvas is
       
    39  * derived from <code>Displayable</code> so the application can switch between
       
    40  * different <code>Canvases</code> together with other
       
    41  * <code>Displayables</code>.
       
    42  * <p>
       
    43  * <b>Canvas</b> the abstract method <code>paint(Graphics g)</code> designed
       
    44  * to be implemented by the developer.
       
    45  */
       
    46 public abstract class Canvas extends Displayable
       
    47 {
       
    48 
       
    49     /**
       
    50      *  Constant for <code>UP</code> game action.
       
    51      */
       
    52     public static final int UP = 1;
       
    53 
       
    54     /**
       
    55      * Constant for <code>DOWN</code> game action.
       
    56      */
       
    57     public static final int DOWN = 6;
       
    58 
       
    59     /**
       
    60      * Constant for <code>LEFT</code> game action.
       
    61      */
       
    62     public static final int LEFT = 2;
       
    63 
       
    64     /**
       
    65      * Constant for <code>RIGHT</code> game action.
       
    66      */
       
    67     public static final int RIGHT = 5;
       
    68 
       
    69     /**
       
    70      * Constant for <code>FIRE</code> game action.
       
    71      */
       
    72     public static final int FIRE = 8;
       
    73 
       
    74     /**
       
    75      * Constant for general "<code>A</code>" game action.
       
    76      */
       
    77     public static final int GAME_A = 9;
       
    78 
       
    79     /**
       
    80      * Constant for general "<code>B</code>" game action.
       
    81      */
       
    82     public static final int GAME_B = 10;
       
    83 
       
    84     /**
       
    85      * Constant for general "<code>C</code>" game action.
       
    86      */
       
    87     public static final int GAME_C = 11;
       
    88 
       
    89     /**
       
    90      * Constant for general "<code>D</code>" game action.
       
    91      */
       
    92     public static final int GAME_D = 12;
       
    93 
       
    94     /**
       
    95      * Key code for <code>0</code> key.
       
    96      */
       
    97     public static final int KEY_NUM0 = 48;
       
    98 
       
    99     /**
       
   100      * Key code for <code>1</code> key.
       
   101      */
       
   102     public static final int KEY_NUM1 = 49;
       
   103 
       
   104     /**
       
   105      * Key code for <code>2</code> key.
       
   106      */
       
   107     public static final int KEY_NUM2 = 50;
       
   108 
       
   109     /**
       
   110      * Key code for <code>3</code> key.
       
   111      */
       
   112     public static final int KEY_NUM3 = 51;
       
   113 
       
   114     /**
       
   115      * Key code for <code>4</code> key.
       
   116      */
       
   117     public static final int KEY_NUM4 = 52;
       
   118 
       
   119     /**
       
   120      * Key code for <code>5</code> key.
       
   121      */
       
   122     public static final int KEY_NUM5 = 53;
       
   123 
       
   124     /**
       
   125      * Key code for <code>6</code> key.
       
   126      */
       
   127     public static final int KEY_NUM6 = 54;
       
   128 
       
   129     /**
       
   130      * Key code for <code>7</code> key.
       
   131      */
       
   132     public static final int KEY_NUM7 = 55;
       
   133 
       
   134     /**
       
   135      * Key code for <code>8</code> key.
       
   136      */
       
   137     public static final int KEY_NUM8 = 56;
       
   138 
       
   139     /**
       
   140      * Key code for <code>9</code> key.
       
   141      */
       
   142     public static final int KEY_NUM9 = 57;
       
   143 
       
   144     /**
       
   145      * Key code for <code>*</code> key.
       
   146      */
       
   147     public static final int KEY_STAR = 42;
       
   148 
       
   149     /**
       
   150      * Key code for <code>#</code> key.
       
   151      */
       
   152     public static final int KEY_POUND = 35;
       
   153 
       
   154 
       
   155     private static final int GAME_CANVAS = 1;
       
   156     private static final int NO_BACKGROUND = 1 << 1;
       
   157     private static final int FULLSCREEN_MODE = 1 << 2;
       
   158 
       
   159     private static final int DISABLE_TAPDETECTION = 1 << 3;
       
   160     private static final int SUPPRESS_GAMEKEYS = 1 << 4;
       
   161     private static final int SUPPRESS_DRAGEVENT = 1 << 5;
       
   162     private static final int CLEANUP_NEEDED = 1 << 6;
       
   163     private static final int REPAINT_PENDING = 1 << 7;
       
   164     private static final int SELECTIONKEY_COMPATIBILITY = 1 << 8;
       
   165 
       
   166     private static final int CURRENTLY_VISIBLE = 1 << 9;
       
   167 
       
   168 
       
   169     // Listeners for various events.
       
   170     private org.eclipse.swt.events.PaintListener paintListener =
       
   171         new CanvasShellPaintListener();
       
   172 
       
   173     private CanvasShellMouseListener mouseListener =
       
   174         new CanvasShellMouseListener();
       
   175 
       
   176     private CanvasShellVisibilityListener shellVisibilityListener =
       
   177         new CanvasShellVisibilityListener();
       
   178 
       
   179     // Canvas Graphics object passed to paint(Graphics g)
       
   180     private Graphics canvasGraphics;
       
   181 
       
   182     // Graphics object for transferring return values
       
   183     // from UI thread
       
   184     private Graphics tempGraphics;
       
   185 
       
   186     // Graphics command buffer for this instance
       
   187     Buffer graphicsBuffer;
       
   188 
       
   189     //On Screen Keypad
       
   190     //private Composite keypadComposite;
       
   191     private CanvasKeypad onScreenkeypad;
       
   192     private static CanvasKeypad sharedKeypad;
       
   193 
       
   194     // Vector of flags that a certain key was pressed but was not released.
       
   195     // Used to implement keyRepeated since eSWT does not support
       
   196     // key repeat events.
       
   197     private Vector keysPressed;
       
   198     private int gameKeyState;
       
   199 
       
   200     private static int objectCount;
       
   201     private static Shell sharedShell;
       
   202     private Shell mShell;
       
   203     private Composite canvasComp;
       
   204     private Label tickerLabel;
       
   205 
       
   206     private int mode;
       
   207     private Object modeLock;
       
   208     private Object cleanupLock;
       
   209     private Object repaintLock;
       
   210     private Object flushLock;
       
   211 
       
   212     private Timer timer = new Timer();
       
   213     private CanvasTimerTask timerTask;
       
   214 
       
   215     private static final int DEFAULT_TIMEOUT = 500;
       
   216     private static final int DEFAULT_TWIPS = 200;
       
   217 
       
   218     private int pointerDownX;
       
   219     private int pointerDownY;
       
   220     private int twips;
       
   221     private int timeout;
       
   222 
       
   223     private int repaintX1;
       
   224     private int repaintY1;
       
   225     private int repaintX2;
       
   226     private int repaintY2;
       
   227 
       
   228 
       
   229     /**
       
   230      * Constructs <code>Canvas</code> object.
       
   231      */
       
   232     public Canvas()
       
   233     {
       
   234         super(null);
       
   235         synchronized(this)
       
   236         {
       
   237             objectCount++;
       
   238         }
       
   239 
       
   240         modeLock = new Object();
       
   241         repaintLock = new Object();
       
   242         cleanupLock = new Object();
       
   243         flushLock = new Object();
       
   244         setMode(GAME_CANVAS, this instanceof GameCanvas);
       
   245         construct();
       
   246         keysPressed = new Vector();
       
   247     }
       
   248 
       
   249     /**
       
   250      * Disposes this instance
       
   251      * Called when finalizer is destroying this instance.
       
   252      */
       
   253     void dispose()
       
   254     {
       
   255         ESWTUIThreadRunner.update(getClass().getName(), -1);
       
   256         ESWTUIThreadRunner.safeSyncExec(new Runnable()
       
   257         {
       
   258             public void run()
       
   259             {
       
   260                 if(graphicsBuffer != null)
       
   261                 {
       
   262                     graphicsBuffer.dispose();
       
   263                     graphicsBuffer = null;
       
   264                 }
       
   265 
       
   266                 synchronized(this)
       
   267                 {
       
   268                     objectCount--;
       
   269 
       
   270                     if((objectCount == 0) || isMode(GAME_CANVAS))
       
   271                     {
       
   272                         mShell.dispose();
       
   273                         sharedShell = null;
       
   274                         sharedKeypad = null;
       
   275                     }
       
   276                     else
       
   277                     {
       
   278                         Ticker ticker = getTicker();
       
   279                         if (ticker != null)
       
   280                         {
       
   281                             ticker.removeLabel(tickerLabel);
       
   282                         }
       
   283                         if(tickerLabel != null)
       
   284                         {
       
   285                             tickerLabel.dispose();
       
   286                         }
       
   287 
       
   288                         canvasComp.dispose();
       
   289                     }
       
   290                 }
       
   291             }
       
   292         });
       
   293     }
       
   294 
       
   295     /* (non-Javadoc)
       
   296      * @see Displayable#eswtConstructShell(int)
       
   297      */
       
   298     Shell eswtConstructShell(int style)
       
   299     {
       
   300         if(isMode(GAME_CANVAS))
       
   301         {
       
   302             mShell = super.eswtConstructShell(style);
       
   303         }
       
   304         else
       
   305         {
       
   306             if(sharedShell == null)
       
   307             {
       
   308                 sharedShell = super.eswtConstructShell(style);
       
   309             }
       
   310             mShell = sharedShell;
       
   311         }
       
   312 
       
   313         // Give the Shell the maximized size already before it becomes visible
       
   314         // so that it will return the correct size.
       
   315         mShell.setBounds(org.eclipse.swt.widgets.Display.getCurrent().getClientArea());
       
   316 
       
   317         // Make the Shell maximized. On Symbian it's automatically maximized
       
   318         // so this has no effect but on other platforms explicit maximizing
       
   319         // might be needed.
       
   320         mShell.setMaximized(true);
       
   321 
       
   322         return mShell;
       
   323     }
       
   324 
       
   325     /**
       
   326      * Sets ticker. If ticker is added already to other canvas(es),
       
   327      * it continues running from position where it was. Otherwise
       
   328      * it will start running from beginning when this method returns.
       
   329      *
       
   330      * @param newTicker New ticker. If null, current ticker is removed.
       
   331      */
       
   332     public void setTicker(Ticker newTicker)
       
   333     {
       
   334         super.setTicker(newTicker);
       
   335 
       
   336         ESWTUIThreadRunner.syncExec(new Runnable()
       
   337         {
       
   338             public void run()
       
   339             {
       
   340                 tickerLabel.setVisible(isMode(CURRENTLY_VISIBLE));
       
   341             }
       
   342         });
       
   343     }
       
   344 
       
   345     /**
       
   346      * Creates singleton Label instance used by Ticker.
       
   347      * Creates tickerLabel on shell and sets the visibility of the same.
       
   348      */
       
   349     Label getTickerLabel()
       
   350     {
       
   351         tickerLabel = super.getTickerLabel();
       
   352 
       
   353         if (!isMode(CURRENTLY_VISIBLE))
       
   354         {
       
   355             ESWTUIThreadRunner.syncExec(new Runnable()
       
   356             {
       
   357                 public void run()
       
   358                 {
       
   359                     tickerLabel.setVisible(false);
       
   360                 }
       
   361             });
       
   362         }
       
   363 
       
   364         return tickerLabel;
       
   365     }
       
   366 
       
   367     /* (non-Javadoc)
       
   368      * @see Displayable#eswtConstructContent(int)
       
   369      */
       
   370     Composite eswtConstructContent(int style)
       
   371     {
       
   372         // Get JAD attribute
       
   373         setMode(NO_BACKGROUND, !JadAttributeUtil.isValue(JadAttributeUtil.ATTRIB_NOKIA_UI_ENHANCEMENT,
       
   374                                                 JadAttributeUtil.VALUE_CANVAS_HAS_BACKGROUND));
       
   375         if(isMode(NO_BACKGROUND))
       
   376         {
       
   377             style |= SWT.NO_BACKGROUND;
       
   378         }
       
   379 
       
   380         // Get JAD attribute for S60 Selection Key Compatibility
       
   381         setMode(SELECTIONKEY_COMPATIBILITY, JadAttributeUtil.isValue(JadAttributeUtil.ATTRIB_NOKIA_MIDLET_S60_SELECTION_KEY_COMPATIBILITY,
       
   382                                     JadAttributeUtil.VALUE_TRUE));
       
   383 
       
   384         // Get JAD attribute for MIDlet Tap Detection
       
   385         String tapAttr = JadAttributeUtil.getValue(JadAttributeUtil.ATTRIB_NOKIA_MIDLET_TAP_DETECTION_OPTIONS);
       
   386         if(tapAttr != null)
       
   387         {
       
   388             if(tapAttr.indexOf(',') == -1)
       
   389             {
       
   390                 setDefaultTapValues();
       
   391             }
       
   392             else
       
   393             {
       
   394                 String twipString = tapAttr.substring(0, tapAttr.indexOf(',')).trim();
       
   395                 String timeoutString = tapAttr.substring(tapAttr.indexOf(',') + 1, tapAttr.length()).trim();
       
   396 
       
   397                 try
       
   398                 {
       
   399                     twips = Integer.parseInt(twipString);
       
   400                     timeout = Integer.parseInt(timeoutString);
       
   401 
       
   402                     // Check for Negative Values
       
   403                     if((twips < 0) && (timeout < 0))
       
   404                     {
       
   405                         setDefaultTapValues();
       
   406                     }
       
   407 
       
   408                     if((twips == 0)  && (timeout == 0))
       
   409                     {
       
   410                         setMode(DISABLE_TAPDETECTION, true);
       
   411                     }
       
   412 
       
   413                     // if any one of the value is zero, set defaults
       
   414                     if(!((twips != 0) && (timeout != 0)))
       
   415                     {
       
   416                         setDefaultTapValues();
       
   417                     }
       
   418                 }
       
   419                 catch(NumberFormatException e)
       
   420                 {
       
   421                     // Alpha Numeric Values of Timeouts and Timeout
       
   422                     setDefaultTapValues();
       
   423                 }
       
   424             }
       
   425         }
       
   426         else
       
   427         {
       
   428             setDefaultTapValues();
       
   429         }
       
   430 
       
   431         canvasComp = super.eswtConstructContent(style);
       
   432         canvasComp.setVisible(false);
       
   433 
       
   434         createOnScreenKeypad();
       
   435         return canvasComp;
       
   436     }
       
   437 
       
   438     void eswtInitGraphics() {
       
   439         // create graphics buffer
       
   440        graphicsBuffer = Buffer.createInstance(this, canvasComp);
       
   441     }
       
   442 
       
   443     /**
       
   444      * Creates OSK(OnScreenKeypad), shared Keypad will be created for Canvas,
       
   445      * seperate OSK will be created for each GameCanvas.
       
   446      */
       
   447     CanvasKeypad createOnScreenKeypad()
       
   448     {
       
   449         // Read the on screen keypad settings from the jad attribute
       
   450         String oskAttr = JadAttributeUtil
       
   451                          .getValue(JadAttributeUtil.ATTRIB_NOKIA_MIDLET_ON_SCREEN_KEYPAD);
       
   452         if(oskAttr != null
       
   453                 && (!oskAttr.equalsIgnoreCase(JadAttributeUtil.VALUE_NO))
       
   454                 && ((oskAttr
       
   455                      .equalsIgnoreCase(JadAttributeUtil.VALUE_GAMEACTIONS)) || (oskAttr
       
   456                              .equalsIgnoreCase(JadAttributeUtil.VALUE_NAVIGATIONKEYS))))
       
   457         {
       
   458             // On screen keypad is required, On devices without keyboard it can
       
   459             // be either navigation keys or navigation and game keys
       
   460 
       
   461             if(isMode(GAME_CANVAS))
       
   462             {
       
   463                 onScreenkeypad = new CanvasKeypad(this, oskAttr);
       
   464                 return onScreenkeypad;
       
   465             }
       
   466 
       
   467             if(sharedKeypad == null)
       
   468             {
       
   469                 sharedKeypad = new CanvasKeypad(this, oskAttr);
       
   470             }
       
   471             onScreenkeypad = sharedKeypad;
       
   472             return onScreenkeypad;
       
   473         }
       
   474 
       
   475         return null;
       
   476     }
       
   477 
       
   478     Rectangle eswtLayoutShellContent()
       
   479     {
       
   480         Rectangle shellArea = mShell.getClientArea();
       
   481         int oskHeight = (onScreenkeypad != null ? onScreenkeypad.getHeight() : 0);
       
   482         int tickerHeight = (tickerLabel != null ? tickerLabel.getBounds().height : 0);
       
   483 
       
   484         canvasComp.setBounds(0, tickerHeight,
       
   485                               shellArea.width, shellArea.height - tickerHeight - oskHeight);
       
   486 
       
   487         canvasComp.setFocus();
       
   488         return canvasComp.getClientArea();
       
   489     }
       
   490 
       
   491     /* (non-Javadoc)
       
   492      * @see Displayable#eswtHandleShowCurrentEvent()
       
   493      */
       
   494     void eswtHandleShowCurrentEvent()
       
   495     {
       
   496         setMode(CURRENTLY_VISIBLE, true);
       
   497         eswtSetTitle();
       
   498         ((MobileShell) mShell).setFullScreenMode(isMode(FULLSCREEN_MODE));
       
   499         if(onScreenkeypad != null)
       
   500         {
       
   501             if(!isMode(GAME_CANVAS))
       
   502             {
       
   503                 onScreenkeypad.setCurrentCanvas(this);
       
   504             }
       
   505             onScreenkeypad.setFullScreenMode(isMode(FULLSCREEN_MODE));
       
   506         }
       
   507         canvasComp.setVisible(true);
       
   508         if(tickerLabel != null)
       
   509         {
       
   510             tickerLabel.setVisible(!isMode(FULLSCREEN_MODE));
       
   511         }
       
   512         addCommands();
       
   513         super.eswtHandleShowCurrentEvent();
       
   514         getContentComp().addPaintListener(paintListener);
       
   515         getContentComp().addMouseListener(mouseListener);
       
   516         getContentComp().addMouseMoveListener(mouseListener);
       
   517         ((MobileShellExtension)getShell()).addSymbianWindowVisibilityListener(shellVisibilityListener);
       
   518     }
       
   519 
       
   520     /* (non-Javadoc)
       
   521      * @see Displayable#eswtHandleHideCurrentEvent()
       
   522      */
       
   523     void eswtHandleHideCurrentEvent()
       
   524     {
       
   525         setMode(CURRENTLY_VISIBLE, false);
       
   526         canvasComp.setVisible(false);
       
   527         if(tickerLabel != null)
       
   528         {
       
   529             tickerLabel.setVisible(false);
       
   530         }
       
   531         removeCommands();
       
   532         super.eswtHandleHideCurrentEvent();
       
   533         getContentComp().removePaintListener(paintListener);
       
   534         getContentComp().removeMouseListener(mouseListener);
       
   535         getContentComp().removeMouseMoveListener(mouseListener);
       
   536         ((MobileShellExtension)getShell()).removeSymbianWindowVisibilityListener(shellVisibilityListener);
       
   537     }
       
   538 
       
   539     /**
       
   540      * eSWT callback to add a Command.
       
   541      */
       
   542     void eswtAddCommand(Command cmd) {
       
   543         if (isMode(CURRENTLY_VISIBLE)) {
       
   544             cmd.eswtAddESWTCommand(mShell, false);
       
   545         }
       
   546         if (eswtIsShown()) {
       
   547             cmd.eswtAddCommandSelectionListener(mShell, getCommandListener());
       
   548         }
       
   549     }
       
   550 
       
   551     /**
       
   552      * Adds the commands to this Canvas.
       
   553      * Adds all the commands of displayable to the shell.
       
   554      */
       
   555     void addCommands()
       
   556     {
       
   557         Command cmd = null;
       
   558         for (Enumeration e = getCommands().elements(); e.hasMoreElements();)
       
   559         {
       
   560             cmd = (Command) e.nextElement();
       
   561             final Command finalCommand = cmd;
       
   562             finalCommand.eswtAddESWTCommand(mShell, false);
       
   563         }
       
   564     }
       
   565 
       
   566     /**
       
   567      * Removes the commands from this Canvas.
       
   568      * Removes all the commands of displayable from the shell.
       
   569      */
       
   570     void removeCommands()
       
   571     {
       
   572         Command cmd = null;
       
   573         for (Enumeration e = getCommands().elements(); e.hasMoreElements();)
       
   574         {
       
   575             cmd = (Command) e.nextElement();
       
   576             final Command finalCommand = cmd;
       
   577             finalCommand.eswtRemoveESWTCommand(mShell);
       
   578         }
       
   579     }
       
   580 
       
   581     /**
       
   582      * Issues the request to repaint the whole Canvas.
       
   583      */
       
   584     public void repaint()
       
   585     {
       
   586         repaint(0, 0, getWidth(), getHeight());
       
   587     }
       
   588 
       
   589     /**
       
   590      * Issues the request to repaint the specified area of the Canvas. The
       
   591      * request is processed asynchronously.
       
   592      *
       
   593      * @param x - left bound of the rectangle to redraw.
       
   594      * @param y - top bound of the rectangle to redraw.
       
   595      * @param width - width of the rectangle to redraw.
       
   596      * @param height - height of the rectangle to redraw.
       
   597      */
       
   598     public void repaint(int x, int y, int width, int height)
       
   599     {
       
   600         // Paint callback event is posted without any invalid area info.
       
   601         // Invalid area info is kept in the member variables. Only one event
       
   602         // per Canvas is added to the queue. If there are more repaint() calls
       
   603         // before the already posted event has been served those are merged
       
   604         // to the invalid area in the member variables without posting a new
       
   605         // event.
       
   606         synchronized(repaintLock)
       
   607         {
       
   608             if(invalidate(x, y, width, height))
       
   609             {
       
   610                 // Note that repaintPending doesn't mean that there's a repaint
       
   611                 // event in the queue. It means that the invalid area is going
       
   612                 // to be repainted and there's no need to add a new event.
       
   613                 // It's possible that the repaint event has already been
       
   614                 // removed from the queue but repaintPending is still true. In
       
   615                 // that case it's currently being processed and we can still
       
   616                 // add to the invalid area.
       
   617                 if(!isMode(REPAINT_PENDING))
       
   618                 {
       
   619                     EventDispatcher eventDispatcher = EventDispatcher.instance();
       
   620                     LCDUIEvent event = eventDispatcher.newEvent(
       
   621                                            LCDUIEvent.CANVAS_PAINT_MIDLET_REQUEST, this);
       
   622                     event.widget = getContentComp();
       
   623                     eventDispatcher.postEvent(event);
       
   624                     setMode(REPAINT_PENDING, true);
       
   625                 }
       
   626             }
       
   627         }
       
   628     }
       
   629 
       
   630     /**
       
   631      * Switches the Canvas between full screen and non-full screen modes.
       
   632      *
       
   633      * @param mode - true switches the Canvas to the full-screen mode.
       
   634      */
       
   635     public void setFullScreenMode(boolean aMode)
       
   636     {
       
   637         setMode(FULLSCREEN_MODE, aMode);
       
   638         ESWTUIThreadRunner.syncExec(new Runnable()
       
   639         {
       
   640             public void run()
       
   641             {
       
   642                 if(tickerLabel != null)
       
   643                 {
       
   644                     if(isMode(FULLSCREEN_MODE))
       
   645                     {
       
   646                         tickerLabel.setBounds(Integer.MIN_VALUE, 0, 0, 0);
       
   647                     }
       
   648                     else
       
   649                     {
       
   650                         tickerLabel.pack();
       
   651                         tickerLabel.setLocation(Integer.MIN_VALUE, 0);
       
   652                     }
       
   653 
       
   654                     if(isMode(CURRENTLY_VISIBLE))
       
   655                     {
       
   656                         tickerLabel.setVisible(!isMode(FULLSCREEN_MODE));
       
   657                     }
       
   658                 }
       
   659 
       
   660                 if(isMode(CURRENTLY_VISIBLE))
       
   661                 {
       
   662                     ((MobileShell)mShell).setFullScreenMode(isMode(FULLSCREEN_MODE));
       
   663                     //set the CanvasKeypad to the required mode
       
   664                     if(onScreenkeypad != null)
       
   665                     {
       
   666                         onScreenkeypad.setFullScreenMode(isMode(FULLSCREEN_MODE));
       
   667                     }
       
   668                 }
       
   669             }
       
   670         });
       
   671     }
       
   672 
       
   673     /**
       
   674      * Processes all the issued paint requests.
       
   675      */
       
   676     public final void serviceRepaints()
       
   677     {
       
   678         EventDispatcher.instance().serviceRepaints(this);
       
   679     }
       
   680 
       
   681     /**
       
   682      * Checks if the Canvas supports pointer dragging events.
       
   683      *
       
   684      * @return true if the Canvas supports pointer dragging, false otherwise.
       
   685      */
       
   686     public boolean hasPointerMotionEvents()
       
   687     {
       
   688         return true;
       
   689     }
       
   690 
       
   691     /**
       
   692      * Checks if the Canvas supports pointer events.
       
   693      *
       
   694      * @return true if the Canvas supports pointer events, false otherwise.
       
   695      */
       
   696     public boolean hasPointerEvents()
       
   697     {
       
   698         return true;
       
   699     }
       
   700 
       
   701     /**
       
   702      * Is the Canvas double buffered.
       
   703      *
       
   704      * @return true if the Canvas is double buffered, false otherwise.
       
   705      */
       
   706     public boolean isDoubleBuffered()
       
   707     {
       
   708         return true;
       
   709     }
       
   710 
       
   711     /**
       
   712      * Queries if the Canvas supports key repeat events.
       
   713      *
       
   714      * @return true if Canvas supports key repeat events, false otherwise.
       
   715      */
       
   716     public boolean hasRepeatEvents()
       
   717     {
       
   718         return true;
       
   719     }
       
   720 
       
   721     /**
       
   722      * Returns game action for a specified key code.
       
   723      *
       
   724      * @param keyCode Key code to map to game action.
       
   725      * @return Game action for a a specified key code or
       
   726      *         IllegalArgumentException.
       
   727      */
       
   728     public int getGameAction(int keyCode)
       
   729     {
       
   730         return KeyTable.getGameAction(keyCode);
       
   731     }
       
   732 
       
   733     /**
       
   734      * Returns the key code specific for a certain game action.
       
   735      *
       
   736      * @param gameAction - game action to be mapped to the key code.
       
   737      * @return Key code that is mapped to the specified game action.
       
   738      */
       
   739     public int getKeyCode(int gameAction)
       
   740     {
       
   741         return KeyTable.getKeyCode(gameAction);
       
   742     }
       
   743 
       
   744     /**
       
   745      * Returns the key name specific for a certain key code.
       
   746      *
       
   747      * @param keyCode - key name to get the name of.
       
   748      * @return String that contains textual name of the key specified by the key
       
   749      *         code.
       
   750      */
       
   751     public String getKeyName(int keyCode)
       
   752     {
       
   753         return KeyTable.getKeyName(keyCode);
       
   754     }
       
   755 
       
   756     /**
       
   757      * Callback to be implemented by the application to render the
       
   758      * <code>Canvas</code>. The clip region of <code>Graphics</code> object
       
   759      * specifies the area that needs to be updated. All the region has to be
       
   760      * updated in <code>paint()</code> method.
       
   761      * <p>
       
   762      * Application should not take into account the source where the
       
   763      * <code>paint()</code> request came from.
       
   764      * <p>
       
   765      * Any interaction with Graphics object outside of <code>paint()</code>
       
   766      * method is undefined.
       
   767      * <p>
       
   768      * The application should never call <code>paint()</code> explicitly, it is
       
   769      * called by the framework.
       
   770      *
       
   771      * @param g - the <code>Graphics</code> object to be used for graphical
       
   772      *            operations on the <code>Canvas.</code>
       
   773      */
       
   774     protected abstract void paint(Graphics g);
       
   775 
       
   776     /**
       
   777      * Callback to signal a key press.
       
   778      *
       
   779      * @param keyCode - key code of the key pressed.
       
   780      */
       
   781     protected void keyPressed(int keyCode)
       
   782     {
       
   783     }
       
   784 
       
   785     /**
       
   786      * Callback to signal a key release.
       
   787      *
       
   788      * @param keyCode - key code of the key released.
       
   789      */
       
   790     protected void keyReleased(int keyCode)
       
   791     {
       
   792     }
       
   793 
       
   794     /**
       
   795      * Callback to signal a key repeat. Happens when the key is pressed down for
       
   796      * a long time.
       
   797      *
       
   798      * @param keyCode - key code of the key repeated.
       
   799      */
       
   800     protected void keyRepeated(int keyCode)
       
   801     {
       
   802     }
       
   803 
       
   804     /**
       
   805      * Callback to signal pointer press event.
       
   806      *
       
   807      * @param x - X-coordinate of the tap point.
       
   808      * @param y - Y-coordinate of the tap point.
       
   809      */
       
   810     protected void pointerPressed(int x, int y)
       
   811     {
       
   812     }
       
   813 
       
   814     /**
       
   815      * Callback to signal pointer release event.
       
   816      *
       
   817      * @param x - X-coordinate of the pointer release point.
       
   818      * @param y - Y-coordinate of the pointer release point.
       
   819      */
       
   820     protected void pointerReleased(int x, int y)
       
   821     {
       
   822     }
       
   823 
       
   824     /**
       
   825      * Callback to signal pointer drag event.
       
   826      *
       
   827      * @param x - X-coordinate of the pointer drag point.
       
   828      * @param y - Y-coordinate of the pointer drag point.
       
   829      */
       
   830     protected void pointerDragged(int x, int y)
       
   831     {
       
   832     }
       
   833 
       
   834     /**
       
   835      * Callback similar to the one in <code>Displayable</code>. Additional
       
   836      * case for <code>sizeChanged</code> to be called in <code>Canvas</code>
       
   837      * is switching between full-screen mode by calling
       
   838      * <code>setFullScreenMode()</code>.
       
   839      */
       
   840     protected void sizeChanged(int w, int h)
       
   841     {
       
   842     }
       
   843 
       
   844     /**
       
   845      * showNotify() is the callback called before the Canvas is shown on the
       
   846      * screen.
       
   847      */
       
   848     protected void showNotify()
       
   849     {
       
   850     }
       
   851 
       
   852     /**
       
   853      * hideNotify() is the callback called after the Canvas is removed from the
       
   854      * screen.
       
   855      */
       
   856     protected void hideNotify()
       
   857     {
       
   858     }
       
   859 
       
   860     /**
       
   861      * Init GameCanvas frame buffer.
       
   862      *
       
   863      * @param supressKeys suppress game keys
       
   864      * @return frame buffer
       
   865      */
       
   866     final void initGameCanvas(boolean suppressKeys)
       
   867     {
       
   868         setMode(SUPPRESS_GAMEKEYS, suppressKeys);
       
   869     }
       
   870 
       
   871     /**
       
   872      * Gets composite that contains Canvas content.
       
   873      *
       
   874      * @return Composite.
       
   875      */
       
   876     Composite getContentComp()
       
   877     {
       
   878         return canvasComp;
       
   879     }
       
   880 
       
   881     /**
       
   882      * Get game canvas frame buffer graphics.
       
   883      */
       
   884     final Graphics getGameBufferGraphics()
       
   885     {
       
   886         tempGraphics = null;
       
   887         ESWTUIThreadRunner.safeSyncExec(new Runnable()
       
   888         {
       
   889             public void run()
       
   890             {
       
   891                 tempGraphics =  graphicsBuffer.getGraphics();
       
   892             }
       
   893         });
       
   894         return tempGraphics;
       
   895     }
       
   896 
       
   897     CanvasKeypad getCanvasKeypad()
       
   898     {
       
   899         return onScreenkeypad;
       
   900     }
       
   901 
       
   902     boolean IsFullScreenMode()
       
   903     {
       
   904         return isMode(FULLSCREEN_MODE);
       
   905     }
       
   906 
       
   907     /**
       
   908      * Return game key states for GameCanvas.
       
   909      *
       
   910      * @return game key states.
       
   911      */
       
   912     final int getGameKeyStates()
       
   913     {
       
   914         int ret = gameKeyState;
       
   915         gameKeyState = 0;
       
   916         return ret;
       
   917     }
       
   918 
       
   919     void renderGraphics(final Graphics g)
       
   920     {
       
   921         // Implementation missing. GameCanvas.paint() should by default render
       
   922         // the the off-screen buffer at (0,0). Rendering of the buffer must be
       
   923         // subject to the clip region and origin translation of the Graphics
       
   924         // object.
       
   925     }
       
   926 
       
   927     /**
       
   928      * Flushes the frameBuffer to the display.
       
   929      *
       
   930      * @param x
       
   931      * @param y
       
   932      * @param width
       
   933      * @param height
       
   934      */
       
   935     void flushGameBuffer(final int x, final int y, final int width,
       
   936                          final int height)
       
   937     {
       
   938         // This is serialized with the
       
   939         // paint callback processing
       
   940         synchronized(flushLock)
       
   941         {
       
   942             synchronized(graphicsBuffer)
       
   943             {
       
   944                  ESWTUIThreadRunner.safeSyncExec(new Runnable()
       
   945                 {
       
   946                     public void run()
       
   947                     {
       
   948                         graphicsBuffer.sync();
       
   949                         graphicsBuffer.blitToDisplay(null, getContentComp());
       
   950                     }
       
   951                 });
       
   952             }
       
   953         }
       
   954     }
       
   955 
       
   956     /**
       
   957      * Called by ShellListener when shell gets activated.
       
   958      */
       
   959     void handleShellActivatedEvent()
       
   960     {
       
   961         super.handleShellActivatedEvent();
       
   962 
       
   963         // reset the game key state
       
   964         gameKeyState = 0;
       
   965 
       
   966         synchronized(cleanupLock)
       
   967         {
       
   968             setMode(CLEANUP_NEEDED, true);
       
   969         }
       
   970 
       
   971         LCDUIEvent event = EventDispatcher.instance().newEvent(LCDUIEvent.CANVAS_SHOWNOTIFY, this);
       
   972         EventDispatcher.instance().postEvent(event);
       
   973     }
       
   974 
       
   975     /**
       
   976      * Called by ShellListener when shell gets de-activated.
       
   977      */
       
   978     void handleShellDeActivatedEvent()
       
   979     {
       
   980         super.handleShellDeActivatedEvent();
       
   981         LCDUIEvent event = EventDispatcher.instance().newEvent(LCDUIEvent.CANVAS_HIDENOTIFY, this);
       
   982         EventDispatcher.instance().postEvent(event);
       
   983     }
       
   984 
       
   985     /*
       
   986      * UI thread calls
       
   987      */
       
   988     void eswtHandleResizeEvent(int width, int height)
       
   989     {
       
   990         super.eswtHandleResizeEvent(width, height);
       
   991         // update new bounds to graphicsBuffer
       
   992         // this call must not be synchronized as we
       
   993         // cannot use locking in UI thread
       
   994         graphicsBuffer.setControlBounds(getContentComp());
       
   995         synchronized(cleanupLock)
       
   996         {
       
   997             setMode(CLEANUP_NEEDED, true);
       
   998         }
       
   999     }
       
  1000 
       
  1001     /*
       
  1002      * UI thread calls
       
  1003      */
       
  1004     void eswtHandleEvent(Event e)
       
  1005     {
       
  1006         super.eswtHandleEvent(e);
       
  1007         if(e.type == SWT.KeyDown)
       
  1008         {
       
  1009             doKeyPressed(e.keyCode);
       
  1010         }
       
  1011         else if(e.type == SWT.KeyUp)
       
  1012         {
       
  1013             doKeyReleased(e.keyCode);
       
  1014         }
       
  1015     }
       
  1016 
       
  1017     private void setMode(final int aMode, boolean value)
       
  1018     {
       
  1019         synchronized(modeLock)
       
  1020         {
       
  1021             if(value)
       
  1022             {
       
  1023                 mode |= aMode;
       
  1024             }
       
  1025             else
       
  1026             {
       
  1027                 mode &= ~aMode;
       
  1028             }
       
  1029         }
       
  1030     }
       
  1031 
       
  1032     private boolean isMode(final int aMode)
       
  1033     {
       
  1034         return ((mode & aMode) != 0);
       
  1035     }
       
  1036 
       
  1037     /*
       
  1038      * UI thread calls. Paint listener of the eSWT widget.
       
  1039      */
       
  1040     class CanvasShellPaintListener implements PaintListener
       
  1041     {
       
  1042         public void paintControl(PaintEvent pe)
       
  1043         {
       
  1044             // Check if we got here from buffer flush
       
  1045             if(graphicsBuffer.isPaintingActive())
       
  1046             {
       
  1047                 graphicsBuffer.blitToDisplay(pe.gc.getGCData().internalGc, null);
       
  1048             }
       
  1049             else
       
  1050             {
       
  1051                 // Native toolkit is requesting an update of an area that has
       
  1052                 // become invalid. Can't do anything here because the contents
       
  1053                 // need to be queried from the MIDlet in another thread by
       
  1054                 // a paint callback. For this a paint callback event is posted.
       
  1055                 // For a moment the native toolkit thinks that the area has
       
  1056                 // been validated when in truth it will be painted later after
       
  1057                 // the paint callback has been executed.
       
  1058                 EventDispatcher eventDispatcher = EventDispatcher.instance();
       
  1059                 LCDUIEvent event = eventDispatcher.newEvent(
       
  1060                                        LCDUIEvent.CANVAS_PAINT_NATIVE_REQUEST,
       
  1061                                        javax.microedition.lcdui.Canvas.this);
       
  1062                 event.x = pe.x;
       
  1063                 event.y = pe.y;
       
  1064                 event.width = pe.width;
       
  1065                 event.height = pe.height;
       
  1066                 event.widget = pe.widget;
       
  1067                 eventDispatcher.postEvent(event);
       
  1068             }
       
  1069         }
       
  1070     }
       
  1071 
       
  1072     /*
       
  1073      * Dispatcher thread or the serviceRepaints()-thread calls.
       
  1074      */
       
  1075     final void doCallback(LCDUIEvent event)
       
  1076     {
       
  1077         switch(event.type)
       
  1078         {
       
  1079         case LCDUIEvent.CANVAS_PAINT_MIDLET_REQUEST: // fall through
       
  1080         case LCDUIEvent.CANVAS_PAINT_NATIVE_REQUEST:
       
  1081             doPaintCallback(event);
       
  1082             break;
       
  1083         case LCDUIEvent.CANVAS_HIDENOTIFY:
       
  1084             hideNotify();
       
  1085             break;
       
  1086         case LCDUIEvent.CANVAS_KEYPRESSED:
       
  1087             keyPressed(event.keyCode);
       
  1088             break;
       
  1089         case LCDUIEvent.CANVAS_KEYREPEATED:
       
  1090             keyRepeated(event.keyCode);
       
  1091             break;
       
  1092         case LCDUIEvent.CANVAS_KEYRELEASED:
       
  1093             keyReleased(event.keyCode);
       
  1094             break;
       
  1095         case LCDUIEvent.CANVAS_POINTERDRAGGED:
       
  1096             pointerDragged(event.x, event.y);
       
  1097             break;
       
  1098         case LCDUIEvent.CANVAS_POINTERPRESSED:
       
  1099             pointerPressed(event.x, event.y);
       
  1100             break;
       
  1101         case LCDUIEvent.CANVAS_POINTERRELEASED:
       
  1102             pointerReleased(event.x, event.y);
       
  1103             break;
       
  1104         case LCDUIEvent.CANVAS_SHOWNOTIFY:
       
  1105             showNotify();
       
  1106             break;
       
  1107         default:
       
  1108             super.doCallback(event);
       
  1109             break;
       
  1110         }
       
  1111     }
       
  1112 
       
  1113     /*
       
  1114      * Dispatcher thread or the serviceRepaints()-thread calls.
       
  1115      */
       
  1116     private final void doPaintCallback(final LCDUIEvent event)
       
  1117     {
       
  1118         synchronized(flushLock)
       
  1119         {
       
  1120             // It's possible that this Canvas is sent to background
       
  1121             // right after the visibility is checked here, however
       
  1122             // it is okay as in such case we just do one extra paint
       
  1123             // callback. The visibility change cannot be synchronized with
       
  1124             // this method, since it would expose implementation to deadlock
       
  1125             if(!isMode(CURRENTLY_VISIBLE))
       
  1126             {
       
  1127                 return;
       
  1128             }
       
  1129 
       
  1130             // Decide the area going to be painted by the callback.
       
  1131             final int redrawNowX;
       
  1132             final int redrawNowY;
       
  1133             final int redrawNowW;
       
  1134             final int redrawNowH;
       
  1135             // Before this thread obtains the repaintLock any repaint() calls
       
  1136             // will still be adding to the invalid area that is going to be
       
  1137             // painted by this callback.
       
  1138             synchronized(repaintLock)
       
  1139             {
       
  1140                 if(event.type == LCDUIEvent.CANVAS_PAINT_NATIVE_REQUEST)
       
  1141                 {
       
  1142                     // Merge with possibly existing repaint() requests
       
  1143                     invalidate(event.x, event.y, event.width, event.height);
       
  1144                 }
       
  1145                 else
       
  1146                 {
       
  1147                     // Need to add a new event to the queue in subsequent repaint()
       
  1148                     // calls.
       
  1149                     setMode(REPAINT_PENDING, false);
       
  1150                 }
       
  1151 
       
  1152                 // Store the current area to be painted
       
  1153                 redrawNowX = repaintX1;
       
  1154                 redrawNowY = repaintY1;
       
  1155                 redrawNowW = repaintX2-repaintX1;
       
  1156                 redrawNowH = repaintY2-repaintY1;
       
  1157 
       
  1158                 // After releasing the lock the repaint() calls will start with
       
  1159                 // new invalid area.
       
  1160                 repaintX1 = repaintX2 = repaintY1 = repaintY2 = 0;
       
  1161 
       
  1162                 // Don't do the callback if there's nothing to paint
       
  1163                 if(!((redrawNowW > 0) && (redrawNowH > 0)))
       
  1164                 {
       
  1165                     return;
       
  1166                 }
       
  1167             }
       
  1168 
       
  1169             // Create instance of Graphics if not created yet
       
  1170             if(canvasGraphics == null)
       
  1171             {
       
  1172                 canvasGraphics = graphicsBuffer.getGraphics();
       
  1173                 canvasGraphics.setSyncStrategy(Graphics.SYNC_LEAVE_SURFACE_SESSION_OPEN);
       
  1174             }
       
  1175 
       
  1176             // Clean the background if dirty, buffer the operations.
       
  1177             synchronized(cleanupLock)
       
  1178             {
       
  1179                 if(isMode(CLEANUP_NEEDED) && isMode(NO_BACKGROUND))
       
  1180                 {
       
  1181                     // UI thread can change the contentArea object reference at
       
  1182                     // any time. Store the object reference locally to ensure it
       
  1183                     // points to the same rectangle all the time.
       
  1184                     Rectangle contentArea = getContentArea();
       
  1185 
       
  1186                     canvasGraphics.setClip(contentArea.x, contentArea.y,
       
  1187                                            contentArea.width, contentArea.height);
       
  1188                     canvasGraphics.cleanBackground(contentArea);
       
  1189                     setMode(CLEANUP_NEEDED, false);
       
  1190                 }
       
  1191             }
       
  1192 
       
  1193             // Clip must define the invalid area
       
  1194             canvasGraphics.reset();
       
  1195             canvasGraphics.setClip(redrawNowX, redrawNowY, redrawNowW, redrawNowH);
       
  1196 
       
  1197             // The callback
       
  1198             paint(canvasGraphics);
       
  1199 
       
  1200             // Blit frame to display
       
  1201             synchronized(graphicsBuffer)
       
  1202             {
       
  1203                 ESWTUIThreadRunner.safeSyncExec(new Runnable()
       
  1204                 {
       
  1205                      public void run()
       
  1206                     {
       
  1207                         if(event.widget.isDisposed())
       
  1208                         {
       
  1209                             return;
       
  1210                         }
       
  1211                         graphicsBuffer.sync();
       
  1212                         graphicsBuffer.blitToDisplay(null, event.widget);
       
  1213                     }
       
  1214                 });
       
  1215             }
       
  1216         }
       
  1217     }
       
  1218 
       
  1219     /*
       
  1220      * UI thread calls to flush the command buffer of a graphics context.
       
  1221      */
       
  1222     private final void doBufferFlush(PaintEvent event, Graphics graphics)
       
  1223     {
       
  1224         //  event.gc.getGCData().internalGc.render(graphics.getCommandBuffer());
       
  1225     }
       
  1226 
       
  1227     /*
       
  1228      * UI thread calls.
       
  1229      */
       
  1230     void doKeyPressed(int keyCode)
       
  1231     {
       
  1232         Logger.method(this, "doKeyPressed", String.valueOf(keyCode));
       
  1233         boolean sendCallback = false;
       
  1234 
       
  1235         if(!(updateGameKeyState(keyCode, true) && isMode(SUPPRESS_GAMEKEYS)))
       
  1236         {
       
  1237             if(isMode(SELECTIONKEY_COMPATIBILITY) && (keyCode == -5))
       
  1238             {
       
  1239                 if(isMode(FULLSCREEN_MODE))
       
  1240                 {
       
  1241                     if(!((getNumCommands() > 0) && hasCommandListener()))
       
  1242                     {
       
  1243                         sendCallback = true;
       
  1244                     }
       
  1245                     else
       
  1246                     {
       
  1247                         sendCallback = false;
       
  1248                     }
       
  1249                 }
       
  1250                 else
       
  1251                 {
       
  1252                     sendCallback = true;
       
  1253                 }
       
  1254             }
       
  1255             else if((!isMode(SELECTIONKEY_COMPATIBILITY)) && (keyCode == -5))
       
  1256             {
       
  1257                 sendCallback = false;
       
  1258             }
       
  1259             else
       
  1260             {
       
  1261                 sendCallback = true;
       
  1262             }
       
  1263         }
       
  1264         else
       
  1265         {
       
  1266             sendCallback = false;
       
  1267         }
       
  1268 
       
  1269         if(sendCallback == true)
       
  1270         {
       
  1271             LCDUIEvent event;
       
  1272 
       
  1273             if(keysPressed.contains(new Integer(keyCode)))
       
  1274             {
       
  1275                 event = EventDispatcher.instance().newEvent(LCDUIEvent.CANVAS_KEYREPEATED, this);
       
  1276             }
       
  1277             else
       
  1278             {
       
  1279                 event = EventDispatcher.instance().newEvent(LCDUIEvent.CANVAS_KEYPRESSED, this);
       
  1280             }
       
  1281             event.keyCode = keyCode;
       
  1282             EventDispatcher.instance().postEvent(event);
       
  1283 
       
  1284         }
       
  1285     }
       
  1286 
       
  1287     /*
       
  1288      * UI thread calls.
       
  1289      */
       
  1290     void doKeyReleased(int keyCode)
       
  1291     {
       
  1292         Logger.method(this, "doKeyReleased", String.valueOf(keyCode));
       
  1293         boolean sendCallback = false;
       
  1294         if(!(updateGameKeyState(keyCode, true) && isMode(SUPPRESS_GAMEKEYS)))
       
  1295         {
       
  1296             if(isMode(SELECTIONKEY_COMPATIBILITY) && (keyCode == -5))
       
  1297             {
       
  1298                 if(isMode(FULLSCREEN_MODE))
       
  1299                 {
       
  1300                     if(!((getNumCommands() > 0) && hasCommandListener()))
       
  1301                     {
       
  1302                         sendCallback = true;
       
  1303                     }
       
  1304                     else
       
  1305                     {
       
  1306                         sendCallback = false;
       
  1307                     }
       
  1308                 }
       
  1309                 else
       
  1310                 {
       
  1311                     sendCallback = true;
       
  1312                 }
       
  1313             }
       
  1314             else if((!isMode(SELECTIONKEY_COMPATIBILITY)) && (keyCode == -5))
       
  1315             {
       
  1316                 sendCallback = false;
       
  1317             }
       
  1318             else
       
  1319             {
       
  1320                 sendCallback = true;
       
  1321             }
       
  1322         }
       
  1323         else
       
  1324         {
       
  1325             sendCallback = false;
       
  1326         }
       
  1327 
       
  1328         if(sendCallback == true)
       
  1329         {
       
  1330 
       
  1331             LCDUIEvent event = EventDispatcher.instance().newEvent(LCDUIEvent.CANVAS_KEYRELEASED, this);
       
  1332             event.keyCode = keyCode;
       
  1333             EventDispatcher.instance().postEvent(event);
       
  1334 
       
  1335         }
       
  1336     }
       
  1337 
       
  1338     /**
       
  1339      * Updates game key states and returns if the key was a game key.
       
  1340      */
       
  1341     private boolean updateGameKeyState(int keyCode, boolean addKeyState)
       
  1342     {
       
  1343         // Ignore key repeat events
       
  1344         if(ESWTUIThreadRunner.getKeyRepeatCount() > 1)
       
  1345         {
       
  1346             return true;
       
  1347         }
       
  1348         try
       
  1349         {
       
  1350             int gameAction = KeyTable.getGameAction(keyCode);
       
  1351             if(addKeyState)
       
  1352             {
       
  1353                 // set bitfield
       
  1354                 gameKeyState |= (1 << gameAction);
       
  1355             }
       
  1356             return true;
       
  1357         }
       
  1358         catch(IllegalArgumentException iae)
       
  1359         {
       
  1360             return false;
       
  1361         }
       
  1362     }
       
  1363 
       
  1364     private void setDefaultTapValues()
       
  1365     {
       
  1366         twips = DEFAULT_TWIPS;
       
  1367         timeout = DEFAULT_TIMEOUT;
       
  1368     }
       
  1369 
       
  1370     class CanvasShellMouseListener implements
       
  1371         org.eclipse.swt.events.MouseListener,
       
  1372         org.eclipse.swt.events.MouseMoveListener
       
  1373     {
       
  1374 
       
  1375         public void mouseDoubleClick(MouseEvent arg0)
       
  1376         {
       
  1377         }
       
  1378 
       
  1379         public void mouseDown(MouseEvent event)
       
  1380         {
       
  1381             LCDUIEvent e = EventDispatcher.instance().newEvent(LCDUIEvent.CANVAS_POINTERPRESSED,
       
  1382                            javax.microedition.lcdui.Canvas.this);
       
  1383             e.x = event.x;
       
  1384             e.y = event.y;
       
  1385             EventDispatcher.instance().postEvent(e);
       
  1386 
       
  1387             if(!isMode(DISABLE_TAPDETECTION))
       
  1388             {
       
  1389                 // Supress Drag events
       
  1390                 setMode(SUPPRESS_DRAGEVENT, true);
       
  1391 
       
  1392                 pointerDownX = event.x;
       
  1393                 pointerDownY = event.y;
       
  1394 
       
  1395                 // Create and Schedule Timer
       
  1396                 timerTask = new CanvasTimerTask();
       
  1397                 timer.schedule(timerTask, timeout);
       
  1398             }
       
  1399         }
       
  1400 
       
  1401         public void mouseUp(MouseEvent event)
       
  1402         {
       
  1403             int pointerUpX = event.x;
       
  1404             int pointerUpY = event.y;
       
  1405 
       
  1406             if(!isMode(DISABLE_TAPDETECTION))
       
  1407             {
       
  1408                 if(timerTask != null)
       
  1409                 {
       
  1410                     timerTask.cancel();
       
  1411                     timerTask = null;
       
  1412                 }
       
  1413 
       
  1414                 // If Timer not expired and Mouseup is withing rectangle assign
       
  1415                 // PointercDown to Pinter Up
       
  1416                 if(isMode(SUPPRESS_DRAGEVENT) && checkWithinRect(event.x, event.y))
       
  1417                 {
       
  1418                     pointerUpX = pointerDownX;
       
  1419                     pointerUpY = pointerDownY;
       
  1420                     setMode(SUPPRESS_DRAGEVENT, false);
       
  1421                 }
       
  1422             }
       
  1423 
       
  1424             LCDUIEvent e = EventDispatcher.instance().newEvent(LCDUIEvent.CANVAS_POINTERRELEASED,
       
  1425                            javax.microedition.lcdui.Canvas.this);
       
  1426             e.x = pointerUpX;
       
  1427             e.y = pointerUpY;
       
  1428             EventDispatcher.instance().postEvent(e);
       
  1429         }
       
  1430 
       
  1431         public void mouseMove(MouseEvent event)
       
  1432         {
       
  1433             // Check for timeout expiration and if PointerUp falls outside the rectangle
       
  1434             if(isMode(DISABLE_TAPDETECTION) || (!isMode(SUPPRESS_DRAGEVENT)) || !checkWithinRect(event.x, event.y))
       
  1435             {
       
  1436                 LCDUIEvent e = EventDispatcher.instance().newEvent(LCDUIEvent.CANVAS_POINTERDRAGGED,
       
  1437                                javax.microedition.lcdui.Canvas.this);
       
  1438                 e.x = event.x;
       
  1439                 e.y = event.y;
       
  1440                 EventDispatcher.instance().postEvent(e);
       
  1441             }
       
  1442         }
       
  1443 
       
  1444         boolean checkWithinRect(int x, int y)
       
  1445         {
       
  1446             // Get pixel per inch
       
  1447             Point P = Display.getCurrent().getDPI();
       
  1448 
       
  1449             float xPxielwidth  = (twips * P.x) / 1440;
       
  1450             float yPixelHeight = (twips * P.y) / 1440;
       
  1451 
       
  1452             int RightX = pointerDownX + (int) xPxielwidth;
       
  1453 
       
  1454             // If the rectange width falls outside the canvas area
       
  1455             if(RightX > getWidth())
       
  1456             {
       
  1457                 RightX = getWidth();
       
  1458             }
       
  1459 
       
  1460             int LeftX = pointerDownX - (int) xPxielwidth;
       
  1461 
       
  1462             // If the rectange width falls outside the canvas area
       
  1463             if(LeftX < 0)
       
  1464                 LeftX = 0;
       
  1465 
       
  1466             int TopY = pointerDownY - (int) yPixelHeight;
       
  1467 
       
  1468             // If the rectange height falls outside the canvas area
       
  1469             if(TopY < 0)
       
  1470                 TopY = 0;
       
  1471 
       
  1472             int DownY = pointerDownY + (int) yPixelHeight;
       
  1473 
       
  1474             // If the rectange heightfalls outside the canvas area.
       
  1475             if(DownY > getHeight())
       
  1476                 DownY = getHeight();
       
  1477 
       
  1478             // Find the PointerUp is within rectange
       
  1479             if((x >= LeftX) && (x <= RightX))
       
  1480             {
       
  1481                 if((y >= TopY) && (y <= DownY))
       
  1482                 {
       
  1483                     return true;
       
  1484                 }
       
  1485             }
       
  1486 
       
  1487             return false;
       
  1488         }
       
  1489     }
       
  1490 
       
  1491     private boolean invalidate(int x, int y, int width, int height)
       
  1492     {
       
  1493         // Regularize bounds
       
  1494         final int x1 = x;
       
  1495         final int y1 = y;
       
  1496         final int x2 = x + width;
       
  1497         final int y2 = y + height;
       
  1498 
       
  1499         // Union the current and new damaged rects
       
  1500         final boolean valid = ((repaintX2 - repaintX1) <= 0) && ((repaintY2 - repaintY1) <= 0);
       
  1501         if(!valid)
       
  1502         {
       
  1503             repaintX1 = Math.min(repaintX1, x1);
       
  1504             repaintY1 = Math.min(repaintY1, y1);
       
  1505             repaintX2 = Math.max(repaintX2, x2);
       
  1506             repaintY2 = Math.max(repaintY2, y2);
       
  1507         }
       
  1508         else
       
  1509         {
       
  1510             repaintX1 = x1;
       
  1511             repaintY1 = y1;
       
  1512             repaintX2 = x2;
       
  1513             repaintY2 = y2;
       
  1514         }
       
  1515 
       
  1516         // UI thread can change the the contentArea object reference at
       
  1517         // any time. Store the object reference locally to ensure it
       
  1518         // points to the same rectangle all the time.
       
  1519         Rectangle contentArea = getContentArea();
       
  1520         if(contentArea == null) return valid;
       
  1521         final int w = contentArea.width;
       
  1522         final int h = contentArea.height;
       
  1523 
       
  1524         // Clip to bounds
       
  1525         repaintX1 = repaintX1 > 0 ? repaintX1 : 0;
       
  1526         repaintY1 = repaintY1 > 0 ? repaintY1 : 0;
       
  1527         repaintX2 = repaintX2 < w ? repaintX2 : w;
       
  1528         repaintY2 = repaintY2 < h ? repaintY2 : h;
       
  1529 
       
  1530         return valid;
       
  1531     }
       
  1532 
       
  1533     class CanvasTimerTask extends TimerTask
       
  1534     {
       
  1535 
       
  1536         public void run()
       
  1537         {
       
  1538             setMode(SUPPRESS_DRAGEVENT, false);
       
  1539         }
       
  1540     }
       
  1541 
       
  1542     class CanvasShellVisibilityListener implements SymbianWindowVisibilityListener
       
  1543     {
       
  1544         public void handleSymbianWindowVisibilityChange(Widget widget, boolean visible) {
       
  1545             if (javax.microedition.lcdui.Canvas.this.getShell() == widget && graphicsBuffer != null)
       
  1546             {
       
  1547                 WindowSurface surface = graphicsBuffer.getWindowSurface();
       
  1548                 if (surface != null)
       
  1549                     surface.handleSymbianWindowVisibilityChange(visible);
       
  1550             }
       
  1551         }
       
  1552     }
       
  1553 }