Mercurial > hg > Applications > tvnjviewer
annotate src/viewer_swing/java/com/glavsoft/viewer/swing/SwingViewerWindow.java @ 30:aa88409a502b
Alice update tag:work-compressedDSM
author | Nozomi Teruya <e125769@ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 08 Nov 2015 21:08:46 +0900 |
parents | e650eaf8deeb |
children |
rev | line source |
---|---|
0 | 1 // Copyright (C) 2010, 2011, 2012, 2013 GlavSoft LLC. |
2 // All rights reserved. | |
3 // | |
4 //------------------------------------------------------------------------- | |
5 // This file is part of the TightVNC software. Please visit our Web site: | |
6 // | |
7 // http://www.tightvnc.com/ | |
8 // | |
9 // This program is free software; you can redistribute it and/or modify | |
10 // it under the terms of the GNU General Public License as published by | |
11 // the Free Software Foundation; either version 2 of the License, or | |
12 // (at your option) any later version. | |
13 // | |
14 // This program is distributed in the hope that it will be useful, | |
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 // GNU General Public License for more details. | |
18 // | |
19 // You should have received a copy of the GNU General Public License along | |
20 // with this program; if not, write to the Free Software Foundation, Inc., | |
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
22 //------------------------------------------------------------------------- | |
23 // | |
24 | |
25 package com.glavsoft.viewer.swing; | |
26 | |
16 | 27 import alice.datasegment.DataSegment; |
18 | 28 import alice.datasegment.ReceiveData; |
16 | 29 |
0 | 30 import com.glavsoft.core.SettingsChangedEvent; |
31 import com.glavsoft.rfb.IChangeSettingsListener; | |
32 import com.glavsoft.rfb.client.KeyEventMessage; | |
33 import com.glavsoft.rfb.protocol.Protocol; | |
34 import com.glavsoft.rfb.protocol.ProtocolContext; | |
35 import com.glavsoft.rfb.protocol.ProtocolSettings; | |
36 import com.glavsoft.utils.Keymap; | |
37 import com.glavsoft.viewer.ConnectionPresenter; | |
38 import com.glavsoft.viewer.UiSettings; | |
39 import com.glavsoft.viewer.Viewer; | |
40 import com.glavsoft.viewer.swing.gui.OptionsDialog; | |
41 | |
42 import javax.swing.*; | |
43 import javax.swing.border.BevelBorder; | |
44 import javax.swing.border.Border; | |
45 import javax.swing.border.EmptyBorder; | |
16 | 46 |
0 | 47 import java.awt.*; |
48 import java.awt.event.*; | |
49 import java.util.LinkedList; | |
50 import java.util.List; | |
51 import java.util.concurrent.Executors; | |
52 import java.util.concurrent.ScheduledExecutorService; | |
53 import java.util.concurrent.ScheduledFuture; | |
54 import java.util.concurrent.TimeUnit; | |
55 import java.util.logging.Logger; | |
56 | |
57 public class SwingViewerWindow implements IChangeSettingsListener { | |
58 public static final int FS_SCROLLING_ACTIVE_BORDER = 20; | |
59 private JToggleButton zoomFitButton; | |
60 private JToggleButton zoomFullScreenButton; | |
61 private JButton zoomInButton; | |
62 private JButton zoomOutButton; | |
63 private JButton zoomAsIsButton; | |
64 private JPanel outerPanel; | |
65 private JScrollPane scroller; | |
66 private JFrame frame; | |
67 private boolean forceResizable = true; | |
68 private ButtonsBar buttonsBar; | |
69 private Surface surface; | |
70 private boolean isSeparateFrame; | |
71 private final boolean isApplet; | |
72 private Viewer viewer; | |
73 private String connectionString; | |
74 private ConnectionPresenter presenter; | |
75 private Rectangle oldContainerBounds; | |
76 private volatile boolean isFullScreen; | |
77 private Border oldScrollerBorder; | |
78 private JLayeredPane lpane; | |
79 private EmptyButtonsBarMouseAdapter buttonsBarMouseAdapter; | |
80 private String remoteDesktopName; | |
81 private ProtocolSettings rfbSettings; | |
82 private UiSettings uiSettings; | |
83 private Protocol workingProtocol; | |
84 | |
85 private boolean isZoomToFitSelected; | |
86 private List<JComponent> kbdButtons; | |
87 | |
88 public SwingViewerWindow(Protocol workingProtocol, ProtocolSettings rfbSettings, UiSettings uiSettings, Surface surface, | |
89 boolean isSeparateFrame, boolean isApplet, Viewer viewer, String connectionString, | |
90 ConnectionPresenter presenter) { | |
91 this.workingProtocol = workingProtocol; | |
92 this.rfbSettings = rfbSettings; | |
93 this.uiSettings = uiSettings; | |
94 this.surface = surface; | |
95 this.isSeparateFrame = isSeparateFrame; | |
96 this.isApplet = isApplet; | |
97 this.viewer = viewer; | |
98 this.connectionString = connectionString; | |
99 this.presenter = presenter; | |
100 createContainer(surface, isApplet, viewer); | |
101 | |
102 if (uiSettings.showControls) { | |
103 createButtonsPanel(workingProtocol, isSeparateFrame? frame: viewer); | |
104 if (isSeparateFrame) registerResizeListener(frame); | |
105 updateZoomButtonsState(); | |
106 } | |
107 if (uiSettings.isFullScreen()) { | |
108 switchOnFullscreenMode(); | |
109 } | |
110 setSurfaceToHandleKbdFocus(); | |
111 if (isSeparateFrame) { | |
112 new Thread(new Runnable() { | |
113 @Override | |
114 public void run() { | |
115 try { | |
116 Thread.sleep(1000); | |
117 } catch (InterruptedException e) { | |
118 // nop | |
119 } | |
120 SwingUtilities.invokeLater(new Runnable() { | |
121 @Override | |
122 public void run() { | |
123 frame.toFront(); | |
124 } | |
125 }); | |
126 } | |
127 }).start(); | |
128 } | |
129 } | |
130 | |
131 private void createContainer(final Surface surface, boolean isApplet, JApplet appletWindow) { | |
132 outerPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)) { | |
133 @Override | |
134 public Dimension getSize() { | |
135 return surface.getPreferredSize(); | |
136 } | |
137 @Override | |
138 public Dimension getPreferredSize() { | |
139 return surface.getPreferredSize(); | |
140 } | |
141 }; | |
142 outerPanel.setBackground(Color.DARK_GRAY); | |
143 lpane = new JLayeredPane() { | |
144 @Override | |
145 public Dimension getSize() { | |
146 return surface.getPreferredSize(); | |
147 } | |
148 @Override | |
149 public Dimension getPreferredSize() { | |
150 return surface.getPreferredSize(); | |
151 } | |
152 }; | |
153 lpane.setPreferredSize(surface.getPreferredSize()); | |
154 lpane.add(surface, JLayeredPane.DEFAULT_LAYER, 0); | |
155 outerPanel.add(lpane); | |
156 | |
157 scroller = new JScrollPane(outerPanel); | |
158 if (isSeparateFrame) { | |
159 frame = new JFrame(); | |
160 if ( ! isApplet) { | |
161 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); | |
162 } | |
163 frame.setModalExclusionType(Dialog.ModalExclusionType.APPLICATION_EXCLUDE); | |
164 Utils.setApplicationIconsForWindow(frame); | |
165 frame.setLayout(new BorderLayout(0, 0)); | |
166 frame.add(scroller, BorderLayout.CENTER); | |
167 | |
168 // frame.pack(); | |
169 outerPanel.setSize(surface.getPreferredSize()); | |
170 internalPack(null); | |
27 | 171 frame.setVisible(!viewer.hideJFrame); |
0 | 172 frame.validate(); |
173 } else { | |
174 appletWindow.setLayout(new BorderLayout(0, 0)); | |
175 appletWindow.add(scroller, BorderLayout.CENTER); | |
176 appletWindow.validate(); | |
177 } | |
178 } | |
179 | |
180 public void pack() { | |
181 final Dimension outerPanelOldSize = outerPanel.getSize(); | |
182 outerPanel.setSize(surface.getPreferredSize()); | |
183 if (isSeparateFrame && ! isZoomToFitSelected()) { | |
184 internalPack(outerPanelOldSize); | |
185 } | |
186 if (buttonsBar != null) { | |
187 updateZoomButtonsState(); | |
188 } | |
189 updateWindowTitle(); | |
190 } | |
191 | |
192 public boolean isZoomToFitSelected() { | |
193 return isZoomToFitSelected; | |
194 } | |
195 | |
196 public void setZoomToFitSelected(boolean zoomToFitSelected) { | |
197 isZoomToFitSelected = zoomToFitSelected; | |
198 } | |
199 | |
200 public void setRemoteDesktopName(String name) { | |
201 remoteDesktopName = name; | |
202 updateWindowTitle(); | |
203 } | |
204 | |
205 private void updateWindowTitle() { | |
206 if (isSeparateFrame) { | |
207 frame.setTitle(remoteDesktopName + " [zoom: " + uiSettings.getScalePercentFormatted() + "%]"); | |
208 } | |
209 } | |
210 | |
211 private void internalPack(Dimension outerPanelOldSize) { | |
212 final Rectangle workareaRectangle = getWorkareaRectangle(); | |
213 if (workareaRectangle.equals(frame.getBounds())) { | |
214 forceResizable = true; | |
215 } | |
216 final boolean isHScrollBar = scroller.getHorizontalScrollBar().isShowing() && ! forceResizable; | |
217 final boolean isVScrollBar = scroller.getVerticalScrollBar().isShowing() && ! forceResizable; | |
218 | |
219 boolean isWidthChangeable = true; | |
220 boolean isHeightChangeable = true; | |
221 if (outerPanelOldSize != null && surface.oldSize != null) { | |
222 isWidthChangeable = forceResizable || | |
223 (outerPanelOldSize.width == surface.oldSize.width && ! isHScrollBar); | |
224 isHeightChangeable = forceResizable || | |
225 (outerPanelOldSize.height == surface.oldSize.height && ! isVScrollBar); | |
226 } | |
227 forceResizable = false; | |
228 frame.validate(); | |
229 | |
230 final Insets containerInsets = frame.getInsets(); | |
231 Dimension preferredSize = frame.getPreferredSize(); | |
232 Rectangle preferredRectangle = new Rectangle(frame.getLocation(), preferredSize); | |
233 | |
234 if (null == outerPanelOldSize && workareaRectangle.contains(preferredRectangle)) { | |
235 frame.pack(); | |
236 } else { | |
237 Dimension minDimension = new Dimension( | |
238 containerInsets.left + containerInsets.right, containerInsets.top + containerInsets.bottom); | |
239 if (buttonsBar != null && buttonsBar.isVisible) { | |
240 minDimension.width += buttonsBar.getWidth(); | |
241 minDimension.height += buttonsBar.getHeight(); | |
242 } | |
243 Dimension dim = new Dimension(preferredSize); | |
244 Point location = frame.getLocation(); | |
245 if ( ! isWidthChangeable) { | |
246 dim.width = frame.getWidth(); | |
247 } else { | |
248 if (isVScrollBar) dim.width += scroller.getVerticalScrollBar().getWidth(); | |
249 if (dim.width < minDimension.width) dim.width = minDimension.width; | |
250 | |
251 int dx = location.x - workareaRectangle.x; | |
252 if (dx < 0) { | |
253 dx = 0; | |
254 location.x = workareaRectangle.x; | |
255 } | |
256 int w = workareaRectangle.width - dx; | |
257 if (w < dim.width) { | |
258 int dw = dim.width - w; | |
259 if (dw < dx) { | |
260 location.x -= dw; | |
261 } else { | |
262 dim.width = workareaRectangle.width; | |
263 location.x = workareaRectangle.x; | |
264 } | |
265 } | |
266 } | |
267 if ( ! isHeightChangeable) { | |
268 dim.height = frame.getHeight(); | |
269 } else { | |
270 | |
271 if (isHScrollBar) dim.height += scroller.getHorizontalScrollBar().getHeight(); | |
272 if (dim.height < minDimension.height) dim.height = minDimension.height; | |
273 | |
274 int dy = location.y - workareaRectangle.y; | |
275 if (dy < 0) { | |
276 dy = 0; | |
277 location.y = workareaRectangle.y; | |
278 } | |
279 int h = workareaRectangle.height - dy; | |
280 if (h < dim.height) { | |
281 int dh = dim.height - h; | |
282 if (dh < dy) { | |
283 location.y -= dh; | |
284 } else { | |
285 dim.height = workareaRectangle.height; | |
286 location.y = workareaRectangle.y; | |
287 } | |
288 } | |
289 } | |
290 if ( ! location.equals(frame.getLocation())) { | |
291 frame.setLocation(location); | |
292 } | |
293 if ( ! isFullScreen ) { | |
294 frame.setSize(dim); | |
295 } | |
296 } | |
297 scroller.revalidate(); | |
298 } | |
299 | |
300 private Rectangle getWorkareaRectangle() { | |
301 final GraphicsConfiguration graphicsConfiguration = frame.getGraphicsConfiguration(); | |
302 final Rectangle screenBounds = graphicsConfiguration.getBounds(); | |
303 final Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(graphicsConfiguration); | |
304 | |
305 screenBounds.x += screenInsets.left; | |
306 screenBounds.y += screenInsets.top; | |
307 screenBounds.width -= screenInsets.left + screenInsets.right; | |
308 screenBounds.height -= screenInsets.top + screenInsets.bottom; | |
309 return screenBounds; | |
310 } | |
311 | |
312 void addZoomButtons() { | |
313 buttonsBar.createStrut(); | |
314 zoomOutButton = buttonsBar.createButton("zoom-out", "Zoom Out", new ActionListener() { | |
315 @Override | |
316 public void actionPerformed(ActionEvent e) { | |
317 zoomFitButton.setSelected(false); | |
318 uiSettings.zoomOut(); | |
319 } | |
320 }); | |
321 zoomInButton = buttonsBar.createButton("zoom-in", "Zoom In", new ActionListener() { | |
322 @Override | |
323 public void actionPerformed(ActionEvent e) { | |
324 zoomFitButton.setSelected(false); | |
325 uiSettings.zoomIn(); | |
326 } | |
327 }); | |
328 zoomAsIsButton = buttonsBar.createButton("zoom-100", "Zoom 100%", new ActionListener() { | |
329 @Override | |
330 public void actionPerformed(ActionEvent e) { | |
331 zoomFitButton.setSelected(false); | |
332 forceResizable = false; | |
333 uiSettings.zoomAsIs(); | |
334 } | |
335 }); | |
336 | |
337 zoomFitButton = buttonsBar.createToggleButton("zoom-fit", "Zoom to Fit Window", | |
338 new ItemListener() { | |
339 @Override | |
340 public void itemStateChanged(ItemEvent e) { | |
341 if (e.getStateChange() == ItemEvent.SELECTED) { | |
342 setZoomToFitSelected(true); | |
343 forceResizable = true; | |
344 zoomToFit(); | |
345 updateZoomButtonsState(); | |
346 } else { | |
347 setZoomToFitSelected(false); | |
348 } | |
349 setSurfaceToHandleKbdFocus(); | |
350 } | |
351 }); | |
352 | |
353 zoomFullScreenButton = buttonsBar.createToggleButton("zoom-fullscreen", "Full Screen", | |
354 new ItemListener() { | |
355 @Override | |
356 public void itemStateChanged(ItemEvent e) { | |
357 updateZoomButtonsState(); | |
358 if (e.getStateChange() == ItemEvent.SELECTED) { | |
359 uiSettings.setFullScreen(switchOnFullscreenMode()); | |
360 } else { | |
361 switchOffFullscreenMode(); | |
362 uiSettings.setFullScreen(false); | |
363 } | |
364 setSurfaceToHandleKbdFocus(); | |
365 } | |
366 }); | |
367 if ( ! isSeparateFrame) { | |
368 zoomFullScreenButton.setEnabled(false); | |
369 zoomFitButton.setEnabled(false); | |
370 } | |
371 } | |
372 | |
373 protected void setSurfaceToHandleKbdFocus() { | |
374 if (surface != null && ! surface.requestFocusInWindow()) { | |
375 surface.requestFocus(); | |
376 } | |
377 } | |
378 | |
379 boolean switchOnFullscreenMode() { | |
380 zoomFullScreenButton.setSelected(true); | |
381 oldContainerBounds = frame.getBounds(); | |
382 setButtonsBarVisible(false); | |
383 forceResizable = true; | |
384 frame.dispose(); | |
385 frame.setUndecorated(true); | |
386 frame.setResizable(false); | |
387 frame.setVisible(true); | |
388 try { | |
389 frame.getGraphicsConfiguration().getDevice().setFullScreenWindow(frame); | |
390 isFullScreen = true; | |
391 scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); | |
392 scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); | |
393 oldScrollerBorder = scroller.getBorder(); | |
394 scroller.setBorder(new EmptyBorder(0, 0, 0, 0)); | |
395 new FullscreenBorderDetectionThread(frame).start(); | |
396 } catch (Exception ex) { | |
397 Logger.getLogger(this.getClass().getName()).info("Cannot switch into FullScreen mode: " + ex.getMessage()); | |
398 return false; | |
399 } | |
400 return true; | |
401 } | |
402 | |
403 private void switchOffFullscreenMode() { | |
404 if (isFullScreen) { | |
405 zoomFullScreenButton.setSelected(false); | |
406 isFullScreen = false; | |
407 setButtonsBarVisible(true); | |
408 try { | |
409 frame.dispose(); | |
410 frame.setUndecorated(false); | |
411 frame.setResizable(true); | |
412 frame.getGraphicsConfiguration().getDevice().setFullScreenWindow(null); | |
413 } catch (Exception e) { | |
414 // nop | |
415 } | |
416 scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); | |
417 scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); | |
418 scroller.setBorder(oldScrollerBorder); | |
419 this.frame.setBounds(oldContainerBounds); | |
420 frame.setVisible(true); | |
421 pack(); | |
422 } | |
423 } | |
424 | |
425 private void zoomToFit() { | |
426 Dimension scrollerSize = scroller.getSize(); | |
427 Insets scrollerInsets = scroller.getInsets(); | |
428 uiSettings.zoomToFit(scrollerSize.width - scrollerInsets.left - scrollerInsets.right, | |
429 scrollerSize.height - scrollerInsets.top - scrollerInsets.bottom + | |
430 (isFullScreen ? buttonsBar.getHeight() : 0), | |
431 workingProtocol.getFbWidth(), workingProtocol.getFbHeight()); | |
432 } | |
433 | |
434 void registerResizeListener(Container container) { | |
435 container.addComponentListener(new ComponentAdapter() { | |
436 @Override | |
437 public void componentResized(ComponentEvent e) { | |
438 if (isZoomToFitSelected()) { | |
439 zoomToFit(); | |
440 updateZoomButtonsState(); | |
441 updateWindowTitle(); | |
442 setSurfaceToHandleKbdFocus(); | |
443 } | |
444 } | |
445 }); | |
446 } | |
447 | |
448 void updateZoomButtonsState() { | |
449 zoomOutButton.setEnabled(uiSettings.getScalePercent() > UiSettings.MIN_SCALE_PERCENT); | |
450 zoomInButton.setEnabled(uiSettings.getScalePercent() < UiSettings.MAX_SCALE_PERCENT); | |
451 zoomAsIsButton.setEnabled(uiSettings.getScalePercent() != 100); | |
452 } | |
453 | |
454 public ButtonsBar createButtonsBar() { | |
455 buttonsBar = new ButtonsBar(); | |
456 return buttonsBar; | |
457 } | |
458 | |
459 public void setButtonsBarVisible(boolean isVisible) { | |
460 setButtonsBarVisible(isVisible, frame); | |
461 } | |
462 | |
463 private void setButtonsBarVisible(boolean isVisible, Container container) { | |
464 buttonsBar.setVisible(isVisible); | |
465 if (isVisible) { | |
466 buttonsBar.borderOff(); | |
467 container.add(buttonsBar.bar, BorderLayout.NORTH); | |
468 container.validate(); | |
469 } else { | |
470 container.remove(buttonsBar.bar); | |
471 buttonsBar.borderOn(); | |
472 } | |
473 } | |
474 | |
475 public void setButtonsBarVisibleFS(boolean isVisible) { | |
476 if (isVisible) { | |
477 if ( ! buttonsBar.isVisible) { | |
478 lpane.add(buttonsBar.bar, JLayeredPane.POPUP_LAYER, 0); | |
479 final int bbWidth = buttonsBar.bar.getPreferredSize().width; | |
480 buttonsBar.bar.setBounds( | |
481 scroller.getViewport().getViewPosition().x + (scroller.getWidth() - bbWidth)/2, 0, | |
482 bbWidth, buttonsBar.bar.getPreferredSize().height); | |
483 | |
484 // prevent mouse events to through down to Surface | |
485 if (null == buttonsBarMouseAdapter) buttonsBarMouseAdapter = new EmptyButtonsBarMouseAdapter(); | |
486 buttonsBar.bar.addMouseListener(buttonsBarMouseAdapter); | |
487 } | |
488 } else { | |
489 buttonsBar.bar.removeMouseListener(buttonsBarMouseAdapter); | |
490 lpane.remove(buttonsBar.bar); | |
491 lpane.repaint(buttonsBar.bar.getBounds()); | |
492 } | |
493 buttonsBar.setVisible(isVisible); | |
494 } | |
495 | |
496 public Surface getSurface() { | |
497 return surface; | |
498 } | |
499 | |
500 void close() { | |
501 if (isSeparateFrame && frame != null) { | |
502 frame.setVisible(false); | |
503 frame.dispose(); | |
504 } | |
505 } | |
506 | |
507 public static class ButtonsBar { | |
508 private static final Insets BUTTONS_MARGIN = new Insets(2, 2, 2, 2); | |
509 private JPanel bar; | |
510 private boolean isVisible; | |
511 | |
512 public ButtonsBar() { | |
513 bar = new JPanel(new FlowLayout(FlowLayout.LEFT, 4, 1)); | |
514 } | |
515 | |
516 public JButton createButton(String iconId, String tooltipText, ActionListener actionListener) { | |
517 JButton button = new JButton(Utils.getButtonIcon(iconId)); | |
518 button.setToolTipText(tooltipText); | |
519 button.setMargin(BUTTONS_MARGIN); | |
520 bar.add(button); | |
521 button.addActionListener(actionListener); | |
522 return button; | |
523 } | |
524 | |
525 public void createStrut() { | |
526 bar.add(Box.createHorizontalStrut(10)); | |
527 } | |
528 | |
529 public JToggleButton createToggleButton(String iconId, String tooltipText, ItemListener itemListener) { | |
530 JToggleButton button = new JToggleButton(Utils.getButtonIcon(iconId)); | |
531 button.setToolTipText(tooltipText); | |
532 button.setMargin(BUTTONS_MARGIN); | |
533 bar.add(button); | |
534 button.addItemListener(itemListener); | |
535 return button; | |
536 } | |
537 | |
538 public void setVisible(boolean isVisible) { | |
539 this.isVisible = isVisible; | |
540 if (isVisible) bar.revalidate(); | |
541 } | |
542 | |
543 public int getWidth() { | |
544 return bar.getMinimumSize().width; | |
545 } | |
546 public int getHeight() { | |
547 return bar.getMinimumSize().height; | |
548 } | |
549 | |
550 public void borderOn() { | |
551 bar.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED)); | |
552 } | |
553 | |
554 public void borderOff() { | |
555 bar.setBorder(BorderFactory.createEmptyBorder()); | |
556 } | |
557 } | |
558 | |
559 private static class EmptyButtonsBarMouseAdapter extends MouseAdapter { | |
560 // empty | |
561 } | |
562 | |
563 private class FullscreenBorderDetectionThread extends Thread { | |
564 public static final int SHOW_HIDE_BUTTONS_BAR_DELAY_IN_MILLS = 700; | |
565 private final JFrame frame; | |
566 private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); | |
567 private ScheduledFuture<?> futureForShow; | |
568 private ScheduledFuture<?> futureForHide; | |
569 private Point mousePoint, oldMousePoint; | |
570 private Point viewPosition; | |
571 | |
572 public FullscreenBorderDetectionThread(JFrame frame) { | |
573 super("FS border detector"); | |
574 this.frame = frame; | |
575 } | |
576 | |
577 public void run() { | |
578 setPriority(Thread.MIN_PRIORITY); | |
579 while(isFullScreen) { | |
580 mousePoint = MouseInfo.getPointerInfo().getLocation(); | |
581 if (null == oldMousePoint) oldMousePoint = mousePoint; | |
582 SwingUtilities.convertPointFromScreen(mousePoint, frame); | |
583 viewPosition = scroller.getViewport().getViewPosition(); | |
584 processButtonsBarVisibility(); | |
585 | |
586 boolean needScrolling = processVScroll() || processHScroll(); | |
587 oldMousePoint = mousePoint; | |
588 if (needScrolling) { | |
589 cancelShowExecutor(); | |
590 setButtonsBarVisibleFS(false); | |
591 makeScrolling(viewPosition); | |
592 } | |
593 try { | |
594 Thread.sleep(100); | |
595 } catch (Exception e) { | |
596 // nop | |
597 } | |
598 } | |
599 } | |
600 | |
601 private boolean processHScroll() { | |
602 if (mousePoint.x < FS_SCROLLING_ACTIVE_BORDER) { | |
603 if (viewPosition.x > 0) { | |
604 int delta = FS_SCROLLING_ACTIVE_BORDER - mousePoint.x; | |
605 if (mousePoint.y != oldMousePoint.y) delta *= 2; // speedify scrolling on mouse moving | |
606 viewPosition.x -= delta; | |
607 if (viewPosition.x < 0) viewPosition.x = 0; | |
608 return true; | |
609 } | |
610 } else if (mousePoint.x > (frame.getWidth() - FS_SCROLLING_ACTIVE_BORDER)) { | |
611 final Rectangle viewRect = scroller.getViewport().getViewRect(); | |
612 final int right = viewRect.width + viewRect.x; | |
613 if (right < outerPanel.getSize().width) { | |
614 int delta = FS_SCROLLING_ACTIVE_BORDER - (frame.getWidth() - mousePoint.x); | |
615 if (mousePoint.y != oldMousePoint.y) delta *= 2; // speedify scrolling on mouse moving | |
616 viewPosition.x += delta; | |
617 if (viewPosition.x + viewRect.width > outerPanel.getSize().width) viewPosition.x = | |
618 outerPanel.getSize().width - viewRect.width; | |
619 return true; | |
620 } | |
621 } | |
622 return false; | |
623 } | |
624 | |
625 private boolean processVScroll() { | |
626 if (mousePoint.y < FS_SCROLLING_ACTIVE_BORDER) { | |
627 if (viewPosition.y > 0) { | |
628 int delta = FS_SCROLLING_ACTIVE_BORDER - mousePoint.y; | |
629 if (mousePoint.x != oldMousePoint.x) delta *= 2; // speedify scrolling on mouse moving | |
630 viewPosition.y -= delta; | |
631 if (viewPosition.y < 0) viewPosition.y = 0; | |
632 return true; | |
633 } | |
634 } else if (mousePoint.y > (frame.getHeight() - FS_SCROLLING_ACTIVE_BORDER)) { | |
635 final Rectangle viewRect = scroller.getViewport().getViewRect(); | |
636 final int bottom = viewRect.height + viewRect.y; | |
637 if (bottom < outerPanel.getSize().height) { | |
638 int delta = FS_SCROLLING_ACTIVE_BORDER - (frame.getHeight() - mousePoint.y); | |
639 if (mousePoint.x != oldMousePoint.x) delta *= 2; // speedify scrolling on mouse moving | |
640 viewPosition.y += delta; | |
641 if (viewPosition.y + viewRect.height > outerPanel.getSize().height) viewPosition.y = | |
642 outerPanel.getSize().height - viewRect.height; | |
643 return true; | |
644 } | |
645 } | |
646 return false; | |
647 } | |
648 | |
649 private void processButtonsBarVisibility() { | |
650 if (mousePoint.y < 1) { | |
651 cancelHideExecutor(); | |
652 // show buttons bar after delay | |
653 if (! buttonsBar.isVisible && (null == futureForShow || futureForShow.isDone())) { | |
654 futureForShow = scheduler.schedule(new Runnable() { | |
655 @Override | |
656 public void run() { | |
657 showButtonsBar(); | |
658 } | |
659 }, SHOW_HIDE_BUTTONS_BAR_DELAY_IN_MILLS, TimeUnit.MILLISECONDS); | |
660 } | |
661 } else { | |
662 cancelShowExecutor(); | |
663 } | |
664 if (buttonsBar.isVisible && mousePoint.y <= buttonsBar.getHeight()) { | |
665 cancelHideExecutor(); | |
666 } | |
667 if (buttonsBar.isVisible && mousePoint.y > buttonsBar.getHeight()) { | |
668 // hide buttons bar after delay | |
669 if (null == futureForHide || futureForHide.isDone()) { | |
670 futureForHide = scheduler.schedule(new Runnable() { | |
671 @Override | |
672 public void run() { | |
673 SwingUtilities.invokeLater(new Runnable() { | |
674 @Override | |
675 public void run() { | |
676 setButtonsBarVisibleFS(false); | |
677 SwingViewerWindow.this.frame.validate(); | |
678 } | |
679 }); | |
680 } | |
681 }, SHOW_HIDE_BUTTONS_BAR_DELAY_IN_MILLS, TimeUnit.MILLISECONDS); | |
682 } | |
683 } | |
684 } | |
685 | |
686 private void cancelHideExecutor() { | |
687 cancelExecutor(futureForHide); | |
688 } | |
689 private void cancelShowExecutor() { | |
690 cancelExecutor(futureForShow); | |
691 } | |
692 | |
693 private void cancelExecutor(ScheduledFuture<?> future) { | |
694 if (future != null && ! future.isDone()) { | |
695 future.cancel(true); | |
696 } | |
697 } | |
698 | |
699 private void makeScrolling(final Point viewPosition) { | |
700 SwingUtilities.invokeLater(new Runnable() { | |
701 @Override | |
702 public void run() { | |
703 scroller.getViewport().setViewPosition(viewPosition); | |
704 final Point mousePosition = surface.getMousePosition(); | |
705 if (mousePosition != null) { | |
706 final MouseEvent mouseEvent = new MouseEvent(frame, 0, 0, 0, | |
707 mousePosition.x, mousePosition.y, 0, false); | |
708 for (MouseMotionListener mml : surface.getMouseMotionListeners()) { | |
709 mml.mouseMoved(mouseEvent); | |
710 } | |
711 } | |
712 } | |
713 }); | |
714 } | |
715 | |
716 private void showButtonsBar() { | |
717 SwingUtilities.invokeLater(new Runnable() { | |
718 @Override | |
719 public void run() { | |
720 setButtonsBarVisibleFS(true); | |
721 } | |
722 }); | |
723 } | |
724 } | |
725 | |
726 protected void createButtonsPanel(final ProtocolContext context, Container container) { | |
727 final SwingViewerWindow.ButtonsBar buttonsBar = createButtonsBar(); | |
728 | |
729 buttonsBar.createButton("options", "Set Options", new ActionListener() { | |
730 @Override | |
731 public void actionPerformed(ActionEvent e) { | |
732 showOptionsDialog(); | |
733 setSurfaceToHandleKbdFocus(); | |
734 } | |
735 }); | |
736 | |
737 buttonsBar.createButton("info", "Show connection info", new ActionListener() { | |
738 @Override | |
739 public void actionPerformed(ActionEvent e) { | |
740 showConnectionInfoMessage(); | |
741 setSurfaceToHandleKbdFocus(); | |
742 } | |
743 }); | |
744 | |
745 buttonsBar.createStrut(); | |
746 | |
747 buttonsBar.createButton("refresh", "Refresh screen", new ActionListener() { | |
748 @Override | |
749 public void actionPerformed(ActionEvent e) { | |
750 context.sendRefreshMessage(); | |
751 setSurfaceToHandleKbdFocus(); | |
752 } | |
753 }); | |
754 | |
755 addZoomButtons(); | |
756 | |
757 kbdButtons = new LinkedList<JComponent>(); | |
758 | |
759 buttonsBar.createStrut(); | |
760 | |
761 JButton ctrlAltDelButton = buttonsBar.createButton("ctrl-alt-del", "Send 'Ctrl-Alt-Del'", new ActionListener() { | |
762 @Override | |
763 public void actionPerformed(ActionEvent e) { | |
764 sendCtrlAltDel(context); | |
765 setSurfaceToHandleKbdFocus(); | |
766 } | |
767 }); | |
768 kbdButtons.add(ctrlAltDelButton); | |
769 | |
770 JButton winButton = buttonsBar.createButton("win", "Send 'Win' key as 'Ctrl-Esc'", new ActionListener() { | |
771 @Override | |
772 public void actionPerformed(ActionEvent e) { | |
773 sendWinKey(context); | |
774 setSurfaceToHandleKbdFocus(); | |
775 } | |
776 }); | |
777 kbdButtons.add(winButton); | |
778 | |
779 JToggleButton ctrlButton = buttonsBar.createToggleButton("ctrl", "Ctrl Lock", | |
780 new ItemListener() { | |
781 @Override | |
782 public void itemStateChanged(ItemEvent e) { | |
783 if (e.getStateChange() == ItemEvent.SELECTED) { | |
784 context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, true)); | |
785 } else { | |
786 context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, false)); | |
787 } | |
788 setSurfaceToHandleKbdFocus(); | |
789 } | |
790 }); | |
791 kbdButtons.add(ctrlButton); | |
792 | |
793 JToggleButton altButton = buttonsBar.createToggleButton("alt", "Alt Lock", | |
794 new ItemListener() { | |
795 @Override | |
796 public void itemStateChanged(ItemEvent e) { | |
797 if (e.getStateChange() == ItemEvent.SELECTED) { | |
798 context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, true)); | |
799 } else { | |
800 context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, false)); | |
801 } | |
802 setSurfaceToHandleKbdFocus(); | |
803 } | |
804 }); | |
805 kbdButtons.add(altButton); | |
22
45176f732171
put protocol instance for stop SenderTask and ReceiverTask
sugi
parents:
18
diff
changeset
|
806 |
45176f732171
put protocol instance for stop SenderTask and ReceiverTask
sugi
parents:
18
diff
changeset
|
807 JButton shareButton = buttonsBar.createButton("share", "Share my screen", new ActionListener() { |
16 | 808 @Override |
809 public void actionPerformed(ActionEvent e) { | |
30
aa88409a502b
Alice update tag:work-compressedDSM
Nozomi Teruya <e125769@ie.u-ryukyu.ac.jp>
parents:
27
diff
changeset
|
810 ReceiveData rData = new ReceiveData("Request"); |
aa88409a502b
Alice update tag:work-compressedDSM
Nozomi Teruya <e125769@ie.u-ryukyu.ac.jp>
parents:
27
diff
changeset
|
811 DataSegment.getLocal().put("Request", rData, false); |
16 | 812 } |
813 }); | |
22
45176f732171
put protocol instance for stop SenderTask and ReceiverTask
sugi
parents:
18
diff
changeset
|
814 kbdButtons.add(shareButton); |
0 | 815 |
816 ModifierButtonEventListener modifierButtonListener = new ModifierButtonEventListener(); | |
817 modifierButtonListener.addButton(KeyEvent.VK_CONTROL, ctrlButton); | |
818 modifierButtonListener.addButton(KeyEvent.VK_ALT, altButton); | |
819 surface.addModifierListener(modifierButtonListener); | |
820 | |
821 // JButton fileTransferButton = new JButton(Utils.getButtonIcon("file-transfer")); | |
822 // fileTransferButton.setMargin(buttonsMargin); | |
823 // buttonBar.add(fileTransferButton); | |
824 | |
825 buttonsBar.createStrut(); | |
826 | |
827 buttonsBar.createButton("close", isApplet ? "Disconnect" : "Close", new ActionListener() { | |
828 @Override | |
829 public void actionPerformed(ActionEvent e) { | |
830 if (frame != null) { | |
831 frame.setVisible(false); | |
832 frame.dispose(); | |
833 } | |
834 presenter.setNeedReconnection(false); | |
835 presenter.cancelConnection(); | |
836 viewer.closeApp(); | |
837 } | |
838 }).setAlignmentX(JComponent.RIGHT_ALIGNMENT); | |
839 | |
840 setButtonsBarVisible(true, container); | |
841 } | |
842 | |
843 private void sendCtrlAltDel(ProtocolContext context) { | |
844 context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, true)); | |
845 context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, true)); | |
846 context.sendMessage(new KeyEventMessage(Keymap.K_DELETE, true)); | |
847 context.sendMessage(new KeyEventMessage(Keymap.K_DELETE, false)); | |
848 context.sendMessage(new KeyEventMessage(Keymap.K_ALT_LEFT, false)); | |
849 context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, false)); | |
850 } | |
851 | |
852 private void sendWinKey(ProtocolContext context) { | |
853 context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, true)); | |
854 context.sendMessage(new KeyEventMessage(Keymap.K_ESCAPE, true)); | |
855 context.sendMessage(new KeyEventMessage(Keymap.K_ESCAPE, false)); | |
856 context.sendMessage(new KeyEventMessage(Keymap.K_CTRL_LEFT, false)); | |
857 } | |
858 | |
859 @Override | |
860 public void settingsChanged(SettingsChangedEvent e) { | |
861 if (ProtocolSettings.isRfbSettingsChangedFired(e)) { | |
862 ProtocolSettings settings = (ProtocolSettings) e.getSource(); | |
863 setEnabledKbdButtons( ! settings.isViewOnly()); | |
864 } | |
865 } | |
866 | |
867 private void setEnabledKbdButtons(boolean enabled) { | |
868 if (kbdButtons != null) { | |
869 for (JComponent b : kbdButtons) { | |
870 b.setEnabled(enabled); | |
871 } | |
872 } | |
873 } | |
874 | |
875 private void showOptionsDialog() { | |
876 OptionsDialog optionsDialog = new OptionsDialog(frame); | |
877 optionsDialog.initControlsFromSettings(rfbSettings, uiSettings, false); | |
878 optionsDialog.setVisible(true); | |
879 presenter.saveHistory(); | |
880 } | |
881 | |
882 private void showConnectionInfoMessage() { | |
883 StringBuilder message = new StringBuilder(); | |
884 message.append("TightVNC Viewer v.").append(Viewer.ver()).append("\n\n"); | |
885 message.append("Connected to: ").append(remoteDesktopName).append("\n"); | |
886 message.append("Host: ").append(connectionString).append("\n\n"); | |
887 | |
888 message.append("Desktop geometry: ") | |
889 .append(String.valueOf(surface.getWidth())) | |
890 .append(" \u00D7 ") // multiplication sign | |
891 .append(String.valueOf(surface.getHeight())).append("\n"); | |
892 message.append("Color format: ") | |
893 .append(String.valueOf(Math.round(Math.pow(2, workingProtocol.getPixelFormat().depth)))) | |
894 .append(" colors (") | |
895 .append(String.valueOf(workingProtocol.getPixelFormat().depth)) | |
896 .append(" bits)\n"); | |
897 message.append("Current protocol version: ") | |
898 .append(workingProtocol.getProtocolVersion()); | |
899 if (workingProtocol.isTight()) { | |
900 message.append("tight"); | |
901 } | |
902 message.append("\n"); | |
903 | |
904 JOptionPane infoPane = new JOptionPane(message.toString(), JOptionPane.INFORMATION_MESSAGE); | |
905 final JDialog infoDialog = infoPane.createDialog(frame, "VNC connection info"); | |
906 infoDialog.setModalityType(Dialog.ModalityType.MODELESS); | |
907 infoDialog.setVisible(true); | |
24 | 908 |
0 | 909 } |
27 | 910 |
911 public void setVisible(boolean b){ | |
912 frame.setVisible(b); | |
913 } | |
0 | 914 } |