positron.js 1.0.3 → 1.0.5
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/bin/positron.js +6 -1
- package/builder.js +24 -2
- package/core/mac/main.swift +208 -22
- package/core/win/PositronRuntime.csproj +1 -1
- package/core/win/main.cs +196 -19
- package/index.js +239 -42
- package/package.json +9 -2
- package/packager.js +30 -7
package/core/win/main.cs
CHANGED
|
@@ -10,13 +10,49 @@ using System.Threading;
|
|
|
10
10
|
using System.Threading.Tasks;
|
|
11
11
|
using System.Windows;
|
|
12
12
|
using System.Windows.Controls;
|
|
13
|
-
using System.Windows.Input;
|
|
14
13
|
using Microsoft.Web.WebView2.Core;
|
|
15
14
|
using Microsoft.Web.WebView2.Wpf;
|
|
16
15
|
using System.Text.Json.Serialization;
|
|
17
16
|
using System.Net;
|
|
18
17
|
using System.Net.Sockets;
|
|
19
18
|
using Microsoft.VisualBasic;
|
|
19
|
+
using System.Runtime.InteropServices;
|
|
20
|
+
using Microsoft.Win32;
|
|
21
|
+
|
|
22
|
+
class PowerSaveBlocker
|
|
23
|
+
{
|
|
24
|
+
// Import the Win32 API
|
|
25
|
+
[DllImport("kernel32.dll")]
|
|
26
|
+
private static extern uint SetThreadExecutionState(uint esFlags);
|
|
27
|
+
|
|
28
|
+
// Flags
|
|
29
|
+
private const uint ES_CONTINUOUS = 0x80000000;
|
|
30
|
+
private const uint ES_SYSTEM_REQUIRED = 0x00000001;
|
|
31
|
+
private const uint ES_DISPLAY_REQUIRED = 0x00000002;
|
|
32
|
+
|
|
33
|
+
private static uint currentState = 0;
|
|
34
|
+
|
|
35
|
+
public static void BlockPowerSave(bool keepDisplayOn = false)
|
|
36
|
+
{
|
|
37
|
+
uint flags = ES_CONTINUOUS | ES_SYSTEM_REQUIRED;
|
|
38
|
+
if (keepDisplayOn)
|
|
39
|
+
{
|
|
40
|
+
flags |= ES_DISPLAY_REQUIRED;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
currentState = SetThreadExecutionState(flags);
|
|
44
|
+
if (currentState == 0)
|
|
45
|
+
{
|
|
46
|
+
Console.WriteLine("Failed to set execution state!");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public static void UnblockPowerSave()
|
|
51
|
+
{
|
|
52
|
+
SetThreadExecutionState(ES_CONTINUOUS);
|
|
53
|
+
currentState = 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
20
56
|
|
|
21
57
|
|
|
22
58
|
namespace PositronWindows
|
|
@@ -24,7 +60,6 @@ namespace PositronWindows
|
|
|
24
60
|
|
|
25
61
|
// MARK: - IPC Message Types
|
|
26
62
|
|
|
27
|
-
|
|
28
63
|
public class IPCMessage
|
|
29
64
|
{
|
|
30
65
|
public int windowId { get; set; }
|
|
@@ -138,10 +173,18 @@ namespace PositronWindows
|
|
|
138
173
|
? Path.Combine(basePath, "resources")
|
|
139
174
|
: basePath;
|
|
140
175
|
|
|
141
|
-
|
|
176
|
+
string backendExeName = "positron-backend.exe";
|
|
177
|
+
if (Directory.Exists(targetDir)) {
|
|
178
|
+
string[] files = Directory.GetFiles(targetDir, "*-backend.exe");
|
|
179
|
+
if (files.Length > 0) {
|
|
180
|
+
backendExeName = Path.GetFileName(files[0]);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (File.Exists(Path.Combine(targetDir, backendExeName)))
|
|
142
185
|
{
|
|
143
186
|
// PACKAGED MODE — C# is the entry point; launch the Node backend
|
|
144
|
-
StartNodeProcess(targetDir);
|
|
187
|
+
StartNodeProcess(targetDir, backendExeName);
|
|
145
188
|
}
|
|
146
189
|
else
|
|
147
190
|
{
|
|
@@ -154,7 +197,7 @@ namespace PositronWindows
|
|
|
154
197
|
}
|
|
155
198
|
else
|
|
156
199
|
{
|
|
157
|
-
error("No
|
|
200
|
+
error($"No {backendExeName} found and POSITRON_IPC_PORT not set. Cannot start.");
|
|
158
201
|
Shutdown();
|
|
159
202
|
return;
|
|
160
203
|
}
|
|
@@ -190,13 +233,13 @@ namespace PositronWindows
|
|
|
190
233
|
|
|
191
234
|
private static int _ipcPort = 9000;
|
|
192
235
|
|
|
193
|
-
private void StartNodeProcess(string workingDirectory)
|
|
236
|
+
private void StartNodeProcess(string workingDirectory, string backendExeName)
|
|
194
237
|
{
|
|
195
238
|
IsPackaged = true;
|
|
196
239
|
|
|
197
240
|
_ipcPort = GetRandomOpenPort();
|
|
198
241
|
|
|
199
|
-
|
|
242
|
+
string backendExe = Path.Combine(workingDirectory, backendExeName);
|
|
200
243
|
|
|
201
244
|
_nodeProcess = new Process
|
|
202
245
|
{
|
|
@@ -336,7 +379,8 @@ private void StartNodeProcess(string workingDirectory)
|
|
|
336
379
|
_ipcClient.Send(new IPCResponse
|
|
337
380
|
{
|
|
338
381
|
windowId = windowId,
|
|
339
|
-
@event = eventName
|
|
382
|
+
@event = eventName,
|
|
383
|
+
data = new() { { "url", webView.Source?.ToString() ?? "" }, { "title", webView.CoreWebView2.DocumentTitle }, { "canGoBack", webView.CoreWebView2.CanGoBack.ToString().ToLower() }, { "canGoForward", webView.CoreWebView2.CanGoForward.ToString().ToLower() } }
|
|
340
384
|
});
|
|
341
385
|
};
|
|
342
386
|
|
|
@@ -360,6 +404,7 @@ private void StartNodeProcess(string workingDirectory)
|
|
|
360
404
|
break;
|
|
361
405
|
}
|
|
362
406
|
|
|
407
|
+
|
|
363
408
|
case "setContextMenu":
|
|
364
409
|
if (!LayoutMap.TryGetValue(windowId, out var layout)) break;
|
|
365
410
|
if (args.Count == 0)
|
|
@@ -395,15 +440,138 @@ private void StartNodeProcess(string workingDirectory)
|
|
|
395
440
|
GetIPCClient().Send(new IPCResponse
|
|
396
441
|
{
|
|
397
442
|
windowId = windowId,
|
|
398
|
-
@event = "setSwipeNav-reply-" + windowId,
|
|
443
|
+
@event = args[^1] ?? "setSwipeNav-reply-" + windowId,
|
|
399
444
|
data = new() { { "enabled", (wvSwipeNav?.CoreWebView2.Settings.IsSwipeNavigationEnabled ?? false).ToString().ToLower() } }
|
|
400
445
|
});
|
|
401
446
|
|
|
447
|
+
break;
|
|
448
|
+
|
|
449
|
+
case "blockPowerSave":
|
|
450
|
+
PowerSaveBlocker.BlockPowerSave();
|
|
451
|
+
break;
|
|
452
|
+
|
|
453
|
+
case "unblockPowerSave":
|
|
454
|
+
PowerSaveBlocker.UnblockPowerSave();
|
|
455
|
+
break;
|
|
456
|
+
|
|
457
|
+
case "isDarkMode":
|
|
458
|
+
bool isLightTheme = true;
|
|
459
|
+
using (RegistryKey? key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"))
|
|
460
|
+
{
|
|
461
|
+
if (key != null)
|
|
462
|
+
{
|
|
463
|
+
object? value = key?.GetValue("AppsUseLightTheme");
|
|
464
|
+
if (value != null && (int)value == 0)
|
|
465
|
+
{
|
|
466
|
+
isLightTheme = false; // Dark Mode
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
GetIPCClient().Send(new IPCResponse
|
|
471
|
+
{
|
|
472
|
+
windowId = windowId,
|
|
473
|
+
@event = args[^1] ?? "isDarkMode-reply-" + windowId,
|
|
474
|
+
data = new() { { "isDarkMode", (!isLightTheme).ToString().ToLower() } }
|
|
475
|
+
});
|
|
476
|
+
break;
|
|
477
|
+
|
|
478
|
+
case "isSwipeNavEnabled":
|
|
479
|
+
if (!WindowsMap.TryGetValue(windowId, out var winCheckSwipe)) break;
|
|
480
|
+
var wvCheckSwipe = GetWebView(windowId);
|
|
481
|
+
if (wvCheckSwipe != null) {
|
|
482
|
+
bool isEnabled = wvCheckSwipe.CoreWebView2.Settings.IsSwipeNavigationEnabled;
|
|
483
|
+
GetIPCClient().Send(new IPCResponse
|
|
484
|
+
{
|
|
485
|
+
windowId = windowId,
|
|
486
|
+
@event = args[^1] ?? "isSwipeNavEnabled-reply-" + windowId,
|
|
487
|
+
data = new() { { "enabled", isEnabled.ToString().ToLower() } }
|
|
488
|
+
}
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
break;
|
|
492
|
+
|
|
493
|
+
case "showFileOpenDialog":
|
|
494
|
+
{
|
|
495
|
+
var dialog = new Microsoft.Win32.OpenFileDialog
|
|
496
|
+
{
|
|
497
|
+
Multiselect = args.Count > 0 && args[0].ToLower() == "true"
|
|
498
|
+
};
|
|
499
|
+
bool? result = dialog.ShowDialog();
|
|
500
|
+
if (result == true)
|
|
501
|
+
{
|
|
502
|
+
string[] files = dialog.FileNames;
|
|
503
|
+
GetIPCClient().Send(new IPCResponse
|
|
504
|
+
{
|
|
505
|
+
windowId = windowId,
|
|
506
|
+
@event = args[^1] ?? "showFileOpenDialog-reply-" + windowId,
|
|
507
|
+
data = new() { { "files", JsonSerializer.Serialize(files) } }
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
break;
|
|
512
|
+
|
|
513
|
+
case "readFromClipboard":
|
|
514
|
+
string clipboardText = "";
|
|
515
|
+
Current.Dispatcher.Invoke(() =>
|
|
516
|
+
{
|
|
517
|
+
try
|
|
518
|
+
{
|
|
519
|
+
clipboardText = Clipboard.GetText();
|
|
520
|
+
}
|
|
521
|
+
catch (Exception ex)
|
|
522
|
+
{
|
|
523
|
+
error($"readFromClipboard failed: {ex.Message}");
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
GetIPCClient().Send(new IPCResponse
|
|
527
|
+
{
|
|
528
|
+
windowId = windowId,
|
|
529
|
+
@event = args[^1] ?? "readFromClipboard-reply-" + windowId,
|
|
530
|
+
data = new() { { "text", clipboardText } }
|
|
531
|
+
});
|
|
532
|
+
break;
|
|
533
|
+
|
|
534
|
+
case "writeToClipboard":
|
|
535
|
+
if (args.Count == 0) break;
|
|
536
|
+
Current.Dispatcher.Invoke(() =>
|
|
537
|
+
{
|
|
538
|
+
try
|
|
539
|
+
{
|
|
540
|
+
Clipboard.SetText(args[0]);
|
|
541
|
+
}
|
|
542
|
+
catch (Exception ex)
|
|
543
|
+
{
|
|
544
|
+
error($"writeToClipboard failed: {ex.Message}");
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
break;
|
|
548
|
+
|
|
549
|
+
case "isVisible":
|
|
550
|
+
if (!WindowsMap.TryGetValue(windowId, out var winVisible)) break;
|
|
551
|
+
bool isVisible = winVisible.IsVisible;
|
|
552
|
+
GetIPCClient().Send(new IPCResponse
|
|
553
|
+
{ windowId = windowId,
|
|
554
|
+
@event = args[^1] ?? "isVisible-reply-" + windowId,
|
|
555
|
+
data = new() { { "isVisible", isVisible.ToString().ToLower() } }
|
|
556
|
+
});
|
|
557
|
+
break;
|
|
558
|
+
|
|
559
|
+
case "isFullscreen":
|
|
560
|
+
if (!WindowsMap.TryGetValue(windowId, out var winFullscreen)) break;
|
|
561
|
+
bool isFullscreen = winFullscreen.WindowState == WindowState.Maximized;
|
|
562
|
+
GetIPCClient().Send(new IPCResponse
|
|
563
|
+
{ windowId = windowId,
|
|
564
|
+
@event = args[^1] ?? "isFullscreen-reply-" + windowId,
|
|
565
|
+
data = new() { { "isFullscreen", isFullscreen.ToString().ToLower() } }
|
|
566
|
+
});
|
|
402
567
|
break;
|
|
403
568
|
|
|
404
569
|
case "closeWindow":
|
|
405
570
|
if (WindowsMap.TryGetValue(windowId, out var winToClose))
|
|
571
|
+
{
|
|
572
|
+
_forceClosing.Add(windowId);
|
|
406
573
|
winToClose.Close(); // Triggers Closed → cleanup above
|
|
574
|
+
}
|
|
407
575
|
else
|
|
408
576
|
error($"closeWindow — no window found with ID {windowId}");
|
|
409
577
|
break;
|
|
@@ -466,6 +634,15 @@ case "forceCloseWindow":
|
|
|
466
634
|
}
|
|
467
635
|
break;
|
|
468
636
|
|
|
637
|
+
case "addToContentBlocker":
|
|
638
|
+
_ipcClient.Send(new IPCResponse
|
|
639
|
+
{
|
|
640
|
+
windowId = windowId,
|
|
641
|
+
@event = args[^1] ?? "addToContentBlocker-reply-" + windowId,
|
|
642
|
+
data = new() { { "status", "success" }, { "warning", "Content blocker not supported on Windows." } }
|
|
643
|
+
});
|
|
644
|
+
break;
|
|
645
|
+
|
|
469
646
|
case "loadFile":
|
|
470
647
|
if (!WindowsMap.TryGetValue(windowId, out _)) break;
|
|
471
648
|
if (args.Count == 0)
|
|
@@ -516,7 +693,7 @@ case "forceCloseWindow":
|
|
|
516
693
|
_ipcClient.Send(new IPCResponse
|
|
517
694
|
{
|
|
518
695
|
windowId = windowId,
|
|
519
|
-
@event = "evaluateJS-reply-" + windowId,
|
|
696
|
+
@event = args[^1] ?? "evaluateJS-reply-" + windowId,
|
|
520
697
|
data = new() { { "result", result ?? "null" } }
|
|
521
698
|
});
|
|
522
699
|
}
|
|
@@ -526,7 +703,7 @@ case "forceCloseWindow":
|
|
|
526
703
|
_ipcClient.Send(new IPCResponse
|
|
527
704
|
{
|
|
528
705
|
windowId = windowId,
|
|
529
|
-
@event = "evaluateJS-reply-" + windowId,
|
|
706
|
+
@event = args[^1] ?? "evaluateJS-reply-" + windowId,
|
|
530
707
|
data = new() { { "error", ex.Message } }
|
|
531
708
|
});
|
|
532
709
|
}
|
|
@@ -540,7 +717,7 @@ case "forceCloseWindow":
|
|
|
540
717
|
_ipcClient.Send(new IPCResponse
|
|
541
718
|
{
|
|
542
719
|
windowId = windowId,
|
|
543
|
-
@event = "isFocused-reply-" + windowId,
|
|
720
|
+
@event = args[^1] ?? "isFocused-reply-" + windowId,
|
|
544
721
|
data = new() { { "isFocused", isFocused.ToString().ToLower() } }
|
|
545
722
|
});
|
|
546
723
|
break;
|
|
@@ -632,7 +809,7 @@ case "setBounds":
|
|
|
632
809
|
_ipcClient.Send(new IPCResponse
|
|
633
810
|
{
|
|
634
811
|
windowId = windowId,
|
|
635
|
-
@event = "prompt-reply-" + windowId,
|
|
812
|
+
@event = args[^1] ?? "prompt-reply-" + windowId,
|
|
636
813
|
data = new() { { "input", result } }
|
|
637
814
|
});
|
|
638
815
|
}
|
|
@@ -650,7 +827,7 @@ case "setBounds":
|
|
|
650
827
|
_ipcClient.Send(new IPCResponse
|
|
651
828
|
{
|
|
652
829
|
windowId = windowId,
|
|
653
|
-
@event = "confirm-reply-" + windowId,
|
|
830
|
+
@event = args[^1] ?? "confirm-reply-" + windowId,
|
|
654
831
|
data = new() { { "confirmed", result.ToString().ToLower() } }
|
|
655
832
|
});
|
|
656
833
|
}
|
|
@@ -776,7 +953,7 @@ case "setBounds":
|
|
|
776
953
|
_ipcClient.Send(new IPCResponse
|
|
777
954
|
{
|
|
778
955
|
windowId = windowId,
|
|
779
|
-
@event = "capture-page-result-" + windowId,
|
|
956
|
+
@event = args[^1] ?? "capture-page-result-" + windowId,
|
|
780
957
|
data = new() { { "imageData", base64 } }
|
|
781
958
|
});
|
|
782
959
|
}
|
|
@@ -797,7 +974,7 @@ case "setBounds":
|
|
|
797
974
|
_ipcClient.Send(new IPCResponse
|
|
798
975
|
{
|
|
799
976
|
windowId = windowId,
|
|
800
|
-
@event = "canGoBack-reply-" + windowId,
|
|
977
|
+
@event = args[^1] ?? "canGoBack-reply-" + windowId,
|
|
801
978
|
data = new() { { "canGoBack", canGoBack.ToString().ToLower() } }
|
|
802
979
|
});
|
|
803
980
|
}
|
|
@@ -813,7 +990,7 @@ case "setBounds":
|
|
|
813
990
|
_ipcClient.Send(new IPCResponse
|
|
814
991
|
{
|
|
815
992
|
windowId = windowId,
|
|
816
|
-
@event = "canGoForward-reply-" + windowId,
|
|
993
|
+
@event = args[^1] ?? "canGoForward-reply-" + windowId,
|
|
817
994
|
data = new() { { "canGoForward", canGoForward.ToString().ToLower() } }
|
|
818
995
|
});
|
|
819
996
|
}
|
|
@@ -829,7 +1006,7 @@ case "setBounds":
|
|
|
829
1006
|
_ipcClient.Send(new IPCResponse
|
|
830
1007
|
{
|
|
831
1008
|
windowId = windowId,
|
|
832
|
-
@event = "getURL-reply-" + windowId,
|
|
1009
|
+
@event = args[^1] ?? "getURL-reply-" + windowId,
|
|
833
1010
|
data = new() { { "url", url } }
|
|
834
1011
|
});
|
|
835
1012
|
}
|
|
@@ -845,7 +1022,7 @@ case "setBounds":
|
|
|
845
1022
|
_ipcClient.Send(new IPCResponse
|
|
846
1023
|
{
|
|
847
1024
|
windowId = windowId,
|
|
848
|
-
@event = "getTitle-reply-" + windowId,
|
|
1025
|
+
@event = args[^1] ?? "getTitle-reply-" + windowId,
|
|
849
1026
|
data = new() { { "title", title } }
|
|
850
1027
|
});
|
|
851
1028
|
}
|