2019-03-30 04:52:00 +00:00
|
|
|
/*
|
|
|
|
Looking Glass - KVM FrameRelay (KVMFR) Client
|
|
|
|
Copyright (C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>
|
|
|
|
https://looking-glass.hostfission.com
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU General Public License as published by the Free Software
|
|
|
|
Foundation; either version 2 of the License, or (at your option) any later
|
|
|
|
version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
|
|
PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
|
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
|
|
Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
#include "config.h"
|
2021-01-26 10:46:30 +00:00
|
|
|
#include "kb.h"
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
#include "common/option.h"
|
2019-04-11 01:12:59 +00:00
|
|
|
#include "common/debug.h"
|
2019-05-21 05:03:59 +00:00
|
|
|
#include "common/stringutils.h"
|
2019-03-30 04:52:00 +00:00
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <unistd.h>
|
2021-01-26 10:46:30 +00:00
|
|
|
#include <string.h>
|
2021-01-18 16:08:56 +00:00
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
// forwards
|
2020-01-18 19:49:56 +00:00
|
|
|
static bool optRendererParse (struct Option * opt, const char * str);
|
|
|
|
static StringList optRendererValues (struct Option * opt);
|
|
|
|
static char * optRendererToString(struct Option * opt);
|
|
|
|
static bool optPosParse (struct Option * opt, const char * str);
|
|
|
|
static StringList optPosValues (struct Option * opt);
|
|
|
|
static char * optPosToString (struct Option * opt);
|
|
|
|
static bool optSizeParse (struct Option * opt, const char * str);
|
|
|
|
static StringList optSizeValues (struct Option * opt);
|
|
|
|
static char * optSizeToString (struct Option * opt);
|
2021-01-26 10:46:30 +00:00
|
|
|
static bool optScancodeValidate(struct Option * opt, const char ** error);
|
2020-01-18 19:49:56 +00:00
|
|
|
static char * optScancodeToString(struct Option * opt);
|
2021-01-18 03:42:57 +00:00
|
|
|
static bool optRotateValidate (struct Option * opt, const char ** error);
|
2019-05-21 05:03:59 +00:00
|
|
|
|
2019-03-30 04:52:00 +00:00
|
|
|
static void doLicense();
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
static struct Option options[] =
|
2019-03-30 04:52:00 +00:00
|
|
|
{
|
2019-05-21 05:03:59 +00:00
|
|
|
// app options
|
|
|
|
{
|
|
|
|
.module = "app",
|
|
|
|
.name = "configFile",
|
|
|
|
.description = "A file to read additional configuration from",
|
|
|
|
.shortopt = 'C',
|
|
|
|
.type = OPTION_TYPE_STRING,
|
|
|
|
.value.x_string = NULL,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "app",
|
|
|
|
.name = "renderer",
|
|
|
|
.description = "Specify the renderer to use",
|
|
|
|
.shortopt = 'g',
|
|
|
|
.type = OPTION_TYPE_CUSTOM,
|
|
|
|
.parser = optRendererParse,
|
|
|
|
.getValues = optRendererValues,
|
|
|
|
.toString = optRendererToString
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "app",
|
|
|
|
.name = "license",
|
2019-05-21 05:51:14 +00:00
|
|
|
.description = "Show the license for this application and then terminate",
|
2019-05-21 05:03:59 +00:00
|
|
|
.shortopt = 'l',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
2019-05-22 02:00:06 +00:00
|
|
|
{
|
|
|
|
.module = "app",
|
|
|
|
.name = "cursorPollInterval",
|
|
|
|
.description = "How often to check for a cursor update in microseconds",
|
|
|
|
.type = OPTION_TYPE_INT,
|
|
|
|
.value.x_int = 1000
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "app",
|
|
|
|
.name = "framePollInterval",
|
|
|
|
.description = "How often to check for a frame update in microseconds",
|
|
|
|
.type = OPTION_TYPE_INT,
|
|
|
|
.value.x_int = 1000
|
|
|
|
},
|
2020-10-29 15:32:25 +00:00
|
|
|
{
|
|
|
|
.module = "app",
|
|
|
|
.name = "allowDMA",
|
|
|
|
.description = "Allow direct DMA transfers if possible (VM-VM only for now)",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
2019-05-21 05:03:59 +00:00
|
|
|
|
|
|
|
// window options
|
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "title",
|
|
|
|
.description = "The window title",
|
|
|
|
.type = OPTION_TYPE_STRING,
|
|
|
|
.value.x_string = "Looking Glass (client)"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "position",
|
|
|
|
.description = "Initial window position at startup",
|
|
|
|
.type = OPTION_TYPE_CUSTOM,
|
|
|
|
.parser = optPosParse,
|
|
|
|
.getValues = optPosValues,
|
|
|
|
.toString = optPosToString
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "size",
|
|
|
|
.description = "Initial window size at startup",
|
|
|
|
.type = OPTION_TYPE_CUSTOM,
|
|
|
|
.parser = optSizeParse,
|
|
|
|
.getValues = optSizeValues,
|
|
|
|
.toString = optSizeToString
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "autoResize",
|
|
|
|
.description = "Auto resize the window to the guest",
|
|
|
|
.shortopt = 'a',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "allowResize",
|
2019-05-27 08:38:01 +00:00
|
|
|
.description = "Allow the window to be manually resized",
|
2019-05-21 05:03:59 +00:00
|
|
|
.shortopt = 'n',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "keepAspect",
|
|
|
|
.description = "Maintain the correct aspect ratio",
|
|
|
|
.shortopt = 'r',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true,
|
|
|
|
},
|
2020-01-03 04:53:44 +00:00
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "forceAspect",
|
|
|
|
.description = "Force the window to maintain the aspect ratio",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true,
|
|
|
|
},
|
2020-10-12 12:27:33 +00:00
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "dontUpscale",
|
|
|
|
.description = "Never try to upscale the window",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
2019-05-21 05:03:59 +00:00
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "borderless",
|
|
|
|
.description = "Borderless mode",
|
|
|
|
.shortopt = 'd',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "fullScreen",
|
|
|
|
.description = "Launch in fullscreen borderless mode",
|
|
|
|
.shortopt = 'F',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
2019-05-26 06:30:24 +00:00
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "maximize",
|
|
|
|
.description = "Launch window maximized",
|
|
|
|
.shortopt = 'T',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
2019-07-01 07:53:12 +00:00
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "minimizeOnFocusLoss",
|
|
|
|
.description = "Minimize window on focus loss",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true,
|
|
|
|
},
|
2019-05-21 05:03:59 +00:00
|
|
|
{
|
|
|
|
.module = "win",
|
2020-05-22 08:28:16 +00:00
|
|
|
.name = "fpsMin",
|
2020-05-22 08:15:17 +00:00
|
|
|
.description = "Frame rate minimum (0 = disable - not recommended, -1 = auto detect)",
|
2019-05-21 05:03:59 +00:00
|
|
|
.shortopt = 'K',
|
|
|
|
.type = OPTION_TYPE_INT,
|
2019-07-09 01:13:24 +00:00
|
|
|
.value.x_int = -1,
|
2019-05-21 05:03:59 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "showFPS",
|
|
|
|
.description = "Enable the FPS & UPS display",
|
|
|
|
.shortopt = 'k',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "ignoreQuit",
|
|
|
|
.description = "Ignore requests to quit (ie: Alt+F4)",
|
|
|
|
.shortopt = 'Q',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "noScreensaver",
|
|
|
|
.description = "Prevent the screensaver from starting",
|
|
|
|
.shortopt = 'S',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
2021-02-03 23:01:53 +00:00
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "autoScreensaver",
|
|
|
|
.description = "Prevent the screensaver from starting when guest requests it",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
2019-05-21 05:03:59 +00:00
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "alerts",
|
|
|
|
.description = "Show on screen alert messages",
|
|
|
|
.shortopt = 'q',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true,
|
|
|
|
},
|
2020-07-19 04:29:29 +00:00
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "quickSplash",
|
|
|
|
.description = "Skip fading out the splash screen when a connection is established",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
2021-01-15 01:40:59 +00:00
|
|
|
{
|
|
|
|
.module = "win",
|
|
|
|
.name = "rotate",
|
2021-01-20 04:35:13 +00:00
|
|
|
.description = "Rotate the displayed image (0, 90, 180, 270)",
|
2021-01-18 03:42:57 +00:00
|
|
|
.type = OPTION_TYPE_INT,
|
|
|
|
.validator = optRotateValidate,
|
|
|
|
.value.x_int = 0,
|
2021-01-15 01:40:59 +00:00
|
|
|
},
|
2019-05-21 05:03:59 +00:00
|
|
|
|
|
|
|
// input options
|
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "grabKeyboard",
|
|
|
|
.description = "Grab the keyboard in capture mode",
|
|
|
|
.shortopt = 'G',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true,
|
|
|
|
},
|
2020-11-28 20:12:19 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "grabKeyboardOnFocus",
|
|
|
|
.description = "Grab the keyboard when focused",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true,
|
|
|
|
},
|
2021-02-13 07:19:01 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "releaseKeysOnFocusLoss",
|
|
|
|
.description = "On focus loss, send key up events to guest for all held keys",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
2019-05-21 05:03:59 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "escapeKey",
|
2021-01-26 10:46:30 +00:00
|
|
|
.description = "Specify the escape key, see <linux/input-event-codes.h> for valid values",
|
2019-05-21 05:03:59 +00:00
|
|
|
.shortopt = 'm',
|
|
|
|
.type = OPTION_TYPE_INT,
|
2021-01-26 10:46:30 +00:00
|
|
|
.value.x_int = KEY_SCROLLLOCK,
|
|
|
|
.validator = optScancodeValidate,
|
|
|
|
.toString = optScancodeToString,
|
2019-05-21 05:03:59 +00:00
|
|
|
},
|
2021-01-04 07:22:39 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "ignoreWindowsKeys",
|
|
|
|
.description = "Do not pass events for the windows keys to the guest",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false
|
|
|
|
},
|
2019-05-21 05:03:59 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "hideCursor",
|
|
|
|
.description = "Hide the local mouse cursor",
|
|
|
|
.shortopt = 'M',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true,
|
|
|
|
},
|
2019-05-23 19:29:38 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "mouseSens",
|
2019-05-23 19:31:16 +00:00
|
|
|
.description = "Initial mouse sensitivity when in capture mode (-9 to 9)",
|
2019-05-23 19:29:38 +00:00
|
|
|
.type = OPTION_TYPE_INT,
|
|
|
|
.value.x_int = 0,
|
|
|
|
},
|
2021-01-09 03:39:48 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "mouseSmoothing",
|
2021-01-09 03:55:20 +00:00
|
|
|
.description = "Apply simple mouse smoothing when rawMouse is not in use (helps reduce aliasing)",
|
2021-01-09 03:39:48 +00:00
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true,
|
|
|
|
},
|
2021-01-07 16:12:42 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "rawMouse",
|
|
|
|
.description = "Use RAW mouse input when in capture mode (good for gaming)",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false,
|
|
|
|
},
|
2020-08-20 05:50:33 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "mouseRedraw",
|
|
|
|
.description = "Mouse movements trigger redraws (ignores FPS minimum)",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true,
|
|
|
|
},
|
2021-01-08 08:41:10 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "autoCapture",
|
|
|
|
.description = "Try to keep the mouse captured when needed",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false
|
|
|
|
},
|
2021-01-09 07:01:08 +00:00
|
|
|
{
|
|
|
|
.module = "input",
|
|
|
|
.name = "captureOnly",
|
|
|
|
.description = "Only enable input via SPICE if in capture mode",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false
|
|
|
|
},
|
2019-05-21 05:03:59 +00:00
|
|
|
|
|
|
|
// spice options
|
|
|
|
{
|
|
|
|
.module = "spice",
|
|
|
|
.name = "enable",
|
|
|
|
.description = "Enable the built in SPICE client for input and/or clipboard support",
|
|
|
|
.shortopt = 's',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "spice",
|
|
|
|
.name = "host",
|
|
|
|
.description = "The SPICE server host or UNIX socket",
|
|
|
|
.shortopt = 'c',
|
|
|
|
.type = OPTION_TYPE_STRING,
|
|
|
|
.value.x_string = "127.0.0.1"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "spice",
|
|
|
|
.name = "port",
|
|
|
|
.description = "The SPICE server port (0 = unix socket)",
|
|
|
|
.shortopt = 'p',
|
|
|
|
.type = OPTION_TYPE_INT,
|
|
|
|
.value.x_int = 5900
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "spice",
|
|
|
|
.name = "input",
|
|
|
|
.description = "Use SPICE to send keyboard and mouse input events to the guest",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "spice",
|
|
|
|
.name = "clipboard",
|
|
|
|
.description = "Use SPICE to syncronize the clipboard contents with the guest",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "spice",
|
|
|
|
.name = "clipboardToVM",
|
|
|
|
.description = "Allow the clipboard to be syncronized TO the VM",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "spice",
|
|
|
|
.name = "clipboardToLocal",
|
|
|
|
.description = "Allow the clipboard to be syncronized FROM the VM",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.module = "spice",
|
|
|
|
.name = "scaleCursor",
|
|
|
|
.description = "Scale cursor input position to screen size when up/down scaled",
|
|
|
|
.shortopt = 'j',
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = true
|
|
|
|
},
|
2020-05-21 01:13:42 +00:00
|
|
|
{
|
|
|
|
.module = "spice",
|
|
|
|
.name = "captureOnStart",
|
|
|
|
.description = "Capture mouse and keyboard on start",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false
|
|
|
|
},
|
2020-11-15 13:41:22 +00:00
|
|
|
{
|
|
|
|
.module = "spice",
|
|
|
|
.name = "alwaysShowCursor",
|
|
|
|
.description = "Always show host cursor",
|
|
|
|
.type = OPTION_TYPE_BOOL,
|
|
|
|
.value.x_bool = false
|
|
|
|
},
|
2019-05-21 05:03:59 +00:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
2021-01-14 06:05:26 +00:00
|
|
|
void config_init(void)
|
2019-05-21 05:03:59 +00:00
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.center = true;
|
|
|
|
g_params.w = 1024;
|
|
|
|
g_params.h = 768;
|
2019-03-30 04:52:00 +00:00
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
option_register(options);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool config_load(int argc, char * argv[])
|
|
|
|
{
|
|
|
|
// load any global options first
|
2019-03-30 04:52:00 +00:00
|
|
|
struct stat st;
|
2019-05-21 05:03:59 +00:00
|
|
|
if (stat("/etc/looking-glass-client.ini", &st) >= 0)
|
2019-03-30 04:52:00 +00:00
|
|
|
{
|
2019-05-21 05:03:59 +00:00
|
|
|
DEBUG_INFO("Loading config from: /etc/looking-glass-client.ini");
|
|
|
|
if (!option_load("/etc/looking-glass-client.ini"))
|
2019-03-30 04:52:00 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
// load user's local options
|
2019-03-30 04:52:00 +00:00
|
|
|
struct passwd * pw = getpwuid(getuid());
|
2019-05-21 05:03:59 +00:00
|
|
|
char * localFile;
|
|
|
|
alloc_sprintf(&localFile, "%s/.looking-glass-client.ini", pw->pw_dir);
|
|
|
|
if (stat(localFile, &st) >= 0)
|
2019-03-30 04:52:00 +00:00
|
|
|
{
|
2019-05-21 05:03:59 +00:00
|
|
|
DEBUG_INFO("Loading config from: %s", localFile);
|
|
|
|
if (!option_load(localFile))
|
2019-03-30 04:52:00 +00:00
|
|
|
{
|
2019-05-21 05:03:59 +00:00
|
|
|
free(localFile);
|
|
|
|
return false;
|
2019-03-30 04:52:00 +00:00
|
|
|
}
|
|
|
|
}
|
2019-05-21 05:03:59 +00:00
|
|
|
free(localFile);
|
2019-03-30 04:52:00 +00:00
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
// parse the command line arguments
|
|
|
|
if (!option_parse(argc, argv))
|
2019-03-30 04:52:00 +00:00
|
|
|
return false;
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
// if a file was specified to also load, do it
|
|
|
|
const char * configFile = option_get_string("app", "configFile");
|
|
|
|
if (configFile)
|
2019-03-30 05:00:47 +00:00
|
|
|
{
|
2019-05-21 05:03:59 +00:00
|
|
|
DEBUG_INFO("Loading config from: %s", configFile);
|
|
|
|
if (!option_load(configFile))
|
|
|
|
return false;
|
2019-03-30 05:00:47 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
// validate the values are sane
|
|
|
|
if (!option_validate())
|
2019-03-30 04:52:00 +00:00
|
|
|
return false;
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
if (option_get_bool("app", "license"))
|
2019-03-30 04:52:00 +00:00
|
|
|
{
|
2019-05-21 05:03:59 +00:00
|
|
|
doLicense();
|
|
|
|
return false;
|
2019-03-30 04:52:00 +00:00
|
|
|
}
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
// setup the application params for the basic types
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.cursorPollInterval = option_get_int ("app", "cursorPollInterval");
|
|
|
|
g_params.framePollInterval = option_get_int ("app", "framePollInterval" );
|
|
|
|
g_params.allowDMA = option_get_bool ("app", "allowDMA" );
|
|
|
|
|
2021-02-03 23:01:53 +00:00
|
|
|
g_params.windowTitle = option_get_string("win", "title" );
|
|
|
|
g_params.autoResize = option_get_bool ("win", "autoResize" );
|
|
|
|
g_params.allowResize = option_get_bool ("win", "allowResize" );
|
|
|
|
g_params.keepAspect = option_get_bool ("win", "keepAspect" );
|
|
|
|
g_params.forceAspect = option_get_bool ("win", "forceAspect" );
|
|
|
|
g_params.dontUpscale = option_get_bool ("win", "dontUpscale" );
|
|
|
|
g_params.borderless = option_get_bool ("win", "borderless" );
|
|
|
|
g_params.fullscreen = option_get_bool ("win", "fullScreen" );
|
|
|
|
g_params.maximize = option_get_bool ("win", "maximize" );
|
|
|
|
g_params.fpsMin = option_get_int ("win", "fpsMin" );
|
|
|
|
g_params.showFPS = option_get_bool ("win", "showFPS" );
|
|
|
|
g_params.ignoreQuit = option_get_bool ("win", "ignoreQuit" );
|
|
|
|
g_params.noScreensaver = option_get_bool ("win", "noScreensaver" );
|
|
|
|
g_params.autoScreensaver = option_get_bool ("win", "autoScreensaver");
|
|
|
|
g_params.showAlerts = option_get_bool ("win", "alerts" );
|
|
|
|
g_params.quickSplash = option_get_bool ("win", "quickSplash" );
|
|
|
|
|
|
|
|
if (g_params.noScreensaver && g_params.autoScreensaver)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "win:noScreensaver (-S) and win:autoScreensaver "
|
|
|
|
"can't be used simultaneously\n");
|
|
|
|
return false;
|
|
|
|
}
|
2019-05-21 05:03:59 +00:00
|
|
|
|
2021-01-18 03:42:57 +00:00
|
|
|
switch(option_get_int("win", "rotate"))
|
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
case 0 : g_params.winRotate = LG_ROTATE_0 ; break;
|
|
|
|
case 90 : g_params.winRotate = LG_ROTATE_90 ; break;
|
|
|
|
case 180: g_params.winRotate = LG_ROTATE_180; break;
|
|
|
|
case 270: g_params.winRotate = LG_ROTATE_270; break;
|
2021-01-18 03:42:57 +00:00
|
|
|
}
|
|
|
|
|
2021-02-13 07:19:01 +00:00
|
|
|
g_params.grabKeyboard = option_get_bool("input", "grabKeyboard" );
|
|
|
|
g_params.grabKeyboardOnFocus = option_get_bool("input", "grabKeyboardOnFocus" );
|
|
|
|
g_params.releaseKeysOnFocusLoss = option_get_bool("input", "releaseKeysOnFocusLoss");
|
|
|
|
g_params.escapeKey = option_get_int ("input", "escapeKey" );
|
|
|
|
g_params.ignoreWindowsKeys = option_get_bool("input", "ignoreWindowsKeys" );
|
|
|
|
g_params.hideMouse = option_get_bool("input", "hideCursor" );
|
|
|
|
g_params.mouseSens = option_get_int ("input", "mouseSens" );
|
|
|
|
g_params.mouseSmoothing = option_get_bool("input", "mouseSmoothing" );
|
|
|
|
g_params.rawMouse = option_get_bool("input", "rawMouse" );
|
|
|
|
g_params.mouseRedraw = option_get_bool("input", "mouseRedraw" );
|
|
|
|
g_params.autoCapture = option_get_bool("input", "autoCapture" );
|
|
|
|
g_params.captureInputOnly = option_get_bool("input", "captureOnly" );
|
2019-05-21 05:03:59 +00:00
|
|
|
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.minimizeOnFocusLoss = option_get_bool("win", "minimizeOnFocusLoss");
|
2019-07-01 07:53:12 +00:00
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
if (option_get_bool("spice", "enable"))
|
2019-03-30 04:52:00 +00:00
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.spiceHost = option_get_string("spice", "host");
|
|
|
|
g_params.spicePort = option_get_int ("spice", "port");
|
2019-03-30 04:52:00 +00:00
|
|
|
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.useSpiceInput = option_get_bool("spice", "input" );
|
|
|
|
g_params.useSpiceClipboard = option_get_bool("spice", "clipboard");
|
2019-03-30 04:52:00 +00:00
|
|
|
|
2021-01-25 08:58:36 +00:00
|
|
|
if (g_params.useSpiceClipboard)
|
2019-03-30 04:52:00 +00:00
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.clipboardToVM = option_get_bool("spice", "clipboardToVM" );
|
|
|
|
g_params.clipboardToLocal = option_get_bool("spice", "clipboardToLocal");
|
2019-03-30 04:52:00 +00:00
|
|
|
|
2021-01-25 08:58:36 +00:00
|
|
|
if (!g_params.clipboardToVM && !g_params.clipboardToLocal)
|
|
|
|
g_params.useSpiceClipboard = false;
|
2019-03-30 04:52:00 +00:00
|
|
|
}
|
|
|
|
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.scaleMouseInput = option_get_bool("spice", "scaleCursor");
|
|
|
|
g_params.captureOnStart = option_get_bool("spice", "captureOnStart");
|
|
|
|
g_params.alwaysShowCursor = option_get_bool("spice", "alwaysShowCursor");
|
2019-03-30 04:52:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-14 06:05:26 +00:00
|
|
|
void config_free(void)
|
2019-03-30 04:52:00 +00:00
|
|
|
{
|
2019-05-21 05:51:45 +00:00
|
|
|
option_free();
|
2019-03-30 04:52:00 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 06:05:26 +00:00
|
|
|
static void doLicense(void)
|
2019-03-30 04:52:00 +00:00
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"\n"
|
|
|
|
"Looking Glass - KVM FrameRelay (KVMFR) Client\n"
|
|
|
|
"Copyright(C) 2017-2019 Geoffrey McRae <geoff@hostfission.com>\n"
|
|
|
|
"https://looking-glass.hostfission.com\n"
|
|
|
|
"\n"
|
|
|
|
"This program is free software; you can redistribute it and / or modify it under\n"
|
|
|
|
"the terms of the GNU General Public License as published by the Free Software\n"
|
|
|
|
"Foundation; either version 2 of the License, or (at your option) any later\n"
|
|
|
|
"version.\n"
|
|
|
|
"\n"
|
|
|
|
"This program is distributed in the hope that it will be useful, but WITHOUT ANY\n"
|
|
|
|
"WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n"
|
|
|
|
"PARTICULAR PURPOSE.See the GNU General Public License for more details.\n"
|
|
|
|
"\n"
|
|
|
|
"You should have received a copy of the GNU General Public License along with\n"
|
|
|
|
"this program; if not, write to the Free Software Foundation, Inc., 59 Temple\n"
|
|
|
|
"Place, Suite 330, Boston, MA 02111 - 1307 USA\n"
|
|
|
|
"\n"
|
|
|
|
);
|
2019-05-21 05:03:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool optRendererParse(struct Option * opt, const char * str)
|
|
|
|
{
|
2020-01-18 19:48:20 +00:00
|
|
|
if (!str)
|
|
|
|
return false;
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
if (strcasecmp(str, "auto") == 0)
|
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.forceRenderer = false;
|
2019-05-21 05:03:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i)
|
|
|
|
if (strcasecmp(str, LG_Renderers[i]->get_name()) == 0)
|
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.forceRenderer = true;
|
|
|
|
g_params.forceRendererIndex = i;
|
2019-05-21 05:03:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static StringList optRendererValues(struct Option * opt)
|
|
|
|
{
|
|
|
|
StringList sl = stringlist_new(false);
|
|
|
|
|
|
|
|
// this typecast is safe as the stringlist doesn't own the values
|
|
|
|
for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i)
|
|
|
|
stringlist_push(sl, (char *)LG_Renderers[i]->get_name());
|
|
|
|
|
|
|
|
return sl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char * optRendererToString(struct Option * opt)
|
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
if (!g_params.forceRenderer)
|
2019-05-21 05:03:59 +00:00
|
|
|
return strdup("auto");
|
|
|
|
|
2021-01-25 08:58:36 +00:00
|
|
|
if (g_params.forceRendererIndex >= LG_RENDERER_COUNT)
|
2019-05-21 05:03:59 +00:00
|
|
|
return NULL;
|
|
|
|
|
2021-01-25 08:58:36 +00:00
|
|
|
return strdup(LG_Renderers[g_params.forceRendererIndex]->get_name());
|
2019-05-21 05:03:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool optPosParse(struct Option * opt, const char * str)
|
|
|
|
{
|
2020-01-18 19:48:20 +00:00
|
|
|
if (!str)
|
|
|
|
return false;
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
if (strcmp(str, "center") == 0)
|
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.center = true;
|
2019-05-21 05:03:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-01-25 08:58:36 +00:00
|
|
|
if (sscanf(str, "%dx%d", &g_params.x, &g_params.y) == 2)
|
2019-05-21 05:03:59 +00:00
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
g_params.center = false;
|
2019-05-21 05:03:59 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static StringList optPosValues(struct Option * opt)
|
|
|
|
{
|
|
|
|
StringList sl = stringlist_new(false);
|
|
|
|
stringlist_push(sl, "center");
|
|
|
|
stringlist_push(sl, "<left>x<top>, ie: 100x100");
|
|
|
|
return sl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char * optPosToString(struct Option * opt)
|
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
if (g_params.center)
|
2019-05-21 05:03:59 +00:00
|
|
|
return strdup("center");
|
|
|
|
|
2021-01-25 08:58:36 +00:00
|
|
|
int len = snprintf(NULL, 0, "%dx%d", g_params.x, g_params.y);
|
2019-05-21 05:03:59 +00:00
|
|
|
char * str = malloc(len + 1);
|
2021-01-25 08:58:36 +00:00
|
|
|
sprintf(str, "%dx%d", g_params.x, g_params.y);
|
2019-05-21 05:03:59 +00:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool optSizeParse(struct Option * opt, const char * str)
|
|
|
|
{
|
2020-01-18 19:48:20 +00:00
|
|
|
if (!str)
|
|
|
|
return false;
|
|
|
|
|
2021-01-25 08:58:36 +00:00
|
|
|
if (sscanf(str, "%dx%d", &g_params.w, &g_params.h) == 2)
|
2019-05-21 05:03:59 +00:00
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
if (g_params.w < 1 || g_params.h < 1)
|
2019-05-21 05:03:59 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static StringList optSizeValues(struct Option * opt)
|
|
|
|
{
|
|
|
|
StringList sl = stringlist_new(false);
|
|
|
|
stringlist_push(sl, "<left>x<top>, ie: 100x100");
|
|
|
|
return sl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char * optSizeToString(struct Option * opt)
|
|
|
|
{
|
2021-01-25 08:58:36 +00:00
|
|
|
int len = snprintf(NULL, 0, "%dx%d", g_params.w, g_params.h);
|
2019-05-21 05:03:59 +00:00
|
|
|
char * str = malloc(len + 1);
|
2021-01-25 08:58:36 +00:00
|
|
|
sprintf(str, "%dx%d", g_params.w, g_params.h);
|
2019-05-21 05:03:59 +00:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2021-01-26 10:46:30 +00:00
|
|
|
static bool optScancodeValidate(struct Option * opt, const char ** error)
|
|
|
|
{
|
|
|
|
if (opt->value.x_int >= 0 && opt->value.x_int < KEY_MAX)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
*error = "Out of range";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-05-21 05:03:59 +00:00
|
|
|
static char * optScancodeToString(struct Option * opt)
|
|
|
|
{
|
|
|
|
char * str;
|
2021-01-18 16:08:56 +00:00
|
|
|
alloc_sprintf(&str, "%d = %s", opt->value.x_int,
|
2021-01-26 10:46:30 +00:00
|
|
|
xfree86_to_str[opt->value.x_int]);
|
2019-05-21 05:03:59 +00:00
|
|
|
return str;
|
2020-01-18 19:48:20 +00:00
|
|
|
}
|
2021-01-15 01:40:59 +00:00
|
|
|
|
2021-01-18 03:42:57 +00:00
|
|
|
static bool optRotateValidate(struct Option * opt, const char ** error)
|
2021-01-15 01:40:59 +00:00
|
|
|
{
|
2021-01-18 03:42:57 +00:00
|
|
|
switch(opt->value.x_int)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case 90:
|
|
|
|
case 180:
|
|
|
|
case 270:
|
|
|
|
return true;
|
2021-01-15 01:40:59 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 03:42:57 +00:00
|
|
|
*error = "Rotation angle must be one of 0, 90, 180 or 270";
|
|
|
|
return false;
|
2021-01-15 01:40:59 +00:00
|
|
|
}
|