swing-ui 1.2.0 → 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.
- package/SwingUI.js +129 -234
- package/classes/PasswordField.js +1 -1
- package/icon.png +0 -0
- package/index.js +2 -9
- package/jar/gui-11.jar +0 -0
- package/package.json +2 -4
- package/types/classes/Ellipse.d.ts +9 -0
- package/types/classes/PasswordField.d.ts +1 -1
- package/types/classes/Rectangle.d.ts +9 -0
- package/types/classes/Window.d.ts +3 -3
- package/types/typedefs.d.ts +25 -9
- package/ui-process-manager.js +1 -1
package/SwingUI.js
CHANGED
|
@@ -41,14 +41,12 @@ export class SwingUI
|
|
|
41
41
|
#_msg_queue = [];
|
|
42
42
|
#queue_limit = 100; // send queued messages after queue size reaches this limit (0 = no message queue)
|
|
43
43
|
#msgCompressThreshold = 1000; // compress messages longer than this
|
|
44
|
-
#textDecoder = new TextDecoder("utf8");
|
|
45
44
|
|
|
46
45
|
#jvm = {
|
|
47
46
|
stdio: {}, JBridge: null, process: null, eventListener: e =>
|
|
48
47
|
{
|
|
49
48
|
}
|
|
50
49
|
};
|
|
51
|
-
#guiManagerWorker = null; // for GUI Process manager worker
|
|
52
50
|
#exiting = false;
|
|
53
51
|
|
|
54
52
|
/**
|
|
@@ -88,9 +86,9 @@ export class SwingUI
|
|
|
88
86
|
11: "Failed to set menu menu. Passed parameter must be of type MenuBar()"
|
|
89
87
|
};
|
|
90
88
|
|
|
91
|
-
//region For Worker IPC
|
|
89
|
+
//region For Worker IPC
|
|
92
90
|
|
|
93
|
-
#
|
|
91
|
+
#guiManagerWorker = null;
|
|
94
92
|
#worker_port1 = null;
|
|
95
93
|
#worker_port2 = null;
|
|
96
94
|
|
|
@@ -156,21 +154,15 @@ export class SwingUI
|
|
|
156
154
|
}
|
|
157
155
|
}();
|
|
158
156
|
|
|
159
|
-
/**
|
|
160
|
-
* Detects best compatible base64 decoder
|
|
161
|
-
*/
|
|
162
|
-
#decodeBase64 = typeof Uint8Array.fromBase64 === 'function' ? b64 => Uint8Array.fromBase64(b64) : typeof Buffer !== 'undefined' ? b64 => Buffer.from(b64, 'base64') : b64 => Uint8Array.from(atob(b64), c => c.charCodeAt(0));
|
|
163
|
-
|
|
164
157
|
//region Internal
|
|
165
158
|
|
|
166
159
|
/**
|
|
167
160
|
* <b>NOTE:</b> Do not instantiate this class. It's already instantiated and assigned to a global variable `ui`.
|
|
168
161
|
* @internal
|
|
169
162
|
*/
|
|
170
|
-
constructor(module_dir
|
|
163
|
+
constructor(module_dir)
|
|
171
164
|
{
|
|
172
165
|
this.#module_dir = module_dir;
|
|
173
|
-
this.#jvm.JBridge = JBridge;
|
|
174
166
|
this.rootDirectory; // detect project dir now
|
|
175
167
|
|
|
176
168
|
// ensure cleanup
|
|
@@ -189,192 +181,102 @@ export class SwingUI
|
|
|
189
181
|
*/
|
|
190
182
|
async InitGUIProcess()
|
|
191
183
|
{
|
|
192
|
-
if(this.runtime === "bun" || this.os === "darwin") this.#useWorkerThread = true;
|
|
193
|
-
|
|
194
184
|
const env = this.env;
|
|
195
185
|
|
|
196
186
|
if(process.argv.some(arg => arg.startsWith("--java-dir="))) env.JAVA_HOME = process.argv.find(arg => arg.startsWith("--java-dir=")).split("=")[1];
|
|
197
187
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
env: env
|
|
228
|
-
};
|
|
188
|
+
this.#msgCompressThreshold = 500; // reduce the threshold
|
|
189
|
+
|
|
190
|
+
const {port1, port2} = new MessageChannel();
|
|
191
|
+
this.#worker_port1 = port1;
|
|
192
|
+
this.#worker_port2 = port2;
|
|
193
|
+
|
|
194
|
+
// start IPC Worker
|
|
195
|
+
const workerPath = path.join(this.#module_dir, "ui-process-manager.js");
|
|
196
|
+
|
|
197
|
+
// set a value for the thread to wait for the worker to start
|
|
198
|
+
Atomics.store(this.#sharedBuffSignal, SwingUI.WorkerSignalIndex.ExecutionControl, SwingUI.WorkerSignal.Block);
|
|
199
|
+
|
|
200
|
+
const options = {
|
|
201
|
+
type: "module",
|
|
202
|
+
workerData: {
|
|
203
|
+
signalBuffer: this.#sharedBuffSignal,
|
|
204
|
+
responsePort: this.#worker_port2,
|
|
205
|
+
moduleDir: this.#module_dir,
|
|
206
|
+
rootDir: this.rootDirectory,
|
|
207
|
+
debugJava: process.argv.some(arg => arg === "--debug-java"),
|
|
208
|
+
verbose: process.argv.some(arg => arg === "--v"),
|
|
209
|
+
os: this.os,
|
|
210
|
+
runtime: this.runtime
|
|
211
|
+
},
|
|
212
|
+
transferList: [this.#worker_port2],
|
|
213
|
+
stdout: true,
|
|
214
|
+
stderr: true,
|
|
215
|
+
env: env
|
|
216
|
+
};
|
|
229
217
|
|
|
230
|
-
|
|
218
|
+
this.#guiManagerWorker = new Worker(workerPath, options);
|
|
231
219
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
220
|
+
// forward worker logs to the main process
|
|
221
|
+
if(this.#guiManagerWorker.stdout != null) // e.g.. bun, and deno on macOS don't have stdout
|
|
222
|
+
{
|
|
223
|
+
this.#guiManagerWorker.stdout.on("data", chunk => console.log(chunk.toString()));
|
|
224
|
+
this.#guiManagerWorker.stderr.on("data", chunk => console.error(chunk.toString()));
|
|
225
|
+
}
|
|
238
226
|
|
|
239
|
-
|
|
227
|
+
this.#guiManagerWorker.on("message", (msg) =>
|
|
228
|
+
{
|
|
229
|
+
switch(msg.type)
|
|
240
230
|
{
|
|
241
|
-
|
|
231
|
+
case "data":
|
|
242
232
|
{
|
|
243
|
-
|
|
244
|
-
{
|
|
245
|
-
|
|
246
|
-
if(this.#inputLinesBuffer.length < 2) queueMicrotask(() => {this.#processInputData();});
|
|
247
|
-
break;
|
|
248
|
-
}
|
|
249
|
-
case "exit":
|
|
250
|
-
{
|
|
251
|
-
this.exit(0);
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
case "worker_log":
|
|
255
|
-
{
|
|
256
|
-
console.log(`WORKER THREAD: ${msg.data}`);
|
|
257
|
-
break;
|
|
258
|
-
}
|
|
259
|
-
case "worker_debug":
|
|
260
|
-
{
|
|
261
|
-
console.debug(`WORKER THREAD: ${msg.data}`);
|
|
262
|
-
break;
|
|
263
|
-
}
|
|
264
|
-
case "worker_warn":
|
|
265
|
-
{
|
|
266
|
-
console.warn(`WORKER THREAD: ${msg.data}`);
|
|
267
|
-
break;
|
|
268
|
-
}
|
|
269
|
-
case "worker_info":
|
|
270
|
-
{
|
|
271
|
-
console.info(`WORKER THREAD: ${msg.data}`);
|
|
272
|
-
break;
|
|
273
|
-
}
|
|
274
|
-
case "worker_error":
|
|
275
|
-
{
|
|
276
|
-
console.error(`WORKER THREAD ERROR: ${msg.data}`);
|
|
277
|
-
break;
|
|
278
|
-
}
|
|
233
|
+
this.#inputLinesBuffer.push(msg.data);
|
|
234
|
+
if(this.#inputLinesBuffer.length < 2) queueMicrotask(() => {this.#processInputData();});
|
|
235
|
+
break;
|
|
279
236
|
}
|
|
280
|
-
|
|
281
|
-
this.#guiManagerWorker.on("online", () => {});
|
|
282
|
-
this.#guiManagerWorker.on("error", (err) => console.error("[SwingUI] GUI Worker error:", err));
|
|
283
|
-
this.#guiManagerWorker.on("exit", (code) =>
|
|
284
|
-
{
|
|
285
|
-
if(!this.#exiting && code !== 0) console.error(`[SwingUI] GUI Worker stopped unexpectedly (exit code ${code})`);
|
|
286
|
-
this.exit(code);
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
// wait for the worker to start
|
|
290
|
-
const r = Atomics.wait(this.#sharedBuffSignal, SwingUI.WorkerSignalIndex.ExecutionControl, SwingUI.WorkerSignal.Block, 10000);
|
|
291
|
-
if(r === "timed-out") throw new Error("Failed to start GUI Worker: timeout.");
|
|
292
|
-
}
|
|
293
|
-
else
|
|
294
|
-
{
|
|
295
|
-
const jvmOpts = {opts: [], env: env};
|
|
296
|
-
if(process.argv.some(arg => arg === "--debug-java")) jvmOpts.opts.push("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005");
|
|
297
|
-
if(this.os === "linux") jvmOpts.opts.push("--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED"); // to be able to set WM_CLASS in Java GUI
|
|
298
|
-
if(this.os === "darwin")
|
|
299
|
-
{
|
|
300
|
-
jvmOpts.opts.push("-Dapple.awt.UIElement=true");
|
|
301
|
-
jvmOpts.opts.push("-Dapple.awt.headless=false"); // was supposed to help JVM on macOS, but didn't. macOS doesn't allow GUI on non-main thread.
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
this.#jvm.JBridge.ensureJvm(jvmOpts);
|
|
305
|
-
this.#jvm.JBridge.appendClasspath(path.join(this.#module_dir, "jar/gui-11.jar"));
|
|
306
|
-
const JBridgeProcessHandle = this.#jvm.JBridge.importClass("java.lang.ProcessHandle");
|
|
307
|
-
this.#jvm.process = await JBridgeProcessHandle.current();
|
|
308
|
-
this.gui_process_id = Number(await this.#jvm.process.pid());
|
|
309
|
-
|
|
310
|
-
// receive events from GUI
|
|
311
|
-
this.#jvm.stdio.stdout = (_, line) =>
|
|
312
|
-
{
|
|
313
|
-
line = line.trim();
|
|
314
|
-
if(!line) return;
|
|
315
|
-
|
|
316
|
-
if(line.startsWith("GUI-EVENT->"))
|
|
237
|
+
case "exit":
|
|
317
238
|
{
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const message = this.#textDecoder.decode(this.#decodeBase64(line.substring(11)));
|
|
321
|
-
this.#inputLinesBuffer.push(message);
|
|
322
|
-
}catch(ex)
|
|
323
|
-
{
|
|
324
|
-
console.error("Failed to parse IPC event:", ex);
|
|
325
|
-
}
|
|
239
|
+
this.exit(0);
|
|
240
|
+
break;
|
|
326
241
|
}
|
|
327
|
-
|
|
242
|
+
case "worker_log":
|
|
328
243
|
{
|
|
329
|
-
console.log(
|
|
244
|
+
console.log(`WORKER THREAD: ${msg.data}`);
|
|
245
|
+
break;
|
|
330
246
|
}
|
|
331
|
-
|
|
332
|
-
this.#processInputData();
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
this.#jvm.stdio.stderr = (_, data) =>
|
|
336
|
-
{
|
|
337
|
-
console.error(data);
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
// enable STDIO redirect to our handlers
|
|
341
|
-
this.#jvm.stdio.guard = this.#jvm.JBridge.stdout.enableRedirect(this.#jvm.stdio.stdout, this.#jvm.stdio.stderr);
|
|
342
|
-
|
|
343
|
-
/*
|
|
344
|
-
this.#jvm.eventListener = this.#jvm.JBridge.newProxy("SwingUI$Callback", {
|
|
345
|
-
eventCall: data =>
|
|
247
|
+
case "worker_debug":
|
|
346
248
|
{
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
data = this.#textDecoder.decode(this.#decodeBase64(data));
|
|
350
|
-
|
|
351
|
-
this.#inputLinesBuffer.push(data);
|
|
249
|
+
console.debug(`WORKER THREAD: ${msg.data}`);
|
|
250
|
+
break;
|
|
352
251
|
}
|
|
353
|
-
|
|
354
|
-
*/
|
|
355
|
-
|
|
356
|
-
const ui_class = this.#jvm.JBridge.importClass("SwingUI");
|
|
357
|
-
const ops = JSON.stringify({
|
|
358
|
-
module_dir: this.#module_dir,
|
|
359
|
-
root_dir: this.rootDirectory,
|
|
360
|
-
verbose: process.argv.some(arg => arg === "--v")
|
|
361
|
-
});
|
|
362
|
-
this.#jvm.gui = new ui_class(ops);
|
|
363
|
-
//await this.#jvm.gui.setEventCallback(this.#jvm.eventListener);
|
|
364
|
-
|
|
365
|
-
// Watchdog
|
|
366
|
-
this.#watchdog_timer = setInterval(() =>
|
|
367
|
-
{
|
|
368
|
-
try
|
|
252
|
+
case "worker_warn":
|
|
369
253
|
{
|
|
370
|
-
|
|
371
|
-
|
|
254
|
+
console.warn(`WORKER THREAD: ${msg.data}`);
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
case "worker_info":
|
|
372
258
|
{
|
|
373
|
-
console.
|
|
374
|
-
|
|
259
|
+
console.info(`WORKER THREAD: ${msg.data}`);
|
|
260
|
+
break;
|
|
375
261
|
}
|
|
376
|
-
|
|
377
|
-
|
|
262
|
+
case "worker_error":
|
|
263
|
+
{
|
|
264
|
+
console.error(`WORKER THREAD ERROR: ${msg.data}`);
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
this.#guiManagerWorker.on("online", () => {});
|
|
270
|
+
this.#guiManagerWorker.on("error", (err) => console.error("[SwingUI] GUI Worker error:", err));
|
|
271
|
+
this.#guiManagerWorker.on("exit", (code) =>
|
|
272
|
+
{
|
|
273
|
+
if(!this.#exiting && code !== 0) console.error(`[SwingUI] GUI Worker stopped unexpectedly (exit code ${code})`);
|
|
274
|
+
this.exit(code);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// wait for the worker to start
|
|
278
|
+
const r = Atomics.wait(this.#sharedBuffSignal, SwingUI.WorkerSignalIndex.ExecutionControl, SwingUI.WorkerSignal.Block, 10000);
|
|
279
|
+
if(r === "timed-out") throw new Error("Failed to start GUI Worker: timeout.");
|
|
378
280
|
|
|
379
281
|
// report current version of this module to UI
|
|
380
282
|
this.sendToGUI({system: "version", value: this.#gui_version, pid: this.pid}, async r =>
|
|
@@ -417,16 +319,6 @@ export class SwingUI
|
|
|
417
319
|
{
|
|
418
320
|
if(typeof msg !== "string" || msg.length === 0) return null;
|
|
419
321
|
|
|
420
|
-
/*try
|
|
421
|
-
{
|
|
422
|
-
msg = decodeURIComponent(msg).trim();
|
|
423
|
-
}catch(ex)
|
|
424
|
-
{
|
|
425
|
-
console.error(this._msg[9] + msg + "\n\n" + ex.stack);
|
|
426
|
-
console.error(ex);
|
|
427
|
-
return null;
|
|
428
|
-
}*/
|
|
429
|
-
|
|
430
322
|
if(msg.startsWith("{") && msg.endsWith("}"))
|
|
431
323
|
{
|
|
432
324
|
try
|
|
@@ -707,13 +599,7 @@ export class SwingUI
|
|
|
707
599
|
sendToGUI(msg, callback = null)
|
|
708
600
|
{
|
|
709
601
|
// create default callback for "get" messages
|
|
710
|
-
if(callback === null && msg.get !== undefined)
|
|
711
|
-
{
|
|
712
|
-
callback = r =>
|
|
713
|
-
{
|
|
714
|
-
return r.value;
|
|
715
|
-
};
|
|
716
|
-
}
|
|
602
|
+
if(callback === null && msg.get !== undefined) callback = r => r.value;
|
|
717
603
|
|
|
718
604
|
// If no callback is needed, then we can stack up messages and send them together
|
|
719
605
|
if(callback != null)
|
|
@@ -721,20 +607,10 @@ export class SwingUI
|
|
|
721
607
|
// Send accumulated messages first
|
|
722
608
|
this.sendMessageQueue();
|
|
723
609
|
|
|
724
|
-
let msgs = JSON.stringify(
|
|
610
|
+
let msgs = '[' + JSON.stringify(msg) + ']';
|
|
725
611
|
this.stats.out += msgs.length;
|
|
726
612
|
|
|
727
|
-
let response;
|
|
728
|
-
|
|
729
|
-
if(this.#useWorkerThread)
|
|
730
|
-
{
|
|
731
|
-
response = this.#sendMessagesViaWorker("b64:" + Buffer.from(msgs, "utf-8").toString("base64"), true);
|
|
732
|
-
}
|
|
733
|
-
else
|
|
734
|
-
{
|
|
735
|
-
response = this.#jvm.gui.receiveDirectMessagesSync("b64:" + Buffer.from(msgs, "utf-8").toString("base64"));
|
|
736
|
-
if(response != null) response = this.#textDecoder.decode(this.#decodeBase64(response));
|
|
737
|
-
}
|
|
613
|
+
let response = this.#sendMessagesViaWorker("b64:" + Buffer.from(msgs, "utf-8").toString("base64"), true);
|
|
738
614
|
|
|
739
615
|
if(response != null && typeof response === "string") response = JSON.parse(response);
|
|
740
616
|
|
|
@@ -748,7 +624,7 @@ export class SwingUI
|
|
|
748
624
|
}
|
|
749
625
|
else
|
|
750
626
|
{
|
|
751
|
-
this.#_msg_queue.push(
|
|
627
|
+
this.#_msg_queue.push(JSON.stringify(msg)); // stringify already to preserve values in case they change before we send the message to GUI
|
|
752
628
|
|
|
753
629
|
if(this.#_msg_queue.length >= this.#queue_limit)
|
|
754
630
|
{
|
|
@@ -782,7 +658,8 @@ export class SwingUI
|
|
|
782
658
|
{
|
|
783
659
|
if(this.#_msg_queue.length < 1) return this;
|
|
784
660
|
|
|
785
|
-
let msgs = JSON.stringify(this.#_msg_queue);
|
|
661
|
+
//let msgs = JSON.stringify(this.#_msg_queue);
|
|
662
|
+
let msgs = '[' + this.#_msg_queue.join(",") + ']';
|
|
786
663
|
|
|
787
664
|
// compress messages if more than one message and long enough
|
|
788
665
|
if(compress && this.#_msg_queue.length > 1 && msgs.length > this.#msgCompressThreshold)
|
|
@@ -800,18 +677,7 @@ export class SwingUI
|
|
|
800
677
|
this.stats.out += msgs.length;
|
|
801
678
|
this.#_msg_queue = []; // clear queue
|
|
802
679
|
|
|
803
|
-
|
|
804
|
-
{
|
|
805
|
-
this.#sendMessagesViaWorker(msgs, false);
|
|
806
|
-
}
|
|
807
|
-
else if(this.#exiting) // when exiting, don't wait for response
|
|
808
|
-
{
|
|
809
|
-
this.#jvm.gui.receiveDirectMessages(msgs);
|
|
810
|
-
}
|
|
811
|
-
else
|
|
812
|
-
{
|
|
813
|
-
this.#jvm.gui.receiveDirectMessagesSync(msgs);
|
|
814
|
-
}
|
|
680
|
+
this.#sendMessagesViaWorker(msgs, false);
|
|
815
681
|
|
|
816
682
|
return this;
|
|
817
683
|
}
|
|
@@ -832,6 +698,48 @@ export class SwingUI
|
|
|
832
698
|
}
|
|
833
699
|
}
|
|
834
700
|
|
|
701
|
+
/**
|
|
702
|
+
* Detect java-bridge compatibility with the current environment.
|
|
703
|
+
*/
|
|
704
|
+
#JavaBridgeSupported()
|
|
705
|
+
{
|
|
706
|
+
const support = {
|
|
707
|
+
windows: {
|
|
708
|
+
node: true,
|
|
709
|
+
deno: true
|
|
710
|
+
},
|
|
711
|
+
linux: {
|
|
712
|
+
node: true,
|
|
713
|
+
deno: false // on Linux java-bridge 2.8.1 has error: "TypeError: java.linux-x64-gnu.node: undefined symbol: uv_run"
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
const os = this.os;
|
|
718
|
+
|
|
719
|
+
if(support[os] === undefined) return false;
|
|
720
|
+
if(support[os][this.runtime] !== true) return false;
|
|
721
|
+
|
|
722
|
+
const arch = this.runtime === "deno" ? Deno.build.arch : globalThis.process?.arch;
|
|
723
|
+
|
|
724
|
+
// Normalize architecture
|
|
725
|
+
const archMap = {
|
|
726
|
+
x86_64: "x64",
|
|
727
|
+
aarch64: "arm64",
|
|
728
|
+
ia32: "x86"
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
const normalizedArch = archMap[arch] || arch;
|
|
732
|
+
|
|
733
|
+
// Platform and architecture support
|
|
734
|
+
const supported = {
|
|
735
|
+
windows: ["x86", "x64"],
|
|
736
|
+
linux: ["x64", "arm64"],
|
|
737
|
+
//darwin: ["x64", "arm64"] // macOS doesn't support UI on not main thread
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
return supported[os]?.includes(normalizedArch) || false;
|
|
741
|
+
}
|
|
742
|
+
|
|
835
743
|
//endregion
|
|
836
744
|
|
|
837
745
|
//region read-only Getters
|
|
@@ -1530,19 +1438,6 @@ export class SwingUI
|
|
|
1530
1438
|
{
|
|
1531
1439
|
this.sendToGUI({java: "exit", code: exitCode});
|
|
1532
1440
|
|
|
1533
|
-
try
|
|
1534
|
-
{
|
|
1535
|
-
//this.#jvm.eventListener.reset();
|
|
1536
|
-
}catch(_)
|
|
1537
|
-
{
|
|
1538
|
-
}
|
|
1539
|
-
try
|
|
1540
|
-
{
|
|
1541
|
-
this.#jvm.stdio.guard.release();
|
|
1542
|
-
}catch(_)
|
|
1543
|
-
{
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
1441
|
setTimeout(() =>
|
|
1547
1442
|
{
|
|
1548
1443
|
if(this.#guiManagerWorker != null)
|
package/classes/PasswordField.js
CHANGED
|
@@ -37,7 +37,7 @@ export class PasswordField extends TextComponent
|
|
|
37
37
|
* const myChar = '\u25CF';
|
|
38
38
|
* const myChar = '\u2B24';
|
|
39
39
|
*
|
|
40
|
-
* @param {string} [character] - A one character string
|
|
40
|
+
* @param {string} [character] - A one character string. If the string has more than one character, only first one will be used.
|
|
41
41
|
* @returns {PasswordField|string} Returns an instance of `this` object when setting a value, otherwise current value is returned.
|
|
42
42
|
*/
|
|
43
43
|
echoChar(...args)
|
package/icon.png
CHANGED
|
Binary file
|
package/index.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* swing-ui GUI for JavaScript, such as Node.js, Bun, Deno 2.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import fs from "fs";
|
|
6
6
|
import path from "path";
|
|
7
7
|
|
|
8
|
-
import JBridge from "java-bridge";
|
|
9
|
-
|
|
10
8
|
// show if debugger options were set
|
|
11
9
|
if(process.execArgv.some(arg => arg.startsWith("--inspect"))) console.log("JavaScript Debugger option is set.");
|
|
12
10
|
|
|
@@ -17,11 +15,6 @@ const __dirname = import.meta.dirname ?? import.meta.dir ?? path.dirname((await
|
|
|
17
15
|
|
|
18
16
|
// Dynamically assign each function to globalThis
|
|
19
17
|
import * as functions from "./functions.js"; // Import all functions from functions.js
|
|
20
|
-
if(typeof structuredClone !== "function") // add structuredClone() function in case it doesn't exist (node <17)
|
|
21
|
-
{
|
|
22
|
-
const v8 = await import("v8");
|
|
23
|
-
functions.structuredClone = ((obj) => {return v8.deserialize(v8.serialize(obj));});
|
|
24
|
-
}
|
|
25
18
|
Object.entries(functions).forEach(([name, func]) => {Object.defineProperty(globalThis, name, {writable: false, configurable: false, value: func});});
|
|
26
19
|
|
|
27
20
|
// Dynamically assign each enum to globalThis
|
|
@@ -93,7 +86,7 @@ for(const file of fs.readdirSync(classesDir))
|
|
|
93
86
|
|
|
94
87
|
try
|
|
95
88
|
{
|
|
96
|
-
let ui = new (await import("./SwingUI.js")).SwingUI(__dirname
|
|
89
|
+
let ui = new (await import("./SwingUI.js")).SwingUI(__dirname);
|
|
97
90
|
await ui.InitGUIProcess();
|
|
98
91
|
Object.defineProperty(globalThis, "ui", {writable: false, configurable: false, value: ui});
|
|
99
92
|
}catch(ex)
|
package/jar/gui-11.jar
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swing-ui",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "Cross-platform Graphic User Interface for Node.js, Bun and Deno 2+",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -54,7 +54,5 @@
|
|
|
54
54
|
"bun": ">= 1.1.0",
|
|
55
55
|
"deno": ">= 2.6.0"
|
|
56
56
|
},
|
|
57
|
-
"dependencies": {
|
|
58
|
-
"java-bridge": "^2.8.1"
|
|
59
|
-
}
|
|
57
|
+
"dependencies": {}
|
|
60
58
|
}
|
|
@@ -23,6 +23,15 @@ export class Ellipse extends Shape {
|
|
|
23
23
|
width: number;
|
|
24
24
|
height: number;
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Sets or gets the size of the `Ellipse` (horizontal and vertical diameter).
|
|
28
|
+
*
|
|
29
|
+
* @param {number|Size} width - Width of the ellipse (horizontal diameter), or a `Size` object (e.g., {width:300,height:300}).
|
|
30
|
+
* @param {number} [height] - Height of the ellipse (vertical diameter).
|
|
31
|
+
* @returns {Size|Ellipse} If called without parameters, current size is returned; otherwise this Ellipse object is returned.
|
|
32
|
+
* @see Size
|
|
33
|
+
*/
|
|
34
|
+
size(...args: any[]): Size | Ellipse;
|
|
26
35
|
/**
|
|
27
36
|
* Returns a JSON object that contains this shape properties. It may be converted back to this shape.
|
|
28
37
|
*
|
|
@@ -14,7 +14,7 @@ export class PasswordField extends TextComponent {
|
|
|
14
14
|
* const myChar = '\u25CF';
|
|
15
15
|
* const myChar = '\u2B24';
|
|
16
16
|
*
|
|
17
|
-
* @param {string} [character] - A one character string
|
|
17
|
+
* @param {string} [character] - A one character string. If the string has more than one character, only first one will be used.
|
|
18
18
|
* @returns {PasswordField|string} Returns an instance of `this` object when setting a value, otherwise current value is returned.
|
|
19
19
|
*/
|
|
20
20
|
echoChar(...args: any[]): PasswordField | string;
|
|
@@ -27,6 +27,15 @@ export class Rectangle extends Shape {
|
|
|
27
27
|
width: number;
|
|
28
28
|
height: number;
|
|
29
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Sets or gets the size of the `Rectangle`.
|
|
32
|
+
*
|
|
33
|
+
* @param {number|Size} width - Width of the Rectangle, or a `Size` object (e.g., {width:300,height:300}).
|
|
34
|
+
* @param {number} [height] - Height of the Rectangle.
|
|
35
|
+
* @returns {Size|Rectangle} If called without parameters, current size is returned; otherwise this Rectangle object is returned.
|
|
36
|
+
* @see Size
|
|
37
|
+
*/
|
|
38
|
+
size(...args: any[]): Size | Rectangle;
|
|
30
39
|
/**
|
|
31
40
|
* Sets corner radius if only one argument passed, or arc width and height if two arguments or size object supplied. The arc size is applied to all corners.
|
|
32
41
|
*
|
|
@@ -330,14 +330,14 @@ export class Window extends ShapeContainer {
|
|
|
330
330
|
*/
|
|
331
331
|
opacity(...args: any[]): number | this;
|
|
332
332
|
/**
|
|
333
|
-
* Sets a ToolBar to one of locations: `top`, `right`, `bottom` and `left
|
|
333
|
+
* Sets a ToolBar to one of locations: `top`, `right`, `bottom` and `left`.
|
|
334
334
|
*
|
|
335
335
|
* @param {string} dockLocation - One of: `top`, `right`, `bottom` and `left`.
|
|
336
336
|
* @param {ToolBar} [toolbar] - ToolBar to set to specified location. Set `null` to remove the toolbar from that location. Omit to get the toolbar already in that location.
|
|
337
|
-
* @returns {
|
|
337
|
+
* @returns {null|any|Window}
|
|
338
338
|
* @since 1.0.8
|
|
339
339
|
*/
|
|
340
|
-
toolBar(dockLocation: string, toolbar?: ToolBar):
|
|
340
|
+
toolBar(dockLocation: string, toolbar?: ToolBar): null | any | Window;
|
|
341
341
|
#private;
|
|
342
342
|
}
|
|
343
343
|
import { ShapeContainer } from "./ShapeContainer.js";
|
package/types/typedefs.d.ts
CHANGED
|
@@ -79,7 +79,7 @@ type DragEvent = {
|
|
|
79
79
|
*/
|
|
80
80
|
target: object;
|
|
81
81
|
/**
|
|
82
|
-
* - One of `dragstart`, `dragend`, `cancel`.
|
|
82
|
+
* - One of `dragstart`, `dragend`, `drag`, `cancel`.
|
|
83
83
|
*/
|
|
84
84
|
type: string;
|
|
85
85
|
/**
|
|
@@ -158,9 +158,21 @@ type ChangeEvent = {
|
|
|
158
158
|
*/
|
|
159
159
|
position?: number | undefined;
|
|
160
160
|
/**
|
|
161
|
-
* - The number of characters inserted or removed. Present when `action` is present.
|
|
161
|
+
* - The number of characters inserted or removed. Present when `action` is present. Applies to text editing components only.
|
|
162
162
|
*/
|
|
163
163
|
length?: number | undefined;
|
|
164
|
+
/**
|
|
165
|
+
* - Value of a currently selected {@link RadioButton}, {@link RadioButtonMenuItem} or {@link ToggleButton} within a group.
|
|
166
|
+
*/
|
|
167
|
+
value?: string | number | undefined;
|
|
168
|
+
/**
|
|
169
|
+
* - Index of a currently selected {@link RadioButton}, {@link RadioButtonMenuItem} or {@link ToggleButton} within a group.
|
|
170
|
+
*/
|
|
171
|
+
index?: number | undefined;
|
|
172
|
+
/**
|
|
173
|
+
* - Indicates if the target {@link RadioButton}, {@link RadioButtonMenuItem} or {@link ToggleButton} component's new state is selected.
|
|
174
|
+
*/
|
|
175
|
+
selected?: boolean | undefined;
|
|
164
176
|
};
|
|
165
177
|
/**
|
|
166
178
|
* Ancestor event received by the {@link UIComponent#onAncestorEvents |onAncestorEvents()} handler callback.
|
|
@@ -933,7 +945,7 @@ type ShapeEvent = {
|
|
|
933
945
|
*/
|
|
934
946
|
target: object;
|
|
935
947
|
/**
|
|
936
|
-
* - One of `add`, `remove`, `click`, `mousedown`, `mouseup`, `mouseenter`, `mouseleave`.
|
|
948
|
+
* - One of: `add`, `remove`, `click`, `mousedown`, `mouseup`, `mouseenter`, `mouseleave`, `mousemove`.
|
|
937
949
|
*/
|
|
938
950
|
type: string;
|
|
939
951
|
/**
|
|
@@ -994,11 +1006,11 @@ type ListItem = {
|
|
|
994
1006
|
*/
|
|
995
1007
|
icon?: string | null | undefined;
|
|
996
1008
|
/**
|
|
997
|
-
* - Item text color as a
|
|
1009
|
+
* - Item text color as a hex string (e.g. `#665500`).
|
|
998
1010
|
*/
|
|
999
1011
|
color?: string | undefined;
|
|
1000
1012
|
/**
|
|
1001
|
-
* - Item background color as a
|
|
1013
|
+
* - Item background color as a hex string (e.g. `#665500`).
|
|
1002
1014
|
*/
|
|
1003
1015
|
background?: string | undefined;
|
|
1004
1016
|
/**
|
|
@@ -1009,6 +1021,10 @@ type ListItem = {
|
|
|
1009
1021
|
* - {@link Font} formatted object.
|
|
1010
1022
|
*/
|
|
1011
1023
|
font?: Font | undefined;
|
|
1024
|
+
/**
|
|
1025
|
+
* - Specifies if the Tree node Item text can be edited by the user. (only in Tree components)
|
|
1026
|
+
*/
|
|
1027
|
+
editable?: boolean | undefined;
|
|
1012
1028
|
/**
|
|
1013
1029
|
* - In some cases items are returned with `index` property to indicate their position within component.
|
|
1014
1030
|
*/
|
|
@@ -1072,9 +1088,9 @@ type Border = {
|
|
|
1072
1088
|
*/
|
|
1073
1089
|
style: BorderStyle;
|
|
1074
1090
|
/**
|
|
1075
|
-
* - Border
|
|
1091
|
+
* - Border width in pixels. Must be >= 1.
|
|
1076
1092
|
*/
|
|
1077
|
-
|
|
1093
|
+
width?: number | undefined;
|
|
1078
1094
|
/**
|
|
1079
1095
|
* - Inner padding as a space-separated string of four integer values: `"top right bottom left"`. Example: `"5 10 5 10"`. Can be set even when `style` is `"none"`.
|
|
1080
1096
|
*/
|
|
@@ -1179,7 +1195,7 @@ type TableColumn = {
|
|
|
1179
1195
|
/**
|
|
1180
1196
|
* - The character used to mask input for the `password` type.
|
|
1181
1197
|
*/
|
|
1182
|
-
|
|
1198
|
+
echoChar?: string | undefined;
|
|
1183
1199
|
/**
|
|
1184
1200
|
* - Icon shown in the column header. Value can be a local file path, URI, or base64 encoded image string.
|
|
1185
1201
|
*/
|
|
@@ -1244,7 +1260,7 @@ type TableColumn = {
|
|
|
1244
1260
|
/**
|
|
1245
1261
|
* Table cell coordinates containing column and row property.
|
|
1246
1262
|
*/
|
|
1247
|
-
type
|
|
1263
|
+
type TableCell = {
|
|
1248
1264
|
/**
|
|
1249
1265
|
* - a column index of the cell
|
|
1250
1266
|
*/
|
package/ui-process-manager.js
CHANGED
|
@@ -54,7 +54,7 @@ else
|
|
|
54
54
|
async function startJar()
|
|
55
55
|
{
|
|
56
56
|
let JAR_PATH = path.join(workerData.moduleDir, "jar/gui-11.jar");
|
|
57
|
-
let JAVA_BIN = env.JAVA_HOME ? path.join(env.JAVA_HOME, workerData.os === "windows" ? "java.exe" : "java") : "java"; // build custom path from specified dir for each OS, or just use default command.
|
|
57
|
+
let JAVA_BIN = env.JAVA_HOME ? path.join(env.JAVA_HOME, "bin", workerData.os === "windows" ? "java.exe" : "java") : "java"; // build custom path from specified dir for each OS, or just use default command.
|
|
58
58
|
let JAVA_OPTS = (env.JAVA_OPTS ?? "").split(" ").filter(Boolean);
|
|
59
59
|
if(JAVA_OPTS.indexOf("-Dfile.encoding=UTF-8") === -1) JAVA_OPTS.push("-Dfile.encoding=UTF-8"); // important
|
|
60
60
|
if(workerData.debugJava) JAVA_OPTS.push("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005"); // for debugging JAR
|