Skip to content

Commit eac9a7f

Browse files
waffles-devwaffles-devTibixDev
authored
feat: Add config options to add new or replace existing arguments for RDP (#332)
* feat: Add config options to add new or replace existing arguments for RDP * style: Visual improvements to RDP args * Fix replacement args being added as new * style: Change experimental color to blue * Allow overwriting of existing arg by specifying empty new arg --------- Co-authored-by: waffles-dev <waffles-dev@outlook.com> Co-authored-by: TibixDev <tibix@fhs.sh>
1 parent 1b24d60 commit eac9a7f

File tree

4 files changed

+137
-17
lines changed

4 files changed

+137
-17
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/renderer/lib/config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import { type WinApp } from "../../types";
44
import { WINBOAT_DIR } from "./constants";
55
import { type PTSerializableDeviceInfo } from "./usbmanager";
66

7+
export type RdpArg ={
8+
original?: string
9+
newArg: string
10+
isReplacement:boolean
11+
}
12+
713
export type WinboatConfigObj = {
814
scale: number;
915
scaleDesktop: number,
@@ -12,7 +18,9 @@ export type WinboatConfigObj = {
1218
passedThroughDevices: PTSerializableDeviceInfo[];
1319
customApps: WinApp[]
1420
experimentalFeatures: boolean
21+
advancedFeatures: boolean
1522
multiMonitor: number
23+
rdpArgs: RdpArg[]
1624
};
1725

1826
const defaultConfig: WinboatConfigObj = {
@@ -23,7 +31,9 @@ const defaultConfig: WinboatConfigObj = {
2331
passedThroughDevices: [],
2432
customApps: [],
2533
experimentalFeatures: false,
34+
advancedFeatures: false,
2635
multiMonitor: 0,
36+
rdpArgs:[]
2737
};
2838

2939
export class WinboatConfig {

src/renderer/lib/winboat.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ const presetApps: WinApp[] = [
5555
}
5656
];
5757

58+
/**
59+
* The stock RDP args that apply to all app launches by default
60+
*/
61+
const stockArgs = ["/cert:ignore", "+clipboard", "/sound:sys:pulse", "/microphone:sys:pulse", "/floatbar", "/compression"];
62+
63+
/**
64+
* Returns second/original param if first is undefined or null, else first/test param
65+
*/
66+
const useOriginalIfUndefinedOrNull = (test: string | undefined, original: string) => {
67+
return (test === undefined || test === null) ? original : test
68+
}
69+
5870
/**
5971
* For specifying custom behavior when launching an app (e.g. novnc)
6072
* Maps a {@link WinApp.Path} to a callback, which is called in {@link Winboat.launchApp} if specified
@@ -646,21 +658,24 @@ export class Winboat {
646658

647659
const cleanAppName = app.Name.replace(/[,.'"]/g, "");
648660

661+
// Arguments specified by user to override stock arguments
662+
const replacementArgs = this.#wbConfig?.config.rdpArgs.filter(a => a.isReplacement);
663+
// Additional (new) arguments added by user
664+
const newArgs = this.#wbConfig?.config.rdpArgs.filter(a => !a.isReplacement).map(v => v.newArg) ?? [];
665+
// The stock arguments after any replacements have been made and new arguments have been added
666+
const combinedArgs = stockArgs.map(argStr => useOriginalIfUndefinedOrNull(replacementArgs?.find(r => argStr === r.original?.trim())?.newArg, argStr))
667+
.concat(newArgs).join(" ");
668+
649669
let cmd = `${freeRDPBin} /u:"${username}"\
650670
/p:"${password}"\
651671
/v:127.0.0.1\
652672
/port:${rdpHostPort}\
653-
/cert:ignore\
654673
${this.#wbConfig?.config.multiMonitor == 2 ? '+span' : ''}\
655-
+clipboard\
656674
-wallpaper\
657-
/sound:sys:pulse\
658-
/microphone:sys:pulse\
659-
/floatbar\
660675
${this.#wbConfig?.config.multiMonitor == 1 ? '/multimon' : ''}\
661676
${this.#wbConfig?.config.smartcardEnabled ? '/smartcard' : ''}\
662-
/compression\
663677
/scale-desktop:${this.#wbConfig?.config.scaleDesktop ?? 100}\
678+
${combinedArgs}\
664679
/wm-class:"${cleanAppName}"\
665680
/app:program:"${app.Path}",name:"${cleanAppName}" &`;
666681

@@ -669,15 +684,11 @@ export class Winboat {
669684
/p:"${password}"\
670685
/v:127.0.0.1\
671686
/port:${rdpHostPort}\
672-
/cert:ignore\
673-
+clipboard\
687+
${combinedArgs}\
674688
+f\
675-
/sound:sys:pulse\
676-
/microphone:sys:pulse\
677-
/floatbar\
678689
${this.#wbConfig?.config.smartcardEnabled ? '/smartcard' : ''}\
679690
/scale:${this.#wbConfig?.config.scale ?? 100}\
680-
/compression &`;
691+
&`;
681692
}
682693

683694
// Multiple spaces become one

src/renderer/views/Config.vue

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,72 @@
254254
</x-card>
255255
</div>
256256
</div>
257+
<div v-show="wbConfig.config.advancedFeatures" :key="rerenderAdvanced">
258+
<x-label class="mb-4 text-neutral-300">FreeRDP</x-label>
259+
<div class="flex flex-col gap-4">
260+
<!-- RDP args -->
261+
<x-card
262+
class="flex flex-row justify-between items-center p-2 py-3 my-0 w-full backdrop-blur-xl backdrop-brightness-150 bg-neutral-800/20">
263+
<div class="w-full">
264+
<div class="flex flex-row gap-2 items-center mb-2">
265+
<Icon class="inline-flex text-violet-400 size-8" icon="fluent:tv-24-filled"></Icon>
266+
<h1 class="my-0 text-lg font-semibold">
267+
FreeRDP Arguments
268+
<span class="bg-blue-500 rounded-full px-3 py-0.5 text-sm ml-2">
269+
Advanced
270+
</span>
271+
</h1>
272+
</div>
273+
274+
<x-label
275+
v-if="wbConfig.config.rdpArgs.length == 0"
276+
class="text-neutral-400 text-[0.9rem] !pt-0 !mt-0"
277+
>
278+
Press the buttons below to add arguments to FreeRDP, you can choose to either add a new argument or modify an existing one to your liking via replacement
279+
</x-label>
280+
<TransitionGroup name="devices" tag="x-box" class="flex-col gap-2 mt-4">
281+
<x-card class="flex justify-between items-center gap-2 px-2 py-0 m-0 bg-white/5"
282+
v-for="(arg, index) in rdpArgs" :key="index"
283+
>
284+
<div class="grid grid-cols-2 gap-2 items-center w-full">
285+
<x-input type="text" class="!max-w-full" v-if="arg.isReplacement"
286+
:value="arg.original" @input="(e: any) => arg.original = e.target.value"
287+
>
288+
<x-label>Original Argument</x-label>
289+
</x-input>
290+
<x-input type="text" class="!max-w-full !mt-0"
291+
:class="{ 'col-span-2': !arg.isReplacement }"
292+
:value="arg.newArg" @input="(e: any) => arg.newArg = e.target.value"
293+
>
294+
<x-label>New Argument</x-label>
295+
</x-input>
296+
</div>
297+
<x-button class="mt-1 !bg-gradient-to-tl from-red-500/20 to-transparent hover:from-red-500/30 transition !border-0"
298+
@click="rdpArgs.splice(index, 1);"
299+
>
300+
<x-icon href="#remove"></x-icon>
301+
</x-button>
302+
</x-card>
303+
</TransitionGroup>
304+
<div class="flex flex-row gap-2" :class="{ 'mt-4': rdpArgs.length }">
305+
<x-button class="!bg-gradient-to-tl from-blue-400/20 shadow-md shadow-blue-950/20 to-transparent hover:from-blue-400/30 transition"
306+
@click="rdpArgs.push({newArg:'', isReplacement:false})
307+
"
308+
>
309+
<x-icon href="#add"></x-icon>
310+
<x-label>Add Argument</x-label>
311+
</x-button>
312+
<x-button class="!bg-gradient-to-tl from-yellow-400/20 shadow-md shadow-yellow-950/20 to-transparent hover:from-yellow-400/30 transition"
313+
@click="rdpArgs.push({newArg:'', original:'', isReplacement:true})"
314+
>
315+
<Icon class="inline-flex size-6" icon="codex:replace" />
316+
<x-label>Replace Argument</x-label>
317+
</x-button>
318+
</div>
319+
</div>
320+
</x-card>
321+
</div>
322+
</div>
257323
<div>
258324
<x-label class="mb-4 text-neutral-300">General</x-label>
259325
<div class="flex flex-col gap-4">
@@ -425,7 +491,26 @@
425491
:toggled="wbConfig.config.experimentalFeatures"
426492
@toggle="toggleExperimentalFeatures"
427493
size="large"
428-
></x-switch>
494+
></x-switch>
495+
</div>
496+
</x-card>
497+
<x-card
498+
class="flex items-center p-2 flex-row justify-between w-full py-3 my-0 bg-neutral-800/20 backdrop-brightness-150 backdrop-blur-xl">
499+
<div>
500+
<div class="flex flex-row items-center gap-2 mb-2">
501+
<Icon class="text-violet-400 inline-flex size-8" icon="mdi:administrator">
502+
</Icon>
503+
<h1 class="text-lg my-0 font-semibold">
504+
Advanced Settings
505+
</h1>
506+
</div>
507+
<p class="text-neutral-400 text-[0.9rem] !pt-0 !mt-0">
508+
If enabled, you'll have access to advanced settings that may prevent WinBoat from working if misconfigured
509+
</p>
510+
</div>
511+
<div class="flex flex-row justify-center items-center gap-2">
512+
<x-switch :toggled="wbConfig.config.advancedFeatures" @toggle="toggleAdvancedFeatures"
513+
size="large"></x-switch>
429514
</div>
430515
</x-card>
431516
</div>
@@ -458,13 +543,13 @@
458543
</template>
459544

460545
<script setup lang="ts">
461-
import { computed, onMounted, ref } from 'vue';
546+
import { computed, onMounted, ref, watch } from 'vue';
462547
import { computedAsync } from '@vueuse/core';
463548
import { ContainerStatus, Winboat } from '../lib/winboat';
464549
import type { ComposeConfig } from '../../types';
465550
import { getSpecs } from '../lib/specs';
466551
import { Icon } from '@iconify/vue';
467-
import { WinboatConfig } from '../lib/config';
552+
import { RdpArg, WinboatConfig } from '../lib/config';
468553
import { USBManager, type PTSerializableDeviceInfo } from '../lib/usbmanager';
469554
import { type Device } from "usb";
470555
import {
@@ -509,10 +594,13 @@ const resetQuestionCounter = ref(0);
509594
const isResettingWinboat = ref(false);
510595
const isUpdatingUSBPrerequisites = ref(false);
511596
const origApplicationScale = ref(0);
597+
const rdpArgs = ref<RdpArg[]>([]);
512598
513599
// For USB Devices
514600
const availableDevices = ref<Device[]>([]);
515601
const rerenderExperimental = ref(0);
602+
// For RDP Args
603+
const rerenderAdvanced = ref(0);
516604
// ^ This ref is needed because reactivity fails on wbConfig.
517605
// We manually increment this value in toggleExperimentalFeatures() to force rerender.
518606
@@ -528,6 +616,10 @@ onMounted(async () => {
528616
await assignValues();
529617
});
530618
619+
watch(rdpArgs, newArgs => {
620+
wbConfig.config.rdpArgs = newArgs;
621+
}, {deep:2});
622+
531623
function ensureNumericInput(e: any) {
532624
if (e.metaKey || e.ctrlKey || e.which <= 0 || e.which === 8 || e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
533625
return;
@@ -571,6 +663,8 @@ async function assignValues() {
571663
572664
origApplicationScale.value = wbConfig.config.scaleDesktop;
573665
666+
rdpArgs.value = wbConfig.config.rdpArgs;
667+
574668
const specs = await getSpecs();
575669
maxRamGB.value = specs.ramGB;
576670
maxNumCores.value = specs.cpuCores;
@@ -759,6 +853,11 @@ async function toggleExperimentalFeatures() {
759853
}
760854
}
761855
856+
async function toggleAdvancedFeatures() {
857+
wbConfig.config.advancedFeatures = !wbConfig.config.advancedFeatures;
858+
rerenderAdvanced.value++;
859+
}
860+
762861
</script>
763862

764863
<style scoped>

0 commit comments

Comments
 (0)