I concede on the Wayland display server always-on-top support. Not my battle. Not likely to be supported (by wayland).
This commit is contained in:
parent
06c7ec0f4d
commit
bbd068e829
|
|
@ -75,7 +75,7 @@ debug = []
|
||||||
# Linux front-end providers — exactly one selected at build time.
|
# Linux front-end providers — exactly one selected at build time.
|
||||||
# build.sh detects the running WM and sets this for you.
|
# build.sh detects the running WM and sets this for you.
|
||||||
x11 = ["dep:x11-dl"]
|
x11 = ["dep:x11-dl"]
|
||||||
wayland = ["dep:smithay-client-toolkit", "dep:wayland-client"]
|
wayland = []
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
windows = { version = "0.58", features = [
|
windows = { version = "0.58", features = [
|
||||||
|
|
@ -86,5 +86,3 @@ windows = { version = "0.58", features = [
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
x11-dl = { version = "2", optional = true }
|
x11-dl = { version = "2", optional = true }
|
||||||
smithay-client-toolkit = { version = "0.20", optional = true }
|
|
||||||
wayland-client = { version = "0.31", optional = true }
|
|
||||||
|
|
|
||||||
|
|
@ -37,18 +37,13 @@ detect_wm_feature() {
|
||||||
echo "$LAYERS_FEATURES"
|
echo "$LAYERS_FEATURES"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
# Native Wayland session AND a compositor known to ship wlr-layer-shell.
|
# Native Wayland session — use the wayland provider (winit xdg-toplevel,
|
||||||
|
# render transparency, user pins on top via compositor).
|
||||||
if [ -n "${WAYLAND_DISPLAY:-}" ]; then
|
if [ -n "${WAYLAND_DISPLAY:-}" ]; then
|
||||||
case "${XDG_CURRENT_DESKTOP:-}" in
|
echo "wayland"
|
||||||
*COSMIC*|*KDE*|*Plasma*|sway|Hyprland|niri|river|Wayfire)
|
return
|
||||||
echo "wayland"
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
fi
|
||||||
# GNOME-Wayland (mutter, no layer-shell), every X11 session, every other
|
# X11 session or no WAYLAND_DISPLAY: use the X11 provider.
|
||||||
# GTK3-class compositor: ship the X11 provider — XWayland honours the hints
|
|
||||||
# everywhere except cosmic-comp, where the wayland provider applies instead.
|
|
||||||
echo "x11"
|
echo "x11"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,11 @@ case "$(uname -s)" in
|
||||||
*) echo "wrong platform: $(uname -s) — use cargo xtask install" >&2; exit 1;;
|
*) echo "wrong platform: $(uname -s) — use cargo xtask install" >&2; exit 1;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
bash "$ROOT/scripts/linux/build.sh"
|
|
||||||
|
|
||||||
STAGE="$ROOT/build/bin/com.jesshunter.layers"
|
STAGE="$ROOT/build/bin/com.jesshunter.layers"
|
||||||
PLUGIN_ID="com.jesshunter.layers"
|
PLUGIN_ID="com.jesshunter.layers"
|
||||||
|
|
||||||
# Drop into every existing KiCad >=10 install we can find — native and flatpak,
|
# Installs into every existing KiCad >=10 plugins dir — native and flatpak.
|
||||||
# every version dir KiCad has already created. We never mkdir kicad/<ver>/plugins;
|
# Does not mkdir kicad/<ver>/plugins; KiCad creates it on first launch.
|
||||||
# KiCad creates it on first launch and we only fill in our own subdir.
|
|
||||||
install_to_kicad_root() {
|
install_to_kicad_root() {
|
||||||
local kicad_root="$1"
|
local kicad_root="$1"
|
||||||
[ -d "$kicad_root" ] || return 1
|
[ -d "$kicad_root" ] || return 1
|
||||||
|
|
@ -46,8 +43,19 @@ NATIVE_ROOT="${XDG_DATA_HOME:-$HOME/.local/share}/kicad"
|
||||||
FLATPAK_ROOT="$HOME/.var/app/org.kicad.KiCad/data/kicad"
|
FLATPAK_ROOT="$HOME/.var/app/org.kicad.KiCad/data/kicad"
|
||||||
|
|
||||||
ok=0
|
ok=0
|
||||||
install_to_kicad_root "$NATIVE_ROOT" && ok=1 || true
|
|
||||||
install_to_kicad_root "$FLATPAK_ROOT" && ok=1 || true
|
# Native install: build with the front-end matching the host's WM (build.sh
|
||||||
|
# autodetects unless LAYERS_FEATURES is set).
|
||||||
|
if [ -d "$NATIVE_ROOT" ]; then
|
||||||
|
bash "$ROOT/scripts/linux/build.sh"
|
||||||
|
install_to_kicad_root "$NATIVE_ROOT" && ok=1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Flatpak install: force the X11 front-end.
|
||||||
|
if [ -d "$FLATPAK_ROOT" ]; then
|
||||||
|
LAYERS_FEATURES=x11 bash "$ROOT/scripts/linux/build.sh"
|
||||||
|
install_to_kicad_root "$FLATPAK_ROOT" && ok=1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$ok" -eq 0 ]; then
|
if [ "$ok" -eq 0 ]; then
|
||||||
echo "no KiCad 10+ install detected. checked:" >&2
|
echo "no KiCad 10+ install detected. checked:" >&2
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ struct LayersColors {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Minimal key=value extractor for the flat subset we care about.
|
/// key=value extractor for the subset.
|
||||||
/// Returns dotted "section.key" → numeric value.
|
/// Returns dotted "section.key" → numeric value.
|
||||||
private static func flatten(_ source: String) -> [String: Double] {
|
private static func flatten(_ source: String) -> [String: Double] {
|
||||||
var out: [String: Double] = [:]
|
var out: [String: Double] = [:]
|
||||||
|
|
|
||||||
|
|
@ -36,14 +36,7 @@ fn main() {
|
||||||
tracing::info!(provider = PROVIDER_NAME, "shell route: provider chosen at build time");
|
tracing::info!(provider = PROVIDER_NAME, "shell route: provider chosen at build time");
|
||||||
|
|
||||||
#[cfg(all(target_os = "linux", feature = "wayland"))]
|
#[cfg(all(target_os = "linux", feature = "wayland"))]
|
||||||
{
|
tracing::info!(provider = PROVIDER_NAME, "wayland: using winit xdg-toplevel (compositor provides pin-on-top via title bar)");
|
||||||
if layers::wayland_shell::try_run() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tracing::warn!(
|
|
||||||
"wayland provider failed to start; falling through to winit so the plugin still loads"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(run)) {
|
if let Err(e) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(run)) {
|
||||||
tracing::error!("layers shell panicked: {e:?}");
|
tracing::error!("layers shell panicked: {e:?}");
|
||||||
|
|
@ -52,7 +45,7 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(target_os = "linux", feature = "wayland"))]
|
#[cfg(all(target_os = "linux", feature = "wayland"))]
|
||||||
const PROVIDER_NAME: &str = "linux/wayland (sctk + wlr-layer-shell)";
|
const PROVIDER_NAME: &str = "linux/wayland (winit + xdg-toplevel)";
|
||||||
#[cfg(all(target_os = "linux", feature = "x11", not(feature = "wayland")))]
|
#[cfg(all(target_os = "linux", feature = "x11", not(feature = "wayland")))]
|
||||||
const PROVIDER_NAME: &str = "linux/x11 (winit + xlib)";
|
const PROVIDER_NAME: &str = "linux/x11 (winit + xlib)";
|
||||||
#[cfg(all(target_os = "linux", not(feature = "x11"), not(feature = "wayland")))]
|
#[cfg(all(target_os = "linux", not(feature = "x11"), not(feature = "wayland")))]
|
||||||
|
|
@ -159,8 +152,21 @@ impl ApplicationHandler for ShellApp {
|
||||||
.with_inner_size(LogicalSize::new(DEFAULT_LOGICAL_SIZE.0, DEFAULT_LOGICAL_SIZE.1))
|
.with_inner_size(LogicalSize::new(DEFAULT_LOGICAL_SIZE.0, DEFAULT_LOGICAL_SIZE.1))
|
||||||
.with_min_inner_size(LogicalSize::new(MIN_LOGICAL_SIZE.0, MIN_LOGICAL_SIZE.1))
|
.with_min_inner_size(LogicalSize::new(MIN_LOGICAL_SIZE.0, MIN_LOGICAL_SIZE.1))
|
||||||
.with_transparent(true)
|
.with_transparent(true)
|
||||||
.with_decorations(true)
|
.with_decorations(true);
|
||||||
.with_window_level(WindowLevel::AlwaysOnTop);
|
|
||||||
|
// On Wayland, always-on-top is the user's choice (only) I mulled it over. Why fight intent?
|
||||||
|
// Who am I to decide what's important? I have thought of a way to do it though, I think. So if any
|
||||||
|
// wayland users DO end up asking me for this feature, I'll add it.
|
||||||
|
// I'd add a cfg to the board change poll that only exists on wayland detected builds, it would use
|
||||||
|
// xdg activation to steal back top level. I think it would work, but it might be too
|
||||||
|
// invasive if it has to take focus as well as return to top. All around, wayland just isn't
|
||||||
|
// meant to do this. Sorry Ubuntu/Gnome/Pop_OS! users. If you use wayland and have any
|
||||||
|
// ideas,
|
||||||
|
// please do let me know.
|
||||||
|
|
||||||
|
// On other platforms it is set programmatically.
|
||||||
|
#[cfg(not(all(target_os = "linux", feature = "wayland")))]
|
||||||
|
let attrs = attrs.with_window_level(WindowLevel::AlwaysOnTop);
|
||||||
|
|
||||||
let window = event_loop
|
let window = event_loop
|
||||||
.create_window(attrs)
|
.create_window(attrs)
|
||||||
|
|
@ -457,8 +463,7 @@ fn set_window_alpha(window: &Window, alpha: f32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// macOS path: NSWindow.alphaValue is set in Swift; Rust side is a no-op.
|
///
|
||||||
// Linux/wayland builds bake alpha into render output (planned), not a window hint.
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
target_os = "macos",
|
target_os = "macos",
|
||||||
target_os = "ios",
|
target_os = "ios",
|
||||||
|
|
|
||||||
|
|
@ -609,8 +609,12 @@ fn render(handle: &mut ViewportHandle) {
|
||||||
ui.draw(&mut handle.renderer, &theme, &style, handle.cursor);
|
ui.draw(&mut handle.renderer, &theme, &style, handle.cursor);
|
||||||
handle.cache = ui.into_cache();
|
handle.cache = ui.into_cache();
|
||||||
|
|
||||||
// NSWindow.alphaValue in Swift fades the composited surface; keep this opaque.
|
// macOS/Windows/X11: the OS fades the composited surface via window-level alpha.
|
||||||
let background = crate::ui::theme::compositor_clear();
|
// Wayland: no window-level opacity; clear with alpha=0 for transparent background.
|
||||||
|
// background; the UI content renders opaque on top.
|
||||||
|
let mut background = crate::ui::theme::compositor_clear();
|
||||||
|
#[cfg(all(target_os = "linux", feature = "wayland"))]
|
||||||
|
{ background.a = 0.0; }
|
||||||
handle.renderer.present(
|
handle.renderer.present(
|
||||||
Some(background),
|
Some(background),
|
||||||
handle.format,
|
handle.format,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,3 @@ pub mod single_instance;
|
||||||
pub mod snapshot;
|
pub mod snapshot;
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod version;
|
pub mod version;
|
||||||
|
|
||||||
#[cfg(all(target_os = "linux", feature = "wayland"))]
|
|
||||||
pub mod wayland_shell;
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ pub fn plugin_dir() -> PathBuf {
|
||||||
|
|
||||||
/// User-writable runtime data root: logs, state, cache, settings, runtime sockets.
|
/// User-writable runtime data root: logs, state, cache, settings, runtime sockets.
|
||||||
/// Decoupled from the plugin install location so a flatpak KiCad (which sandboxes
|
/// Decoupled from the plugin install location so a flatpak KiCad (which sandboxes
|
||||||
/// its own data dirs) still writes somewhere we can `tail -f` from a normal shell.
|
/// its own data dirs) still writes somewhere accessible from a normal shell.
|
||||||
pub fn data_dir() -> PathBuf {
|
pub fn data_dir() -> PathBuf {
|
||||||
if let Ok(v) = std::env::var("LAYERS_DATA_DIR") {
|
if let Ok(v) = std::env::var("LAYERS_DATA_DIR") {
|
||||||
if !v.is_empty() {
|
if !v.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ pub fn try_run() -> bool {
|
||||||
let layer = layer_shell.create_layer_surface(
|
let layer = layer_shell.create_layer_surface(
|
||||||
&qh,
|
&qh,
|
||||||
surface,
|
surface,
|
||||||
Layer::Top,
|
Layer::Overlay,
|
||||||
Some("layers"),
|
Some("layers"),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
@ -145,6 +145,8 @@ pub fn try_run() -> bool {
|
||||||
first_configure: true,
|
first_configure: true,
|
||||||
raw_display,
|
raw_display,
|
||||||
raw_window,
|
raw_window,
|
||||||
|
focused: false,
|
||||||
|
hovered: false,
|
||||||
exit: false,
|
exit: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -175,6 +177,8 @@ struct State {
|
||||||
first_configure: bool,
|
first_configure: bool,
|
||||||
raw_display: RawDisplayHandle,
|
raw_display: RawDisplayHandle,
|
||||||
raw_window: RawWindowHandle,
|
raw_window: RawWindowHandle,
|
||||||
|
focused: bool,
|
||||||
|
hovered: bool,
|
||||||
exit: bool,
|
exit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -202,6 +206,7 @@ impl State {
|
||||||
|
|
||||||
fn render(&mut self, qh: &QueueHandle<Self>) {
|
fn render(&mut self, qh: &QueueHandle<Self>) {
|
||||||
if let Some(vp) = self.viewport.as_mut() {
|
if let Some(vp) = self.viewport.as_mut() {
|
||||||
|
vp.set_window_alpha(crate::ui::theme::window_alpha(self.focused, self.hovered));
|
||||||
vp.render_frame();
|
vp.render_frame();
|
||||||
}
|
}
|
||||||
let surface = self.layer.wl_surface();
|
let surface = self.layer.wl_surface();
|
||||||
|
|
@ -377,6 +382,7 @@ impl KeyboardHandler for State {
|
||||||
_: &[u32],
|
_: &[u32],
|
||||||
_keysyms: &[Keysym],
|
_keysyms: &[Keysym],
|
||||||
) {
|
) {
|
||||||
|
self.focused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave(
|
fn leave(
|
||||||
|
|
@ -387,6 +393,7 @@ impl KeyboardHandler for State {
|
||||||
_surface: &wl_surface::WlSurface,
|
_surface: &wl_surface::WlSurface,
|
||||||
_: u32,
|
_: u32,
|
||||||
) {
|
) {
|
||||||
|
self.focused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn press_key(
|
fn press_key(
|
||||||
|
|
@ -462,9 +469,11 @@ impl PointerHandler for State {
|
||||||
self.last_pointer = (lx, ly);
|
self.last_pointer = (lx, ly);
|
||||||
match event.kind {
|
match event.kind {
|
||||||
PointerEventKind::Enter { .. } => {
|
PointerEventKind::Enter { .. } => {
|
||||||
|
self.hovered = true;
|
||||||
vp.push_mouse_move(lx, ly);
|
vp.push_mouse_move(lx, ly);
|
||||||
}
|
}
|
||||||
PointerEventKind::Leave { .. } => {
|
PointerEventKind::Leave { .. } => {
|
||||||
|
self.hovered = false;
|
||||||
vp.push_mouse_left();
|
vp.push_mouse_left();
|
||||||
}
|
}
|
||||||
PointerEventKind::Motion { .. } => {
|
PointerEventKind::Motion { .. } => {
|
||||||
|
|
@ -496,8 +505,8 @@ impl PointerHandler for State {
|
||||||
|
|
||||||
/// Find a wayland socket and connect, regardless of whether `WAYLAND_DISPLAY` is set.
|
/// Find a wayland socket and connect, regardless of whether `WAYLAND_DISPLAY` is set.
|
||||||
/// Inside flatpak the env var is often stripped even when the socket itself is bind-
|
/// Inside flatpak the env var is often stripped even when the socket itself is bind-
|
||||||
/// mounted into the sandbox at `$XDG_RUNTIME_DIR/wayland-*`. We list candidates,
|
/// mounted into the sandbox at `$XDG_RUNTIME_DIR/wayland-*`. Lists candidates
|
||||||
/// log everything we find, and try each in order.
|
/// and tries each in order.
|
||||||
fn probe_connection() -> Option<Connection> {
|
fn probe_connection() -> Option<Connection> {
|
||||||
let runtime_dir = std::env::var_os("XDG_RUNTIME_DIR").map(std::path::PathBuf::from);
|
let runtime_dir = std::env::var_os("XDG_RUNTIME_DIR").map(std::path::PathBuf::from);
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
|
|
@ -531,7 +540,7 @@ fn probe_connection() -> Option<Connection> {
|
||||||
if !name_str.starts_with("wayland-") {
|
if !name_str.starts_with("wayland-") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Skip lock files; we want the socket itself.
|
// Skip lock files; only the socket matters.
|
||||||
if name_str.ends_with(".lock") {
|
if name_str.ends_with(".lock") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue