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