Skip to content

Instantly share code, notes, and snippets.

@Bad-ptr
Last active February 12, 2017 15:11
Show Gist options
  • Save Bad-ptr/38c382c1e33cec1a08290105241d8ea3 to your computer and use it in GitHub Desktop.
Save Bad-ptr/38c382c1e33cec1a08290105241d8ea3 to your computer and use it in GitHub Desktop.
;;; common-mode-line.el --- mode-line common for all windows.
;; Copyright (C) 2017 Constantin Kulikov
;;
;; Author: Constantin Kulikov (Bad_ptr) <[email protected]>
;; Version: 0.1
;; Package-Requires: ()
;; Date: 2017/01/24 16:22:13
;; License: GPL either version 3 or any later version
;; Keywords: frames, windows, mode-line, convenience
;; X-URL: https://gist.github.com/Bad-ptr/38c382c1e33cec1a08290105241d8ea3
;;; License:
;; This file is not part of GNU Emacs.
;; 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, 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, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
;;; Commentary:
;; Draws a common per-frame mode-line.
;; Put this file into your load-path and the following into your ~/.emacs:
;; (require 'common-mode-line)
;; (common-mode-line-mode)
;;; Code:
(require 'cl)
(defgroup common-mode-line nil
"Customize common-mode-line."
:prefix "common-mode-line-"
:group 'convenience
:link '(url-link :tag "Github page"
"https://gist.github.com/Bad-ptr/38c382c1e33cec1a08290105241d8ea3"))
(defcustom common-mode-line-type nil
"How to draw common-mode-line."
:group 'common-mode-line
:type '(choice
(const :tag "Use ordinary window" :value nil)
(const :tag "Use side window" :value side-window)))
(defcustom common-mode-line-window-side 'bottom
"Side of the frame where mode-line will be displayed."
:group 'common-mode-line
:type '(choice
(const :tag "At the bottom of the frame" :value bottom)
(const :tag "At the top of the frame" :value top)))
(defcustom common-mode-line-window-slot
(cond
((eq 'bottom common-mode-line-window-side) 1)
(t -1))
"Side window slot to use."
:group 'common-mode-line
:type '(choice
(const :tag "Middle slot" :value nil)
(integer :tag "\n\
A value of zero means use the middle slot.\n\
A negative value means use a slot\n\
preceding (that is, above or on the left of) the middle slot.\n\
A positive value means use a slot following (that is, below or\n\
on the right of) the middle slot"
:value 0)))
(defvar common-mode-line--buffer nil
"Buffer used to display mode-line.")
(defcustom common-mode-line-buffer-name " *common-mode-line*"
"Name of the buffer used to display mode-line in it."
:group 'common-mode-line
:type 'string
:set #'(lambda (sym val)
(custom-set-default sym val)
(when (buffer-live-p common-mode-line--buffer)
(with-current-buffer common-mode-line--buffer
(rename-buffer val)))))
(defvar common-mode-line--delayed-update-timer nil
"Timer used to delay an update of the mode-line.")
(defcustom common-mode-line-update-delay 0.5
"Time to delay an update of mode-line after last action."
:group 'common-mode-line
:type 'float)
(defvar common-mode-line--saved-emacs-mode-line-format
(default-value 'mode-line-format)
"Value of the mode-line-format before `common-mode-line-mode'
activation.")
(defvar common-mode-line--selected-window nil
"Used to track current window.")
(unless (facep 'common-mode-line-face)
(defface common-mode-line-face
'((default :inherit mode-line))
"Face for common mode-line.")
(copy-face 'mode-line 'common-mode-line-face))
(defface common-mode-line-mode-line-active-face
'((default :inherit mode-line :height 0.3))
"Face for active window bottom border.")
(defface common-mode-line-mode-line-inactive-face
'((default :inherit mode-line-inactive :height 0.3))
"Face for inactive window bottom border.")
(defun common-mode-line--get-create-buffer ()
(if (buffer-live-p common-mode-line--buffer)
common-mode-line--buffer
(setq common-mode-line--buffer
(with-current-buffer (get-buffer-create
common-mode-line-buffer-name)
(buffer-disable-undo)
(setq-local mode-line-format nil)
(setq-local header-line-format nil)
(setq-local cursor-type nil)
(setq-local cursor-in-non-selected-windows nil)
(setq-local left-fringe-width 0)
(setq-local right-fringe-width 0)
(setq-local overflow-newline-into-fringe nil)
(setq-local word-wrap nil)
(setq-local show-trailing-whitespace nil)
(toggle-truncate-lines 1)
(current-buffer)))))
(defun common-mode-line--make-window (&optional frame)
(let (win)
(with-selected-frame (or frame (selected-frame))
(setq win
(if common-mode-line-type
(display-buffer-in-side-window
buf `((side . ,common-mode-line-window-side)
(slot . ,common-mode-line-window-slot)
(window-height . 1)))
(split-window (frame-root-window) nil
(if (eq 'bottom common-mode-line-window-side)
'below 'above)))))
win))
(defun common-mode-line--create-window (&optional frame)
(let* (window-configuration-change-hook
(buf (common-mode-line--get-create-buffer))
(win (common-mode-line--make-window frame)))
(set-frame-parameter frame 'common-mode-line-window win)
(with-selected-window win
(with-current-buffer buf
(set-window-buffer win buf)
(set-window-dedicated-p win t)
(set-window-parameter win 'no-other-window t)
(set-window-parameter win 'common-mode-line-window t)
(setq-local window-min-height 1)
(setq-local window-safe-min-height 1)
(setq-local window-size-fixed nil)
(fit-window-to-buffer win 1 1)
(when (fboundp 'window-preserve-size)
(window-preserve-size win nil t))
;; (shrink-window-if-larger-than-buffer)
(setq-local window-size-fixed t))
)
win))
(defun common-mode-line--get-create-window (&optional frame)
(let ((win (frame-parameter frame 'common-mode-line-window)))
(unless (window-live-p win)
(setq win (window-with-parameter 'common-mode-line-window t frame)))
(unless (window-live-p win)
(setq win (common-mode-line--create-window frame)))
win))
(defun common-mode-line--update ()
(let* (window-configuration-change-hook
(win (common-mode-line--get-create-window))
(cwin (selected-window)))
(unless (eq win cwin)
(setq common-mode-line--selected-window
(if (eq (minibuffer-window) cwin)
(minibuffer-selected-window)
cwin))
(with-current-buffer (common-mode-line--get-create-buffer)
(setq-local buffer-read-only nil)
(erase-buffer)
(let* ((ml-s (format-mode-line
(list "" '(eldoc-mode-line-string
(" " eldoc-mode-line-string " "))
(default-value 'mode-line-format))
'common-mode-line-face
common-mode-line--selected-window))
(win-w (window-width win))
(fill-w (max 0 (- win-w (string-width ml-s)))))
(insert
(concat ml-s (propertize (make-string fill-w ?\ )
'face 'common-mode-line-face))))
(goto-char (point-min))
(setq-local buffer-read-only t))
;; (with-selected-window win
;; (let (window-size-fixed)
;; (shrink-window-if-larger-than-buffer))
;; )
(setq mode-line-format ""))))
(defun common-mode-line--delayed-update (&rest args)
(when common-mode-line-mode
(unless (timerp common-mode-line--delayed-update-timer)
(setq common-mode-line--delayed-update-timer
(run-with-idle-timer
common-mode-line-update-delay nil
#'(lambda ()
(common-mode-line--update)
(setq common-mode-line--delayed-update-timer nil)))))))
(defun common-mode-line--activate (&optional frames)
(add-to-list 'window-persistent-parameters
'(common-mode-line-window . writable))
(add-to-list 'window-persistent-parameters
'(no-other-window . writable))
(add-to-list 'face-remapping-alist
'(mode-line common-mode-line-mode-line-active-face))
(add-to-list 'face-remapping-alist
'(mode-line-inactive common-mode-line-mode-line-inactive-face))
(unless (listp frames) (setq frames (list frames)))
(unless frames (setq frames
(delete-if #'(lambda (f) (or (not (frame-live-p f))
(and (daemonp)
(eq f terminal-frame))))
(frame-list))))
(dolist (frame frames)
(common-mode-line--get-create-window frame))
(setq common-mode-line--saved-emacs-mode-line-format
(default-value 'mode-line-format)
mode-line-format nil)
(add-hook 'post-command-hook #'common-mode-line--delayed-update)
(ad-activate #'force-mode-line-update))
(defun common-mode-line--deactivate (&optional frames)
(when (timerp common-mode-line--delayed-update-timer)
(cancel-timer common-mode-line--delayed-update-timer)
(setq common-mode-line--delayed-update-timer nil))
(unless (listp frames) (setq frames (list frames)))
(let (all win)
(unless frames
(setq frames (frame-list)
all t))
(dolist (frame frames)
(setq win (window-with-parameter 'common-mode-line-window))
(when (window-live-p win)
(set-window-dedicated-p win nil)
(delete-window win))
(set-frame-parameter frame 'common-mode-line-window nil))
(unless (window-with-parameter 'common-mode-line-window t)
(setq all t))
(when all
(setq face-remapping-alist
(delq
(assq 'mode-line
face-remapping-alist)
face-remapping-alist))
(setq face-remapping-alist
(delq
(assq 'mode-line-inactive
face-remapping-alist)
face-remapping-alist))
(dolist (w (window-list))
(with-current-buffer (window-buffer w)
(setq mode-line-format common-mode-line--saved-emacs-mode-line-format)))
(kill-buffer (common-mode-line--get-create-buffer))
(remove-hook 'post-command-hook #'common-mode-line--delayed-update)
(ad-deactivate #'force-mode-line-update))))
(defadvice force-mode-line-update
(after common-mode-line--delayed-update-adv)
(common-mode-line--delayed-update)
nil)
;;;###autoload
(define-minor-mode common-mode-line-mode
"Toggle the common-mode-line-mode.
When active it draws a mode-line at the bottom(or top) of
the frame."
:require 'common-mode-line-mode
:group 'common-mode-line-mode
:init-value nil
:global t
;; :lighter " cml"
(if common-mode-line-mode
(common-mode-line--activate)
(common-mode-line--deactivate)))
(provide 'common-mode-line)
;;; common-mode-line.el ends here
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment