[Emacs] Add some EXWM documentation
Add also some literate config
This commit is contained in:
parent
bd12a71a92
commit
99fad403f0
@ -3081,21 +3081,227 @@ I’ll also create a fuction for connecting to this new Tramp protocol:
|
|||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: Packages-Configuration-EXWM-pr14yxs09aj0
|
:CUSTOM_ID: Packages-Configuration-EXWM-pr14yxs09aj0
|
||||||
:END:
|
:END:
|
||||||
#+begin_src emacs-lisp
|
So, I’m finally slowly getting back to EXWM. I tried it a couple of
|
||||||
(defvar phundrak/with-exwm (and (eq window-system 'x)
|
years ago, but that was with the SpacemacsOS layer on Spacemacs, on a
|
||||||
(seq-contains command-line-args "--use-exwm")))
|
laptop which got accidentaly formatted before I could save my config
|
||||||
|
and all… So it got me some time to come back. I’m still a bit worried
|
||||||
|
about Emacs being single threaded, so if I get one blocking function
|
||||||
|
blocking Emacs, my whole desktop will hang, but for now I haven’t had
|
||||||
|
this issue.
|
||||||
|
|
||||||
|
First, I need to install the /X protocol Emacs Lisp Bindings/. It
|
||||||
|
doesn’t seem to be available in any repo, so I’ll install it directly
|
||||||
|
from Git.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
(use-package xelb
|
(use-package xelb
|
||||||
:straight (xelb :build t
|
:straight (xelb :build t
|
||||||
:type git
|
:type git
|
||||||
:host github
|
:host github
|
||||||
:repo "ch11ng/xelb"))
|
:repo "ch11ng/xelb"))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
;; config.daviwil.com/desktop
|
Next is a function I’ve +stolen+ copied from Daviwil’s [[https://config.daviwil.com/desktop][desktop
|
||||||
|
configuration]]. This allows to launch software in the background
|
||||||
|
easily.
|
||||||
|
#+begin_src emacs-lisp
|
||||||
(defun exwm/run-in-background (command &optional once)
|
(defun exwm/run-in-background (command &optional once)
|
||||||
(let ((command-parts (split-string command " +")))
|
(let ((command-parts (split-string command " +")))
|
||||||
(apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts)))))
|
(apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts)))))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
*** EXWM itself
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: Packages-Configuration-EXWM-EXWM-itself-hhgexz61aaj0
|
||||||
|
:END:
|
||||||
|
Now we come to the plat de résistance. Like with ~xelb~, I’m using its
|
||||||
|
Git source to install it to make sure I get the right version --- the
|
||||||
|
version available on the GNU ELPA is from the same source, true, but I
|
||||||
|
don’t know at which rate it is updated. And more packages down the
|
||||||
|
line will depend on this Git repository, so I might as well just clone
|
||||||
|
it right now.
|
||||||
|
|
||||||
|
As you can see, in the ~:config~ secion I added to two hooks functions
|
||||||
|
so buffers are accurately renamed. While the average X window will
|
||||||
|
simply get the name of the current X window, I want Firefox and
|
||||||
|
Qutebrowser to be prefixed with the name of the browser. Actually, all
|
||||||
|
these will be renamed this way:
|
||||||
|
#+name: exwm-renamed-buffers-list
|
||||||
|
- Discord
|
||||||
|
- Firefox
|
||||||
|
- Qutebrowser
|
||||||
|
|
||||||
|
#+name: exwm-gen-buffers-rename
|
||||||
|
#+headers: :exports none :tangle no
|
||||||
|
#+begin_src emacs-lisp :var buffers=exwm-renamed-buffers-list :cache yes
|
||||||
|
(mapconcat (lambda (buffer)
|
||||||
|
(let ((buffer-name (car buffer)))
|
||||||
|
(format "(\"%s\" %S)"
|
||||||
|
(downcase buffer-name)
|
||||||
|
`(exwm-workspace-rename-buffer (concat ,(concat buffer-name " - %s")
|
||||||
|
exwm-title)))))
|
||||||
|
buffers
|
||||||
|
"\n")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS[53d4805340ff070b477ea5d3725105c488ffb1fd]: exwm-gen-buffers-rename
|
||||||
|
: ("discord" (exwm-workspace-rename-buffer (concat "Discord - %s" exwm-title)))
|
||||||
|
: ("firefox" (exwm-workspace-rename-buffer (concat "Firefox - %s" exwm-title)))
|
||||||
|
: ("qutebrowser" (exwm-workspace-rename-buffer (concat "Qutebrowser - %s" exwm-title)))
|
||||||
|
|
||||||
|
#+name: exwm-buffers-name
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
|
(add-hook 'exwm-update-class-hook
|
||||||
|
(lambda () (exwm-workspace-rename-buffer exwm-class-name)))
|
||||||
|
|
||||||
|
(add-hook 'exwm-update-title-hook
|
||||||
|
(lambda ()
|
||||||
|
(pcase exwm-class-name
|
||||||
|
<<exwm-gen-buffers-rename()>>
|
||||||
|
)))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
As you can see below, in the ~:config~ section I added two advices and one
|
||||||
|
hook in order to correctly integrate evil with EXWM. When I’m in an X
|
||||||
|
window, I want to be in insert-mode so I can type however I want.
|
||||||
|
However, when I exit one, I want to default back to normal-mode.
|
||||||
|
#+name: exwm-advices-evil
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
|
(add-hook 'exwm-manage-finish-hook (lambda () (call-interactively #'exwm-input-release-keyboard)))
|
||||||
|
(advice-add #'exwm-input-grab-keyboard :after (lambda (&optional id) (evil-normal-state)))
|
||||||
|
(advice-add #'exwm-input-release-keyboard :after (lambda (&optional id) (evil-insert-state)))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
Secondly, I add ~i~, ~C-SPC~, and ~M-m~ as exwm prefix keys so they aren’t
|
||||||
|
sent directly to the X windows but caught by Emacs (and EXWM). I’ll
|
||||||
|
use the ~i~ key in normal-mode to enter ~insert-mode~ and have Emacs
|
||||||
|
release the keyboard so the X window can grab it. ~s-I~ will also toggle
|
||||||
|
between releasing to and grabing the keyboard from X windows.
|
||||||
|
~s-<escape>~ will be only useful for grabing back the keyboard, a bit
|
||||||
|
like exiting the insert state from evil back to the normal state.
|
||||||
|
#+name: exwm-prefix-keys
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
|
(general-define-key
|
||||||
|
:keymaps 'exwm-mode-map
|
||||||
|
:states 'normal
|
||||||
|
"i" #'exwm-input-release-keyboard)
|
||||||
|
|
||||||
|
(exwm-input-set-key (kbd "s-I") #'exwm-input-toggle-keyboard)
|
||||||
|
(exwm-input-set-key (kbd "s-<escape>") #'exwm-input-grab-keyboard)
|
||||||
|
|
||||||
|
(push ?\i exwm-input-prefix-keys)
|
||||||
|
(push (kbd "C-SPC") exwm-input-prefix-keys)
|
||||||
|
(push (kbd "M-m") exwm-input-prefix-keys)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
As stated a couple of times in my different configuration files, I’m
|
||||||
|
using the bépo layout, which means the default keys in the number row
|
||||||
|
are laid as follow:
|
||||||
|
#+name: exwm-bepo-number-row
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
|
(defconst exwm-workspace-keys '("\"" "«" "»" "(" ")" "@" "+" "-" "/" "*"))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
With this, we can create keybinds for going or sending X windows to
|
||||||
|
workspaces 0 to 9.
|
||||||
|
#+name: exwm-workspace-keybinds
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
|
(setq exwm-input-global-keys
|
||||||
|
`(,@exwm-input-global-keys
|
||||||
|
,@(mapcar (lambda (i)
|
||||||
|
`(,(kbd (format "s-%s" (nth i exwm-workspace-keys))) .
|
||||||
|
(lambda ()
|
||||||
|
(interactive)
|
||||||
|
(exwm-workspace-switch-create ,i))))
|
||||||
|
(number-sequence 0 9))
|
||||||
|
,@(mapcar (lambda (i)
|
||||||
|
`(,(kbd (format "s-%d" i)) .
|
||||||
|
(lambda ()
|
||||||
|
(interactive)
|
||||||
|
(exwm-workspace-move-window ,i))))
|
||||||
|
(number-sequence 0 9))))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
You can then see the list of the keybinds I have set for EXWM, which
|
||||||
|
are all prefixed with ~SPC x~ in normal mode (and ~C-SPC x~ in insert
|
||||||
|
mode), with the exception of ~s-RET~ which opens an eshell terminal.
|
||||||
|
#+name: exwm-keybinds
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
|
(exwm-input-set-key (kbd "s-<return>") (lambda ()
|
||||||
|
(interactive)
|
||||||
|
(eshell)))
|
||||||
|
|
||||||
|
(phundrak/leader-key
|
||||||
|
:infix "x"
|
||||||
|
"" '(:ignore t :which-key "EXWM")
|
||||||
|
"k" #'exwm-input-send-next-key
|
||||||
|
"l" '((lambda ()
|
||||||
|
(interactive)
|
||||||
|
(start-process "" nil "plock"))
|
||||||
|
:which-key "lock")
|
||||||
|
"r" '(:ignore t :wk "rofi")
|
||||||
|
"rr" '((lambda () (interactive)
|
||||||
|
(with-temp-buffer
|
||||||
|
(shell-command "rofi -show drun" (current-buffer) (current-buffer))))
|
||||||
|
:wk "drun")
|
||||||
|
"rw" '((lambda () (interactive)
|
||||||
|
(with-temp-buffer "rofi -show window" (current-buffer) (current-buffer)))
|
||||||
|
:wk "windows")
|
||||||
|
"R" '(:ignore t :wk "restart")
|
||||||
|
"Rr" #'exwm-reset
|
||||||
|
"RR" #'exwm-restart
|
||||||
|
"t" '(:ignore t :which-key "toggle")
|
||||||
|
"tf" #'exwm-layout-toggle-fullscreen
|
||||||
|
"tF" #'exwm-floating-toggle-floating
|
||||||
|
"tm" #'exwm-layout-toggle-mode-line
|
||||||
|
"w" '(:ignore t :which-key "workspaces")
|
||||||
|
"wa" #'exwm-workspace-add
|
||||||
|
"wd" #'exwm-workspace-delete
|
||||||
|
"ws" #'exwm-workspace-switch
|
||||||
|
"x" '((lambda ()
|
||||||
|
(interactive)
|
||||||
|
(let ((command (string-trim (read-shell-command "RUN: "))))
|
||||||
|
(start-process command nil command)))
|
||||||
|
:which-key "run")
|
||||||
|
"RET" #'eshell-new)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
A couple of commands are also automatically executed:
|
||||||
|
#+name: exwm-autostart-list
|
||||||
|
- ~mpc stop~ :: stops any music played by MPD (if any) when Emacs is
|
||||||
|
launched.
|
||||||
|
- ~pumopm~ :: my power manager, you can see its code source [[https://labs.phundrak.com/phundrak/pumopm][here]].
|
||||||
|
- ~xss-lock plock~ :: automatically lock the desktop with my script [[file:bin.org::#Lock-635fcb38][plock]].
|
||||||
|
- ~xrdb -merge $HOME/.Xresources~ :: use the settings from my xresources
|
||||||
|
file
|
||||||
|
|
||||||
|
#+name: exwm-generate-autostarts
|
||||||
|
#+headers: :exports results :tangle no
|
||||||
|
#+begin_src emacs-lisp :var autostarts=exwm-autostart-list :cache yes
|
||||||
|
(mapconcat (lambda (command)
|
||||||
|
(let* ((whitespace (rx (+ space)))
|
||||||
|
(raw-command (car (split-string (car command) "::" t whitespace)))
|
||||||
|
(command (replace-regexp-in-string (regexp-quote "~") "" raw-command)))
|
||||||
|
(format "%S" `(exwm/run-in-background ,command))))
|
||||||
|
autostarts
|
||||||
|
"\n")
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+RESULTS[c480df0f806b0007d125e570ab95c7e17dc2199d]: exwm-generate-autostarts
|
||||||
|
: (exwm/run-in-background "mpc stop")
|
||||||
|
: (exwm/run-in-background "pumopm")
|
||||||
|
: (exwm/run-in-background "xss-lock plock")
|
||||||
|
: (exwm/run-in-background "xrdb -merge $HOME/.Xresources")
|
||||||
|
|
||||||
|
Finally, let’s only initialize and start EXWM once functions from
|
||||||
|
exwm-randr ran, because otherwise having multiple monitors don’t work.
|
||||||
|
#+name: exwm-init
|
||||||
|
#+begin_src emacs-lisp :tangle no
|
||||||
|
(with-eval-after-load 'exwm-randr
|
||||||
|
(exwm-init))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
The complete configuration for the ~exwm~ package can be found below.
|
||||||
|
#+begin_src emacs-lisp :noweb yes
|
||||||
(use-package exwm
|
(use-package exwm
|
||||||
:straight (exwm :build t
|
:straight (exwm :build t
|
||||||
:type git
|
:type git
|
||||||
@ -3108,81 +3314,27 @@ I’ll also create a fuction for connecting to this new Tramp protocol:
|
|||||||
(require 'exwm-config)
|
(require 'exwm-config)
|
||||||
(setq exwm-workspace-number 3)
|
(setq exwm-workspace-number 3)
|
||||||
:config
|
:config
|
||||||
(add-hook 'exwm-manage-finish-hook (lambda () (call-interactively #'exwm-input-release-keyboard)))
|
<<exwm-buffers-name>>
|
||||||
(advice-add #'exwm-input-grab-keyboard :after (lambda (&optional id) (evil-normal-state)))
|
|
||||||
(advice-add #'exwm-input-release-keyboard :after (lambda (&optional id) (evil-insert-state)))
|
|
||||||
|
|
||||||
(general-define-key
|
<<exwm-advices-evil>>
|
||||||
:keymaps 'exwm-mode-map
|
<<exwm-prefix-keys>>
|
||||||
:states 'normal
|
|
||||||
"i" #'exwm-input-release-keyboard)
|
|
||||||
(push ?\i exwm-input-prefix-keys)
|
|
||||||
|
|
||||||
(add-hook 'exwm-update-class-hook
|
<<exwm-bepo-number-row>>
|
||||||
(lambda () (exwm-workspace-rename-buffer exwm-class-name)))
|
<<exwm-workspace-keybinds>>
|
||||||
|
|
||||||
(defconst exwm-workspace-keys '("*" "\"" "«" "»" "(" ")" "@" "+" "-" "/"))
|
<<exwm-keybinds>>
|
||||||
(setq exwm-input-global-keys
|
|
||||||
`(,@exwm-input-global-keys
|
|
||||||
,@(mapcar (lambda (i)
|
|
||||||
`(,(kbd (format "s-%s" (nth i exwm-workspace-keys))) .
|
|
||||||
(lambda ()
|
|
||||||
(interactive)
|
|
||||||
(exwm-workspace-switch-create ,i))))
|
|
||||||
(number-sequence 0 9))
|
|
||||||
,@(mapcar (lambda (i)
|
|
||||||
`(,(kbd (format "s-%d" i)) .
|
|
||||||
(lambda ()
|
|
||||||
(interactive)
|
|
||||||
(exwm-workspace-move-window ,i))))
|
|
||||||
(number-sequence 0 9))))
|
|
||||||
|
|
||||||
(exwm-input-set-key (kbd "C-q") #'exwm-input-send-next-key)
|
<<exwm-generate-autostarts()>>
|
||||||
(exwm-input-set-key (kbd "s-I") #'exwm-input-toggle-keyboard)
|
|
||||||
(exwm-input-set-key (kbd "s-l") (lambda () (start-process "" nil "plock")))
|
|
||||||
(exwm-input-set-key (kbd "s-r") #'exwm-reset)
|
|
||||||
(exwm-input-set-key (kbd "s-R") #'exwm-restart)
|
|
||||||
(exwm-input-set-key (kbd "s-w") #'exwm-workspace-switch)
|
|
||||||
(exwm-input-set-key (kbd "s-<return>") (lambda ()
|
|
||||||
(interactive)
|
|
||||||
(start-process-shell-command "kitty" nil "kitty")))
|
|
||||||
(exwm-input-set-key (kbd "s-<escape>") #'exwm-input-grab-keyboard)
|
|
||||||
(exwm-input-set-key (kbd "s-d") (lambda ()
|
|
||||||
(interactive)
|
|
||||||
(start-process "RUN" nil (string-trim (read-shell-command "RUN: ")))))
|
|
||||||
|
|
||||||
(phundrak/leader-key
|
<<exwm-init>>
|
||||||
:infix "x"
|
)
|
||||||
"" '(:ignore t :which-key "EXWM")
|
#+end_src
|
||||||
"k" #'exwm-input-send-next-key
|
|
||||||
"l" '((lambda ()
|
|
||||||
(interactive)
|
|
||||||
(start-process "" nil "plock"))
|
|
||||||
:which-key "lock")
|
|
||||||
"r" #'exwm-reset
|
|
||||||
"R" #'exwm-restart
|
|
||||||
"t" '(:ignore t :which-key "toggle")
|
|
||||||
"tf" #'exwm-layout-toggle-fullscreen
|
|
||||||
"tF" #'exwm-floating-toggle-floating
|
|
||||||
"tm" #'exwm-layout-toggle-mode-line
|
|
||||||
"w" '(:ignore t :which-key "workspaces")
|
|
||||||
"wa" #'exwm-workspace-add
|
|
||||||
"wd" #'exwm-workspace-delete
|
|
||||||
"x" '((lambda ()
|
|
||||||
(interactive)
|
|
||||||
(let ((command (string-trim (read-shell-command "RUN: "))))
|
|
||||||
(start-process command nil command)))
|
|
||||||
:which-key "run"))
|
|
||||||
|
|
||||||
(exwm/run-in-background "mpc stop")
|
|
||||||
(exwm/run-in-background "pumopm")
|
|
||||||
;; (exwm/run-in-background "nm-applet")
|
|
||||||
(exwm/run-in-background "xss-lock")
|
|
||||||
(exwm/run-in-background "xrdb -merge $HOME/.Xresources")
|
|
||||||
|
|
||||||
(after! exwm-randr
|
|
||||||
(exwm-init)))
|
|
||||||
|
|
||||||
|
*** EXWM-Evil integration
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: Packages-Configuration-EXWM-EXWM-Evil-integration-kwlexz61aaj0
|
||||||
|
:END:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
(use-package evil-exwm-state
|
(use-package evil-exwm-state
|
||||||
:defer t
|
:defer t
|
||||||
:after exwm
|
:after exwm
|
||||||
@ -3190,19 +3342,13 @@ I’ll also create a fuction for connecting to this new Tramp protocol:
|
|||||||
:type git
|
:type git
|
||||||
:host github
|
:host github
|
||||||
:repo "domenzain/evil-exwm-state"))
|
:repo "domenzain/evil-exwm-state"))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
(use-package desktop-environment
|
*** Multimonitor support
|
||||||
:defer t
|
:PROPERTIES:
|
||||||
:straight (desktop-environment :build t
|
:CUSTOM_ID: Packages-Configuration-EXWM-Multimonitor-support-l5pexz61aaj0
|
||||||
:type git
|
:END:
|
||||||
:host github
|
#+begin_src emacs-lisp
|
||||||
:repo "DamienCassou/desktop-environment")
|
|
||||||
:diminish t
|
|
||||||
:config
|
|
||||||
(setq desktop-environment-update-exwm-global-keys :prefix)
|
|
||||||
(setq exwm-layout-show-al-buffers t))
|
|
||||||
|
|
||||||
|
|
||||||
(use-package exwm-randr
|
(use-package exwm-randr
|
||||||
:after exwm
|
:after exwm
|
||||||
:straight (exwm-randr :build t
|
:straight (exwm-randr :build t
|
||||||
@ -3220,6 +3366,54 @@ I’ll also create a fuction for connecting to this new Tramp protocol:
|
|||||||
(exwm-randr-enable))
|
(exwm-randr-enable))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
*** Keybinds for a desktop environment
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: Packages-Configuration-EXWM-Keybinds-for-a-desktop-environment-q2sexz61aaj0
|
||||||
|
:END:
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package desktop-environment
|
||||||
|
:defer t
|
||||||
|
:straight (desktop-environment :build t
|
||||||
|
:type git
|
||||||
|
:host github
|
||||||
|
:repo "DamienCassou/desktop-environment")
|
||||||
|
:diminish t
|
||||||
|
:config
|
||||||
|
(setq desktop-environment-update-exwm-global-keys :prefix
|
||||||
|
exwm-layout-show-al-buffers t)
|
||||||
|
|
||||||
|
(setq desktop-environment-bluetooth-command "bluetoothctl"
|
||||||
|
|
||||||
|
desktop-environment-brightness-get-command "xbacklight -get"
|
||||||
|
desktop-environment-brightness-get-regexp (rx line-start (group (+ digit)))
|
||||||
|
desktop-environment-brightness-set-command "xbacklight %s"
|
||||||
|
desktop-environment-brightness-normal-increment "-inc 5"
|
||||||
|
desktop-environment-brightness-normal-decrement "-dec 5"
|
||||||
|
desktop-environment-brightness-small-increment "-inc 2"
|
||||||
|
desktop-environment-brightness-small-decrement "-dec 2"
|
||||||
|
|
||||||
|
desktop-environment-volume-normal-decrement "5%-"
|
||||||
|
desktop-environment-volume-normal-increment "5%+"
|
||||||
|
desktop-environment-volume-small-decrement "2%-"
|
||||||
|
desktop-environment-volume-small-increment "2%+"
|
||||||
|
desktop-environment-volume-set-command "amixer -q Master %s unmute"
|
||||||
|
|
||||||
|
desktop-environment-screenshot-directory "~/Pictures/Screenshots"
|
||||||
|
desktop-environment-screenlock-command "plock"
|
||||||
|
|
||||||
|
desktop-environment-music-toggle-command "mpc toggle"
|
||||||
|
desktop-environment-music-previous-command "mpc prev"
|
||||||
|
desktop-environment-music-next-command "mpc next"
|
||||||
|
desktop-environment-music-stop-command "mpc stop")
|
||||||
|
|
||||||
|
(general-define-key
|
||||||
|
"<XF86AudioPause>" (lambda () (interactive)
|
||||||
|
(with-temp-buffer
|
||||||
|
(shell-command "mpc pause" (current-buffer) (current-buffer)))))
|
||||||
|
|
||||||
|
(desktop-environment-mode))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
*** Bluetooth
|
*** Bluetooth
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: Packages-Configuration-EXWM-Bluetooth-k0zhpda0aaj0
|
:CUSTOM_ID: Packages-Configuration-EXWM-Bluetooth-k0zhpda0aaj0
|
||||||
|
Loading…
Reference in New Issue
Block a user