ch11ng / exwm

Emacs X Window Manager
2.85k stars 136 forks source link

Feature request: include quick return to previous workspace #784

Open gnusupport opened 3 years ago

gnusupport commented 3 years ago

As my personal way of using EXWM is to switch to workspace with browser and then come back to workspace with email client, I would like that EXWM includes a function for a quick return to previously used workspace. That would be something similar like Alt-TAB in some other Window Managers.

lucasgruss commented 3 years ago

Hi, I tried a quick hack, the following snippet should work:

(defvar exwm-workspace--switch-history-hack (cons exwm-workspace-current-index '()))

(add-hook 'exwm-workspace-switch-hook
          (lambda ()
            (setq exwm-workspace--switch-history-hack
                  (cons exwm-workspace-current-index
                        (car exwm-workspace--switch-history-hack)))))

(defun exwm-workspace-switch-to-last ()
  (interactive)
  "Switch to the workspace that was used before current workspace"
  (exwm-workspace-switch (cdr exwm-workspace--switch-history-hack)))
(add-to-list 'exwm-input-global-keys '([?\s-q] . exwm-workspace-switch-to-last))

My emacs-lisp is not the best, so there might be a better way to achieve the same results, but I would say this works well enough. I would also suggest that this code be evaluated after exwm has been started, as I don't know when variable exwm-workspace-current-index is initialized. As for turning it into an actual feature of EXWM this will depend on the maintainers, but it might be interesting to at least add this snippet of code to the cookbook for people with the same workflow ?

HumHongeKamyaab commented 3 years ago

@lucasgruss +1 I was looking for same in-built function.

gnusupport commented 3 years ago

Excellent, thank you.

gnusupport commented 3 years ago

Something is not working well there.

lucasgruss commented 3 years ago

Can you be more specific as to what the issue is ?

gnusupport commented 3 years ago

Following is working maybe once, when I come to X program like browser, it will not work and bring me back, and then if I only wish to switch between workspace 1 and 2, without any X program, it does not work any more.

(defvar exwm-workspace--switch-history-hack (cons exwm-workspace-current-index '()))

(add-hook 'exwm-workspace-switch-hook
          (lambda ()
            (setq exwm-workspace--switch-history-hack
                  (cons exwm-workspace-current-index
                        (car exwm-workspace--switch-history-hack)))))

(defun exwm-workspace-switch-to-last ()
  (interactive)
  "Switch to the workspace that was used before current workspace"
  (exwm-workspace-switch (cdr exwm-workspace--switch-history-hack)))

(global-set-key (kbd "s-q") #'exwm-workspace-switch-to-last)
HumHongeKamyaab commented 3 years ago

@gnusupport Did you try this

(exwm-input-set-key (kbd "s-q") #'exwm-workspace-switch-to-last)
gnusupport commented 3 years ago

That works now better.

What does not work is that when I switch to X browser, then I cannot go back.

Jean

HumHongeKamyaab commented 3 years ago

Hi, I tried a quick hack, the following snippet should work:

(defvar exwm-workspace--switch-history-hack (cons exwm-workspace-current-index '()))

(add-hook 'exwm-workspace-switch-hook
          (lambda ()
            (setq exwm-workspace--switch-history-hack
                  (cons exwm-workspace-current-index
                        (car exwm-workspace--switch-history-hack)))))

(defun exwm-workspace-switch-to-last ()
  (interactive)
  "Switch to the workspace that was used before current workspace"
  (exwm-workspace-switch (cdr exwm-workspace--switch-history-hack)))

(bind-key (kbd "M-<tab>") #'exwm-workspace-switch-to-last)

My emacs-lisp is not the best, so there might be a better way to achieve the same results, but I would say this works well enough. I would also suggest that this code be evaluated after exwm has been started, as I don't know when variable exwm-workspace-current-index is initialized. As for turning it into an actual feature of EXWM this will depend on the maintainers, but it might be interesting to at least add this snippet of code to the cookbook for people with the same workflow ?

@lucasgruss Instead of switching to last workspace, I want to cyclically switch between different workspaces using (exwm-input-set-key (kbd "s-p") #'exwm-workspace-switch-cyclically). For eg if I have 3 workspaces numbered 0, 1, 2. Each time I press "s-p", workspace switch from 0 to 1, 1 to 2, and 2 to 0 respectively. Can you suggest modification to your elisp hack for it. Also I can't figure out how to add workspace number in the modeline.

lucasgruss commented 3 years ago

@gnusupport Yes for the command to work when an X window is active, it should be bound to a key through exwm-input-global-key not with bind-key, my bad. I'll edit the code to work correctly.

@HumHongeKamyaab sure, the following function should work:

(defun exwm-workspace-switch-cycle ()
  "Cycle through workspaces"
  (interactive)
  (exwm-workspace-switch
   (or (nth (+ exwm-workspace-current-index 1) exwm-workspace--list)
   (car exwm-workspace--list))))

To bind commands with EXWM, the docstring of exwm-input-set-key recommends setting or customizing exwm-input-global-keys to allow keybindings to persist from one session to another.

For indication of workspace in the modeline, you can refer to #556

gnusupport commented 3 years ago

I am now successfully using it:

(defvar exwm-workspace--switch-history-hack (cons exwm-workspace-current-index '()))

(add-hook 'exwm-workspace-switch-hook
          (lambda ()
            (setq exwm-workspace--switch-history-hack
                  (cons exwm-workspace-current-index
                        (car exwm-workspace--switch-history-hack)))))

(defun exwm-workspace-switch-to-last ()
  (interactive)
  "Switch to the workspace that was used before current workspace"
  (exwm-workspace-switch (cdr exwm-workspace--switch-history-hack)))

(exwm-input-set-key (kbd "s-q") #'exwm-workspace-switch-to-last)

So is that maybe entering the EXWM as official version?

spiderbit commented 3 years ago

I was literally just trying to implement exwm-workspace-switch-cycle, I just called it exwm-switch-monitor. Because the other 2 ways to switch the monitor are not efficiently usable, I am surprised how bad dualhead support in exwm currently is. pressing alt+0 and alt+1 to switch between monitor focus is absurd, or using the exwm-work-space-switch commend where you then have to either press 0 / 1 or left/right is pretty absurd, emacs is about efficiency and this 2 commands kill every efficiency of using dualhead setups.

lucasgruss commented 3 years ago

@spiderbit I don't know your prefered method to switch windows/frames, but have you tried using framemove ? This made it possible to switch monitors pretty easily for me, as I use s-[h/j/k/l] to navigate windows with windmove, setting (setq framemove-hook-into-windmove t) makes everything pretty seamless. You can take a look at my config as reference.

When I have some more time, I might open a pull request to add some usability tips in the cookbook and see if they get approved by the maintainers, and close a couple ongoing issues

spiderbit commented 3 years ago

@lucasgruss Well I want 1 button to switch monitors, and ideally only visible frames, except that exwm don't marks the non active workspaces as non-visible frames. So the best I can do is having only 2 workspaces and never use more and then use this exwm-workspace-switch-cycle on a button.

I am no fan of using A keychords and B having 2 different shortcuts to switch monitors like S-left S-right, currenty I use "W" for that and w for cycling through my windows, like it is default in xah-fly-keys, only in command mode because xah-fly-keys is a modal mode, not perfect but close.

spiderbit commented 3 years ago

Another problem seems to be that when I maximize a video player (mpv / firefox) I can't use command keys. So I can't switch to the other monitor. So when I fullscreen the player with "f" the only way to get the focus on the other monitor is by change it with the mouse.

medranocalvo commented 3 years ago

@lucasgruss, you are very welcome to add this to the cookbook https://github.com/ch11ng/exwm/wiki/Cookbook. Thanks!

lucasgruss commented 3 years ago

@medranocalvo I just added some bits of information, I might add some more later if that's okay !

@HumHongeKamyaab I just realized that there is absolutely no need for my hack in order to cycle through workspaces, since other-frame exists and is just what you are looking for. It is much better than what I did, supports cycling in both directions and jumps by more than one step.

gnusupport commented 3 years ago

I have just tried that, it takes very long time for M-x other-frame to execute.

Myself I cannot live anymore without the below one.

(defvar exwm-workspace--switch-history-hack (cons exwm-workspace-current-index '()))

(add-hook 'exwm-workspace-switch-hook
          (lambda ()
            (setq exwm-workspace--switch-history-hack
                  (cons exwm-workspace-current-index
                        (car exwm-workspace--switch-history-hack)))))

(defun exwm-workspace-switch-to-last ()
  (interactive)
  "Switch to the workspace that was used before current workspace"
  (exwm-workspace-switch (cdr exwm-workspace--switch-history-hack)))

(exwm-input-set-key (kbd "s-q") #'exwm-workspace-switch-to-last)