blob: 4c7e21224d2f55ddac650a353204f9a1e9bef403 [file] [log] [blame]
Pierre Ossman5156d5e2011-03-09 09:42:34 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
DRCb65bb932011-06-24 03:17:00 +00003 * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
Pierre Ossman5156d5e2011-03-09 09:42:34 +00004 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18 * USA.
19 */
20
21#include <string.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <errno.h>
25#include <signal.h>
26#include <locale.h>
27#include <sys/stat.h>
28
29#ifdef WIN32
30#include <direct.h>
31#define mkdir(path, mode) _mkdir(path)
32#endif
33
34#include <os/os.h>
35#include <rfb/Logger_stdio.h>
36#include <rfb/SecurityClient.h>
37#include <rfb/Security.h>
38#ifdef HAVE_GNUTLS
39#include <rfb/CSecurityTLS.h>
40#endif
41#include <rfb/LogWriter.h>
42#include <rfb/Timer.h>
43#include <network/TcpSocket.h>
44
45#include <FL/Fl.H>
46#include <FL/Fl_Widget.H>
47#include <FL/fl_ask.H>
Pierre Ossmanb8858222011-04-29 11:51:38 +000048#include <FL/x.H>
Pierre Ossman5156d5e2011-03-09 09:42:34 +000049
50#include "i18n.h"
51#include "parameters.h"
52#include "CConn.h"
Pierre Ossman561ff0c2011-05-13 14:04:59 +000053#include "ServerDialog.h"
Pierre Ossman5156d5e2011-03-09 09:42:34 +000054#include "UserDialog.h"
55
DRCb65bb932011-06-24 03:17:00 +000056#ifdef WIN32
57#include "win32.h"
58#endif
59
Pierre Ossman5156d5e2011-03-09 09:42:34 +000060rfb::LogWriter vlog("main");
61
62using namespace network;
63using namespace rfb;
64using namespace std;
65
Pierre Ossmanb8858222011-04-29 11:51:38 +000066static char aboutText[1024];
DRCd8e93dc2011-07-28 22:13:40 +000067extern const char* buildTime;
Pierre Ossman5156d5e2011-03-09 09:42:34 +000068
69static bool exitMainloop = false;
Pierre Ossmane2ef5c12011-07-12 16:56:34 +000070static const char *exitError = NULL;
Pierre Ossman5156d5e2011-03-09 09:42:34 +000071
Pierre Ossmane2ef5c12011-07-12 16:56:34 +000072void exit_vncviewer(const char *error)
Pierre Ossman5156d5e2011-03-09 09:42:34 +000073{
Pierre Ossmane2ef5c12011-07-12 16:56:34 +000074 // Prioritise the first error we get as that is probably the most
75 // relevant one.
76 if ((error != NULL) && (exitError == NULL))
77 exitError = strdup(error);
78
Pierre Ossman5156d5e2011-03-09 09:42:34 +000079 exitMainloop = true;
80}
81
Pierre Ossmanb8858222011-04-29 11:51:38 +000082void about_vncviewer()
83{
84 fl_message_title(_("About TigerVNC Viewer"));
85 fl_message(aboutText);
86}
87
88static void about_callback(Fl_Widget *widget, void *data)
89{
90 about_vncviewer();
91}
92
Pierre Ossman5156d5e2011-03-09 09:42:34 +000093static void CleanupSignalHandler(int sig)
94{
95 // CleanupSignalHandler allows C++ object cleanup to happen because it calls
96 // exit() rather than the default which is to abort.
97 vlog.info("CleanupSignalHandler called");
98 exit(1);
99}
100
101static void init_fltk()
102{
103 // Basic text size (10pt @ 96 dpi => 13px)
104 FL_NORMAL_SIZE = 13;
105
106#ifndef __APPLE__
107 // Select a FLTK scheme and background color that looks somewhat
108 // close to modern Linux and Windows.
109 Fl::scheme("gtk+");
110 Fl::background(220, 220, 220);
111#else
112 // On Mac OS X there is another scheme that fits better though.
113 Fl::scheme("plastic");
114#endif
115
116 // This makes the "icon" in dialogs rounded, which fits better
117 // with the above schemes.
118 fl_message_icon()->box(FL_UP_BOX);
119
120 // Turn off the annoying behaviour where popups track the mouse.
121 fl_message_hotspot(false);
122
123 // Avoid empty titles for popups
124 fl_message_title_default(_("TigerVNC Viewer"));
125
126#ifdef WIN32
127 // Most "normal" Windows apps use this font for UI elements.
128 Fl::set_font(FL_HELVETICA, "Tahoma");
129#endif
130
131 // FLTK exposes these so that we can translate them.
132 fl_no = _("No");
133 fl_yes = _("Yes");
134 fl_ok = _("OK");
135 fl_cancel = _("Cancel");
136 fl_close = _("Close");
Pierre Ossmanb8858222011-04-29 11:51:38 +0000137
138#ifdef __APPLE__
Pierre Ossman41ba6032011-06-16 11:09:31 +0000139 Fl_Mac_App_Menu::about = _("About ");
140 Fl_Mac_App_Menu::print = ""; // Don't want the print item
141 Fl_Mac_App_Menu::services = _("Services");
142 Fl_Mac_App_Menu::hide = _("Hide ");
143 Fl_Mac_App_Menu::hide_others = _("Hide Others");
144 Fl_Mac_App_Menu::show = _("Show All");
145 Fl_Mac_App_Menu::quit = _("Quit ");
146
Pierre Ossmanb8858222011-04-29 11:51:38 +0000147 fl_mac_set_about(about_callback, NULL);
148#endif
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000149}
150
151static void mkvnchomedir()
152{
153 // Create .vnc in the user's home directory if it doesn't already exist
154 char* homeDir = NULL;
155
156 if (getvnchomedir(&homeDir) == -1) {
157 vlog.error(_("Could not create VNC home directory: can't obtain home "
158 "directory path."));
159 } else {
160 int result = mkdir(homeDir, 0755);
161 if (result == -1 && errno != EEXIST)
162 vlog.error(_("Could not create VNC home directory: %s."), strerror(errno));
163 delete [] homeDir;
164 }
165}
166
167static void usage(const char *programName)
168{
169 fprintf(stderr,
170 "\nusage: %s [parameters] [host:displayNum] [parameters]\n"
171 " %s [parameters] -listen [port] [parameters]\n",
172 programName, programName);
173 fprintf(stderr,"\n"
174 "Parameters can be turned on with -<param> or off with -<param>=0\n"
175 "Parameters which take a value can be specified as "
176 "-<param> <value>\n"
177 "Other valid forms are <param>=<value> -<param>=<value> "
178 "--<param>=<value>\n"
179 "Parameter names are case-insensitive. The parameters are:\n\n");
180 Configuration::listParams(79, 14);
181 exit(1);
182}
183
184int main(int argc, char** argv)
185{
Pierre Ossman561ff0c2011-05-13 14:04:59 +0000186 const char* vncServerName = NULL;
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000187 UserDialog dlg;
188
DRCd8e93dc2011-07-28 22:13:40 +0000189 const char englishAbout[] = N_("TigerVNC Viewer %d-bit v%s (%s)\n"
190 "%s\n"
DRC07baad72011-06-28 05:42:30 +0000191 "Copyright (C) 1999-2011 TigerVNC Team and many others (see README.txt)\n"
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000192 "See http://www.tigervnc.org for information on TigerVNC.");
193
194 setlocale(LC_ALL, "");
195 bindtextdomain(PACKAGE_NAME, LOCALEDIR);
196 textdomain(PACKAGE_NAME);
197
198 rfb::SecurityClient::setDefaults();
199
200 // Write about text to console, still using normal locale codeset
201 snprintf(aboutText, sizeof(aboutText),
DRCd8e93dc2011-07-28 22:13:40 +0000202 gettext(englishAbout), (int)sizeof(size_t)*8, PACKAGE_VERSION,
203 __BUILD__, buildTime);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000204 fprintf(stderr,"\n%s\n", aboutText);
205
206 // Set gettext codeset to what our GUI toolkit uses. Since we are
207 // passing strings from strerror/gai_strerror to the GUI, these must
208 // be in GUI codeset as well.
209 bind_textdomain_codeset(PACKAGE_NAME, "UTF-8");
210 bind_textdomain_codeset("libc", "UTF-8");
211
212 // Re-create the aboutText for the GUI, now using GUI codeset
213 snprintf(aboutText, sizeof(aboutText),
DRCd8e93dc2011-07-28 22:13:40 +0000214 gettext(englishAbout), (int)sizeof(size_t)*8, PACKAGE_VERSION,
215 __BUILD__, buildTime);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000216
217 rfb::initStdIOLoggers();
218 rfb::LogWriter::setLogParams("*:stderr:30");
219
220#ifdef SIGHUP
221 signal(SIGHUP, CleanupSignalHandler);
222#endif
223 signal(SIGINT, CleanupSignalHandler);
224 signal(SIGTERM, CleanupSignalHandler);
225
226 init_fltk();
227
228 Configuration::enableViewerParams();
229
DRC5aa06502011-06-23 22:04:46 +0000230 int i = 1;
231 if (!Fl::args(argc, argv, i) || i < argc)
232 for (; i < argc; i++) {
233 if (Configuration::setParam(argv[i]))
234 continue;
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000235
DRC5aa06502011-06-23 22:04:46 +0000236 if (argv[i][0] == '-') {
237 if (i+1 < argc) {
238 if (Configuration::setParam(&argv[i][1], argv[i+1])) {
239 i++;
240 continue;
241 }
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000242 }
DRC5aa06502011-06-23 22:04:46 +0000243 usage(argv[0]);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000244 }
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000245
DRC5aa06502011-06-23 22:04:46 +0000246 vncServerName = argv[i];
247 }
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000248
249 if (!::autoSelect.hasBeenSet()) {
250 // Default to AutoSelect=0 if -PreferredEncoding or -FullColor is used
251 ::autoSelect.setParam(!::preferredEncoding.hasBeenSet() &&
252 !::fullColour.hasBeenSet() &&
253 !::fullColourAlias.hasBeenSet());
254 }
255 if (!::fullColour.hasBeenSet() && !::fullColourAlias.hasBeenSet()) {
256 // Default to FullColor=0 if AutoSelect=0 && LowColorLevel is set
257 if (!::autoSelect && (::lowColourLevel.hasBeenSet() ||
258 ::lowColourLevelAlias.hasBeenSet())) {
259 ::fullColour.setParam(false);
260 }
261 }
262 if (!::customCompressLevel.hasBeenSet()) {
263 // Default to CustomCompressLevel=1 if CompressLevel is used.
264 ::customCompressLevel.setParam(::compressLevel.hasBeenSet());
265 }
266
267 mkvnchomedir();
268
269 CSecurity::upg = &dlg;
270#ifdef HAVE_GNUTLS
271 CSecurityTLS::msg = &dlg;
272#endif
273
Pierre Ossman561ff0c2011-05-13 14:04:59 +0000274 if (vncServerName == NULL) {
275 vncServerName = ServerDialog::run();
276 if ((vncServerName == NULL) || (vncServerName[0] == '\0'))
277 return 1;
278 }
279
Pierre Ossmane2ef5c12011-07-12 16:56:34 +0000280 CConn *cc = new CConn(vncServerName);
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000281
282 while (!exitMainloop) {
283 int next_timer;
284
285 next_timer = Timer::checkTimeouts();
286 if (next_timer == 0)
287 next_timer = INT_MAX;
288
289 if (Fl::wait((double)next_timer / 1000.0) < 0.0) {
290 vlog.error(_("Internal FLTK error. Exiting."));
291 break;
292 }
293 }
294
Pierre Ossmane2ef5c12011-07-12 16:56:34 +0000295 delete cc;
296
297 if (exitError != NULL)
298 fl_alert(exitError);
299
Pierre Ossman5156d5e2011-03-09 09:42:34 +0000300 return 0;
301}