diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 71b9f7ce..80f58afa 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -215,7 +215,6 @@ endif() add_subdirectory("${PROJECT_TOP}/resources" "${CMAKE_BINARY_DIR}/resources") add_subdirectory("${PROJECT_TOP}/common" "${CMAKE_BINARY_DIR}/common" ) add_subdirectory("${PROJECT_TOP}/repos/LGMP/lgmp" "${CMAKE_BINARY_DIR}/LGMP" ) -add_subdirectory("${PROJECT_TOP}/repos/PureSpice" "${CMAKE_BINARY_DIR}/PureSpice") add_subdirectory("${PROJECT_TOP}/repos/gui" "${CMAKE_BINARY_DIR}/gui" EXCLUDE_FROM_ALL) add_subdirectory(displayservers) @@ -275,10 +274,6 @@ if(ENABLE_AUDIO) ) endif() -if(ENABLE_USB_AUDIO) - target_compile_definitions(looking-glass-client PRIVATE ENABLE_USB_AUDIO) -endif() - install(TARGETS looking-glass-client RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT binary) diff --git a/client/include/interface/displayserver.h b/client/include/interface/displayserver.h index b542f891..90b06dbb 100644 --- a/client/include/interface/displayserver.h +++ b/client/include/interface/displayserver.h @@ -146,7 +146,7 @@ struct LG_DisplayServerOps /* called when it's time to create and show the application window */ bool (*init)(const LG_DSInitParams params); - /* called at startup after window creation, renderer and SPICE is ready */ + /* called after window creation, renderer, and input providers are ready */ void (*startup)(void); /* called just before final window destruction, before final free */ diff --git a/client/src/app.c b/client/src/app.c index e904848f..75cb52f5 100644 --- a/client/src/app.c +++ b/client/src/app.c @@ -339,15 +339,15 @@ bool app_clipboardRequest(LG_ClipboardData type, return lgClipboard_request(type, replyFn, opaque); } -static int mapSpiceToImGuiButton(uint32_t button) +static int mapInputToImGuiButton(uint32_t button) { switch (button) { - case 1: // SPICE_MOUSE_BUTTON_LEFT + case 1: // left return ImGuiMouseButton_Left; - case 2: // SPICE_MOUSE_BUTTON_MIDDLE + case 2: // middle return ImGuiMouseButton_Middle; - case 3: // SPICE_MOUSE_BUTTON_RIGHT + case 3: // right return ImGuiMouseButton_Right; } @@ -364,7 +364,7 @@ void app_handleButtonPress(int button) if (app_isOverlayMode()) { - int igButton = mapSpiceToImGuiButton(button); + int igButton = mapInputToImGuiButton(button); if (igButton != -1) g_state.io->MouseDown[igButton] = true; return; @@ -388,7 +388,7 @@ void app_handleButtonRelease(int button) if (app_isOverlayMode()) { - int igButton = mapSpiceToImGuiButton(button); + int igButton = mapInputToImGuiButton(button); if (igButton != -1) g_state.io->MouseDown[igButton] = false; return; diff --git a/client/src/config.c b/client/src/config.c index 0c29da49..b4279878 100644 --- a/client/src/config.c +++ b/client/src/config.c @@ -430,109 +430,71 @@ static struct Option options[] = .type = OPTION_TYPE_INT, .value.x_int = 200 }, - - // 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 synchronize the clipboard contents with the guest", - .type = OPTION_TYPE_BOOL, - .value.x_bool = true - }, - { - .module = "spice", - .name = "clipboardToVM", - .description = "Allow the clipboard to be synchronized TO the VM", - .type = OPTION_TYPE_BOOL, - .value.x_bool = true - }, - { - .module = "spice", - .name = "clipboardToLocal", - .description = "Allow the clipboard to be synchronized FROM the VM", - .type = OPTION_TYPE_BOOL, - .value.x_bool = true - }, - { - .module = "spice", - .name = "audio", - .description = "Enable SPICE audio support", - .type = OPTION_TYPE_BOOL, - .value.x_bool = true - }, - { - .module = "spice", - .name = "usbAudio", - .description = "Use USB redirection for SPICE audio playback", - .type = OPTION_TYPE_BOOL, - .value.x_bool = false - }, - { - .module = "spice", + .module = "input", .name = "scaleCursor", + .old_module = "spice", + .old_name = "scaleCursor", .description = "Scale cursor input position to screen size when up/down scaled", .shortopt = 'j', .type = OPTION_TYPE_BOOL, .value.x_bool = true }, { - .module = "spice", + .module = "input", .name = "captureOnStart", + .old_module = "spice", + .old_name = "captureOnStart", .description = "Capture mouse and keyboard on start", .type = OPTION_TYPE_BOOL, .value.x_bool = false }, { - .module = "spice", + .module = "input", .name = "alwaysShowCursor", + .old_module = "spice", + .old_name = "alwaysShowCursor", .description = "Always show host cursor", .type = OPTION_TYPE_BOOL, .value.x_bool = false }, { - .module = "spice", - .name = "showCursorDot", - .description = "Use a \"dot\" cursor when the window does not have focus", - .type = OPTION_TYPE_BOOL, - .value.x_bool = true + .module = "input", + .name = "showCursorDot", + .old_module = "spice", + .old_name = "showCursorDot", + .description = "Use a \"dot\" cursor when the window does not have focus", + .type = OPTION_TYPE_BOOL, + .value.x_bool = true }, { - .module = "spice", - .name = "largeCursorDot", - .description = "Use a larger version of the \"dot\" cursor", - .type = OPTION_TYPE_BOOL, - .value.x_bool = false + .module = "input", + .name = "largeCursorDot", + .old_module = "spice", + .old_name = "largeCursorDot", + .description = "Use a larger version of the \"dot\" cursor", + .type = OPTION_TYPE_BOOL, + .value.x_bool = false + }, + + // clipboard options + { + .module = "clipboard", + .name = "toVM", + .old_module = "spice", + .old_name = "clipboardToVM", + .description = "Allow the clipboard to be synchronized TO the VM", + .type = OPTION_TYPE_BOOL, + .value.x_bool = true + }, + { + .module = "clipboard", + .name = "toLocal", + .old_module = "spice", + .old_name = "clipboardToLocal", + .description = "Allow the clipboard to be synchronized FROM the VM", + .type = OPTION_TYPE_BOOL, + .value.x_bool = true }, // audio options @@ -753,44 +715,23 @@ bool config_load(int argc, char * argv[]) g_params.helpMenuDelayUs = option_get_int("input", "helpMenuDelay") * (uint64_t) 1000; - g_params.scaleMouseInput = option_get_bool("spice", "scaleCursor"); - g_params.captureOnStart = option_get_bool("spice", "captureOnStart"); - g_params.alwaysShowCursor = option_get_bool("spice", "alwaysShowCursor"); - g_params.showCursorDot = option_get_bool("spice", "showCursorDot"); - g_params.largeCursorDot = option_get_bool("spice", "largeCursorDot"); + g_params.scaleMouseInput = option_get_bool("input", "scaleCursor"); + g_params.captureOnStart = option_get_bool("input", "captureOnStart"); + g_params.alwaysShowCursor = option_get_bool("input", "alwaysShowCursor"); + g_params.showCursorDot = option_get_bool("input", "showCursorDot"); + g_params.largeCursorDot = option_get_bool("input", "largeCursorDot"); g_params.minimizeOnFocusLoss = option_get_bool("win", "minimizeOnFocusLoss"); g_params.setGuestRes = option_get_bool("win", "setGuestRes" ); - g_params.clipboardToVM = option_get_bool("spice", "clipboardToVM" ); - g_params.clipboardToLocal = option_get_bool("spice", "clipboardToLocal"); + g_params.clipboardToVM = option_get_bool("clipboard", "toVM" ); + g_params.clipboardToLocal = option_get_bool("clipboard", "toLocal"); - if ((g_params.useSpice = option_get_bool("spice", "enable"))) - { - g_params.spiceHost = option_get_string("spice", "host"); - g_params.spicePort = option_get_int ("spice", "port"); - - g_params.useSpiceInput = option_get_bool("spice", "input" ); - g_params.useSpiceClipboard = - option_get_bool("spice", "clipboard") && - (g_params.clipboardToVM || g_params.clipboardToLocal); - g_params.useSpiceAudio = option_get_bool("spice", "audio" ); - g_params.useSpiceUSBAudio = option_get_bool("spice", "usbAudio"); - -#if !ENABLE_USB_AUDIO - if (g_params.useSpiceAudio && g_params.useSpiceUSBAudio) - { - DEBUG_WARN("USB audio is unavailable in this build, using SPICE audio"); - g_params.useSpiceUSBAudio = false; - } -#endif - } - - g_params.audioDebug = option_get_bool("audio", "debug"); - g_params.audioPeriodSize = option_get_int("audio", "periodSize"); - g_params.audioLatencyOffset = option_get_int("audio", "latencyOffset"); + g_params.audioDebug = option_get_bool("audio", "debug" ); + g_params.audioPeriodSize = option_get_int ("audio", "periodSize" ); + g_params.audioLatencyOffset = option_get_int ("audio", "latencyOffset" ); g_params.micShowIndicator = option_get_bool("audio", "micShowIndicator"); - g_params.audioSyncVolume = option_get_bool("audio", "syncVolume"); + g_params.audioSyncVolume = option_get_bool("audio", "syncVolume" ); return true; } @@ -1030,11 +971,20 @@ static bool optRotateValidate(struct Option * opt, const char ** error) static bool optTransportValidate(struct Option * opt, const char ** error) { - if (lgTransport_isValid(opt->value.x_string)) - return true; + if (!lgTransport_isValid(opt->value.x_string)) + { + *error = "Unknown transport"; + return false; + } - *error = "Unknown transport (expected lgmp or test)"; - return false; + if (strcmp(opt->value.x_string, "spice") == 0 && + !option_get_bool("spice", "enable")) + { + *error = "The SPICE transport is disabled by spice:enable"; + return false; + } + + return true; } static bool optMicDefaultParse(struct Option * opt, const char * str) diff --git a/client/src/main.c b/client/src/main.c index 231c1369..8014d531 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -2164,7 +2164,8 @@ static const LG_TransportFallbackEventOps fallbackEvents = static bool fallbackStart(void) { - if (!g_params.useSpice || strcmp(g_params.transport, "spice") == 0) + if (!option_get_bool("spice", "enable") || + strcmp(g_params.transport, "spice") == 0) return true; if (lgTransportFallback_start("spice", &swSurfaceEvents, @@ -2261,7 +2262,8 @@ static void reportBadVersion(void) static MsgBoxHandle showSpiceInputHelp(void) { static bool done = false; - if (!g_params.useSpiceInput || done) + if (!option_get_bool("spice", "enable") || + !option_get_bool("spice", "input") || done) return NULL; done = true; diff --git a/client/src/main.h b/client/src/main.h index 5657bfea..900c2f5b 100644 --- a/client/src/main.h +++ b/client/src/main.h @@ -204,13 +204,6 @@ struct AppParams bool setGuestRes; int fpsMin; LG_RendererRotate winRotate; - bool useSpice; - bool useSpiceInput; - bool useSpiceClipboard; - bool useSpiceAudio; - bool useSpiceUSBAudio; - const char * spiceHost; - unsigned int spicePort; bool clipboardToVM; bool clipboardToLocal; bool scaleMouseInput; diff --git a/client/src/usb_audio.h b/client/src/usb_audio.h index c897246c..7d60f6d9 100644 --- a/client/src/usb_audio.h +++ b/client/src/usb_audio.h @@ -67,7 +67,7 @@ bool lgUsbAudio_recordData( const LG_AudioClock * sourceClock); /* Return the time until ISO-IN processing is needed. This must be queried on - * the PureSpice processing thread. */ + * the transport processing thread. */ uint64_t lgUsbAudio_processDelayNs(const LG_USBAudio * audio); const LG_USBRedirDeviceOps * lgUsbAudio_deviceOps(void); diff --git a/client/tests/CMakeLists.txt b/client/tests/CMakeLists.txt index 6a6f7e7f..45cecad9 100644 --- a/client/tests/CMakeLists.txt +++ b/client/tests/CMakeLists.txt @@ -107,7 +107,6 @@ target_compile_definitions(mouse-tests PRIVATE ) target_include_directories(mouse-tests PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../src" - "${PROJECT_TOP}/repos/PureSpice/include" "${PROJECT_TOP}/repos/gui/cimgui" "${PROJECT_TOP}/repos/gui/cimgui/imgui" ) diff --git a/client/transports/SPICE/CMakeLists.txt b/client/transports/SPICE/CMakeLists.txt index 5ebf9f84..1a61b476 100644 --- a/client/transports/SPICE/CMakeLists.txt +++ b/client/transports/SPICE/CMakeLists.txt @@ -1,6 +1,11 @@ cmake_minimum_required(VERSION 3.10) project(transport_SPICE LANGUAGES C) +add_subdirectory( + "${PROJECT_TOP}/repos/PureSpice" + "${CMAKE_BINARY_DIR}/PureSpice" +) + set(SOURCES clipboard.c input.c @@ -29,7 +34,7 @@ target_include_directories(transport_SPICE PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../src ) -target_link_libraries(transport_SPICE +target_link_libraries(transport_SPICE PRIVATE lg_common purespice ) @@ -40,7 +45,7 @@ endif() if(ENABLE_USB_AUDIO) target_compile_definitions(transport_SPICE PRIVATE ENABLE_USB_AUDIO) - target_link_libraries(transport_SPICE + target_link_libraries(transport_SPICE PRIVATE PkgConfig::USBREDIRPARSER ) endif() diff --git a/client/transports/SPICE/spice.c b/client/transports/SPICE/spice.c index 3c84e7ad..54d08696 100644 --- a/client/transports/SPICE/spice.c +++ b/client/transports/SPICE/spice.c @@ -36,6 +36,65 @@ static void spiceDisconnect(LG_Transport * transport); static void spiceSetup(void) { + static struct Option options[] = + { + { + .module = "spice", + .name = "enable", + .description = "Enable the built-in SPICE transport", + .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 = "Enable SPICE keyboard and mouse input", + .type = OPTION_TYPE_BOOL, + .value.x_bool = true + }, + { + .module = "spice", + .name = "clipboard", + .description = "Enable SPICE clipboard synchronization", + .type = OPTION_TYPE_BOOL, + .value.x_bool = true + }, + { + .module = "spice", + .name = "audio", + .description = "Enable SPICE audio support", + .type = OPTION_TYPE_BOOL, + .value.x_bool = true + }, + { + .module = "spice", + .name = "usbAudio", + .description = "Use USB redirection for SPICE audio playback", + .type = OPTION_TYPE_BOOL, + .value.x_bool = false + }, + {0} + }; + + option_register(options); + const PSInit init = { .log = @@ -60,12 +119,20 @@ static bool spiceCreate(LG_Transport ** result) transport->host = option_get_string("spice", "host"); transport->port = option_get_int("spice", "port"); transport->inputEnabled = option_get_bool("spice", "input"); - transport->clipboardEnabled = option_get_bool("spice", "clipboard"); + transport->clipboardEnabled = + option_get_bool("spice", "clipboard") && + (option_get_bool("clipboard", "toVM") || + option_get_bool("clipboard", "toLocal")); transport->audioEnabled = option_get_bool("spice", "audio"); transport->usbAudioEnabled = option_get_bool("spice", "usbAudio"); transport->audioDebug = option_get_bool("audio", "debug"); +#if !ENABLE_USB_AUDIO + if (transport->audioEnabled && transport->usbAudioEnabled) + DEBUG_WARN("USB audio is unavailable in this build, using SPICE audio"); +#endif + #if ENABLE_AUDIO transport->playbackEnabled = transport->audioEnabled && lgAudio_supportsPlayback();