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.
|
||||
# build.sh detects the running WM and sets this for you.
|
||||
x11 = ["dep:x11-dl"]
|
||||
wayland = ["dep:smithay-client-toolkit", "dep:wayland-client"]
|
||||
wayland = []
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
windows = { version = "0.58", features = [
|
||||
|
|
@ -86,5 +86,3 @@ windows = { version = "0.58", features = [
|
|||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
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"
|
||||
return
|
||||
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
|
||||
case "${XDG_CURRENT_DESKTOP:-}" in
|
||||
*COSMIC*|*KDE*|*Plasma*|sway|Hyprland|niri|river|Wayfire)
|
||||
echo "wayland"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
echo "wayland"
|
||||
return
|
||||
fi
|
||||
# GNOME-Wayland (mutter, no layer-shell), every X11 session, every other
|
||||
# GTK3-class compositor: ship the X11 provider — XWayland honours the hints
|
||||
# everywhere except cosmic-comp, where the wayland provider applies instead.
|
||||
# X11 session or no WAYLAND_DISPLAY: use the X11 provider.
|
||||
echo "x11"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,14 +9,11 @@ case "$(uname -s)" in
|
|||
*) echo "wrong platform: $(uname -s) — use cargo xtask install" >&2; exit 1;;
|
||||
esac
|
||||
|
||||
bash "$ROOT/scripts/linux/build.sh"
|
||||
|
||||
STAGE="$ROOT/build/bin/com.jesshunter.layers"
|
||||
PLUGIN_ID="com.jesshunter.layers"
|
||||
|
||||
# Drop into every existing KiCad >=10 install we can find — native and flatpak,
|
||||
# every version dir KiCad has already created. We never mkdir kicad/<ver>/plugins;
|
||||
# KiCad creates it on first launch and we only fill in our own subdir.
|
||||
# Installs into every existing KiCad >=10 plugins dir — native and flatpak.
|
||||
# Does not mkdir kicad/<ver>/plugins; KiCad creates it on first launch.
|
||||
install_to_kicad_root() {
|
||||
local kicad_root="$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"
|
||||
|
||||
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
|
||||
echo "no KiCad 10+ install detected. checked:" >&2
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ struct LayersColors {
|
|||
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.
|
||||
private static func flatten(_ source: String) -> [String: Double] {
|
||||
var out: [String: Double] = [:]
|
||||
|
|
|
|||
|
|
@ -36,14 +36,7 @@ fn main() {
|
|||
tracing::info!(provider = PROVIDER_NAME, "shell route: provider chosen at build time");
|
||||
|
||||
#[cfg(all(target_os = "linux", feature = "wayland"))]
|
||||
{
|
||||
if layers::wayland_shell::try_run() {
|
||||
return;
|
||||
}
|
||||
tracing::warn!(
|
||||
"wayland provider failed to start; falling through to winit so the plugin still loads"
|
||||
);
|
||||
}
|
||||
tracing::info!(provider = PROVIDER_NAME, "wayland: using winit xdg-toplevel (compositor provides pin-on-top via title bar)");
|
||||
|
||||
if let Err(e) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(run)) {
|
||||
tracing::error!("layers shell panicked: {e:?}");
|
||||
|
|
@ -52,7 +45,7 @@ fn main() {
|
|||
}
|
||||
|
||||
#[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")))]
|
||||
const PROVIDER_NAME: &str = "linux/x11 (winit + xlib)";
|
||||
#[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_min_inner_size(LogicalSize::new(MIN_LOGICAL_SIZE.0, MIN_LOGICAL_SIZE.1))
|
||||
.with_transparent(true)
|
||||
.with_decorations(true)
|
||||
.with_window_level(WindowLevel::AlwaysOnTop);
|
||||
.with_decorations(true);
|
||||
|
||||
// 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
|
||||
.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(
|
||||
target_os = "macos",
|
||||
target_os = "ios",
|
||||
|
|
|
|||
|
|
@ -609,8 +609,12 @@ fn render(handle: &mut ViewportHandle) {
|
|||
ui.draw(&mut handle.renderer, &theme, &style, handle.cursor);
|
||||
handle.cache = ui.into_cache();
|
||||
|
||||
// NSWindow.alphaValue in Swift fades the composited surface; keep this opaque.
|
||||
let background = crate::ui::theme::compositor_clear();
|
||||
// macOS/Windows/X11: the OS fades the composited surface via window-level alpha.
|
||||
// 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(
|
||||
Some(background),
|
||||
handle.format,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,3 @@ pub mod single_instance;
|
|||
pub mod snapshot;
|
||||
pub mod ui;
|
||||
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.
|
||||
/// 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 {
|
||||
if let Ok(v) = std::env::var("LAYERS_DATA_DIR") {
|
||||
if !v.is_empty() {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ pub fn try_run() -> bool {
|
|||
let layer = layer_shell.create_layer_surface(
|
||||
&qh,
|
||||
surface,
|
||||
Layer::Top,
|
||||
Layer::Overlay,
|
||||
Some("layers"),
|
||||
None,
|
||||
);
|
||||
|
|
@ -145,6 +145,8 @@ pub fn try_run() -> bool {
|
|||
first_configure: true,
|
||||
raw_display,
|
||||
raw_window,
|
||||
focused: false,
|
||||
hovered: false,
|
||||
exit: false,
|
||||
};
|
||||
|
||||
|
|
@ -175,6 +177,8 @@ struct State {
|
|||
first_configure: bool,
|
||||
raw_display: RawDisplayHandle,
|
||||
raw_window: RawWindowHandle,
|
||||
focused: bool,
|
||||
hovered: bool,
|
||||
exit: bool,
|
||||
}
|
||||
|
||||
|
|
@ -202,6 +206,7 @@ impl State {
|
|||
|
||||
fn render(&mut self, qh: &QueueHandle<Self>) {
|
||||
if let Some(vp) = self.viewport.as_mut() {
|
||||
vp.set_window_alpha(crate::ui::theme::window_alpha(self.focused, self.hovered));
|
||||
vp.render_frame();
|
||||
}
|
||||
let surface = self.layer.wl_surface();
|
||||
|
|
@ -377,6 +382,7 @@ impl KeyboardHandler for State {
|
|||
_: &[u32],
|
||||
_keysyms: &[Keysym],
|
||||
) {
|
||||
self.focused = true;
|
||||
}
|
||||
|
||||
fn leave(
|
||||
|
|
@ -387,6 +393,7 @@ impl KeyboardHandler for State {
|
|||
_surface: &wl_surface::WlSurface,
|
||||
_: u32,
|
||||
) {
|
||||
self.focused = false;
|
||||
}
|
||||
|
||||
fn press_key(
|
||||
|
|
@ -462,9 +469,11 @@ impl PointerHandler for State {
|
|||
self.last_pointer = (lx, ly);
|
||||
match event.kind {
|
||||
PointerEventKind::Enter { .. } => {
|
||||
self.hovered = true;
|
||||
vp.push_mouse_move(lx, ly);
|
||||
}
|
||||
PointerEventKind::Leave { .. } => {
|
||||
self.hovered = false;
|
||||
vp.push_mouse_left();
|
||||
}
|
||||
PointerEventKind::Motion { .. } => {
|
||||
|
|
@ -496,8 +505,8 @@ impl PointerHandler for State {
|
|||
|
||||
/// 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-
|
||||
/// mounted into the sandbox at `$XDG_RUNTIME_DIR/wayland-*`. We list candidates,
|
||||
/// log everything we find, and try each in order.
|
||||
/// mounted into the sandbox at `$XDG_RUNTIME_DIR/wayland-*`. Lists candidates
|
||||
/// and tries each in order.
|
||||
fn probe_connection() -> Option<Connection> {
|
||||
let runtime_dir = std::env::var_os("XDG_RUNTIME_DIR").map(std::path::PathBuf::from);
|
||||
tracing::info!(
|
||||
|
|
@ -531,7 +540,7 @@ fn probe_connection() -> Option<Connection> {
|
|||
if !name_str.starts_with("wayland-") {
|
||||
continue;
|
||||
}
|
||||
// Skip lock files; we want the socket itself.
|
||||
// Skip lock files; only the socket matters.
|
||||
if name_str.ends_with(".lock") {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue