/*
*
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package javax.microedition.lcdui;
/* import javax.microedition.lcdui.KeyConverter; */
import java.util.Vector;
import java.util.Enumeration;
import com.sun.midp.configurator.Constants;
/**
* Look and feel implementation of <code>Canvas</code> based on
* platform widget.
*/
class CanvasLFImpl extends DisplayableLFImpl implements CanvasLF {
/**
* LF implementation of <code>Canvas</code>.
* @param canvas the <code>Canvas</code> associated with this
* <code>CanvasLFImpl</code>
*/
CanvasLFImpl(Canvas canvas) {
super(canvas);
this.canvas = canvas;
}
// ************************************************************
// public methods - CanvasLF interface implementation
// ************************************************************
/**
* Notifies look & feel object that repaint of a (x, y, width, height)
* area is needed.
*
* SYNC NOTE: The caller of this method handles synchronization.
*
* @param x The x coordinate of the region to repaint
* @param y The y coordinate of the region to repaint
* @param width The width of the region to repaint
* @param height The height of the region to repaint
* @param target an optional paint target to receive the paint request
* when it returns via callPaint()
*/
public void lRepaint(int x, int y, int width, int height,
Object target) {
lRequestPaint(x, y, width, height, target);
}
/**
* Notifies that repaint of the entire <code>Canvas</code> look&feel
* is needed.
* Repaints the viewport area.
*
* SYNC NOTE: The caller of this method handles synchronization.
*/
public void lRepaint() {
lRequestPaintContents();
}
/**
* Request serviceRepaints from current <code>Display</code>.
* SYNC NOTE: Unlike most other LF methods, no locking is held when
* this function is called because <code>Display.serviceRepaints()</code>
* needs to handle its own locking.
*/
public void uServiceRepaints() {
// 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);
}
}
/**
* Notify this <code>Canvas</code> that it is being shown on the
* given <code>Display</code>.
*/
public void uCallShow() {
// Create native resource with title and ticker
super.uCallShow();
// Notify the canvas subclass before showing native resource
synchronized (Display.calloutLock) {
try {
canvas.showNotify();
/* For MMAPI VideoControl in a Canvas */
if (mmHelper != null) {
for (Enumeration e = embeddedVideos.elements();
e.hasMoreElements();) {
mmHelper.showVideo(e.nextElement());
}
}
} catch (Throwable t) {
Display.handleThrowable(t);
}
}
}
/**
* Notify this <code>Canvas</code> that it is being hidden on the
* given <code>Display</code>.
*/
public void uCallHide() {
int oldState = state;
// Delete native resources including title and ticker
super.uCallHide();
// Notify canvas subclass after hiding the native resource
synchronized (Display.calloutLock) {
if (oldState == SHOWN) {
try {
canvas.hideNotify();
/* For MMAPI VideoControl in a Canvas */
if (mmHelper != null) {
for (Enumeration e = embeddedVideos.elements();
e.hasMoreElements();) {
mmHelper.hideVideo(e.nextElement());
}
}
} catch (Throwable t) {
Display.handleThrowable(t);
}
}
}
}
/**
* Notify this <code>Canvas</code> that it is being frozen on the
* given <code>Display</code>.
*/
public void uCallFreeze() {
int oldState = state;
// Delete native resources including title and ticker
super.uCallFreeze();
// Notify canvas subclass after hiding the native resource
synchronized (Display.calloutLock) {
if (oldState == SHOWN) {
try {
canvas.hideNotify();
// For MMAPI VideoControl in a Canvas
if (mmHelper != null) {
for (Enumeration e = embeddedVideos.elements();
e.hasMoreElements();) {
mmHelper.hideVideo(e.nextElement());
}
}
} catch (Throwable t) {
Display.handleThrowable(t);
}
}
}
}
/**
* Paint this <code>Canvas</code>.
*
* @param g the <code>Graphics</code> to paint to
* @param target the target Object of this repaint
*/
public void uCallPaint(Graphics g, Object target) {
super.uCallPaint(g, target);
// We prevent the Canvas from drawing outside of the
// allowable viewport.
// We also need to preserve the original translation.
// g.preserveMIDPRuntimeGC(x, y, WIDTH, HEIGHT);
// Reset the graphics context according to the spec. requirement.
// This is a must before we call canvas's paint(g) since the
// title or ticker drawing routines may change the GC before.
g.resetGC();
try {
synchronized (Display.calloutLock) {
canvas.paint(g);
}
} catch (Throwable t) {
Display.handleThrowable(t);
}
// If there are any video players in this canvas,
// let the helper class invoke video rendering
// Update frames of any video players displayed on this Canvas
if (mmHelper != null) {
for (Enumeration e = embeddedVideos.elements();
e.hasMoreElements();) {
mmHelper.paintVideo(e.nextElement(), g);
}
}
// g.restoreMIDPRuntimeGC();
}
// ************************************************************
// package private methods
// ************************************************************
/**
* Handle a key press.
*
* @param keyCode The key that was pressed
*/
void uCallKeyPressed(int keyCode) {
if (allowKey(keyCode)) {
synchronized (Display.calloutLock) {
try {
canvas.keyPressed(keyCode);
} catch (Throwable t) {
Display.handleThrowable(t);
}
}
}
}
/**
* Handle a key release.
*
* @param keyCode The key that was released
*/
void uCallKeyReleased(int keyCode) {
if (allowKey(keyCode)) {
synchronized (Display.calloutLock) {
try {
canvas.keyReleased(keyCode);
} catch (Throwable t) {
Display.handleThrowable(t);
}
}
}
}
/**
* Handle a repeated key press.
*
* @param keyCode The key that was pressed
*/
void uCallKeyRepeated(int keyCode) {
if (allowKey(keyCode)) {
synchronized (Display.calloutLock) {
try {
canvas.keyRepeated(keyCode);
} catch (Throwable t) {
Display.handleThrowable(t);
}
}
}
}
/**
* Handle a pointer press event.
*
* @param x The x coordinate of the press
* @param y The y coordinate of the press
*/
void uCallPointerPressed(int x, int y) {
synchronized (Display.calloutLock) {
try {
canvas.pointerPressed(x, 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 uCallPointerReleased(int x, int y) {
synchronized (Display.calloutLock) {
try {
canvas.pointerReleased(x, 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 uCallPointerDragged(int x, int y) {
synchronized (Display.calloutLock) {
try {
canvas.pointerDragged(x, y);
} catch (Throwable t) {
Display.handleThrowable(t);
}
}
}
/**
* Add embedded video player.
* This is called by <code>MMHelperImpl</code>, whenever a video
* player joins this canvas.
*
* @param video The player joining this canvas.
*/
void addEmbeddedVideo(Object video) {
embeddedVideos.addElement(video);
}
/**
* Remove embedded video player.
* This is called by <code>MMHelperImpl</code>, whenever a video
* player leaves this canvas.
*
* @param video The player leaving this canvas.
*/
void removeEmbeddedVideo(Object video) {
embeddedVideos.removeElement(video);
}
// ************************************************************
// private methods
// ************************************************************
/**
* 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 (!canvas.suppressKeyEvents) {
return true;
}
switch (KeyConverter.getGameAction(keyCode)) {
case -1:
// Invalid keycode, don't block this key.
return true;
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;
}
}
/**
* Create and show native resource for this <code>Canvas</code>.
*/
void createNativeResource() {
nativeId = createNativeResource0(canvas.title,
canvas.ticker == null ? null : canvas.ticker.getString());
}
/**
* Create and show native resource for this <code>Canvas</code>.
* @param title title of the canvas
* @param tickerText text for the ticker
* @return native resource ID
*/
private native int createNativeResource0(String title, String tickerText);
/**
* <code>Canvas</code> being stored in this object.
*/
Canvas canvas;
/**
* A vector of embedded video players.
*/
private Vector embeddedVideos = new Vector(1);
/**
* The <code>MMHelperImpl</code> instance.
*/
private static MMHelperImpl mmHelper = MMHelperImpl.getInstance();
}