summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Lundin <hugo@lundin.dev>2021-07-15 12:52:56 +0200
committerHugo Lundin <hugo@lundin.dev>2021-07-16 16:08:19 +0200
commitc084e586927ff040014d6a8ea8c519b3a9a368d2 (patch)
treef7e29ef1cfb3065dc6297a26b1e8dd6f5f8ddfe9
parente2200c2456220c4dcc45024050d36fae6213f894 (diff)
downloadtigervnc-c084e586927ff040014d6a8ea8c519b3a9a368d2.tar.gz
tigervnc-c084e586927ff040014d6a8ea8c519b3a9a368d2.zip
Add fullscreen mode parameter
Before this commit, `FullScreen` and `FullScreenAllMonitors` could be used to configure whether to use the current monitor in fullscreen, or all monitors in fullscreen. This commit deprecates `FullScreenAllMonitors` in favour of `FullScreenMode` (which can either be `current` or `all`). This allows for additional modes to be added, without the risk of having invalid states (for example two activate two different fullscreen modes at the same time). A new concept has been added; read-only parameters. They are parameters that will be read, but never written back. This allows for migration paths to be constructed, where a parameter can be taken to consideration but then for example be discarded, logged or changed into something else. This has been used for `FullScreenAllMonitors` to provide a migration path. On startup of vncviewer, if `FullScreenAllMonitors` is enabled, `FullScreenMode=all` will be automatically enabled instead. The next time the configuration file is written to disk, `FullScreenAllMonitors` will then be removed.
-rw-r--r--vncviewer/DesktopWindow.cxx7
-rw-r--r--vncviewer/OptionsDialog.cxx49
-rw-r--r--vncviewer/OptionsDialog.h4
-rw-r--r--vncviewer/parameters.cxx166
-rw-r--r--vncviewer/parameters.h3
-rw-r--r--vncviewer/vncviewer.cxx12
-rw-r--r--vncviewer/vncviewer.man10
7 files changed, 182 insertions, 69 deletions
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 8c85c4d9..1fdce182 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -880,10 +880,11 @@ int DesktopWindow::fltkHandle(int event, Fl_Window *win)
return ret;
}
-
void DesktopWindow::fullscreen_on()
{
- if (not fullScreenAllMonitors)
+ bool all_monitors = !strcasecmp(fullScreenMode, "all");
+
+ if (not all_monitors)
fullscreen_screens(-1, -1, -1, -1);
else {
int top, bottom, left, right;
@@ -1377,7 +1378,7 @@ void DesktopWindow::handleOptions(void *data)
self->ungrabKeyboard();
// Call fullscreen_on even if active since it handles
- // fullScreenAllMonitors
+ // fullScreenMode
if (fullScreen)
self->fullscreen_on();
else if (!fullScreen && self->fullscreen_active())
diff --git a/vncviewer/OptionsDialog.cxx b/vncviewer/OptionsDialog.cxx
index 872a49cf..cbf4571d 100644
--- a/vncviewer/OptionsDialog.cxx
+++ b/vncviewer/OptionsDialog.cxx
@@ -297,7 +297,12 @@ void OptionsDialog::loadOptions(void)
}
remoteResizeCheckbox->value(remoteResize);
fullScreenCheckbox->value(fullScreen);
- fullScreenAllMonitorsCheckbox->value(fullScreenAllMonitors);
+
+ if (!strcasecmp(fullScreenMode, "all")) {
+ allMonitorsButton->setonly();
+ } else {
+ currentMonitorButton->setonly();
+ }
handleDesktopSize(desktopSizeCheckbox, this);
@@ -407,7 +412,12 @@ void OptionsDialog::storeOptions(void)
}
remoteResize.setParam(remoteResizeCheckbox->value());
fullScreen.setParam(fullScreenCheckbox->value());
- fullScreenAllMonitors.setParam(fullScreenAllMonitorsCheckbox->value());
+
+ if (allMonitorsButton->value()) {
+ fullScreenMode.setParam("All");
+ } else {
+ fullScreenMode.setParam("Current");
+ }
/* Misc. */
shared.setParam(sharedCheckbox->value());
@@ -755,6 +765,7 @@ void OptionsDialog::createInputPage(int tx, int ty, int tw, int th)
void OptionsDialog::createScreenPage(int tx, int ty, int tw, int th)
{
int x;
+ int width, height;
Fl_Group *group = new Fl_Group(tx, ty, tw, th, _("Screen"));
@@ -783,15 +794,35 @@ void OptionsDialog::createScreenPage(int tx, int ty, int tw, int th)
fullScreenCheckbox = new Fl_Check_Button(LBLRIGHT(tx, ty,
CHECK_MIN_WIDTH,
CHECK_HEIGHT,
- _("Full-screen mode")));
- ty += CHECK_HEIGHT + TIGHT_MARGIN;
+ _("Enable full-screen")));
+ ty += CHECK_HEIGHT + INNER_MARGIN;
- fullScreenAllMonitorsCheckbox = new Fl_Check_Button(LBLRIGHT(tx + INDENT, ty,
- CHECK_MIN_WIDTH,
- CHECK_HEIGHT,
- _("Enable full-screen mode over all monitors")));
- ty += CHECK_HEIGHT + TIGHT_MARGIN;
+ width = tw - OUTER_MARGIN * 2;
+ height = th - ty + OUTER_MARGIN * 3;
+ Fl_Group *fullScreenModeGroup = new Fl_Group(tx,
+ ty,
+ width,
+ height);
+
+ {
+ tx += INDENT;
+
+ currentMonitorButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
+ RADIO_MIN_WIDTH,
+ RADIO_HEIGHT,
+ _("Use current monitor")));
+ currentMonitorButton->type(FL_RADIO_BUTTON);
+ ty += RADIO_HEIGHT + TIGHT_MARGIN;
+
+ allMonitorsButton = new Fl_Round_Button(LBLRIGHT(tx, ty,
+ RADIO_MIN_WIDTH,
+ RADIO_HEIGHT,
+ _("Use all monitors")));
+ allMonitorsButton->type(FL_RADIO_BUTTON);
+ ty += RADIO_HEIGHT + TIGHT_MARGIN;
+ }
+ fullScreenModeGroup->end();
group->end();
}
diff --git a/vncviewer/OptionsDialog.h b/vncviewer/OptionsDialog.h
index fd3b9500..1c78ca16 100644
--- a/vncviewer/OptionsDialog.h
+++ b/vncviewer/OptionsDialog.h
@@ -125,7 +125,9 @@ protected:
Fl_Int_Input *desktopHeightInput;
Fl_Check_Button *remoteResizeCheckbox;
Fl_Check_Button *fullScreenCheckbox;
- Fl_Check_Button *fullScreenAllMonitorsCheckbox;
+
+ Fl_Round_Button *currentMonitorButton;
+ Fl_Round_Button *allMonitorsButton;
/* Misc. */
Fl_Check_Button *sharedCheckbox;
diff --git a/vncviewer/parameters.cxx b/vncviewer/parameters.cxx
index b28a1112..1525f13f 100644
--- a/vncviewer/parameters.cxx
+++ b/vncviewer/parameters.cxx
@@ -101,10 +101,13 @@ IntParameter qualityLevel("QualityLevel",
8);
BoolParameter maximize("Maximize", "Maximize viewer window", false);
-BoolParameter fullScreen("FullScreen", "Full screen mode", false);
+BoolParameter fullScreen("FullScreen", "Enable full screen", false);
+StringParameter fullScreenMode("FullScreenMode", "Specify which monitors to use when in full screen. "
+ "Should be either Current or All",
+ "Current");
BoolParameter fullScreenAllMonitors("FullScreenAllMonitors",
- "Enable full screen over all monitors",
- true);
+ "[DEPRECATED] Enable full screen over all monitors",
+ false);
StringParameter desktopSize("DesktopSize",
"Reconfigure desktop size on the server on "
"connect (if possible)", "");
@@ -175,7 +178,7 @@ static VoidParameter* parameterArray[] = {
&noJpeg,
&qualityLevel,
&fullScreen,
- &fullScreenAllMonitors,
+ &fullScreenMode,
&desktopSize,
&remoteResize,
&viewOnly,
@@ -190,6 +193,10 @@ static VoidParameter* parameterArray[] = {
&fullscreenSystemKeys
};
+static VoidParameter* readOnlyParameterArray[] = {
+ &fullScreenAllMonitors
+};
+
// Encoding Table
static struct {
const char first;
@@ -399,6 +406,30 @@ static bool getKeyInt(const char* _name, int* dest, HKEY* hKey) {
return true;
}
+static bool removeValue(const char* _name, HKEY* hKey) {
+ const DWORD buffersize = 256;
+ wchar_t name[buffersize];
+
+ unsigned size = fl_utf8towc(_name, strlen(_name)+1, name, buffersize);
+ if (size >= buffersize) {
+ vlog.error(_("The name of the parameter %s was too large to remove from the registry"), _name);
+ return false;
+ }
+
+ LONG res = RegDeleteValueW(*hKey, name);
+ if (res != ERROR_SUCCESS) {
+ if (res == ERROR_FILE_NOT_FOUND) {
+ // The value does not exist, no need to remove it.
+ return true;
+ } else {
+ vlog.error(_("Failed to remove parameter %s from the registry: %ld"),
+ _name, res);
+ return false;
+ }
+ }
+
+ return true;
+}
void saveHistoryToRegKey(const vector<string>& serverHistory) {
HKEY hKey;
@@ -456,6 +487,12 @@ static void saveToReg(const char* servername) {
}
}
+ // Remove read-only parameters to replicate the behaviour of Linux/macOS when they
+ // store a config to disk. If the parameter hasn't been migrated at this point it
+ // will be lost.
+ for (size_t i = 0; i < sizeof(readOnlyParameterArray)/sizeof(VoidParameter*); i++)
+ removeValue(readOnlyParameterArray[i]->getName(), &hKey);
+
res = RegCloseKey(hKey);
if (res != ERROR_SUCCESS) {
vlog.error(_("Failed to close registry key: %ld"), res);
@@ -500,6 +537,29 @@ void loadHistoryFromRegKey(vector<string>& serverHistory) {
}
}
+static void findAndSetViewerParametersFromReg(VoidParameter* parameters[], size_t parameters_len, HKEY* hKey) {
+
+ const size_t buffersize = 256;
+ int intValue = 0;
+ char stringValue[buffersize];
+
+ for (size_t i = 0; i < parameters_len/sizeof(VoidParameter*); i++) {
+ if (dynamic_cast<StringParameter*>(parameters[i]) != NULL) {
+ if (getKeyString(parameters[i]->getName(), stringValue, buffersize, hKey))
+ parameters[i]->setParam(stringValue);
+ } else if (dynamic_cast<IntParameter*>(parameters[i]) != NULL) {
+ if (getKeyInt(parameters[i]->getName(), &intValue, hKey))
+ ((IntParameter*)parameters[i])->setParam(intValue);
+ } else if (dynamic_cast<BoolParameter*>(parameters[i]) != NULL) {
+ if (getKeyInt(parameters[i]->getName(), &intValue, hKey))
+ ((BoolParameter*)parameters[i])->setParam(intValue);
+ } else {
+ vlog.error(_("Unknown parameter type for parameter %s"),
+ parameters[i]->getName());
+ }
+ }
+}
+
static char* loadFromReg() {
HKEY hKey;
@@ -523,24 +583,8 @@ static char* loadFromReg() {
if (getKeyString("ServerName", servernameBuffer, buffersize, &hKey))
snprintf(servername, buffersize, "%s", servernameBuffer);
- int intValue = 0;
- char stringValue[buffersize];
-
- for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
- if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
- if (getKeyString(parameterArray[i]->getName(), stringValue, buffersize, &hKey))
- parameterArray[i]->setParam(stringValue);
- } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
- if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
- ((IntParameter*)parameterArray[i])->setParam(intValue);
- } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
- if (getKeyInt(parameterArray[i]->getName(), &intValue, &hKey))
- ((BoolParameter*)parameterArray[i])->setParam(intValue);
- } else {
- vlog.error(_("Unknown parameter type for parameter %s"),
- parameterArray[i]->getName());
- }
- }
+ findAndSetViewerParametersFromReg(parameterArray, sizeof(parameterArray), &hKey);
+ findAndSetViewerParametersFromReg(readOnlyParameterArray, sizeof(readOnlyParameterArray), &hKey);
res = RegCloseKey(hKey);
if (res != ERROR_SUCCESS){
@@ -607,6 +651,48 @@ void saveViewerParameters(const char *filename, const char *servername) {
fclose(f);
}
+static bool findAndSetViewerParameterFromValue(
+ VoidParameter* parameters[], size_t parameters_len,
+ char* value, char* line, int lineNr, char* filepath)
+{
+ const size_t buffersize = 256;
+ char decodingBuffer[buffersize];
+
+ // Find and set the correct parameter
+ for (size_t i = 0; i < parameters_len/sizeof(VoidParameter*); i++) {
+
+ if (dynamic_cast<StringParameter*>(parameters[i]) != NULL) {
+ if (strcasecmp(line, ((StringParameter*)parameters[i])->getName()) == 0) {
+
+ if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
+ vlog.error(_("Failed to read line %d in file %s: %s"),
+ lineNr, filepath, _("Invalid format or too large value"));
+ continue;
+ }
+ ((StringParameter*)parameters[i])->setParam(decodingBuffer);
+ return false;
+ }
+
+ } else if (dynamic_cast<IntParameter*>(parameters[i]) != NULL) {
+ if (strcasecmp(line, ((IntParameter*)parameters[i])->getName()) == 0) {
+ ((IntParameter*)parameters[i])->setParam(atoi(value));
+ return false;
+ }
+
+ } else if (dynamic_cast<BoolParameter*>(parameters[i]) != NULL) {
+ if (strcasecmp(line, ((BoolParameter*)parameters[i])->getName()) == 0) {
+ ((BoolParameter*)parameters[i])->setParam(atoi(value));
+ return false;
+ }
+
+ } else {
+ vlog.error(_("Unknown parameter type for parameter %s"),
+ parameters[i]->getName());
+ }
+ }
+
+ return true;
+}
char* loadViewerParameters(const char *filename) {
@@ -705,38 +791,12 @@ char* loadViewerParameters(const char *filename) {
invalidParameterName = false;
} else {
+ invalidParameterName = findAndSetViewerParameterFromValue(parameterArray, sizeof(parameterArray),
+ value, line, lineNr, filepath);
- // Find and set the correct parameter
- for (size_t i = 0; i < sizeof(parameterArray)/sizeof(VoidParameter*); i++) {
-
- if (dynamic_cast<StringParameter*>(parameterArray[i]) != NULL) {
- if (strcasecmp(line, ((StringParameter*)parameterArray[i])->getName()) == 0) {
-
- if(!decodeValue(value, decodingBuffer, sizeof(decodingBuffer))) {
- vlog.error(_("Failed to read line %d in file %s: %s"),
- lineNr, filepath, _("Invalid format or too large value"));
- continue;
- }
- ((StringParameter*)parameterArray[i])->setParam(decodingBuffer);
- invalidParameterName = false;
- }
-
- } else if (dynamic_cast<IntParameter*>(parameterArray[i]) != NULL) {
- if (strcasecmp(line, ((IntParameter*)parameterArray[i])->getName()) == 0) {
- ((IntParameter*)parameterArray[i])->setParam(atoi(value));
- invalidParameterName = false;
- }
-
- } else if (dynamic_cast<BoolParameter*>(parameterArray[i]) != NULL) {
- if (strcasecmp(line, ((BoolParameter*)parameterArray[i])->getName()) == 0) {
- ((BoolParameter*)parameterArray[i])->setParam(atoi(value));
- invalidParameterName = false;
- }
-
- } else {
- vlog.error(_("Unknown parameter type for parameter %s"),
- parameterArray[i]->getName());
- }
+ if (invalidParameterName) {
+ invalidParameterName = findAndSetViewerParameterFromValue(readOnlyParameterArray, sizeof(readOnlyParameterArray),
+ value, line, lineNr, filepath);
}
}
diff --git a/vncviewer/parameters.h b/vncviewer/parameters.h
index 3d8ac24f..fee37ee8 100644
--- a/vncviewer/parameters.h
+++ b/vncviewer/parameters.h
@@ -49,7 +49,8 @@ extern rfb::IntParameter qualityLevel;
extern rfb::BoolParameter maximize;
extern rfb::BoolParameter fullScreen;
-extern rfb::BoolParameter fullScreenAllMonitors;
+extern rfb::StringParameter fullScreenMode;
+extern rfb::BoolParameter fullScreenAllMonitors; // deprecated
extern rfb::StringParameter desktopSize;
extern rfb::StringParameter geometry;
extern rfb::BoolParameter remoteResize;
diff --git a/vncviewer/vncviewer.cxx b/vncviewer/vncviewer.cxx
index bb41a2f7..6a84c7cb 100644
--- a/vncviewer/vncviewer.cxx
+++ b/vncviewer/vncviewer.cxx
@@ -435,6 +435,16 @@ potentiallyLoadConfigurationFile(char *vncServerName)
}
}
+static void
+migrateDeprecatedOptions()
+{
+ if (fullScreenAllMonitors) {
+ vlog.info(_("FullScreenAllMonitors is deprecated, set FullScreenMode to 'all' instead."));
+
+ fullScreenMode.setParam("all");
+ }
+}
+
#ifndef WIN32
static int
interpretViaParam(char *remoteHost, int *remotePort, int localPort)
@@ -613,6 +623,8 @@ int main(int argc, char** argv)
// Check if the server name in reality is a configuration file
potentiallyLoadConfigurationFile(vncServerName);
+ migrateDeprecatedOptions();
+
mkvnchomedir();
CSecurity::upg = &dlg;
diff --git a/vncviewer/vncviewer.man b/vncviewer/vncviewer.man
index 868e6aeb..ff81b914 100644
--- a/vncviewer/vncviewer.man
+++ b/vncviewer/vncviewer.man
@@ -205,9 +205,15 @@ Maximize viewer window.
Start in full-screen mode.
.
.TP
-.B \-FullScreenAllMonitors
+.B \-FullScreenAllMonitors (DEPRECATED)
Use all local monitors and not just the current one when switching to
-full-screen mode.
+full-screen mode. Replaced by \fB-FullScreenMode=all\fP
+.
+.TP
+.B \-FullScreenMode \fImode\fP
+Specify which monitors to use when in full screen. It should be either "Current" or "All".
+The default is "Current".
+.
.
.TP
.B \-FullscreenSystemKeys