ch11ng / exwm

Emacs X Window Manager
2.85k stars 134 forks source link

Fullscreen windows hide all keybindings #786

Open spiderbit opened 4 years ago

spiderbit commented 4 years ago

I have currently a shortcut setup to change focus to other monitor (workspace) but when I fullscreen mpv or a video in firefox I can't use that shortcut, so I have to move over with the mouse and press the key to get the focus there, is there a way to keep the keymaps?

lucasgruss commented 4 years ago

The function exwm-layout-set-fullscreen is used to set fullscreen. At the end of the function, last statement is (exwm-input--release-keyboard exwm--id) which forces char-mode. I redefined the function with a little tweak at the end to ensure that the input mode currently used is kept in fullscreen:

(cl-defun exwm-layout-set-fullscreen (&optional id)
  "Make window ID fullscreen."
  (interactive)
  (exwm--log "id=#x%x" (or id 0))
  (unless (and (or id (derived-mode-p 'exwm-mode))
               (not (exwm-layout--fullscreen-p)))
    (cl-return-from exwm-layout-set-fullscreen))
  (with-current-buffer (if id (exwm--id->buffer id) (window-buffer))
    ;; Expand the X window to fill the whole screen.
    (with-slots (x y width height) (exwm-workspace--get-geometry exwm--frame)
      (exwm--set-geometry exwm--id x y width height))
    ;; Raise the X window.
    (xcb:+request exwm--connection
        (make-instance 'xcb:ConfigureWindow
                       :window exwm--id
                       :value-mask (logior xcb:ConfigWindow:BorderWidth
                                           xcb:ConfigWindow:StackMode)
                       :border-width 0
                       :stack-mode xcb:StackMode:Above))
    (cl-pushnew xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)
    (exwm-layout--set-ewmh-state exwm--id)
    (xcb:flush exwm--connection)
    (set-window-dedicated-p (get-buffer-window) t)
    (when (eq 'char-mode exwm--selected-input-mode)
      (exwm-input--release-keyboard exwm--id))))

If you want it fixed right now you can redefine it in your init file or in your version of exwm-layout while I open a pull request and see if it gets accepted (once I have made some more testing)

spiderbit commented 4 years ago

just tried it out, have not the latest exwm version installed currently so I got a error but after uncommenting this line: (exwm-layout--set-ewmh-state exwm--id)

it seems to work. Can use my keyboard shortcut in xah-fly-keys, I would expect that other modal modes like vi modes and avy-window or what they are called, should work with that too.

That said it should be activated by a variable or needs some refinement :D because I can then switch to a different window (not only frame) that is than not visible and as example write there blindly or use keys to start some actions I don't see, the same with the minibuffer can open them invisible and do some stuff :D

Or does this layout function I forgo for now (have to upgrade later) fix this problems?

lucasgruss commented 4 years ago

Hi, No, in either case there is a problem with window switching when an X window is fullscreen like you described. Here are wrapper functions inspired by windower.el around exwm-layout-set-fullscreen and exwm-reset that try to make it less painful.

(defvar exwm--last-configuration nil
  "Last window configuration before maximizing X window.")

(defun my/exwm-layout-fullscreen ()
  "Save window configuration and close other windows before fullscreen."
  (interactive)
  (unless (= 1 (count-windows))
    (progn
      (setq exwm--last-configuration (current-window-configuration))
      (delete-other-windows)))
  (exwm-layout-set-fullscreen))

(defun my/exwm-reset ()
  "Restore window configuration before fullscreen."
  (interactive)
  (exwm-reset)
  (when exwm--last-configuration
    (progn
      (set-window-configuration exwm--last-configuration)
      (setq exwm--last-configuration nil))))

Let me know if those wrappers are a step in the right direction ! The idea is simply to close all windows before enabling fullscreen and restoring them when exiting it. It makes window switching impossible (thus fixing the focus problem) while fullscreen is active, but you have to exit fullscreen before being able to get back to your other window. If this is one too many keystrokes for you, writing a wrapper around other-window to call exwm-reset before the switch should do the trick too, in which case insert only the following:

(defun other-window-wrapper ()
  "Call 'exwm-reset' before calling other-window."
  (exwm-reset)
  (other-window))

Writing the same kind of wrapper function for your prefered M-x command (if you're using ivy, helm, ido or even vanilla M-x) should be easy. You also need to rebind all functions to their wrapped versions.

edit: I am not advising functions here, as I think wrappers allow for more flexibility since they are explicitly called. I am personally using framemove and windmove to navigate monitors, so I were to advise functions for window movement, changing to another screen would unset fullscreen on the first monitor. Since use cases vary so much, I doubt that EXWM will include "better" handling of fullscreen, which is better left to the users to implement.

spiderbit commented 4 years ago

@lucasgruss Well for now we don't even have a included function to switch the monitor because there is no variable that tracks the history of which workspace(frame) was active on which monitor the last time or which is currently active.

I find it a bit strange that a tiling wm has such crappy multi-monitor support.

About your last wrappers, I am a bit confused I don't have a keybiding to do fullscreen in emacs it's the "f" binding of the players (in browser or mpv), so how can I use that wrapper for it?

spiderbit commented 4 years ago

@lucasgruss I don't get why on github I see current released version is 0.23, but on my package manager I see:

Archive: gnu Version: 0.24 Homepage: https://github.com/ch11ng/exwm

Did he stop tagging in git the versions, the problem is that the version 0.23 I have installed has not this exwm-layout--set-ewmh-state version and without having it exwm-mff-mode does crazy things :D.

Well I try out the 0.24 version then I guess and report back if I still have problem, or do I have to use git head?

lucasgruss commented 4 years ago

@lucasgruss Well for now we don't even have a included function to switch the monitor because there is no variable that tracks the history of which workspace(frame) was active on which monitor the last time or which is currently active.

I find it a bit strange that a tiling wm has such crappy multi-monitor support.

I agree to some extent, that multi monitor support is the bare minimum, but with a little emacs lisp hacking I find that those are quickly solved. Since everyone has a different workflow, the need for some features might never arise for some users, while being a deal breaker for others. In the example you mention, if you keep to strictly one workspace per monitor, other-frame is all you need to switch monitor, but not sufficient for those using much more workspaces. I also think that EXWM's implementation of workspaces is not really the best when a certain number of them is used, as a lot of frames tend to slow down Emacs in my experience.

About your last wrappers, I am a bit confused I don't have a keybiding to do fullscreen in emacs it's the "f" binding of the players (in browser or mpv), so how can I use that wrapper for it?

You are right, I did not take that into account since I usually call the fullscreen command manually (not by having the programs request fullscreen), in which case you can't use the wrappers for fullscreen. Please update to the latest version of exwm and add the following code to your init file:

(defvar exwm--last-configuration nil
  "Last window configuration before maximizing X window.")

(defun my/exwm-layout-set-fullscreen-save-configuration (&optional _id)
  "Save window configuration and close other windows before fullscreen."
  (interactive)
  (unless (= 1 (count-windows))
    (progn
      (setq exwm--last-configuration (current-window-configuration))
      (delete-other-windows))))

(defun my/exwm-layout-unset-fullscreen-restore-configuration (&optional _id)
  "Restore window configuration before window was fullscreened."
  (interactive)
  (when exwm--last-configuration
    (progn
      (set-window-configuration exwm--last-configuration)
      (setq exwm--last-configuration nil))))

(advice-add 'exwm-layout-set-fullscreen :before #'my/exwm-layout-set-fullscreen-save-configuration)
(advice-add 'exwm-layout-unset-fullscreen :after #'my/exwm-layout-unset-fullscreen-restore-configuration)

It should inhibit window switching when fullscreen is used. tell me if this is a step in the right direction when you get to test it :)

@lucasgruss I don't get why on github I see current released version is 0.23, but on my package manager I see:

Archive: gnu Version: 0.24 Homepage: https://github.com/ch11ng/exwm

Did he stop tagging in git the versions, the problem is that the version 0.23 I have installed has not this exwm-layout--set-ewmh-state version and without having it exwm-mff-mode does crazy things :D.

Well I try out the 0.24 version then I guess and report back if I still have problem, or do I have to use git head?

The wiki mentions changes for version 0.24 so I believe the tag was forgotten, but the version is really 0.24 :)

spiderbit commented 4 years ago

luckily because I already had exwm updated yesterday I could test that fast, and with the other window works out great.

But it becomes very weird when I use other commands M-x or something opens invisibly the minibuffer and does stuff, now you will say when do you do that, fair enough I guess, but it could be that I think I have focus on the other monitor and do it and it becomes then very weird somehow the minibuffer because a semi normal buffer that got bigger by pressing enter and I could switch there with other-window...

Also I can with in my case Menu + 4 split the screen in the back and then use the switch-window again all invisible, but well I either can live with that or somehow change all the keybindings according to the fullscreen hooks.

So sorry can't think to deeply now to late, just had enough power in my to test it out 4:00 a'clock a.m. here :P

I could try to force insert mode but set the key for switch-frame somehow... but have to look into that another time.

spiderbit commented 3 years ago

I wrote something related to that problem, it's a bit more specialized comfort function to switch between a fullscreen window and back so you can do some mpv control and go on with your work you left of if you bind it to a button. If you don't use xah-fly-mode you can delete that lines or of course change code for other fullscreen players maybe that is helpful for somebody else:

(defun window-mpv-p (window)
  "checks if WINDOW is a mpv window"
  (equal "mpv" (buffer-name (window-buffer window))))

(defun switch-to-mpv-and-back ()
  (interactive) 
  (if (and (window-mpv-p (car (window-list)))
       (boundp 'sb/saved-window)
       sb/saved-window)
      ;; reset original window and fly-state
      (progn (select-window sb/saved-window)
         (setq sb/saved-window nil)
         (unless sb/saved-insert-state-q
           (xah-fly-command-mode-activate)))
    ;; switch to mpv and enter insert mode
    (progn
      ;; save start states
      (setq sb/saved-window (car (window-list)))
      (setq sb/saved-insert-state-q xah-fly-insert-state-q)
      ;; switch to mpv
      (select-window
       (car (seq-filter
         (lambda (window)
           (window-mpv-p window))
         (window-list-1 nil 0 t))))
      (xah-fly-insert-mode-activate))))