diff --git a/packages/frontend/src/components/RemoteDesktopModal.vue b/packages/frontend/src/components/RemoteDesktopModal.vue index b1d4773..0cbf763 100644 --- a/packages/frontend/src/components/RemoteDesktopModal.vue +++ b/packages/frontend/src/components/RemoteDesktopModal.vue @@ -25,6 +25,11 @@ const rdpDisplayRef = ref(null); const rdpContainerRef = ref(null); const guacClient = ref(null); const connectionStatus = ref<'disconnected' | 'connecting' | 'connected' | 'error'>('disconnected'); +const isResizing = ref(false); +const resizeStartX = ref(0); +const resizeStartY = ref(0); +const initialModalWidthForResize = ref(0); // Renamed to avoid conflict if other 'initialModalWidth' exists +const initialModalHeightForResize = ref(0); // Renamed const statusMessage = ref(''); const keyboard = ref(null); const mouse = ref(null); @@ -502,6 +507,11 @@ onUnmounted(() => { disconnectGuacamole(); // 这里已经调用了 removeInputListeners document.removeEventListener('mousemove', onRestoreButtonMouseMove); document.removeEventListener('mouseup', onRestoreButtonMouseUp); + // Clean up resize listeners if component is unmounted while resizing + if (isResizing.value) { + document.removeEventListener('mousemove', doResize); + document.removeEventListener('mouseup', stopResize); + } }); watch(() => props.connection, (newConnection, oldConnection) => { @@ -529,6 +539,59 @@ const computedModalStyle = computed(() => { }; }); +// Watch for modal size changes to update Guacamole client +watchEffect(() => { + const currentStyle = computedModalStyle.value; // Dependency + if (guacClient.value && connectionStatus.value === 'connected' && rdpContainerRef.value) { + nextTick(() => { + if (rdpContainerRef.value && guacClient.value) { + const displayWidth = rdpContainerRef.value.offsetWidth; + const displayHeight = rdpContainerRef.value.offsetHeight; + if (displayWidth > 0 && displayHeight > 0) { + // console.log(`[RDP Modal] Resizing Guacamole display to: ${displayWidth}x${displayHeight} due to style change.`); + guacClient.value.sendSize(displayWidth, displayHeight); + } + } + }); + } +}); + +const initResize = (event: MouseEvent) => { + isResizing.value = true; + resizeStartX.value = event.clientX; + resizeStartY.value = event.clientY; + initialModalWidthForResize.value = desiredModalWidth.value; + initialModalHeightForResize.value = desiredModalHeight.value; + + document.addEventListener('mousemove', doResize); + document.addEventListener('mouseup', stopResize); + event.preventDefault(); +}; + +const doResize = (event: MouseEvent) => { + if (!isResizing.value) return; + + const deltaX = event.clientX - resizeStartX.value; + const deltaY = event.clientY - resizeStartY.value; + + let newWidth = initialModalWidthForResize.value + deltaX; + let newHeight = initialModalHeightForResize.value + deltaY; + + newWidth = Math.max(MIN_MODAL_WIDTH, newWidth); + newHeight = Math.max(MIN_MODAL_HEIGHT, newHeight); + + desiredModalWidth.value = newWidth; + desiredModalHeight.value = newHeight; +}; + +const stopResize = () => { + if (!isResizing.value) return; + isResizing.value = false; + document.removeEventListener('mousemove', doResize); + document.removeEventListener('mouseup', stopResize); + // Guacamole size update is handled by the watchEffect above +}; +