app bundle
This commit is contained in:
@@ -132,6 +132,35 @@
|
|||||||
unset slermCache slermStale slermTmp slermDir slermGlob slermLib
|
unset slermCache slermStale slermTmp slermDir slermGlob slermLib
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
# macOS only gives a process a dock icon, a menu bar and a real
|
||||||
|
# application name when it runs from a bundle, so ship one and keep
|
||||||
|
# bin/slerm as a symlink into it for terminal use.
|
||||||
|
appBundle = version: ''
|
||||||
|
app="$out/Applications/slerm.app"
|
||||||
|
mkdir -p "$app/Contents/MacOS" "$app/Contents/Resources"
|
||||||
|
cat > "$app/Contents/Info.plist" <<EOF
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleName</key><string>slerm</string>
|
||||||
|
<key>CFBundleDisplayName</key><string>slerm</string>
|
||||||
|
<key>CFBundleExecutable</key><string>slerm</string>
|
||||||
|
<key>CFBundleIdentifier</key><string>org.slerm.slerm</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
|
||||||
|
<key>CFBundlePackageType</key><string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key><string>${version}</string>
|
||||||
|
<key>CFBundleVersion</key><string>${version}</string>
|
||||||
|
<key>LSApplicationCategoryType</key><string>public.app-category.developer-tools</string>
|
||||||
|
<key>LSMinimumSystemVersion</key><string>11.0</string>
|
||||||
|
<key>NSHighResolutionCapable</key><true/>
|
||||||
|
<key>NSSupportsAutomaticGraphicsSwitching</key><true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
EOF
|
||||||
|
mv "$out/bin/slerm" "$app/Contents/MacOS/slerm"
|
||||||
|
ln -s "$app/Contents/MacOS/slerm" "$out/bin/slerm"
|
||||||
|
'';
|
||||||
ghosttyEnv = {
|
ghosttyEnv = {
|
||||||
GHOSTTY_SOURCE_DIR = "${ghostty-src}";
|
GHOSTTY_SOURCE_DIR = "${ghostty-src}";
|
||||||
GHOSTTY_ZIG_SYSTEM_DIR = "${ghosttyDeps}";
|
GHOSTTY_ZIG_SYSTEM_DIR = "${ghosttyDeps}";
|
||||||
@@ -183,6 +212,10 @@
|
|||||||
"--skip=tests::osc7_wins_over_the_process_directory_but_only_for_this_machine"
|
"--skip=tests::osc7_wins_over_the_process_directory_but_only_for_this_machine"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
postInstall = lib.optionalString pkgs.stdenv.hostPlatform.isDarwin (
|
||||||
|
appBundle manifest.package.version
|
||||||
|
);
|
||||||
|
|
||||||
postFixup = lib.optionalString pkgs.stdenv.hostPlatform.isLinux ''
|
postFixup = lib.optionalString pkgs.stdenv.hostPlatform.isLinux ''
|
||||||
wrapProgram "$out/bin/slerm" \
|
wrapProgram "$out/bin/slerm" \
|
||||||
--suffix LD_LIBRARY_PATH : ${lib.makeLibraryPath runtimeLibraries} \
|
--suffix LD_LIBRARY_PATH : ${lib.makeLibraryPath runtimeLibraries} \
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/nix/store/c0ngrz7m1zjs95pb9qm3rx5ka3sbvpvb-slerm-0.1.0
|
/nix/store/6vj9g5xzxd0whdnxd0zsg02m1rwsrlrn-slerm-0.1.0
|
||||||
+38
@@ -23,6 +23,37 @@ pub struct App {
|
|||||||
suppressed: HashSet<egui::Key>,
|
suppressed: HashSet<egui::Key>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Width kept free at the left of the tab bar for the macOS traffic lights,
|
||||||
|
/// which float over the content once the titlebar is hidden.
|
||||||
|
const TITLEBAR_INSET: f32 = 70.0;
|
||||||
|
/// Height the tab bar needs so the traffic lights fit inside it.
|
||||||
|
const TITLEBAR_HEIGHT: f32 = 28.0;
|
||||||
|
|
||||||
|
/// With the titlebar hidden the tab bar takes its place, so let the empty space
|
||||||
|
/// beside the tabs drag the window and double-click to zoom, like a titlebar.
|
||||||
|
fn drag_window(ui: &mut egui::Ui) {
|
||||||
|
let used = ui.min_rect();
|
||||||
|
let free = Rect::from_min_max(
|
||||||
|
egui::pos2(used.right(), used.top()),
|
||||||
|
egui::pos2(ui.max_rect().right(), used.bottom()),
|
||||||
|
);
|
||||||
|
if free.width() <= 0.0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let response = ui.interact(
|
||||||
|
free,
|
||||||
|
ui.id().with("titlebar drag"),
|
||||||
|
egui::Sense::click_and_drag(),
|
||||||
|
);
|
||||||
|
if response.double_clicked() {
|
||||||
|
let maximized = ui.input(|i| i.viewport().maximized.unwrap_or(false));
|
||||||
|
ui.ctx()
|
||||||
|
.send_viewport_cmd(egui::ViewportCommand::Maximized(!maximized));
|
||||||
|
} else if response.drag_started_by(egui::PointerButton::Primary) {
|
||||||
|
ui.ctx().send_viewport_cmd(egui::ViewportCommand::StartDrag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fonts(config: &Config) -> Result<egui::FontDefinitions> {
|
pub fn fonts(config: &Config) -> Result<egui::FontDefinitions> {
|
||||||
let mut fonts = egui::FontDefinitions::default();
|
let mut fonts = egui::FontDefinitions::default();
|
||||||
if let Some(path) = &config.font_path {
|
if let Some(path) = &config.font_path {
|
||||||
@@ -353,6 +384,10 @@ impl eframe::App for App {
|
|||||||
let mut action = None;
|
let mut action = None;
|
||||||
egui::TopBottomPanel::top("tabs").show(ctx, |ui| {
|
egui::TopBottomPanel::top("tabs").show(ctx, |ui| {
|
||||||
ui.horizontal_wrapped(|ui| {
|
ui.horizontal_wrapped(|ui| {
|
||||||
|
if cfg!(target_os = "macos") {
|
||||||
|
ui.add_space(TITLEBAR_INSET);
|
||||||
|
ui.set_min_height(TITLEBAR_HEIGHT);
|
||||||
|
}
|
||||||
for (index, tab) in self.tabs.iter().enumerate() {
|
for (index, tab) in self.tabs.iter().enumerate() {
|
||||||
let title = self.panes[&tab.active].terminal.title().unwrap_or("");
|
let title = self.panes[&tab.active].terminal.title().unwrap_or("");
|
||||||
let label = if title.is_empty() {
|
let label = if title.is_empty() {
|
||||||
@@ -396,6 +431,9 @@ impl eframe::App for App {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
if cfg!(target_os = "macos") {
|
||||||
|
drag_window(ui);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if let Some(error) = self.error.clone() {
|
if let Some(error) = self.error.clone() {
|
||||||
egui::TopBottomPanel::bottom("error").show(ctx, |ui| {
|
egui::TopBottomPanel::bottom("error").show(ctx, |ui| {
|
||||||
|
|||||||
+14
-5
@@ -67,12 +67,21 @@ fn main() -> Result<()> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
libghostty_vt::kitty::graphics::set_png_decoder(Some(Box::new(render::PngDecoder)))?;
|
libghostty_vt::kitty::graphics::set_png_decoder(Some(Box::new(render::PngDecoder)))?;
|
||||||
|
let mut viewport = egui::ViewportBuilder::default()
|
||||||
|
.with_title("slerm")
|
||||||
|
.with_inner_size([config.window_width, config.window_height])
|
||||||
|
.with_min_inner_size([320.0, 200.0])
|
||||||
|
.with_app_id("slerm");
|
||||||
|
if cfg!(target_os = "macos") {
|
||||||
|
// Hide the titlebar and draw under it; the traffic lights stay on top of
|
||||||
|
// the tab bar, which reserves room for them (see app::TITLEBAR_INSET).
|
||||||
|
viewport = viewport
|
||||||
|
.with_fullsize_content_view(true)
|
||||||
|
.with_titlebar_shown(false)
|
||||||
|
.with_title_shown(false);
|
||||||
|
}
|
||||||
let options = eframe::NativeOptions {
|
let options = eframe::NativeOptions {
|
||||||
viewport: egui::ViewportBuilder::default()
|
viewport,
|
||||||
.with_title("slerm")
|
|
||||||
.with_inner_size([config.window_width, config.window_height])
|
|
||||||
.with_min_inner_size([320.0, 200.0])
|
|
||||||
.with_app_id("slerm"),
|
|
||||||
renderer: eframe::Renderer::Wgpu,
|
renderer: eframe::Renderer::Wgpu,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user