@@ -111,8 +111,8 @@ CConn::CConn(const char* vncServerName, network::Socket* socket=NULL) | |||
} | |||
} 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; | |||
} | |||
} | |||
@@ -259,7 +259,7 @@ void CConn::socketEvent(FL_SOCKET fd, void *data) | |||
Timer::checkTimeouts(); | |||
// Also check if we need to stop reading and terminate | |||
if (should_exit()) | |||
if (should_disconnect()) | |||
break; | |||
} | |||
@@ -270,14 +270,14 @@ void CConn::socketEvent(FL_SOCKET fd, void *data) | |||
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()); | |||
} | |||
@@ -1393,7 +1393,7 @@ void DesktopWindow::repositionWidgets() | |||
void DesktopWindow::handleClose(Fl_Widget *wnd, void *data) | |||
{ | |||
exit_vncviewer(); | |||
disconnect(); | |||
} | |||
@@ -103,7 +103,7 @@ static rfb::LogWriter vlog("Viewport"); | |||
// 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 }; | |||
@@ -572,8 +572,9 @@ int Viewport::handle(int event) | |||
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); | |||
@@ -669,8 +670,9 @@ void Viewport::sendPointerEvent(const rfb::Point& pos, int buttonMask) | |||
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)) | |||
@@ -771,8 +773,9 @@ void Viewport::handleClipboardChange(int source, void *data) | |||
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()); | |||
} | |||
} | |||
@@ -785,8 +788,9 @@ void Viewport::flushPendingClipboard() | |||
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) { | |||
@@ -795,8 +799,9 @@ void Viewport::flushPendingClipboard() | |||
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()); | |||
} | |||
} | |||
@@ -822,8 +827,9 @@ void Viewport::handlePointerTimeout(void *data) | |||
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()); | |||
} | |||
} | |||
@@ -892,8 +898,9 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym) | |||
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()); | |||
} | |||
} | |||
@@ -927,8 +934,9 @@ void Viewport::handleKeyRelease(int keyCode) | |||
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); | |||
@@ -1239,8 +1247,8 @@ void Viewport::initContextMenu() | |||
{ | |||
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, | |||
@@ -1314,8 +1322,8 @@ void Viewport::popupContextMenu() | |||
return; | |||
switch (m->argument()) { | |||
case ID_EXIT: | |||
exit_vncviewer(); | |||
case ID_DISCONNECT: | |||
disconnect(); | |||
break; | |||
case ID_FULLSCREEN: | |||
if (window()->fullscreen_active()) |
@@ -69,6 +69,10 @@ BoolParameter alertOnFatalError("AlertOnFatalError", | |||
"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); |
@@ -74,6 +74,7 @@ extern rfb::StringParameter menuKey; | |||
extern rfb::BoolParameter fullscreenSystemKeys; | |||
extern rfb::BoolParameter alertOnFatalError; | |||
extern rfb::BoolParameter reconnectOnError; | |||
#ifndef WIN32 | |||
extern rfb::StringParameter via; |
@@ -181,7 +181,7 @@ static int handleTouchEvent(void *event, void *data) | |||
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)) { | |||
@@ -248,14 +248,14 @@ void enable_touch() | |||
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 | |||
} | |||
@@ -22,6 +22,7 @@ | |||
#include <config.h> | |||
#endif | |||
#include <assert.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <ctype.h> | |||
@@ -87,7 +88,8 @@ static const char *argv0 = NULL; | |||
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() | |||
{ | |||
@@ -107,17 +109,19 @@ 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); | |||
} | |||
@@ -131,7 +135,30 @@ void exit_vncviewer(const char *error, ...) | |||
} | |||
} | |||
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; | |||
} | |||
@@ -142,17 +169,57 @@ void about_vncviewer() | |||
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; | |||
} | |||
} | |||
@@ -429,8 +496,8 @@ potentiallyLoadConfigurationFile(char *vncServerName) | |||
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()); | |||
} | |||
} | |||
} | |||
@@ -640,7 +707,7 @@ int main(int argc, char** argv) | |||
// 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 | |||
@@ -687,7 +754,7 @@ int main(int argc, char** argv) | |||
} | |||
} 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 */ | |||
} | |||
@@ -708,17 +775,9 @@ int main(int argc, char** argv) | |||
#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; | |||
} |
@@ -27,9 +27,11 @@ | |||
# 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 |
@@ -328,6 +328,12 @@ respectively. | |||
.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 |