mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 07:01:30 +00:00
[client] recovery: add force keybind
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
Add a configured escape key plus Shift+R command that requests display recovery from the LGMP transport and switches video to SPICE. Track the request on the main thread, report its asynchronous result, and return its producer instance with the request serial for exact correlation. Preserve normal escape+R rotation behavior, including custom Shift escape keys.
This commit is contained in:
@@ -485,7 +485,7 @@ typedef struct LG_TransportOps
|
|||||||
LG_TransportStatus (*getRecoveryInfo)(LG_Transport * transport,
|
LG_TransportStatus (*getRecoveryInfo)(LG_Transport * transport,
|
||||||
LG_RecoveryInfo * info);
|
LG_RecoveryInfo * info);
|
||||||
LG_TransportStatus (*requestRecovery)(LG_Transport * transport,
|
LG_TransportStatus (*requestRecovery)(LG_Transport * transport,
|
||||||
LG_RecoveryRequest request, uint32_t * serial);
|
LG_RecoveryRequest request, uint64_t * instance, uint32_t * serial);
|
||||||
|
|
||||||
LG_TransportStatus (*sendControl)(LG_Transport * transport,
|
LG_TransportStatus (*sendControl)(LG_Transport * transport,
|
||||||
const LG_TransportControl * control, LG_TransportControlToken * token);
|
const LG_TransportControl * control, LG_TransportControlToken * token);
|
||||||
|
|||||||
@@ -47,6 +47,12 @@
|
|||||||
|
|
||||||
#define SHADER_MOUSE_VALID (UINT32_C(1) << 31)
|
#define SHADER_MOUSE_VALID (UINT32_C(1) << 31)
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
KEY_MODIFIER_LEFT_SHIFT = 0x1,
|
||||||
|
KEY_MODIFIER_RIGHT_SHIFT = 0x2,
|
||||||
|
};
|
||||||
|
|
||||||
#define MTRACE(fmt, ...) \
|
#define MTRACE(fmt, ...) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
@@ -273,6 +279,9 @@ void app_handleFocusEvent(bool focused)
|
|||||||
|
|
||||||
if (!focused)
|
if (!focused)
|
||||||
{
|
{
|
||||||
|
atomic_store_explicit(
|
||||||
|
&g_state.keyModifiers, 0, memory_order_release);
|
||||||
|
g_state.escapeActive = false;
|
||||||
core_setGrabQuiet(false);
|
core_setGrabQuiet(false);
|
||||||
core_setCursorInView(false);
|
core_setCursorInView(false);
|
||||||
}
|
}
|
||||||
@@ -289,8 +298,6 @@ void app_handleFocusEvent(bool focused)
|
|||||||
if (g_params.releaseKeysOnFocusLoss)
|
if (g_params.releaseKeysOnFocusLoss)
|
||||||
lgInput_releaseKeys();
|
lgInput_releaseKeys();
|
||||||
|
|
||||||
g_state.escapeActive = false;
|
|
||||||
|
|
||||||
if (!g_params.showCursorDot)
|
if (!g_params.showCursorDot)
|
||||||
g_state.ds->setPointer(LG_POINTER_NONE);
|
g_state.ds->setPointer(LG_POINTER_NONE);
|
||||||
|
|
||||||
@@ -418,10 +425,20 @@ void app_handleWheelMotion(double motion)
|
|||||||
|
|
||||||
void app_handleKeyPressInternal(int sc)
|
void app_handleKeyPressInternal(int sc)
|
||||||
{
|
{
|
||||||
|
if (sc == KEY_LEFTSHIFT)
|
||||||
|
atomic_fetch_or_explicit(&g_state.keyModifiers,
|
||||||
|
KEY_MODIFIER_LEFT_SHIFT, memory_order_acq_rel);
|
||||||
|
else if (sc == KEY_RIGHTSHIFT)
|
||||||
|
atomic_fetch_or_explicit(&g_state.keyModifiers,
|
||||||
|
KEY_MODIFIER_RIGHT_SHIFT, memory_order_acq_rel);
|
||||||
|
|
||||||
if (!app_isOverlayMode() || !g_state.io->WantCaptureKeyboard)
|
if (!app_isOverlayMode() || !g_state.io->WantCaptureKeyboard)
|
||||||
{
|
{
|
||||||
if (sc == g_params.escapeKey && !g_state.escapeActive)
|
if (sc == g_params.escapeKey && !g_state.escapeActive)
|
||||||
{
|
{
|
||||||
|
memset(g_state.escapeKeys, 0, sizeof(g_state.escapeKeys));
|
||||||
|
memset(g_state.escapeShiftKeys, 0,
|
||||||
|
sizeof(g_state.escapeShiftKeys));
|
||||||
g_state.escapeActive = true;
|
g_state.escapeActive = true;
|
||||||
g_state.escapeTime = microtime();
|
g_state.escapeTime = microtime();
|
||||||
g_state.escapeAction = -1;
|
g_state.escapeAction = -1;
|
||||||
@@ -431,6 +448,7 @@ void app_handleKeyPressInternal(int sc)
|
|||||||
|
|
||||||
if (g_state.escapeActive)
|
if (g_state.escapeActive)
|
||||||
{
|
{
|
||||||
|
const bool repeat = g_state.escapeKeys[sc];
|
||||||
g_state.escapeAction = sc;
|
g_state.escapeAction = sc;
|
||||||
g_state.escapeKeys[sc] = true;
|
g_state.escapeKeys[sc] = true;
|
||||||
KeybindHandle handle;
|
KeybindHandle handle;
|
||||||
@@ -438,6 +456,23 @@ void app_handleKeyPressInternal(int sc)
|
|||||||
{
|
{
|
||||||
if (handle->sc == sc)
|
if (handle->sc == sc)
|
||||||
{
|
{
|
||||||
|
unsigned modifiers = atomic_load_explicit(
|
||||||
|
&g_state.keyModifiers, memory_order_acquire);
|
||||||
|
if (g_params.escapeKey == KEY_LEFTSHIFT)
|
||||||
|
modifiers &= ~(unsigned)KEY_MODIFIER_LEFT_SHIFT;
|
||||||
|
else if (g_params.escapeKey == KEY_RIGHTSHIFT)
|
||||||
|
modifiers &= ~(unsigned)KEY_MODIFIER_RIGHT_SHIFT;
|
||||||
|
const bool shift = modifiers != 0;
|
||||||
|
if (!repeat)
|
||||||
|
g_state.escapeShiftKeys[sc] =
|
||||||
|
shift && handle->shiftCallback;
|
||||||
|
|
||||||
|
if (g_state.escapeShiftKeys[sc])
|
||||||
|
{
|
||||||
|
if (!repeat)
|
||||||
|
handle->shiftCallback(sc, handle->shiftOpaque);
|
||||||
|
}
|
||||||
|
else
|
||||||
handle->callback(sc, handle->opaque);
|
handle->callback(sc, handle->opaque);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -472,6 +507,13 @@ void app_handleKeyPressInternal(int sc)
|
|||||||
|
|
||||||
void app_handleKeyReleaseInternal(int sc)
|
void app_handleKeyReleaseInternal(int sc)
|
||||||
{
|
{
|
||||||
|
if (sc == KEY_LEFTSHIFT)
|
||||||
|
atomic_fetch_and_explicit(&g_state.keyModifiers,
|
||||||
|
~(unsigned)KEY_MODIFIER_LEFT_SHIFT, memory_order_acq_rel);
|
||||||
|
else if (sc == KEY_RIGHTSHIFT)
|
||||||
|
atomic_fetch_and_explicit(&g_state.keyModifiers,
|
||||||
|
~(unsigned)KEY_MODIFIER_RIGHT_SHIFT, memory_order_acq_rel);
|
||||||
|
|
||||||
if (g_state.escapeActive && sc == g_params.escapeKey)
|
if (g_state.escapeActive && sc == g_params.escapeKey)
|
||||||
{
|
{
|
||||||
if (g_state.escapeAction == -1)
|
if (g_state.escapeAction == -1)
|
||||||
@@ -487,6 +529,7 @@ void app_handleKeyReleaseInternal(int sc)
|
|||||||
if (g_state.escapeKeys[sc])
|
if (g_state.escapeKeys[sc])
|
||||||
{
|
{
|
||||||
g_state.escapeKeys[sc] = false;
|
g_state.escapeKeys[sc] = false;
|
||||||
|
g_state.escapeShiftKeys[sc] = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -816,8 +859,11 @@ KeybindHandle app_registerKeybind(int sc, KeybindFn callback, void * opaque,
|
|||||||
|
|
||||||
handle->sc = sc;
|
handle->sc = sc;
|
||||||
handle->callback = callback;
|
handle->callback = callback;
|
||||||
|
handle->shiftCallback = NULL;
|
||||||
handle->description = description;
|
handle->description = description;
|
||||||
|
handle->shiftDescription = NULL;
|
||||||
handle->opaque = opaque;
|
handle->opaque = opaque;
|
||||||
|
handle->shiftOpaque = NULL;
|
||||||
|
|
||||||
ll_push(g_state.bindings, handle);
|
ll_push(g_state.bindings, handle);
|
||||||
return handle;
|
return handle;
|
||||||
|
|||||||
@@ -50,6 +50,11 @@ static void bind_rotate(int sc, void * opaque)
|
|||||||
core_updatePositionInfo();
|
core_updatePositionInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bind_forceRecovery(int sc, void * opaque)
|
||||||
|
{
|
||||||
|
atomic_store_explicit(&g_state.forceRecovery, true, memory_order_release);
|
||||||
|
}
|
||||||
|
|
||||||
static void bind_input(int sc, void * opaque)
|
static void bind_input(int sc, void * opaque)
|
||||||
{
|
{
|
||||||
g_state.ignoreInput = !g_state.ignoreInput;
|
g_state.ignoreInput = !g_state.ignoreInput;
|
||||||
@@ -150,8 +155,13 @@ void keybind_commonRegister(void)
|
|||||||
"Full screen toggle");
|
"Full screen toggle");
|
||||||
app_registerKeybind(KEY_V, bind_video , NULL,
|
app_registerKeybind(KEY_V, bind_video , NULL,
|
||||||
"Video stream toggle");
|
"Video stream toggle");
|
||||||
app_registerKeybind(KEY_R, bind_rotate , NULL,
|
KeybindHandle rotate = app_registerKeybind(KEY_R, bind_rotate, NULL,
|
||||||
"Rotate the output clockwise by 90° increments");
|
"Rotate the output clockwise by 90° increments");
|
||||||
|
if (rotate)
|
||||||
|
{
|
||||||
|
rotate->shiftCallback = bind_forceRecovery;
|
||||||
|
rotate->shiftDescription = "Force guest display recovery";
|
||||||
|
}
|
||||||
app_registerKeybind(KEY_Q, bind_quit , NULL,
|
app_registerKeybind(KEY_Q, bind_quit , NULL,
|
||||||
"Quit");
|
"Quit");
|
||||||
app_registerKeybind(KEY_O, bind_toggleOverlay, NULL,
|
app_registerKeybind(KEY_O, bind_toggleOverlay, NULL,
|
||||||
|
|||||||
@@ -2803,6 +2803,13 @@ struct RecoveryPrompt
|
|||||||
bool retryDeclined;
|
bool retryDeclined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ForcedRecovery
|
||||||
|
{
|
||||||
|
uint64_t instance;
|
||||||
|
uint32_t serial;
|
||||||
|
bool pending;
|
||||||
|
};
|
||||||
|
|
||||||
static bool recoveryGetInfo(LG_RecoveryInfo * info)
|
static bool recoveryGetInfo(LG_RecoveryInfo * info)
|
||||||
{
|
{
|
||||||
if (!g_state.transport.ops->getRecoveryInfo)
|
if (!g_state.transport.ops->getRecoveryInfo)
|
||||||
@@ -3043,6 +3050,152 @@ static bool recoverySerialNewer(uint32_t serial, uint32_t reference)
|
|||||||
return difference && difference < 0x80000000U;
|
return difference && difference < 0x80000000U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool recoveryRequestNewer(const LG_RecoveryInfo * info)
|
||||||
|
{
|
||||||
|
return info->requestSerial != 0 &&
|
||||||
|
(info->ackSerial == 0 ||
|
||||||
|
recoverySerialNewer(info->requestSerial, info->ackSerial));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void recoveryHandleForced(struct ForcedRecovery * recovery)
|
||||||
|
{
|
||||||
|
const bool triggered = atomic_exchange_explicit(
|
||||||
|
&g_state.forceRecovery, false, memory_order_acq_rel);
|
||||||
|
if (!triggered && !recovery->pending)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LG_RecoveryInfo info = { 0 };
|
||||||
|
if (!recoveryGetInfo(&info) ||
|
||||||
|
!(info.capabilities & LG_RECOVERY_CAP_DISPLAY))
|
||||||
|
{
|
||||||
|
if (triggered)
|
||||||
|
app_alert(LG_ALERT_WARNING,
|
||||||
|
"Guest display recovery is unavailable");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.uuidValid)
|
||||||
|
lgTransportFallback_setPrimaryUUID(g_state.fallback, info.uuid);
|
||||||
|
else
|
||||||
|
lgTransportFallback_clearPrimaryUUID(g_state.fallback);
|
||||||
|
|
||||||
|
const bool requestNewer = recoveryRequestNewer(&info);
|
||||||
|
const LG_RecoveryRequest currentRequest = requestNewer ?
|
||||||
|
info.request : info.ackRequest;
|
||||||
|
const uint32_t currentSerial = requestNewer ?
|
||||||
|
info.requestSerial : info.ackSerial;
|
||||||
|
|
||||||
|
if (recovery->pending)
|
||||||
|
{
|
||||||
|
const bool instanceChanged = recovery->instance != info.instance;
|
||||||
|
const bool currentRelevant = currentSerial &&
|
||||||
|
(instanceChanged || currentSerial == recovery->serial ||
|
||||||
|
recoverySerialNewer(currentSerial, recovery->serial));
|
||||||
|
if (!currentRelevant && instanceChanged)
|
||||||
|
{
|
||||||
|
recovery->pending = false;
|
||||||
|
app_alert(LG_ALERT_WARNING,
|
||||||
|
"Guest display recovery was interrupted");
|
||||||
|
if (!triggered)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (currentRelevant &&
|
||||||
|
currentRequest == LG_RECOVERY_REQ_RECOVERY)
|
||||||
|
{
|
||||||
|
recovery->instance = info.instance;
|
||||||
|
recovery->serial = currentSerial;
|
||||||
|
if (!requestNewer && info.state == LG_RECOVERY_STATE_ACTIVE)
|
||||||
|
{
|
||||||
|
recovery->pending = false;
|
||||||
|
fallbackRequestVideo();
|
||||||
|
app_alert(LG_ALERT_SUCCESS,
|
||||||
|
"Guest display recovery is active");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!requestNewer && info.state == LG_RECOVERY_STATE_FAILED)
|
||||||
|
{
|
||||||
|
recovery->pending = false;
|
||||||
|
app_alert(LG_ALERT_WARNING, "Recovery failed: %s",
|
||||||
|
recoveryErrorText(info.error));
|
||||||
|
if (!triggered)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fallbackRequestVideo();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (currentRelevant)
|
||||||
|
{
|
||||||
|
recovery->pending = false;
|
||||||
|
app_alert(LG_ALERT_WARNING,
|
||||||
|
"Guest display recovery was superseded");
|
||||||
|
if (!triggered)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fallbackRequestVideo();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!triggered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const bool pendingRecovery = requestNewer &&
|
||||||
|
info.request == LG_RECOVERY_REQ_RECOVERY;
|
||||||
|
const bool switchingRecovery = !requestNewer && info.ackSerial &&
|
||||||
|
info.ackRequest == LG_RECOVERY_REQ_RECOVERY &&
|
||||||
|
info.state == LG_RECOVERY_STATE_SWITCHING;
|
||||||
|
const bool activeRecovery = !requestNewer && info.ackSerial &&
|
||||||
|
info.ackRequest == LG_RECOVERY_REQ_RECOVERY &&
|
||||||
|
info.state == LG_RECOVERY_STATE_ACTIVE;
|
||||||
|
if (activeRecovery)
|
||||||
|
{
|
||||||
|
fallbackRequestVideo();
|
||||||
|
app_alert(LG_ALERT_SUCCESS,
|
||||||
|
"Guest display recovery is already active");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pendingRecovery || switchingRecovery)
|
||||||
|
{
|
||||||
|
recovery->instance = info.instance;
|
||||||
|
recovery->serial = currentSerial;
|
||||||
|
recovery->pending = true;
|
||||||
|
fallbackRequestVideo();
|
||||||
|
app_alert(LG_ALERT_INFO,
|
||||||
|
"Guest display recovery is already pending");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_state.transport.ops->requestRecovery)
|
||||||
|
{
|
||||||
|
app_alert(LG_ALERT_WARNING,
|
||||||
|
"Guest display recovery is unavailable");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t serial = 0;
|
||||||
|
const LG_TransportStatus status =
|
||||||
|
g_state.transport.ops->requestRecovery(g_state.transport.handle,
|
||||||
|
LG_RECOVERY_REQ_RECOVERY, &recovery->instance, &serial);
|
||||||
|
if (status != LG_TRANSPORT_OK)
|
||||||
|
{
|
||||||
|
app_alert(LG_ALERT_WARNING,
|
||||||
|
"Guest display recovery request failed (%d)", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
recovery->serial = serial;
|
||||||
|
recovery->pending = true;
|
||||||
|
fallbackRequestVideo();
|
||||||
|
app_alert(LG_ALERT_INFO, "Guest display recovery requested");
|
||||||
|
}
|
||||||
|
|
||||||
static void recoveryHandleMismatch(struct RecoveryPrompt * prompt,
|
static void recoveryHandleMismatch(struct RecoveryPrompt * prompt,
|
||||||
const LG_VersionMismatch * mismatch)
|
const LG_VersionMismatch * mismatch)
|
||||||
{
|
{
|
||||||
@@ -3114,9 +3267,7 @@ static void recoveryHandleMismatch(struct RecoveryPrompt * prompt,
|
|||||||
else
|
else
|
||||||
lgTransportFallback_clearPrimaryUUID(g_state.fallback);
|
lgTransportFallback_clearPrimaryUUID(g_state.fallback);
|
||||||
|
|
||||||
const bool requestNewer = info.requestSerial != 0 &&
|
const bool requestNewer = recoveryRequestNewer(&info);
|
||||||
(info.ackSerial == 0 ||
|
|
||||||
recoverySerialNewer(info.requestSerial, info.ackSerial));
|
|
||||||
const LG_RecoveryRequest globalRequest = requestNewer ?
|
const LG_RecoveryRequest globalRequest = requestNewer ?
|
||||||
info.request : info.ackRequest;
|
info.request : info.ackRequest;
|
||||||
const uint32_t globalSerial = requestNewer ?
|
const uint32_t globalSerial = requestNewer ?
|
||||||
@@ -3218,7 +3369,8 @@ static void recoveryHandleMismatch(struct RecoveryPrompt * prompt,
|
|||||||
const LG_TransportStatus status =
|
const LG_TransportStatus status =
|
||||||
g_state.transport.ops->requestRecovery ?
|
g_state.transport.ops->requestRecovery ?
|
||||||
g_state.transport.ops->requestRecovery(g_state.transport.handle,
|
g_state.transport.ops->requestRecovery(g_state.transport.handle,
|
||||||
LG_RECOVERY_REQ_RECOVERY, &prompt->serial) :
|
LG_RECOVERY_REQ_RECOVERY, &prompt->instance,
|
||||||
|
&prompt->serial) :
|
||||||
LG_TRANSPORT_UNAVAILABLE;
|
LG_TRANSPORT_UNAVAILABLE;
|
||||||
prompt->requested = status == LG_TRANSPORT_OK;
|
prompt->requested = status == LG_TRANSPORT_OK;
|
||||||
prompt->owned = prompt->requested;
|
prompt->owned = prompt->requested;
|
||||||
@@ -3346,6 +3498,8 @@ static int lg_run(void)
|
|||||||
frameTimingInit();
|
frameTimingInit();
|
||||||
lgInput_init();
|
lgInput_init();
|
||||||
lgAudio_init();
|
lgAudio_init();
|
||||||
|
atomic_init(&g_state.forceRecovery, false);
|
||||||
|
atomic_init(&g_state.keyModifiers, 0);
|
||||||
if (!clipboard_init())
|
if (!clipboard_init())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -3688,6 +3842,7 @@ static int lg_run(void)
|
|||||||
MsgBoxHandle msgs[10];
|
MsgBoxHandle msgs[10];
|
||||||
int msgsCount;
|
int msgsCount;
|
||||||
struct RecoveryPrompt recoveryPrompt = { 0 };
|
struct RecoveryPrompt recoveryPrompt = { 0 };
|
||||||
|
struct ForcedRecovery forcedRecovery = { 0 };
|
||||||
atomic_init(&recoveryPrompt.choice, RECOVERY_PENDING);
|
atomic_init(&recoveryPrompt.choice, RECOVERY_PENDING);
|
||||||
atomic_init(&recoveryPrompt.handle, 0);
|
atomic_init(&recoveryPrompt.handle, 0);
|
||||||
atomic_init(&recoveryPrompt.message, 0);
|
atomic_init(&recoveryPrompt.message, 0);
|
||||||
@@ -3704,6 +3859,7 @@ restart:
|
|||||||
while(app_getState() == APP_STATE_RUNNING)
|
while(app_getState() == APP_STATE_RUNNING)
|
||||||
{
|
{
|
||||||
fallbackHandleEvents();
|
fallbackHandleEvents();
|
||||||
|
recoveryHandleForced(&forcedRecovery);
|
||||||
|
|
||||||
if (initialFallbackEnable && microtime() > initialFallbackEnable)
|
if (initialFallbackEnable && microtime() > initialFallbackEnable)
|
||||||
{
|
{
|
||||||
@@ -3795,7 +3951,7 @@ restart:
|
|||||||
|
|
||||||
recoveryClose(&recoveryPrompt);
|
recoveryClose(&recoveryPrompt);
|
||||||
LG_RecoveryInfo recoveryInfo = { 0 };
|
LG_RecoveryInfo recoveryInfo = { 0 };
|
||||||
if (recoveryGetInfo(&recoveryInfo) &&
|
if (!forcedRecovery.pending && recoveryGetInfo(&recoveryInfo) &&
|
||||||
(recoveryInfo.state == LG_RECOVERY_STATE_ACTIVE ||
|
(recoveryInfo.state == LG_RECOVERY_STATE_ACTIVE ||
|
||||||
recoveryInfo.state == LG_RECOVERY_STATE_SWITCHING ||
|
recoveryInfo.state == LG_RECOVERY_STATE_SWITCHING ||
|
||||||
recoveryInfo.request == LG_RECOVERY_REQ_RECOVERY ||
|
recoveryInfo.request == LG_RECOVERY_REQ_RECOVERY ||
|
||||||
@@ -3804,7 +3960,7 @@ restart:
|
|||||||
{
|
{
|
||||||
const LG_TransportStatus status =
|
const LG_TransportStatus status =
|
||||||
g_state.transport.ops->requestRecovery(g_state.transport.handle,
|
g_state.transport.ops->requestRecovery(g_state.transport.handle,
|
||||||
LG_RECOVERY_REQ_NORMAL, NULL);
|
LG_RECOVERY_REQ_NORMAL, NULL, NULL);
|
||||||
if (status != LG_TRANSPORT_OK)
|
if (status != LG_TRANSPORT_OK)
|
||||||
DEBUG_WARN("Failed to leave recovery mode: %d", status);
|
DEBUG_WARN("Failed to leave recovery mode: %d", status);
|
||||||
}
|
}
|
||||||
@@ -3931,6 +4087,7 @@ restart:
|
|||||||
while(likely(app_getState() == APP_STATE_RUNNING))
|
while(likely(app_getState() == APP_STATE_RUNNING))
|
||||||
{
|
{
|
||||||
fallbackHandleEvents();
|
fallbackHandleEvents();
|
||||||
|
recoveryHandleForced(&forcedRecovery);
|
||||||
if (unlikely(!g_state.transport.ops->sessionValid(
|
if (unlikely(!g_state.transport.ops->sessionValid(
|
||||||
g_state.transport.handle)))
|
g_state.transport.handle)))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ struct AppState
|
|||||||
|
|
||||||
atomic_bool fallbackEndpointMismatch;
|
atomic_bool fallbackEndpointMismatch;
|
||||||
atomic_uint transportLost;
|
atomic_uint transportLost;
|
||||||
|
atomic_bool forceRecovery;
|
||||||
|
|
||||||
uint8_t guestUUID[16];
|
uint8_t guestUUID[16];
|
||||||
bool guestUUIDValid;
|
bool guestUUIDValid;
|
||||||
@@ -130,6 +131,8 @@ struct AppState
|
|||||||
uint64_t escapeTime;
|
uint64_t escapeTime;
|
||||||
int escapeAction;
|
int escapeAction;
|
||||||
bool escapeKeys[KEY_MAX];
|
bool escapeKeys[KEY_MAX];
|
||||||
|
bool escapeShiftKeys[KEY_MAX];
|
||||||
|
atomic_uint keyModifiers;
|
||||||
bool escapeHelp;
|
bool escapeHelp;
|
||||||
struct ll * bindings;
|
struct ll * bindings;
|
||||||
bool haveSrcSize;
|
bool haveSrcSize;
|
||||||
@@ -265,8 +268,11 @@ struct KeybindHandle
|
|||||||
{
|
{
|
||||||
int sc;
|
int sc;
|
||||||
KeybindFn callback;
|
KeybindFn callback;
|
||||||
|
KeybindFn shiftCallback;
|
||||||
const char * description;
|
const char * description;
|
||||||
|
const char * shiftDescription;
|
||||||
void * opaque;
|
void * opaque;
|
||||||
|
void * shiftOpaque;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum WarpState
|
enum WarpState
|
||||||
|
|||||||
@@ -82,6 +82,14 @@ static int help_render(void * udata, bool interactive, struct Rect * windowRects
|
|||||||
igText("%s+%s", escapeName, keyName);
|
igText("%s+%s", escapeName, keyName);
|
||||||
igTableNextColumn();
|
igTableNextColumn();
|
||||||
igTextUnformatted(handle->description, NULL);
|
igTextUnformatted(handle->description, NULL);
|
||||||
|
|
||||||
|
if (handle->shiftCallback && handle->shiftDescription)
|
||||||
|
{
|
||||||
|
igTableNextColumn();
|
||||||
|
igText("%s+Shift+%s", escapeName, keyName);
|
||||||
|
igTableNextColumn();
|
||||||
|
igTextUnformatted(handle->shiftDescription, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
igEndTable();
|
igEndTable();
|
||||||
|
|||||||
@@ -1420,7 +1420,7 @@ static LG_TransportStatus lgmp_getRecoveryInfo(LG_Transport * this,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static LG_TransportStatus lgmp_requestRecovery(LG_Transport * this,
|
static LG_TransportStatus lgmp_requestRecovery(LG_Transport * this,
|
||||||
LG_RecoveryRequest request, uint32_t * serial)
|
LG_RecoveryRequest request, uint64_t * instance, uint32_t * serial)
|
||||||
{
|
{
|
||||||
uint32_t wireRequest;
|
uint32_t wireRequest;
|
||||||
switch (request)
|
switch (request)
|
||||||
@@ -1505,6 +1505,8 @@ static LG_TransportStatus lgmp_requestRecovery(LG_Transport * this,
|
|||||||
}
|
}
|
||||||
if (serial)
|
if (serial)
|
||||||
*serial = ticket;
|
*serial = ticket;
|
||||||
|
if (instance)
|
||||||
|
*instance = header.session;
|
||||||
|
|
||||||
LG_UNLOCK(this->recoveryLock);
|
LG_UNLOCK(this->recoveryLock);
|
||||||
return LG_TRANSPORT_OK;
|
return LG_TRANSPORT_OK;
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ not have :kbd:`ScrLk`.
|
|||||||
- Toggle the video stream
|
- Toggle the video stream
|
||||||
* - :kbd:`ScrLk` + :kbd:`R`
|
* - :kbd:`ScrLk` + :kbd:`R`
|
||||||
- Rotate clockwise by 90 degrees
|
- Rotate clockwise by 90 degrees
|
||||||
|
* - :kbd:`ScrLk` + :kbd:`Shift` + :kbd:`R`
|
||||||
|
- Force guest display recovery mode
|
||||||
* - :kbd:`ScrLk` + :kbd:`=`
|
* - :kbd:`ScrLk` + :kbd:`=`
|
||||||
- Ask the IDD to match the client window resolution
|
- Ask the IDD to match the client window resolution
|
||||||
* - :kbd:`ScrLk` + :kbd:`I`
|
* - :kbd:`ScrLk` + :kbd:`I`
|
||||||
|
|||||||
Reference in New Issue
Block a user