Mercurial > hg > Applications > TreeVNC
diff src/viewer_swing/java/com/glavsoft/viewer/swing/Surface.java @ 0:4689cc86d6cb
create TreeViewer2 Repository
author | Yu Taninari <you@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 03 Jul 2012 13:20:49 +0900 |
parents | |
children | 3c072f2f39bb 17b702648079 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/Surface.java Tue Jul 03 13:20:49 2012 +0900 @@ -0,0 +1,232 @@ +// Copyright (C) 2010, 2011 GlavSoft LLC. +// All rights reserved. +// +//------------------------------------------------------------------------- +// This file is part of the TightVNC software. Please visit our Web site: +// +// http://www.tightvnc.com/ +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// 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. +//------------------------------------------------------------------------- +// + +package com.glavsoft.viewer.swing; + +import com.glavsoft.core.SettingsChangedEvent; +import com.glavsoft.drawing.Renderer; +import com.glavsoft.rfb.IChangeSettingsListener; +import com.glavsoft.rfb.IRepaintController; +import com.glavsoft.rfb.encoding.PixelFormat; +import com.glavsoft.rfb.encoding.decoder.FramebufferUpdateRectangle; +import com.glavsoft.rfb.protocol.ProtocolContext; +import com.glavsoft.rfb.protocol.ProtocolSettings; +import com.glavsoft.transport.Reader; +import com.glavsoft.viewer.Viewer; + +import javax.swing.*; +import java.awt.*; + +@SuppressWarnings("serial") +public class Surface extends JPanel implements IRepaintController, IChangeSettingsListener { + + private int width; + private int height; + private SoftCursorImpl cursor; + private RendererImpl renderer; + private MouseEventListener mouseEventListener; + private KeyEventListener keyEventListener; + private boolean showCursor; + private ModifierButtonEventListener modifierButtonListener; + private boolean isUserInputEnabled = false; + private final ProtocolContext context; + private double scaleFactor; + private final Viewer viewer; + + @Override + public boolean isDoubleBuffered() { + // TODO returning false in some reason may speed ups drawing, but may + // not. Needed in challenging. + return false; + } + + public Surface(ProtocolContext context, Viewer viewer, double scaleFactor) { + this.context = context; + this.viewer = viewer; + this.scaleFactor = scaleFactor; + init(context.getFbWidth(), context.getFbHeight()); + + if ( ! context.getSettings().isViewOnly()) { + setUserInputEnabled(true, context.getSettings().isConvertToAscii()); + } + showCursor = context.getSettings().isShowRemoteCursor(); + } + + private void setUserInputEnabled(boolean enable, boolean convertToAscii) { + if (enable == isUserInputEnabled) return; + isUserInputEnabled = enable; + if (enable) { + if (null == mouseEventListener) { + mouseEventListener = new MouseEventListener(this, context, scaleFactor); + } + addMouseListener(mouseEventListener); + addMouseMotionListener(mouseEventListener); + addMouseWheelListener(mouseEventListener); + + setFocusTraversalKeysEnabled(false); + if (null == keyEventListener) { + keyEventListener = new KeyEventListener(context); + if (modifierButtonListener != null) { + keyEventListener.addModifierListener(modifierButtonListener); + } + } + keyEventListener.setConvertToAscii(convertToAscii); + addKeyListener(keyEventListener); + enableInputMethods(false); + } else { + removeMouseListener(mouseEventListener); + removeMouseMotionListener(mouseEventListener); + removeMouseWheelListener(mouseEventListener); + removeKeyListener(keyEventListener); + } + } + + @Override + public Renderer createRenderer(Reader reader, int width, int height, PixelFormat pixelFormat) { + renderer = new RendererImpl(reader, width, height, pixelFormat); + synchronized (renderer) { + cursor = renderer.getCursor(); + } + init(renderer.getWidth(), renderer.getHeight()); + updateFrameSize(); + return renderer; + } + + private void init(int width, int height) { + this.width = width; + this.height = height; + setSize(getPreferredSize()); + } + + private void updateFrameSize() { + setSize(getPreferredSize()); + viewer.packContainer(); + requestFocus(); + } + + @Override + public void paintComponent(Graphics g) { + ((Graphics2D)g).scale(scaleFactor, scaleFactor); + ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + synchronized (renderer) { + Image offscreenImage = renderer.getOffscreenImage(); + if (offscreenImage != null) { + g.drawImage(offscreenImage, 0, 0, null); + } + } + synchronized (cursor) { + Image cursorImage = cursor.getImage(); + if (showCursor && cursorImage != null && + (scaleFactor != 1 || + g.getClipBounds().intersects(cursor.rX, cursor.rY, cursor.width, cursor.height))) { + g.drawImage(cursorImage, cursor.rX, cursor.rY, null); + } + } + } + + @Override + public Dimension getPreferredSize() { + return new Dimension((int)(this.width * scaleFactor), (int)(this.height * scaleFactor)); + } + + @Override + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + @Override + public Dimension getMaximumSize() { + return getPreferredSize(); + } + + /** + * Saves context and simply invokes native JPanel repaint method which + * asyncroniously register repaint request using invokeLater to repaint be + * runned in Swing event dispatcher thread. So may be called from other + * threads. + */ + @Override + public void repaintBitmap(FramebufferUpdateRectangle rect) { + repaintBitmap(rect.x, rect.y, rect.width, rect.height); + } + + @Override + public void repaintBitmap(int x, int y, int width, int height) { + repaint((int)(x * scaleFactor), (int)(y * scaleFactor), + (int)Math.ceil(width * scaleFactor), (int)Math.ceil(height * scaleFactor)); + } + + @Override + public void repaintCursor() { + synchronized (cursor) { + repaint((int)(cursor.oldRX * scaleFactor), (int)(cursor.oldRY * scaleFactor), + (int)Math.ceil(cursor.oldWidth * scaleFactor) + 1, (int)Math.ceil(cursor.oldHeight * scaleFactor) + 1); + repaint((int)(cursor.rX * scaleFactor), (int)(cursor.rY * scaleFactor), + (int)Math.ceil(cursor.width * scaleFactor) + 1, (int)Math.ceil(cursor.height * scaleFactor) + 1); + } + } + + @Override + public void updateCursorPosition(short x, short y) { + synchronized (cursor) { + cursor.updatePosition(x, y); + repaintCursor(); + } + } + + private void showCursor(boolean show) { + synchronized (cursor) { + showCursor = show; + } + } + + public void addModifierListener(ModifierButtonEventListener modifierButtonListener) { + this.modifierButtonListener = modifierButtonListener; + if (keyEventListener != null) { + keyEventListener.addModifierListener(modifierButtonListener); + } + } + + @Override + public void settingsChanged(SettingsChangedEvent e) { + if (ProtocolSettings.isRfbSettingsChangedFired(e)) { + ProtocolSettings settings = (ProtocolSettings) e.getSource(); + setUserInputEnabled( ! settings.isViewOnly(), settings.isConvertToAscii()); + showCursor(settings.isShowRemoteCursor()); + } else if (UiSettings.isUiSettingsChangedFired(e)) { + UiSettings settings = (UiSettings) e.getSource(); + scaleFactor = settings.getScaleFactor(); + } + mouseEventListener.setScaleFactor(scaleFactor); + updateFrameSize(); + } + + @Override + public void setPixelFormat(PixelFormat pixelFormat) { + if (renderer != null) { + renderer.initPixelFormat(pixelFormat); + } + } + +}