From 3703a46461c85c41b0a2c1f44c1ac7e4b13669ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Thu, 30 May 2024 12:08:08 +0200 Subject: [PATCH 01/11] ElixirKit: Target .NET 8 --- elixirkit/elixirkit_dotnet/ElixirKit.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elixirkit/elixirkit_dotnet/ElixirKit.csproj b/elixirkit/elixirkit_dotnet/ElixirKit.csproj index 51b1a6ff14d..3cea7086ebb 100644 --- a/elixirkit/elixirkit_dotnet/ElixirKit.csproj +++ b/elixirkit/elixirkit_dotnet/ElixirKit.csproj @@ -1,7 +1,7 @@ - net46 + net8.0 10.0 enable From 16736daef995592c4595a1ffef5f26ad1fc608de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Thu, 30 May 2024 12:11:01 +0200 Subject: [PATCH 02/11] env.bat: Do not use a short node name --- rel/app/env.bat.eex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rel/app/env.bat.eex b/rel/app/env.bat.eex index 28adc6ec7e2..e1b0e588d96 100644 --- a/rel/app/env.bat.eex +++ b/rel/app/env.bat.eex @@ -14,10 +14,10 @@ set ELIXIR_ERL_OPTIONS=!ELIXIR_ERL_OPTIONS! -epmd_module Elixir.Livebook.EPMD -s for /f "skip=1" %%X in ('wmic os get localdatetime') do if not defined TIMESTAMP set TIMESTAMP=%%X if defined LIVEBOOK_DISTRIBUTION set RELEASE_DISTRIBUTION=!LIVEBOOK_DISTRIBUTION! -if not defined RELEASE_DISTRIBUTION set RELEASE_DISTRIBUTION=sname +if not defined RELEASE_DISTRIBUTION set RELEASE_DISTRIBUTION=name if defined LIVEBOOK_NODE set RELEASE_NODE=!LIVEBOOK_NODE! -if not defined RELEASE_NODE set RELEASE_NODE=livebook-app-!TIMESTAMP:~8,6!-!RANDOM! +if not defined RELEASE_NODE set RELEASE_NODE=livebook-app-!TIMESTAMP:~8,6!-!RANDOM!@127.0.0.1 set RELEASE_MODE=interactive set MIX_ARCHIVES=!RELEASE_ROOT!\vendor\archives From 2d49268df61ae279078137db324633e67a6a2b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Thu, 30 May 2024 12:12:25 +0200 Subject: [PATCH 03/11] Installer.nsi: Execute as user, write HKCU keys --- rel/app/windows/Installer.nsi | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/rel/app/windows/Installer.nsi b/rel/app/windows/Installer.nsi index f255277ef14..aa8d1ba8d65 100644 --- a/rel/app/windows/Installer.nsi +++ b/rel/app/windows/Installer.nsi @@ -10,7 +10,7 @@ Unicode True InstallDir "$LOCALAPPDATA\Livebook" ; Need admin for registering URL scheme -RequestExecutionLevel admin +RequestExecutionLevel user !define MUI_ABORTWARNING !define MUI_ICON "Resources\AppIcon.ico" @@ -77,26 +77,26 @@ SectionEnd Section "Install Handlers" DetailPrint "Registering .livemd File Handler" - DeleteRegKey HKCR ".livemd" - WriteRegStr HKCR ".livemd" "" "Livebook.LiveMarkdown" - DeleteRegKey HKCR "Livebook.LiveMarkdown" - WriteRegStr HKCR "Livebook.LiveMarkdown" "" "LiveMarkdown" - WriteRegStr HKCR "Livebook.LiveMarkdown\DefaultIcon" "" "$INSTDIR\Livebook.exe,1" - WriteRegStr HKCR "Livebook.LiveMarkdown\shell\open\command" "" '"$INSTDIR\Livebook.exe" "open:%1"' + DeleteRegKey HKCU "Software\Classes\.livemd" + WriteRegStr HKCU "Software\Classes\.livemd" "" "Livebook.LiveMarkdown" + DeleteRegKey HKCU "Software\Classes\Livebook.LiveMarkdown" + WriteRegStr HKCU "Software\Classes\Livebook.LiveMarkdown" "" "LiveMarkdown" + WriteRegStr HKCU "Software\Classes\Livebook.LiveMarkdown\DefaultIcon" "" "$INSTDIR\Livebook.exe,1" + WriteRegStr HKCU "Software\Classes\Livebook.LiveMarkdown\shell\open\command" "" '"$INSTDIR\Livebook.exe" "open:%1"' DetailPrint "Registering livebook URL Handler" - DeleteRegKey HKCR "livebook" - WriteRegStr HKCR "livebook" "" "Livebook URL Protocol" - WriteRegStr HKCR "livebook" "URL Protocol" "" - WriteRegStr HKCR "livebook\shell" "" "" - WriteRegStr HKCR "livebook\shell\open" "" "" - WriteRegStr HKCR "livebook\shell\open\command" "" '"$INSTDIR\Livebook.exe" "open:%1"' + DeleteRegKey HKCU "Software\Classes\livebook" + WriteRegStr HKCU "Software\Classes\livebook" "" "Livebook URL Protocol" + WriteRegStr HKCU "Software\Classes\livebook" "URL Protocol" "" + WriteRegStr HKCU "Software\Classes\livebook\shell" "" "" + WriteRegStr HKCU "Software\Classes\livebook\shell\open" "" "" + WriteRegStr HKCU "Software\Classes\livebook\shell\open\command" "" '"$INSTDIR\Livebook.exe" "open:%1"' SectionEnd Section "Uninstall" - DeleteRegKey HKCR ".livemd" - DeleteRegKey HKCR "Livebook.LiveMarkdown" - DeleteRegKey HKCR "livebook" + DeleteRegKey HKCU "Software\Classes\.livemd" + DeleteRegKey HKCU "Software\Classes\Livebook.LiveMarkdown" + DeleteRegKey HKCU "Software\Classes\livebook" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" DeleteRegKey HKLM "Software\Dashbit\Livebook" DeleteRegKey /ifempty HKLM "Software\Dashbit" From ca04b02c90ffdabbbf474ad2d0af7b8542a6c227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Thu, 30 May 2024 12:14:50 +0200 Subject: [PATCH 04/11] Implemented Livebook without Windows Forms. vc_redist.x64.exe is no longer required --- rel/app/windows/App.manifest | 9 -- rel/app/windows/Installer.nsi | 4 - rel/app/windows/Livebook.cs | 228 +++++++++++++---------------- rel/app/windows/Livebook.csproj | 13 +- rel/app/windows/build_installer.sh | 7 - 5 files changed, 111 insertions(+), 150 deletions(-) delete mode 100644 rel/app/windows/App.manifest diff --git a/rel/app/windows/App.manifest b/rel/app/windows/App.manifest deleted file mode 100644 index f2708ecb131..00000000000 --- a/rel/app/windows/App.manifest +++ /dev/null @@ -1,9 +0,0 @@ - - - - - true - PerMonitorV2 - - - diff --git a/rel/app/windows/Installer.nsi b/rel/app/windows/Installer.nsi index aa8d1ba8d65..0881ab3d806 100644 --- a/rel/app/windows/Installer.nsi +++ b/rel/app/windows/Installer.nsi @@ -30,10 +30,6 @@ FunctionEnd Section "Install" SetOutPath "$INSTDIR" - File "bin\vc_redist.x64.exe" - ExecWait '"$INSTDIR\vc_redist.x64.exe" /install /quiet /norestart' - Delete "$INSTDIR\vc_redist.x64.exe" - File /a /r "bin\Livebook-Release\" CreateDirectory "$LOCALAPPDATA\Livebook\Logs" diff --git a/rel/app/windows/Livebook.cs b/rel/app/windows/Livebook.cs index 270173de7c7..fbc236f4745 100644 --- a/rel/app/windows/Livebook.cs +++ b/rel/app/windows/Livebook.cs @@ -2,157 +2,144 @@ using System.Diagnostics; using System.Drawing; using System.IO; -using System.Windows.Forms; +using System.Runtime.InteropServices; +using H.NotifyIcon.Core; +using TextCopy; #nullable enable namespace Livebook; +class TrayIconMenu: TrayIconWithContextMenu +{ + public new void Create() + { + base.Create(); + WindowUtilities.RunMessageLoop(); + } +} + static class LivebookMain { - [STAThread] + [DllImport("User32.dll", CharSet = CharSet.Unicode)] + // https://learn.microsoft.com/de-de/windows/win32/api/winuser/nf-winuser-messagebox + static extern int MessageBox(IntPtr h, string m, string c, int type); + static int MB_OK = 0x00000000; + static int MB_ICONERROR = 0x00000010; + static string logPath = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "Livebook", + "Logs", + "Livebook.log" + ); + + static void ProcessExitHandler(object? sender, EventArgs eventArgs) + { + var elixirCode = ElixirKit.API.Stop(); + if (elixirCode != 0) + { + var message = $"Livebook exited with exit code {elixirCode}.\r\nLogs available at: {logPath}"; + MessageBox(0, message, "Error", MB_OK | MB_ICONERROR); + } + } + static void Main(string[] args) { + AppDomain.CurrentDomain.ProcessExit += ProcessExitHandler; + var prefix = "open:"; var url = ""; if (args.Length == 1 && args[0].StartsWith(prefix)) { - var uri = new System.Uri(args[0].Remove(0, prefix.Length)); + var uri = new Uri(args[0].Remove(0, prefix.Length)); url = uri.AbsoluteUri; } - var logPath = getLogPath(); + using var iconStream = H.Resources.AppIcon_ico.AsStream(); + using var icon = new Icon(iconStream); - if (ElixirKit.API.IsMainInstance("dev.livebook.Livebook")) - { - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new LivebookApp(url, logPath)); - - var code = ElixirKit.API.Stop(); - if (code == 0) { return; } - var message = $"Livebook exited with exit code {code}.\r\nLogs available at: {logPath}"; - MessageBox.Show(new Form() { TopMost = true }, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - else + var notifyIcon = new TrayIconMenu { - ElixirKit.API.Publish("open", url); - } - } - - internal static string getLogPath() - { - return Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "Livebook", - "Logs", - "Livebook.log" - ); - } -} - -class DummyForm : Form {} - -class LivebookApp : ApplicationContext -{ - private NotifyIcon notifyIcon; - private string? url; - private string logPath; - - public LivebookApp(string url, string logPath) - { - this.logPath = logPath; - - ThreadExit += threadExit; - - ContextMenuStrip menu = new ContextMenuStrip(); - menu.Items.Add("Open", null, openClicked); - menu.Items.Add("New Notebook", null, openNewNotebookClicked); - menu.Items.Add(new ToolStripSeparator()); + Icon = icon.Handle, + ToolTip = "Livebook", + Visibility = IconVisibility.Visible + }; - var copyURLButton = menu.Items.Add("Copy URL", null, copyURLClicked); - copyURLButton.Enabled = false; + notifyIcon.MessageWindow.MouseEventReceived += notifyIconClicked; + + var copyURLButton = new PopupMenuItem("Copy URL", (_, _) => ClipboardService.SetText(url)) + { + Enabled = false + }; - menu.Items.Add("View Logs", null, viewLogsClicked); - menu.Items.Add("Open .livebookdesktop.bat", null, openBootScriptClicked); - menu.Items.Add(new ToolStripSeparator()); - menu.Items.Add("Settings", null, openSettingsClicked); - menu.Items.Add("Quit", null, quitClicked); - notifyIcon = new NotifyIcon() + notifyIcon.ContextMenu = new PopupMenu() { - Text = "Livebook", - Visible = true, - Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath)!, - ContextMenuStrip = menu + Items = + { + new PopupMenuItem("Open", (_, _) => ElixirKit.API.Publish("open", "")), + new PopupMenuItem("New Notebook", (_, _) => ElixirKit.API.Publish("open", "/new")), + new PopupMenuSeparator(), + copyURLButton, + new PopupMenuItem("View Logs", (_, _) => Process.Start("notepad.exe", logPath)), + new PopupMenuItem("Open .livebookdesktop.bat", (_, _) => openBootScriptClicked()), + new PopupMenuSeparator(), + new PopupMenuItem("Settings", (_, _) => ElixirKit.API.Publish("open", "/settings")), + new PopupMenuItem("Quit", (_, _) => { + notifyIcon.Dispose(); + AppDomain.CurrentDomain.ProcessExit -= ProcessExitHandler; + Environment.Exit(0); + }), + } }; - notifyIcon.Click += notifyIconClicked; Directory.CreateDirectory(Path.GetDirectoryName(logPath)!); - ElixirKit.API.Start( - name: "app", - logPath: logPath, - ready: () => { - ElixirKit.API.Subscribe((name, data) => - { - switch (name) + if (ElixirKit.API.IsMainInstance("dev.livebook.Livebook")) + { + ElixirKit.API.Start( + name: "app", + logPath: logPath, + ready: () => { + ElixirKit.API.Subscribe((name, data) => { - case "url": - copyURLButton.Enabled = true; - this.url = data; - break; - - default: - throw new Exception($"unknown event {name}"); - } - }); - - ElixirKit.API.Publish("open", url); - }, - exited: (exitCode) => - { - Application.Exit(); - } - ); - } + switch (name) + { + case "url": + copyURLButton.Enabled = true; + url = data; + break; + + default: + throw new Exception($"unknown event {name}"); + } + }); + + ElixirKit.API.Publish("open", url); + }, + exited: (exitCode) => + { + Environment.Exit(exitCode); + } + ); - private void threadExit(object? sender, EventArgs e) - { - notifyIcon.Visible = false; + notifyIcon.Create(); + } + else + { + ElixirKit.API.Publish("open", url); + } } - private void notifyIconClicked(object? sender, EventArgs e) + static void notifyIconClicked(object? sender, MessageWindow.MouseEventReceivedEventArgs args) { - MouseEventArgs mouseEventArgs = (MouseEventArgs)e; - - if (mouseEventArgs.Button == MouseButtons.Left) + if (args.MouseEvent == MouseEvent.IconLeftMouseDown) { ElixirKit.API.Publish("open", ""); } } - private void openClicked(object? sender, EventArgs e) - { - ElixirKit.API.Publish("open", ""); - } - - private void openNewNotebookClicked(object? sender, EventArgs e) - { - ElixirKit.API.Publish("open", "/new"); - } - - private void copyURLClicked(object? sender, EventArgs e) - { - System.Windows.Forms.Clipboard.SetText(url!); - } - - private void viewLogsClicked(object? sender, EventArgs e) - { - Process.Start(logPath); - } - - private void openBootScriptClicked(object? sender, EventArgs e) + static void openBootScriptClicked() { var path = Path.Combine( @@ -178,15 +165,4 @@ private void openBootScriptClicked(object? sender, EventArgs e) Process.Start("notepad.exe", path); } - - private void openSettingsClicked(object? sender, EventArgs e) - { - ElixirKit.API.Publish("open", "/settings"); - } - - private void quitClicked(object? sender, EventArgs e) - { - notifyIcon.Visible = false; - Application.Exit(); - } } diff --git a/rel/app/windows/Livebook.csproj b/rel/app/windows/Livebook.csproj index e2a8cb3c512..d96b7166fbd 100644 --- a/rel/app/windows/Livebook.csproj +++ b/rel/app/windows/Livebook.csproj @@ -5,19 +5,24 @@ WinExe bin/Livebook-$(Configuration) bin/Livebook-$(Configuration) - net4.6-windows + net8.0-windows 10.0 win-x64 - false - true + true + true true Resources/AppIcon.ico - App.manifest + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/rel/app/windows/build_installer.sh b/rel/app/windows/build_installer.sh index c80ef122607..7a761be30b0 100755 --- a/rel/app/windows/build_installer.sh +++ b/rel/app/windows/build_installer.sh @@ -11,13 +11,6 @@ dotnet publish Livebook.csproj $build_args mix release app --overwrite --path=${target_dir}/rel ) -vc_redist_path="bin/vc_redist.x64.exe" -if [ ! -f $vc_redist_path ]; then - url="https://aka.ms/vs/17/release/vc_redist.x64.exe" - echo "downloading $url" - curl -L --fail --output $vc_redist_path $url -fi - makensis \ //DERTS_VERSION=`elixir -e "IO.puts :erlang.system_info(:version)"` \ //DLIVEBOOK_VERSION=`elixir -e "Mix.start() ; Mix.Project.in_project(:livebook, \"../../..\", fn _ -> IO.puts Mix.Project.config()[:version] end)"` \ From 0941be487903c4ac718e111319dd4e04c62b7378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Thu, 30 May 2024 20:55:55 +0200 Subject: [PATCH 05/11] Revert "ElixirKit: Target .NET 8" This reverts commit 3703a46461c85c41b0a2c1f44c1ac7e4b13669ba. --- elixirkit/elixirkit_dotnet/ElixirKit.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elixirkit/elixirkit_dotnet/ElixirKit.csproj b/elixirkit/elixirkit_dotnet/ElixirKit.csproj index 3cea7086ebb..51b1a6ff14d 100644 --- a/elixirkit/elixirkit_dotnet/ElixirKit.csproj +++ b/elixirkit/elixirkit_dotnet/ElixirKit.csproj @@ -1,7 +1,7 @@ - net8.0 + net46 10.0 enable From f2fcaa75c1bb05fbfa0050ffaf44b520d221d186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Thu, 30 May 2024 20:56:10 +0200 Subject: [PATCH 06/11] Revert "Implemented Livebook without Windows Forms. vc_redist.x64.exe is no longer required" This reverts commit ca04b02c90ffdabbbf474ad2d0af7b8542a6c227. --- rel/app/windows/App.manifest | 9 ++ rel/app/windows/Installer.nsi | 4 + rel/app/windows/Livebook.cs | 228 ++++++++++++++++------------- rel/app/windows/Livebook.csproj | 13 +- rel/app/windows/build_installer.sh | 7 + 5 files changed, 150 insertions(+), 111 deletions(-) create mode 100644 rel/app/windows/App.manifest diff --git a/rel/app/windows/App.manifest b/rel/app/windows/App.manifest new file mode 100644 index 00000000000..f2708ecb131 --- /dev/null +++ b/rel/app/windows/App.manifest @@ -0,0 +1,9 @@ + + + + + true + PerMonitorV2 + + + diff --git a/rel/app/windows/Installer.nsi b/rel/app/windows/Installer.nsi index 0881ab3d806..aa8d1ba8d65 100644 --- a/rel/app/windows/Installer.nsi +++ b/rel/app/windows/Installer.nsi @@ -30,6 +30,10 @@ FunctionEnd Section "Install" SetOutPath "$INSTDIR" + File "bin\vc_redist.x64.exe" + ExecWait '"$INSTDIR\vc_redist.x64.exe" /install /quiet /norestart' + Delete "$INSTDIR\vc_redist.x64.exe" + File /a /r "bin\Livebook-Release\" CreateDirectory "$LOCALAPPDATA\Livebook\Logs" diff --git a/rel/app/windows/Livebook.cs b/rel/app/windows/Livebook.cs index fbc236f4745..270173de7c7 100644 --- a/rel/app/windows/Livebook.cs +++ b/rel/app/windows/Livebook.cs @@ -2,144 +2,157 @@ using System.Diagnostics; using System.Drawing; using System.IO; -using System.Runtime.InteropServices; -using H.NotifyIcon.Core; -using TextCopy; +using System.Windows.Forms; #nullable enable namespace Livebook; -class TrayIconMenu: TrayIconWithContextMenu -{ - public new void Create() - { - base.Create(); - WindowUtilities.RunMessageLoop(); - } -} - static class LivebookMain { - [DllImport("User32.dll", CharSet = CharSet.Unicode)] - // https://learn.microsoft.com/de-de/windows/win32/api/winuser/nf-winuser-messagebox - static extern int MessageBox(IntPtr h, string m, string c, int type); - static int MB_OK = 0x00000000; - static int MB_ICONERROR = 0x00000010; - static string logPath = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "Livebook", - "Logs", - "Livebook.log" - ); - - static void ProcessExitHandler(object? sender, EventArgs eventArgs) - { - var elixirCode = ElixirKit.API.Stop(); - if (elixirCode != 0) - { - var message = $"Livebook exited with exit code {elixirCode}.\r\nLogs available at: {logPath}"; - MessageBox(0, message, "Error", MB_OK | MB_ICONERROR); - } - } - + [STAThread] static void Main(string[] args) { - AppDomain.CurrentDomain.ProcessExit += ProcessExitHandler; - var prefix = "open:"; var url = ""; if (args.Length == 1 && args[0].StartsWith(prefix)) { - var uri = new Uri(args[0].Remove(0, prefix.Length)); + var uri = new System.Uri(args[0].Remove(0, prefix.Length)); url = uri.AbsoluteUri; } - using var iconStream = H.Resources.AppIcon_ico.AsStream(); - using var icon = new Icon(iconStream); + var logPath = getLogPath(); - var notifyIcon = new TrayIconMenu + if (ElixirKit.API.IsMainInstance("dev.livebook.Livebook")) { - Icon = icon.Handle, - ToolTip = "Livebook", - Visibility = IconVisibility.Visible - }; - - notifyIcon.MessageWindow.MouseEventReceived += notifyIconClicked; - - var copyURLButton = new PopupMenuItem("Copy URL", (_, _) => ClipboardService.SetText(url)) + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new LivebookApp(url, logPath)); + + var code = ElixirKit.API.Stop(); + if (code == 0) { return; } + var message = $"Livebook exited with exit code {code}.\r\nLogs available at: {logPath}"; + MessageBox.Show(new Form() { TopMost = true }, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + else { - Enabled = false - }; + ElixirKit.API.Publish("open", url); + } + } + + internal static string getLogPath() + { + return Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "Livebook", + "Logs", + "Livebook.log" + ); + } +} + +class DummyForm : Form {} + +class LivebookApp : ApplicationContext +{ + private NotifyIcon notifyIcon; + private string? url; + private string logPath; + + public LivebookApp(string url, string logPath) + { + this.logPath = logPath; + + ThreadExit += threadExit; - notifyIcon.ContextMenu = new PopupMenu() + ContextMenuStrip menu = new ContextMenuStrip(); + menu.Items.Add("Open", null, openClicked); + menu.Items.Add("New Notebook", null, openNewNotebookClicked); + menu.Items.Add(new ToolStripSeparator()); + + var copyURLButton = menu.Items.Add("Copy URL", null, copyURLClicked); + copyURLButton.Enabled = false; + + menu.Items.Add("View Logs", null, viewLogsClicked); + menu.Items.Add("Open .livebookdesktop.bat", null, openBootScriptClicked); + menu.Items.Add(new ToolStripSeparator()); + menu.Items.Add("Settings", null, openSettingsClicked); + menu.Items.Add("Quit", null, quitClicked); + notifyIcon = new NotifyIcon() { - Items = - { - new PopupMenuItem("Open", (_, _) => ElixirKit.API.Publish("open", "")), - new PopupMenuItem("New Notebook", (_, _) => ElixirKit.API.Publish("open", "/new")), - new PopupMenuSeparator(), - copyURLButton, - new PopupMenuItem("View Logs", (_, _) => Process.Start("notepad.exe", logPath)), - new PopupMenuItem("Open .livebookdesktop.bat", (_, _) => openBootScriptClicked()), - new PopupMenuSeparator(), - new PopupMenuItem("Settings", (_, _) => ElixirKit.API.Publish("open", "/settings")), - new PopupMenuItem("Quit", (_, _) => { - notifyIcon.Dispose(); - AppDomain.CurrentDomain.ProcessExit -= ProcessExitHandler; - Environment.Exit(0); - }), - } + Text = "Livebook", + Visible = true, + Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath)!, + ContextMenuStrip = menu }; + notifyIcon.Click += notifyIconClicked; Directory.CreateDirectory(Path.GetDirectoryName(logPath)!); - if (ElixirKit.API.IsMainInstance("dev.livebook.Livebook")) - { - ElixirKit.API.Start( - name: "app", - logPath: logPath, - ready: () => { - ElixirKit.API.Subscribe((name, data) => - { - switch (name) - { - case "url": - copyURLButton.Enabled = true; - url = data; - break; - - default: - throw new Exception($"unknown event {name}"); - } - }); - - ElixirKit.API.Publish("open", url); - }, - exited: (exitCode) => + ElixirKit.API.Start( + name: "app", + logPath: logPath, + ready: () => { + ElixirKit.API.Subscribe((name, data) => { - Environment.Exit(exitCode); - } - ); + switch (name) + { + case "url": + copyURLButton.Enabled = true; + this.url = data; + break; + + default: + throw new Exception($"unknown event {name}"); + } + }); + + ElixirKit.API.Publish("open", url); + }, + exited: (exitCode) => + { + Application.Exit(); + } + ); + } - notifyIcon.Create(); - } - else - { - ElixirKit.API.Publish("open", url); - } + private void threadExit(object? sender, EventArgs e) + { + notifyIcon.Visible = false; } - static void notifyIconClicked(object? sender, MessageWindow.MouseEventReceivedEventArgs args) + private void notifyIconClicked(object? sender, EventArgs e) { - if (args.MouseEvent == MouseEvent.IconLeftMouseDown) + MouseEventArgs mouseEventArgs = (MouseEventArgs)e; + + if (mouseEventArgs.Button == MouseButtons.Left) { ElixirKit.API.Publish("open", ""); } } - static void openBootScriptClicked() + private void openClicked(object? sender, EventArgs e) + { + ElixirKit.API.Publish("open", ""); + } + + private void openNewNotebookClicked(object? sender, EventArgs e) + { + ElixirKit.API.Publish("open", "/new"); + } + + private void copyURLClicked(object? sender, EventArgs e) + { + System.Windows.Forms.Clipboard.SetText(url!); + } + + private void viewLogsClicked(object? sender, EventArgs e) + { + Process.Start(logPath); + } + + private void openBootScriptClicked(object? sender, EventArgs e) { var path = Path.Combine( @@ -165,4 +178,15 @@ static void openBootScriptClicked() Process.Start("notepad.exe", path); } + + private void openSettingsClicked(object? sender, EventArgs e) + { + ElixirKit.API.Publish("open", "/settings"); + } + + private void quitClicked(object? sender, EventArgs e) + { + notifyIcon.Visible = false; + Application.Exit(); + } } diff --git a/rel/app/windows/Livebook.csproj b/rel/app/windows/Livebook.csproj index d96b7166fbd..e2a8cb3c512 100644 --- a/rel/app/windows/Livebook.csproj +++ b/rel/app/windows/Livebook.csproj @@ -5,24 +5,19 @@ WinExe bin/Livebook-$(Configuration) bin/Livebook-$(Configuration) - net8.0-windows + net4.6-windows 10.0 win-x64 - true - true + false + true true Resources/AppIcon.ico + App.manifest - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - diff --git a/rel/app/windows/build_installer.sh b/rel/app/windows/build_installer.sh index 7a761be30b0..c80ef122607 100755 --- a/rel/app/windows/build_installer.sh +++ b/rel/app/windows/build_installer.sh @@ -11,6 +11,13 @@ dotnet publish Livebook.csproj $build_args mix release app --overwrite --path=${target_dir}/rel ) +vc_redist_path="bin/vc_redist.x64.exe" +if [ ! -f $vc_redist_path ]; then + url="https://aka.ms/vs/17/release/vc_redist.x64.exe" + echo "downloading $url" + curl -L --fail --output $vc_redist_path $url +fi + makensis \ //DERTS_VERSION=`elixir -e "IO.puts :erlang.system_info(:version)"` \ //DLIVEBOOK_VERSION=`elixir -e "Mix.start() ; Mix.Project.in_project(:livebook, \"../../..\", fn _ -> IO.puts Mix.Project.config()[:version] end)"` \ From 92b921ba989d922a102588f928fa04f4e9a62390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Thu, 30 May 2024 20:57:57 +0200 Subject: [PATCH 07/11] Removed vc_redist.x64.exe, since it requires admin rights --- rel/app/windows/Installer.nsi | 4 ---- rel/app/windows/build_installer.sh | 7 ------- 2 files changed, 11 deletions(-) diff --git a/rel/app/windows/Installer.nsi b/rel/app/windows/Installer.nsi index aa8d1ba8d65..0881ab3d806 100644 --- a/rel/app/windows/Installer.nsi +++ b/rel/app/windows/Installer.nsi @@ -30,10 +30,6 @@ FunctionEnd Section "Install" SetOutPath "$INSTDIR" - File "bin\vc_redist.x64.exe" - ExecWait '"$INSTDIR\vc_redist.x64.exe" /install /quiet /norestart' - Delete "$INSTDIR\vc_redist.x64.exe" - File /a /r "bin\Livebook-Release\" CreateDirectory "$LOCALAPPDATA\Livebook\Logs" diff --git a/rel/app/windows/build_installer.sh b/rel/app/windows/build_installer.sh index c80ef122607..7a761be30b0 100755 --- a/rel/app/windows/build_installer.sh +++ b/rel/app/windows/build_installer.sh @@ -11,13 +11,6 @@ dotnet publish Livebook.csproj $build_args mix release app --overwrite --path=${target_dir}/rel ) -vc_redist_path="bin/vc_redist.x64.exe" -if [ ! -f $vc_redist_path ]; then - url="https://aka.ms/vs/17/release/vc_redist.x64.exe" - echo "downloading $url" - curl -L --fail --output $vc_redist_path $url -fi - makensis \ //DERTS_VERSION=`elixir -e "IO.puts :erlang.system_info(:version)"` \ //DLIVEBOOK_VERSION=`elixir -e "Mix.start() ; Mix.Project.in_project(:livebook, \"../../..\", fn _ -> IO.puts Mix.Project.config()[:version] end)"` \ From dc36122ee715e01c8c3f26f706732a7f33ebd88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Sat, 22 Jun 2024 11:57:34 +0200 Subject: [PATCH 08/11] Revert "Removed vc_redist.x64.exe, since it requires admin rights" This reverts commit 92b921ba989d922a102588f928fa04f4e9a62390. --- rel/app/windows/Installer.nsi | 4 ++++ rel/app/windows/build_installer.sh | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/rel/app/windows/Installer.nsi b/rel/app/windows/Installer.nsi index 0881ab3d806..aa8d1ba8d65 100644 --- a/rel/app/windows/Installer.nsi +++ b/rel/app/windows/Installer.nsi @@ -30,6 +30,10 @@ FunctionEnd Section "Install" SetOutPath "$INSTDIR" + File "bin\vc_redist.x64.exe" + ExecWait '"$INSTDIR\vc_redist.x64.exe" /install /quiet /norestart' + Delete "$INSTDIR\vc_redist.x64.exe" + File /a /r "bin\Livebook-Release\" CreateDirectory "$LOCALAPPDATA\Livebook\Logs" diff --git a/rel/app/windows/build_installer.sh b/rel/app/windows/build_installer.sh index 7a761be30b0..c80ef122607 100755 --- a/rel/app/windows/build_installer.sh +++ b/rel/app/windows/build_installer.sh @@ -11,6 +11,13 @@ dotnet publish Livebook.csproj $build_args mix release app --overwrite --path=${target_dir}/rel ) +vc_redist_path="bin/vc_redist.x64.exe" +if [ ! -f $vc_redist_path ]; then + url="https://aka.ms/vs/17/release/vc_redist.x64.exe" + echo "downloading $url" + curl -L --fail --output $vc_redist_path $url +fi + makensis \ //DERTS_VERSION=`elixir -e "IO.puts :erlang.system_info(:version)"` \ //DLIVEBOOK_VERSION=`elixir -e "Mix.start() ; Mix.Project.in_project(:livebook, \"../../..\", fn _ -> IO.puts Mix.Project.config()[:version] end)"` \ From a8100aac2dbc02774b1df48286c2d6ee85bb4e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Sat, 22 Jun 2024 12:33:15 +0200 Subject: [PATCH 09/11] Write HKCU registry entries for the uninstaller --- rel/app/windows/Installer.nsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rel/app/windows/Installer.nsi b/rel/app/windows/Installer.nsi index aa8d1ba8d65..ea79fadd604 100644 --- a/rel/app/windows/Installer.nsi +++ b/rel/app/windows/Installer.nsi @@ -39,13 +39,13 @@ Section "Install" CreateDirectory "$LOCALAPPDATA\Livebook\Logs" WriteUninstaller "$INSTDIR\LivebookUninstall.exe" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayName" "Livebook" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayVersion" "${LIVEBOOK_VERSION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayIcon" "$INSTDIR\Livebook.exe" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "Publisher" "Dashbit" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "UninstallString" '"$INSTDIR\LivebookUninstall.exe"' - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "NoModify" 1 - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "NoRepair" 1 + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayName" "Livebook" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayVersion" "${LIVEBOOK_VERSION}" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayIcon" "$INSTDIR\Livebook.exe" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "Publisher" "Dashbit" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "UninstallString" '"$INSTDIR\LivebookUninstall.exe"' + WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "NoModify" 1 + WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "NoRepair" 1 WriteRegStr HKLM "Software\Dashbit\Livebook" "InstallRoot" "$INSTDIR" SectionEnd @@ -97,7 +97,7 @@ Section "Uninstall" DeleteRegKey HKCU "Software\Classes\.livemd" DeleteRegKey HKCU "Software\Classes\Livebook.LiveMarkdown" DeleteRegKey HKCU "Software\Classes\livebook" - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" + DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" DeleteRegKey HKLM "Software\Dashbit\Livebook" DeleteRegKey /ifempty HKLM "Software\Dashbit" From 9179c34362f93f38b93164cdd6f405afcaddbc06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Thu, 30 May 2024 12:12:25 +0200 Subject: [PATCH 10/11] Installer.nsi: Execute as user, write HKCU keys --- rel/app/windows/Installer.nsi | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/rel/app/windows/Installer.nsi b/rel/app/windows/Installer.nsi index f255277ef14..aa8d1ba8d65 100644 --- a/rel/app/windows/Installer.nsi +++ b/rel/app/windows/Installer.nsi @@ -10,7 +10,7 @@ Unicode True InstallDir "$LOCALAPPDATA\Livebook" ; Need admin for registering URL scheme -RequestExecutionLevel admin +RequestExecutionLevel user !define MUI_ABORTWARNING !define MUI_ICON "Resources\AppIcon.ico" @@ -77,26 +77,26 @@ SectionEnd Section "Install Handlers" DetailPrint "Registering .livemd File Handler" - DeleteRegKey HKCR ".livemd" - WriteRegStr HKCR ".livemd" "" "Livebook.LiveMarkdown" - DeleteRegKey HKCR "Livebook.LiveMarkdown" - WriteRegStr HKCR "Livebook.LiveMarkdown" "" "LiveMarkdown" - WriteRegStr HKCR "Livebook.LiveMarkdown\DefaultIcon" "" "$INSTDIR\Livebook.exe,1" - WriteRegStr HKCR "Livebook.LiveMarkdown\shell\open\command" "" '"$INSTDIR\Livebook.exe" "open:%1"' + DeleteRegKey HKCU "Software\Classes\.livemd" + WriteRegStr HKCU "Software\Classes\.livemd" "" "Livebook.LiveMarkdown" + DeleteRegKey HKCU "Software\Classes\Livebook.LiveMarkdown" + WriteRegStr HKCU "Software\Classes\Livebook.LiveMarkdown" "" "LiveMarkdown" + WriteRegStr HKCU "Software\Classes\Livebook.LiveMarkdown\DefaultIcon" "" "$INSTDIR\Livebook.exe,1" + WriteRegStr HKCU "Software\Classes\Livebook.LiveMarkdown\shell\open\command" "" '"$INSTDIR\Livebook.exe" "open:%1"' DetailPrint "Registering livebook URL Handler" - DeleteRegKey HKCR "livebook" - WriteRegStr HKCR "livebook" "" "Livebook URL Protocol" - WriteRegStr HKCR "livebook" "URL Protocol" "" - WriteRegStr HKCR "livebook\shell" "" "" - WriteRegStr HKCR "livebook\shell\open" "" "" - WriteRegStr HKCR "livebook\shell\open\command" "" '"$INSTDIR\Livebook.exe" "open:%1"' + DeleteRegKey HKCU "Software\Classes\livebook" + WriteRegStr HKCU "Software\Classes\livebook" "" "Livebook URL Protocol" + WriteRegStr HKCU "Software\Classes\livebook" "URL Protocol" "" + WriteRegStr HKCU "Software\Classes\livebook\shell" "" "" + WriteRegStr HKCU "Software\Classes\livebook\shell\open" "" "" + WriteRegStr HKCU "Software\Classes\livebook\shell\open\command" "" '"$INSTDIR\Livebook.exe" "open:%1"' SectionEnd Section "Uninstall" - DeleteRegKey HKCR ".livemd" - DeleteRegKey HKCR "Livebook.LiveMarkdown" - DeleteRegKey HKCR "livebook" + DeleteRegKey HKCU "Software\Classes\.livemd" + DeleteRegKey HKCU "Software\Classes\Livebook.LiveMarkdown" + DeleteRegKey HKCU "Software\Classes\livebook" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" DeleteRegKey HKLM "Software\Dashbit\Livebook" DeleteRegKey /ifempty HKLM "Software\Dashbit" From 9acf44e125ae302d9799dab25cc70ea5e4eb6eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marduk=20Bola=C3=B1os?= Date: Sat, 22 Jun 2024 12:33:15 +0200 Subject: [PATCH 11/11] Write HKCU registry entries for the uninstaller --- rel/app/windows/Installer.nsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rel/app/windows/Installer.nsi b/rel/app/windows/Installer.nsi index aa8d1ba8d65..ea79fadd604 100644 --- a/rel/app/windows/Installer.nsi +++ b/rel/app/windows/Installer.nsi @@ -39,13 +39,13 @@ Section "Install" CreateDirectory "$LOCALAPPDATA\Livebook\Logs" WriteUninstaller "$INSTDIR\LivebookUninstall.exe" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayName" "Livebook" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayVersion" "${LIVEBOOK_VERSION}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayIcon" "$INSTDIR\Livebook.exe" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "Publisher" "Dashbit" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "UninstallString" '"$INSTDIR\LivebookUninstall.exe"' - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "NoModify" 1 - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "NoRepair" 1 + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayName" "Livebook" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayVersion" "${LIVEBOOK_VERSION}" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "DisplayIcon" "$INSTDIR\Livebook.exe" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "Publisher" "Dashbit" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "UninstallString" '"$INSTDIR\LivebookUninstall.exe"' + WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "NoModify" 1 + WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" "NoRepair" 1 WriteRegStr HKLM "Software\Dashbit\Livebook" "InstallRoot" "$INSTDIR" SectionEnd @@ -97,7 +97,7 @@ Section "Uninstall" DeleteRegKey HKCU "Software\Classes\.livemd" DeleteRegKey HKCU "Software\Classes\Livebook.LiveMarkdown" DeleteRegKey HKCU "Software\Classes\livebook" - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" + DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Livebook" DeleteRegKey HKLM "Software\Dashbit\Livebook" DeleteRegKey /ifempty HKLM "Software\Dashbit"