Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make frames in Emacs GUI behaves like frames in Terminal

Tags:

emacs

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?

like image 752
Amumu Avatar asked Jun 11 '14 08:06

Amumu


People also ask

How do I change frames in Emacs?

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.

What is a frame in Emacs?

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.

How do I close a frame in Emacs?

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 ).

How many windows buffers may have?

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.


2 Answers

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)
like image 170
Amos Avatar answered Oct 16 '22 03:10

Amos


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.)

like image 34
Drew Avatar answered Oct 16 '22 03:10

Drew