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 34KB

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