|
|
1.1 root 1: ;; Mouse handling for Sun windows
2: ;; Copyright (C) 1987 Free Software Foundation, Inc.
3:
4: ;; This file is part of GNU Emacs.
5:
6: ;; GNU Emacs is distributed in the hope that it will be useful,
7: ;; but WITHOUT ANY WARRANTY. No author or distributor
8: ;; accepts responsibility to anyone for the consequences of using it
9: ;; or for whether it serves any particular purpose or works at all,
10: ;; unless he says so in writing. Refer to the GNU Emacs General Public
11: ;; License for full details.
12:
13: ;; Everyone is granted permission to copy, modify and redistribute
14: ;; GNU Emacs, but only under the conditions described in the
15: ;; GNU Emacs General Public License. A copy of this license is
16: ;; supposed to have been given to you along with GNU Emacs so you
17: ;; can know your rights and responsibilities. It should be in a
18: ;; file named COPYING. Among other things, the copyright notice
19: ;; and this notice must be preserved on all copies.
20:
21: ;;; Jeff Peck, Sun Microsystems, Jan 1987.
22: ;;; Original idea by Stan Jefferson
23:
24: (provide 'sun-mouse)
25:
26: ;;;
27: ;;; Modelled after the GNUEMACS keymap interface.
28: ;;;
29: ;;; User Functions:
30: ;;; make-mousemap, copy-mousemap,
31: ;;; define-mouse, global-set-mouse, local-set-mouse,
32: ;;; use-global-mousemap, use-local-mousemap,
33: ;;; mouse-lookup, describe-mouse-bindings
34: ;;;
35: ;;; Options:
36: ;;; extra-click-wait, scrollbar-width
37: ;;;
38:
39: (defvar extra-click-wait 150
40: "*Number of milliseconds to wait for an extra click.
41: Set this to zero if you don't want chords or double clicks.")
42:
43: (defvar scrollbar-width 5
44: "*The character width of the scrollbar.
45: The cursor is deemed to be in the right edge scrollbar if it is this near the
46: right edge, and more than two chars past the end of the indicated line.
47: Setting to nil limits the scrollbar to the edge or vertical dividing bar.")
48:
49: ;;;
50: ;;; Mousemaps
51: ;;;
52: (defun make-mousemap ()
53: "Returns a new mousemap."
54: (cons 'mousemap nil))
55:
56: (defun copy-mousemap (mousemap)
57: "Return a copy of mousemap."
58: (copy-alist mousemap))
59:
60: (defun define-mouse (mousemap mouse-list def)
61: "Args MOUSEMAP, MOUSE-LIST, DEF. Define MOUSE-LIST in MOUSEMAP as DEF.
62: MOUSE-LIST is a list of atoms specifing a mouse hit according to these rules:
63: * One of these atoms specifies the active region of the definition.
64: text, scrollbar, modeline, minibuffer
65: * One or two or these atoms specify the button or button combination.
66: left, middle, right, double
67: * Any combination of these atoms specify the active shift keys.
68: control, shift, meta
69: * With a single unshifted button, you can add
70: up
71: to indicate an up-click.
72: The atom `double' is used with a button designator to denote a double click.
73: Two button chords are denoted by listing the two buttons.
74: See sun-mouse-handler for the treatment of the form DEF."
75: (mousemap-set (mouse-list-to-mouse-code mouse-list) mousemap def))
76:
77: (defun global-set-mouse (mouse-list def)
78: "Give MOUSE-EVENT-LIST a local definition of DEF.
79: See define-mouse for a description of MOUSE-EVENT-LIST and DEF.
80: Note that if MOUSE-EVENT-LIST has a local definition in the current buffer,
81: that local definition will continue to shadow any global definition."
82: (interactive "xMouse event: \nxDefinition: ")
83: (define-mouse current-global-mousemap mouse-list def))
84:
85: (defun local-set-mouse (mouse-list def)
86: "Give MOUSE-EVENT-LIST a local definition of DEF.
87: See define-mouse for a description of the arguments.
88: The definition goes in the current buffer's local mousemap.
89: Normally buffers in the same major mode share a local mousemap."
90: (interactive "xMouse event: \nxDefinition: ")
91: (if (null current-local-mousemap)
92: (setq current-local-mousemap (make-mousemap)))
93: (define-mouse current-local-mousemap mouse-list def))
94:
95: (defun use-global-mousemap (mousemap)
96: "Selects MOUSEMAP as the global mousemap."
97: (setq current-global-mousemap mousemap))
98:
99: (defun use-local-mousemap (mousemap)
100: "Selects MOUSEMAP as the local mousemap.
101: nil for MOUSEMAP means no local mousemap."
102: (setq current-local-mousemap mousemap))
103:
104:
105: ;;;
106: ;;; Interface to the Mouse encoding defined in Emacstool.c
107: ;;;
108: ;;; Called when mouse-prefix is sent to emacs, additional
109: ;;; information is read in as a list (button x y time-delta)
110: ;;;
111: ;;; First, some generally useful functions:
112: ;;;
113:
114: (defun logtest (x y)
115: "True if any bits set in X are also set in Y.
116: Just like the Common Lisp function of the same name."
117: (not (zerop (logand x y))))
118:
119:
120: ;;;
121: ;;; Hit accessors.
122: ;;;
123:
124: (defconst sm::ButtonBits 7) ; Lowest 3 bits.
125: (defconst sm::ShiftmaskBits 56) ; Second lowest 3 bits (56 = 63 - 7).
126: (defconst sm::DoubleBits 64) ; Bit 7.
127: (defconst sm::UpBits 128) ; Bit 8.
128:
129: ;;; All the useful code bits
130: (defmacro sm::hit-code (hit)
131: (` (nth 0 (, hit))))
132: ;;; The button, or buttons if a chord.
133: (defmacro sm::hit-button (hit)
134: (` (logand sm::ButtonBits (nth 0 (, hit)))))
135: ;;; The shift, control, and meta flags.
136: (defmacro sm::hit-shiftmask (hit)
137: (` (logand sm::ShiftmaskBits (nth 0 (, hit)))))
138: ;;; Set if a double click (but not a chord).
139: (defmacro sm::hit-double (hit)
140: (` (logand sm::DoubleBits (nth 0 (, hit)))))
141: ;;; Set on button release (as opposed to button press).
142: (defmacro sm::hit-up (hit)
143: (` (logand sm::UpBits (nth 0 (, hit)))))
144: ;;; Screen x position.
145: (defmacro sm::hit-x (hit) (list 'nth 1 hit))
146: ;;; Screen y position.
147: (defmacro sm::hit-y (hit) (list 'nth 2 hit))
148: ;;; Millisconds since last hit.
149: (defmacro sm::hit-delta (hit) (list 'nth 3 hit))
150:
151: (defmacro sm::hit-up-p (hit) ; A predicate.
152: (` (not (zerop (sm::hit-up (, hit))))))
153:
154: ;;;
155: ;;; Loc accessors. for sm::window-xy
156: ;;;
157: (defmacro sm::loc-w (loc) (list 'nth 0 loc))
158: (defmacro sm::loc-x (loc) (list 'nth 1 loc))
159: (defmacro sm::loc-y (loc) (list 'nth 2 loc))
160:
161: (defmacro eval-in-buffer (buffer &rest forms)
162: "Macro to switches to BUFFER, evaluates FORMS, returns to original buffer."
163: ;; When you don't need the complete window context of eval-in-window
164: (` (let ((StartBuffer (current-buffer)))
165: (unwind-protect
166: (progn
167: (set-buffer (, buffer))
168: (,@ forms))
169: (set-buffer StartBuffer)))))
170:
171: (put 'eval-in-buffer 'lisp-indent-hook 1)
172:
173: ;;; this is used extensively by sun-fns.el
174: ;;;
175: (defmacro eval-in-window (window &rest forms)
176: "Switch to WINDOW, evaluate FORMS, return to original window."
177: (` (let ((OriginallySelectedWindow (selected-window)))
178: (unwind-protect
179: (progn
180: (select-window (, window))
181: (,@ forms))
182: (select-window OriginallySelectedWindow)))))
183: (put 'eval-in-window 'lisp-indent-hook 1)
184:
185: ;;;
186: ;;; handy utility, generalizes window_loop
187: ;;;
188:
189: ;;; It's a macro (and does not evaluate its arguments).
190: (defmacro eval-in-windows (form &optional yesmini)
191: "Switches to each window and evaluates FORM. Optional argument
192: YESMINI says to include the minibuffer as a window.
193: This is a macro, and does not evaluate its arguments."
194: (` (let ((OriginallySelectedWindow (selected-window)))
195: (unwind-protect
196: (while (progn
197: (, form)
198: (not (eq OriginallySelectedWindow
199: (select-window
200: (next-window nil (, yesmini)))))))
201: (select-window OriginallySelectedWindow)))))
202: (put 'eval-in-window 'lisp-indent-hook 0)
203:
204: (defun move-to-loc (x y)
205: "Move cursor to window location X, Y.
206: Handles wrapped and horizontally scrolled lines correctly."
207: (move-to-window-line y)
208: ;; window-line-end expects this to return the window column it moved to.
209: (let ((cc (current-column))
210: (nc (move-to-column
211: (if (zerop (window-hscroll))
212: (+ (current-column)
213: (min (- (window-width) 2) ; To stay on the line.
214: x))
215: (+ (window-hscroll) -1
216: (min (1- (window-width)) ; To stay on the line.
217: x))))))
218: (- nc cc)))
219:
220:
221: (defun minibuffer-window-p (window)
222: "True iff this WINDOW is minibuffer."
223: (= (screen-height)
224: (nth 3 (window-edges window)) ; The bottom edge.
225: ))
226:
227:
228: (defun sun-mouse-handler (&optional hit)
229: "Evaluates the function or list associated with a mouse hit.
230: Expecting to read a hit, which is a list: (button x y delta).
231: A form bound to button by define-mouse is found by mouse-lookup.
232: The variables: *mouse-window*, *mouse-x*, *mouse-y* are bound.
233: If the form is a symbol (symbolp), it is funcall'ed with *mouse-window*,
234: *mouse-x*, and *mouse-y* as arguments; if the form is a list (listp),
235: the form is eval'ed; if the form is neither of these, it is an error.
236: Returns nil."
237: (interactive)
238: (if (null hit) (setq hit (sm::combined-hits)))
239: (let ((loc (sm::window-xy (sm::hit-x hit) (sm::hit-y hit))))
240: (let ((*mouse-window* (sm::loc-w loc))
241: (*mouse-x* (sm::loc-x loc))
242: (*mouse-y* (sm::loc-y loc))
243: (mouse-code (mouse-event-code hit loc)))
244: (let ((form (eval-in-buffer (window-buffer *mouse-window*)
245: (mouse-lookup mouse-code))))
246: (cond ((null form)
247: (if (not (sm::hit-up-p hit)) ; undefined up hits are ok.
248: (error "Undefined mouse event: %s"
249: (prin1-to-string
250: (mouse-code-to-mouse-list mouse-code)))))
251: ((symbolp form)
252: (setq this-command form)
253: (funcall form *mouse-window* *mouse-x* *mouse-y*))
254: ((listp form)
255: (setq this-command (car form))
256: (eval form))
257: (t
258: (error "Mouse action must be symbol or list, but was: %s"
259: form))))))
260: ;; Don't let 'sun-mouse-handler get on last-command,
261: ;; since this function should be transparent.
262: (if (eq this-command 'sun-mouse-handler)
263: (setq this-command last-command))
264: ;; (message (prin1-to-string this-command)) ; to see what your buttons did
265: nil)
266:
267: (defun sm::combined-hits ()
268: "Read and return next mouse-hit, include possible double click"
269: (let ((hit1 (mouse-hit-read)))
270: (if (not (sm::hit-up-p hit1)) ; Up hits dont start doubles or chords.
271: (let ((hit2 (mouse-second-hit extra-click-wait)))
272: (if hit2 ; we cons'd it, we can smash it.
273: ; (setf (sm::hit-code hit1) (logior (sm::hit-code hit1) ...))
274: (setcar hit1 (logior (sm::hit-code hit1)
275: (sm::hit-code hit2)
276: (if (= (sm::hit-button hit1)
277: (sm::hit-button hit2))
278: sm::DoubleBits 0))))))
279: hit1))
280:
281: (defun mouse-hit-read ()
282: "Read mouse-hit list from keyboard. Like (read 'read-char),
283: but that uses minibuffer, and mucks up last-command."
284: (let ((char-list nil) (char nil))
285: (while (not (equal 13 ; Carriage return.
286: (prog1 (setq char (read-char))
287: (setq char-list (cons char char-list))))))
288: (read (mapconcat 'char-to-string (nreverse char-list) ""))
289: ))
290:
291: ;;; Second Click Hackery....
292: ;;; if prefix is not mouse-prefix, need a way to unread the char...
293: ;;; or else have mouse flush input queue, or else need a peek at next char.
294:
295: ;;; There is no peek, but since one character can be unread, we only
296: ;;; have to flush the queue when the command after a mouse click
297: ;;; starts with mouse-prefix1 (see below).
298: ;;; Something to do later: We could buffer the read commands and
299: ;;; execute them ourselves after doing the mouse command (using
300: ;;; lookup-key ??).
301:
302: (defvar mouse-prefix1 24 ; C-x
303: "First char of mouse-prefix. Used to detect double clicks and chords.")
304:
305: (defvar mouse-prefix2 0 ; C-@
306: "Second char of mouse-prefix. Used to detect double clicks and chords.")
307:
308:
309: (defun mouse-second-hit (hit-wait)
310: "Returns the next mouse hit occurring within HIT-WAIT milliseconds."
311: (if (sit-for-millisecs hit-wait) nil ; No input within hit-wait millisecs.
312: (let ((pc1 (read-char)))
313: (if (or (not (equal pc1 mouse-prefix1))
314: (sit-for-millisecs 3)) ; a mouse prefix will have second char
315: (progn (setq unread-command-char pc1) ; Can get away with one unread.
316: nil) ; Next input not mouse event.
317: (let ((pc2 (read-char)))
318: (if (not (equal pc2 mouse-prefix2))
319: (progn (setq unread-command-char pc1) ; put back the ^X
320: ;;; Too bad can't do two: (setq unread-command-char (list pc1 pc2))
321: (ding) ; user will have to retype that pc2.
322: nil) ; This input is not a mouse event.
323: ;; Next input has mouse prefix and is within time limit.
324: (let ((new-hit (mouse-hit-read))) ; Read the new hit.
325: (if (sm::hit-up-p new-hit) ; Ignore up events when timing.
326: (mouse-second-hit (- hit-wait (sm::hit-delta new-hit)))
327: new-hit ; New down hit within limit, return it.
328: ))))))))
329:
330: (defun sm::window-xy (x y)
331: "Find window containing screen coordinates X and Y.
332: Returns list (window x y) where x and y are relative to window."
333: (or
334: (catch 'found
335: (eval-in-windows
336: (let ((we (window-edges (selected-window))))
337: (let ((le (nth 0 we))
338: (te (nth 1 we))
339: (re (nth 2 we))
340: (be (nth 3 we)))
341: (if (= re (screen-width))
342: ;; include the continuation column with this window
343: (setq re (1+ re)))
344: (if (= be (screen-height))
345: ;; include partial line at bottom of screen with this window
346: ;; id est, if window is not multple of char size.
347: (setq be (1+ be)))
348:
349: (if (and (>= x le) (< x re)
350: (>= y te) (< y be))
351: (throw 'found
352: (list (selected-window) (- x le) (- y te))))))
353: t)) ; include minibuffer in eval-in-windows
354: ;;If x,y from a real mouse click, we shouldn't get here.
355: (list nil x y)
356: ))
357:
358: (defun sm::window-region (loc)
359: "Parse LOC into a region symbol.
360: Returns one of (text scrollbar modeline minibuffer)"
361: (let ((w (sm::loc-w loc))
362: (x (sm::loc-x loc))
363: (y (sm::loc-y loc)))
364: (let ((right (1- (window-width w)))
365: (bottom (1- (window-height w))))
366: (cond ((minibuffer-window-p w) 'minibuffer)
367: ((>= y bottom) 'modeline)
368: ((>= x right) 'scrollbar)
369: ;; far right column (window seperator) is always a scrollbar
370: ((and scrollbar-width
371: ;; mouse within scrollbar-width of edge.
372: (>= x (- right scrollbar-width))
373: ;; mouse a few chars past the end of line.
374: (>= x (+ 2 (window-line-end w x y))))
375: 'scrollbar)
376: (t 'text)))))
377:
378: (defun window-line-end (w x y)
379: "Return WINDOW column (ignore X) containing end of line Y"
380: (eval-in-window w (save-excursion (move-to-loc (screen-width) y))))
381:
382: ;;;
383: ;;; The encoding of mouse events into a mousemap.
384: ;;; These values must agree with coding in emacstool:
385: ;;;
386: (defconst sm::keyword-alist
387: '((left . 1) (middle . 2) (right . 4)
388: (shift . 8) (control . 16) (meta . 32) (double . 64) (up . 128)
389: (text . 256) (scrollbar . 512) (modeline . 1024) (minibuffer . 2048)
390: ))
391:
392: (defun mouse-event-code (hit loc)
393: "Maps MOUSE-HIT and LOC into a mouse-code."
394: ;;;Region is a code for one of text, modeline, scrollbar, or minibuffer.
395: (logior (sm::hit-code hit)
396: (mouse-region-to-code (sm::window-region loc))))
397:
398: (defun mouse-region-to-code (region)
399: "Returns partial mouse-code for specified REGION."
400: (cdr (assq region sm::keyword-alist)))
401:
402: (defun mouse-list-to-mouse-code (mouse-list)
403: "Map a MOUSE-LIST to a mouse-code."
404: (apply 'logior
405: (mapcar (function (lambda (x)
406: (cdr (assq x sm::keyword-alist))))
407: mouse-list)))
408:
409: (defun mouse-code-to-mouse-list (mouse-code)
410: "Map a MOUSE-CODE to a mouse-list."
411: (apply 'nconc (mapcar
412: (function (lambda (x)
413: (if (logtest mouse-code (cdr x))
414: (list (car x)))))
415: sm::keyword-alist)))
416:
417: (defun mousemap-set (code mousemap value)
418: (let* ((alist (cdr mousemap))
419: (assq-result (assq code alist)))
420: (if assq-result
421: (setcdr assq-result value)
422: (setcdr mousemap (cons (cons code value) alist)))))
423:
424: (defun mousemap-get (code mousemap)
425: (cdr (assq code (cdr mousemap))))
426:
427: (defun mouse-lookup (mouse-code)
428: "Look up MOUSE-EVENT and return the definition. nil means undefined."
429: (or (mousemap-get mouse-code current-local-mousemap)
430: (mousemap-get mouse-code current-global-mousemap)))
431:
432: ;;;
433: ;;; I (jpeck) don't understand the utility of the next four functions
434: ;;; ask Steven Greenbaum <froud@kestrel>
435: ;;;
436: (defun mouse-mask-lookup (mask list)
437: "Args MASK (a bit mask) and LIST (a list of (code . form) pairs).
438: Returns a list of elements of LIST whose code or'ed with MASK is non-zero."
439: (let ((result nil))
440: (while list
441: (if (logtest mask (car (car list)))
442: (setq result (cons (car list) result)))
443: (setq list (cdr list)))
444: result))
445:
446: (defun mouse-union (l l-unique)
447: "Return the union of list of mouse (code . form) pairs L and L-UNIQUE,
448: where L-UNIQUE is considered to be union'ized already."
449: (let ((result l-unique))
450: (while l
451: (let ((code-form-pair (car l)))
452: (if (not (assq (car code-form-pair) result))
453: (setq result (cons code-form-pair result))))
454: (setq l (cdr l)))
455: result))
456:
457: (defun mouse-union-first-prefered (l1 l2)
458: "Return the union of lists of mouse (code . form) pairs L1 and L2,
459: based on the code's, with preference going to elements in L1."
460: (mouse-union l2 (mouse-union l1 nil)))
461:
462: (defun mouse-code-function-pairs-of-region (region)
463: "Return a list of (code . function) pairs, where each code is
464: currently set in the REGION."
465: (let ((mask (mouse-region-to-code region)))
466: (mouse-union-first-prefered
467: (mouse-mask-lookup mask (cdr current-local-mousemap))
468: (mouse-mask-lookup mask (cdr current-global-mousemap))
469: )))
470:
471: ;;;
472: ;;; Functions for DESCRIBE-MOUSE-BINDINGS
473: ;;; And other mouse documentation functions
474: ;;; Still need a good procedure to print out a help sheet in readable format.
475: ;;;
476:
477: (defun one-line-doc-string (function)
478: "Returns first line of documentation string for FUNCTION.
479: If there is no documentation string, then the string
480: \"No documentation\" is returned."
481: (while (consp function) (setq function (car function)))
482: (let ((doc (documentation function)))
483: (if (null doc)
484: "No documentation."
485: (string-match "^.*$" doc)
486: (substring doc 0 (match-end 0)))))
487:
488: (defun print-mouse-format (binding)
489: (princ (car binding))
490: (princ ": ")
491: (mapcar (function
492: (lambda (mouse-list)
493: (princ mouse-list)
494: (princ " ")))
495: (cdr binding))
496: (terpri)
497: (princ " ")
498: (princ (one-line-doc-string (car binding)))
499: (terpri)
500: )
501:
502: (defun print-mouse-bindings (region)
503: "Prints mouse-event bindings for REGION."
504: (mapcar 'print-mouse-format (sm::event-bindings region)))
505:
506: (defun sm::event-bindings (region)
507: "Returns an alist of (function . (mouse-list1 ... mouse-listN)) for REGION,
508: where each mouse-list is bound to the function in REGION."
509: (let ((mouse-bindings (mouse-code-function-pairs-of-region region))
510: (result nil))
511: (while mouse-bindings
512: (let* ((code-function-pair (car mouse-bindings))
513: (current-entry (assoc (cdr code-function-pair) result)))
514: (if current-entry
515: (setcdr current-entry
516: (cons (mouse-code-to-mouse-list (car code-function-pair))
517: (cdr current-entry)))
518: (setq result (cons (cons (cdr code-function-pair)
519: (list (mouse-code-to-mouse-list
520: (car code-function-pair))))
521: result))))
522: (setq mouse-bindings (cdr mouse-bindings))
523: )
524: result))
525:
526: (defun describe-mouse-bindings ()
527: "Lists all current mouse-event bindings."
528: (interactive)
529: (with-output-to-temp-buffer "*Help*"
530: (princ "Text Region") (terpri)
531: (princ "---- ------") (terpri)
532: (print-mouse-bindings 'text) (terpri)
533: (princ "Modeline Region") (terpri)
534: (princ "-------- ------") (terpri)
535: (print-mouse-bindings 'modeline) (terpri)
536: (princ "Scrollbar Region") (terpri)
537: (princ "--------- ------") (terpri)
538: (print-mouse-bindings 'scrollbar)))
539:
540: (defun describe-mouse-briefly (mouse-list)
541: "Print a short description of the function bound to MOUSE-LIST."
542: (interactive "xDescibe mouse list briefly: ")
543: (let ((function (mouse-lookup (mouse-list-to-mouse-code mouse-list))))
544: (if function
545: (message "%s runs the command %s" mouse-list function)
546: (message "%s is undefined" mouse-list))))
547:
548: (defun mouse-help-menu (function-and-binding)
549: (cons (prin1-to-string (car function-and-binding))
550: (menu-create ; Two sub-menu items of form ("String" . nil)
551: (list (list (one-line-doc-string (car function-and-binding)))
552: (list (prin1-to-string (cdr function-and-binding)))))))
553:
554: (defun mouse-help-region (w x y &optional region)
555: "Displays a menu of mouse functions callable in this region."
556: (let* ((region (or region (sm::window-region (list w x y))))
557: (mlist (mapcar (function mouse-help-menu)
558: (sm::event-bindings region)))
559: (menu (menu-create (cons (list (symbol-name region)) mlist)))
560: (item (sun-menu-evaluate w 0 y menu))
561: )))
562:
563: ;;;
564: ;;; Menu interface functions
565: ;;;
566: ;;; use defmenu, because this interface is subject to change
567: ;;; really need a menu-p, but we use vectorp and the context...
568: ;;;
569: (defun menu-create (items)
570: "Functional form for defmenu, given a list of ITEMS returns a menu.
571: Each ITEM is a (STRING . VALUE) pair."
572: (apply 'vector items)
573: )
574:
575: (defmacro defmenu (menu &rest itemlist)
576: "Defines MENU to be a menu, the ITEMS are (STRING . VALUE) pairs.
577: See sun-menu-evaluate for interpretation of ITEMS."
578: (list 'defconst menu (funcall 'menu-create itemlist))
579: )
580:
581: (defun sun-menu-evaluate (*menu-window* *menu-x* *menu-y* menu)
582: "Display a pop-up menu in WINDOW at X Y and evaluate selected item
583: of MENU. MENU (or its symbol-value) should be a menu defined by defmenu.
584: A menu ITEM is a (STRING . FORM) pair;
585: the FORM associated with the selected STRING is evaluated,
586: and the resulting value is returned. Generally these FORMs are
587: evaluated for their side-effects rather than their values.
588: If the selected form is a menu or a symbol whose value is a menu,
589: then it is displayed and evaluated as a pullright menu item.
590: If the the FORM of the first ITEM is nil, the STRING of the item
591: is used as a label for the menu, i.e. it's inverted and not selectible."
592:
593: (if (symbolp menu) (setq menu (symbol-value menu)))
594: (eval (sun-menu-internal *menu-window* *menu-x* *menu-y* 4 menu)))
595:
596: (defun sun-get-frame-data (code)
597: "Sends the tty-sub-window escape sequence CODE to terminal,
598: and returns a cons of the two numbers in returned escape sequence.
599: That is it returns (cons <car> <cdr>) from \"\\E[n;<car>;<cdr>t\".
600: CODE values: 13 = Tool-Position, 14 = Size-in-Pixels, 18 = Size-in-Chars."
601: (send-string-to-terminal (concat "\033[" (int-to-string code) "t"))
602: (let (char str x y)
603: (while (not (equal 116 (setq char (read-char)))) ; #\t = 116
604: (setq str (cons char str)))
605: (setq str (mapconcat 'char-to-string (nreverse str) ""))
606: (string-match ";[0-9]*" str)
607: (setq y (substring str (1+ (match-beginning 0)) (match-end 0)))
608: (setq str (substring str (match-end 0)))
609: (string-match ";[0-9]*" str)
610: (setq x (substring str (1+ (match-beginning 0)) (match-end 0)))
611: (cons (string-to-int y) (string-to-int x))))
612:
613: (defun sm::font-size ()
614: "Returns font size in pixels: (cons Ysize Xsize)"
615: (let ((pix (sun-get-frame-data 14)) ; returns size in pixels
616: (chr (sun-get-frame-data 18))) ; returns size in chars
617: (cons (/ (car pix) (car chr)) (/ (cdr pix) (cdr chr)))))
618:
619: (defvar sm::menu-kludge-x nil
620: "Cached frame-to-window X-Offset for sm::menu-kludge")
621: (defvar sm::menu-kludge-y nil
622: "Cached frame-to-window Y-Offset for sm::menu-kludge")
623:
624: (defun sm::menu-kludge ()
625: "If sunfns.c uses <Menu_Base_Kludge> this function must be here!"
626: (or sm::menu-kludge-y
627: (let ((fs (sm::font-size)))
628: (setq sm::menu-kludge-y (+ 8 (car fs)) ; a title line and borders
629: sm::menu-kludge-x 4))) ; best values depend on .defaults/Menu
630: (let ((wl (sun-get-frame-data 13))) ; returns frame location
631: (cons (+ (car wl) sm::menu-kludge-y)
632: (+ (cdr wl) sm::menu-kludge-x))))
633:
634: ;;;
635: ;;; Function interface to selection/region
636: ;;; primative functions are defined in sunfns.c
637: ;;;
638: (defun sun-yank-selection ()
639: "Set mark and yank the contents of the current sunwindows selection
640: into the current buffer at point."
641: (interactive "*")
642: (set-mark-command nil)
643: (insert-string (sun-get-selection)))
644:
645: (defun sun-select-region (beg end)
646: "Set the sunwindows selection to the region in the current buffer."
647: (interactive "r")
648: (sun-set-selection (buffer-substring beg end)))
649:
650: ;;;
651: ;;; Support for emacstool
652: ;;; This closes the window instead of stopping emacs.
653: ;;;
654: (defun suspend-emacstool (&optional stuffstring)
655: "If running under as a detached process emacstool,
656: you don't want to suspend (there is no way to resume),
657: just close the window, and wait for reopening."
658: (interactive)
659: (if (and (boundp 'suspend-hook) suspend-hook)
660: (funcall suspend-hook))
661: (if stuffstring (send-string-to-terminal stuffstring))
662: (send-string-to-terminal "\033[2t") ; To close EmacsTool window.
663: (if (and (boundp 'suspend-resume-hook) suspend-resume-hook)
664: (funcall suspend-resume-hook)))
665: ;;;
666: ;;; initialize mouse maps
667: ;;;
668:
669: (make-variable-buffer-local 'current-local-mousemap)
670: (setq-default current-local-mousemap nil)
671: (defvar current-global-mousemap (make-mousemap))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.