Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

corfu and external monitor #86

Closed
11111000000 opened this issue Nov 3, 2024 · 6 comments
Closed

corfu and external monitor #86

11111000000 opened this issue Nov 3, 2024 · 6 comments

Comments

@11111000000
Copy link

11111000000 commented Nov 3, 2024

When external monitor attached, then corfu (triggered from notebook screen) shown on external monitor. How to fix that?

@minad
Copy link
Member

minad commented Nov 3, 2024

This is a Corfu issue, unfortunately still not fixed. See minad/corfu#408.

@minad minad closed this as completed Nov 3, 2024
@Stebalien
Copy link
Contributor

It may also be possible to fix it in EXWM by making the frame the root window instead of making a separate root window, making child frames siblings of X windows. See #64. But... that's mostly a guess at this point, I don't know enough about X programming to know if that'll work (and it would complicate EXWM.

@minad
Copy link
Member

minad commented Nov 4, 2024

It would be nice if EXWM-specific hacks could be removed from Corfu/Posframe and similar packages. It could be that child frames will see more usage in the future, also given that a terminal port is in the works. In any case we would first need an implementation and we should carefully weigh the pros and cons, avoiding unnecessarily complicating EXWM.

@11111000000
Copy link
Author

Currently it works ok with that:

(defun corfu--make-frame (frame x y width height buffer)
  "Show BUFFER in child frame at X/Y with WIDTH/HEIGHT.
FRAME is the existing frame."
  (when-let (((frame-live-p frame))
           (timer (frame-parameter frame 'corfu--hide-timer)))
    (cancel-timer timer)
    (set-frame-parameter frame 'corfu--hide-timer nil))
  (let* ((window-min-height 1)
        (window-min-width 1)
        (inhibit-redisplay t)
        (x-gtk-resize-child-frames corfu--gtk-resize-child-frames)
        (before-make-frame-hook)
        (after-make-frame-functions)
        (parent (window-frame)))
    (unless (and (frame-live-p frame)
             (eq (frame-parent frame)
                  (and (not (bound-and-true-p exwm--connection)) parent))
             ;; If there is more than one window, `frame-root-window' may
             ;; return nil.  Recreate the frame in this case.
             (window-live-p (frame-root-window frame)))
      (when frame (delete-frame frame))
      (setq frame (make-frame
                  `((parent-frame . ,parent)
                    (minibuffer . ,(minibuffer-window parent))
                    (width . 0) (height . 0) (visibility . nil)
                    ,@corfu--frame-parameters))))
    ;; XXX HACK Setting the same frame-parameter/face-background is not a nop.
    ;; Check before applying the setting. Without the check, the frame flickers
    ;; on Mac. We have to apply the face background before adjusting the frame
    ;; parameter, otherwise the border is not updated.
    (let ((new (face-attribute 'corfu-border :background nil 'default)))
      (unless (equal (face-attribute 'internal-border :background frame 'default) new)
        (set-face-background 'internal-border new frame)))
    ;; Reset frame parameters if they changed.  For example `tool-bar-mode'
    ;; overrides the parameter `tool-bar-lines' for every frame, including child
    ;; frames.  The child frame API is a pleasure to work with.  It is full of
    ;; lovely surprises.
    (when-let ((params (frame-parameters frame))
             (reset (seq-remove
                     (lambda (p) (equal (alist-get (car p) params) (cdr p)))
                     `((background-color
                        . ,(face-attribute 'corfu-default :background nil 'default))
                       (font . ,(frame-parameter parent 'font))
                       ,@corfu--frame-parameters))))
      (modify-frame-parameters frame reset))
    (let ((win (frame-root-window frame)))
      (unless (eq (window-buffer win) buffer)
        (set-window-buffer win buffer))
      ;; Disallow selection of root window (gh:minad/corfu#63)
      (set-window-parameter win 'no-delete-other-windows t)
      (set-window-parameter win 'no-other-window t)
      ;; Mark window as dedicated to prevent frame reuse (gh:minad/corfu#60)
      (set-window-dedicated-p win t))
    (redirect-frame-focus frame parent)
    (set-frame-size frame width height t)
    (unless (equal (frame-position frame) (cons x y))
      (if (bound-and-true-p exwm--connection)          
          (set-frame-position
           frame
           (+ x (car (frame-monitor-geometry exwm-workspace--current)))
           (+ y (car (cdr (frame-monitor-geometry exwm-workspace--current)))))
        (set-frame-position frame x y))
      ))
  (make-frame-visible frame)
  ;; Unparent child frame if EXWM is used, otherwise EXWM buffers are drawn on
  ;; top of the Corfu child frame.
  (when (and (bound-and-true-p exwm--connection) (frame-parent frame))
    (set-frame-parameter frame 'parent-frame nil))
  frame)

@11111000000
Copy link
Author

Now it not works :-( corfu ;; Package-Version: 20241223.1449
;; Package-Revision: bbc205c92938

@11111000000
Copy link
Author

now works:


(defun get-focused-monitor-geometry ()
  "Get the geometry of the monitor displaying the selected frame in EXWM."
  (let* ((monitor-attrs (frame-monitor-attributes))
        (workarea (assoc 'workarea monitor-attrs))
        (geometry (cdr workarea)))
    (list (nth 0 geometry) ; X
          (nth 1 geometry) ; Y
          (nth 2 geometry) ; Width
          (nth 3 geometry) ; Height
          )))

(defun advise-corfu-make-frame-with-monitor-awareness (orig-fun frame x y width height)
  "Advise `corfu--make-frame` to be monitor-aware, adjusting X and Y according to the focused monitor."
  ;; Get the geometry of the currently focused monitor
  (let* ((monitor-geometry (get-focused-monitor-geometry))
        (monitor-x (nth 0 monitor-geometry))
        (monitor-y (nth 1 monitor-geometry))
        ;; You may want to adjust the logic below if you have specific preferences
        ;; on where on the monitor the posframe should appear.
        ;; Currently, it places the posframe at its intended X and Y, but ensures
        ;; it's within the bounds of the focused monitor.
        (new-x (+ monitor-x x))
        (new-y (+ monitor-y y)))

    ;; Call the original function with potentially adjusted coordinates
    (funcall orig-fun frame new-x new-y width height)))


(advice-add 'corfu--make-frame :around #'advise-corfu-make-frame-with-monitor-awareness)



Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants