From ab1edbf0f4df98fbb80f2214ffcf0774ce4ddb39 Mon Sep 17 00:00:00 2001 From: Erwin Boskma Date: Fri, 3 May 2024 17:16:20 +0200 Subject: [PATCH] Initial commit --- .envrc | 3 + .gitignore | 14 +++ build.zig | 127 +++++++++++++++++++++++++++ build.zig.zon | 36 ++++++++ flake.lock | 196 ++++++++++++++++++++++++++++++++++++++++++ flake.nix | 71 ++++++++++++++++ nix/zls/default.nix | 54 ++++++++++++ nix/zls/deps.nix | 20 +++++ src/main.zig | 203 ++++++++++++++++++++++++++++++++++++++++++++ src/root.zig | 10 +++ src/version.zig | 18 ++++ 11 files changed, 752 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 build.zig create mode 100644 build.zig.zon create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/zls/default.nix create mode 100644 nix/zls/deps.nix create mode 100644 src/main.zig create mode 100644 src/root.zig create mode 100644 src/version.zig diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..0568783 --- /dev/null +++ b/.envrc @@ -0,0 +1,3 @@ +dotenv_if_exists + +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..819b6d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +### direnv ### +.direnv + +### nix ### +/result + +### zig ### +# Zig programming language + +zig-cache/ +zig-out/ +build/ +build-*/ +docgen_tmp/ diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..f5f0990 --- /dev/null +++ b/build.zig @@ -0,0 +1,127 @@ +const std = @import("std"); +const mem = std.mem; +const path = std.fs.path; + +const Build = std.Build; + +const Scanner = @import("zig-wayland").Scanner; + +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) 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 optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); + + const scanner = Scanner.create(b, .{}); + const wayland = b.createModule(.{ .root_source_file = scanner.result }); + + scanner.addSystemProtocol("stable/xdg-shell/xdg-shell.xml"); + scanner.addSystemProtocol("unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"); + + const wlr_protocols_path = blk: { + const pc_output = b.run(&.{ "pkg-config", "--variable=pkgdatadir", "wlr-protocols" }); + break :blk mem.trim(u8, pc_output, &std.ascii.whitespace); + }; + + scanner.addCustomProtocol(b.pathJoin(&.{ wlr_protocols_path, "unstable/wlr-layer-shell-unstable-v1.xml" })); + scanner.addCustomProtocol(b.pathJoin(&.{ wlr_protocols_path, "unstable/wlr-foreign-toplevel-management-unstable-v1.xml" })); + + scanner.generate("wl_compositor", 1); + scanner.generate("wl_shm", 1); + scanner.generate("wl_output", 4); + scanner.generate("xdg_wm_base", 6); + scanner.generate("zwp_idle_inhibit_manager_v1", 1); + scanner.generate("zwlr_foreign_toplevel_manager_v1", 3); + scanner.generate("zwlr_layer_shell_v1", 4); + + // const lib = b.addStaticLibrary(.{ + // .name = "vegetable-hamper", + // // In this case the main source file is merely a path, however, in more + // // complicated build scripts, this could be a generated file. + // .root_source_file = b.path("src/root.zig"), + // .target = target, + // .optimize = optimize, + // }); + + // // This declares intent for the library to be installed into the standard + // // location when the user invokes the "install" step (the default step when + // // running `zig build`). + // b.installArtifact(lib); + + const exe = b.addExecutable(.{ + .name = "vegetable-hamper", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); + + // Add wayland module + exe.root_module.addImport("wayland", wayland); + exe.linkLibC(); + exe.linkSystemLibrary2("wayland-client", .{ .needed = true }); + exe.linkSystemLibrary2("wlroots", .{ .needed = true }); + + scanner.addCSource(exe); + + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); + + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); + + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); + + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } + + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); + + // Creates a step for unit testing. This only builds the test executable + // but does not run it. + // const lib_unit_tests = b.addTest(.{ + // .root_source_file = b.path("src/root.zig"), + // .target = target, + // .optimize = optimize, + // }); + + // const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); + + // const exe_unit_tests = b.addTest(.{ + // .root_source_file = b.path("src/main.zig"), + // .target = target, + // .optimize = optimize, + // }); + + // const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); + + // Similar to creating the run step earlier, this exposes a `test` step to + // the `zig build --help` menu, providing a way for the user to request + // running the unit tests. + // const test_step = b.step("test", "Run unit tests"); + // test_step.dependOn(&run_lib_unit_tests.step); + // test_step.dependOn(&run_exe_unit_tests.step); +} diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..7e4c8ee --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,36 @@ +.{ + .name = "vegetable-hamper", + // This is a [Semantic Version](https://semver.org/). + // In a future version of Zig it will be used for package deduplication. + .version = "0.1.0", + + // This field is optional. + // This is currently advisory only; Zig does not yet do anything + // with this value. + //.minimum_zig_version = "0.11.0", + + // This field is optional. + // Each dependency must either provide a `url` and `hash`, or a `path`. + // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. + // Once all dependencies are fetched, `zig build` no longer requires + // internet connectivity. + .dependencies = .{ + .@"zig-wayland" = .{ + .url = "https://codeberg.org/ifreund/zig-wayland/archive/fe04636c866c6289b74c0803e621c9cc1bc1d1a4.tar.gz", + .hash = "12205b33855e3634201e6777a06d9d50ff8f4477b47ef95024009dd3e60df7b269d3", + }, + }, + .paths = .{ + // This makes *all* files, recursively, included in this package. It is generally + // better to explicitly list the files and directories instead, to insure that + // fetching from tarballs, file system paths, and version control all result + // in the same contents hash. + "", + // For example... + //"build.zig", + //"build.zig.zon", + //"src", + //"LICENSE", + //"README.md", + }, +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..e1a8ded --- /dev/null +++ b/flake.lock @@ -0,0 +1,196 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1712014858, + "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1714478972, + "narHash": "sha256-q//cgb52vv81uOuwz1LaXElp3XAe1TqrABXODAEF6Sk=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "2849da033884f54822af194400f8dff435ada242", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1714562304, + "narHash": "sha256-Mr3U37Rh6tH0FbaDFu0aZDwk9mPAe7ASaqDOGgLqqLU=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "bcd44e224fd68ce7d269b4f44d24c2220fd821e7", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1711703276, + "narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d8fe5e6c92d0d190646fb9f1056741a229980089", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1710695816, + "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "614b4613980a522ba49f0d194531beddbb7220d3", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "git-hooks": "git-hooks", + "nixpkgs": "nixpkgs", + "treefmt-nix": "treefmt-nix" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1714058656, + "narHash": "sha256-Qv4RBm4LKuO4fNOfx9wl40W2rBbv5u5m+whxRYUMiaA=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "c6aaf729f34a36c445618580a9f95a48f5e4e03f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d3f7bbb --- /dev/null +++ b/flake.nix @@ -0,0 +1,71 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + + flake-parts.url = "github:hercules-ci/flake-parts"; + + treefmt-nix = { + url = "github:numtide/treefmt-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + git-hooks = { + url = "github:cachix/git-hooks.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + { ... }@inputs: + inputs.flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ "x86_64-linux" ]; + + imports = [ + inputs.git-hooks.flakeModule + inputs.treefmt-nix.flakeModule + + ./nix/zls + ]; + + perSystem = + { + pkgs, + lib, + config, + ... + }: + { + treefmt = { + projectRootFile = "flake.lock"; + + programs = { + deadnix.enable = true; + nixfmt = { + enable = true; + package = pkgs.nixfmt-rfc-style; + }; + }; + }; + + devShells.default = + with pkgs; + mkShell { + name = "zig-app"; + + packages = [ + zig_0_12 + config.packages.zls + + wayland + wayland-protocols + wlroots_0_17 + wlr-protocols + + swayidle + + pkg-config + ]; + }; + }; + }; +} diff --git a/nix/zls/default.nix b/nix/zls/default.nix new file mode 100644 index 0000000..a5cfde3 --- /dev/null +++ b/nix/zls/default.nix @@ -0,0 +1,54 @@ +{ + # { lib + # , stdenv + # , fetchFromGitHub + # , zig_0_11 + # , callPackage + # }: + + perSystem = + { pkgs, lib, ... }: + { + packages.zls = + let + in + pkgs.stdenv.mkDerivation (finalAttrs: { + pname = "zls"; + version = "0.12.0"; + + src = pkgs.fetchFromGitHub { + owner = "zigtools"; + repo = "zls"; + rev = finalAttrs.version; + fetchSubmodules = true; + hash = "sha256-2iVDPUj9ExgTooDQmCCtZs3wxBe2be9xjzAk9HedPNY="; + }; + + langref = pkgs.fetchurl { + url = "https://raw.githubusercontent.com/ziglang/zig/a685ab1499d6560c523f0dbce2890dc140671e43/doc/langref.html.in"; + hash = "sha256-7lFSfkVLOrn42nYnYyDmBkkRfM903lUUJZ5Sg+eBUpE="; + }; + + zigBuildFlags = [ "-Dversion_data_path=${finalAttrs.langref}" ]; + + nativeBuildInputs = [ pkgs.zig_0_12.hook ]; + + postPatch = '' + ln -s ${pkgs.callPackage ./deps.nix { }} $ZIG_GLOBAL_CACHE_DIR/p + ''; + + meta = { + description = "Zig LSP implementation + Zig Language Server"; + mainProgram = "zls"; + changelog = "https://github.com/zigtools/zls/releases/tag/${finalAttrs.version}"; + homepage = "https://github.com/zigtools/zls"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ + figsoda + moni + ]; + platforms = lib.platforms.unix; + }; + }); + }; +} diff --git a/nix/zls/deps.nix b/nix/zls/deps.nix new file mode 100644 index 0000000..4de5062 --- /dev/null +++ b/nix/zls/deps.nix @@ -0,0 +1,20 @@ +# generated by zon2nix (https://github.com/figsoda/zon2nix) + +{ linkFarm, fetchzip }: + +linkFarm "zig-packages" [ + { + name = "12201314cffeb40c5e4e3da166217d2c74628c74486414aaf97422bcd2279915b9fd"; + path = fetchzip { + url = "https://github.com/ziglibs/known-folders/archive/bf79988adcfce166f848e4b11e718c1966365329.tar.gz"; + hash = "sha256-Q7eMdyScqj8qEiAHg1BnGRTsWSQOKWWTc6hUYHNlgGg="; + }; + } + { + name = "12200d71e4b7029ea56a429e24260c6c0e85a3069b0d4ba85eace21a0fd75910aa64"; + path = fetchzip { + url = "https://github.com/ziglibs/diffz/archive/e10bf15962e45affb3fcd7d9a950977a69c901b3.tar.gz"; + hash = "sha256-yVFPVn4jGfcoE2V4xdTqdThYPutshL6U4feDzetWgFw="; + }; + } +] diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..f3f191f --- /dev/null +++ b/src/main.zig @@ -0,0 +1,203 @@ +const std = @import("std"); +const mem = std.mem; + +const wayland = @import("wayland"); +const wl = wayland.client.wl; +const zwp = wayland.client.zwp; +const zwlr = wayland.client.zwlr; + +const version = @import("version.zig").getVersion(); + +const Context = struct { + toplevel_mgr: ?*zwlr.ForeignToplevelManagerV1, + idle_inhibit_mgr: ?*zwp.IdleInhibitManagerV1, + handles: std.AutoHashMap(*zwlr.ForeignToplevelHandleV1, ToplevelFullscreen), + idle_inhibitor: ?*zwp.IdleInhibitorV1, + shm: ?*wl.Shm, + compositor: ?*wl.Compositor, + layer_shell: ?*zwlr.LayerShellV1, + surface: ?*wl.Surface, +}; + +const ToplevelFullscreen = enum { Fullscreen, NotFullscreen }; + +pub fn main() anyerror!void { + std.log.info("Vegetable Hamper v{}", .{version}); + + var context = Context{ + .toplevel_mgr = null, + .idle_inhibit_mgr = null, + .handles = std.AutoHashMap(*zwlr.ForeignToplevelHandleV1, ToplevelFullscreen).init(std.heap.page_allocator), + .idle_inhibitor = null, + .shm = null, + .compositor = null, + .layer_shell = null, + .surface = null, + }; + defer context.handles.deinit(); + + const display = try wl.Display.connect(null); + const registry = try display.getRegistry(); + registry.setListener(*Context, registry_listener, &context); + + if (display.roundtrip() != .SUCCESS) { + print("Initial roundtrip failed", .{}); + return error.RoundTripFailed; + } + + const compositor = context.compositor orelse return error.NoWlCompositor; + const shm = context.shm orelse return error.NoWlShm; + const layer_shell = context.layer_shell orelse return error.NoLayerShell; + const toplevel_mgr = context.toplevel_mgr orelse return error.NoTopLevelManager; + _ = context.idle_inhibit_mgr orelse return error.NoIdleInhibitManager; + + const buffer = blk: { + const width = 1; + const height = 1; + const stride = width * 4; + const size = stride * height; + + const fd = try std.posix.memfd_create("vegetable-hamper", 0); + try std.posix.ftruncate(fd, size); + const data = try std.posix.mmap(null, size, std.posix.PROT.READ | std.posix.PROT.WRITE, .{ .TYPE = .SHARED }, fd, 0); + // @memcpy(data, @embedFile("res/cat.bgra")); + @memset(data, 0); + + const pool = try shm.createPool(fd, size); + defer pool.destroy(); + + break :blk try pool.createBuffer(0, width, height, stride, wl.Shm.Format.argb8888); + }; + + context.surface = try compositor.createSurface(); + defer context.surface.?.destroy(); + + const wlr_surface = try layer_shell.getLayerSurface(context.surface.?, null, .background, "vegetable-hamper"); + defer wlr_surface.destroy(); + + wlr_surface.setSize(1, 1); + + toplevel_mgr.setListener(*Context, toplevel_manager_listener, &context); + + wlr_surface.setListener(*wl.Surface, wlr_surface_listener, context.surface.?); + + context.surface.?.commit(); + + if (display.roundtrip() != .SUCCESS) return error.RoundtripFailed; + + context.surface.?.attach(buffer, 0, 0); + context.surface.?.commit(); + + while (true) { + if (display.dispatch() != .SUCCESS) return error.DispatchFailed; + } +} + +fn wlr_surface_listener(wlr_surface: *zwlr.LayerSurfaceV1, event: zwlr.LayerSurfaceV1.Event, surface: *wl.Surface) void { + switch (event) { + .configure => |configure| { + wlr_surface.ackConfigure(configure.serial); + surface.commit(); + }, + .closed => {}, + } +} + +fn registry_listener(registry: *wl.Registry, event: wl.Registry.Event, ctx: *Context) void { + switch (event) { + .global => |global| { + if (mem.orderZ(u8, global.interface, zwlr.ForeignToplevelManagerV1.getInterface().name) == .eq) { + std.log.debug("Found zwlr_foreign_toplevel_manager_v1", .{}); + ctx.toplevel_mgr = registry.bind(global.name, zwlr.ForeignToplevelManagerV1, 1) catch return; + } else if (mem.orderZ(u8, global.interface, zwp.IdleInhibitManagerV1.getInterface().name) == .eq) { + std.log.debug("Found zwp_idle_inhibit_manager_v1", .{}); + ctx.idle_inhibit_mgr = registry.bind(global.name, zwp.IdleInhibitManagerV1, 1) catch @panic("Error binding idle inhibit manager"); + } else if (mem.orderZ(u8, global.interface, wl.Compositor.getInterface().name) == .eq) { + std.log.debug("Found wl_compositor", .{}); + ctx.compositor = registry.bind(global.name, wl.Compositor, 1) catch return; + } else if (mem.orderZ(u8, global.interface, wl.Shm.getInterface().name) == .eq) { + std.log.debug("Found wl_shm", .{}); + ctx.shm = registry.bind(global.name, wl.Shm, 1) catch return; + } else if (mem.orderZ(u8, global.interface, zwlr.LayerShellV1.getInterface().name) == .eq) { + std.log.debug("Found wlr_layer_shell", .{}); + ctx.layer_shell = registry.bind(global.name, zwlr.LayerShellV1, 1) catch return; + } else { + std.log.debug("Unhandled interface: {s}", .{global.interface}); + } + }, + .global_remove => {}, + } +} + +fn toplevel_manager_listener(manager: *zwlr.ForeignToplevelManagerV1, event: zwlr.ForeignToplevelManagerV1.Event, ctx: *Context) void { + _ = manager; + var handles = &ctx.handles; + + switch (event) { + .toplevel => |toplevel| { + std.log.debug("New toplevel", .{}); + handles.put(toplevel.toplevel, .NotFullscreen) catch return; + + toplevel.toplevel.setListener(*Context, toplevel_listener, ctx); + }, + .finished => {}, + } +} + +fn toplevel_listener(handle: *zwlr.ForeignToplevelHandleV1, event: zwlr.ForeignToplevelHandleV1.Event, ctx: *Context) void { + var handles = &ctx.handles; + switch (event) { + .state => |stateEvent| { + const states = stateEvent.state.slice(c_int); + std.log.debug("State: {x}", .{states}); + for (states) |s| { + const state: zwlr.ForeignToplevelHandleV1.State = @enumFromInt(s); + switch (state) { + .fullscreen => { + std.log.debug("Something went fullscreen", .{}); + ctx.handles.put(handle, .Fullscreen) catch return; + if (ctx.idle_inhibitor == null) { + ctx.idle_inhibitor = ctx.idle_inhibit_mgr.?.createInhibitor(ctx.surface.?) catch @panic("Error creating idle inhibitor"); + print("Now hampering vegetation", .{}); + } + }, + else => { + ctx.handles.put(handle, .NotFullscreen) catch return; + var values = ctx.handles.valueIterator(); + const someFullscreen = while (values.next()) |fs| { + if (fs.* == .Fullscreen) { + break true; + } + } else false; + + if (!someFullscreen and ctx.idle_inhibitor != null) { + ctx.idle_inhibitor.?.destroy(); + ctx.idle_inhibitor = null; + print("No more full screen applications, no more hampering", .{}); + } + }, + } + } + }, + .title => {}, + .app_id => {}, + .output_enter => {}, + .output_leave => {}, + .done => {}, + .closed => { + std.log.debug("Closed", .{}); + _ = handles.remove(handle); + }, + .parent => {}, + } +} + +fn print(comptime format: []const u8, args: anytype) void { + const stdout_file = std.io.getStdOut().writer(); + var bw = std.io.bufferedWriter(stdout_file); + const stdout = bw.writer(); + + stdout.print(format ++ "\n", args) catch @panic("Could not write to stdout"); + + bw.flush() catch @panic("Could not flush stdout"); // don't forget to flush! +} diff --git a/src/root.zig b/src/root.zig new file mode 100644 index 0000000..ecfeade --- /dev/null +++ b/src/root.zig @@ -0,0 +1,10 @@ +const std = @import("std"); +const testing = std.testing; + +export fn add(a: i32, b: i32) i32 { + return a + b; +} + +test "basic add functionality" { + try testing.expect(add(3, 7) == 10); +} diff --git a/src/version.zig b/src/version.zig new file mode 100644 index 0000000..f1feedd --- /dev/null +++ b/src/version.zig @@ -0,0 +1,18 @@ +const std = @import("std"); + +pub fn getVersion() Version { + return Version{}; +} +const Version = struct { + comptime major: u8 = 0, + comptime minor: u8 = 1, + comptime patch: u8 = 0, + const Self = @This(); + + pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void { + _ = fmt; + _ = options; + + try writer.print("{}.{}.{}", .{ self.major, self.minor, self.patch }); + } +};