@@ -18,18 +18,30 @@
|
|||||||
"i686-windows"
|
"i686-windows"
|
||||||
"x86_64-windows"
|
"x86_64-windows"
|
||||||
];
|
];
|
||||||
|
|
||||||
in flake-utils.lib.eachSystem systems (system:
|
in flake-utils.lib.eachSystem systems (system:
|
||||||
let
|
let
|
||||||
|
|
||||||
pkgs = nixpkgs.legacyPackages.${system};
|
pkgs = nixpkgs.legacyPackages.${system};
|
||||||
|
lib = pkgs.lib;
|
||||||
naersk-lib = naersk.lib.${system};
|
naersk-lib = naersk.lib.${system};
|
||||||
|
isLinux = pkgs.stdenv.hostPlatform.isLinux;
|
||||||
|
|
||||||
alfis = { webgui ? true, doh ? true, edge ? false }:
|
guiBuildInputs = lib.optionals isLinux (with pkgs; [
|
||||||
|
gtk3
|
||||||
|
webkitgtk_4_1
|
||||||
|
xdotool
|
||||||
|
libayatana-appindicator
|
||||||
|
]);
|
||||||
|
|
||||||
|
guiNativeBuildInputs = [ pkgs.pkg-config ]
|
||||||
|
++ lib.optionals isLinux [ pkgs.makeWrapper pkgs.wrapGAppsHook ];
|
||||||
|
|
||||||
|
guiRuntimeTools = lib.optionals isLinux [ pkgs.kdePackages.kdialog ];
|
||||||
|
guiRuntimeLibPath = lib.optionalString isLinux (lib.makeLibraryPath guiBuildInputs);
|
||||||
|
|
||||||
|
alfis = { webgui ? true, doh ? true }:
|
||||||
let
|
let
|
||||||
features = builtins.concatStringsSep " " (builtins.concatMap
|
features = builtins.concatStringsSep " " (builtins.concatMap
|
||||||
({ option, features }: pkgs.lib.optionals option features) [
|
({ option, features }: lib.optionals option features) [
|
||||||
{
|
{
|
||||||
option = webgui;
|
option = webgui;
|
||||||
features = [ "webgui" ];
|
features = [ "webgui" ];
|
||||||
@@ -38,55 +50,40 @@
|
|||||||
option = doh;
|
option = doh;
|
||||||
features = [ "doh" ];
|
features = [ "doh" ];
|
||||||
}
|
}
|
||||||
{
|
|
||||||
option = edge;
|
|
||||||
features = [ "edge" ];
|
|
||||||
}
|
|
||||||
]);
|
]);
|
||||||
in naersk-lib.buildPackage {
|
in naersk-lib.buildPackage {
|
||||||
pname = "alfis";
|
pname = "alfis";
|
||||||
nativeBuildInputs = with pkgs; [ pkg-config webkitgtk kdialog ];
|
root = ./.;
|
||||||
dontWrapQtApps = true;
|
nativeBuildInputs = guiNativeBuildInputs;
|
||||||
|
buildInputs = guiBuildInputs;
|
||||||
cargoBuildOptions = opts:
|
cargoBuildOptions = opts:
|
||||||
opts ++ [ "--no-default-features" ]
|
opts ++ [ "--no-default-features" ]
|
||||||
++ [ "--features" ''"${features}"'' ];
|
++ lib.optionals (features != "") [ "--features" features ];
|
||||||
root = ./.;
|
preFixup = lib.optionalString isLinux ''
|
||||||
|
gappsWrapperArgs+=(--prefix PATH : "${lib.makeBinPath guiRuntimeTools}")
|
||||||
|
gappsWrapperArgs+=(--prefix LD_LIBRARY_PATH : "${guiRuntimeLibPath}")
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
isWindows = builtins.elem system [ "i686-windows" "x86_64-windows" ];
|
|
||||||
in rec {
|
in rec {
|
||||||
|
|
||||||
packages = {
|
packages = {
|
||||||
alfis = alfis {
|
alfis = alfis {
|
||||||
webgui = true;
|
webgui = true;
|
||||||
doh = true;
|
doh = true;
|
||||||
edge = false;
|
|
||||||
};
|
};
|
||||||
alfisWithoutGUI = alfis {
|
alfisWithoutGUI = alfis {
|
||||||
webgui = false;
|
webgui = false;
|
||||||
doh = true;
|
doh = true;
|
||||||
edge = false;
|
|
||||||
};
|
|
||||||
} // pkgs.lib.optionalAttrs isWindows {
|
|
||||||
alfisEdge = alfis {
|
|
||||||
webgui = false;
|
|
||||||
doh = true;
|
|
||||||
edge = true;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
defaultPackage = packages.alfis;
|
defaultPackage = packages.alfis;
|
||||||
|
|
||||||
apps = with flake-utils.lib;
|
apps = with flake-utils.lib; {
|
||||||
{
|
alfis = mkApp { drv = packages.alfis; };
|
||||||
alfis = mkApp { drv = packages.alfis; };
|
alfisWithoutGUI = mkApp { drv = packages.alfisWithoutGUI; };
|
||||||
alfisWithoutGUI = mkApp { drv = packages.alfisWithoutGUI; };
|
};
|
||||||
} // pkgs.lib.optionalAttrs isWindows {
|
|
||||||
alfisEdge = mkApp { drv = packages.alfisEdge; };
|
|
||||||
};
|
|
||||||
defaultApp = apps.alfis;
|
defaultApp = apps.alfis;
|
||||||
|
|
||||||
devShell = import ./shell.nix { inherit pkgs; };
|
devShell = import ./shell.nix { inherit pkgs; };
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,21 @@
|
|||||||
{ pkgs ? import <nixpkgs> { } }:
|
{ pkgs ? import <nixpkgs> { } }:
|
||||||
|
|
||||||
|
let
|
||||||
|
runtimeLibs = with pkgs; [
|
||||||
|
gtk3
|
||||||
|
webkitgtk_4_1
|
||||||
|
xdotool
|
||||||
|
libayatana-appindicator
|
||||||
|
];
|
||||||
|
|
||||||
|
packages = with pkgs; [
|
||||||
|
cargo
|
||||||
|
rustc
|
||||||
|
pkg-config
|
||||||
|
kdePackages.kdialog
|
||||||
|
] ++ runtimeLibs;
|
||||||
|
in
|
||||||
pkgs.mkShell {
|
pkgs.mkShell {
|
||||||
buildInputs =
|
buildInputs = packages;
|
||||||
[ pkgs.cargo pkgs.rustc pkgs.webkitgtk pkgs.pkg-config pkgs.kdialog ];
|
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath runtimeLibs;
|
||||||
}
|
}
|
||||||
|
|||||||
+14
@@ -148,6 +148,20 @@ fn main() {
|
|||||||
no_gui = true;
|
no_gui = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "webgui", target_os = "linux"))]
|
||||||
|
if !no_gui {
|
||||||
|
let running_via_sudo = env::var_os("SUDO_UID").is_some();
|
||||||
|
let has_graphical_session = env::var_os("DISPLAY").is_some() || env::var_os("WAYLAND_DISPLAY").is_some();
|
||||||
|
|
||||||
|
if running_via_sudo {
|
||||||
|
warn!(target: LOG_TARGET_MAIN, "Running GUI via sudo is not supported on Linux, starting without GUI");
|
||||||
|
no_gui = true;
|
||||||
|
} else if !has_graphical_session {
|
||||||
|
warn!(target: LOG_TARGET_MAIN, "No graphical session detected, starting without GUI");
|
||||||
|
no_gui = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
if opt_matches.opt_present("service") {
|
if opt_matches.opt_present("service") {
|
||||||
let appdata = env::var("PROGRAMDATA").expect("Failed to get APPDATA directory");
|
let appdata = env::var("PROGRAMDATA").expect("Failed to get APPDATA directory");
|
||||||
|
|||||||
+63
-28
@@ -3,6 +3,7 @@ extern crate serde;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate tinyfiledialogs as tfd;
|
extern crate tinyfiledialogs as tfd;
|
||||||
|
|
||||||
|
use std::panic::{self, AssertUnwindSafe};
|
||||||
use std::sync::{Arc, Mutex, MutexGuard};
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
@@ -61,13 +62,8 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, hid
|
|||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
let icon = load_icon_from_png();
|
let icon = load_icon_from_png();
|
||||||
|
|
||||||
let tray_icon = TrayIconBuilder::new()
|
let tray_icon = build_tray_icon(&title, tray_menu, icon);
|
||||||
.with_menu(Box::new(tray_menu))
|
let tray_available = tray_icon.is_some();
|
||||||
.with_tooltip(&title)
|
|
||||||
.with_icon(icon)
|
|
||||||
.with_menu_on_left_click(false)
|
|
||||||
.build()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let window_size = tao::dpi::LogicalSize::new(1024, 720);
|
let window_size = tao::dpi::LogicalSize::new(1024, 720);
|
||||||
// Get primary monitor and calculate center position
|
// Get primary monitor and calculate center position
|
||||||
@@ -90,7 +86,7 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, hid
|
|||||||
.with_inner_size(window_size)
|
.with_inner_size(window_size)
|
||||||
.with_min_inner_size(tao::dpi::LogicalSize::new(773, 350))
|
.with_min_inner_size(tao::dpi::LogicalSize::new(773, 350))
|
||||||
.with_resizable(true)
|
.with_resizable(true)
|
||||||
.with_visible(!hide);
|
.with_visible(!hide || !tray_available);
|
||||||
|
|
||||||
if let Some(position) = position {
|
if let Some(position) = position {
|
||||||
builder = builder.with_position(position);
|
builder = builder.with_position(position);
|
||||||
@@ -319,15 +315,17 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, hid
|
|||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
|
||||||
let proxy = event_loop.create_proxy();
|
if tray_available {
|
||||||
TrayIconEvent::set_event_handler(Some(move |event| {
|
let proxy = event_loop.create_proxy();
|
||||||
let _ = proxy.send_event(UserEvent::TrayIconEvent(event));
|
TrayIconEvent::set_event_handler(Some(move |event| {
|
||||||
}));
|
let _ = proxy.send_event(UserEvent::TrayIconEvent(event));
|
||||||
|
}));
|
||||||
|
|
||||||
let proxy = event_loop.create_proxy();
|
let proxy = event_loop.create_proxy();
|
||||||
MenuEvent::set_event_handler(Some(move |event| {
|
MenuEvent::set_event_handler(Some(move |event| {
|
||||||
let _ = proxy.send_event(UserEvent::MenuEvent(event));
|
let _ = proxy.send_event(UserEvent::MenuEvent(event));
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
let proxy = event_loop.create_proxy();
|
let proxy = event_loop.create_proxy();
|
||||||
|
|
||||||
@@ -340,7 +338,14 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, hid
|
|||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
window.set_visible(false);
|
if tray_available {
|
||||||
|
window.set_visible(false);
|
||||||
|
} else {
|
||||||
|
info!("Interface closed, exiting");
|
||||||
|
post(Event::ActionQuit);
|
||||||
|
thread::sleep(Duration::from_millis(100));
|
||||||
|
*control_flow = ControlFlow::Exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TaoEvent::UserEvent(user_event) => {
|
TaoEvent::UserEvent(user_event) => {
|
||||||
let wv = webview_clone.lock().unwrap();
|
let wv = webview_clone.lock().unwrap();
|
||||||
@@ -364,19 +369,21 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, hid
|
|||||||
show_warning(&wv, &text);
|
show_warning(&wv, &text);
|
||||||
}
|
}
|
||||||
UserEvent::TrayIconEvent(event) => {
|
UserEvent::TrayIconEvent(event) => {
|
||||||
match event {
|
if let Some(tray_icon) = tray_icon.as_ref() {
|
||||||
TrayIconEvent::DoubleClick { button, .. } => {
|
match event {
|
||||||
if button == tray_icon::MouseButton::Left {
|
TrayIconEvent::DoubleClick { button, .. } => {
|
||||||
window.set_visible(true);
|
if button == tray_icon::MouseButton::Left {
|
||||||
window.set_focus();
|
window.set_visible(true);
|
||||||
|
window.set_focus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
TrayIconEvent::Enter { .. } => {
|
||||||
|
let nodes = connected_nodes.load(Ordering::SeqCst);
|
||||||
|
let title = format!("ALFIS {}\nConnected: {nodes}", env!("CARGO_PKG_VERSION"));
|
||||||
|
let _ = tray_icon.set_tooltip(Some(title));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
TrayIconEvent::Enter { .. } => {
|
|
||||||
let nodes = connected_nodes.load(Ordering::SeqCst);
|
|
||||||
let title = format!("ALFIS {}\nConnected: {nodes}", env!("CARGO_PKG_VERSION"));
|
|
||||||
let _ = tray_icon.set_tooltip(Some(title));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UserEvent::MenuEvent(event) => {
|
UserEvent::MenuEvent(event) => {
|
||||||
@@ -396,6 +403,34 @@ pub fn run_interface(context: Arc<Mutex<Context>>, miner: Arc<Mutex<Miner>>, hid
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_tray_icon(title: &str, tray_menu: Menu, icon: tray_icon::Icon) -> Option<tray_icon::TrayIcon> {
|
||||||
|
let previous_hook = panic::take_hook();
|
||||||
|
panic::set_hook(Box::new(|_| {}));
|
||||||
|
|
||||||
|
let result = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||||
|
TrayIconBuilder::new()
|
||||||
|
.with_menu(Box::new(tray_menu))
|
||||||
|
.with_tooltip(title)
|
||||||
|
.with_icon(icon)
|
||||||
|
.with_menu_on_left_click(false)
|
||||||
|
.build()
|
||||||
|
}));
|
||||||
|
|
||||||
|
panic::set_hook(previous_hook);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(Ok(tray_icon)) => Some(tray_icon),
|
||||||
|
Ok(Err(error)) => {
|
||||||
|
warn!("Tray icon is unavailable: {error}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
warn!("Tray icon is unavailable: failed to load appindicator library, continuing without tray support");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum UserEvent {
|
enum UserEvent {
|
||||||
EvalJs(String),
|
EvalJs(String),
|
||||||
|
|||||||
Reference in New Issue
Block a user