In terminal, Emacs manage multiple frames with names like F1, F2.... because it can't create multiple OS windows. I want the GUI version to behave this way, that is, instead of creating multiple OS windows, I want it to create many virtual frames inside a single Emacs window. Is there a way?
To cycle through frames in that inherent order you can use command other-frame ( C-x 5 o ). To move through frames in an arbitrary order that you choose, you would need to create a list or alist of them in that order, and cycle through it.
A frame is a screen object that contains one or more Emacs windows (see Windows). It is the kind of object called a “window” in the terminology of graphical environments; but we can't call it a “window” here, because Emacs uses that word in a different way.
Typing C-x C-c closes all the frames on the current display, and ends the Emacs session if it has no frames open on any other displays (see Exiting Emacs). To close just the selected frame, type C-x 5 0 (that is zero, not o ).
In fact, you can have more than one window on the same buffer. Doing so is often helpful if you want to look at different parts of a large file simultaneously. You can even have the same part of the buffer displayed in two windows, and any change you make in one window is reflected in the other.
There is a way to mimic the frame switching behavior of terminal emacs in GUI. Here is what I did. Basicly it uses make-frame-invisible
to hide inactive frames. It works well on archlinux with i3.
(defsubst +amos--is-frame-daemons-frame (f)
(and (daemonp) (eq f terminal-frame)))
(defun +amos--frame-list-without-daemon ()
"Return a list of frames without the daemon's frame."
(if (daemonp)
(filtered-frame-list
#'(lambda (f) (not (+amos--is-frame-daemons-frame f))))
(frame-list)))
(defun +amos/workspace-new ()
(interactive)
(let ((name (frame-parameter nil 'name))
(oframe (selected-frame)))
(select-frame (if (s-starts-with? "F" name)
(make-frame)
(make-frame `((name . ,name)))))
(make-frame-invisible oframe t))
(setq +amos--frame-list (reverse (+amos--frame-list-without-daemon))))
(setq +amos-tmux-need-switch nil)
;; TODO ring lru
(defun +amos/workspace-delete ()
(interactive)
(let ((f (selected-frame)))
(select-frame (previous-frame))
(make-frame-visible)
(delete-frame f))
(setq +amos--frame-list (reverse (+amos--frame-list-without-daemon)))
(+doom-modeline|set-selected-window)
(realign-windows)
(when +amos-tmux-need-switch
(shell-command! "tmux switch-client -t amos\; run-shell -t amos '/home/amos/scripts/setcursor.sh $(tmux display -p \"#{pane_tty}\")'")
(setq +amos-tmux-need-switch nil)))
(defun +amos/workspace-switch-to (index)
(interactive)
(when (< index (length +amos--frame-list))
(let ((frame (nth index +amos--frame-list))
(oframe (selected-frame)))
(select-frame frame)
(raise-frame frame)
(make-frame-invisible oframe t)
(setq +amos-tmux-need-switch nil)
(realign-windows)
(recenter))))
(defun +amos/workspace-switch-to-1 () (interactive) (+amos/workspace-switch-to 0))
(defun +amos/workspace-switch-to-2 () (interactive) (+amos/workspace-switch-to 1))
(defun +amos/workspace-switch-to-3 () (interactive) (+amos/workspace-switch-to 2))
(defun +amos/workspace-switch-to-4 () (interactive) (+amos/workspace-switch-to 3))
(defun +amos/workspace-switch-to-5 () (interactive) (+amos/workspace-switch-to 4))
(defun +amos/workspace-switch-to-6 () (interactive) (+amos/workspace-switch-to 5))
(defun +amos/workspace-switch-to-7 () (interactive) (+amos/workspace-switch-to 6))
(defun +amos/workspace-switch-to-8 () (interactive) (+amos/workspace-switch-to 7))
(defun +amos/workspace-switch-to-9 () (interactive) (+amos/workspace-switch-to 8))
(defun +amos-workspace-cycle (off)
(let* ((n (length +amos--frame-list))
(index (-elem-index (selected-frame) +amos--frame-list))
(i (% (+ off index n) n)))
(+amos/workspace-switch-to i)))
(defun +amos/workspace-switch-left () (interactive) (+amos-workspace-cycle -1))
(defun +amos/workspace-switch-right () (interactive) (+amos-workspace-cycle +1))
(defun +amos|maybe-delete-frame-buffer (frame)
(let ((windows (window-list frame)))
(dolist (window windows)
(let ((buffer (window-buffer (car windows))))
(when (eq 1 (length (get-buffer-window-list buffer nil t)))
(kill-buffer buffer))))))
(add-to-list 'delete-frame-functions #'+amos|maybe-delete-frame-buffer)
If what you mean is that you want to be able to access frames by name, then yes, you can do this with Icicles.
By default, C-x 5 o
is bound to multi-command icicle-select-frame
. This lets you select one or more frames by name.
A frame's name comes from its name
frame parameter. It is suffixed as needed by [NUMBER]
, to
make it unique. For example, in a context where frames are named for
their buffers and you have two frames showing buffer *Help*
, one of
the frames will be called *Help*[2]
for use with this command.
Frame selection with C-x 5 o
uses completion and cycling. The completion can be vanilla Emacs completion or regexp (including, of course, substring) completion. (It can also be any of several fuzzy completions.)
(If, for some reason, you want the frame names to be just F1
, F2
, etc., as with terminal Emacs, then you just need to do that at the level of frame parameter name
. You can do that using hooks etc.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With