subtree(3p/exwm): update & hard reset to commit 'a6e66f5e33'

This contains a bunch of upstream changes after the new maintainers of
EXWM took over, including proper mainlined versions of patches I've
been carrying around here manually.

Notably this undoes the Chromium focus fix patch, lets see how that goes.

git-subtree-dir: third_party/exwm
git-subtree-mainline: a756b46bc70a8a1dbb205d50283a3fe65282ed91
git-subtree-split: a6e66f5e33
Change-Id: Ibcaba379b56611b8f1918c3b60469492d64a3eb7
This commit is contained in:
Vincent Ambo 2024-02-06 10:03:20 +03:00
commit 35e7b8a1a8
16 changed files with 483 additions and 163 deletions

View file

@ -1 +1,2 @@
LICENSE
README.md

View file

@ -1,6 +1,6 @@
;;; exwm-background.el --- X Background Module for EXWM -*- lexical-binding: t -*-
;; Copyright (C) 2022-2023 Free Software Foundation, Inc.
;; Copyright (C) 2022-2024 Free Software Foundation, Inc.
;; Author: Steven Allen <steven@stebalien.com>
@ -27,7 +27,7 @@
;; (require 'exwm-background)
;; (exwm-background-enable)
;;
;; By default, this will apply the theme's background color. However, that
;; By default, this will apply the theme's background color. However, that
;; color can be customized via the `exwm-background-color' setting.
;;; Code:
@ -47,13 +47,13 @@
(defconst exwm-background--properties '("_XROOTPMAP_ID" "_XSETROOT_ID" "ESETROOT_PMAP_ID")
"The background properties to set.
We can't need to set these so that compositing window managers can correctly display the background
color.")
We can't need to set these so that compositing window managers
can correctly display the background color.")
(defvar exwm-background--connection nil
"The X connection used for setting the background.
We use a separate connection as other background-setting tools may kill this connection when they
replace it.")
We use a separate connection as other background-setting tools
may kill this connection when they replace it.")
(defvar exwm-background--pixmap nil
"Cached background pixmap.")

View file

@ -1,50 +0,0 @@
;;; exwm-cm.el --- Compositing Manager for EXWM -*- lexical-binding: t -*-
;; Copyright (C) 2016-2023 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This module is obsolete since EXWM now supports third-party compositors.
;;; Code:
(make-obsolete-variable 'exwm-cm-opacity
"This variable should no longer be used." "26")
(defun exwm-cm-set-opacity (&rest _args)
(declare (obsolete nil "26")))
(defun exwm-cm-enable ()
(declare (obsolete nil "26")))
(defun exwm-cm-start ()
(declare (obsolete nil "26")))
(defun exwm-cm-stop ()
(declare (obsolete nil "26")))
(defun exwm-cm-toggle ()
(declare (obsolete nil "26")))
(provide 'exwm-cm)
;;; exwm-cm.el ends here

View file

@ -1,6 +1,6 @@
;;; exwm-config.el --- Predefined configurations -*- lexical-binding: t -*-
;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
;; Copyright (C) 2015-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>

View file

@ -1,6 +1,6 @@
;;; exwm-core.el --- Core definitions -*- lexical-binding: t -*-
;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
;; Copyright (C) 2015-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>
@ -33,6 +33,10 @@
(require 'xcb-ewmh)
(require 'xcb-debug)
(defgroup exwm-debug nil
"Debugging."
:group 'exwm)
(defcustom exwm-debug-log-time-function #'exwm-debug-log-uptime
"Function used for generating timestamps in `exwm-debug' logs.
@ -40,7 +44,6 @@ Here are some predefined candidates:
`exwm-debug-log-uptime': Display the uptime of this Emacs instance.
`exwm-debug-log-time': Display time of day.
`nil': Disable timestamp."
:group 'exwm-debug
:type `(choice (const :tag "Emacs uptime" ,#'exwm-debug-log-uptime)
(const :tag "Time of day" ,#'exwm-debug-log-time)
(const :tag "Off" nil)
@ -203,7 +206,7 @@ If FRAME is null, use selected frame."
"Convert COLOR to PIXEL (index in TrueColor colormap)."
(when (and color
(eq (x-display-visual-class) 'true-color))
(let ((rgb (x-color-values color)))
(let ((rgb (color-values color)))
(logior (ash (ash (pop rgb) -8) 16)
(ash (ash (pop rgb) -8) 8)
(ash (pop rgb) -8)))))

View file

@ -1,6 +1,6 @@
;;; exwm-floating.el --- Floating Module for EXWM -*- lexical-binding: t -*-
;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
;; Copyright (C) 2015-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>
@ -31,17 +31,16 @@
(defgroup exwm-floating nil
"Floating."
:version "25.3"
:group 'exwm)
(defcustom exwm-floating-setup-hook nil
"Normal hook run when an X window has been made floating, in the
context of the corresponding buffer."
"Normal hook run when an X window has been made floating.
This hook runs in the context of the corresponding buffer."
:type 'hook)
(defcustom exwm-floating-exit-hook nil
"Normal hook run when an X window has exited floating state, in the
context of the corresponding buffer."
"Normal hook run when an X window has exited floating state.
This hook runs in the context of the corresponding buffer."
:type 'hook)
(defcustom exwm-floating-border-color "navy"

View file

@ -1,6 +1,6 @@
;;; exwm-input.el --- Input Module for EXWM -*- lexical-binding: t -*-
;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
;; Copyright (C) 2015-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>
@ -40,7 +40,6 @@
(defgroup exwm-input nil
"Input."
:version "25.3"
:group 'exwm)
(defcustom exwm-input-prefix-keys
@ -102,6 +101,13 @@ defined in `exwm-mode-map' here."
(defconst exwm-input--update-focus-interval 0.01
"Time interval (in seconds) for accumulating input focus update requests.")
(defconst exwm-input--passthrough-functions '(read-char
read-char-exclusive
read-key-sequence-vector
read-key-sequence
read-event)
"Low-level read functions that must be exempted from EXWM input handling.")
(defvar exwm-input--during-command nil
"Indicate whether between `pre-command-hook' and `post-command-hook'.")
@ -129,11 +135,14 @@ defined in `exwm-mode-map' here."
(defvar exwm-input--timestamp-window nil)
(defvar exwm-input--update-focus-timer nil
"Timer for deferring the update of input focus.")
(defvar exwm-input--update-focus-lock nil
"Lock for solving input focus update contention.")
(defvar exwm-input--update-focus-timer nil
"Timer for deferring the update of input focus.")
(defvar exwm-input--update-focus-window nil "The (Emacs) window to be focused.
This value should always be overwritten.")
(defvar exwm-input--echo-area-timer nil "Timer for detecting echo area dirty.")
@ -291,38 +300,38 @@ ARGS are additional arguments to CALLBACK."
"Run in `buffer-list-update-hook' to track input focus."
(when (and ; this hook is called incesantly; place cheap tests on top
(not exwm-input--skip-buffer-list-update)
(exwm--terminal-p)) ; skip other terminals, e.g. TTY client frames
(exwm--terminal-p) ; skip other terminals, e.g. TTY client frames
(not (frame-parameter nil 'no-accept-focus)))
(exwm--log "current-buffer=%S selected-window=%S"
(current-buffer) (selected-window))
(redirect-frame-focus (selected-frame) nil)
(setq exwm-input--update-focus-window (selected-window))
(exwm-input--update-focus-defer)))
(defun exwm-input--update-focus-defer ()
"Defer updating input focus."
(redirect-frame-focus (selected-frame) nil)
"Schedule a deferred update to input focus.
Instead of immediately focusing the current window, it defers the focus change
until the selected window stops changing (debouncing input focus updates)."
(when exwm-input--update-focus-timer
(cancel-timer exwm-input--update-focus-timer))
(setq exwm-input--update-focus-timer
;; Attempt to accumulate successive events close enough.
(run-with-timer exwm-input--update-focus-interval
nil
#'exwm-input--update-focus-commit
(selected-window))))
#'exwm-input--update-focus-commit)))
(defun exwm-input--update-focus-commit (window)
"Commit updating input focus."
(let ((cwin (selected-window)))
(if exwm-input--update-focus-lock
(unless (eq exwm-input--update-focus-lock cwin)
(exwm-input--update-focus-defer))
(if (and cwin window (eq cwin window))
(let ((exwm-input--update-focus-lock cwin))
(exwm-input--update-focus window))
(exwm-input--update-focus-defer)))))
(defun exwm-input--update-focus-commit ()
"Attempt to update the window focus.
If we're currently updating the window focus, re-schedule a focus update
attempt later."
(if exwm-input--update-focus-lock
(exwm-input--update-focus-defer)
(let ((exwm-input--update-focus-lock t))
(exwm-input--update-focus exwm-input--update-focus-window))))
(defun exwm-input--update-focus (window)
"Update input focus."
(when (and (window-live-p window)
(not (frame-parameter (window-frame window) 'no-accept-focus)))
"Update input focus to WINDOW."
(when (window-live-p window)
(exwm--log "focus-window=%s focus-buffer=%s" window (window-buffer window))
(with-current-buffer (window-buffer window)
(if (derived-mode-p 'exwm-mode)
@ -573,20 +582,10 @@ instead."
(when (called-interactively-p 'any)
(exwm-input--update-global-prefix-keys)))
;; Putting (t . EVENT) into `unread-command-events' does not really work
;; as documented for Emacs < 26.2.
(eval-and-compile
(if (or (< emacs-major-version 26)
(and (= emacs-major-version 26)
(< emacs-minor-version 2)))
(defsubst exwm-input--unread-event (event)
(declare (indent defun))
(setq unread-command-events
(append unread-command-events (list event))))
(defsubst exwm-input--unread-event (event)
(declare (indent defun))
(setq unread-command-events
(append unread-command-events `((t . ,event)))))))
(defsubst exwm-input--unread-event (event)
(declare (indent defun))
(setq unread-command-events
(append unread-command-events `((t . ,event)))))
(defun exwm-input--mimic-read-event (event)
"Process EVENT as if it were returned by `read-event'."
@ -747,7 +746,7 @@ Current buffer must be an `exwm-mode' buffer."
(defun exwm-input--on-ButtonPress-line-mode (buffer button-event)
"Handle button events in line mode.
BUFFER is the `exwm-mode' buffer the event was generated
on. BUTTON-EVENT is the X event converted into an Emacs event.
on. BUTTON-EVENT is the X event converted into an Emacs event.
The return value is used as event_mode to release the original
button event."
@ -970,11 +969,6 @@ multiple keys. If END-KEY is non-nil, stop sending keys if it's pressed."
#'exwm-input-send-simulation-key))))
exwm-input--simulation-keys))
(defun exwm-input-set-simulation-keys (simulation-keys)
"Please customize or set `exwm-input-simulation-keys' instead."
(declare (obsolete nil "26"))
(exwm-input--set-simulation-keys simulation-keys))
(defcustom exwm-input-simulation-keys nil
"Simulation keys.
@ -1151,6 +1145,11 @@ One use is to access the keymap bound to KEYS (as prefix keys) in `char-mode'."
(exwm--log)
(exwm-input--on-minibuffer-exit)))
(defun exwm-input--call-with-passthrough (function &rest args)
"Bind `exwm-input-line-mode-passthrough' and call FUNCTION with ARGS."
(let ((exwm-input-line-mode-passthrough t))
(apply function args)))
(defun exwm-input--init ()
"Initialize the keyboard module."
(exwm--log)
@ -1206,7 +1205,10 @@ One use is to access the keymap bound to KEYS (as prefix keys) in `char-mode'."
(run-with-idle-timer 0 t #'exwm-input--on-echo-area-dirty))
(add-hook 'echo-area-clear-hook #'exwm-input--on-echo-area-clear)
;; Update focus when buffer list updates
(add-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update))
(add-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update)
(dolist (fun exwm-input--passthrough-functions)
(advice-add fun :around #'exwm-input--call-with-passthrough)))
(defun exwm-input--post-init ()
"The second stage in the initialization of the input module."
@ -1216,6 +1218,8 @@ One use is to access the keymap bound to KEYS (as prefix keys) in `char-mode'."
(defun exwm-input--exit ()
"Exit the input module."
(exwm--log)
(dolist (fun exwm-input--passthrough-functions)
(advice-remove fun #'exwm-input--call-with-passthrough))
(exwm-input--unset-simulation-keys)
(remove-hook 'pre-command-hook #'exwm-input--on-pre-command)
(remove-hook 'post-command-hook #'exwm-input--on-post-command)

View file

@ -1,6 +1,6 @@
;;; exwm-layout.el --- Layout Module for EXWM -*- lexical-binding: t -*-
;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
;; Copyright (C) 2015-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>
@ -29,7 +29,6 @@
(defgroup exwm-layout nil
"Layout."
:version "25.3"
:group 'exwm)
(defcustom exwm-layout-auto-iconify t
@ -146,8 +145,8 @@ See variable `exwm-layout-auto-iconify'."
(exwm--set-geometry id x y width height)
(xcb:+request exwm--connection (make-instance 'xcb:MapWindow :window id))
(exwm-layout--set-state id xcb:icccm:WM_STATE:NormalState)
;; (setq exwm--ewmh-state
;; (delq xcb:Atom:_NET_WM_STATE_HIDDEN exwm--ewmh-state))
(setq exwm--ewmh-state
(delq xcb:Atom:_NET_WM_STATE_HIDDEN exwm--ewmh-state))
(exwm-layout--set-ewmh-state id)
(exwm-layout--auto-iconify)))
(xcb:flush exwm--connection))
@ -157,7 +156,8 @@ See variable `exwm-layout-auto-iconify'."
(with-current-buffer (exwm--id->buffer id)
(unless (or (exwm-layout--iconic-state-p)
(and exwm--floating-frame
(eq 4294967295. exwm--desktop)))
exwm--desktop
(= 4294967295. exwm--desktop)))
(exwm--log "Hide #x%x" id)
(when exwm--floating-frame
(let* ((container (frame-parameter exwm--floating-frame
@ -182,7 +182,7 @@ See variable `exwm-layout-auto-iconify'."
:window id :value-mask xcb:CW:EventMask
:event-mask (exwm--get-client-event-mask)))
(exwm-layout--set-state id xcb:icccm:WM_STATE:IconicState)
;; (cl-pushnew xcb:Atom:_NET_WM_STATE_HIDDEN exwm--ewmh-state)
(cl-pushnew xcb:Atom:_NET_WM_STATE_HIDDEN exwm--ewmh-state)
(exwm-layout--set-ewmh-state id)
(exwm-layout--auto-iconify)
(xcb:flush exwm--connection))))
@ -207,8 +207,7 @@ See variable `exwm-layout-auto-iconify'."
xcb:ConfigWindow:StackMode)
:border-width 0
:stack-mode xcb:StackMode:Above))
;; commented out to work around https://github.com/ch11ng/exwm/issues/759
;; (cl-pushnew xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)
(cl-pushnew xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)
(exwm-layout--set-ewmh-state exwm--id)
(xcb:flush exwm--connection)
(set-window-dedicated-p (get-buffer-window) t)

View file

@ -1,7 +1,7 @@
;;; exwm-manage.el --- Window Management Module for -*- lexical-binding: t -*-
;;; EXWM
;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
;; Copyright (C) 2015-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>
@ -30,7 +30,6 @@
(defgroup exwm-manage nil
"Manage."
:version "25.3"
:group 'exwm)
(defcustom exwm-manage-finish-hook nil
@ -235,6 +234,23 @@ Override current hinds if FORCE is non-nil."
(elt value 2))) ;MotifWmHints.decorations
(setq exwm--mwm-hints-decorations nil))))))))
(defun exwm-manage--update-default-directory (id)
"Update the `default-directory' of X window ID.
Sets the `default-directory' of the EXWM buffer associated with X window to
match its current working directory.
This only works when procfs is mounted, which may not be the case on some BSDs."
(with-current-buffer (exwm--id->buffer id)
(if-let* ((response (xcb:+request-unchecked+reply exwm--connection
(make-instance 'xcb:ewmh:get-_NET_WM_PID
:window id)))
(pid (slot-value response 'value))
(cwd (file-symlink-p (format "/proc/%d/cwd" pid)))
((file-accessible-directory-p cwd)))
(setq default-directory (file-name-as-directory cwd))
(setq default-directory (expand-file-name "~/")))))
(defun exwm-manage--set-client-list ()
"Set _NET_CLIENT_LIST."
(exwm--log)
@ -394,23 +410,20 @@ Override current hinds if FORCE is non-nil."
(if (plist-get exwm--configurations 'char-mode)
(exwm-input-release-keyboard id)
(exwm-input-grab-keyboard id))
(let ((simulation-keys (plist-get exwm--configurations 'simulation-keys))
(prefix-keys (plist-get exwm--configurations 'prefix-keys)))
(with-current-buffer (exwm--id->buffer id)
(when simulation-keys
(exwm-input-set-local-simulation-keys simulation-keys))
(when prefix-keys
(setq-local exwm-input-prefix-keys prefix-keys))))
(when-let ((simulation-keys (plist-get exwm--configurations 'simulation-keys)))
(exwm-input-set-local-simulation-keys simulation-keys))
(when-let ((prefix-keys (plist-get exwm--configurations 'prefix-keys)))
(setq-local exwm-input-prefix-keys prefix-keys))
(setq exwm-workspace--switch-history-outdated t)
(exwm--update-desktop id)
(exwm-manage--update-ewmh-state id)
(with-current-buffer (exwm--id->buffer id)
(when (or (plist-get exwm--configurations 'fullscreen)
(exwm-layout--fullscreen-p))
(setq exwm--ewmh-state (delq xcb:Atom:_NET_WM_STATE_FULLSCREEN
exwm--ewmh-state))
(exwm-layout-set-fullscreen id))
(run-hooks 'exwm-manage-finish-hook)))))
(exwm-manage--update-default-directory id)
(when (or (plist-get exwm--configurations 'fullscreen)
(exwm-layout--fullscreen-p))
(setq exwm--ewmh-state (delq xcb:Atom:_NET_WM_STATE_FULLSCREEN
exwm--ewmh-state))
(exwm-layout-set-fullscreen id))
(run-hooks 'exwm-manage-finish-hook))))
(defun exwm-manage--unmanage-window (id &optional withdraw-only)
"Unmanage window ID.

View file

@ -1,6 +1,6 @@
;;; exwm-randr.el --- RandR Module for EXWM -*- lexical-binding: t -*-
;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
;; Copyright (C) 2015-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>
@ -56,7 +56,6 @@
(defgroup exwm-randr nil
"RandR."
:version "25.3"
:group 'exwm)
(defcustom exwm-randr-refresh-hook nil
@ -91,10 +90,6 @@ corresponding monitors whenever the monitors are active.
\\='(1 \"HDMI-1\" 3 \"DP-1\")"
:type '(plist :key-type integer :value-type string))
(with-no-warnings
(define-obsolete-variable-alias 'exwm-randr-workspace-output-plist
'exwm-randr-workspace-monitor-plist "27.1"))
(defvar exwm-randr--last-timestamp 0 "Used for debouncing events.")
(defvar exwm-randr--prev-screen-change-seqnum nil
@ -269,9 +264,6 @@ In a mirroring setup some monitors overlap and should be treated as one."
(xcb:flush exwm--connection)
(run-hooks 'exwm-randr-refresh-hook))))
(define-obsolete-function-alias 'exwm-randr--refresh #'exwm-randr-refresh
"27.1")
(defun exwm-randr--on-ScreenChangeNotify (data _synthetic)
"Handle `ScreenChangeNotify' event.

View file

@ -1,7 +1,7 @@
;;; exwm-systemtray.el --- System Tray Module for -*- lexical-binding: t -*-
;;; EXWM
;; Copyright (C) 2016-2023 Free Software Foundation, Inc.
;; Copyright (C) 2016-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>
@ -57,7 +57,6 @@
(defgroup exwm-systemtray nil
"System tray."
:version "25.3"
:group 'exwm)
(defcustom exwm-systemtray-height nil

View file

@ -1,6 +1,6 @@
;;; exwm-workspace.el --- Workspace Module for EXWM -*- lexical-binding: t -*-
;; Copyright (C) 1015-2023 Free Software Foundation, Inc.
;; Copyright (C) 1015-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>
@ -31,7 +31,6 @@
(defgroup exwm-workspace nil
"Workspace."
:version "25.3"
:group 'exwm)
(defcustom exwm-workspace-switch-hook nil

View file

@ -1,6 +1,6 @@
;;; exwm-xim.el --- XIM Module for EXWM -*- lexical-binding: t -*-
;; Copyright (C) 2019-2023 Free Software Foundation, Inc.
;; Copyright (C) 2019-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>

336
third_party/exwm/exwm-xsettings.el vendored Normal file
View file

@ -0,0 +1,336 @@
;;; exwm-xsettings.el --- XSETTINGS Module for EXWM -*- lexical-binding: t -*-
;; Copyright (C) 2022-2024 Free Software Foundation, Inc.
;; Author: Steven Allen <steven@stebalien.com>
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Implements the XSETTINGS protocol, allowing Emacs to manage the system theme,
;; fonts, icons, etc.
;;
;; This package can be configured as follows:
;;
;; (require 'exwm-xsettings)
;; (setq exwm-xsettings-theme '("Adwaita" . "Adwaita-dark") ;; light/dark
;; exwm-xsettings `(("Xft/HintStyle" . "hintslight")
;; ("Xft/RGBA" . "rgb")
;; ("Xft/lcdfilter" . "lcddefault")
;; ("Xft/Antialias" . 1)
;; ;; DPI is in 1024ths of an inch, so this is a DPI of
;; ;; 144, equivalent to ;; a scaling factor of 1.5
;; ;; (144 = 1.5 * 96).
;; ("Xft/DPI" . ,(* 144 1024))
;; ("Xft/Hinting" . 1)))
;; (exwm-xsettings-enable)
;;
;; To modify these settings at runtime, customize them with
;; `custom-set-variables' or `setopt' (Emacs 29+). E.g., the following will
;; immediately change the icon theme to "Papirus" at runtime, even in running
;; applications:
;;
;; (setopt exwm-xsettings-icon-theme "Papirus")
;;; Code:
(require 'xcb-ewmh)
(require 'xcb-xsettings)
(require 'exwm-core)
(defvar exwm-xsettings--connection nil)
(defvar exwm-xsettings--XSETTINGS_SETTINGS-atom nil)
(defvar exwm-xsettings--XSETTINGS_S0-atom nil)
(defvar exwm-xsettings--selection-owner-window nil)
(defvar exwm-xsettings--serial 0)
(defun exwm-xsettings--rgba-match (_widget value)
"Return t if VALUE is a valid RGBA color."
(and (numberp value) (<= 0 value 1)))
(defun exwm-xsettings--custom-set (symbol value)
"Setter used by `exwm-xsettings' customization options.
SYMBOL is the setting being updated and VALUE is the new value."
(set-default-toplevel-value symbol value)
(exwm-xsettings--update-settings))
(defgroup exwm-xsettings nil
"XSETTINGS."
:group 'exwm)
(defcustom exwm-xsettings nil
"Alist of custom XSETTINGS.
These settings take precedence over `exwm-xsettings-theme' and
`exwm-xsettings-icon-theme'."
:type '(alist :key-type (string :tag "Name")
:value-type (choice :tag "Value"
(string :tag "String")
(integer :tag "Integer")
(list :tag "Color"
(number :tag "Red"
:type-error
"This field should contain a number between 0 and 1."
:match exwm-xsettings--rgba-match)
(number :tag "Green"
:type-error
"This field should contain a number between 0 and 1."
:match exwm-xsettings--rgba-match)
(number :tag "Blue"
:type-error
"This field should contain a number between 0 and 1."
:match exwm-xsettings--rgba-match)
(number :tag "Alpha"
:type-error
"This field should contain a number between 0 and 1."
:match exwm-xsettings--rgba-match
:value 1.0))))
:initialize #'custom-initialize-default
:set #'exwm-xsettings--custom-set)
(defcustom exwm-xsettings-theme nil
"The system-wide theme."
:type '(choice (string :tag "Theme")
(cons (string :tag "Light Theme")
(string :tag "Dark Theme")))
:initialize #'custom-initialize-default
:set #'exwm-xsettings--custom-set)
(defcustom exwm-xsettings-icon-theme nil
"The system-wide icon theme."
:type '(choice (string :tag "Icon Theme")
(cons (string :tag "Light Icon Theme")
(string :tag "Dark Icon Theme")))
:initialize #'custom-initialize-default
:set #'exwm-xsettings--custom-set)
(defalias 'exwm-xsettings--color-dark-p
(if (eval-when-compile (< emacs-major-version 29))
;; Borrowed from Emacs 29.
(lambda (rgb)
"Whether RGB is more readable against white than black."
(unless (<= 0 (apply #'min rgb) (apply #'max rgb) 1)
(error "RGB components %S not in [0,1]" rgb))
(let* ((r (expt (nth 0 rgb) 2.2))
(g (expt (nth 1 rgb) 2.2))
(b (expt (nth 2 rgb) 2.2))
(y (+ (* r 0.2126) (* g 0.7152) (* b 0.0722))))
(< y 0.325)))
'color-dark-p))
(defun exwm-xsettings--pick-theme (theme)
"Pick a light or dark theme from the given THEME.
If THEME is a string, it's returned directly.
If THEME is a cons of (LIGHT . DARK), the appropriate theme is picked based on
the default face's background color."
(pcase theme
((cl-type string) theme)
(`(,(cl-type string) . ,(cl-type string))
(if (exwm-xsettings--color-dark-p (color-name-to-rgb (face-background 'default)))
(cdr theme) (car theme)))
(_ (error "Expected theme to be a string or a pair of strings"))))
(defun exwm-xsettings--get-settings ()
"Get the current settings.
Combines `exwm-xsettings', `exwm-xsettings-theme' (if set), and
`exwm-xsettings-icon-theme' (if set)."
(cl-remove-duplicates
(append
exwm-xsettings
(when exwm-xsettings-theme
(list (cons "Net/ThemeName" (exwm-xsettings--pick-theme exwm-xsettings-theme))))
(when exwm-xsettings-icon-theme
(list (cons "Net/IconThemeName" (exwm-xsettings--pick-theme exwm-xsettings-icon-theme)))))
:key 'car
:test 'string=))
(defun exwm-xsettings--make-settings (settings serial)
"Construct a new settings object.
SETTINGS is an alist of key/value pairs.
SERIAL is a sequence number."
(make-instance 'xcb:xsettings:-Settings
:byte-order (if xcb:lsb 0 1)
:serial serial
:settings-len (length settings)
:settings
(mapcar
(lambda (prop)
(let* ((name (car prop))
(value (cdr prop))
(common (list :name name
:name-len (length name)
:last-change-serial serial)))
(pcase value
((cl-type string)
(apply #'make-instance 'xcb:xsettings:-SETTING_STRING
:value-len (length value)
:value value
common))
((cl-type integer)
(apply #'make-instance 'xcb:xsettings:-SETTING_INTEGER
:value value common))
((and (cl-type list) (app length (or 3 4)))
;; Convert from RGB(A) to 16bit integers.
(setq value (mapcar (lambda (x) (round (* x #xffff))) value))
(apply #'make-instance 'xcb:xsettings:-SETTING_COLOR
:red (pop value)
:green (pop value)
:blue (pop value)
:alpha (or (pop value) #xffff)))
(_ (error "Setting value must be a string, integer, or length 3-4 list")))))
settings)))
(defun exwm-xsettings--update-settings ()
"Update the xsettings."
(when exwm-xsettings--connection
(setq exwm-xsettings--serial (1+ exwm-xsettings--serial))
(let* ((settings (exwm-xsettings--get-settings))
(bytes (xcb:marshal (exwm-xsettings--make-settings settings exwm-xsettings--serial))))
(xcb:+request exwm-xsettings--connection
(make-instance 'xcb:ChangeProperty
:mode xcb:PropMode:Replace
:window exwm-xsettings--selection-owner-window
:property exwm-xsettings--XSETTINGS_SETTINGS-atom
:type exwm-xsettings--XSETTINGS_SETTINGS-atom
:format 8
:data-len (length bytes)
:data bytes)))
(xcb:flush exwm-xsettings--connection)))
(defun exwm-xsettings--on-theme-change (&rest _)
"Called when the Emacs theme is changed."
;; We only bother updating the xsettings if changing the theme could effect
;; the settings.
(when (or (consp exwm-xsettings-theme) (consp exwm-xsettings-icon-theme))
(exwm-xsettings--update-settings)))
(defun exwm-xsettings--on-SelectionClear (_data _synthetic)
"Called when another xsettings daemon takes over."
(exwm--log "XSETTINGS manager has been replaced.")
(exwm-xsettings--exit))
(cl-defun exwm-xsettings--init ()
"Initialize the XSETTINGS module."
(exwm--log)
(cl-assert (not exwm-xsettings--connection))
;; Connect
(setq exwm-xsettings--connection (xcb:connect))
(set-process-query-on-exit-flag (slot-value exwm-xsettings--connection
'process)
nil)
;; Intern the atoms.
(setq exwm-xsettings--XSETTINGS_SETTINGS-atom
(exwm--intern-atom "_XSETTINGS_SETTINGS" exwm-xsettings--connection)
exwm-xsettings--XSETTINGS_S0-atom
(exwm--intern-atom "_XSETTINGS_S0" exwm-xsettings--connection))
;; Detect running XSETTINGS managers.
(with-slots (owner)
(xcb:+request-unchecked+reply exwm-xsettings--connection
(make-instance 'xcb:GetSelectionOwner
:selection exwm-xsettings--XSETTINGS_S0-atom))
(when (/= owner xcb:Window:None)
(xcb:disconnect exwm-xsettings--connection)
(setq exwm-xsettings--connection nil)
(warn "[EXWM] Other XSETTINGS manager detected")
(cl-return-from exwm-xsettings--init)))
(let ((id(xcb:generate-id exwm-xsettings--connection)))
(setq exwm-xsettings--selection-owner-window id)
;; Create a settings window.
(xcb:+request exwm-xsettings--connection
(make-instance 'xcb:CreateWindow
:wid id
:parent exwm--root
:class xcb:WindowClass:InputOnly
:x 0
:y 0
:width 1
:height 1
:border-width 0
:depth 0
:visual 0
:value-mask xcb:CW:OverrideRedirect
:override-redirect 1))
;; Set _NET_WM_NAME.
(xcb:+request exwm-xsettings--connection
(make-instance 'xcb:ewmh:set-_NET_WM_NAME
:window id
:data "EXWM: exwm-xsettings--selection-owner-window"))
;; Apply the XSETTINGS properties.
(exwm-xsettings--update-settings)
;; Take ownership and notify.
(xcb:+request exwm-xsettings--connection
(make-instance 'xcb:SetSelectionOwner
:owner id
:selection exwm-xsettings--XSETTINGS_S0-atom
:time xcb:Time:CurrentTime))
(xcb:+request exwm-xsettings--connection
(make-instance 'xcb:SendEvent
:propagate 0
:destination exwm--root
:event-mask xcb:EventMask:StructureNotify
:event (xcb:marshal
(make-instance 'xcb:xsettings:-ClientMessage
:window exwm--root
:time xcb:Time:CurrentTime
:selection exwm-xsettings--XSETTINGS_S0-atom
:owner id)
exwm-xsettings--connection)))
;; Detect loss of XSETTINGS ownership.
(xcb:+event exwm-xsettings--connection 'xcb:SelectionClear
#'exwm-xsettings--on-SelectionClear)
(xcb:flush exwm-xsettings--connection))
;; Update the xsettings if/when the theme changes.
(add-hook 'enable-theme-functions #'exwm-xsettings--on-theme-change)
(add-hook 'disable-theme-functions #'exwm-xsettings--on-theme-change))
(defun exwm-xsettings--exit ()
"Exit the XSETTINGS module."
(exwm--log)
(when exwm-xsettings--connection
(remove-hook 'enable-theme-functions #'exwm-xsettings--on-theme-change)
(remove-hook 'disable-theme-functions #'exwm-xsettings--on-theme-change)
(xcb:disconnect exwm-xsettings--connection)
(setq exwm-xsettings--connection nil
exwm-xsettings--XSETTINGS_SETTINGS-atom nil
exwm-xsettings--XSETTINGS_S0-atom nil
exwm-xsettings--selection-owner-window nil)))
(defun exwm-xsettings-enable ()
"Enable xsettings support for EXWM."
(exwm--log)
(add-hook 'exwm-init-hook #'exwm-xsettings--init)
(add-hook 'exwm-exit-hook #'exwm-xsettings--exit))
(provide 'exwm-xsettings)
;;; exwm-xsettings.el ends here

View file

@ -1,13 +1,13 @@
;;; exwm.el --- Emacs X Window Manager -*- lexical-binding: t -*-
;; Copyright (C) 2015-2023 Free Software Foundation, Inc.
;; Copyright (C) 2015-2024 Free Software Foundation, Inc.
;; Author: Chris Feng <chris.w.feng@gmail.com>
;; Maintainer: Adrián Medraño Calvo <adrian@medranocalvo.com>
;; Maintainer: Adrián Medraño Calvo <adrian@medranocalvo.com>, Steven Allen <steven@stebalien.com>, Daniel Mendler <mail@daniel-mendler.de>
;; Version: 0.28
;; Package-Requires: ((xelb "0.18"))
;; Package-Requires: ((emacs "27.1") (xelb "0.18"))
;; Keywords: unix
;; URL: https://github.com/ch11ng/exwm
;; URL: https://github.com/emacs-exwm/exwm
;; This file is part of GNU Emacs.
@ -29,14 +29,18 @@
;; Overview
;; --------
;; EXWM (Emacs X Window Manager) is a full-featured tiling X window manager
;; for Emacs built on top of [XELB](https://github.com/ch11ng/xelb).
;; for Emacs built on top of [XELB](https://github.com/emacs-exwm/xelb).
;; It features:
;; + Fully keyboard-driven operations
;; + Hybrid layout modes (tiling & stacking)
;; + Dynamic workspace support
;; + ICCCM/EWMH compliance
;; + (Optional) RandR (multi-monitor) support
;; + (Optional) Built-in system tray
;; Optional features:
;; + RandR (multi-monitor) support
;; + System tray
;; + Input method
;; + Background setting support
;; + XSETTINGS server
;; Installation & configuration
;; ----------------------------
@ -54,7 +58,7 @@
;; xinit -- vt01
;;
;; You should additionally hide the menu-bar, tool-bar, etc to increase the
;; usable space. Please check the wiki (https://github.com/ch11ng/exwm/wiki)
;; usable space. Please check the wiki (https://github.com/emacs-exwm/exwm/wiki)
;; for more detailed instructions on installation, configuration, usage, etc.
;; References:
@ -77,7 +81,6 @@
(defgroup exwm nil
"Emacs X Window Manager."
:tag "EXWM"
:version "25.3"
:group 'applications
:prefix "exwm-")
@ -97,7 +100,10 @@
"Normal hook run when window title is updated."
:type 'hook)
(defcustom exwm-blocking-subrs '(x-file-dialog x-popup-dialog x-select-font)
(defcustom exwm-blocking-subrs
;; `x-file-dialog' and `x-select-font' are missing on some Emacs builds, for
;; example on the X11 Lucid build.
'(x-file-dialog x-popup-dialog x-select-font message-box message-or-box)
"Subrs (primitives) that would normally block EXWM."
:type '(repeat function))
@ -110,6 +116,10 @@
(defconst exwm--server-name "server-exwm"
"Name of the subordinate Emacs server.")
(defvar exwm--server-timeout 1
"Number of seconds to wait for the subordinate Emacs server to exit.
After this time, the server will be killed.")
(defvar exwm--server-process nil "Process of the subordinate Emacs server.")
(defun exwm-reset ()
@ -166,7 +176,7 @@ Argument XWIN contains the X window of the `exwm-mode' buffer."
(when reply
(setq desktop (slot-value reply 'value))
(cond
((eq desktop 4294967295.)
((and desktop (= desktop 4294967295.))
(unless (or (not exwm--floating-frame)
(eq exwm--frame exwm-workspace--current)
(and exwm--desktop
@ -482,9 +492,6 @@ RAW-DATA contains unmarshalled ClientMessage event data."
(exwm-workspace-switch (elt data 0)))
;; _NET_ACTIVE_WINDOW.
((= type xcb:Atom:_NET_ACTIVE_WINDOW)
(dolist (f exwm-workspace--list)
(when (eq id (frame-parameter f 'exwm-outer-id))
(x-focus-frame f t)))
(let ((buffer (exwm--id->buffer id))
iconic window)
(if (buffer-live-p buffer)
@ -1002,8 +1009,13 @@ FRAME, if given, indicates the X display EXWM should manage."
(defun exwm--server-stop ()
"Stop the subordinate Emacs server."
(exwm--log)
(server-force-delete exwm--server-name)
(when exwm--server-process
(when (process-live-p exwm--server-process)
(cl-loop
initially (signal-process exwm--server-process 'TERM)
while (process-live-p exwm--server-process)
repeat (* 10 exwm--server-timeout)
do (sit-for 0.1)))
(delete-process exwm--server-process)
(setq exwm--server-process nil)))
@ -1020,7 +1032,7 @@ FUNCTION is the function to be evaluated, ARGS are the arguments."
(car command-line-args) ;The executable file
"-d" (frame-parameter nil 'display)
"-Q"
(concat "--daemon=" exwm--server-name)
(concat "--fg-daemon=" exwm--server-name)
"--eval"
;; Create an invisible frame
"(make-frame '((window-system . x) (visibility)))"))

View file

@ -49,6 +49,19 @@ depot.nix.readTree.drvTargets {
self.git
];
});
# Pin xelb to a newer one until the new maintainers do a release.
xelb = eself.trivialBuild {
pname = "xelb";
version = "0.19-dev"; # invented version, last actual release was 0.18
src = self.fetchFromGitHub {
owner = "emacs-exwm";
repo = "xelb";
rev = "86089eba2de6c818bfa2fac075cb7ad876262798";
sha256 = "1mmlrd2zpcwiv8gh10y7lrpflnbmsycdascrxjr3bfcwa8yx7901";
};
};
})
);