[gpm] Using gpm in emacs

Nick Roberts nickrob@snap.net.nz
Mon Dec 20 02:21:54 CET 2004


Hi,

emacs-devel are interested in including mouse support for Emacs in a text-only
terminal. I have been advised that the best way to do this might be to connect
to the gpm socket and use its own protocol. I see that there are library calls
in ncurses (getmouse etc) that use gpm. The manual page says that getmouse
uses the wgetch input stream. However term.c in Emacs source code does not
seem to call wgetch but uses calls like tputs. Does this mean that I must use
the library libgpm.a directly? [Please cc to me as I am not subscribed to the
list]

As you can see I know little about the ncurses library but I can learn and I
am hoping that I can `hook things up'. It should be possible to do more this
way than working at the lisp level.

For the moment, I've been playing with t-mouse.el from gpm-1.20.1 (why is it
in contrib?) and made a few changes (some `borrowed' from xt-mouse.el):

1) Make t-mouse-mode a minor mode and use autoload.
2) Use local variable mouse-position-function instead of defadvice.
3) Make mouse events work in header-line, margin and menu-bar and calculate
   co-ordinates accordingly.
4) Terminal support for Mandrake (well at least 9.0) and use with-temp-buffer

I hope to make mouse clicks on the mode-line position dependent shortly,
as for Emacs 21 using X. 

Enable/disable this mode with `M-x t-mouse-mode'. When packaged properly
Emacs should find this command without the need to load t-mouse.el beforehand.
If it doesn't, in your .emacs file put something like:

(autoload 't-mouse-mode "/home/nick/lisp/t-mouse"
  "Toggle t-mouse mode." t)


Please feel free to use any changes that you like.


Nick


*** gpm-1.20.1/contrib/emacs/t-mouse.el	2002-12-25 11:57:16.000000000 +1300
--- t-mouse.el	2004-12-20 13:20:14.000000000 +1300
***************
*** 27,33 ****
  ;; too much internals dependent cruft here.
  
  
- (require 'advice)
  
  (defvar t-mouse-process nil 
    "Embeds the process which passes mouse events to emacs.
--- 27,32 ----
***************
*** 69,88 ****
  (defun t-mouse-tty ()
    "Returns number of virtual terminal Emacs is running on, as a string.
  For example, \"2\" for /dev/tty2."
!   (let ((buffer (generate-new-buffer "*t-mouse*")))
!     (call-process "ps" nil buffer nil "h" (format "%s" (emacs-pid)))
!     (prog1 (save-excursion
!              (set-buffer buffer)
!              (goto-char (point-min))
!              (if (or
! 		  ;; Many versions of "ps", all different....
! 		  (re-search-forward " +tty\\(.?[0-9a-f]\\)" nil t)
! 		  (re-search-forward "p \\([0-9a-f]\\)" nil t)
! 		  (re-search-forward "v0\\([0-9a-f]\\)" nil t)
! 		  (re-search-forward "[0-9]+ +\\([0-9]+\\)" nil t)
! 		  (re-search-forward "[\\t ]*[0-9]+[\\t ]+\\([0-9]+\\)" nil t))
!                  (buffer-substring (match-beginning 1) (match-end 1))))
!       (kill-buffer buffer))))
  
  
  ;; due to a horrible kludge in Emacs' keymap handler
--- 68,85 ----
  (defun t-mouse-tty ()
    "Returns number of virtual terminal Emacs is running on, as a string.
  For example, \"2\" for /dev/tty2."
!   (with-temp-buffer
!     (call-process "ps" nil t nil "h" (format "%s" (emacs-pid)))
!     (goto-char (point-min))
!     (if (or
! 	 ;; Many versions of "ps", all different....
! 	 (re-search-forward " +tty\\(.?[0-9a-f]\\)" nil t)
! 	 (re-search-forward "p \\([0-9a-f]\\)" nil t)
! 	 (re-search-forward "v0\\([0-9a-f]\\)" nil t)
! 	 (re-search-forward "[0-9]+ +\\([0-9]+\\)" nil t)
! 	 (re-search-forward "[\\t ]*[0-9]+[\\t ]+\\([0-9]+\\)" nil t)
! 	 (re-search-forward " +vc/\\(.?[0-9a-f]\\)" nil t)
! 	(buffer-substring (match-beginning 1) (match-end 1)))))
  
  
  ;; due to a horrible kludge in Emacs' keymap handler
***************
*** 160,182 ****
           (top (nth 1 left-top-right-bottom))
           (right (nth 2 left-top-right-bottom))
           (bottom (nth 3 left-top-right-bottom))
!          (coords-or-part (coordinates-in-window-p x-dot-y w)))
      (cond
       ((consp coords-or-part)
        (let ((wx (car coords-or-part)) (wy (cdr coords-or-part)))
          (if (< wx (- right left 1))
              (list w 
!                   (t-mouse-lispy-buffer-posn-from-coords w wx wy)
!                   coords-or-part timestamp)
            (list w 'vertical-scroll-bar
                  (cons (1+ wy) (- bottom top)) timestamp))))
       ((eq coords-or-part 'mode-line)
        (list w 'mode-line (cons (- x left) 0) timestamp))
       ((eq coords-or-part 'vertical-line)
!       (list w 'vertical-line (cons 0 (- y top)) timestamp)))))     
  
  ;;; This fun is partly Copyright (C) 1994 Per Abrahamsen <abraham@iesd.auc.dk>
- 
  (defun t-mouse-make-event ()
    "Makes a Lisp style event from the contents of mouse input accumulator.
  Also trims the accumulator by all the data used to build the event."
--- 157,191 ----
           (top (nth 1 left-top-right-bottom))
           (right (nth 2 left-top-right-bottom))
           (bottom (nth 3 left-top-right-bottom))
!          (coords-or-part (if w (coordinates-in-window-p x-dot-y w) nil)))
      (cond
       ((consp coords-or-part)
        (let ((wx (car coords-or-part)) (wy (cdr coords-or-part)))
          (if (< wx (- right left 1))
              (list w 
!                   (t-mouse-lispy-buffer-posn-from-coords
! 		   w (- wx left-margin-width)
! 		   (- wy (if header-line-format 1 0)))
!                   (cons (- (car coords-or-part) left-margin-width)
! 			(- (cdr coords-or-part) (if header-line-format 1 0)))
! 		  timestamp)
            (list w 'vertical-scroll-bar
                  (cons (1+ wy) (- bottom top)) timestamp))))
       ((eq coords-or-part 'mode-line)
        (list w 'mode-line (cons (- x left) 0) timestamp))
+      ((eq coords-or-part 'header-line)
+       (list w 'header-line (cons (- x left) 0) timestamp))
+      ((eq coords-or-part nil)
+       (list w 'menu-bar (cons 0 (- y top)) timestamp))
       ((eq coords-or-part 'vertical-line)
!       (list w 'vertical-line (cons 0 (- y top)) timestamp))
!      ((eq coords-or-part 'left-margin)
!       (list w 'left-margin (cons x (- y top)) timestamp nil
! 	    (t-mouse-lispy-buffer-posn-from-coords
! 	     w (+ (- x left) left-margin-width) (- y top))
! 	    (cons x (- y top)) nil '(0. 0) '(0 . 0))))))
  
  ;;; This fun is partly Copyright (C) 1994 Per Abrahamsen <abraham@iesd.auc.dk>
  (defun t-mouse-make-event ()
    "Makes a Lisp style event from the contents of mouse input accumulator.
  Also trims the accumulator by all the data used to build the event."
***************
*** 224,230 ****
  
          (cond
           ;;sink all events on the stupid text mode menubar.
!          ((and menu-bar-mode (eq 0 (cdr t-mouse-current-xy))) nil)
           ((= type-switch 4)             ;must be drag
            (let ((count (nth 2 ob))
                  (start-element
--- 233,239 ----
  
          (cond
           ;;sink all events on the stupid text mode menubar.
! ;         ((and menu-bar-mode (eq 0 (cdr t-mouse-current-xy))) nil)
           ((= type-switch 4)             ;must be drag
            (let ((count (nth 2 ob))
                  (start-element
***************
*** 250,256 ****
                    'mouse-movement)
                  (t-mouse-make-event-element current-xy-avec-time))))))))
  
- 
  (defun t-mouse-process-filter (proc string)
    (setq t-mouse-filter-accumulator
          (concat t-mouse-filter-accumulator string))
--- 259,264 ----
***************
*** 264,292 ****
            (print unread-command-events t-mouse-debug-buffer))
        (setq event (t-mouse-make-event)))))
  
! 
! ;; this overrides a C function which stupidly assumes (no X => no mouse)
! (defadvice mouse-position (around t-mouse-mouse-position activate)
    "Return the t-mouse-position unless running with a window system.
  The (secret) scrollbar interface is not implemented yet."
!   (if (not window-system)
!       (setq ad-return-value
!             (cons (selected-frame) t-mouse-current-xy))
!     ad-do-it))
! 
! (setq mouse-sel-set-selection-function
!       (function (lambda (type value)
!                   (if (not window-system)
!                       (if (eq 'PRIMARY type) (kill-new value))
!                     (funcall t-mouse-prev-set-selection-function
!                              type value)))))
! 
! (setq mouse-sel-get-selection-function
!       (function (lambda (type)
!                   (if (not window-system)
!                       (if (eq 'PRIMARY type)
!                           (current-kill 0) "")
!                     (funcall t-mouse-prev-get-selection-function type)))))
  
  ;; It should be possible to just send SIGTSTP to the inferior with
  ;; stop-process.  That doesn't work; mev receives the signal fine but
--- 272,282 ----
            (print unread-command-events t-mouse-debug-buffer))
        (setq event (t-mouse-make-event)))))
  
! (defun t-mouse-mouse-position-function (pos)
    "Return the t-mouse-position unless running with a window system.
  The (secret) scrollbar interface is not implemented yet."
!   (setcdr pos t-mouse-current-xy)
!   pos)
  
  ;; It should be possible to just send SIGTSTP to the inferior with
  ;; stop-process.  That doesn't work; mev receives the signal fine but
***************
*** 307,341 ****
                             ;(continue-process t-mouse-process)
                             (process-send-string t-mouse-process "pop\n")))))
  
! 
! ;;; User commands
! 
! (defun t-mouse-stop ()
!   "Stop getting mouse events from an asynchronous process."
!   (interactive)
!   (delete-process t-mouse-process)
!   (setq t-mouse-process nil))
! 
! (defun t-mouse-run ()
!   "Starts getting a stream of mouse events from an asynchronous process.
! Only works if Emacs is running on a virtual terminal without a window system.
! Returns the newly created asynchronous process."
!   (interactive)
!   (let ((tty (t-mouse-tty))
!         (process-connection-type t))
!     (if (or window-system (not (stringp tty)))
!         (error "Run t-mouse on a virtual terminal without a window system"))
!     (setq t-mouse-process 
!           (start-process "t-mouse" nil
!                          "mev" "-i" "-E" "-C" tty
!                          (if t-mouse-swap-alt-keys
!                              "-M-leftAlt" "-M-rightAlt")
!                          "-e-move" "-dall" "-d-hard"
!                          "-f")))
!   (setq t-mouse-filter-accumulator "")
!   (set-process-filter t-mouse-process 't-mouse-process-filter)
!   (process-kill-without-query t-mouse-process)
!   t-mouse-process)
  
  (provide 't-mouse)
  
--- 297,337 ----
                             ;(continue-process t-mouse-process)
                             (process-send-string t-mouse-process "pop\n")))))
  
! ;;;###autoload
! (define-minor-mode t-mouse-mode
!   "Toggle t-mouse mode.
! With prefix arg, turn t-mouse mode on iff arg is positive.
! 
! Turn it on to use emacs mouse commands, and off to use t-mouse commands."
!   nil " Mouse" nil :global t
!   (if t-mouse-mode
!       ;; Turn it on
!       (unless window-system
!         ;; Starts getting a stream of mouse events from an asynchronous
!         ;; process.  Only works if Emacs is running on a virtual terminal
!         ;; without a window system.
! 	(progn
! 	 (setq mouse-position-function #'t-mouse-mouse-position-function)
! 	 (let ((tty (t-mouse-tty))
! 	       (process-connection-type t))
! 	   (if (not (stringp tty))
! 	       (error "Cannot find a virtual terminal."))
! 	   (setq t-mouse-process 
! 		 (start-process "t-mouse" nil
! 				"mev" "-i" "-E" "-C" tty
! 				(if t-mouse-swap-alt-keys
! 				    "-M-leftAlt" "-M-rightAlt")
! 				"-e-move" "-dall" "-d-hard"
! 				"-f")))
! 	 (setq t-mouse-filter-accumulator "")
! 	 (set-process-filter t-mouse-process 't-mouse-process-filter)
! 	 (process-kill-without-query t-mouse-process)))
! ; use line below for emacs 21.4 onwards
! ;	 (set-process-query-on-exit-flag t-mouse-process nil)))
!     ;; Turn it off
!     (setq mouse-position-function nil)
!     (delete-process t-mouse-process)
!     (setq t-mouse-process nil)))
  
  (provide 't-mouse)
  


More information about the gpm mailing list