((section 2 "Outdated egg!" (p "This is an egg for CHICKEN 4, the unsupported old release.  You're almost certainly looking for " (int-link "/eggref/5/i3" "the CHICKEN 5 version of this egg") ", if it exists.") (p "If it does not exist, there may be equivalent functionality provided by another egg; have a look at the " (link "https://wiki.call-cc.org/chicken-projects/egg-index-5.html" "egg index") ". Otherwise, please consider porting this egg to the current version of CHICKEN.")) (section 2 "i3" (p "Extends the i3 window manager via its IPC interface.") (toc) (section 3 (tt "i3") (p (b "[module]") " " (tt "i3")) (p "Note that there are more examples than what is documented here at " (link "http://code.stapelberg.de/git/i3-egg/tree/examples") ". That repository is also the canonical location for this egg’s source code.") (ul (li (int-link "#connect" "connect")) (li (int-link "#cmd" "cmd")) (li (int-link "#subscribe" "subscribe")) (li (int-link "#tree" "tree")) (li (int-link "#workspaces" "workspaces")) (li (int-link "#filter-containers" "filter-containers")) (li (int-link "#descend-focused" "descend-focused")) (li (int-link "#focused-con" "focused-con")) (li (int-link "#connection?" "connection?")) (li (int-link "#process-events-forever" "process-events-forever")))) (section 3 (tt "connect") (def (sig (procedure "(connect) → connection" (id connect))) (p "Connects to i3 running on the display specified by the environment variable " (tt "DISPLAY") ".") (highlight scheme "(define (connect)\n  (let ((cmd-fd (socket af/unix sock/stream))\n        (event-fd (socket af/unix sock/stream)))\n    (socket-connect cmd-fd (unix-address (i3-socket-path)))\n    (socket-connect event-fd (unix-address (i3-socket-path)))\n    (let ((conn (make-i3-conn cmd-fd event-fd (make-mutex) #f '())))\n      (i3-conn-event-thread-set!\n        conn\n        (thread-start! (lambda () (read-events conn))))\n      conn)))"))) (section 3 (tt "cmd") (def (sig (procedure "(cmd conn msg #!optional (type 0)) → reply + reply-type" (id cmd))) (p "Sends the given MSG to i3, by default as command.") (dl (dt "conn") (dd "A connection to i3, created with " (int-link "#connect" "(connect)") ".") (dt "msg") (dd "The payload of the message, e.g. a command when " (tt "type") " is 0.") (dt "type") (dd "The numeric message type, “COMMAND” (0) by default.  See also " (link "http://i3wm.org/docs/ipc.html#_sending_messages_to_i3") " for message types.")) (highlight scheme "(define (cmd conn msg #!optional (type 0))\n  (let ((sock (i3-conn-cmd-fd conn)))\n    (socket-send-all sock (i3-format-ipc-message msg type))\n    (i3-read-one-message sock)))")) (section 4 "Examples" (p "Change focus to the window to the right:") (pre "(cmd (connect) \"focus right\")"))) (section 3 (tt "subscribe") (def (sig (procedure "(subscribe conn event thunk) → unspecified" (id subscribe))) (p "Subscribes to the specified EVENT (e.g. \"workspace\") and calls THUNK when an event arrives.") (highlight scheme "(define (subscribe conn event thunk)\n  (i3-conn-callbacks-set!\n    conn\n    (alist-update!\n      (alist-ref event i3-event-name-to-type string=?)\n      thunk\n      (i3-conn-callbacks conn)))\n  (let ((sock (i3-conn-event-fd conn)) (mutex (i3-conn-evmutex conn)))\n    (mutex-lock! mutex)\n    (socket-send-all\n      sock\n      (i3-format-ipc-message (json->string (vector event)) 2))\n    (i3-read-one-message sock)\n    (mutex-unlock! mutex)))"))) (section 3 (tt "tree") (def (sig (procedure "(tree conn) → reply + reply-type" (id tree))) (p "Convenience function to get the layout tree from i3.") (p "See " (link "http://i3wm.org/docs/ipc.html#_tree_reply") " for the reply format.") (dl (dt "conn") (dd "A connection to i3, created with " (int-link "#connect" "(connect)") ".")) (highlight scheme "(define (tree conn) (cmd conn \"\" 4))")) (section 4 "Examples" (p "Return a list of all Chrome windows:") (pre "(filter-containers\n (lambda (con) (string-suffix? \" - Google Chrome\" (alist-ref 'name con)))\n (tree (connect)))"))) (section 3 (tt "workspaces") (def (sig (procedure "(workspaces conn) → reply + reply-type" (id workspaces))) (p "Convenience function to get the workspaces from i3.") (p "See " (link "http://i3wm.org/docs/ipc.html#_workspaces_reply") " for the reply format.") (dl (dt "conn") (dd "A connection to i3, created with " (int-link "#connect" "(connect)"))) (highlight scheme "(define (workspaces conn) (cmd conn \"\" 1))"))) (section 3 (tt "filter-containers") (def (sig (procedure "(filter-containers predicate tree) → list" (id filter-containers))) (p "Returns a list containing all containers for which the given predicate returns #t.") (dl (dt "predicate") (dd "Predicate which is evaluated for each i3 container. Only containers for which the predicate returns #t are included in the return list") (dt "tree") (dd "(Part of) a list of containers as returned by " (int-link "#tree" "(tree)") ".")) (highlight scheme "(define (filter-containers predicate tree)\n  (if (null? tree)\n    '()\n    (append\n      (if (predicate tree) (list tree) (list))\n      (apply append\n             (filter-map\n               (lambda (node) (filter-containers predicate node))\n               (cdr (assoc 'nodes tree)))))))")) (section 4 "Examples" (p "Return a list of all Chrome windows:") (pre "(filter-containers\n (lambda (con) (string-suffix? \" - Google Chrome\" (alist-ref 'name con)))\n (tree (connect)))"))) (section 3 (tt "descend-focused") (def (sig (procedure "(descend-focused stop-predicate tree) → alist" (id descend-focused))) (p "Descends the focused containers of the given TREE, stopping at the first container which satisfies STOP-PREDICATE.") (dl (dt "stop-predicate") (dd "Processing stops when this predicate first returns true. The return value is the container with which this predicate was evaluated.") (dt "tree") (dd "(Part of) a list of containers as returned by " (int-link "#tree" "(tree)") ".")) (highlight scheme "(define (descend-focused stop-predicate tree)\n  (if (stop-predicate tree)\n    tree\n    (if (null? (alist-ref 'focus tree))\n      tree\n      (descend-focused\n        stop-predicate\n        (let ((focused-id (first (alist-ref 'focus tree))))\n          (find (lambda (con) (= (alist-ref 'id con) focused-id))\n                (append\n                  (alist-ref 'nodes tree)\n                  (alist-ref 'floating_nodes tree))))))))"))) (section 3 (tt "focused-con") (def (sig (procedure "(focused-con tree) → alist" (id focused-con))) (p "Returns the currently focused container.") (dl (dt "tree") (dd "(Part of) a list of containers as returned by " (int-link "#tree" "(tree)") ".")) (highlight scheme "(define (focused-con tree)\n  (descend-focused (lambda (con) (null? (alist-ref 'nodes con))) tree))")) (section 4 "Examples" (p "Print the name of the currently focused window:") (pre "(format #t \"~A~N\" (alist-ref 'name (focused-con (tree (connect)))))") (p "Print the name of the focused window of workspace 1:") (pre "(let ((ws-1\n       (first\n        (filter-containers\n         (lambda (con)\n           (and (= (alist-ref 'type con) 4)\n                (string= (alist-ref 'name con) \"1\")))\n         (tree (connect))))))\n  (format #t \"~A~N\" (focused-con ws-1)))"))) (section 3 "About this egg" (section 4 "Author" (p (int-link "/users/anonymous" "Michael Stapelberg"))) (section 4 "Colophon" (p "Documented by " (int-link "/egg/cock" "cock") ".")))))