@matjash/pixi-native-linux-x64 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD_PARTY_NOTICES.md +7 -6
- package/index.cjs +1 -0
- package/native/audio/binding-path.js +16 -0
- package/native/audio/dist/linux-x64/native_audio.node +0 -0
- package/native/audio/package.json +7 -0
- package/native/audio/src/audio_impl.rs +1348 -0
- package/native/audio/src/index.d.ts +63 -0
- package/native/audio/src/index.js +5 -0
- package/native/audio/src/lib.rs +5 -0
- package/native/gpu/dist/linux-x64/pixi_native_gpu.node +0 -0
- package/native/gpu/package.json +20 -20
- package/native/gpu/src/binding-path.js +13 -9
- package/native/gpu/src/index.d.ts +430 -683
- package/native/gpu/src/index.js +34 -33
- package/native/video/package.json +5 -5
- package/native/video/src/binding-path.js +16 -7
- package/native/video/src/index.d.ts +28 -28
- package/native/video/src/index.js +39 -39
- package/native/video/src/lib.rs +34 -7
- package/native/window/binding-path.js +9 -3
- package/native/window/dist/linux-x64/libSDL3.so.0 +0 -0
- package/native/window/dist/linux-x64/native_window.node +0 -0
- package/native/window/package.json +5 -5
- package/native/window/src/index.d.ts +54 -8
- package/native/window/src/index.js +80 -11
- package/native/window/src/key-mapping.js +32 -0
- package/native/window/src/lib.rs +658 -46
- package/package.json +1 -1
package/native/gpu/src/index.js
CHANGED
|
@@ -1,47 +1,48 @@
|
|
|
1
|
-
const Fs = require(
|
|
2
|
-
const { getBindingPath } = require(
|
|
1
|
+
const Fs = require("fs");
|
|
2
|
+
const { getBindingPath } = require("./binding-path.js");
|
|
3
3
|
|
|
4
|
-
const bindingPath = getBindingPath()
|
|
4
|
+
const bindingPath = getBindingPath();
|
|
5
5
|
if (!Fs.existsSync(bindingPath)) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
throw new Error(
|
|
7
|
+
`Native WebGPU is not supported by this pixi-native distribution for ${process.platform}-${process.arch}: ` +
|
|
8
|
+
"pixi_native_gpu.node is not included.",
|
|
9
|
+
);
|
|
10
10
|
}
|
|
11
|
-
const binding = require(bindingPath)
|
|
11
|
+
const binding = require(bindingPath);
|
|
12
12
|
|
|
13
|
-
const contexts = new Set()
|
|
13
|
+
const contexts = new Set();
|
|
14
14
|
|
|
15
15
|
// Pixi probes navigator.gpu by requesting a device before it initializes with
|
|
16
16
|
// the explicitly supplied adapter/device pair. Return the context-owned device
|
|
17
17
|
// so capability detection cannot create an unrelated second Dawn device.
|
|
18
|
-
const createNavigatorAdapter = (context) =>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
18
|
+
const createNavigatorAdapter = (context) =>
|
|
19
|
+
new Proxy(context.adapter, {
|
|
20
|
+
get: (target, property) => {
|
|
21
|
+
if (property === "requestDevice") return async () => context.device;
|
|
22
|
+
const value = Reflect.get(target, property, target);
|
|
23
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
24
|
+
},
|
|
25
|
+
});
|
|
25
26
|
|
|
26
27
|
const createWindowContext = (options) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
28
|
+
const context = binding.createWindowContext(options);
|
|
29
|
+
const navigatorAdapter = createNavigatorAdapter(context);
|
|
30
|
+
const gpu = {
|
|
31
|
+
requestAdapter: async () => navigatorAdapter,
|
|
32
|
+
getPreferredCanvasFormat: () => context.renderer.getPreferredFormat(),
|
|
33
|
+
wgslLanguageFeatures: new Set(),
|
|
34
|
+
};
|
|
35
|
+
const result = { ...context, gpu };
|
|
36
|
+
contexts.add(result);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
38
39
|
|
|
39
40
|
const destroy = (context) => {
|
|
40
|
-
|
|
41
|
-
}
|
|
41
|
+
contexts.delete(context);
|
|
42
|
+
};
|
|
42
43
|
|
|
43
44
|
module.exports = {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
45
|
+
createWindowContext,
|
|
46
|
+
destroy,
|
|
47
|
+
...binding.globals,
|
|
48
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@pixi-native/native-video",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"main": "./src/index.js",
|
|
6
|
+
"types": "./src/index.d.ts"
|
|
7
7
|
}
|
|
@@ -2,16 +2,25 @@ const path = require("node:path");
|
|
|
2
2
|
|
|
3
3
|
const SUPPORTED_TARGETS = new Set(["linux-x64", "win32-x64"]);
|
|
4
4
|
|
|
5
|
-
function getPlatformDirectory(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
function getPlatformDirectory(
|
|
6
|
+
platform = process.platform,
|
|
7
|
+
arch = process.arch,
|
|
8
|
+
) {
|
|
9
|
+
const target = `${platform}-${arch}`;
|
|
10
|
+
if (!SUPPORTED_TARGETS.has(target)) {
|
|
11
|
+
throw new Error(`Native video is unsupported on ${target}`);
|
|
12
|
+
}
|
|
13
|
+
return target;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
function getBindingPath(platform = process.platform, arch = process.arch) {
|
|
14
|
-
|
|
17
|
+
return path.resolve(
|
|
18
|
+
__dirname,
|
|
19
|
+
"..",
|
|
20
|
+
"dist",
|
|
21
|
+
getPlatformDirectory(platform, arch),
|
|
22
|
+
"native_video.node",
|
|
23
|
+
);
|
|
15
24
|
}
|
|
16
25
|
|
|
17
26
|
module.exports = { getBindingPath, getPlatformDirectory };
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
export interface DecoderOptions {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
2
|
+
width: number;
|
|
3
|
+
height: number;
|
|
4
|
+
fps?: number;
|
|
5
|
+
startTime?: number;
|
|
6
|
+
ffmpegPath?: string;
|
|
7
|
+
vaapiDevice?: string;
|
|
8
|
+
playbackRate?: number;
|
|
9
|
+
endTime?: number;
|
|
10
|
+
sourcePaced?: boolean;
|
|
11
|
+
inputArgs?: string[];
|
|
12
|
+
outputArgs?: string[];
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export interface VideoFrame {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
timestampUs: number;
|
|
19
|
+
data: Uint8Array;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export class NativeVideoDecoder {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
public constructor(options: DecoderOptions);
|
|
24
|
+
public open(source: string): void;
|
|
25
|
+
public pollLatest(): VideoFrame | null;
|
|
26
|
+
public pollNext(): VideoFrame | null;
|
|
27
|
+
public queuedFrames(): number;
|
|
28
|
+
public catchUpTo(timestampUs: number): void;
|
|
29
|
+
public pollError(): string | null;
|
|
30
|
+
public backend(): string;
|
|
31
|
+
public decodedFrames(): number;
|
|
32
|
+
public droppedFrames(): number;
|
|
33
|
+
public skippedFrames(): number;
|
|
34
|
+
public isFinished(): boolean;
|
|
35
|
+
public close(): void;
|
|
36
36
|
}
|
|
@@ -5,57 +5,57 @@ const requireNative = createRequire(__filename);
|
|
|
5
5
|
const native = requireNative(getBindingPath());
|
|
6
6
|
|
|
7
7
|
class NativeVideoDecoder {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.decoder = new native.NativeVideoDecoder(options);
|
|
10
|
+
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
open(source) {
|
|
13
|
+
this.decoder.open(source);
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
pollLatest() {
|
|
17
|
+
return this.decoder.pollLatest();
|
|
18
|
+
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
pollNext() {
|
|
21
|
+
return this.decoder.pollNext();
|
|
22
|
+
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
queuedFrames() {
|
|
25
|
+
return this.decoder.queuedFrames();
|
|
26
|
+
}
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
catchUpTo(timestampUs) {
|
|
29
|
+
this.decoder.catchUpTo(timestampUs);
|
|
30
|
+
}
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
pollError() {
|
|
33
|
+
return this.decoder.pollError();
|
|
34
|
+
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
backend() {
|
|
37
|
+
return this.decoder.backend();
|
|
38
|
+
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
decodedFrames() {
|
|
41
|
+
return this.decoder.decodedFrames();
|
|
42
|
+
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
droppedFrames() {
|
|
45
|
+
return this.decoder.droppedFrames();
|
|
46
|
+
}
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
skippedFrames() {
|
|
49
|
+
return this.decoder.skippedFrames();
|
|
50
|
+
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
isFinished() {
|
|
53
|
+
return this.decoder.isFinished();
|
|
54
|
+
}
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
close() {
|
|
57
|
+
this.decoder.close();
|
|
58
|
+
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
module.exports = { NativeVideoDecoder };
|
package/native/video/src/lib.rs
CHANGED
|
@@ -40,7 +40,6 @@ pub struct VideoFrame {
|
|
|
40
40
|
|
|
41
41
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
42
42
|
enum DecoderBackend {
|
|
43
|
-
#[cfg(target_os = "windows")]
|
|
44
43
|
D3d11va,
|
|
45
44
|
Vaapi,
|
|
46
45
|
Cpu,
|
|
@@ -49,7 +48,6 @@ enum DecoderBackend {
|
|
|
49
48
|
impl DecoderBackend {
|
|
50
49
|
fn name(self) -> &'static str {
|
|
51
50
|
match self {
|
|
52
|
-
#[cfg(target_os = "windows")]
|
|
53
51
|
Self::D3d11va => "D3D11VA",
|
|
54
52
|
Self::Vaapi => "VA-API",
|
|
55
53
|
Self::Cpu => "CPU",
|
|
@@ -504,7 +502,6 @@ fn ffmpeg_args(request: &FfmpegRequest, backend: DecoderBackend) -> Vec<String>
|
|
|
504
502
|
];
|
|
505
503
|
|
|
506
504
|
match backend {
|
|
507
|
-
#[cfg(target_os = "windows")]
|
|
508
505
|
DecoderBackend::D3d11va => {
|
|
509
506
|
args.extend(["-hwaccel".to_string(), "d3d11va".to_string()]);
|
|
510
507
|
}
|
|
@@ -538,12 +535,29 @@ fn ffmpeg_args(request: &FfmpegRequest, backend: DecoderBackend) -> Vec<String>
|
|
|
538
535
|
"fps={},scale={}:{}:flags=fast_bilinear:in_range=auto:out_range=tv:in_color_matrix=auto:out_color_matrix=bt709,format=nv12",
|
|
539
536
|
request.fps, request.width, request.height
|
|
540
537
|
);
|
|
541
|
-
let filter =
|
|
542
|
-
format!("hwdownload,format=nv12,{scale}")
|
|
543
|
-
|
|
544
|
-
|
|
538
|
+
let filter = match backend {
|
|
539
|
+
DecoderBackend::Vaapi => format!("hwdownload,format=nv12,{scale}"),
|
|
540
|
+
DecoderBackend::D3d11va => scale,
|
|
541
|
+
// Keep the CPU fallback independent from the color-negotiation path
|
|
542
|
+
// used after VA-API download. Some FFmpeg builds fail to initialize
|
|
543
|
+
// auto_scale when that path is reused for software yuv420p frames.
|
|
544
|
+
DecoderBackend::Cpu => format!(
|
|
545
|
+
"fps={},scale={}:{}:flags=fast_bilinear,format=nv12",
|
|
546
|
+
request.fps, request.width, request.height
|
|
547
|
+
),
|
|
545
548
|
};
|
|
546
549
|
|
|
550
|
+
if backend == DecoderBackend::Cpu {
|
|
551
|
+
// The bundled/minimal FFmpeg builds can fail filter negotiation when
|
|
552
|
+
// multiple filter workers initialize the software graph concurrently.
|
|
553
|
+
args.extend([
|
|
554
|
+
"-filter_threads".to_string(),
|
|
555
|
+
"1".to_string(),
|
|
556
|
+
"-filter_complex_threads".to_string(),
|
|
557
|
+
"1".to_string(),
|
|
558
|
+
]);
|
|
559
|
+
}
|
|
560
|
+
|
|
547
561
|
args.extend([
|
|
548
562
|
"-vf".to_string(),
|
|
549
563
|
filter,
|
|
@@ -820,6 +834,19 @@ mod tests {
|
|
|
820
834
|
assert!(threads_index > input_index && threads_index < pipe_index);
|
|
821
835
|
}
|
|
822
836
|
|
|
837
|
+
#[test]
|
|
838
|
+
fn builds_serial_software_fallback_filter() {
|
|
839
|
+
let args = ffmpeg_args(&request(30.0, 0.0), DecoderBackend::Cpu);
|
|
840
|
+
assert!(args.windows(2).any(|pair| pair == ["-filter_threads", "1"]));
|
|
841
|
+
assert!(args
|
|
842
|
+
.windows(2)
|
|
843
|
+
.any(|pair| pair == ["-filter_complex_threads", "1"]));
|
|
844
|
+
assert!(args
|
|
845
|
+
.iter()
|
|
846
|
+
.any(|arg| arg == "fps=30,scale=1280:720:flags=fast_bilinear,format=nv12"));
|
|
847
|
+
assert!(!args.iter().any(|arg| arg.contains("in_color_matrix=auto")));
|
|
848
|
+
}
|
|
849
|
+
|
|
823
850
|
#[test]
|
|
824
851
|
fn redacts_url_credentials_from_ffmpeg_errors() {
|
|
825
852
|
assert_eq!(
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
const Path = require(
|
|
1
|
+
const Path = require("path");
|
|
2
2
|
|
|
3
|
-
const getBindingPath = () =>
|
|
3
|
+
const getBindingPath = () =>
|
|
4
|
+
Path.join(
|
|
5
|
+
__dirname,
|
|
6
|
+
"dist",
|
|
7
|
+
`${process.platform}-${process.arch}`,
|
|
8
|
+
"native_window.node",
|
|
9
|
+
);
|
|
4
10
|
|
|
5
|
-
module.exports = { getBindingPath }
|
|
11
|
+
module.exports = { getBindingPath };
|
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@pixi-native/native-window",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"main": "./src/index.js",
|
|
6
|
+
"types": "./src/index.d.ts"
|
|
7
7
|
}
|
|
@@ -1,11 +1,46 @@
|
|
|
1
|
-
export interface
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
export interface NativeSurfaceDescriptor {
|
|
2
|
+
readonly version: 1;
|
|
3
|
+
readonly api: "win32" | "x11" | "wayland";
|
|
4
|
+
readonly window: Buffer;
|
|
5
|
+
readonly display?: Buffer;
|
|
6
|
+
readonly instance?: Buffer;
|
|
7
|
+
readonly eglWindow?: Buffer;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface NativeWindowOptions {
|
|
11
|
+
readonly title: string;
|
|
12
|
+
readonly width: number;
|
|
13
|
+
readonly height: number;
|
|
14
|
+
readonly resizable: boolean;
|
|
15
|
+
readonly borderless: boolean;
|
|
16
|
+
readonly transparent: boolean;
|
|
17
|
+
readonly x?: number;
|
|
18
|
+
readonly y?: number;
|
|
19
|
+
readonly graphics: "webgpu" | "webgl";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface NativeWindow {
|
|
23
|
+
readonly id: number;
|
|
24
|
+
readonly x: number;
|
|
25
|
+
readonly y: number;
|
|
26
|
+
readonly pixelWidth: number;
|
|
27
|
+
readonly pixelHeight: number;
|
|
28
|
+
readonly display: { readonly frequency: number };
|
|
29
|
+
readonly destroyed: boolean;
|
|
30
|
+
readonly surface: NativeSurfaceDescriptor;
|
|
31
|
+
readonly videoDriver: string;
|
|
32
|
+
readonly transparent: boolean;
|
|
33
|
+
pollEvents(): void;
|
|
34
|
+
setPosition(x: number, y: number): void;
|
|
35
|
+
minimize(): void;
|
|
36
|
+
maximize(): void;
|
|
37
|
+
restore(): void;
|
|
38
|
+
makeGlCurrent(): boolean;
|
|
39
|
+
setGlSwapInterval(interval: number): boolean;
|
|
40
|
+
swapGl(): boolean;
|
|
41
|
+
glVersion(): string;
|
|
42
|
+
on(event: string, listener: (event: Record<string, unknown>) => void): this;
|
|
43
|
+
destroy(): void;
|
|
9
44
|
}
|
|
10
45
|
|
|
11
46
|
export interface ModalFrameController {
|
|
@@ -13,5 +48,16 @@ export interface ModalFrameController {
|
|
|
13
48
|
detach(): void;
|
|
14
49
|
}
|
|
15
50
|
|
|
51
|
+
export interface NativeWindowApi {
|
|
52
|
+
createWindow(options: NativeWindowOptions): NativeWindow;
|
|
53
|
+
pollEvents(): void;
|
|
54
|
+
waitForCompositorFrame(timeoutMs?: number): Promise<boolean>;
|
|
55
|
+
createModalFrameController(
|
|
56
|
+
nativeData: Buffer,
|
|
57
|
+
onFrame: () => void,
|
|
58
|
+
onState: (active: boolean) => void,
|
|
59
|
+
): ModalFrameController;
|
|
60
|
+
}
|
|
61
|
+
|
|
16
62
|
declare const nativeWindow: NativeWindowApi;
|
|
17
63
|
export = nativeWindow;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
const
|
|
1
|
+
const { EventEmitter } = require("node:events");
|
|
2
|
+
const Fs = require("node:fs");
|
|
2
3
|
const { createRequire } = require("node:module");
|
|
3
4
|
const { getBindingPath } = require("../binding-path.js");
|
|
5
|
+
const { normalizeSdlKeyName } = require("./key-mapping.js");
|
|
4
6
|
|
|
5
7
|
const requireNative = createRequire(__filename);
|
|
6
8
|
const bindingPath = getBindingPath();
|
|
@@ -11,22 +13,89 @@ if (!Fs.existsSync(bindingPath)) {
|
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
const binding = requireNative(bindingPath);
|
|
16
|
+
const windows = new Map();
|
|
17
|
+
let waylandPositionWarned = false;
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
class NativeWindow extends EventEmitter {
|
|
20
|
+
constructor(options) {
|
|
21
|
+
super();
|
|
22
|
+
this._nativeWindow = new binding.NativeSdlWindow(options);
|
|
23
|
+
windows.set(this._nativeWindow.id, this);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get id() { return this._nativeWindow.id; }
|
|
27
|
+
get x() { return this._nativeWindow.x; }
|
|
28
|
+
get y() { return this._nativeWindow.y; }
|
|
29
|
+
get pixelWidth() { return this._nativeWindow.pixelWidth; }
|
|
30
|
+
get pixelHeight() { return this._nativeWindow.pixelHeight; }
|
|
31
|
+
get display() { return { frequency: this._nativeWindow.refreshRate }; }
|
|
32
|
+
get destroyed() { return this._nativeWindow.destroyed; }
|
|
33
|
+
get surface() { return this._nativeWindow.surface; }
|
|
34
|
+
get videoDriver() { return this._nativeWindow.videoDriver; }
|
|
35
|
+
get transparent() { return this._nativeWindow.transparent; }
|
|
36
|
+
|
|
37
|
+
pollEvents() { pollEvents(); }
|
|
38
|
+
|
|
39
|
+
setPosition(x, y) {
|
|
40
|
+
if (this._nativeWindow.setPosition(x, y)) return;
|
|
41
|
+
if (!waylandPositionWarned) {
|
|
42
|
+
waylandPositionWarned = true;
|
|
43
|
+
console.warn(
|
|
44
|
+
"[pixi-native] SDL3 Wayland ignores absolute toplevel window positioning.",
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
minimize() { this._nativeWindow.minimize(); }
|
|
50
|
+
maximize() { this._nativeWindow.maximize(); }
|
|
51
|
+
restore() { this._nativeWindow.restore(); }
|
|
52
|
+
makeGlCurrent() { return this._nativeWindow.makeGlCurrent(); }
|
|
53
|
+
setGlSwapInterval(interval) { return this._nativeWindow.setGlSwapInterval(interval); }
|
|
54
|
+
swapGl() { return this._nativeWindow.swapGl(); }
|
|
55
|
+
glVersion() { return this._nativeWindow.glVersion(); }
|
|
56
|
+
|
|
57
|
+
destroy() {
|
|
58
|
+
if (this.destroyed) return;
|
|
59
|
+
windows.delete(this.id);
|
|
60
|
+
this._nativeWindow.destroy();
|
|
61
|
+
this.removeAllListeners();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const emitNativeEvent = (window, event) => {
|
|
66
|
+
const { kind, windowId, superKey, ...payload } = event;
|
|
67
|
+
if (kind === "keyDown" || kind === "keyUp") {
|
|
68
|
+
payload.key = normalizeSdlKeyName(payload.key);
|
|
69
|
+
}
|
|
70
|
+
window.emit(kind, { ...payload, type: kind, super: superKey });
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const pollEvents = () => {
|
|
74
|
+
for (const event of binding.pollEvents()) {
|
|
75
|
+
if (event.kind === "quit") {
|
|
76
|
+
for (const window of [...windows.values()]) {
|
|
77
|
+
emitNativeEvent(window, { ...event, kind: "close" });
|
|
78
|
+
}
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const window = windows.get(event.windowId);
|
|
82
|
+
if (window) emitNativeEvent(window, event);
|
|
83
|
+
}
|
|
17
84
|
};
|
|
18
85
|
|
|
86
|
+
const createWindow = (options) => new NativeWindow(options);
|
|
19
87
|
const waitForCompositorFrame = (timeoutMs) =>
|
|
20
88
|
binding.waitForCompositorFrame(timeoutMs);
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const controller = new binding.ModalFrameController(
|
|
24
|
-
nativeData,
|
|
25
|
-
onFrame,
|
|
26
|
-
onState,
|
|
27
|
-
);
|
|
89
|
+
const createModalFrameController = (nativeData, onFrame, onState) => {
|
|
90
|
+
const controller = new binding.ModalFrameController(nativeData, onFrame, onState);
|
|
28
91
|
controller.attach();
|
|
29
92
|
return controller;
|
|
30
93
|
};
|
|
31
94
|
|
|
32
|
-
module.exports = {
|
|
95
|
+
module.exports = {
|
|
96
|
+
NativeWindow,
|
|
97
|
+
createWindow,
|
|
98
|
+
createModalFrameController,
|
|
99
|
+
pollEvents,
|
|
100
|
+
waitForCompositorFrame,
|
|
101
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const SDL_KEY_NAMES = Object.freeze({
|
|
2
|
+
Up: "up",
|
|
3
|
+
Down: "down",
|
|
4
|
+
Left: "left",
|
|
5
|
+
Right: "right",
|
|
6
|
+
Space: "space",
|
|
7
|
+
Return: "return",
|
|
8
|
+
Escape: "escape",
|
|
9
|
+
Backspace: "backspace",
|
|
10
|
+
Tab: "tab",
|
|
11
|
+
"Left Ctrl": "ctrl",
|
|
12
|
+
"Right Ctrl": "ctrl",
|
|
13
|
+
"Left Shift": "shift",
|
|
14
|
+
"Right Shift": "shift",
|
|
15
|
+
"Left Alt": "alt",
|
|
16
|
+
"Right Alt": "alt",
|
|
17
|
+
"Left GUI": "gui",
|
|
18
|
+
"Right GUI": "gui",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/** Preserves the key names exposed by the previous @kmamal/sdl adapter. */
|
|
22
|
+
const normalizeSdlKeyName = (name) => {
|
|
23
|
+
if (typeof name !== "string") return name;
|
|
24
|
+
const mapped = SDL_KEY_NAMES[name];
|
|
25
|
+
if (mapped) return mapped;
|
|
26
|
+
if (/^[A-Z]$/.test(name) || /^F\d{1,2}$/.test(name)) {
|
|
27
|
+
return name.toLowerCase();
|
|
28
|
+
}
|
|
29
|
+
return name;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = { normalizeSdlKeyName };
|