@@ -18,18 +18,30 @@
|
||||
"i686-windows"
|
||||
"x86_64-windows"
|
||||
];
|
||||
|
||||
in flake-utils.lib.eachSystem systems (system:
|
||||
let
|
||||
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
|
||||
lib = pkgs.lib;
|
||||
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
|
||||
features = builtins.concatStringsSep " " (builtins.concatMap
|
||||
({ option, features }: pkgs.lib.optionals option features) [
|
||||
({ option, features }: lib.optionals option features) [
|
||||
{
|
||||
option = webgui;
|
||||
features = [ "webgui" ];
|
||||
@@ -38,55 +50,40 @@
|
||||
option = doh;
|
||||
features = [ "doh" ];
|
||||
}
|
||||
{
|
||||
option = edge;
|
||||
features = [ "edge" ];
|
||||
}
|
||||
]);
|
||||
in naersk-lib.buildPackage {
|
||||
pname = "alfis";
|
||||
nativeBuildInputs = with pkgs; [ pkg-config webkitgtk kdialog ];
|
||||
dontWrapQtApps = true;
|
||||
root = ./.;
|
||||
nativeBuildInputs = guiNativeBuildInputs;
|
||||
buildInputs = guiBuildInputs;
|
||||
cargoBuildOptions = opts:
|
||||
opts ++ [ "--no-default-features" ]
|
||||
++ [ "--features" ''"${features}"'' ];
|
||||
root = ./.;
|
||||
++ lib.optionals (features != "") [ "--features" features ];
|
||||
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 {
|
||||
|
||||
packages = {
|
||||
alfis = alfis {
|
||||
webgui = true;
|
||||
doh = true;
|
||||
edge = false;
|
||||
};
|
||||
alfisWithoutGUI = alfis {
|
||||
webgui = false;
|
||||
doh = true;
|
||||
edge = false;
|
||||
};
|
||||
} // pkgs.lib.optionalAttrs isWindows {
|
||||
alfisEdge = alfis {
|
||||
webgui = false;
|
||||
doh = true;
|
||||
edge = true;
|
||||
};
|
||||
};
|
||||
|
||||
defaultPackage = packages.alfis;
|
||||
|
||||
apps = with flake-utils.lib;
|
||||
{
|
||||
alfis = mkApp { drv = packages.alfis; };
|
||||
alfisWithoutGUI = mkApp { drv = packages.alfisWithoutGUI; };
|
||||
} // pkgs.lib.optionalAttrs isWindows {
|
||||
alfisEdge = mkApp { drv = packages.alfisEdge; };
|
||||
};
|
||||
apps = with flake-utils.lib; {
|
||||
alfis = mkApp { drv = packages.alfis; };
|
||||
alfisWithoutGUI = mkApp { drv = packages.alfisWithoutGUI; };
|
||||
};
|
||||
|
||||
defaultApp = apps.alfis;
|
||||
|
||||
devShell = import ./shell.nix { inherit pkgs; };
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
{ 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 {
|
||||
buildInputs =
|
||||
[ pkgs.cargo pkgs.rustc pkgs.webkitgtk pkgs.pkg-config pkgs.kdialog ];
|
||||
buildInputs = packages;
|
||||
LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath runtimeLibs;
|
||||
}
|
||||
|
||||
+14
@@ -148,6 +148,20 @@ fn main() {
|
||||
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)]
|
||||
if opt_matches.opt_present("service") {
|
||||
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 tinyfiledialogs as tfd;
|
||||
|
||||
use std::panic::{self, AssertUnwindSafe};
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
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"))]
|
||||
let icon = load_icon_from_png();
|
||||
|
||||
let tray_icon = TrayIconBuilder::new()
|
||||
.with_menu(Box::new(tray_menu))
|
||||
.with_tooltip(&title)
|
||||
.with_icon(icon)
|
||||
.with_menu_on_left_click(false)
|
||||
.build()
|
||||
.unwrap();
|
||||
let tray_icon = build_tray_icon(&title, tray_menu, icon);
|
||||
let tray_available = tray_icon.is_some();
|
||||
|
||||
let window_size = tao::dpi::LogicalSize::new(1024, 720);
|
||||
// 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_min_inner_size(tao::dpi::LogicalSize::new(773, 350))
|
||||
.with_resizable(true)
|
||||
.with_visible(!hide);
|
||||
.with_visible(!hide || !tray_available);
|
||||
|
||||
if let Some(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
|
||||
});
|
||||
|
||||
let proxy = event_loop.create_proxy();
|
||||
TrayIconEvent::set_event_handler(Some(move |event| {
|
||||
let _ = proxy.send_event(UserEvent::TrayIconEvent(event));
|
||||
}));
|
||||
if tray_available {
|
||||
let proxy = event_loop.create_proxy();
|
||||
TrayIconEvent::set_event_handler(Some(move |event| {
|
||||
let _ = proxy.send_event(UserEvent::TrayIconEvent(event));
|
||||
}));
|
||||
|
||||
let proxy = event_loop.create_proxy();
|
||||
MenuEvent::set_event_handler(Some(move |event| {
|
||||
let _ = proxy.send_event(UserEvent::MenuEvent(event));
|
||||
}));
|
||||
let proxy = event_loop.create_proxy();
|
||||
MenuEvent::set_event_handler(Some(move |event| {
|
||||
let _ = proxy.send_event(UserEvent::MenuEvent(event));
|
||||
}));
|
||||
}
|
||||
|
||||
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,
|
||||
..
|
||||
} => {
|
||||
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) => {
|
||||
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);
|
||||
}
|
||||
UserEvent::TrayIconEvent(event) => {
|
||||
match event {
|
||||
TrayIconEvent::DoubleClick { button, .. } => {
|
||||
if button == tray_icon::MouseButton::Left {
|
||||
window.set_visible(true);
|
||||
window.set_focus();
|
||||
if let Some(tray_icon) = tray_icon.as_ref() {
|
||||
match event {
|
||||
TrayIconEvent::DoubleClick { button, .. } => {
|
||||
if button == tray_icon::MouseButton::Left {
|
||||
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) => {
|
||||
@@ -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)]
|
||||
enum UserEvent {
|
||||
EvalJs(String),
|
||||
|
||||
Reference in New Issue
Block a user