From 9142e3d8e9084fa2eb0d2e569b9b9165aac5a09a Mon Sep 17 00:00:00 2001 From: niten Date: Tue, 9 May 2023 16:17:23 -0700 Subject: [PATCH] Initial checkin --- .gitignore | 9 ++ build.clj | 126 ++++++++++++++++++++ deps.edn | 27 +++++ metadata.edn | 8 ++ src/clj/notifier/core.clj | 40 +++++++ src/java/org/freedesktop/Notifications.java | 47 ++++++++ 6 files changed, 257 insertions(+) create mode 100644 .gitignore create mode 100644 build.clj create mode 100644 deps.edn create mode 100644 metadata.edn create mode 100644 src/clj/notifier/core.clj create mode 100644 src/java/org/freedesktop/Notifications.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b9f7c3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +.idea +*.log +tmp/ + +.cpcache/ +.nrepl-port +target/ +result diff --git a/build.clj b/build.clj new file mode 100644 index 0000000..96778e2 --- /dev/null +++ b/build.clj @@ -0,0 +1,126 @@ +(ns build + (:require [clojure.tools.build.api :as b] + [clojure.pprint :refer [pprint]] + [clojure.edn :as edn])) + +(def lib 'org.fudo/notifier) +(def default-version "DEV") +(defn- class-dir [{:keys [target]}] (format "%s/classes" target)) +(def basis (b/create-basis {:project "deps.edn"})) +(defn- jar-file [{:keys [target version] + :or {version default-version}}] + (format "%s/%s-%s.jar" target (name lib) version)) + +(defn- uberjar-file [{:keys [target version] + :or {version default-version}}] + (format "%s/%s-uber-%s.jar" target (name lib) version)) + +(def default-params + { + :verbose false + :version "DEV" + }) + +(defn clean [{:keys [target] :as params}] + (b/delete {:path target}) + params) + +(defn compile-java [{:keys [verbose java-src] :as params}] + (when verbose (println (format "compiling java files in %s..." java-src))) + (b/javac {:src-dirs [java-src] + :class-dir (class-dir params) + :basis basis + :javac-opts ["-source" "16" "-target" "16"]}) + params) + +(defn compile-clj [{:keys [verbose clj-src] :as params}] + (when verbose (println (format "compiling clj files in %s..." clj-src))) + (b/compile-clj {:basis basis + :src-dirs [clj-src] + :class-dir (class-dir params)})) + +(defn- read-metadata [filename] + (-> filename + (slurp) + (edn/read-string))) + +(defn- process-params [base-params] + (-> base-params + (merge (read-metadata (or (:metadata base-params) + "metadata.edn"))) + (update :target str) + (update :version str) + (update :java-src str) + (update :clj-src str))) + +(defn jar [base-params] + (let [params (process-params base-params) + {:keys [java-src clj-src version verbose]} params + classes (class-dir params)] + (when verbose + (print "parameters: ") + (pprint params)) + (compile-java params) + (compile-clj params) + (when verbose (println (format "writing POM file to %s..." classes))) + (b/write-pom { + :class-dir classes + :lib lib + :version (str version) + :basis basis + :src-dirs [java-src clj-src] + }) + (when verbose (println (format "copying source files from %s to %s..." + [java-src clj-src] classes))) + (b/copy-dir {:src-dirs [java-src clj-src] + :target-dir classes}) + (let [jar (jar-file params)] + (when verbose (println (format "writing JAR file to %s..." jar))) + (b/jar {:class-dir classes + :jar-file jar})) + (when verbose (println "done!")) + params)) + +(defn uberjar [base-params] + (let [params (process-params base-params) + {:keys [java-src clj-src version verbose]} params + classes (class-dir params)] + (when verbose + (print "parameters: ") + (pprint params)) + (compile-java params) + (compile-clj params) + (when verbose (println (format "writing POM file to %s..." classes))) + (b/write-pom { + :class-dir classes + :lib lib + :version (str version) + :basis basis + :src-dirs [java-src clj-src] + }) + (when verbose (println (format "copying source files from %s to %s..." + [java-src clj-src] classes))) + (b/copy-dir {:src-dirs [java-src clj-src] + :target-dir classes}) + (let [uberjar (uberjar-file params)] + (when verbose (println (format "writing uberjar file to %s..." uberjar))) + (b/uber {:class-dir classes + :uber-file uberjar + :basis basis})) + (when verbose (println "done!")) + params)) + +(defn install [base-params] + (let [params (process-params base-params) + {:keys [version verbose]} params + target-file (jar-file params)] + (jar params) + (when verbose (println (format "installing %s..." target-file))) + (b/install { + :basis basis + :lib lib + :version (str version) + :jar-file target-file + :class-dir (class-dir params) + }) + params)) diff --git a/deps.edn b/deps.edn new file mode 100644 index 0000000..3ac30f1 --- /dev/null +++ b/deps.edn @@ -0,0 +1,27 @@ +{ + :paths ["src/clj" "src/java"] + :deps { + org.clojure/clojure { :mvn/version "1.11.1" } + ;;org.freedesktop/libdbus-java { :mvn/version "2.7" } + ;;com.github.hypfvieh/libmatthew { :mvn/version "0.8.3" } + ;;com.github.hypfvieh/dbus-java { :mvn/version "3.3.2" } + com.github.hypfvieh/dbus-java-core { :mvn/version "4.3.0" } + com.github.hypfvieh/dbus-java-transport-native-unixsocket { :mvn/version "4.3.0" } + } + :aliases { + :install { + :extra-deps { + io.github.clojure/tools.build {:mvn/version "0.9.4"} + } + :ns-default build + :exec-fn install + } + :build { + :extra-deps { + io.github.clojure/tools.build {:mvn/version "0.9.4"} + } + :ns-default build + :exec-fn uberjar + } + } + } diff --git a/metadata.edn b/metadata.edn new file mode 100644 index 0000000..5f7f149 --- /dev/null +++ b/metadata.edn @@ -0,0 +1,8 @@ +{ + :version "0.1" + :target "target" + :java-src "src/java" + :clj-src "src/clj" + :main-ns "notifier.core" + :verbose true + } diff --git a/src/clj/notifier/core.clj b/src/clj/notifier/core.clj new file mode 100644 index 0000000..19551fc --- /dev/null +++ b/src/clj/notifier/core.clj @@ -0,0 +1,40 @@ +(ns notifier.core + (:import org.freedesktop.Notifications + org.freedesktop.dbus.connections.impl.DBusConnectionBuilder + org.freedesktop.dbus.types.UInt32)) + +(def ^:private ^:const NOTIFICATIONS_PATH "/org/freedesktop/Notifications") +(def ^:private ^:const NOTIFICATIONS_BUS "org.freedesktop.Notifications") + +(def urgencies {:low 0 :normal 1 :critical 2}) + +(defn connect-session-bus [] + (-> (DBusConnectionBuilder/forSessionBus) + (.build) + (.getRemoteObject NOTIFICATIONS_BUS NOTIFICATIONS_PATH Notifications))) + +(defn send-notification! + [bus + {:keys [app replace-id icon summary body actions timeout urgency] + :or {replace-id 0 + icon "" + actions [] + timeout -1 + urgency :low} + :as args}] + (doseq [arg [:app :summary :body]] + (when (not (contains? args arg)) + (throw (ex-info (format "missing required argument: %s" arg) + {:arg arg})))) + (let [urgency-lvl (get urgencies urgency)] + (when (nil? urgency-lvl) + (throw (ex-info (format "bad urgency level: %s" urgency) {})) + (.Notify bus + app + (UInt32. replace-id) + icon + summary + body + actions + { "urgency" urgency-lvl } + timeout)))) diff --git a/src/java/org/freedesktop/Notifications.java b/src/java/org/freedesktop/Notifications.java new file mode 100644 index 0000000..2909e8d --- /dev/null +++ b/src/java/org/freedesktop/Notifications.java @@ -0,0 +1,47 @@ +package org.freedesktop; + +import java.util.List; +import java.util.Map; +import org.freedesktop.dbus.interfaces.DBusInterface; +// import org.freedesktop.dbus.DBusSignal; +import org.freedesktop.dbus.types.UInt32; +import org.freedesktop.dbus.types.Variant; +import org.freedesktop.dbus.exceptions.DBusException; + +public interface Notifications extends DBusInterface { + // public static class ActionInvoked extends DBusSignal { + // public final UInt32 id; + // public final String action_key; + + // public ActionInvoked(String path, UInt32 id, String action_key) throws DBusException { + // super(path, id, action_key); + // this.id = id; + // this.action_key = action_key; + // } + // } + + // public static class NotificationClosed extends DBusSignal { + // public final UInt32 id; + // public final UInt32 reason; + + // public NotificationClosed(String path, UInt32 id, UInt32 reason) throws DBusException { + // super(path, id, reason); + // this.id = id; + // this.reason = reason; + // } + // } + + // public void CloseNotification(UInt32 id); + public List GetCapabilities(); + // public Quad GetServerInformation(); + + public UInt32 Notify( + String app_name, + UInt32 replaces_id, + String app_icon, + String summary, + String body, + List actions, + Map> hints, + int expire_timeout); +}