/* JPC: An x86 PC Hardware Emulator for a pure Java Virtual Machine Release Version 2.4 A project from the Physics Dept, The University of Oxford Copyright (C) 2007-2010 The University of Oxford This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 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 for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Details (including contact information) can be found at: jpc.sourceforge.net or the developer website sourceforge.net/projects/jpc/ Conceived and Developed by: Rhys Newman, Ian Preston, Chris Dennis End of licence header */ package org.jpc.j2se; import java.awt.*; import java.io.*; import javax.swing.JScrollPane; import org.jpc.emulator.*; import org.jpc.emulator.pci.peripheral.*; import org.jpc.emulator.peripheral.*; /** * * @author Rhys Newman */ public class PCMonitor extends KeyHandlingPanel { private Keyboard keyboard; private DefaultVGACard vgaCard; private Updater updater; private Component frame = null; private PC pc; private double scaleX = 1.0; private double scaleY = 1.0; private boolean ignoreResize = false; private volatile boolean clearBackground; public PCMonitor(PC pc) { this(null, pc); } public PCMonitor(LayoutManager mgr, PC pc) { super(mgr); this.pc = pc; clearBackground = true; setDoubleBuffered(false); requestFocusInWindow(); vgaCard = (DefaultVGACard) pc.getComponent(VGACard.class); vgaCard.setMonitor(this); vgaCard.resizeDisplay(720, 480); keyboard = (Keyboard) pc.getComponent(Keyboard.class); setInputMap(WHEN_FOCUSED, null); } protected PC getPC() { return pc; } public void saveState(OutputStream out) throws IOException { int[] rawImageData = vgaCard.getDisplayBuffer(); byte[] dummy = new byte[rawImageData.length * 4]; for (int i = 0, j = 0; i < rawImageData.length; i++) { int val = rawImageData[i]; dummy[j++] = (byte) (val >> 24); dummy[j++] = (byte) (val >> 16); dummy[j++] = (byte) (val >> 8); dummy[j++] = (byte) (val); } DataOutputStream output = new DataOutputStream(out); output.writeInt(rawImageData.length); out.write(dummy); out.flush(); } public void loadState(InputStream in) throws IOException { DataInputStream input = new DataInputStream(in); int len = input.readInt(); int[] rawImageData = vgaCard.getDisplayBuffer(); if (len != rawImageData.length) { throw new IOException("Image size not consistent with saved image state"); } byte[] dummy = new byte[len * 4]; input.readFully(dummy); for (int i = 0, j = 0; i < len; i++) { int val = 0; val |= (0xff & dummy[j++]) << 24; val |= (0xff & dummy[j++]) << 16; val |= (0xff & dummy[j++]) << 8; val |= 0xff & dummy[j++]; rawImageData[i] = val; } } public void setFrame(Component f) { this.frame = f; } public void repeatedKeyPress(int keyCode) { keyboard.keyPressed(KeyMapping.getScancode(Integer.valueOf(keyCode))); } public void keyPressed(int keyCode) { keyboard.keyPressed(KeyMapping.getScancode(Integer.valueOf(keyCode))); } public void keyReleased(int keyCode) { keyboard.keyReleased(KeyMapping.getScancode(Integer.valueOf(keyCode))); } public void mouseEventReceived(int dx, int dy, int dz, int buttons) { keyboard.putMouseEvent(dx, dy, dz, buttons); } public synchronized void startUpdateThread() { stopUpdateThread(); updater = new Updater(); updater.start(); } public synchronized void stopUpdateThread() { if (updater != null) updater.halt(); } public synchronized boolean isRunning() { if (updater == null) return false; return updater.running; } class Updater extends Thread { private volatile boolean running = !Option.noScreen.isSet(); public Updater() { super("PC Monitor Updater Task"); } public void run() { while (running) { try { Thread.sleep(20); } catch (InterruptedException e) {} vgaCard.prepareUpdate(); vgaCard.updateDisplay(); /* int xmin = (int)((vgaCard.getXMin() -1 ) * scaleX); int xmax = (int)(vgaCard.getXMax() * scaleX); int ymin = (int)((vgaCard.getYMin() - 1) * scaleY); int ymax = (int)(vgaCard.getYMax() * scaleY); repaint(xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); */ repaint(); } } public void halt() { try { running = false; interrupt(); } catch (SecurityException e) {} } } public void resizeDisplay(int width, int height) { resizeDisplayCommon((int)(width * scaleX), (int)(height * scaleY)); } private void resizeDisplayCommon(int width, int height) { //System.out.println("resized X="+width+" Y="+height); //System.out.println("resized scaleX="+scaleX+" scaleY="+scaleY); setPreferredSize(new Dimension(width, height)); setMaximumSize(new Dimension(width, height)); setMinimumSize(new Dimension(width, height)); clearBackground = true; revalidate(); repaint(); } public void scaleDisplay(int width, int height) { Dimension display = vgaCard.getDisplaySize(); double displayWidth=display.width; double displayHeight=display.height; if(width > displayWidth) { scaleX = width / displayWidth; }else{ scaleX = 1.0; } if(height > displayHeight) { scaleY = height / displayHeight; }else{ scaleY = 1.0; } //System.out.println("scale display scaleX="+scaleX+" scaleY="+scaleY + "actual x="+displayWidth+" y="+displayHeight); } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { if (clearBackground) { g.setColor(Color.white); Dimension s1 = getSize(); Dimension s2 = vgaCard.getDisplaySize(); if (s1.width > s2.width) g.fillRect(s2.width, 0, s1.width - s2.width, s1.height); if (s1.height > s2.height) g.fillRect(0, s2.height, s1.width, s1.height - s2.height); clearBackground = false; } vgaCard.paintPCMonitor((Graphics2D)g, this); } }