}
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("Failed to connect to \"%s\":\n\n%s"),
- vncServerName, e.str());
+ abort_connection(_("Failed to connect to \"%s\":\n\n%s"),
+ vncServerName, e.str());
return;
}
}
Timer::checkTimeouts();
// Also check if we need to stop reading and terminate
- if (should_exit())
+ if (should_disconnect())
break;
}
if (!cc->desktop) {
vlog.error(_("The connection was dropped by the server before "
"the session could be established."));
- exit_vncviewer(_("The connection was dropped by the server "
+ abort_connection(_("The connection was dropped by the server "
"before the session could be established."));
} else {
- exit_vncviewer();
+ disconnect();
}
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("An unexpected error occurred when communicating "
+ abort_connection(_("An unexpected error occurred when communicating "
"with the server:\n\n%s"), e.str());
}
void DesktopWindow::handleClose(Fl_Widget *wnd, void *data)
{
- exit_vncviewer();
+ disconnect();
}
// Menu constants
-enum { ID_EXIT, ID_FULLSCREEN, ID_MINIMIZE, ID_RESIZE,
+enum { ID_DISCONNECT, ID_FULLSCREEN, ID_MINIMIZE, ID_RESIZE,
ID_CTRL, ID_ALT, ID_MENUKEY, ID_CTRLALTDEL,
ID_REFRESH, ID_OPTIONS, ID_INFO, ID_ABOUT };
cc->sendClipboardData(filtered);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("An unexpected error occurred when communicating "
- "with the server:\n\n%s"), e.str());
+ abort_connection(_("An unexpected error occurred when "
+ "communicating with the server:\n\n%s"),
+ e.str());
}
strFree(filtered);
cc->writer()->writePointerEvent(pos, buttonMask);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("An unexpected error occurred when communicating "
- "with the server:\n\n%s"), e.str());
+ abort_connection(_("An unexpected error occurred when "
+ "communicating with the server:\n\n%s"),
+ e.str());
}
} else {
if (!Fl::has_timeout(handlePointerTimeout, this))
self->cc->announceClipboard(true);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("An unexpected error occurred when communicating "
- "with the server:\n\n%s"), e.str());
+ abort_connection(_("An unexpected error occurred when "
+ "communicating with the server:\n\n%s"),
+ e.str());
}
}
cc->requestClipboard();
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("An unexpected error occurred when communicating "
- "with the server:\n\n%s"), e.str());
+ abort_connection(_("An unexpected error occurred when "
+ "communicating with the server:\n\n%s"),
+ e.str());
}
}
if (pendingClientClipboard) {
cc->announceClipboard(true);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("An unexpected error occurred when communicating "
- "with the server:\n\n%s"), e.str());
+ abort_connection(_("An unexpected error occurred when "
+ "communicating with the server:\n\n%s"),
+ e.str());
}
}
self->lastButtonMask);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("An unexpected error occurred when communicating "
- "with the server:\n\n%s"), e.str());
+ abort_connection(_("An unexpected error occurred when "
+ "communicating with the server:\n\n%s"),
+ e.str());
}
}
cc->writer()->writeKeyEvent(keySym, keyCode, true);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("An unexpected error occurred when communicating "
- "with the server:\n\n%s"), e.str());
+ abort_connection(_("An unexpected error occurred when "
+ "communicating with the server:\n\n%s"),
+ e.str());
}
}
cc->writer()->writeKeyEvent(iter->second, keyCode, false);
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("An unexpected error occurred when communicating "
- "with the server:\n\n%s"), e.str());
+ abort_connection(_("An unexpected error occurred when "
+ "communicating with the server:\n\n%s"),
+ e.str());
}
downKeySym.erase(iter);
{
contextMenu->clear();
- fltk_menu_add(contextMenu, p_("ContextMenu|", "E&xit viewer"),
- 0, NULL, (void*)ID_EXIT, FL_MENU_DIVIDER);
+ fltk_menu_add(contextMenu, p_("ContextMenu|", "Dis&connect"),
+ 0, NULL, (void*)ID_DISCONNECT, FL_MENU_DIVIDER);
fltk_menu_add(contextMenu, p_("ContextMenu|", "&Full screen"),
0, NULL, (void*)ID_FULLSCREEN,
return;
switch (m->argument()) {
- case ID_EXIT:
- exit_vncviewer();
+ case ID_DISCONNECT:
+ disconnect();
break;
case ID_FULLSCREEN:
if (window()->fullscreen_active())
"Give a dialog on connection problems rather "
"than exiting immediately", true);
+BoolParameter reconnectOnError("ReconnectOnError",
+ "Give a dialog on connection problems rather "
+ "than exiting immediately and ask for a reconnect.", true);
+
StringParameter passwordFile("PasswordFile",
"Password file for VNC authentication", "");
AliasParameter passwd("passwd", "Alias for PasswordFile", &passwordFile);
extern rfb::BoolParameter fullscreenSystemKeys;
extern rfb::BoolParameter alertOnFatalError;
+extern rfb::BoolParameter reconnectOnError;
#ifndef WIN32
extern rfb::StringParameter via;
handlers[msg->hwnd] = new Win32TouchHandler(msg->hwnd);
} catch (rfb::Exception& e) {
vlog.error(_("Failed to create touch handler: %s"), e.str());
- exit_vncviewer(_("Failed to create touch handler: %s"), e.str());
+ abort_vncviewer(_("Failed to create touch handler: %s"), e.str());
}
// Add a special hook-in for handling events sent directly to WndProc
if (!SetWindowSubclass(msg->hwnd, &win32WindowProc, 1, 0)) {
fl_open_display();
if (!XQueryExtension(fl_display, "XInputExtension", &xi_major, &ev, &err)) {
- exit_vncviewer(_("X Input extension not available."));
+ abort_vncviewer(_("X Input extension not available."));
return; // Not reached
}
major_ver = 2;
minor_ver = 2;
if (XIQueryVersion(fl_display, &major_ver, &minor_ver) != Success) {
- exit_vncviewer(_("X Input 2 (or newer) is not available."));
+ abort_vncviewer(_("X Input 2 (or newer) is not available."));
return; // Not reached
}
#include <config.h>
#endif
+#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
static bool inMainloop = false;
static bool exitMainloop = false;
-static const char *exitError = NULL;
+static char *exitError = NULL;
+static bool fatalError = false;
static const char *about_text()
{
return buffer;
}
-void exit_vncviewer(const char *error, ...)
+
+void abort_vncviewer(const char *error, ...)
{
+ fatalError = true;
+
// Prioritise the first error we get as that is probably the most
// relevant one.
- if ((error != NULL) && (exitError == NULL)) {
+ if (exitError == NULL) {
va_list ap;
va_start(ap, error);
exitError = (char*)malloc(1024);
- if (exitError)
- (void) vsnprintf((char*)exitError, 1024, error, ap);
+ vsnprintf(exitError, 1024, error, ap);
va_end(ap);
}
}
}
-bool should_exit()
+void abort_connection(const char *error, ...)
+{
+ assert(inMainloop);
+
+ // Prioritise the first error we get as that is probably the most
+ // relevant one.
+ if (exitError == NULL) {
+ va_list ap;
+
+ va_start(ap, error);
+ exitError = (char*)malloc(1024);
+ vsnprintf(exitError, 1024, error, ap);
+ va_end(ap);
+ }
+
+ exitMainloop = true;
+}
+
+void disconnect()
+{
+ exitMainloop = true;
+}
+
+bool should_disconnect()
{
return exitMainloop;
}
fl_message("%s", about_text());
}
-void run_mainloop()
+static void mainloop(const char* vncserver, network::Socket* sock)
{
- int next_timer;
+ while (true) {
+ CConn *cc;
- next_timer = Timer::checkTimeouts();
- if (next_timer == 0)
- next_timer = INT_MAX;
+ exitMainloop = false;
- if (Fl::wait((double)next_timer / 1000.0) < 0.0) {
- vlog.error(_("Internal FLTK error. Exiting."));
- exit(-1);
+ cc = new CConn(vncServerName, sock);
+
+ while (!exitMainloop) {
+ int next_timer;
+
+ next_timer = Timer::checkTimeouts();
+ if (next_timer == 0)
+ next_timer = INT_MAX;
+
+ if (Fl::wait((double)next_timer / 1000.0) < 0.0) {
+ vlog.error(_("Internal FLTK error. Exiting."));
+ exit(-1);
+ }
+ }
+
+ delete cc;
+
+ if (fatalError) {
+ assert(exitError != NULL);
+ if (alertOnFatalError)
+ fl_alert("%s", exitError);
+ break;
+ }
+
+ if (exitError == NULL)
+ break;
+
+ if(reconnectOnError && (sock == NULL)) {
+ int ret;
+ ret = fl_choice(_("%s\n\n"
+ "Attempt to reconnect?"),
+ fl_yes, fl_no, 0, exitError);
+ free(exitError);
+ exitError = NULL;
+ if (ret == 0)
+ continue;
+ else
+ break;
+ }
+
+ if (alertOnFatalError)
+ fl_alert("%s", exitError);
+
+ break;
}
}
vncServerName[VNCSERVERNAMELEN-1] = '\0';
} catch (rfb::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("Error reading configuration file \"%s\":\n\n%s"),
- vncServerName, e.str());
+ abort_vncviewer(_("Error reading configuration file \"%s\":\n\n%s"),
+ vncServerName, e.str());
}
}
}
// TRANSLATORS: "Parameters" are command line arguments, or settings
// from a file or the Windows registry.
vlog.error(_("Parameters -listen and -via are incompatible"));
- exit_vncviewer(_("Parameters -listen and -via are incompatible"));
+ abort_vncviewer(_("Parameters -listen and -via are incompatible"));
return 1; /* Not reached */
}
#endif
}
} catch (rdr::Exception& e) {
vlog.error("%s", e.str());
- exit_vncviewer(_("Failure waiting for incoming VNC connection:\n\n%s"), e.str());
+ abort_vncviewer(_("Failure waiting for incoming VNC connection:\n\n%s"), e.str());
return 1; /* Not reached */
}
#endif
}
- CConn *cc = new CConn(vncServerName, sock);
-
inMainloop = true;
- while (!exitMainloop)
- run_mainloop();
+ mainloop(vncServerName, sock);
inMainloop = false;
- delete cc;
-
- if (exitError != NULL && alertOnFatalError)
- fl_alert("%s", exitError);
-
return 0;
}
# define __printf_attr(a, b)
#endif // __GNUC__
-void exit_vncviewer(const char *error = NULL, ...) __printf_attr(1, 2);
-bool should_exit();
+void abort_vncviewer(const char *error, ...) __printf_attr(1, 2);
+void abort_connection(const char *error, ...) __printf_attr(1, 2);
+void disconnect();
+bool should_disconnect();
+
void about_vncviewer();
-void run_mainloop();
#endif
.TP
.B \-AlertOnFatalError
Display a dialog with any fatal error before exiting. Default is on.
+.
+.TP
+.B \-ReconnectOnError
+Display a dialog with any error and offer the possibility to retry
+establishing the connection. In case this is off no dialog to
+re-connect will be offered. Default is on.
.SH FILES
.TP