{"id":15873812,"url":"https://github.com/phronmophobic/clj-cef","last_synced_at":"2025-03-16T04:30:46.889Z","repository":{"id":62431942,"uuid":"336659872","full_name":"phronmophobic/clj-cef","owner":"phronmophobic","description":"Clojure bindings for the Chromium Embedded Framework","archived":false,"fork":false,"pushed_at":"2023-09-23T20:57:12.000Z","size":4167,"stargazers_count":51,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-04-27T03:02:54.196Z","etag":null,"topics":["cef","chromium-embedded-framework","clojure"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phronmophobic.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-06T23:40:47.000Z","updated_at":"2024-03-18T16:42:54.000Z","dependencies_parsed_at":"2023-09-23T23:40:16.746Z","dependency_job_id":null,"html_url":"https://github.com/phronmophobic/clj-cef","commit_stats":{"total_commits":168,"total_committers":1,"mean_commits":168.0,"dds":0.0,"last_synced_commit":"7c7f3f8e88d38f00547e47f1ad6c1218316e33de"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fclj-cef","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fclj-cef/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fclj-cef/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fclj-cef/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phronmophobic","download_url":"https://codeload.github.com/phronmophobic/clj-cef/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243802943,"owners_count":20350316,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cef","chromium-embedded-framework","clojure"],"created_at":"2024-10-06T01:06:58.525Z","updated_at":"2025-03-16T04:30:45.954Z","avatar_url":"https://github.com/phronmophobic.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# clj-cef\n\nClojure bindings for the Chromium Embedded Framework\n\nDependency:\n\n[![Clojars Project](https://img.shields.io/clojars/v/com.phronemophobic/clj-cef.svg)](https://clojars.org/com.phronemophobic/clj-cef)\n\n## Rationale\n\n\nFrom \u003chttps://bitbucket.org/chromiumembedded/cef/src/master/\u003e\n\n\u003e Some use cases for CEF include:\n\u003e \n\u003e- Embedding an HTML5-compliant Web browser control in an existing native application.\n\u003e- Creating a light-weight native “shell” application that hosts a user interface developed primarily using Web technologies.\n\u003e- Rendering Web content “off-screen” in applications that have their own custom drawing frameworks.\n\u003e- Acting as a host for automated testing of existing Web properties and applications.\n\nThe purpose of clj-cef is to make all of these features available from clojure. The current priority is to expose as much cef functionality as possible. As such, the current API tries to match the underlying cef c api as closely as possible. Future versions or projects may provide more idiomatic clojure wrapping.\n\nWe're typically spoiled by clojure libraries. Most libraries are made simple. They have worry free threading models. The JVM handles memory management. This is not one of those libraries. `clj-cef` is a thin wrapper around cef which has sharp edges. It also provides a huge amount of access and functionality that isn't really available otherwise. As much as possible, `clj-cef` tries to make correct code the path of least resistance while also providing as much access to the underlying functionality. If you have questions, drop by the #clj-cef channel on the clojurian's slack.\n\nCurrently, clj-cef will run on Mac OSX and linux.\n\n## Naming\n\nThe clojure and Java wrappers are generated from the cef header files. Translation of names and callbacks are as follows:\n\n| Struct                            | Naming               | Prefix  | Suffix | Example         | package/namespace         |\n| --                                | --                   | --      | --     | --              | --                        |\n| cef c struct                      | cef\\_struct\\_name\\_t | cef_    | \\_t    | cef\\_browser\\_t |                           |\n| Java Classes wrapping cef Structs | CamelCase            | Cef     |        | CefBrowser      | com.phronemophobic.cljcef |\n| clojure struct creation           | map-\u003estruct-name     | map-\u003e   |        | map-\u003ebrowser    | com.phronemophobic.cef    |\n| clojure struct manipulation       | merge-\u003estruct-name   | merge-\u003e |        | merge-\u003ebrowser  | com.phronemophobic.cef    |\n\n| Callback                        | Naming    | Example   |\n| --                              | --        | --        |\n| cef c struct callback           | func_name | load\\_url |\n| Java methods wrapping callbacks | camelCase | loadUrl   |\n\n\n## Threading\n\nIn general, most cef functions expect to be called on **the** main thread unless otherwise documented. On Mac OSX, the main thread is a very specific thread. If cef functions are called on the wrong thread, it will crash the jvm.\n\nTasks can be run on the main thread using `com.phronemophobic.cinterop/dispatch-sync` or `com.phronemophobic.cinterop/dispatch-async`.\n\n```clojure\n\n(require '[com.phronemophobic.cinterop\n           :refer [dispatch-sync\n                   dispatch-async]])\n\n;; synchronous. will return when the task completes\n(dispatch-sync\n (fn []\n   (cef/prepare-environment!)))\n\n;; asynchronous. will return immediately\n(dispatch-async\n (fn []\n   (cef/prepare-environment!)))\n```\n\n## Linux Dependencies\n\n```sh\napt install xvfb libatk1.0-dev libatk-bridge2.0-dev libxkbcommon-dev libxcomposite-dev libxrandr-dev libgbm-dev libxdamage-dev\n```\n\nWhen running cef on linux without a display, use xvfb. The easiest way to use xvfb is to prefix command line commands with `xvfb-run`. See https://magpcss.org/ceforum/viewtopic.php?t=16993 for more information. \n\n## Memory Management\n\nAll Cef* structs are automatically reference counted and managed by `clj-cef`. However, non Cef* struct data received from callbacks or provided to cef are not.\n\nTo prevent from crashing the JVM, follow these rules:\n- Retain references to any non Cef* struct data provided in calls to cef\n- Make copies of any data received from cef callbacks that will outlast the callback call. \n\n## Usage\n\nNote:If running on linux without a display, prefix cli commands with `xvfb-run`.\n\nAll the examples will use the following requires.\n\n```clojure\n(:require [com.phronemophobic.cef :as cef\n             :refer [print-doc]]\n            [com.phronemophobic.cinterop\n             :refer [dispatch-sync\n                     dispatch-async]])\n```\n\nThe main steps for using `clj-cef` are:\n1. Download and extract the Chromium Embedded Framework\n2. Initialize cef.\n3. Use the library\n\n### 1. Download and extract the Chromium Embedded Framework\n\nThe cef framework is about 80MB compressed (~230MB uncompressed) which makes it a poor fit including within the library jar. On linux, 300MB compressed and 1GB uncompressed.\n\n```clojure\n;; will download and extract cef framework to /tmp/com.phronemophobic.cef/\n(dispatch-sync\n (fn []\n   (cef/download-and-prepare-environment!)))\n\n;; or \n;; provide target dir\n;; (dispatch-sync\n;;  (fn []\n;;    (cef/download-and-prepare-environment! target-dir)))\n```\n\n### 2. Initialize cef\n\n\n```clojure\n(dispatch-sync\n (fn []\n   (let [app (cef/map-\u003eapp\n              {:get-browser-process-handler\n               (fn [this]\n                 (cef/map-\u003ebrowser-process-handler\n                  {:on-context-initialized\n                   (fn [this]\n                     (println \"initialized!\"))}))})]\n     (cef/cef-initialize app))))\n```\n\nIf you used a custom target directory for cef, pass the target dir to `cef/cef-initialize` like so: `(cef/cef-initialize app target-dir)`.\n\nNote: clj-cef is running in the browser process (see [processes](https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-processes)). A generic render process is used automatically.\n\n### 3. Use the library\n\nThe cef library has a huge amount of functionality. For examples check out:\n\n[browser](examples/browser): A simple browser UI using membrane+skija.  \n[htmltoimage](examples/htmltoimage): A cli for converting a url to an image.  \n[cssinspect](examples/cssinspect): A cli for calculating css coverage and finding unused css for a url.  \n\n## Cef message loop\n\nThe browser does its work in a message loop. There are two ways to run the message loop:\n\n1. `cef-run-message-loop`\n\n```clojure\n(dispatch-async\n (fn []\n   (cef/cef-run-message-loop)))\n```\n\nCalling `cef-run-message-loop` will take over the main thread until `cef-quit-message-loop` is called (`dispatch-sync` and `dispatch-async` tasks won't be run until the message loop quits).\n\nTasks can be posted to the cef message loop using `cef/post-task-to-main`:\n\n```clojure\n(cef/post-task-to-main\n (fn []\n   (.loadUrl (.getMainFrame browser) url)))\n```\n\n```clojure\n;; quit the message loop\n(cef/post-task-to-main cef/cef-quit-message-loop)\n```\n\nUsing `cef-run-message-loop` is the easiest way to make sure the message loop is being pumped, but it's less flexible. Additionally, since it takes over **the** main thread, other resources that require **the** main thread (eg. any UI code like skija, javafx, swing, etc.) will be starved.\n\n2. `cef-do-message-loop-work`\n\nThe `cef-do-message-loop-work` function will perform a single iteration of CEF message loop work. This method is more flexible and makes it possible to integrate cef with other projects that also require running on **the** main thread.\n\n```clojure\n(dispatch-sync\n (fn []\n   (.loadUrl (.getMainFrame browser) url)\n   (doseq [i (range 15)\n           :while (= 1 (.isLoading browser))]\n     (cef/cef-do-message-loop-work)\n     (Thread/sleep 500))))\n```\n\nFor more info, check out the [examples](examples/) or cef docs.\n[Message loop docs](https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-message-loop-integration)\n\n## Documentation\n\nAll `com.phronemophobic.cef/map-\u003e`* and `com.phronemophobic.cef/merge-\u003e`* functions have the comments provided by their wrapped counter parts from the cef library. Additionally, all Cef* struct instances can have their documentation printed or retrieved using `com.phronemophobic.cef/print-doc` and `com.phronemophobic.cef/doc` respectively.\n\n[CEF Project page](https://bitbucket.org/chromiumembedded/cef/src/master/)  \n[Cef API docs](https://bitbucket.org/chromiumembedded/cef/src/master/)  \n[clj-cef reference docs](https://phronmophobic.github.io/clj-cef/)  \n[Examples](examples/)  \n\n If you have questions, drop by the #clj-cef channel on the clojurian's slack.\n\n## Scary Keychain popup\n\n\u003e java wants to use your confidential information stored in \"Chromium Safe Storage\" in your keychain.\n\nYou can deny and things will continue to work, but cookies might not be encrypted. It's unclear based off the available documentation.\n\nSee https://bitbucket.org/chromiumembedded/cef/issues/2692/mac-networkservice-allow-custom-service.\n\nPer the issue:\n\u003e This prompt can be disabled and cookies will not be encrypted if you pass the --use-mock-keychain command-line flag.\n\nFor example:\n```clojure\n\n;; assuming app created during setup\n\n;; modify the CefApp\n(cef/merge-\u003eapp app\n                {:on-before-command-line-processing\n                 (fn [app s command-line]\n                   (.appendSwitch command-line \"--use-mock-keychain\"))})\n\n;; initialize as normal\n(cef/cef-initialize app)\n\n```\n\n## FAQ\n\n### Why aren't my callbacks being called?\n\nYou need to pump the cef event loop with either `cef/cef-run-message-loop` or `cef/cef-do-message-loop-work`.\n\n### Why am I getting \"Unable to open X display\"?\n\nCef requires an X display on linux. Use xvfb. See linux docs above and https://magpcss.org/ceforum/viewtopic.php?t=16993 for more information.\n\n### Why not java-cef?\n\n* java-cef wraps cef which wraps the Chromium library. The c api provided by cef is fairly clojure friendly (thanks to JNA). \n* the java wrapper doesn't make accessing cef from clojure any easier.\n* java-cef is hard to build, https://bitbucket.org/chromiumembedded/java-cef/wiki/BranchesAndBuilding\n* java-cef enforces a rigid application structure, https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-mac-os-x\n* java-cef is not repl friendly\n\n### Why is `get-render-process-handler` never called?\n\nthe render process is a completely different OS process. While providing a render process handler using `clj-cef` is technically possible, it's not very straightforward. Fortuately, most interesting functionality can be accessed solely from the browser process. If you need a render process handler, please file an issue.\n\n## Easy ways to crash the JVM\n\n- Call Cef functions before preparing or initializing cef\n- Calling a cef function on the wrong thread\n- Passing data to cef that may be garbage collected before it's done being used\n- Holding onto data that may be freed\n- Pay careful attention to the expected return types of callbacks.\n\n# License\n\nCopyright 2021 Adrian Smith. clj-cef is licensed under Apache License v2.0.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphronmophobic%2Fclj-cef","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphronmophobic%2Fclj-cef","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphronmophobic%2Fclj-cef/lists"}