You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

OptionsDialog.cxx 32KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069
  1. /* Copyright 2011-2021 Pierre Ossman <ossman@cendio.se> for Cendio AB
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include <config.h>
  20. #endif
  21. #include <assert.h>
  22. #include <stdlib.h>
  23. #include <list>
  24. #include <rdr/types.h>
  25. #include <rfb/encodings.h>
  26. #ifdef HAVE_GNUTLS
  27. #include <rfb/Security.h>
  28. #include <rfb/SecurityClient.h>
  29. #include <rfb/CSecurityTLS.h>
  30. #endif
  31. #include "OptionsDialog.h"
  32. #include "fltk_layout.h"
  33. #include "i18n.h"
  34. #include "menukey.h"
  35. #include "parameters.h"
  36. #include "MonitorArrangement.h"
  37. #include <FL/Fl.H>
  38. #include <FL/Fl_Tabs.H>
  39. #include <FL/Fl_Button.H>
  40. #include <FL/Fl_Check_Button.H>
  41. #include <FL/Fl_Return_Button.H>
  42. #include <FL/Fl_Round_Button.H>
  43. #include <FL/Fl_Int_Input.H>
  44. #include <FL/Fl_Choice.H>
  45. using namespace std;
  46. using namespace rdr;
  47. using namespace rfb;
  48. std::map<OptionsCallback*, void*> OptionsDialog::callbacks;
  49. static std::set<OptionsDialog *> instances;
  50. OptionsDialog::OptionsDialog()
  51. : Fl_Window(450, 460, _("VNC Viewer: Connection Options"))
  52. {
  53. int x, y;
  54. Fl_Button *button;
  55. Fl_Tabs *tabs = new Fl_Tabs(OUTER_MARGIN, OUTER_MARGIN,
  56. w() - OUTER_MARGIN*2,
  57. h() - OUTER_MARGIN*2 - INNER_MARGIN - BUTTON_HEIGHT);
  58. {
  59. int tx, ty, tw, th;
  60. tabs->client_area(tx, ty, tw, th, TABS_HEIGHT);
  61. createCompressionPage(tx, ty, tw, th);
  62. createSecurityPage(tx, ty, tw, th);
  63. createInputPage(tx, ty, tw, th);
  64. createDisplayPage(tx, ty, tw, th);
  65. createMiscPage(tx, ty, tw, th);
  66. }
  67. tabs->end();
  68. x = w() - BUTTON_WIDTH * 2 - INNER_MARGIN - OUTER_MARGIN;
  69. y = h() - BUTTON_HEIGHT - OUTER_MARGIN;
  70. button = new Fl_Button(x, y, BUTTON_WIDTH, BUTTON_HEIGHT, _("Cancel"));
  71. button->callback(this->handleCancel, this);
  72. x += BUTTON_WIDTH + INNER_MARGIN;
  73. button = new Fl_Return_Button(x, y, BUTTON_WIDTH, BUTTON_HEIGHT, _("OK"));
  74. button->callback(this->handleOK, this);
  75. callback(this->handleCancel, this);
  76. set_modal();
  77. if (instances.size() == 0)
  78. Fl::add_handler(fltk_event_handler);
  79. instances.insert(this);
  80. }
  81. OptionsDialog::~OptionsDialog()
  82. {
  83. instances.erase(this);
  84. if (instances.size() == 0)
  85. Fl::remove_handler(fltk_event_handler);
  86. }
  87. void OptionsDialog::showDialog(void)
  88. {
  89. static OptionsDialog *dialog = NULL;
  90. if (!dialog)
  91. dialog = new OptionsDialog();
  92. if (dialog->shown())
  93. return;
  94. dialog->show();
  95. }
  96. void OptionsDialog::addCallback(OptionsCallback *cb, void *data)
  97. {
  98. callbacks[cb] = data;
  99. }
  100. void OptionsDialog::removeCallback(OptionsCallback *cb)
  101. {
  102. callbacks.erase(cb);
  103. }
  104. void OptionsDialog::show(void)
  105. {
  106. /* show() gets called for raise events as well */
  107. if (!shown())
  108. loadOptions();
  109. Fl_Window::show();
  110. }
  111. void OptionsDialog::loadOptions(void)
  112. {
  113. /* Compression */
  114. autoselectCheckbox->value(autoSelect);
  115. int encNum = encodingNum(preferredEncoding);
  116. switch (encNum) {
  117. case encodingTight:
  118. tightButton->setonly();
  119. break;
  120. case encodingZRLE:
  121. zrleButton->setonly();
  122. break;
  123. case encodingHextile:
  124. hextileButton->setonly();
  125. break;
  126. case encodingRaw:
  127. rawButton->setonly();
  128. break;
  129. }
  130. if (fullColour)
  131. fullcolorCheckbox->setonly();
  132. else {
  133. switch (lowColourLevel) {
  134. case 0:
  135. verylowcolorCheckbox->setonly();
  136. break;
  137. case 1:
  138. lowcolorCheckbox->setonly();
  139. break;
  140. case 2:
  141. mediumcolorCheckbox->setonly();
  142. break;
  143. }
  144. }
  145. char digit[2] = "0";
  146. compressionCheckbox->value(customCompressLevel);
  147. jpegCheckbox->value(!noJpeg);
  148. digit[0] = '0' + compressLevel;
  149. compressionInput->value(digit);
  150. digit[0] = '0' + qualityLevel;
  151. jpegInput->value(digit);
  152. handleAutoselect(autoselectCheckbox, this);
  153. handleCompression(compressionCheckbox, this);
  154. handleJpeg(jpegCheckbox, this);
  155. #ifdef HAVE_GNUTLS
  156. /* Security */
  157. Security security(SecurityClient::secTypes);
  158. list<U8> secTypes;
  159. list<U8>::iterator iter;
  160. list<U32> secTypesExt;
  161. list<U32>::iterator iterExt;
  162. encNoneCheckbox->value(false);
  163. encTLSCheckbox->value(false);
  164. encX509Checkbox->value(false);
  165. authNoneCheckbox->value(false);
  166. authVncCheckbox->value(false);
  167. authPlainCheckbox->value(false);
  168. secTypes = security.GetEnabledSecTypes();
  169. for (iter = secTypes.begin(); iter != secTypes.end(); ++iter) {
  170. switch (*iter) {
  171. case secTypeNone:
  172. encNoneCheckbox->value(true);
  173. authNoneCheckbox->value(true);
  174. break;
  175. case secTypeVncAuth:
  176. encNoneCheckbox->value(true);
  177. authVncCheckbox->value(true);
  178. break;
  179. }
  180. }
  181. secTypesExt = security.GetEnabledExtSecTypes();
  182. for (iterExt = secTypesExt.begin(); iterExt != secTypesExt.end(); ++iterExt) {
  183. switch (*iterExt) {
  184. case secTypePlain:
  185. encNoneCheckbox->value(true);
  186. authPlainCheckbox->value(true);
  187. break;
  188. case secTypeTLSNone:
  189. encTLSCheckbox->value(true);
  190. authNoneCheckbox->value(true);
  191. break;
  192. case secTypeTLSVnc:
  193. encTLSCheckbox->value(true);
  194. authVncCheckbox->value(true);
  195. break;
  196. case secTypeTLSPlain:
  197. encTLSCheckbox->value(true);
  198. authPlainCheckbox->value(true);
  199. break;
  200. case secTypeX509None:
  201. encX509Checkbox->value(true);
  202. authNoneCheckbox->value(true);
  203. break;
  204. case secTypeX509Vnc:
  205. encX509Checkbox->value(true);
  206. authVncCheckbox->value(true);
  207. break;
  208. case secTypeX509Plain:
  209. encX509Checkbox->value(true);
  210. authPlainCheckbox->value(true);
  211. break;
  212. }
  213. }
  214. caInput->value(CSecurityTLS::X509CA);
  215. crlInput->value(CSecurityTLS::X509CRL);
  216. handleX509(encX509Checkbox, this);
  217. #endif
  218. /* Input */
  219. const char *menuKeyBuf;
  220. viewOnlyCheckbox->value(viewOnly);
  221. emulateMBCheckbox->value(emulateMiddleButton);
  222. acceptClipboardCheckbox->value(acceptClipboard);
  223. #if !defined(WIN32) && !defined(__APPLE__)
  224. setPrimaryCheckbox->value(setPrimary);
  225. #endif
  226. sendClipboardCheckbox->value(sendClipboard);
  227. #if !defined(WIN32) && !defined(__APPLE__)
  228. sendPrimaryCheckbox->value(sendPrimary);
  229. #endif
  230. systemKeysCheckbox->value(fullscreenSystemKeys);
  231. menuKeyChoice->value(0);
  232. menuKeyBuf = menuKey;
  233. for (int i = 0; i < getMenuKeySymbolCount(); i++)
  234. if (!strcmp(getMenuKeySymbols()[i].name, menuKeyBuf))
  235. menuKeyChoice->value(i + 1);
  236. /* Display */
  237. if (!fullScreen) {
  238. windowedButton->setonly();
  239. } else {
  240. if (!strcasecmp(fullScreenMode, "all")) {
  241. allMonitorsButton->setonly();
  242. } else if (!strcasecmp(fullScreenMode, "selected")) {
  243. selectedMonitorsButton->setonly();
  244. } else {
  245. currentMonitorButton->setonly();
  246. }
  247. }
  248. monitorArrangement->set(fullScreenSelectedMonitors.getParam());
  249. handleFullScreenMode(selectedMonitorsButton, this);
  250. /* Misc. */
  251. sharedCheckbox->value(shared);
  252. reconnectCheckbox->value(reconnectOnError);
  253. dotCursorCheckbox->value(dotWhenNoCursor);
  254. }
  255. void OptionsDialog::storeOptions(void)
  256. {
  257. /* Compression */
  258. autoSelect.setParam(autoselectCheckbox->value());
  259. if (tightButton->value())
  260. preferredEncoding.setParam(encodingName(encodingTight));
  261. else if (zrleButton->value())
  262. preferredEncoding.setParam(encodingName(encodingZRLE));
  263. else if (hextileButton->value())
  264. preferredEncoding.setParam(encodingName(encodingHextile));
  265. else if (rawButton->value())
  266. preferredEncoding.setParam(encodingName(encodingRaw));
  267. fullColour.setParam(fullcolorCheckbox->value());
  268. if (verylowcolorCheckbox->value())
  269. lowColourLevel.setParam(0);
  270. else if (lowcolorCheckbox->value())
  271. lowColourLevel.setParam(1);
  272. else if (mediumcolorCheckbox->value())
  273. lowColourLevel.setParam(2);
  274. customCompressLevel.setParam(compressionCheckbox->value());
  275. noJpeg.setParam(!jpegCheckbox->value());
  276. compressLevel.setParam(atoi(compressionInput->value()));
  277. qualityLevel.setParam(atoi(jpegInput->value()));
  278. #ifdef HAVE_GNUTLS
  279. /* Security */
  280. Security security;
  281. /* Process security types which don't use encryption */
  282. if (encNoneCheckbox->value()) {
  283. if (authNoneCheckbox->value())
  284. security.EnableSecType(secTypeNone);
  285. if (authVncCheckbox->value())
  286. security.EnableSecType(secTypeVncAuth);
  287. if (authPlainCheckbox->value())
  288. security.EnableSecType(secTypePlain);
  289. }
  290. /* Process security types which use TLS encryption */
  291. if (encTLSCheckbox->value()) {
  292. if (authNoneCheckbox->value())
  293. security.EnableSecType(secTypeTLSNone);
  294. if (authVncCheckbox->value())
  295. security.EnableSecType(secTypeTLSVnc);
  296. if (authPlainCheckbox->value())
  297. security.EnableSecType(secTypeTLSPlain);
  298. }
  299. /* Process security types which use X509 encryption */
  300. if (encX509Checkbox->value()) {
  301. if (authNoneCheckbox->value())
  302. security.EnableSecType(secTypeX509None);
  303. if (authVncCheckbox->value())
  304. security.EnableSecType(secTypeX509Vnc);
  305. if (authPlainCheckbox->value())
  306. security.EnableSecType(secTypeX509Plain);
  307. }
  308. SecurityClient::secTypes.setParam(security.ToString());
  309. CSecurityTLS::X509CA.setParam(caInput->value());
  310. CSecurityTLS::X509CRL.setParam(crlInput->value());
  311. #endif
  312. /* Input */
  313. viewOnly.setParam(viewOnlyCheckbox->value());
  314. emulateMiddleButton.setParam(emulateMBCheckbox->value());
  315. acceptClipboard.setParam(acceptClipboardCheckbox->value());
  316. #if !defined(WIN32) && !defined(__APPLE__)
  317. setPrimary.setParam(setPrimaryCheckbox->value());
  318. #endif
  319. sendClipboard.setParam(sendClipboardCheckbox->value());
  320. #if !defined(WIN32) && !defined(__APPLE__)
  321. sendPrimary.setParam(sendPrimaryCheckbox->value());
  322. #endif
  323. fullscreenSystemKeys.setParam(systemKeysCheckbox->value());
  324. if (menuKeyChoice->value() == 0)
  325. menuKey.setParam("");
  326. else {
  327. menuKey.setParam(menuKeyChoice->text());
  328. }
  329. /* Display */
  330. if (windowedButton->value()) {
  331. fullScreen.setParam(false);
  332. } else {
  333. fullScreen.setParam(true);
  334. if (allMonitorsButton->value()) {
  335. fullScreenMode.setParam("All");
  336. } else if (selectedMonitorsButton->value()) {
  337. fullScreenMode.setParam("Selected");
  338. } else {
  339. fullScreenMode.setParam("Current");
  340. }
  341. }
  342. fullScreenSelectedMonitors.setParam(monitorArrangement->get());
  343. /* Misc. */
  344. shared.setParam(sharedCheckbox->value());
  345. reconnectOnError.setParam(reconnectCheckbox->value());
  346. dotWhenNoCursor.setParam(dotCursorCheckbox->value());
  347. std::map<OptionsCallback*, void*>::const_iterator iter;
  348. for (iter = callbacks.begin();iter != callbacks.end();++iter)
  349. iter->first(iter->second);
  350. }
  351. void OptionsDialog::createCompressionPage(int tx, int ty, int tw, int th)
  352. {
  353. Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Compression"));
  354. int orig_tx, orig_ty;
  355. int half_width, full_width;
  356. int height;
  357. tx += OUTER_MARGIN;
  358. ty += OUTER_MARGIN;
  359. full_width = tw - OUTER_MARGIN * 2;
  360. half_width = (full_width - INNER_MARGIN) / 2;
  361. /* AutoSelect checkbox */
  362. autoselectCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  363. CHECK_MIN_WIDTH,
  364. CHECK_HEIGHT,
  365. _("Auto select")));
  366. autoselectCheckbox->callback(handleAutoselect, this);
  367. ty += CHECK_HEIGHT + INNER_MARGIN;
  368. /* Two columns */
  369. orig_tx = tx;
  370. orig_ty = ty;
  371. /* VNC encoding box */
  372. ty += GROUP_LABEL_OFFSET;
  373. height = GROUP_MARGIN * 2 + TIGHT_MARGIN * 3 + RADIO_HEIGHT * 4;
  374. encodingGroup = new Fl_Group(tx, ty, half_width, height,
  375. _("Preferred encoding"));
  376. encodingGroup->box(FL_ENGRAVED_BOX);
  377. encodingGroup->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
  378. {
  379. tx += GROUP_MARGIN;
  380. ty += GROUP_MARGIN;
  381. tightButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
  382. RADIO_MIN_WIDTH,
  383. RADIO_HEIGHT,
  384. "Tight"));
  385. tightButton->type(FL_RADIO_BUTTON);
  386. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  387. zrleButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
  388. RADIO_MIN_WIDTH,
  389. RADIO_HEIGHT,
  390. "ZRLE"));
  391. zrleButton->type(FL_RADIO_BUTTON);
  392. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  393. hextileButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
  394. RADIO_MIN_WIDTH,
  395. RADIO_HEIGHT,
  396. "Hextile"));
  397. hextileButton->type(FL_RADIO_BUTTON);
  398. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  399. rawButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
  400. RADIO_MIN_WIDTH,
  401. RADIO_HEIGHT,
  402. "Raw"));
  403. rawButton->type(FL_RADIO_BUTTON);
  404. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  405. }
  406. ty += GROUP_MARGIN - TIGHT_MARGIN;
  407. encodingGroup->end();
  408. /* Second column */
  409. tx = orig_tx + half_width + INNER_MARGIN;
  410. ty = orig_ty;
  411. /* Color box */
  412. ty += GROUP_LABEL_OFFSET;
  413. height = GROUP_MARGIN * 2 + TIGHT_MARGIN * 3 + RADIO_HEIGHT * 4;
  414. colorlevelGroup = new Fl_Group(tx, ty, half_width, height, _("Color level"));
  415. colorlevelGroup->box(FL_ENGRAVED_BOX);
  416. colorlevelGroup->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
  417. {
  418. tx += GROUP_MARGIN;
  419. ty += GROUP_MARGIN;
  420. fullcolorCheckbox = new Fl_Round_Button(LBLRIGHT(tx, ty,
  421. RADIO_MIN_WIDTH,
  422. RADIO_HEIGHT,
  423. _("Full")));
  424. fullcolorCheckbox->type(FL_RADIO_BUTTON);
  425. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  426. mediumcolorCheckbox = new Fl_Round_Button(LBLRIGHT(tx, ty,
  427. RADIO_MIN_WIDTH,
  428. RADIO_HEIGHT,
  429. _("Medium")));
  430. mediumcolorCheckbox->type(FL_RADIO_BUTTON);
  431. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  432. lowcolorCheckbox = new Fl_Round_Button(LBLRIGHT(tx, ty,
  433. RADIO_MIN_WIDTH,
  434. RADIO_HEIGHT,
  435. _("Low")));
  436. lowcolorCheckbox->type(FL_RADIO_BUTTON);
  437. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  438. verylowcolorCheckbox = new Fl_Round_Button(LBLRIGHT(tx, ty,
  439. RADIO_MIN_WIDTH,
  440. RADIO_HEIGHT,
  441. _("Very low")));
  442. verylowcolorCheckbox->type(FL_RADIO_BUTTON);
  443. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  444. }
  445. ty += GROUP_MARGIN - TIGHT_MARGIN;
  446. colorlevelGroup->end();
  447. /* Back to normal */
  448. tx = orig_tx;
  449. ty += INNER_MARGIN;
  450. /* Checkboxes */
  451. compressionCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  452. CHECK_MIN_WIDTH,
  453. CHECK_HEIGHT,
  454. _("Custom compression level:")));
  455. compressionCheckbox->callback(handleCompression, this);
  456. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  457. compressionInput = new Fl_Int_Input(tx + INDENT, ty,
  458. INPUT_HEIGHT, INPUT_HEIGHT,
  459. _("level (0=fast, 9=best)"));
  460. compressionInput->align(FL_ALIGN_RIGHT);
  461. ty += INPUT_HEIGHT + INNER_MARGIN;
  462. jpegCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  463. CHECK_MIN_WIDTH,
  464. CHECK_HEIGHT,
  465. _("Allow JPEG compression:")));
  466. jpegCheckbox->callback(handleJpeg, this);
  467. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  468. jpegInput = new Fl_Int_Input(tx + INDENT, ty,
  469. INPUT_HEIGHT, INPUT_HEIGHT,
  470. _("quality (0=poor, 9=best)"));
  471. jpegInput->align(FL_ALIGN_RIGHT);
  472. ty += INPUT_HEIGHT + INNER_MARGIN;
  473. group->end();
  474. }
  475. void OptionsDialog::createSecurityPage(int tx, int ty, int tw, int th)
  476. {
  477. #ifdef HAVE_GNUTLS
  478. Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Security"));
  479. int orig_tx;
  480. int width, height;
  481. tx += OUTER_MARGIN;
  482. ty += OUTER_MARGIN;
  483. width = tw - OUTER_MARGIN * 2;
  484. orig_tx = tx;
  485. /* Encryption */
  486. ty += GROUP_LABEL_OFFSET;
  487. height = GROUP_MARGIN * 2 + TIGHT_MARGIN * 4 + CHECK_HEIGHT * 3 + (INPUT_LABEL_OFFSET + INPUT_HEIGHT) * 2;
  488. encryptionGroup = new Fl_Group(tx, ty, width, height, _("Encryption"));
  489. encryptionGroup->box(FL_ENGRAVED_BOX);
  490. encryptionGroup->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
  491. {
  492. tx += GROUP_MARGIN;
  493. ty += GROUP_MARGIN;
  494. encNoneCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  495. CHECK_MIN_WIDTH,
  496. CHECK_HEIGHT,
  497. _("None")));
  498. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  499. encTLSCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  500. CHECK_MIN_WIDTH,
  501. CHECK_HEIGHT,
  502. _("TLS with anonymous certificates")));
  503. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  504. encX509Checkbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  505. CHECK_MIN_WIDTH,
  506. CHECK_HEIGHT,
  507. _("TLS with X509 certificates")));
  508. encX509Checkbox->callback(handleX509, this);
  509. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  510. ty += INPUT_LABEL_OFFSET;
  511. caInput = new Fl_Input(tx + INDENT, ty,
  512. width - GROUP_MARGIN*2 - INDENT, INPUT_HEIGHT,
  513. _("Path to X509 CA certificate"));
  514. caInput->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
  515. ty += INPUT_HEIGHT + TIGHT_MARGIN;
  516. ty += INPUT_LABEL_OFFSET;
  517. crlInput = new Fl_Input(tx + INDENT, ty,
  518. width - GROUP_MARGIN*2 - INDENT, INPUT_HEIGHT,
  519. _("Path to X509 CRL file"));
  520. crlInput->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
  521. ty += INPUT_HEIGHT + TIGHT_MARGIN;
  522. }
  523. ty += GROUP_MARGIN - TIGHT_MARGIN;
  524. encryptionGroup->end();
  525. /* Back to normal */
  526. tx = orig_tx;
  527. ty += INNER_MARGIN;
  528. /* Authentication */
  529. ty += GROUP_LABEL_OFFSET;
  530. height = GROUP_MARGIN * 2 + TIGHT_MARGIN * 2 + CHECK_HEIGHT * 3;
  531. authenticationGroup = new Fl_Group(tx, ty, width, height, _("Authentication"));
  532. authenticationGroup->box(FL_ENGRAVED_BOX);
  533. authenticationGroup->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
  534. {
  535. tx += GROUP_MARGIN;
  536. ty += GROUP_MARGIN;
  537. authNoneCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  538. CHECK_MIN_WIDTH,
  539. CHECK_HEIGHT,
  540. _("None")));
  541. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  542. authVncCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  543. CHECK_MIN_WIDTH,
  544. CHECK_HEIGHT,
  545. _("Standard VNC (insecure without encryption)")));
  546. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  547. authPlainCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  548. CHECK_MIN_WIDTH,
  549. CHECK_HEIGHT,
  550. _("Username and password (insecure without encryption)")));
  551. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  552. }
  553. ty += GROUP_MARGIN - TIGHT_MARGIN;
  554. authenticationGroup->end();
  555. /* Back to normal */
  556. tx = orig_tx;
  557. ty += INNER_MARGIN;
  558. group->end();
  559. #endif
  560. }
  561. void OptionsDialog::createInputPage(int tx, int ty, int tw, int th)
  562. {
  563. Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Input"));
  564. int orig_tx;
  565. int width;
  566. tx += OUTER_MARGIN;
  567. ty += OUTER_MARGIN;
  568. width = tw - OUTER_MARGIN * 2;
  569. viewOnlyCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  570. CHECK_MIN_WIDTH,
  571. CHECK_HEIGHT,
  572. _("View only (ignore mouse and keyboard)")));
  573. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  574. orig_tx = tx;
  575. /* Mouse */
  576. ty += GROUP_LABEL_OFFSET;
  577. mouseGroup = new Fl_Group(tx, ty, width, 0, _("Mouse"));
  578. mouseGroup->box(FL_ENGRAVED_BOX);
  579. mouseGroup->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
  580. /* Needed for final resize to work sanely */
  581. mouseGroup->resizable(NULL);
  582. {
  583. tx += GROUP_MARGIN;
  584. ty += GROUP_MARGIN;
  585. emulateMBCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  586. CHECK_MIN_WIDTH,
  587. CHECK_HEIGHT,
  588. _("Emulate middle mouse button")));
  589. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  590. dotCursorCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  591. CHECK_MIN_WIDTH,
  592. CHECK_HEIGHT,
  593. _("Show dot when no cursor")));
  594. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  595. }
  596. ty += GROUP_MARGIN - TIGHT_MARGIN;
  597. mouseGroup->end();
  598. mouseGroup->size(mouseGroup->w(), ty - mouseGroup->y());
  599. /* Back to normal */
  600. tx = orig_tx;
  601. ty += INNER_MARGIN;
  602. /* Keyboard */
  603. ty += GROUP_LABEL_OFFSET;
  604. keyboardGroup = new Fl_Group(tx, ty, width, 0, _("Keyboard"));
  605. keyboardGroup->box(FL_ENGRAVED_BOX);
  606. keyboardGroup->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
  607. /* Needed for final resize to work sanely */
  608. keyboardGroup->resizable(NULL);
  609. {
  610. tx += GROUP_MARGIN;
  611. ty += GROUP_MARGIN;
  612. systemKeysCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  613. CHECK_MIN_WIDTH,
  614. CHECK_HEIGHT,
  615. _("Pass system keys directly to server (full screen)")));
  616. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  617. menuKeyChoice = new Fl_Choice(LBLLEFT(tx, ty, 150, CHOICE_HEIGHT, _("Menu key")));
  618. fltk_menu_add(menuKeyChoice, _("None"), 0, NULL, (void*)0, FL_MENU_DIVIDER);
  619. for (int i = 0; i < getMenuKeySymbolCount(); i++)
  620. fltk_menu_add(menuKeyChoice, getMenuKeySymbols()[i].name, 0, NULL, 0, 0);
  621. ty += CHOICE_HEIGHT + TIGHT_MARGIN;
  622. }
  623. ty += GROUP_MARGIN - TIGHT_MARGIN;
  624. keyboardGroup->end();
  625. keyboardGroup->size(keyboardGroup->w(), ty - keyboardGroup->y());
  626. /* Back to normal */
  627. tx = orig_tx;
  628. ty += INNER_MARGIN;
  629. /* Clipboard */
  630. ty += GROUP_LABEL_OFFSET;
  631. clipboardGroup = new Fl_Group(tx, ty, width, 0, _("Clipboard"));
  632. clipboardGroup->box(FL_ENGRAVED_BOX);
  633. clipboardGroup->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
  634. /* Needed for final resize to work sanely */
  635. clipboardGroup->resizable(NULL);
  636. {
  637. tx += GROUP_MARGIN;
  638. ty += GROUP_MARGIN;
  639. acceptClipboardCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  640. CHECK_MIN_WIDTH,
  641. CHECK_HEIGHT,
  642. _("Accept clipboard from server")));
  643. acceptClipboardCheckbox->callback(handleClipboard, this);
  644. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  645. #if !defined(WIN32) && !defined(__APPLE__)
  646. setPrimaryCheckbox = new Fl_Check_Button(LBLRIGHT(tx + INDENT, ty,
  647. CHECK_MIN_WIDTH,
  648. CHECK_HEIGHT,
  649. _("Also set primary selection")));
  650. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  651. #endif
  652. sendClipboardCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  653. CHECK_MIN_WIDTH,
  654. CHECK_HEIGHT,
  655. _("Send clipboard to server")));
  656. sendClipboardCheckbox->callback(handleClipboard, this);
  657. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  658. #if !defined(WIN32) && !defined(__APPLE__)
  659. sendPrimaryCheckbox = new Fl_Check_Button(LBLRIGHT(tx + INDENT, ty,
  660. CHECK_MIN_WIDTH,
  661. CHECK_HEIGHT,
  662. _("Send primary selection as clipboard")));
  663. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  664. #endif
  665. }
  666. ty += GROUP_MARGIN - TIGHT_MARGIN;
  667. clipboardGroup->end();
  668. clipboardGroup->size(clipboardGroup->w(), ty - clipboardGroup->y());
  669. /* Back to normal */
  670. tx = orig_tx;
  671. ty += INNER_MARGIN;
  672. group->end();
  673. }
  674. void OptionsDialog::createDisplayPage(int tx, int ty, int tw, int th)
  675. {
  676. Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Display"));
  677. int orig_tx;
  678. int width;
  679. tx += OUTER_MARGIN;
  680. ty += OUTER_MARGIN;
  681. width = tw - OUTER_MARGIN * 2;
  682. orig_tx = tx;
  683. /* Display mode */
  684. ty += GROUP_LABEL_OFFSET;
  685. displayModeGroup = new Fl_Group(tx, ty, width, 0, _("Display mode"));
  686. displayModeGroup->box(FL_ENGRAVED_BOX);
  687. displayModeGroup->align(FL_ALIGN_LEFT | FL_ALIGN_TOP);
  688. /* Needed for final resize to work sanely */
  689. displayModeGroup->resizable(NULL);
  690. {
  691. tx += GROUP_MARGIN;
  692. ty += GROUP_MARGIN;
  693. width -= GROUP_MARGIN * 2;
  694. windowedButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
  695. RADIO_MIN_WIDTH,
  696. RADIO_HEIGHT,
  697. _("Windowed")));
  698. windowedButton->type(FL_RADIO_BUTTON);
  699. windowedButton->callback(handleFullScreenMode, this);
  700. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  701. currentMonitorButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
  702. RADIO_MIN_WIDTH,
  703. RADIO_HEIGHT,
  704. _("Full screen on current monitor")));
  705. currentMonitorButton->type(FL_RADIO_BUTTON);
  706. currentMonitorButton->callback(handleFullScreenMode, this);
  707. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  708. allMonitorsButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
  709. RADIO_MIN_WIDTH,
  710. RADIO_HEIGHT,
  711. _("Full screen on all monitors")));
  712. allMonitorsButton->type(FL_RADIO_BUTTON);
  713. allMonitorsButton->callback(handleFullScreenMode, this);
  714. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  715. selectedMonitorsButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
  716. RADIO_MIN_WIDTH,
  717. RADIO_HEIGHT,
  718. _("Full screen on selected monitor(s)")));
  719. selectedMonitorsButton->type(FL_RADIO_BUTTON);
  720. selectedMonitorsButton->callback(handleFullScreenMode, this);
  721. ty += RADIO_HEIGHT + TIGHT_MARGIN;
  722. monitorArrangement = new MonitorArrangement(
  723. tx + INDENT, ty,
  724. width - INDENT, 150);
  725. ty += 150 + TIGHT_MARGIN;
  726. }
  727. ty += GROUP_MARGIN - TIGHT_MARGIN;
  728. displayModeGroup->end();
  729. displayModeGroup->size(displayModeGroup->w(),
  730. ty - displayModeGroup->y());
  731. /* Back to normal */
  732. tx = orig_tx;
  733. ty += INNER_MARGIN;
  734. width = tw - OUTER_MARGIN * 2;
  735. group->end();
  736. }
  737. void OptionsDialog::createMiscPage(int tx, int ty, int tw, int th)
  738. {
  739. Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Misc."));
  740. tx += OUTER_MARGIN;
  741. ty += OUTER_MARGIN;
  742. sharedCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  743. CHECK_MIN_WIDTH,
  744. CHECK_HEIGHT,
  745. _("Shared (don't disconnect other viewers)")));
  746. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  747. reconnectCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
  748. CHECK_MIN_WIDTH,
  749. CHECK_HEIGHT,
  750. _("Ask to reconnect on connection errors")));
  751. ty += CHECK_HEIGHT + TIGHT_MARGIN;
  752. group->end();
  753. }
  754. void OptionsDialog::handleAutoselect(Fl_Widget *widget, void *data)
  755. {
  756. OptionsDialog *dialog = (OptionsDialog*)data;
  757. if (dialog->autoselectCheckbox->value()) {
  758. dialog->encodingGroup->deactivate();
  759. dialog->colorlevelGroup->deactivate();
  760. } else {
  761. dialog->encodingGroup->activate();
  762. dialog->colorlevelGroup->activate();
  763. }
  764. // JPEG setting is also affected by autoselection
  765. dialog->handleJpeg(dialog->jpegCheckbox, dialog);
  766. }
  767. void OptionsDialog::handleCompression(Fl_Widget *widget, void *data)
  768. {
  769. OptionsDialog *dialog = (OptionsDialog*)data;
  770. if (dialog->compressionCheckbox->value())
  771. dialog->compressionInput->activate();
  772. else
  773. dialog->compressionInput->deactivate();
  774. }
  775. void OptionsDialog::handleJpeg(Fl_Widget *widget, void *data)
  776. {
  777. OptionsDialog *dialog = (OptionsDialog*)data;
  778. if (dialog->jpegCheckbox->value() &&
  779. !dialog->autoselectCheckbox->value())
  780. dialog->jpegInput->activate();
  781. else
  782. dialog->jpegInput->deactivate();
  783. }
  784. void OptionsDialog::handleX509(Fl_Widget *widget, void *data)
  785. {
  786. OptionsDialog *dialog = (OptionsDialog*)data;
  787. if (dialog->encX509Checkbox->value()) {
  788. dialog->caInput->activate();
  789. dialog->crlInput->activate();
  790. } else {
  791. dialog->caInput->deactivate();
  792. dialog->crlInput->deactivate();
  793. }
  794. }
  795. void OptionsDialog::handleClipboard(Fl_Widget *widget, void *data)
  796. {
  797. #if !defined(WIN32) && !defined(__APPLE__)
  798. OptionsDialog *dialog = (OptionsDialog*)data;
  799. if (dialog->acceptClipboardCheckbox->value())
  800. dialog->setPrimaryCheckbox->activate();
  801. else
  802. dialog->setPrimaryCheckbox->deactivate();
  803. if (dialog->sendClipboardCheckbox->value())
  804. dialog->sendPrimaryCheckbox->activate();
  805. else
  806. dialog->sendPrimaryCheckbox->deactivate();
  807. #endif
  808. }
  809. void OptionsDialog::handleFullScreenMode(Fl_Widget *widget, void *data)
  810. {
  811. OptionsDialog *dialog = (OptionsDialog*)data;
  812. if (dialog->selectedMonitorsButton->value()) {
  813. dialog->monitorArrangement->activate();
  814. } else {
  815. dialog->monitorArrangement->deactivate();
  816. }
  817. }
  818. void OptionsDialog::handleCancel(Fl_Widget *widget, void *data)
  819. {
  820. OptionsDialog *dialog = (OptionsDialog*)data;
  821. dialog->hide();
  822. }
  823. void OptionsDialog::handleOK(Fl_Widget *widget, void *data)
  824. {
  825. OptionsDialog *dialog = (OptionsDialog*)data;
  826. dialog->hide();
  827. dialog->storeOptions();
  828. }
  829. int OptionsDialog::fltk_event_handler(int event)
  830. {
  831. std::set<OptionsDialog *>::iterator iter;
  832. if (event != FL_SCREEN_CONFIGURATION_CHANGED)
  833. return 0;
  834. // Refresh monitor arrangement widget to match the parameter settings after
  835. // screen configuration has changed. The MonitorArrangement index doesn't work
  836. // the same way as the FLTK screen index.
  837. for (iter = instances.begin(); iter != instances.end(); iter++)
  838. Fl::add_timeout(0, handleScreenConfigTimeout, (*iter));
  839. return 0;
  840. }
  841. void OptionsDialog::handleScreenConfigTimeout(void *data)
  842. {
  843. OptionsDialog *self = (OptionsDialog *)data;
  844. assert(self);
  845. self->monitorArrangement->set(fullScreenSelectedMonitors.getParam());
  846. }