Skip Navigation

Help getting frames in the right locations under macos

I am required to use macos for work but I am having a hell of a time getting my frames to move to the right places in macos, I'll post snippets from my init.el and hopefully someone can recommend fixes. I use emacs-plus from homebrew and I have a 4k external monitor that is positioned to the left of my laptop monitor. This is the output of (display-monitor-attributes-list)

;; (((geometry 0 0 1440 900)
;;   (workarea 0 0 1440 900)
;;   (mm-size 286 179)
;;   (frames)
;;   (source . "NS"))
;;  ((geometry -3840 -1260 3840 2160)
;;   (workarea -3840 -1260 3840 2160)
;;   (mm-size 598 340)
;;   (frames #<frame *scratch* 0x129cbee30>)
;;   (source . "NS")))

Problem 1 (solved probably)

helm frame did not pop up in the correct location, I think I've figured it out but I'm not sure if it's the ideal solution

(defalias 'display-current-monitor-attributes (lambda()
                                                (defalias 'current-monitor-attrs (lambda (attrs)
                                                                                   (cond
                                                                                    ((null (cdr attrs)) (car attrs))
                                                                                    ((member (selected-frame) (assoc 'frames (car attrs))) (car attrs))
                                                                                    (t (current-monitor-attrs (cdr attrs))))))
                                                (current-monitor-attrs (display-monitor-attributes-list))))

 (defun my-helm-display-buffer-in-own-frame (buffer &optional resume)
    "Display Helm buffer BUFFER in a separate frame.

(fixed for my convenience)

Function suitable for `helm-display-function',
`helm-completion-in-region-display-function' and/or
`helm-show-completion-default-display-function'.

See `helm-display-buffer-height' and `helm-display-buffer-width'
to configure frame size.

Note that this feature is available only with emacs-25+.
Note also it is not working properly in helm nested session with emacs
version < emacs-28."
    (cl-assert (and (fboundp 'window-absolute-pixel-edges)
                    (fboundp 'frame-geometry))
               nil "Helm buffer in own frame is only available starting at emacs-25+")
    (if (or (not (display-graphic-p))
            nil
            ;(derived-mode-p 'dirvish-mode 'dired-mode)
            )
        ;; Fallback to default when frames are not usable.
        (helm-default-display-buffer buffer)
      (let* ((frame-info (frame-geometry))
             (workarea (cdr (assq 'workarea (display-current-monitor-attributes))))
             (half-screen-size (truncate (/ (cadddr workarea) 2)))
             (screen-x-origin (car workarea))
             (screen-y-origin (cadr workarea))
             (outer-position (cdr (assq 'outer-position frame-info)))
             (title-bar-size (cddr (assq 'title-bar-size frame-info)))
             (pixel-position (or (window-absolute-pixel-position) (window-absolute-pixel-position nil (selected-window)) (window-absolute-pixel-position nil (old-selected-window)) ))
             (pos-absolute (cons (car pixel-position) (- (cdr pixel-position) title-bar-size)))
             ;; (position (posn-at-point))
             ;; (position-window (posn-window position))
             ;; (pos-relative-to-window (posn-x-y position))
             ;; (window-edges (window-pixel-edges position-window))
             ;; (pos-relative-to-frame (cons (+ (car window-edges) (car pos-relative-to-window)) (+ (cdr pos-relative-to-window )(cadr window-edges))))
             ;; (pos-absolute (cons (+ (car outer-position) (car pos-relative-to-frame)) (+ (cdr pos-relative-to-frame) (cdr outer-position) title-bar-size)))
             (already-helm-buffer-p (prog1 helm--buffer-in-new-frame-p (setq helm--buffer-in-new-frame-p t)))
             (prmt-size (length helm--prompt))
             (line-height (frame-char-height))
             (window-min-height 1)
             (window-min-width helm-display-buffer-width )
             (new-frame-alist
              (if resume
                  (buffer-local-value 'helm--last-frame-parameters
                                      (get-buffer buffer))
                `((width . ,helm-display-buffer-width)
                  (height . ,helm-display-buffer-height)
                  ;; (height . 1)
                  (parent . '(selected-frame))
                  (user-position . t)
                  (tab-bar-show . nil)
                  (tool-bar-lines . 0)
                  (left . ,(cond (already-helm-buffer-p (car outer-position))
                                 (t
                                  (- (max (car pos-absolute) screen-x-origin (car outer-position))
                                     (* (frame-char-width)
                                        (let ((delta-point (- (point) (pos-bol))))
                                          (cond
                                           ((derived-mode-p 'dired-mode 'dirvish-mode) 0)
                                           ((> prmt-size delta-point) delta-point)
                                           (t prmt-size))))))))
                  (top . ,(cond
                           ;; Helm frame top distance already calculated
                           (already-helm-buffer-p (cdr outer-position))
                           ;; Point is below the halfway-point
                           ((> (- (cdr pos-absolute) screen-y-origin) half-screen-size)
                            (- (cdr pos-absolute)
                               (* (+ helm-display-buffer-height 3) line-height)))
                           (t
                            (+ (cdr pos-absolute)
                               (* 2 line-height)))))
                  (title . "Helm")
                  (undecorated-round . ,helm-use-undecorated-frame-option)
                  (background-color . ,(or helm-frame-background-color
                                           (face-attribute 'default :background)))
                  (foreground-color . ,(or helm-frame-foreground-color
                                           (face-attribute 'default :foreground)))
                  (alpha . ,(or helm-frame-alpha 100))
                  (font . ,(assoc-default 'font (frame-parameters)))
                  (vertical-scroll-bars . nil)
                  (menu-bar-lines . 0)
                  (fullscreen . nil)
                  (auto-raise . nil)
                  (visibility . ,(null helm-display-buffer-reuse-frame))
                  (minibuffer . t))))
             display-buffer-alist)
        ;; Display minibuffer above or below only in initial session,
        ;; not on a session triggered by action, this way if user have
        ;; toggled minibuffer and header-line manually she keeps this
        ;; setting in next action.
        (unless (or helm--executing-helm-action resume)
          ;; Add the hook inconditionally, if
          ;; helm-echo-input-in-header-line is nil helm-hide-minibuffer-maybe
          ;; will have anyway no effect so no need to remove the hook.
          (add-hook 'helm-minibuffer-set-up-hook 'helm-hide-minibuffer-maybe)
          (with-helm-buffer
            (setq-local helm-echo-input-in-header-line
                        (<= (- (cdr pos-absolute) screen-y-origin) half-screen-size))))
        ;; When frame size have been modified manually by user restore
        ;; it to default value unless resuming or not using
        ;; `helm-display-buffer-reuse-frame'.
        ;; This have to be done AFTER raising the frame otherwise
        ;; minibuffer visibility is lost until next session.
        (helm-display-buffer-popup-frame buffer new-frame-alist)
        (unless (or resume (not helm-display-buffer-reuse-frame))
          (set-frame-size helm-popup-frame
                          helm-display-buffer-width
                          helm-display-buffer-height))
        )
      (helm-log-run-hook "helm-display-buffer-in-own-frame" 'helm-window-configuration-hook)))



  (setq helm-display-function 'my-helm-display-buffer-in-own-frame
        helm-show-completion-display-function 'my-helm-display-buffer-in-own-frame
        helm-display-buffer-reuse-frame t
        helm-display-buffer-width 150
        helm-display-buffer-height 25
        helm-frame-alpha 100
        helm-use-undecorated-frame-option t)

Problem 2 (here be dragons (please help))

Whenever I lock my laptop my main emacs frame ends up on the laptop monitor still sized for the 4k external display I use making it unusable, to ameliorate this I bound the following to C-$ but it doesn't seem to always work, it seems to maximize on the monitor macos chooses the frame is on instead of on the monitor the frame should be on based on it's position. When I unplug the monitor and call this function it completely fucks up and moves of-screen and I have to delete the frame and open a new one.

The ideal solution would be not having to use a function at all and instead have macos not fuck up the position of my frames when I lock the pc.

(global-set-key (kbd "C-$")
                (defalias 'maximize-frame-on-display
                  (lambda (&optional arg)
                    "maximizes frame on a chosen display"
                    (interactive "P")
                    (let* ((available-displays (display-monitor-attributes-list))
                           (display-info (mapcar (lambda (display)
                                                  (cons (format "%.1f" (cadr (assq 'workarea display)))
                                                        (cadr (assq 'workarea display))))
                                                available-displays))
                           (sorted-info (sort display-info (lambda (a b) (< (cdr a) (cdr b)))))
                           (chosen-left (if arg (completing-read "Choose display: " (mapcar #'car sorted-info)) (caar sorted-info)))
                           (selfr (selected-frame)))
                      (set-frame-parameter selfr 'left `(+ ,(cdr (assoc chosen-left display-info))))
                      (set-frame-parameter selfr 'top 0.0)
                      (set-frame-parameter selfr 'fullscreen nil)
                      (set-frame-parameter selfr 'fullscreen 'maximized)))))

To make this stranger the following works and always places new frames on the left monitor as it should

(setq default-frame-alist '((ns-appearance . dark)
                            (ns-transparent-titlebar . t)
                            (width . 0.5)
                            (height . 1.0)
                            (user-position . t)
                            (fullscreen . maximized)
                            (left . 0.0)
                            (top . 0.0)
                            (font ."-*-Consolas for Powerline-*-*-*-*-16-160-*-*-*-*")
                            (cursor-type . box)
                            ;; (undecorated-round . t)
                            (undecorated . t)
                            (vertical-scroll-bars . nil)))

Problem 3 (kinda solved but I would like something more elegant) macos doesn't seem to have tiling so I had to make some functions for it, is there a package so I can use that instead?

(defalias 'custom-tile-thirds-vertical (lambda ( &optional direction )
                                         "Repositions emacs frame into the left/center/right third of the current display"
                                         (interactive "p")
                                         (let* ((current-position (frame-position))
                                                (direction (cond (direction direction) (t 1)))
                                                (monitor-attr (display-current-monitor-attributes))
                                                (workarea (cdr (assoc 'workarea monitor-attr)))
                                                (origin-x (car workarea))
                                                (origin-y (cadr workarea))
                                                (delta-x (- (car current-position) origin-x ))
                                                (width (caddr workarea))
                                                (third-width (/ width 3))
                                                (height (cadddr workarea)))
                                           (set-frame-size (selected-frame) third-width height t)
                                           (set-frame-position
                                            (selected-frame)
                                            (+ origin-x
                                               (* third-width
                                                  (cond
                                                   ((= 0 (% delta-x third-width)) (% (+ 3 (/ delta-x third-width) direction) 3))
                                                   (t 0))))
                                            origin-y))))


(defalias 'custom-tile-quarters (lambda (&optional direction)
                                  "Reposition emacs frame in corners of current display"
                                  (interactive "p")
                                  (let* ((current-position (frame-position))
                                         (direction (cond (direction direction) (t 1)))
                                         (monitor-attr (display-current-monitor-attributes))
                                         (workarea (cdr (assoc 'workarea monitor-attr)))
                                         (origin-x (car workarea))
                                         (origin-y (cadr workarea))
                                         (delta-x (- (car current-position) origin-x ))
                                         (delta-y (- (cdr current-position) origin-y ))
                                         (width (caddr workarea))
                                         (half-width (/ width 2))
                                         (height (cadddr workarea))
                                         (half-height (/ height 2))
                                         (new-position (cond
                                                        ((and (= 0 delta-x) (= 0 delta-y)) (cond
                                                                                            ((> 0 direction) (list 0 half-height))
                                                                                            (t (list half-width 0))))
                                                        ((and (= 0 delta-x) (= half-height delta-y)) (cond
                                                                                                      ((> 0 direction) (list half-width half-height))
                                                                                                      (t (list 0 0))))
                                                        ((and (= half-width delta-x) (= 0 delta-y)) (cond
                                                                                                     ((> 0 direction) (list 0 0))
                                                                                                     (t (list half-width half-height))))
                                                        ((and (= half-width delta-x) (= half-height delta-y)) (cond
                                                                                                               ((> 0 direction) (list half-width 0))
                                                                                                               (t (list 0 half-height))))
                                                        (t (list 0 0))
                                                        )))
                                    (set-frame-size (selected-frame) half-width half-height t)
                                    (set-frame-position
                                     (selected-frame)
                                     (+ origin-x (car new-position))
                                     (+ origin-y (cadr new-position ))))))


(defalias 'custom-tile-snap-left (lambda ()
                                  "Reposition emacs frame to take up left half of the screen"
                                  (interactive)
                                  (let* ((current-position (frame-position))
                                         (monitor-attr (display-current-monitor-attributes))
                                         (workarea (cdr (assoc 'workarea monitor-attr)))
                                         (origin-x (car workarea))
                                         (origin-y (cadr workarea))
                                         (width (caddr workarea))
                                         (half-width (/ width 2))
                                         (height (cadddr workarea)))
                                    (set-frame-size (selected-frame) half-width height t)
                                    (set-frame-position
                                     (selected-frame)
                                     origin-x
                                     origin-y))))

(defalias 'custom-tile-snap-LEFT (lambda ()
                                  "Reposition emacs frame to take up left two thirds of the screen"
                                  (interactive)
                                  (let* ((current-position (frame-position))
                                         (monitor-attr (display-current-monitor-attributes))
                                         (workarea (cdr (assoc 'workarea monitor-attr)))
                                         (origin-x (car workarea))
                                         (origin-y (cadr workarea))
                                         (width (caddr workarea))
                                         (third-width (floor (/ width 3)))
                                         (height (cadddr workarea)))
                                    (set-frame-size (selected-frame) (* 2 third-width) height t)
                                    (set-frame-position
                                     (selected-frame)
                                     origin-x
                                     origin-y))))

(defalias 'custom-tile-snap-right (lambda ()
                                  "Reposition emacs frame to take up left half of the screen"
                                  (interactive)
                                  (let* ((current-position (frame-position))
                                         (monitor-attr (display-current-monitor-attributes))
                                         (workarea (cdr (assoc 'workarea monitor-attr)))
                                         (origin-x (car workarea))
                                         (origin-y (cadr workarea))
                                         (width (caddr workarea))
                                         (half-width (/ width 2))
                                         (height (cadddr workarea)))
                                    (set-frame-size (selected-frame) half-width height t)
                                    (set-frame-position
                                     (selected-frame)
                                     (+ origin-x half-width)
                                     origin-y))))
0
0 comments