blob: a409af1d906657dc0a64804b3d832dd6388ecbef [file] [log] [blame]
Constantin Kaplinsky2844fd52008-04-14 08:02:25 +00001//
2// Copyright (C) 2001 HorizonLive.com, Inc. All Rights Reserved.
3// Copyright (C) 2001 Constantin Kaplinsky. All Rights Reserved.
4// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
5// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
6//
7// This is free software; you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (at your option) any later version.
11//
12// This software is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this software; if not, write to the Free Software
19// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20// USA.
21//
22
23//
24// Options frame.
25//
26// This deals with all the options the user can play with.
27// It sets the encodings array and some booleans.
28//
29
Constantin Kaplinsky90d8a502008-04-14 09:45:50 +000030package com.tightvnc.vncviewer;
31
Constantin Kaplinsky2844fd52008-04-14 08:02:25 +000032import java.awt.*;
33import java.awt.event.*;
34
35class OptionsFrame extends Frame
36 implements WindowListener, ActionListener, ItemListener {
37
38 static String[] names = {
39 "Encoding",
40 "Compression level",
41 "JPEG image quality",
42 "Cursor shape updates",
43 "Use CopyRect",
44 "Continuous updates",
45 "Restricted colors",
46 "Mouse buttons 2 and 3",
47 "View only",
48 "Scale remote cursor",
49 "Share desktop",
50 };
51
52 static String[][] values = {
53 { "Auto", "Raw", "RRE", "CoRRE", "Hextile", "Zlib", "Tight", "ZRLE" },
54 { "Default", "1", "2", "3", "4", "5", "6", "7", "8", "9" },
55 { "JPEG off", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" },
56 { "Enable", "Ignore", "Disable" },
57 { "Yes", "No" },
58 { "Yes", "No" },
59 { "Yes", "No" },
60 { "Normal", "Reversed" },
61 { "Yes", "No" },
62 { "No", "50%", "75%", "125%", "150%" },
63 { "Yes", "No" },
64 };
65
66 final int
67 encodingIndex = 0,
68 compressLevelIndex = 1,
69 jpegQualityIndex = 2,
70 cursorUpdatesIndex = 3,
71 useCopyRectIndex = 4,
72 contUpdatesIndex = 5,
73 eightBitColorsIndex = 6,
74 mouseButtonIndex = 7,
75 viewOnlyIndex = 8,
76 scaleCursorIndex = 9,
77 shareDesktopIndex = 10;
78
79 Label[] labels = new Label[names.length];
80 Choice[] choices = new Choice[names.length];
81 Button closeButton;
82 VncViewer viewer;
83
84
85 //
86 // The actual data which other classes look at:
87 //
88
89 int preferredEncoding;
90 int compressLevel;
91 int jpegQuality;
92 boolean useCopyRect;
93 boolean continuousUpdates;
94 boolean requestCursorUpdates;
95 boolean ignoreCursorUpdates;
96
97 boolean eightBitColors;
98
99 boolean reverseMouseButtons2And3;
100 boolean shareDesktop;
101 boolean viewOnly;
102 int scaleCursor;
103
104 boolean autoScale;
105 int scalingFactor;
106
107 //
108 // Constructor. Set up the labels and choices from the names and values
109 // arrays.
110 //
111
112 OptionsFrame(VncViewer v) {
113 super("TightVNC Options");
114
115 viewer = v;
116
117 GridBagLayout gridbag = new GridBagLayout();
118 setLayout(gridbag);
119
120 GridBagConstraints gbc = new GridBagConstraints();
121 gbc.fill = GridBagConstraints.BOTH;
122
123 for (int i = 0; i < names.length; i++) {
124 labels[i] = new Label(names[i]);
125 gbc.gridwidth = 1;
126 gridbag.setConstraints(labels[i],gbc);
127 add(labels[i]);
128
129 choices[i] = new Choice();
130 gbc.gridwidth = GridBagConstraints.REMAINDER;
131 gridbag.setConstraints(choices[i],gbc);
132 add(choices[i]);
133 choices[i].addItemListener(this);
134
135 for (int j = 0; j < values[i].length; j++) {
136 choices[i].addItem(values[i][j]);
137 }
138 }
139
140 closeButton = new Button("Close");
141 gbc.gridwidth = GridBagConstraints.REMAINDER;
142 gridbag.setConstraints(closeButton, gbc);
143 add(closeButton);
144 closeButton.addActionListener(this);
145
146 pack();
147
148 addWindowListener(this);
149
150 // Set up defaults
151
152 choices[encodingIndex].select("Auto");
153 choices[compressLevelIndex].select("Default");
154 choices[jpegQualityIndex].select("6");
155 choices[cursorUpdatesIndex].select("Enable");
156 choices[useCopyRectIndex].select("Yes");
157 choices[contUpdatesIndex].select("No");
158 choices[eightBitColorsIndex].select("No");
159 choices[mouseButtonIndex].select("Normal");
160 choices[viewOnlyIndex].select("No");
161 choices[scaleCursorIndex].select("No");
162 choices[shareDesktopIndex].select("Yes");
163
164 // But let them be overridden by parameters
165
166 for (int i = 0; i < names.length; i++) {
167 String s = viewer.readParameter(names[i], false);
168 if (s != null) {
169 for (int j = 0; j < values[i].length; j++) {
170 if (s.equalsIgnoreCase(values[i][j])) {
171 choices[i].select(j);
172 }
173 }
174 }
175 }
176
177 // FIXME: Provide some sort of GUI for "Scaling Factor".
178
179 autoScale = false;
180 scalingFactor = 100;
181 String s = viewer.readParameter("Scaling Factor", false);
182 if (s != null) {
183 if (s.equalsIgnoreCase("Auto")) {
184 autoScale = true;
185 } else {
186 // Remove the '%' char at the end of string if present.
187 if (s.charAt(s.length() - 1) == '%') {
188 s = s.substring(0, s.length() - 1);
189 }
190 // Convert to an integer.
191 try {
192 scalingFactor = Integer.parseInt(s);
193 }
194 catch (NumberFormatException e) {
195 scalingFactor = 100;
196 }
197 // Make sure scalingFactor is in the range of [1..1000].
198 if (scalingFactor < 1) {
199 scalingFactor = 1;
200 } else if (scalingFactor > 1000) {
201 scalingFactor = 1000;
202 }
203 }
204 }
205
206 // Make the booleans and encodings array correspond to the state of the GUI
207
208 setEncodings();
209 setColorFormat();
210 setContinuousUpdates();
211 setOtherOptions();
212 }
213
214
215 //
216 // Disable the shareDesktop option
217 //
218
219 void disableShareDesktop() {
220 labels[shareDesktopIndex].setEnabled(false);
221 choices[shareDesktopIndex].setEnabled(false);
222 }
223
224
225 //
226 // Disable the "Continuous updates" option. This method is called
227 // when we figure out that the server does not support corresponding
228 // protocol extensions.
229 //
230
231 void disableContUpdates() {
232 labels[contUpdatesIndex].setEnabled(false);
233 choices[contUpdatesIndex].setEnabled(false);
234 choices[contUpdatesIndex].select("No");
235 continuousUpdates = false;
236 }
237
238
239 //
240 // setEncodings looks at the encoding, compression level, JPEG
241 // quality level, cursor shape updates and copyRect choices and sets
242 // corresponding variables properly. Then it calls the VncViewer's
243 // setEncodings method to send a SetEncodings message to the RFB
244 // server.
245 //
246
247 void setEncodings() {
248 useCopyRect = choices[useCopyRectIndex].getSelectedItem().equals("Yes");
249
250 preferredEncoding = RfbProto.EncodingRaw;
251 boolean enableCompressLevel = false;
252 boolean enableQualityLevel = false;
253
254 if (choices[encodingIndex].getSelectedItem().equals("RRE")) {
255 preferredEncoding = RfbProto.EncodingRRE;
256 } else if (choices[encodingIndex].getSelectedItem().equals("CoRRE")) {
257 preferredEncoding = RfbProto.EncodingCoRRE;
258 } else if (choices[encodingIndex].getSelectedItem().equals("Hextile")) {
259 preferredEncoding = RfbProto.EncodingHextile;
260 } else if (choices[encodingIndex].getSelectedItem().equals("ZRLE")) {
261 preferredEncoding = RfbProto.EncodingZRLE;
262 } else if (choices[encodingIndex].getSelectedItem().equals("Zlib")) {
263 preferredEncoding = RfbProto.EncodingZlib;
264 enableCompressLevel = true;
265 } else if (choices[encodingIndex].getSelectedItem().equals("Tight")) {
266 preferredEncoding = RfbProto.EncodingTight;
267 enableCompressLevel = true;
268 enableQualityLevel = !eightBitColors;
269 } else if (choices[encodingIndex].getSelectedItem().equals("Auto")) {
270 preferredEncoding = -1;
271 enableQualityLevel = !eightBitColors;
272 }
273
274 // Handle compression level setting.
275
276 try {
277 compressLevel =
278 Integer.parseInt(choices[compressLevelIndex].getSelectedItem());
279 }
280 catch (NumberFormatException e) {
281 compressLevel = -1;
282 }
283 if (compressLevel < 1 || compressLevel > 9) {
284 compressLevel = -1;
285 }
286 labels[compressLevelIndex].setEnabled(enableCompressLevel);
287 choices[compressLevelIndex].setEnabled(enableCompressLevel);
288
289 // Handle JPEG quality setting.
290
291 try {
292 jpegQuality =
293 Integer.parseInt(choices[jpegQualityIndex].getSelectedItem());
294 }
295 catch (NumberFormatException e) {
296 jpegQuality = -1;
297 }
298 if (jpegQuality < 0 || jpegQuality > 9) {
299 jpegQuality = -1;
300 }
301 labels[jpegQualityIndex].setEnabled(enableQualityLevel);
302 choices[jpegQualityIndex].setEnabled(enableQualityLevel);
303
304 // Request cursor shape updates if necessary.
305
306 requestCursorUpdates =
307 !choices[cursorUpdatesIndex].getSelectedItem().equals("Disable");
308
309 if (requestCursorUpdates) {
310 ignoreCursorUpdates =
311 choices[cursorUpdatesIndex].getSelectedItem().equals("Ignore");
312 }
313
314 viewer.setEncodings();
315 }
316
317 //
318 // setColorFormat sets eightBitColors variable depending on the GUI
319 // setting, causing switches between 8-bit and 24-bit colors mode if
320 // necessary.
321 //
322
323 void setColorFormat() {
324
325 eightBitColors =
326 choices[eightBitColorsIndex].getSelectedItem().equals("Yes");
327
328 boolean enableJPEG = !eightBitColors &&
329 (choices[encodingIndex].getSelectedItem().equals("Tight") ||
330 choices[encodingIndex].getSelectedItem().equals("Auto"));
331
332 labels[jpegQualityIndex].setEnabled(enableJPEG);
333 choices[jpegQualityIndex].setEnabled(enableJPEG);
334 }
335
336 //
337 // setContinuousUpdates sets continuousUpdates variable depending on
338 // the GUI setting. VncViewer monitors the state of this variable and
339 // send corresponding protocol messages to the server when necessary.
340 //
341
342 void setContinuousUpdates() {
343
344 continuousUpdates =
345 choices[contUpdatesIndex].getSelectedItem().equals("Yes");
346 }
347
348 //
349 // setOtherOptions looks at the "other" choices (ones that do not
350 // cause sending any protocol messages) and sets the boolean flags
351 // appropriately.
352 //
353
354 void setOtherOptions() {
355
356 reverseMouseButtons2And3
357 = choices[mouseButtonIndex].getSelectedItem().equals("Reversed");
358
359 viewOnly
360 = choices[viewOnlyIndex].getSelectedItem().equals("Yes");
361 if (viewer.vc != null)
362 viewer.vc.enableInput(!viewOnly);
363
364 shareDesktop
365 = choices[shareDesktopIndex].getSelectedItem().equals("Yes");
366
367 String scaleString = choices[scaleCursorIndex].getSelectedItem();
368 if (scaleString.endsWith("%"))
369 scaleString = scaleString.substring(0, scaleString.length() - 1);
370 try {
371 scaleCursor = Integer.parseInt(scaleString);
372 }
373 catch (NumberFormatException e) {
374 scaleCursor = 0;
375 }
376 if (scaleCursor < 10 || scaleCursor > 500) {
377 scaleCursor = 0;
378 }
379 if (requestCursorUpdates && !ignoreCursorUpdates && !viewOnly) {
380 labels[scaleCursorIndex].setEnabled(true);
381 choices[scaleCursorIndex].setEnabled(true);
382 } else {
383 labels[scaleCursorIndex].setEnabled(false);
384 choices[scaleCursorIndex].setEnabled(false);
385 }
386 if (viewer.vc != null)
387 viewer.vc.createSoftCursor(); // update cursor scaling
388 }
389
390
391 //
392 // Respond to actions on Choice controls
393 //
394
395 public void itemStateChanged(ItemEvent evt) {
396 Object source = evt.getSource();
397
398 if (source == choices[encodingIndex] ||
399 source == choices[compressLevelIndex] ||
400 source == choices[jpegQualityIndex] ||
401 source == choices[cursorUpdatesIndex] ||
402 source == choices[useCopyRectIndex]) {
403
404 setEncodings();
405
406 if (source == choices[cursorUpdatesIndex]) {
407 setOtherOptions(); // update scaleCursor state
408 }
409
410 } else if (source == choices[eightBitColorsIndex]) {
411
412 setColorFormat();
413
414 } else if (source == choices[contUpdatesIndex]) {
415
416 setContinuousUpdates();
417
418 } else if (source == choices[mouseButtonIndex] ||
419 source == choices[shareDesktopIndex] ||
420 source == choices[viewOnlyIndex] ||
421 source == choices[scaleCursorIndex]) {
422
423 setOtherOptions();
424
425 }
426 }
427
428 //
429 // Respond to button press
430 //
431
432 public void actionPerformed(ActionEvent evt) {
433 if (evt.getSource() == closeButton)
434 setVisible(false);
435 }
436
437 //
438 // Respond to window events
439 //
440
441 public void windowClosing(WindowEvent evt) {
442 setVisible(false);
443 }
444
445 public void windowActivated(WindowEvent evt) {}
446 public void windowDeactivated(WindowEvent evt) {}
447 public void windowOpened(WindowEvent evt) {}
448 public void windowClosed(WindowEvent evt) {}
449 public void windowIconified(WindowEvent evt) {}
450 public void windowDeiconified(WindowEvent evt) {}
451}