mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-25 23:07:18 +00:00
[client] added configuration file loading support
the client now will look for a configuration file in the following locations by default. * /etc/looking-glass.conf * ~/.looking-glass.conf All configuration files are loaded and may override values specified by any prior configuration files loaded. Sample Config: global: { fullScreen=false; showFPS=true; x=0; y=0; w=800; h=600; } OpenGL: { mipmap="false"; }
This commit is contained in:
parent
59fa025292
commit
40bfdcdf8c
@ -6,7 +6,7 @@ CFLAGS += -ffast-math
|
|||||||
CFLAGS += -fdata-sections -ffunction-sections
|
CFLAGS += -fdata-sections -ffunction-sections
|
||||||
LDFLAGS += -Wl,--gc-sections
|
LDFLAGS += -Wl,--gc-sections
|
||||||
|
|
||||||
LIBS = sdl2 SDL2_ttf gl glu libssl openssl spice-protocol fontconfig x11
|
LIBS = sdl2 SDL2_ttf gl glu libssl openssl spice-protocol fontconfig x11 libconfig
|
||||||
CFLAGS += $(shell pkg-config --cflags $(LIBS))
|
CFLAGS += $(shell pkg-config --cflags $(LIBS))
|
||||||
LDFLAGS += $(shell pkg-config --libs $(LIBS))
|
LDFLAGS += $(shell pkg-config --libs $(LIBS))
|
||||||
BUILD ?= .build
|
BUILD ?= .build
|
||||||
|
@ -50,8 +50,8 @@ LG_RendererOpt;
|
|||||||
|
|
||||||
typedef struct LG_RendererOptValue
|
typedef struct LG_RendererOptValue
|
||||||
{
|
{
|
||||||
const LG_RendererOpt * opt;
|
const LG_RendererOpt * opt;
|
||||||
const char * value;
|
char * value;
|
||||||
} LG_RendererOptValue;
|
} LG_RendererOptValue;
|
||||||
|
|
||||||
typedef LG_RendererOpt * LG_RendererOptions;
|
typedef LG_RendererOpt * LG_RendererOptions;
|
||||||
|
187
client/main.c
187
client/main.c
@ -24,6 +24,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include <SDL2/SDL_ttf.h>
|
#include <SDL2/SDL_ttf.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -33,6 +34,7 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <libconfig.h>
|
||||||
#include <fontconfig/fontconfig.h>
|
#include <fontconfig/fontconfig.h>
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
@ -75,6 +77,7 @@ RendererOpts;
|
|||||||
|
|
||||||
struct AppParams
|
struct AppParams
|
||||||
{
|
{
|
||||||
|
const char * configFile;
|
||||||
bool autoResize;
|
bool autoResize;
|
||||||
bool allowResize;
|
bool allowResize;
|
||||||
bool keepAspect;
|
bool keepAspect;
|
||||||
@ -83,10 +86,10 @@ struct AppParams
|
|||||||
bool center;
|
bool center;
|
||||||
int x, y;
|
int x, y;
|
||||||
unsigned int w, h;
|
unsigned int w, h;
|
||||||
const char * shmFile;
|
char * shmFile;
|
||||||
bool showFPS;
|
bool showFPS;
|
||||||
bool useSpice;
|
bool useSpice;
|
||||||
const char * spiceHost;
|
char * spiceHost;
|
||||||
unsigned int spicePort;
|
unsigned int spicePort;
|
||||||
bool scaleMouseInput;
|
bool scaleMouseInput;
|
||||||
bool hideMouse;
|
bool hideMouse;
|
||||||
@ -100,6 +103,7 @@ struct AppParams
|
|||||||
struct AppState state;
|
struct AppState state;
|
||||||
struct AppParams params =
|
struct AppParams params =
|
||||||
{
|
{
|
||||||
|
.configFile = "/etc/looking-glass.conf",
|
||||||
.autoResize = false,
|
.autoResize = false,
|
||||||
.allowResize = true,
|
.allowResize = true,
|
||||||
.keepAspect = true,
|
.keepAspect = true,
|
||||||
@ -950,6 +954,7 @@ void doHelp(char * app)
|
|||||||
"\n"
|
"\n"
|
||||||
" -h Print out this help\n"
|
" -h Print out this help\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" -C PATH Specify an additional configuration file to load\n"
|
||||||
" -f PATH Specify the path to the shared memory file [current: %s]\n"
|
" -f PATH Specify the path to the shared memory file [current: %s]\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -s Disable spice client\n"
|
" -s Disable spice client\n"
|
||||||
@ -1012,11 +1017,156 @@ void doLicense()
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool load_config(const char * configFile)
|
||||||
|
{
|
||||||
|
config_t cfg;
|
||||||
|
int itmp;
|
||||||
|
const char *stmp;
|
||||||
|
|
||||||
|
config_init(&cfg);
|
||||||
|
if (!config_read_file(&cfg, configFile))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Config file error %s:%d - %s",
|
||||||
|
config_error_file(&cfg),
|
||||||
|
config_error_line(&cfg),
|
||||||
|
config_error_text(&cfg)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_setting_t * global = config_lookup(&cfg, "global");
|
||||||
|
if (global)
|
||||||
|
{
|
||||||
|
if (config_setting_lookup_string(global, "shmFile", &stmp))
|
||||||
|
{
|
||||||
|
free(params.shmFile);
|
||||||
|
params.shmFile = strdup(stmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_setting_lookup_string(global, "forceRenderer", &stmp))
|
||||||
|
{
|
||||||
|
bool ok = false;
|
||||||
|
for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i)
|
||||||
|
if (strcasecmp(LG_Renderers[i]->get_name(), stmp) == 0)
|
||||||
|
{
|
||||||
|
params.forceRenderer = true;
|
||||||
|
params.forceRendererIndex = i;
|
||||||
|
ok = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("No such renderer: %s", stmp);
|
||||||
|
config_destroy(&cfg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_setting_lookup_bool (global, "scaleMouseInput", &itmp)) params.scaleMouseInput = (itmp != 0);
|
||||||
|
if (config_setting_lookup_bool (global, "hideMouse" , &itmp)) params.hideMouse = (itmp != 0);
|
||||||
|
if (config_setting_lookup_bool (global, "showFPS" , &itmp)) params.showFPS = (itmp != 0);
|
||||||
|
if (config_setting_lookup_bool (global, "autoResize" , &itmp)) params.autoResize = (itmp != 0);
|
||||||
|
if (config_setting_lookup_bool (global, "allowResize" , &itmp)) params.allowResize = (itmp != 0);
|
||||||
|
if (config_setting_lookup_bool (global, "keepAspect" , &itmp)) params.keepAspect = (itmp != 0);
|
||||||
|
if (config_setting_lookup_bool (global, "borderless" , &itmp)) params.borderless = (itmp != 0);
|
||||||
|
if (config_setting_lookup_bool (global, "fullScreen" , &itmp)) params.fullscreen = (itmp != 0);
|
||||||
|
if (config_setting_lookup_bool (global, "ignoreQuit" , &itmp)) params.ignoreQuit = (itmp != 0);
|
||||||
|
|
||||||
|
if (config_setting_lookup_int(global, "x", ¶ms.x)) params.center = false;
|
||||||
|
if (config_setting_lookup_int(global, "y", ¶ms.y)) params.center = false;
|
||||||
|
|
||||||
|
if (config_setting_lookup_int(global, "w", &itmp))
|
||||||
|
{
|
||||||
|
if (itmp < 1)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Invalid window width, must be greater then 1px");
|
||||||
|
config_destroy(&cfg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
params.w = (unsigned int)itmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_setting_lookup_int(global, "h", &itmp))
|
||||||
|
{
|
||||||
|
if (itmp < 1)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Invalid window height, must be greater then 1px");
|
||||||
|
config_destroy(&cfg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
params.h = (unsigned int)itmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i)
|
||||||
|
{
|
||||||
|
const LG_Renderer * r = LG_Renderers[i];
|
||||||
|
RendererOpts * opts = ¶ms.rendererOpts[i];
|
||||||
|
config_setting_t * group = config_lookup(&cfg, r->get_name());
|
||||||
|
if (!group)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for(unsigned int j = 0; j < r->option_count; ++j)
|
||||||
|
{
|
||||||
|
const char * name = r->options[j].name;
|
||||||
|
if (!config_setting_lookup_string(group, name, &stmp))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (r->options[j].validator && !r->options[j].validator(stmp))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Renderer \"%s\" reported invalid value for option \"%s\"", r->get_name(), name);
|
||||||
|
config_destroy(&cfg);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts->argc == opts->size)
|
||||||
|
{
|
||||||
|
opts->size += 5;
|
||||||
|
opts->argv = realloc(opts->argv, sizeof(LG_RendererOptValue) * opts->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
opts->argv[opts->argc].opt = &r->options[j];
|
||||||
|
opts->argv[opts->argc].value = strdup(stmp);
|
||||||
|
++opts->argc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config_destroy(&cfg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char * argv[])
|
int main(int argc, char * argv[])
|
||||||
{
|
{
|
||||||
|
params.shmFile = strdup(params.shmFile );
|
||||||
|
params.spiceHost = strdup(params.spiceHost);
|
||||||
|
|
||||||
|
{
|
||||||
|
// load any global then local config options first
|
||||||
|
struct stat st;
|
||||||
|
if (stat("/etc/looking-glass.conf", &st) >= 0)
|
||||||
|
{
|
||||||
|
DEBUG_INFO("Loading config from: /etc/looking-glass.conf");
|
||||||
|
if (!load_config("/etc/looking-glass.conf"))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct passwd * pw = getpwuid(getuid());
|
||||||
|
const char pattern[] = "%s/.looking-glass.conf";
|
||||||
|
const size_t len = strlen(pw->pw_dir) + sizeof(pattern);
|
||||||
|
char buffer[len];
|
||||||
|
snprintf(buffer, len, pattern, pw->pw_dir);
|
||||||
|
if (stat(buffer, &st) >= 0)
|
||||||
|
{
|
||||||
|
DEBUG_INFO("Loading config from: %s", buffer);
|
||||||
|
if (!load_config(buffer))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
switch(getopt(argc, argv, "hf:sc:p:jMvkg:o:anrdFx:y:w:b:Ql"))
|
switch(getopt(argc, argv, "hC:f:sc:p:jMvkg:o:anrdFx:y:w:b:Ql"))
|
||||||
{
|
{
|
||||||
case '?':
|
case '?':
|
||||||
case 'h':
|
case 'h':
|
||||||
@ -1027,8 +1177,15 @@ int main(int argc, char * argv[])
|
|||||||
case -1:
|
case -1:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'C':
|
||||||
|
params.configFile = optarg;
|
||||||
|
if (!load_config(optarg))
|
||||||
|
return -1;
|
||||||
|
continue;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
params.shmFile = optarg;
|
free(params.shmFile);
|
||||||
|
params.shmFile = strdup(optarg);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
@ -1036,7 +1193,8 @@ int main(int argc, char * argv[])
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
params.spiceHost = optarg;
|
free(params.spiceHost);
|
||||||
|
params.spiceHost = strdup(optarg);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
@ -1162,7 +1320,7 @@ int main(int argc, char * argv[])
|
|||||||
|
|
||||||
if (opt->validator && !opt->validator(value))
|
if (opt->validator && !opt->validator(value))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Renderer \"%s\" reported Invalid value for option \"%s\"\n", renderer->get_name(), option);
|
fprintf(stderr, "Renderer \"%s\" reported invalid value for option \"%s\"\n", renderer->get_name(), option);
|
||||||
doHelp(argv[0]);
|
doHelp(argv[0]);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1174,7 +1332,7 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts->argv[opts->argc].opt = opt;
|
opts->argv[opts->argc].opt = opt;
|
||||||
opts->argv[opts->argc].value = value;
|
opts->argv[opts->argc].value = strdup(value);
|
||||||
++opts->argc;
|
++opts->argc;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1235,5 +1393,18 @@ int main(int argc, char * argv[])
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return run();
|
const int ret = run();
|
||||||
|
|
||||||
|
free(params.shmFile);
|
||||||
|
free(params.spiceHost);
|
||||||
|
for(unsigned int i = 0; i < LG_RENDERER_COUNT; ++i)
|
||||||
|
{
|
||||||
|
RendererOpts * opts = ¶ms.rendererOpts[i];
|
||||||
|
for(unsigned int j = 0; j < opts->argc; ++j)
|
||||||
|
free(opts->argv[j].value);
|
||||||
|
free(opts->argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user