quickwin 1.1.4 → 1.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.
Files changed (41) hide show
  1. package/README.en.md +7 -3
  2. package/README.md +7 -3
  3. package/examples/exec_server.js +3535 -34
  4. package/examples/exec_server.ts +71 -26
  5. package/examples/exec_server_worker.js +45 -0
  6. package/examples/exec_server_worker.ts +39 -0
  7. package/examples/pdf_viewer.js +11 -10
  8. package/examples/setres.js +104 -0
  9. package/examples/setres.ts +120 -0
  10. package/examples/test_gallery.js +11 -10
  11. package/examples/test_react_lazy.js +11 -10
  12. package/examples/test_react_listbox.js +11 -10
  13. package/examples/test_root_window.js +11 -10
  14. package/examples/test_tab.js +11 -10
  15. package/lib/fetch.js +35 -7
  16. package/lib/fetch.ts +24 -4
  17. package/lib/text-measure.js +8 -6
  18. package/lib/text-measure.ts +8 -6
  19. package/main.js +46 -0
  20. package/package.json +2 -1
  21. package/quickwin.d.ts +2 -1
  22. package/qwin-nowasm-x86.exe +0 -0
  23. package/qwin-nowasm.exe +0 -0
  24. package/qwin-x86.exe +0 -0
  25. package/qwin.exe +0 -0
  26. package/test/run.js +4 -1
  27. package/test/run.ts +4 -1
  28. package/test/test_net_fetch.js +62 -0
  29. package/test/test_net_fetch.ts +72 -0
  30. package/test/test_react_complex.js +14 -13
  31. package/test/test_react_counter.js +11 -10
  32. package/test/test_react_flex.js +11 -10
  33. package/test/test_react_hidden.js +13 -12
  34. package/test/test_react_listview_link.js +11 -10
  35. package/test/test_react_render.js +11 -10
  36. package/test/test_wolfssl_read.js +201 -0
  37. package/test/test_wolfssl_read.ts +181 -0
  38. package/test/test_worker_concurrent.js +45 -0
  39. package/test/test_worker_concurrent.ts +56 -0
  40. package/test/test_worker_data_url.js +46 -0
  41. package/test/test_worker_data_url.ts +51 -0
@@ -1,35 +1,80 @@
1
1
  import { createServer } from '../lib/http-server.js'
2
- import * as std from 'std'
3
-
4
- function readAll(file: std.FILE): string {
5
- const chunks: Uint8Array[] = []
6
- const buf = new Uint8Array(4096)
7
- while (true) {
8
- const n = file.read(buf.buffer, 0, 4096)
9
- if (n <= 0) break
10
- chunks.push(buf.slice(0, n))
11
- }
12
- let total = 0
13
- for (const c of chunks) total += c.length
14
- const out = new Uint8Array(total)
15
- let offset = 0
16
- for (const c of chunks) { out.set(c, offset); offset += c.length }
17
- return new TextDecoder().decode(out)
2
+ import * as os from 'os'
3
+
4
+ // WORKER_DATA_URL 由 esbuild --define 在 build.ts 中注入(base64 data: URL)
5
+ declare const WORKER_DATA_URL: string
6
+
7
+ const EXEC_TIMEOUT_MS = 60_000
8
+
9
+ interface ExecResult {
10
+ out: Uint8Array
11
+ code: number
12
+ error: string | null
13
+ }
14
+
15
+ function runInWorker(cmd: string): Promise<ExecResult> {
16
+ return new Promise((resolve, reject) => {
17
+ const worker = new os.Worker(WORKER_DATA_URL)
18
+ const id = 1
19
+ let settled = false
20
+ let timer: ReturnType<typeof os.setTimeout>
21
+
22
+ const finish = (fn: () => void) => {
23
+ if (settled) return
24
+ settled = true
25
+ os.clearTimeout(timer)
26
+ worker.onmessage = null
27
+ fn()
28
+ }
29
+
30
+ timer = os.setTimeout(() => {
31
+ finish(() => reject(new Error('exec timeout')))
32
+ }, EXEC_TIMEOUT_MS)
33
+
34
+ worker.onmessage = (e) => {
35
+ const msg = e.data as { type: string; id: number; out?: Uint8Array; code?: number; error?: string | null }
36
+ if (msg.type !== 'result' || msg.id !== id) return
37
+ finish(() => resolve({ out: msg.out ?? new Uint8Array(0), code: msg.code ?? -1, error: msg.error ?? null }))
38
+ }
39
+
40
+ try {
41
+ worker.postMessage({ type: 'run', id, cmd })
42
+ } catch (ex) {
43
+ finish(() => reject(ex instanceof Error ? ex : new Error(String(ex))))
44
+ }
45
+ })
18
46
  }
19
47
 
20
48
  const server = createServer(async (req) => {
21
- if (req.method === 'POST' && new URL(req.url).pathname === '/exec') {
49
+ const path = new URL(req.url).pathname
50
+ if (req.method === 'GET' && (path === '/' || path === '/health')) {
51
+ return new Response('ok', { headers: { 'Content-Type': 'text/plain' } })
52
+ }
53
+ if (req.method === 'POST' && path === '/exec') {
22
54
  const body = await req.json() as { cmd: string }
23
- const file = std.popen(body.cmd, 'r')
24
- if (!file) return new Response('popen failed', { status: 500 })
25
- const output = readAll(file)
26
- file.close()
27
- return new Response(output, {
28
- headers: { 'Content-Type': 'application/octet-stream' }
29
- })
55
+ try {
56
+ const { out, code, error } = await runInWorker(body.cmd)
57
+ if (error) {
58
+ return new Response(JSON.stringify({ error }), {
59
+ status: 500,
60
+ headers: { 'Content-Type': 'application/json' }
61
+ })
62
+ }
63
+ return new Response(out, {
64
+ headers: {
65
+ 'Content-Type': 'application/octet-stream',
66
+ 'X-Exit-Code': String(code),
67
+ }
68
+ })
69
+ } catch (ex) {
70
+ return new Response(JSON.stringify({ error: String(ex) }), {
71
+ status: 504,
72
+ headers: { 'Content-Type': 'application/json' }
73
+ })
74
+ }
30
75
  }
31
76
  return new Response('Not Found', { status: 404 })
32
77
  })
33
78
 
34
- server.listen(8080)
35
- console.log('listening on http://localhost:8080')
79
+ const rc = server.listen(8080, '0.0.0.0')
80
+ console.log('listen rc=' + rc + ' addr=' + JSON.stringify(server.address()))
@@ -0,0 +1,45 @@
1
+ import * as os from 'os';
2
+ import * as std from 'std';
3
+ function readBytes(file) {
4
+ const chunks = [];
5
+ const buf = new Uint8Array(4096);
6
+ while (true) {
7
+ const n = file.read(buf.buffer, 0, 4096);
8
+ if (n <= 0)
9
+ break;
10
+ chunks.push(buf.slice(0, n));
11
+ }
12
+ let total = 0;
13
+ for (const c of chunks)
14
+ total += c.length;
15
+ const out = new Uint8Array(total);
16
+ let offset = 0;
17
+ for (const c of chunks) {
18
+ out.set(c, offset);
19
+ offset += c.length;
20
+ }
21
+ return out;
22
+ }
23
+ const parent = os.Worker.parent;
24
+ parent.onmessage = (e) => {
25
+ const msg = e.data;
26
+ if (msg.type !== 'run' || typeof msg.cmd !== 'string')
27
+ return;
28
+ let out = new Uint8Array(0);
29
+ let code = -1;
30
+ let error = null;
31
+ try {
32
+ const file = std.popen(msg.cmd, 'r');
33
+ if (!file) {
34
+ error = 'popen failed';
35
+ }
36
+ else {
37
+ out = readBytes(file);
38
+ code = file.close();
39
+ }
40
+ }
41
+ catch (ex) {
42
+ error = String(ex);
43
+ }
44
+ parent.postMessage({ type: 'result', id: msg.id, out, code, error });
45
+ };
@@ -0,0 +1,39 @@
1
+ import * as os from 'os'
2
+ import * as std from 'std'
3
+
4
+ function readBytes(file: std.FILE): Uint8Array {
5
+ const chunks: Uint8Array[] = []
6
+ const buf = new Uint8Array(4096)
7
+ while (true) {
8
+ const n = file.read(buf.buffer, 0, 4096)
9
+ if (n <= 0) break
10
+ chunks.push(buf.slice(0, n))
11
+ }
12
+ let total = 0
13
+ for (const c of chunks) total += c.length
14
+ const out = new Uint8Array(total)
15
+ let offset = 0
16
+ for (const c of chunks) { out.set(c, offset); offset += c.length }
17
+ return out
18
+ }
19
+
20
+ const parent = os.Worker.parent
21
+ parent.onmessage = (e) => {
22
+ const msg = e.data as { type: string; id: number; cmd?: string }
23
+ if (msg.type !== 'run' || typeof msg.cmd !== 'string') return
24
+ let out: Uint8Array = new Uint8Array(0)
25
+ let code = -1
26
+ let error: string | null = null
27
+ try {
28
+ const file = std.popen(msg.cmd, 'r')
29
+ if (!file) {
30
+ error = 'popen failed'
31
+ } else {
32
+ out = readBytes(file)
33
+ code = file.close()
34
+ }
35
+ } catch (ex) {
36
+ error = String(ex)
37
+ }
38
+ parent.postMessage({ type: 'result', id: msg.id, out, code, error })
39
+ }
@@ -15370,7 +15370,7 @@ var import_react_reconciler = __toESM(require_react_reconciler(), 1);
15370
15370
  var import_react = __toESM(require_react(), 1);
15371
15371
  var import_constants = __toESM(require_constants(), 1);
15372
15372
  import * as gui3 from "gui";
15373
- import * as os from "os";
15373
+ import * as os2 from "os";
15374
15374
 
15375
15375
  // _build/lib/react-qw/props.js
15376
15376
  import * as gui from "gui";
@@ -15491,6 +15491,7 @@ function calculateFlexLayout(flex, parentW, parentH, children) {
15491
15491
 
15492
15492
  // _build/lib/text-measure.js
15493
15493
  import * as ffi from "ffi";
15494
+ import * as os from "os";
15494
15495
  import * as win from "win";
15495
15496
  import * as gui2 from "gui";
15496
15497
  function loadProc(lib, name) {
@@ -15507,7 +15508,7 @@ var DrawTextW = loadProc(user32, "DrawTextW");
15507
15508
  var GetDC = loadProc(user32, "GetDC");
15508
15509
  var ReleaseDC = loadProc(user32, "ReleaseDC");
15509
15510
  var SelectObject = loadProc(gdi32, "SelectObject");
15510
- var FFI_TYPE_UINT642 = ffi.FFI_TYPE_UINT64;
15511
+ var FFI_HND = os.arch === "ia32" ? ffi.FFI_TYPE_UINT32 : ffi.FFI_TYPE_UINT64;
15511
15512
  var FFI_S32 = ffi.FFI_TYPE_SINT32;
15512
15513
  var FFI_PTR = ffi.FFI_TYPE_POINTER;
15513
15514
  function measureText(hdc, text, maxWidth) {
@@ -15515,14 +15516,14 @@ function measureText(hdc, text, maxWidth) {
15515
15516
  const rect = new ArrayBuffer(16);
15516
15517
  const dv = new DataView(rect);
15517
15518
  dv.setInt32(8, maxWidth, true);
15518
- ffi.ffiCall(DrawTextW, [FFI_TYPE_UINT642, FFI_PTR, FFI_S32, FFI_PTR, FFI_S32], [
15519
+ ffi.ffiCall(DrawTextW, [FFI_HND, FFI_PTR, FFI_S32, FFI_PTR, FFI_S32], [
15519
15520
  hdc,
15520
15521
  textBuf,
15521
15522
  -1,
15522
15523
  rect,
15523
15524
  1024
15524
15525
  /* gui.DrawTextFlag.CALCRECT */
15525
- ], FFI_TYPE_UINT642);
15526
+ ], FFI_S32);
15526
15527
  return { width: dv.getInt32(8, true), height: dv.getInt32(12, true) };
15527
15528
  }
15528
15529
  function getButtonIdealSize(hwnd) {
@@ -15532,15 +15533,15 @@ function getButtonIdealSize(hwnd) {
15532
15533
  return { width: dv.getInt32(0, true), height: dv.getInt32(4, true) };
15533
15534
  }
15534
15535
  function measureTextForHwnd(hwnd, text) {
15535
- const hdc = ffi.ffiCall(GetDC, [FFI_TYPE_UINT642], [hwnd], FFI_TYPE_UINT642);
15536
+ const hdc = ffi.ffiCall(GetDC, [FFI_HND], [hwnd], FFI_HND);
15536
15537
  if (!hdc)
15537
15538
  return { width: 0, height: 0 };
15538
15539
  const hFont = gui2.SendMessage(hwnd, 49, 0, 0);
15539
- const oldFont = hFont ? ffi.ffiCall(SelectObject, [FFI_TYPE_UINT642, FFI_TYPE_UINT642], [hdc, hFont], FFI_TYPE_UINT642) : 0;
15540
+ const oldFont = hFont ? ffi.ffiCall(SelectObject, [FFI_HND, FFI_HND], [hdc, hFont], FFI_HND) : 0;
15540
15541
  const result = measureText(hdc, text, 0);
15541
15542
  if (hFont)
15542
- ffi.ffiCall(SelectObject, [FFI_TYPE_UINT642, FFI_TYPE_UINT642], [hdc, oldFont], FFI_TYPE_UINT642);
15543
- ffi.ffiCall(ReleaseDC, [FFI_TYPE_UINT642, FFI_TYPE_UINT642], [hwnd, hdc], FFI_S32);
15543
+ ffi.ffiCall(SelectObject, [FFI_HND, FFI_HND], [hdc, oldFont], FFI_HND);
15544
+ ffi.ffiCall(ReleaseDC, [FFI_HND, FFI_HND], [hwnd, hdc], FFI_S32);
15544
15545
  const wr = gui2.GetWindowRect(hwnd);
15545
15546
  const cr = gui2.GetClientRect(hwnd);
15546
15547
  if (wr && cr) {
@@ -15853,10 +15854,10 @@ var hostConfig = {
15853
15854
  clearContainer(_container) {
15854
15855
  },
15855
15856
  scheduleTimeout(fn, delay) {
15856
- return os.setTimeout(fn, delay);
15857
+ return os2.setTimeout(fn, delay);
15857
15858
  },
15858
15859
  cancelTimeout(id) {
15859
- os.clearTimeout?.(id);
15860
+ os2.clearTimeout?.(id);
15860
15861
  },
15861
15862
  noTimeout: -1,
15862
15863
  supportsMutation: true,
@@ -0,0 +1,104 @@
1
+ import * as std from 'std';
2
+ import * as gui from 'gui';
3
+ import * as win from 'win';
4
+ import * as ffi from 'ffi';
5
+ const user32 = win.LoadLibrary('user32.dll');
6
+ if (!user32) {
7
+ print('LoadLibrary user32 failed');
8
+ std.exit(1);
9
+ }
10
+ function loadProc(lib, name) {
11
+ const ptr = win.GetProcAddress(lib, name);
12
+ if (!ptr) {
13
+ print('GetProcAddress ' + name + ' failed');
14
+ std.exit(1);
15
+ }
16
+ return ptr;
17
+ }
18
+ const EnumDisplaySettingsA = loadProc(user32, 'EnumDisplaySettingsA');
19
+ const ChangeDisplaySettingsA = loadProc(user32, 'ChangeDisplaySettingsA');
20
+ /** DEVMODEA used by EnumDisplaySettings; driver reports actual dmSize (often 124). */
21
+ const DEVMODE_SIZE = 220;
22
+ const DM_PELSWIDTH = 0x00800000;
23
+ const DM_PELSHEIGHT = 0x01000000;
24
+ const ENUM_CURRENT_SETTINGS = -1;
25
+ const CDS_UPDATEREGISTRY = 0x00000001;
26
+ const CDS_TEST = 0x00000002;
27
+ const DISP_CHANGE = {
28
+ 0: 'SUCCESSFUL',
29
+ 1: 'RESTART',
30
+ [-1]: 'FAILED',
31
+ [-2]: 'BADMODE',
32
+ [-3]: 'NOTUPDATED',
33
+ [-4]: 'BADFLAGS',
34
+ [-5]: 'BADPARAM',
35
+ [-6]: 'BADDUALVIEW',
36
+ };
37
+ function newDevMode() {
38
+ const buf = new ArrayBuffer(DEVMODE_SIZE);
39
+ new DataView(buf).setUint16(36, DEVMODE_SIZE, true);
40
+ return buf;
41
+ }
42
+ function enumMode(modeNum, buf) {
43
+ return ffi.ffiCall(EnumDisplaySettingsA, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_SINT32, ffi.FFI_TYPE_POINTER], [null, modeNum, buf], ffi.FFI_TYPE_SINT32);
44
+ }
45
+ function getPels(dv) {
46
+ return [dv.getUint32(108, true), dv.getUint32(112, true), dv.getUint32(120, true)];
47
+ }
48
+ function applyFromCurrent(w, h, flags, label) {
49
+ const dm = newDevMode();
50
+ if (!enumMode(ENUM_CURRENT_SETTINGS, dm)) {
51
+ print(label + ': EnumDisplaySettings CURRENT failed');
52
+ return null;
53
+ }
54
+ const dv = new DataView(dm);
55
+ const before = getPels(dv);
56
+ const size = dv.getUint16(36, true);
57
+ const extra = dv.getUint16(38, true);
58
+ const fields = dv.getUint32(40, true);
59
+ const bpp = dv.getUint32(104, true);
60
+ const freq = dv.getUint32(120, true);
61
+ print(label + ': base size=' + size + ' extra=' + extra + ' fields=0x' + fields.toString(16) +
62
+ ' ' + before[0] + 'x' + before[1] + '@' + freq + ' bpp=' + bpp);
63
+ dv.setUint32(40, fields | DM_PELSWIDTH | DM_PELSHEIGHT, true);
64
+ dv.setUint32(108, w, true);
65
+ dv.setUint32(112, h, true);
66
+ const ret = ffi.ffiCall(ChangeDisplaySettingsA, [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_UINT32], [dm, flags], ffi.FFI_TYPE_SINT32);
67
+ print(label + ': ChangeDisplaySettings ' + w + 'x' + h +
68
+ ' flags=0x' + flags.toString(16) + ' ret=' + ret + ' (' + (DISP_CHANGE[ret] ?? '?') + ')');
69
+ return ret;
70
+ }
71
+ const targetW = Number(scriptArgs[1] ?? '1024');
72
+ const targetH = Number(scriptArgs[2] ?? '768');
73
+ if (!Number.isFinite(targetW) || !Number.isFinite(targetH) || targetW <= 0 || targetH <= 0) {
74
+ print('usage: qwin.exe setres.js [width] [height]');
75
+ std.exit(1);
76
+ }
77
+ print('before GetScreenSize: ' + JSON.stringify(gui.GetScreenSize()));
78
+ const probe = newDevMode();
79
+ const modes32 = [];
80
+ for (let i = 0; i < 200; i++) {
81
+ if (!enumMode(i, probe))
82
+ break;
83
+ const dv = new DataView(probe);
84
+ if (dv.getUint32(104, true) !== 32)
85
+ continue;
86
+ const p = getPels(dv);
87
+ modes32.push(p[0] + 'x' + p[1] + '@' + p[2]);
88
+ }
89
+ print('32bpp modes sample: ' + modes32.slice(0, 25).join(', ') + (modes32.length > 25 ? ' ...' : ''));
90
+ const testRet = applyFromCurrent(targetW, targetH, CDS_TEST, 'TEST');
91
+ if (testRet === 0) {
92
+ applyFromCurrent(targetW, targetH, 0, 'DYNAMIC');
93
+ print('after dynamic GetScreenSize: ' + JSON.stringify(gui.GetScreenSize()));
94
+ applyFromCurrent(targetW, targetH, CDS_UPDATEREGISTRY, 'REGISTRY');
95
+ print('after registry GetScreenSize: ' + JSON.stringify(gui.GetScreenSize()));
96
+ }
97
+ else if (testRet !== null) {
98
+ print('target rejected; try 800x600');
99
+ const t2 = applyFromCurrent(800, 600, CDS_TEST, 'TEST800');
100
+ if (t2 === 0) {
101
+ applyFromCurrent(800, 600, 0, 'DYNAMIC800');
102
+ print('after 800x600 GetScreenSize: ' + JSON.stringify(gui.GetScreenSize()));
103
+ }
104
+ }
@@ -0,0 +1,120 @@
1
+ import * as std from 'std'
2
+ import * as gui from 'gui'
3
+ import * as win from 'win'
4
+ import * as ffi from 'ffi'
5
+
6
+ const user32 = win.LoadLibrary('user32.dll')
7
+ if (!user32) { print('LoadLibrary user32 failed'); std.exit(1) }
8
+
9
+ function loadProc(lib: win.HMODULE, name: string): number {
10
+ const ptr = win.GetProcAddress(lib, name)
11
+ if (!ptr) { print('GetProcAddress ' + name + ' failed'); std.exit(1) }
12
+ return ptr
13
+ }
14
+
15
+ const EnumDisplaySettingsA = loadProc(user32, 'EnumDisplaySettingsA')
16
+ const ChangeDisplaySettingsA = loadProc(user32, 'ChangeDisplaySettingsA')
17
+
18
+ /** DEVMODEA used by EnumDisplaySettings; driver reports actual dmSize (often 124). */
19
+ const DEVMODE_SIZE = 220
20
+ const DM_PELSWIDTH = 0x00800000
21
+ const DM_PELSHEIGHT = 0x01000000
22
+ const ENUM_CURRENT_SETTINGS = -1
23
+ const CDS_UPDATEREGISTRY = 0x00000001
24
+ const CDS_TEST = 0x00000002
25
+
26
+ const DISP_CHANGE: Record<number, string> = {
27
+ 0: 'SUCCESSFUL',
28
+ 1: 'RESTART',
29
+ [-1]: 'FAILED',
30
+ [-2]: 'BADMODE',
31
+ [-3]: 'NOTUPDATED',
32
+ [-4]: 'BADFLAGS',
33
+ [-5]: 'BADPARAM',
34
+ [-6]: 'BADDUALVIEW',
35
+ }
36
+
37
+ function newDevMode(): ArrayBuffer {
38
+ const buf = new ArrayBuffer(DEVMODE_SIZE)
39
+ new DataView(buf).setUint16(36, DEVMODE_SIZE, true)
40
+ return buf
41
+ }
42
+
43
+ function enumMode(modeNum: number, buf: ArrayBuffer): number {
44
+ return ffi.ffiCall(
45
+ EnumDisplaySettingsA,
46
+ [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_SINT32, ffi.FFI_TYPE_POINTER],
47
+ [null, modeNum, buf],
48
+ ffi.FFI_TYPE_SINT32,
49
+ )
50
+ }
51
+
52
+ function getPels(dv: DataView): [number, number, number] {
53
+ return [dv.getUint32(108, true), dv.getUint32(112, true), dv.getUint32(120, true)]
54
+ }
55
+
56
+ function applyFromCurrent(w: number, h: number, flags: number, label: string): number | null {
57
+ const dm = newDevMode()
58
+ if (!enumMode(ENUM_CURRENT_SETTINGS, dm)) {
59
+ print(label + ': EnumDisplaySettings CURRENT failed')
60
+ return null
61
+ }
62
+ const dv = new DataView(dm)
63
+ const before = getPels(dv)
64
+ const size = dv.getUint16(36, true)
65
+ const extra = dv.getUint16(38, true)
66
+ const fields = dv.getUint32(40, true)
67
+ const bpp = dv.getUint32(104, true)
68
+ const freq = dv.getUint32(120, true)
69
+ print(label + ': base size=' + size + ' extra=' + extra + ' fields=0x' + fields.toString(16) +
70
+ ' ' + before[0] + 'x' + before[1] + '@' + freq + ' bpp=' + bpp)
71
+
72
+ dv.setUint32(40, fields | DM_PELSWIDTH | DM_PELSHEIGHT, true)
73
+ dv.setUint32(108, w, true)
74
+ dv.setUint32(112, h, true)
75
+
76
+ const ret = ffi.ffiCall(
77
+ ChangeDisplaySettingsA,
78
+ [ffi.FFI_TYPE_POINTER, ffi.FFI_TYPE_UINT32],
79
+ [dm, flags],
80
+ ffi.FFI_TYPE_SINT32,
81
+ )
82
+ print(label + ': ChangeDisplaySettings ' + w + 'x' + h +
83
+ ' flags=0x' + flags.toString(16) + ' ret=' + ret + ' (' + (DISP_CHANGE[ret] ?? '?') + ')')
84
+ return ret
85
+ }
86
+
87
+ const targetW = Number(scriptArgs[1] ?? '1024')
88
+ const targetH = Number(scriptArgs[2] ?? '768')
89
+ if (!Number.isFinite(targetW) || !Number.isFinite(targetH) || targetW <= 0 || targetH <= 0) {
90
+ print('usage: qwin.exe setres.js [width] [height]')
91
+ std.exit(1)
92
+ }
93
+
94
+ print('before GetScreenSize: ' + JSON.stringify(gui.GetScreenSize()))
95
+
96
+ const probe = newDevMode()
97
+ const modes32: string[] = []
98
+ for (let i = 0; i < 200; i++) {
99
+ if (!enumMode(i, probe)) break
100
+ const dv = new DataView(probe)
101
+ if (dv.getUint32(104, true) !== 32) continue
102
+ const p = getPels(dv)
103
+ modes32.push(p[0] + 'x' + p[1] + '@' + p[2])
104
+ }
105
+ print('32bpp modes sample: ' + modes32.slice(0, 25).join(', ') + (modes32.length > 25 ? ' ...' : ''))
106
+
107
+ const testRet = applyFromCurrent(targetW, targetH, CDS_TEST, 'TEST')
108
+ if (testRet === 0) {
109
+ applyFromCurrent(targetW, targetH, 0, 'DYNAMIC')
110
+ print('after dynamic GetScreenSize: ' + JSON.stringify(gui.GetScreenSize()))
111
+ applyFromCurrent(targetW, targetH, CDS_UPDATEREGISTRY, 'REGISTRY')
112
+ print('after registry GetScreenSize: ' + JSON.stringify(gui.GetScreenSize()))
113
+ } else if (testRet !== null) {
114
+ print('target rejected; try 800x600')
115
+ const t2 = applyFromCurrent(800, 600, CDS_TEST, 'TEST800')
116
+ if (t2 === 0) {
117
+ applyFromCurrent(800, 600, 0, 'DYNAMIC800')
118
+ print('after 800x600 GetScreenSize: ' + JSON.stringify(gui.GetScreenSize()))
119
+ }
120
+ }
@@ -15367,7 +15367,7 @@ var import_react_reconciler = __toESM(require_react_reconciler(), 1);
15367
15367
  var import_react = __toESM(require_react(), 1);
15368
15368
  var import_constants = __toESM(require_constants(), 1);
15369
15369
  import * as gui3 from "gui";
15370
- import * as os from "os";
15370
+ import * as os2 from "os";
15371
15371
 
15372
15372
  // _build/lib/react-qw/props.js
15373
15373
  import * as gui from "gui";
@@ -15488,6 +15488,7 @@ function calculateFlexLayout(flex, parentW, parentH, children) {
15488
15488
 
15489
15489
  // _build/lib/text-measure.js
15490
15490
  import * as ffi from "ffi";
15491
+ import * as os from "os";
15491
15492
  import * as win from "win";
15492
15493
  import * as gui2 from "gui";
15493
15494
  function loadProc(lib, name) {
@@ -15504,7 +15505,7 @@ var DrawTextW = loadProc(user32, "DrawTextW");
15504
15505
  var GetDC = loadProc(user32, "GetDC");
15505
15506
  var ReleaseDC = loadProc(user32, "ReleaseDC");
15506
15507
  var SelectObject = loadProc(gdi32, "SelectObject");
15507
- var FFI_TYPE_UINT642 = ffi.FFI_TYPE_UINT64;
15508
+ var FFI_HND = os.arch === "ia32" ? ffi.FFI_TYPE_UINT32 : ffi.FFI_TYPE_UINT64;
15508
15509
  var FFI_S32 = ffi.FFI_TYPE_SINT32;
15509
15510
  var FFI_PTR = ffi.FFI_TYPE_POINTER;
15510
15511
  function measureText(hdc, text, maxWidth) {
@@ -15512,14 +15513,14 @@ function measureText(hdc, text, maxWidth) {
15512
15513
  const rect = new ArrayBuffer(16);
15513
15514
  const dv = new DataView(rect);
15514
15515
  dv.setInt32(8, maxWidth, true);
15515
- ffi.ffiCall(DrawTextW, [FFI_TYPE_UINT642, FFI_PTR, FFI_S32, FFI_PTR, FFI_S32], [
15516
+ ffi.ffiCall(DrawTextW, [FFI_HND, FFI_PTR, FFI_S32, FFI_PTR, FFI_S32], [
15516
15517
  hdc,
15517
15518
  textBuf,
15518
15519
  -1,
15519
15520
  rect,
15520
15521
  1024
15521
15522
  /* gui.DrawTextFlag.CALCRECT */
15522
- ], FFI_TYPE_UINT642);
15523
+ ], FFI_S32);
15523
15524
  return { width: dv.getInt32(8, true), height: dv.getInt32(12, true) };
15524
15525
  }
15525
15526
  function getButtonIdealSize(hwnd2) {
@@ -15529,15 +15530,15 @@ function getButtonIdealSize(hwnd2) {
15529
15530
  return { width: dv.getInt32(0, true), height: dv.getInt32(4, true) };
15530
15531
  }
15531
15532
  function measureTextForHwnd(hwnd2, text) {
15532
- const hdc = ffi.ffiCall(GetDC, [FFI_TYPE_UINT642], [hwnd2], FFI_TYPE_UINT642);
15533
+ const hdc = ffi.ffiCall(GetDC, [FFI_HND], [hwnd2], FFI_HND);
15533
15534
  if (!hdc)
15534
15535
  return { width: 0, height: 0 };
15535
15536
  const hFont = gui2.SendMessage(hwnd2, 49, 0, 0);
15536
- const oldFont = hFont ? ffi.ffiCall(SelectObject, [FFI_TYPE_UINT642, FFI_TYPE_UINT642], [hdc, hFont], FFI_TYPE_UINT642) : 0;
15537
+ const oldFont = hFont ? ffi.ffiCall(SelectObject, [FFI_HND, FFI_HND], [hdc, hFont], FFI_HND) : 0;
15537
15538
  const result = measureText(hdc, text, 0);
15538
15539
  if (hFont)
15539
- ffi.ffiCall(SelectObject, [FFI_TYPE_UINT642, FFI_TYPE_UINT642], [hdc, oldFont], FFI_TYPE_UINT642);
15540
- ffi.ffiCall(ReleaseDC, [FFI_TYPE_UINT642, FFI_TYPE_UINT642], [hwnd2, hdc], FFI_S32);
15540
+ ffi.ffiCall(SelectObject, [FFI_HND, FFI_HND], [hdc, oldFont], FFI_HND);
15541
+ ffi.ffiCall(ReleaseDC, [FFI_HND, FFI_HND], [hwnd2, hdc], FFI_S32);
15541
15542
  const wr = gui2.GetWindowRect(hwnd2);
15542
15543
  const cr = gui2.GetClientRect(hwnd2);
15543
15544
  if (wr && cr) {
@@ -15850,10 +15851,10 @@ var hostConfig = {
15850
15851
  clearContainer(_container) {
15851
15852
  },
15852
15853
  scheduleTimeout(fn, delay) {
15853
- return os.setTimeout(fn, delay);
15854
+ return os2.setTimeout(fn, delay);
15854
15855
  },
15855
15856
  cancelTimeout(id) {
15856
- os.clearTimeout?.(id);
15857
+ os2.clearTimeout?.(id);
15857
15858
  },
15858
15859
  noTimeout: -1,
15859
15860
  supportsMutation: true,
@@ -15367,7 +15367,7 @@ var import_react_reconciler = __toESM(require_react_reconciler(), 1);
15367
15367
  var import_react = __toESM(require_react(), 1);
15368
15368
  var import_constants = __toESM(require_constants(), 1);
15369
15369
  import * as gui3 from "gui";
15370
- import * as os from "os";
15370
+ import * as os2 from "os";
15371
15371
 
15372
15372
  // _build/lib/react-qw/props.js
15373
15373
  import * as gui from "gui";
@@ -15488,6 +15488,7 @@ function calculateFlexLayout(flex, parentW, parentH, children) {
15488
15488
 
15489
15489
  // _build/lib/text-measure.js
15490
15490
  import * as ffi from "ffi";
15491
+ import * as os from "os";
15491
15492
  import * as win from "win";
15492
15493
  import * as gui2 from "gui";
15493
15494
  function loadProc(lib, name) {
@@ -15504,7 +15505,7 @@ var DrawTextW = loadProc(user32, "DrawTextW");
15504
15505
  var GetDC = loadProc(user32, "GetDC");
15505
15506
  var ReleaseDC = loadProc(user32, "ReleaseDC");
15506
15507
  var SelectObject = loadProc(gdi32, "SelectObject");
15507
- var FFI_TYPE_UINT642 = ffi.FFI_TYPE_UINT64;
15508
+ var FFI_HND = os.arch === "ia32" ? ffi.FFI_TYPE_UINT32 : ffi.FFI_TYPE_UINT64;
15508
15509
  var FFI_S32 = ffi.FFI_TYPE_SINT32;
15509
15510
  var FFI_PTR = ffi.FFI_TYPE_POINTER;
15510
15511
  function measureText(hdc, text, maxWidth) {
@@ -15512,14 +15513,14 @@ function measureText(hdc, text, maxWidth) {
15512
15513
  const rect = new ArrayBuffer(16);
15513
15514
  const dv = new DataView(rect);
15514
15515
  dv.setInt32(8, maxWidth, true);
15515
- ffi.ffiCall(DrawTextW, [FFI_TYPE_UINT642, FFI_PTR, FFI_S32, FFI_PTR, FFI_S32], [
15516
+ ffi.ffiCall(DrawTextW, [FFI_HND, FFI_PTR, FFI_S32, FFI_PTR, FFI_S32], [
15516
15517
  hdc,
15517
15518
  textBuf,
15518
15519
  -1,
15519
15520
  rect,
15520
15521
  1024
15521
15522
  /* gui.DrawTextFlag.CALCRECT */
15522
- ], FFI_TYPE_UINT642);
15523
+ ], FFI_S32);
15523
15524
  return { width: dv.getInt32(8, true), height: dv.getInt32(12, true) };
15524
15525
  }
15525
15526
  function getButtonIdealSize(hwnd2) {
@@ -15529,15 +15530,15 @@ function getButtonIdealSize(hwnd2) {
15529
15530
  return { width: dv.getInt32(0, true), height: dv.getInt32(4, true) };
15530
15531
  }
15531
15532
  function measureTextForHwnd(hwnd2, text) {
15532
- const hdc = ffi.ffiCall(GetDC, [FFI_TYPE_UINT642], [hwnd2], FFI_TYPE_UINT642);
15533
+ const hdc = ffi.ffiCall(GetDC, [FFI_HND], [hwnd2], FFI_HND);
15533
15534
  if (!hdc)
15534
15535
  return { width: 0, height: 0 };
15535
15536
  const hFont = gui2.SendMessage(hwnd2, 49, 0, 0);
15536
- const oldFont = hFont ? ffi.ffiCall(SelectObject, [FFI_TYPE_UINT642, FFI_TYPE_UINT642], [hdc, hFont], FFI_TYPE_UINT642) : 0;
15537
+ const oldFont = hFont ? ffi.ffiCall(SelectObject, [FFI_HND, FFI_HND], [hdc, hFont], FFI_HND) : 0;
15537
15538
  const result = measureText(hdc, text, 0);
15538
15539
  if (hFont)
15539
- ffi.ffiCall(SelectObject, [FFI_TYPE_UINT642, FFI_TYPE_UINT642], [hdc, oldFont], FFI_TYPE_UINT642);
15540
- ffi.ffiCall(ReleaseDC, [FFI_TYPE_UINT642, FFI_TYPE_UINT642], [hwnd2, hdc], FFI_S32);
15540
+ ffi.ffiCall(SelectObject, [FFI_HND, FFI_HND], [hdc, oldFont], FFI_HND);
15541
+ ffi.ffiCall(ReleaseDC, [FFI_HND, FFI_HND], [hwnd2, hdc], FFI_S32);
15541
15542
  const wr = gui2.GetWindowRect(hwnd2);
15542
15543
  const cr = gui2.GetClientRect(hwnd2);
15543
15544
  if (wr && cr) {
@@ -15850,10 +15851,10 @@ var hostConfig = {
15850
15851
  clearContainer(_container) {
15851
15852
  },
15852
15853
  scheduleTimeout(fn, delay) {
15853
- return os.setTimeout(fn, delay);
15854
+ return os2.setTimeout(fn, delay);
15854
15855
  },
15855
15856
  cancelTimeout(id) {
15856
- os.clearTimeout?.(id);
15857
+ os2.clearTimeout?.(id);
15857
15858
  },
15858
15859
  noTimeout: -1,
15859
15860
  supportsMutation: true,