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/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
- if (File.Exists(Path.Combine(targetDir, "positron-backend.exe")))
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 positron-backend.exe found and POSITRON_IPC_PORT not set. Cannot start.");
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
- string backendExe = Path.Combine(workingDirectory, "positron-backend.exe");
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
  }