Add the WM cube to support emacs as a window manager

This commit is contained in:
Sameer Rahmani 2021-04-21 11:45:33 +01:00
parent 862724290b
commit 801fcb06e7
7 changed files with 254 additions and 15 deletions

View File

@ -61,3 +61,11 @@ compile:
clean: clean:
@rm -rf $(shell find `pwd` -iname "*~") @rm -rf $(shell find `pwd` -iname "*~")
@rm -rf $(shell find `pwd`/core -iname "*.elc") @rm -rf $(shell find `pwd`/core -iname "*.elc")
.PHYNY: dummy-x
dummy-x:
Xephyr -br -ac -noreset -screen 800x600 :1
.PHONY: test-wm
test-wm:
DISPLAY=:1 FG42_WM=true FG42_V3=true fg42-wm

54
core/cubes/wm.el Normal file
View File

@ -0,0 +1,54 @@
;;; WMCube --- The elisp cube for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.0.0
;;
;; This program 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.
;;
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;; Code:
(require 'fpkg)
(require 'fg42/flags)
(require 'fg42/cube)
(require 'fg42/utils)
(autoload-cube 'fg42/initialize-wm "wm/core.el" "Initalize the WM mode.")
(defflag wm
"The flag to enable WM mode in FG42.")
(defmacro when-wm (&rest body)
"Run the BODY only if in wm mode."
(if (string= (getenv "FG42_WM") "true")
`(progn ,@body)
nil))
(defcube fg42/wm-cube
(:docs "cubes/fg42/wm-cube.org")
(if-flag wm
(when-wm
(message "[WM] Initilizing...")
(fpkg/use exwm)
(fg42/initialize-wm))
(error "[SKIP] WM flag is not active.")))
(provide 'cubes/wm)
;;; wm.el ends here

159
core/cubes/wm/core.el Normal file
View File

@ -0,0 +1,159 @@
;;; WMCube --- The elisp cube for FG42 -*- lexical-binding: t; -*-
;;
;; Copyright (c) 2010-2021 Sameer Rahmani & Contributors
;;
;; Author: Sameer Rahmani <lxsameer@gnu.org>
;; URL: https://gitlab.com/FG42/FG42
;; Version: 3.0.0
;;
;; This program 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.
;;
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
;;
;;; Commentary:
;;; Code:
(defun wm-randr ()
"RandR support for WM"
(when-wm
(require 'exwm-randr)
(setq exwm-randr-workspace-output-plist '(0 "HDMI-1"
1 "HDMI-1"
2 "HDMI-1"
3 "HDMI-1"
4 "HDMI-1"
5 "HDMI-1"
6 "eDP-1"
7 "HDMI-1"
8 "HDMI-1"
9 "HDMI-1"))
(add-hook 'exwm-randr-screen-change-hook
(lambda ()
(start-process-shell-command
"xrandr" nil "xrandr --output HDMI-1 --above eDP-1 --mode 1920x1080")))
(exwm-randr-enable)))
(defun fg42/initialize-wm ()
"Initilize EXWM window manager with the given PARAMS."
(interactive)
(require 'exwm)
(require 'exwm-config)
(require 'exwm-systemtray)
(exwm-config-ido)
;; Set the initial number of workspaces (they can also be created later).
(setq exwm-workspace-number 10)
;; All buffers created in EXWM mode are named "*EXWM*". You may want to
;; change it in `exwm-update-class-hook' and `exwm-update-title-hook', which
;; are run when a new X window class name or title is available. Here's
;; some advice on this topic:
;; + Always use `exwm-workspace-rename-buffer` to avoid naming conflict.
;; + For applications with multiple windows (e.g. GIMP), the class names of
;; all windows are probably the same. Using window titles for them makes
;; more sense.
;; In the following example, we use class names for all windows except for
;; Java applications and GIMP.
(add-hook 'exwm-update-class-hook
(lambda ()
(unless (or (string-prefix-p "sun-awt-X11-" exwm-instance-name)
(string= "gimp" exwm-instance-name))
(exwm-workspace-rename-buffer exwm-class-name))))
(add-hook 'exwm-update-title-hook
(lambda ()
(when (or (not exwm-instance-name)
(string-prefix-p "sun-awt-X11-" exwm-instance-name)
(string= "gimp" exwm-instance-name))
(exwm-workspace-rename-buffer exwm-title))))
;; Global keybindings can be defined with `exwm-input-global-keys'.
;; Here are a few examples:
(setq exwm-input-global-keys
`(
;; Bind "s-r" to exit char-mode and fullscreen mode.
([?\s-r] . exwm-reset)
([?\s-g] . keyboard-quit)
([8388640] . other-window)
;; Bind "s-w" to switch workspace interactively.
([?\s-w] . exwm-workspace-switch)
;; Bind "s-0" to "s-9" to switch to a workspace by its index.
,@(mapcar (lambda (i)
`(,(kbd (format "s-%d" i)) .
(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
(number-sequence 0 9))
;; Bind "s-&" to launch applications ('M-&' also works if the output
;; buffer does not bother you).
([?\s-d] . (lambda (command)
(interactive (list (read-shell-command "$ ")))
(start-process-shell-command command nil command)))
;; Bind "s-<f2>" to "slock", a simple X display locker.
([s-f2] . (lambda ()
(interactive)
(start-process "" nil "/usr/bin/slock")))))
;; To add a key binding only available in line-mode, simply define it in
;; `exwm-mode-map'. The following example shortens 'C-c q' to 'C-q'.
(define-key exwm-mode-map [?\C-q] #'exwm-input-send-next-key)
(push ?\C-c exwm-input-prefix-keys)
;; The following example demonstrates how to use simulation keys to mimic
;; the behavior of Emacs. The value of `exwm-input-simulation-keys` is a
;; list of cons cells (SRC . DEST), where SRC is the key sequence you press
;; and DEST is what EXWM actually sends to application. Note that both SRC
;; and DEST should be key sequences (vector or string).
(setq exwm-input-simulation-keys
`(
;; movement
(,(kbd "C-b") . left)
(,(kbd "M-b") . ,(kbd "C-<left>"))
(,(kbd "C-f") . right)
(,(kbd "M-f") . ,(kbd "C-<right>"))
(,(kbd "C-p") . up)
(,(kbd "C-n") . down)
(,(kbd "C-a") . home)
(,(kbd "C-e") . end)
(,(kbd "M-v") . prior)
(,(kbd "C-v") . next)
(,(kbd "C-d") . delete)
;;(,(kbs "C-k") . [S-end delete])
;; navigation
(,(kbd "C-c b") . ,(kbd "M-<left>"))
(,(kbd "C-c f") . ,(kbd "M-<right>"))
(,(kbd "C-c w") . ,(kbd "C-w"))
(,(kbd "C-w") . ,(kbd "C-x"))
(,(kbd "M-w") . ,(kbd "C-c"))
(,(kbd "C-y") . ,(kbd "C-v"))
;; search
(,(kbd "C-s") . ,(kbd "C-f"))))
;; You can hide the minibuffer and echo area when they're not used, by
;; uncommenting the following line.
;;(setq exwm-workspace-minibuffer-position 'bottom)
;; Do not forget to enable EXWM. It will start by itself when things are
;; ready. You can put it _anywhere_ in your configuration.
(exwm-enable)
(exwm-systemtray-enable)
(wm-randr)
;; (with-flag nlinum
;; (add-hook 'exwm-mode-hook 'disable-nlinum))
)
(provide 'cubes/wm/core)
;;; core.el ends here

View File

@ -33,10 +33,8 @@
(defun fg42/initialize () (defun fg42/initialize ()
"Initialize FG42 after the Emacs window is rendered by loading the user init file." "Initialize FG42 after the Emacs window is rendered by loading the user init file."
(add-hook 'window-setup-hook (when (file-exists-p user-init-file)
(lambda () (load user-init-file)))
(when (file-exists-p user-init-file)
(load user-init-file)))))
(provide 'fg42) (provide 'fg42)

View File

@ -38,7 +38,7 @@ Flags are defined using the \\[defflag] through out the source code.
To see a list of available flags use \\[fg42/show-all-flags] and to see To see a list of available flags use \\[fg42/show-all-flags] and to see
the documentation of each flag simply use \\[describe-flag]." the documentation of each flag simply use \\[describe-flag]."
:group fg42 :group 'fg42
:package-version '(FG42 . "3.x") :package-version '(FG42 . "3.x")
:type '(symbol) :type '(symbol)
:tag "FG42 Flags") :tag "FG42 Flags")
@ -46,7 +46,8 @@ the documentation of each flag simply use \\[describe-flag]."
(defmacro use-flags (&rest flags) (defmacro use-flags (&rest flags)
"Set the given FLAGS to activate their functionalities in FG42." "Set the given FLAGS to activate their functionalities in FG42."
(setq fg42/flags flags)) (setq fg42/flags flags)
t)
(defun fg42/-merge-flags (flags-set &rest new-flags) (defun fg42/-merge-flags (flags-set &rest new-flags)
@ -81,25 +82,38 @@ For example, `(fg42/merge-flags (list f1 f2 f3) f4 -f2)' will return `(f1 f3 f4)
(defmacro defflag (flag-name docstring) (defmacro defflag (flag-name docstring)
"Define a new flag FLAG-NAME with the given DOCSTRING." "Define a new flag FLAG-NAME with the given DOCSTRING."
(let ((var-name (format "fg42/-flag-%s" flag-name))) (let ((var-name (intern (format "fg42/-flag-%s" flag-name))))
`(if (boundp ,var-name) `(if (boundp ',var-name)
(warn (foramt "Flag name `%s' already defined" ,flag-name)) (warn (foramt "Flag name `%s' already defined" ,flag-name))
(progn (progn
(defvar ,var-name t) (defvar ,var-name t)
(add-to-list 'fg42/available-flags ,flag-name))))) (add-to-list 'fg42/available-flags ',flag-name)))))
(defmacro when-flag (flag &rest body) (defmacro when-flag (flag &rest body)
"Evaluate the BODY only if the given FLAG is active." "Evaluate the BODY only if the given FLAG is active."
(declare (indent defun))
;; The `cube-local-flags' variable here is going to be ;; The `cube-local-flags' variable here is going to be
;; defined in cubes to hold the local flags for each cube ;; defined in cubes to hold the local flags for each cube
(if (and (boundp 'cube-local-flags) (if (and (boundp 'cube-local-flags)
(member flag cube-local-flags)) (member flag cube-local-flags))
`,@body `,@body
(if (member flag fg42/flags) `(if (member ',flag fg42/flags)
`,@body ,body
nil))) nil)))
(defmacro if-flag (flag then else)
"Evaluate the THEN expr only if the given FLAG is active otherwise ELSE."
(declare (indent defun))
;; The `cube-local-flags' variable here is going to be
;; defined in cubes to hold the local flags for each cube
(if (and (boundp 'cube-local-flags)
(member flag cube-local-flags))
`,@then
`(if (member ',flag fg42/flags)
,then
,else)))
(provide 'fg42/flags) (provide 'fg42/flags)

View File

@ -163,5 +163,11 @@ last item in second form, etc."
(load-file file))) (load-file file)))
(defmacro autoload-cube (fn file docstring)
"A wrapper for autloading FN at FILE with the given DOCSTRING.
This macro looks inside of the cubes directories."
`(autoload ,fn (expand-file-name (format "core/cubes/%s" ,file) fg42-home) ,docstring))
(provide 'fg42/utils) (provide 'fg42/utils)
;;; utils.el ends here ;;; utils.el ends here

View File

@ -32,8 +32,8 @@
(defmacro fpkg/use (pkg &rest details) (defmacro fpkg/use (pkg &rest details)
"Install the given package details PKG via use-package and straight." "Install the given package details PKG via use-package and straight."
(declare (indent defun)) (declare (indent defun))
(message "heeeeeeeeeeeeeeeeeeeeer %s" pkg)
(if (listp details) (if (and (listp details) (< 0 (length details)))
`(use-package ,pkg :straight ,@details :defer t) `(use-package ,pkg :straight ,@details :defer t)
`(use-package ,pkg :straight t :defer t))) `(use-package ,pkg :straight t :defer t)))