Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 7s
Root cause: Every GraphicsUpdate copied the full 8.3MB decoded image into the front buffer, cloned all 8.3MB for IPC, and transferred all 8.3MB to the frontend — even when only a 100x100 pixel region changed. During window drag, this created a 25MB/frame pipeline backup. Fix: - Track dirty rectangles from ironrdp's GraphicsUpdate(InclusiveRectangle) - Write path: only copy changed rows from decoded image to front buffer (e.g. 100 rows × 1920 pixels = 768KB vs 8.3MB full frame) - Accumulate dirty region as union of all rects since last get_frame - Read path: if dirty region < 50% of frame, extract only the dirty rectangle bytes; otherwise fall back to full frame - Binary IPC format: 8-byte header [x,y,w,h as u16 LE] + pixel data - Frontend: putImageData at dirty rect offset instead of full frame - Status bar: h-9 text-sm for 3440x1440 readability During window drag (typical 300x400 dirty rect): Before: 8.3MB write + 8.3MB clone + 8.3MB IPC = 24.9MB per frame After: 480KB write + 480KB extract + 480KB IPC = 1.4MB per frame ~17x reduction in data movement per frame. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
70 lines
2.2 KiB
Vue
70 lines
2.2 KiB
Vue
<template>
|
|
<div class="h-9 flex items-center justify-between px-4 bg-[var(--wraith-bg-secondary)] border-t border-[var(--wraith-border)] text-sm text-[var(--wraith-text-muted)] shrink-0">
|
|
<!-- Left: connection info -->
|
|
<div class="flex items-center gap-3">
|
|
<template v-if="sessionStore.activeSession">
|
|
<span class="flex items-center gap-1">
|
|
<span
|
|
class="w-1.5 h-1.5 rounded-full"
|
|
:class="sessionStore.activeSession.protocol === 'ssh' ? 'bg-[#3fb950]' : 'bg-[#1f6feb]'"
|
|
/>
|
|
{{ sessionStore.activeSession.protocol.toUpperCase() }}
|
|
</span>
|
|
<span class="text-[var(--wraith-text-secondary)]">·</span>
|
|
<span>{{ connectionInfo }}</span>
|
|
</template>
|
|
<template v-else>
|
|
<span>Ready</span>
|
|
</template>
|
|
</div>
|
|
|
|
<!-- Right: terminal info -->
|
|
<div class="flex items-center gap-3">
|
|
<button
|
|
class="hover:text-[var(--wraith-text-primary)] transition-colors cursor-pointer"
|
|
title="Change terminal theme"
|
|
@click="emit('open-theme-picker')"
|
|
>
|
|
Theme: {{ activeThemeName }}
|
|
</button>
|
|
<span>UTF-8</span>
|
|
<span v-if="sessionStore.activeDimensions">
|
|
{{ sessionStore.activeDimensions.cols }}×{{ sessionStore.activeDimensions.rows }}
|
|
</span>
|
|
<span v-else>120×40</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, ref } from "vue";
|
|
import { useSessionStore } from "@/stores/session.store";
|
|
import { useConnectionStore } from "@/stores/connection.store";
|
|
|
|
const sessionStore = useSessionStore();
|
|
const connectionStore = useConnectionStore();
|
|
|
|
const activeThemeName = ref("Default");
|
|
|
|
const emit = defineEmits<{
|
|
"open-theme-picker": [];
|
|
}>();
|
|
|
|
const connectionInfo = computed(() => {
|
|
const session = sessionStore.activeSession;
|
|
if (!session) return "";
|
|
|
|
const conn = connectionStore.connections.find((c) => c.id === session.connectionId);
|
|
if (!conn) return session.name;
|
|
|
|
const user = session.username ? `${session.username}@` : "";
|
|
return `${user}${conn.hostname}:${conn.port}`;
|
|
});
|
|
|
|
function setThemeName(name: string): void {
|
|
activeThemeName.value = name;
|
|
}
|
|
|
|
defineExpose({ setThemeName, activeThemeName });
|
|
</script>
|