/* * $Id$ * * Copyright (C) 2003-2014 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.driver.video.cursor; import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.awt.image.Raster; import org.jnode.awt.util.BitmapGraphics; import org.jnode.driver.video.HardwareCursor; import org.jnode.driver.video.HardwareCursorAPI; import org.jnode.driver.video.HardwareCursorImage; import org.jnode.driver.video.Surface; import org.jnode.vm.Unsafe; public class SoftwareCursor extends BitmapGraphics implements HardwareCursorAPI { private BitmapGraphics graphics; private HardwareCursorImage cursorImage; private boolean cursorVisible = false; private int[] screenBackup; private Rectangle cursorArea = new Rectangle(0, 0, 0, 0); private Rectangle screenArea = new Rectangle(); public SoftwareCursor(BitmapGraphics graphics) { setBitmapGraphics(graphics); } public void setBitmapGraphics(BitmapGraphics graphics) { if (this.graphics != graphics) { hideCursor(); this.graphics = graphics; if (cursorImage != null) { int newHotspotX = (int) Math.min(graphics.getWidth() - 1, cursorArea.getX() + cursorImage.getHotSpotX()); int newHotspotY = (int) Math.min(graphics.getHeight() - 1, cursorArea.getY() + cursorImage.getHotSpotY()); cursorArea.setLocation(newHotspotX - cursorImage.getHotSpotX(), newHotspotY - cursorImage.getHotSpotY()); } // TODO test when screen resolution is changing showCursor(); } } @Override public void copyArea(int srcX, int srcY, int w, int h, int dstX, int dstY) { // TODO don't take cursor pixels for the source final boolean intersects = intersectsCursor(dstX, dstY, w, h); if (intersects) { hideCursor(); } graphics.copyArea(srcX, srcY, w, h, dstX, dstY); if (intersects) { showCursor(); } } @Override public int doGetPixel(int x, int y) { // TODO don't take cursor pixels return graphics.doGetPixel(x, y); } @Override public int[] doGetPixels(Rectangle r) { // TODO don't take cursor pixels return graphics.doGetPixels(r); } @Override public void drawAlphaRaster(Raster raster, AffineTransform tx, int srcX, int srcY, int dstX, int dstY, int w, int h, int color) { final boolean intersects = intersectsCursor(dstX, dstY, w, h); if (intersects) { hideCursor(); } graphics.drawAlphaRaster(raster, tx, srcX, srcY, dstX, dstY, w, h, color); if (intersects) { showCursor(); } } @Override public void drawImage(Raster src, int srcX, int srcY, int dstX, int dstY, int w, int h) { final boolean intersects = intersectsCursor(dstX, dstY, w, h); if (intersects) { hideCursor(); } graphics.drawImage(src, srcX, srcY, dstX, dstY, w, h); if (intersects) { showCursor(); } } @Override public void drawImage(Raster src, int srcX, int srcY, int dstX, int dstY, int w, int h, int bgColor) { final boolean intersects = intersectsCursor(dstX, dstY, w, h); if (intersects) { hideCursor(); } graphics.drawImage(src, srcX, srcY, dstX, dstY, w, h, bgColor); if (intersects) { showCursor(); } } @Override public void drawLine(int x, int y, int w, int color, int mode) { final boolean intersects = intersectsCursor(x, y, w, 1); if (intersects) { hideCursor(); } graphics.drawLine(x, y, w, color, mode); if (intersects) { showCursor(); } } @Override public void drawPixels(int x, int y, int count, int color, int mode) { final boolean intersects = intersectsCursor(x, y, count, 1); if (intersects) { hideCursor(); } graphics.drawPixels(x, y, count, color, mode); if (intersects) { showCursor(); } } public int getWidth() { return graphics.getWidth(); } public int getHeight() { return graphics.getHeight(); } public void setCursorImage(HardwareCursor cursor) { if (cursor == null) { return; } try { final HardwareCursorImage cursImage = cursor.getImage(20, 20); if ((cursImage != null) && (this.cursorImage != cursImage)) { hideCursor(); cursorArea.setSize(cursImage.getWidth(), cursImage.getHeight()); if (cursorImage != null) { int newX = (int) (cursorArea.getX() + cursorImage.getHotSpotX() - cursImage .getHotSpotX()); int newY = (int) (cursorArea.getY() + cursorImage.getHotSpotY() - cursImage .getHotSpotY()); cursorArea.setLocation(newX, newY); } this.cursorImage = cursImage; showCursor(); } } catch (Throwable t) { Unsafe.debugStackTrace("error in setCursorImage (" + t.getClass().getName() + ")", t); } } public void setCursorPosition(int x, int y) { try { // x,y corresponds to the location of the cursor's hotspot on the // screen // it can be anywhere in the screen area (but some part of the // cursor might not be visible) x = Math.min(Math.max(x, 0), graphics.getWidth() - 1); y = Math.min(Math.max(y, 0), graphics.getHeight() - 1); if ((cursorArea.getX() != x) || (cursorArea.getY() != y)) { hideCursor(); if (cursorImage != null) { int newX = (int) (x - cursorImage.getHotSpotX()); int newY = (int) (y - cursorImage.getHotSpotY()); cursorArea.setLocation(newX, newY); } else { cursorArea.setLocation(x, y); } showCursor(); } } catch (Throwable t) { Unsafe.debugStackTrace("error in setCursorPosition", t); } } public void setCursorVisible(boolean visible) { try { if (this.cursorVisible != visible) { this.cursorVisible = visible; if (visible) { showCursor(); } else { hideCursor(); } } } catch (Throwable t) { Unsafe.debugStackTrace("error in setCursorVisible", t); } } private boolean intersectsCursor(int x, int y, int width, int height) { boolean intersects = false; if (cursorVisible && (width > 0) && (height > 0)) { screenArea.setBounds(x, y, width, height); intersects = cursorArea.intersects(screenArea); } return intersects; } private void showCursor() { if (cursorImage != null) { if (screenBackup == null) { screenBackup = new int[cursorImage.getWidth() * cursorImage.getHeight()]; } // screenBackup = graphics.doGetPixels(cursorArea); final int cursorX = (int) cursorArea.getX(); final int cursorY = (int) cursorArea.getY(); final int maxY = Math.min(cursorY + cursorImage.getHeight(), graphics.getHeight()); final int maxX = Math.min(cursorX + cursorImage.getWidth(), graphics.getWidth()); final int width = cursorImage.getWidth(); int index = 0; for (int y = cursorY; y < maxY; y++) { int lineIndex = index; for (int x = cursorX; x < maxX; x++) { screenBackup[lineIndex] = graphics.doGetPixel(x, y); lineIndex++; } index += width; } putPixels(cursorImage.getImage(), screenBackup); } } private void hideCursor() { if ((cursorImage != null) && (screenBackup != null)) { putPixels(screenBackup, null); } } private void putPixels(int[] pixels, int[] background) { final int cursorX = (int) cursorArea.getX(); final int cursorY = (int) cursorArea.getY(); final int maxY = Math.min(cursorY + cursorImage.getHeight(), graphics.getHeight()); final int maxX = Math.min(cursorX + cursorImage.getWidth(), graphics.getWidth()); final int width = cursorImage.getWidth(); int index = 0; for (int y = cursorY; y < maxY; y++) { int lineIndex = index; for (int x = cursorX; x < maxX; x++) { int color; if (background == null) { color = pixels[lineIndex]; } else { final int c = pixels[lineIndex]; final boolean isTransparent = (c == 0); color = isTransparent ? background[lineIndex] : c; } graphics.drawPixels(x, y, 1, color, Surface.PAINT_MODE); lineIndex++; } index += width; } } }