zonuexe / right-click-context

Emacs Right Click Context menu
https://www.emacswiki.org/emacs/ZonuExe
60 stars 5 forks source link

Left click outside menu pastes and right click in text wrongly selects #2

Open LouisAsh opened 7 years ago

LouisAsh commented 7 years ago

I love this package. However, there are two problems that pretty much make it unusable for me in its current state:

1) whenever the context menu is opened, left-clicking outside it still activates the top-first option in the menu that is being displayed (e.g. when the first options is "Paste", left clicking outside the menu mistakenly pastes).

2) whenever one right clicks anywhere in a text file, the context menu is not shown where the click was performed, but rather where the cursor is. I guess this is a simple fix: the right click should first move the cursor and just then open the right-click context menu.

With these two issues corrected, this package would become a must have for anyone who is not extremely purist about having basic mouse features in Emacs.

jcs090218 commented 5 years ago
  1. whenever the context menu is opened, left-clicking outside it still activates the top-first option in the menu that is being displayed (e.g. when the first options is "Paste", left clicking outside the menu mistakenly pastes).

I think the first issue here is popup.el's fault. popup.el doesn't handle mouse event very well. I made a quick hack to popup.el and it resolved the issue, but the solution is ugly. The benefit to this solution is you can always call jcs-popup-clicked-on-menu-p to check if the mouse clicked on the popup object or not.

;; ----------------------------------------------------------------------------------------
;; Changes to popup.el.
(defvar jcs-popup-mouse-events-flag nil
  "Check if `popup-menu-item-of-mouse-event' is called.")
(defvar jcs-popup-selected-item-flag nil
  "Check if `popup-selected-item' is called.")

(defun jcs-popup-clicked-on-menu-p ()
  "Check if the user actually clicked on the `popup' object."
  (and jcs-popup-mouse-events-flag
       (not jcs-popup-selected-item-flag)))

(defun jcs-advice-popup-menu-item-of-mouse-event-after (event)
  "Advice after execute `popup-menu-item-of-mouse-event' command."
  (setq jcs-popup-mouse-events-flag t)
  (setq jcs-popup-selected-item-flag nil))
(advice-add 'popup-menu-item-of-mouse-event :after #'jcs-advice-popup-menu-item-of-mouse-event-after)

(defun jcs-advice-popup-selected-item-after (popup)
  "Advice after execute `popup-selected-item' command."
  (setq jcs-popup-selected-item-flag t)
  (setq jcs-popup-selected-item-flag (jcs-last-input-event-p "mouse-1")))
(advice-add 'popup-selected-item :after #'jcs-advice-popup-selected-item-after)

(defun jcs-advice-popup-select-around (orig-fun &rest args)
  "Advice around execute `popup-draw' command."
  (let ((do-orig-fun t))
    (when (and (jcs-last-input-event-p "mouse-1")
               (not (jcs-popup-clicked-on-menu-p)))
      (popup-delete (nth (1- (length popup-instances)) popup-instances))
      (setq do-orig-fun nil))
    (when do-orig-fun
      (apply orig-fun args))))
(advice-add 'popup-draw :around #'jcs-advice-popup-select-around)

;; ----------------------------------------------------------------------------------------

(defun jcs-last-input-event-p (te)
  "Check if `last-input-event' a target event.
TE : Target event name"
  (let ((is-event nil))
    (when (listp last-input-event)
      (let ((kn (nth 0 last-input-event)))
        (when (string-match-p te (symbol-name kn))
          (setq is-event t))))
    is-event))

;; ----------------------------------------------------------------------------------------

;; NOTE: Overwrite the `right-click-context-menu` function.
;;;###autoload
(defun right-click-context-menu ()
  "Open Right Click Context menu."
  (interactive)
  (let ((value (popup-cascade-menu (right-click-context--build-menu-for-popup-el (right-click-context--menu-tree) nil))))
    (when (and
           ;; ------------------------------
           ;; NOTE: Line changes.
           (jcs-popup-clicked-on-menu-p)
           ;; ------------------------------
           value)
      (if (symbolp value)
          (call-interactively value t)
        (eval value)))))

2. whenever one right clicks anywhere in a text file, the context menu is not shown where the click was performed, but rather where the cursor is. I guess this is a simple fix: the right click should first move the cursor and just then open the right-click context menu.

Fixed on the newest version.