add openbrowser script

This commit is contained in:
LordMZTE 2022-11-16 22:55:11 +01:00
parent bab46a305a
commit b64d5befe3
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6
6 changed files with 174 additions and 0 deletions

View file

@ -21,6 +21,7 @@ install-scripts target=(`echo $HOME` + "/.local"):
cd scripts/randomwallpaper && zig build -Drelease-fast -p {{target}}
cd scripts/vinput && zig build -Drelease-fast -p {{target}}
cd scripts/playtwitch && zig build -Drelease-fast -p {{target}}
cd scripts/openbrowser && zig build -Drelease-fast -p {{target}}
cd scripts/prompt && gyro build -Drelease-fast -p {{target}}
cd scripts/mzteinit && gyro build -Drelease-fast -p {{target}}

5
scripts/openbrowser/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
zig-cache/
zig-out/
deps.zig
gyro.lock
.gyro

View file

@ -0,0 +1,7 @@
[Desktop Entry]
Name=Open Browser
Comment=Opens the best browser given a link
Exec=openbrowser %u
Type=Application
Categories=Network
MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;

View file

@ -0,0 +1,40 @@
const std = @import("std");
pub fn build(b: *std.build.Builder) void {
// Standard target options allows the person running `zig build` to choose
// what target to build for. Here we do not override the defaults, which
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("openbrowser", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
const desktop_install_step = b.addInstallFile(
.{ .path = "assets/openbrowser.desktop" },
"share/applications/openbrowser.desktop",
);
b.getInstallStep().dependOn(&desktop_install_step.step);
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
const exe_tests = b.addTest("src/main.zig");
exe_tests.setTarget(target);
exe_tests.setBuildMode(mode);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&exe_tests.step);
}

View file

@ -0,0 +1,67 @@
const std = @import("std");
running: bool,
exepath: ?[]const u8,
const Self = @This();
/// Frees the data of this ProcessInfo.
/// `alloc` must be the same allocator that was supplied to `get`!
pub fn deinit(self: *Self, alloc: std.mem.Allocator) void {
if (self.exepath) |exepath|
alloc.free(exepath);
self.* = undefined;
}
/// Gets information about a process given it's name
pub fn get(
name: []const u8,
alloc: std.mem.Allocator,
) !Self {
var proc_dir = try std.fs.openIterableDirAbsolute("/proc", .{});
defer proc_dir.close();
var proc_iter = proc_dir.iterate();
procs: while (try proc_iter.next()) |proc| {
// Filter directories that aren't PIDs
for (std.fs.path.basename(proc.name)) |letter|
if (!std.ascii.isDigit(letter))
continue :procs;
var buf: [512]u8 = undefined;
const cmdline_f = std.fs.openFileAbsolute(
try std.fmt.bufPrint(&buf, "/proc/{s}/cmdline", .{proc.name}),
.{},
) catch |e| {
// This just happens when we're dealing with another user's process.
if (e == error.AccessDenied)
continue;
return e;
};
defer cmdline_f.close();
const cmdline_data = try cmdline_f.readToEndAlloc(alloc, std.math.maxInt(usize));
defer alloc.free(cmdline_data);
var cmdline_splits = std.mem.split(u8, cmdline_data, &.{0});
const exepath = cmdline_splits.next() orelse return error.InvalidCmdline;
// this is a startsWith instead of an eql because the arguments in the
// cmdline file are sometimes (and only sometimes!) separated by spaces
// and not null bytes.
if (!std.mem.startsWith(u8, std.fs.path.basename(exepath), name))
continue;
return .{
.running = true,
.exepath = try alloc.dupe(u8, exepath),
};
}
return .{
.running = false,
.exepath = null,
};
}

View file

@ -0,0 +1,54 @@
const std = @import("std");
const ProcessInfo = @import("ProcessInfo.zig");
pub const log_level = .debug;
const browsers = &[_][]const u8{
"luakit",
"waterfox-g4",
"firefox",
"chromium",
};
pub fn main() !void {
if (std.os.argv.len < 2) {
std.log.err("need >=1 argument", .{});
return error.WrongArgs;
}
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const alloc = gpa.allocator();
for (browsers) |browser| {
var info = try ProcessInfo.get(browser, alloc);
defer info.deinit(alloc);
if (!info.running)
continue;
std.log.info("found running browser {s}", .{info.exepath.?});
try start(browser, alloc);
return;
}
std.log.info("no running browser, using first choice", .{});
try start(browsers[0], alloc);
}
fn start(browser: []const u8, alloc: std.mem.Allocator) !void {
// args to browser will be same length as argv
const argv = try alloc.alloc([]const u8, std.os.argv.len);
defer alloc.free(argv);
argv[0] = browser;
for (std.os.argv[1..]) |arg, i| {
argv[i + 1] = std.mem.span(arg);
}
std.log.info("child argv: {s}", .{argv});
var child = std.ChildProcess.init(argv, alloc);
_ = try child.spawnAndWait();
}