Change `select-active-region' mechanics.

Save region text prior to buffer modification.
Set window selection lazily, during `deactivate-mark' or after each
command when the region is temporarily active.

* lisp/cus-start.el: Add custom declaration for select-active-regions.

* lisp/mouse.el (mouse-drag-track): Remove hacks to deal with old
select-active-regions implementation.
(mouse-yank-at-click): Doc fix.

* lisp/simple.el (select-active-regions): Move to keyboard.c.
(deactivate-mark): Used saved-region-selection.
(select-active-region): Function removed.
(activate-mark, set-mark, push-mark-command)
(handle-shift-selection): Don't call it.
(keyboard-quit): Avoid adding the region to the window selection.

* src/insdel.c (prepare_to_modify_buffer): Save active region text to
Vsaved_region_selection.

* src/keyboard.c (Vselect_active_regions): Move from simple.el.
(Vsaved_region_selection, Qx_set_selection, QPRIMARY, Qlazy): New
vars.
(command_loop_1): Set window selection prior to deactivating the
mark.

* src/xselect.c (QPRIMARY): Move to keyboard.c.
This commit is contained in:
Chong Yidong 2010-08-07 15:39:04 -04:00
parent d064e6a60d
commit 9852377f78
9 changed files with 132 additions and 56 deletions

View file

@ -192,7 +192,10 @@ The way Emacs interacts with the clipboard and primary selection, by
default, is now similar to other X applications. In particular, kill
and yank use the clipboard, in addition to the primary selection.
*** `select-active-regions' now defaults to t.
*** `select-active-regions' now defaults to `lazy'.
This means that any active region made with shift-selection or mouse
dragging, or acted on by Emacs (e.g. with M-w or C-w), is
automatically added to the primary window selection.
*** `x-select-enable-clipboard' now defaults to t.

View file

@ -1,3 +1,18 @@
2010-08-07 Chong Yidong <cyd@stupidchicken.com>
* simple.el (select-active-regions): Move to keyboard.c.
(deactivate-mark): Used saved-region-selection.
(select-active-region): Function removed.
(activate-mark, set-mark, push-mark-command)
(handle-shift-selection): Don't call it.
(keyboard-quit): Avoid adding the region to the window selection.
* mouse.el (mouse-drag-track): Remove hacks to deal with old
select-active-regions implementation.
(mouse-yank-at-click): Doc fix.
* cus-start.el: Add custom declaration for select-active-regions.
2010-08-07 Eli Zaretskii <eliz@gnu.org>
* simple.el (delete-forward-char): Doc fix.

View file

@ -197,6 +197,11 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of
(help-char keyboard character)
(help-event-list keyboard (repeat (sexp :format "%v")))
(menu-prompting menu boolean)
(select-active-regions killing
(choice (const :tag "lazy" lazy)
(const :tag "always" t)
(const :tag "off" nil))
"24.1")
(suggest-key-bindings keyboard (choice (const :tag "off" nil)
(integer :tag "time" 2)
(other :tag "on")))

View file

@ -697,9 +697,6 @@ This should be bound to a mouse drag event."
(window-system)
(sit-for 1))
(push-mark)
;; If `select-active-regions' is non-nil, `set-mark' sets the
;; primary selection to the buffer's region, overriding the role
;; of `copy-region-as-kill'; that's why we did the copy first.
(set-mark (point))
(if (numberp end) (goto-char end))
(mouse-set-region-1)))
@ -905,10 +902,6 @@ DO-MOUSE-DRAG-REGION-POST-PROCESS should only be used by
`mouse-drag-region'."
(mouse-minibuffer-check start-event)
(setq mouse-selection-click-count-buffer (current-buffer))
;; We must call deactivate-mark before repositioning point.
;; Otherwise, for `select-active-regions' non-nil, we get the wrong
;; selection if the user drags a region, clicks elsewhere to
;; reposition point, then middle-clicks to paste the selection.
(deactivate-mark)
(let* ((original-window (selected-window))
;; We've recorded what we needed from the current buffer and
@ -955,10 +948,7 @@ DO-MOUSE-DRAG-REGION-POST-PROCESS should only be used by
(if (eq transient-mark-mode 'lambda)
'(only)
(cons 'only transient-mark-mode)))
(let ((range (mouse-start-end start-point start-point click-count))
;; Prevent `push-mark' from clobbering the primary selection
;; if the user clicks without dragging.
(select-active-regions nil))
(let ((range (mouse-start-end start-point start-point click-count)))
(goto-char (nth 0 range))
(push-mark nil t t)
(goto-char (nth 1 range)))
@ -1017,23 +1007,16 @@ DO-MOUSE-DRAG-REGION-POST-PROCESS should only be used by
;; If point has moved, finish the drag.
(let* (last-command this-command)
;; Copy the region so that `select-active-regions' can
;; override `copy-region-as-kill'.
(and mouse-drag-copy-region
do-mouse-drag-region-post-process
(let (deactivate-mark)
(copy-region-as-kill (mark) (point))))
;; For `select-active-regions' non-nil, ensure that
;; further alterations of the region (e.g. via
;; shift-selection) continue to update PRIMARY.
(select-active-region))
(copy-region-as-kill (mark) (point)))))
;; If point hasn't moved, run the binding of the
;; terminating up-event.
(if do-multi-click
(goto-char start-point)
(let (select-active-regions)
(deactivate-mark)))
(deactivate-mark))
(when (and (functionp fun)
(= start-hscroll (window-hscroll start-window))
;; Don't run the up-event handler if the window
@ -1251,9 +1234,7 @@ Also move point to one end of the text thus inserted (normally the end),
and set mark at the beginning.
Prefix arguments are interpreted as with \\[yank].
If `mouse-yank-at-point' is non-nil, insert at point
regardless of where you click.
If `select-active-regions' is non-nil, the mark is deactivated
before inserting the text."
regardless of where you click."
(interactive "e\nP")
;; Give temporary modes such as isearch a chance to turn off.
(run-hooks 'mouse-leave-buffer-hook)

View file

@ -3666,29 +3666,27 @@ a mistake; see the documentation of `set-mark'."
(marker-position (mark-marker))
(signal 'mark-inactive nil)))
(defcustom select-active-regions t
"If non-nil, an active region automatically becomes the window selection."
:type 'boolean
:group 'killing
:version "24.1")
(declare-function x-selection-owner-p "xselect.c" (&optional selection))
;; Many places set mark-active directly, and several of them failed to also
;; run deactivate-mark-hook. This shorthand should simplify.
(defsubst deactivate-mark (&optional force)
"Deactivate the mark by setting `mark-active' to nil.
Unless FORCE is non-nil, this function does nothing if Transient
Mark mode is disabled.
This function also runs `deactivate-mark-hook'."
(when (or transient-mark-mode force)
;; Copy the latest region into the primary selection, if desired.
(and select-active-regions
mark-active
(display-selections-p)
(x-selection-owner-p 'PRIMARY)
(x-set-selection 'PRIMARY (buffer-substring-no-properties
(region-beginning) (region-end))))
(when (and select-active-regions
(region-active-p)
(display-selections-p))
;; The var `saved-region-selection', if non-nil, is the text in
;; the region prior to the last command modifying the buffer.
;; Set the selection to that, or to the current region.
(cond (saved-region-selection
(x-set-selection 'PRIMARY saved-region-selection)
(setq saved-region-selection nil))
((/= (region-beginning) (region-end))
(x-set-selection 'PRIMARY
(buffer-substring-no-properties
(point) (mark))))))
(if (and (null force)
(or (eq transient-mark-mode 'lambda)
(and (eq (car-safe transient-mark-mode) 'only)
@ -3706,14 +3704,7 @@ This function also runs `deactivate-mark-hook'."
(when (mark t)
(setq mark-active t)
(unless transient-mark-mode
(setq transient-mark-mode 'lambda))
(select-active-region)))
(defsubst select-active-region ()
"Set the PRIMARY X selection if `select-active-regions' is non-nil."
(and select-active-regions
(display-selections-p)
(x-set-selection 'PRIMARY (current-buffer))))
(setq transient-mark-mode 'lambda))))
(defun set-mark (pos)
"Set this buffer's mark to POS. Don't use this function!
@ -3736,7 +3727,6 @@ store it in a Lisp variable. Example:
(progn
(setq mark-active t)
(run-hooks 'activate-mark-hook)
(select-active-region)
(set-marker (mark-marker) pos (current-buffer)))
;; Normally we never clear mark-active except in Transient Mark mode.
;; But when we actually clear out the mark value too, we must
@ -3820,7 +3810,6 @@ Display `Mark set' unless the optional second arg NOMSG is non-nil."
(push-mark nil nomsg t)
(setq mark-active t)
(run-hooks 'activate-mark-hook)
(select-active-region)
(unless nomsg
(message "Mark activated")))))
@ -4008,11 +3997,8 @@ Otherwise, if the region has been activated temporarily,
deactivate it, and restore the variable `transient-mark-mode' to
its earlier value."
(cond ((and shift-select-mode this-command-keys-shift-translated)
(if (and mark-active
(eq (car-safe transient-mark-mode) 'only))
;; Another program may have grabbed the selection; make
;; sure we get it back now.
(select-active-region)
(unless (and mark-active
(eq (car-safe transient-mark-mode) 'only))
(setq transient-mark-mode
(cons 'only
(unless (eq transient-mark-mode 'lambda)
@ -5576,7 +5562,10 @@ it skips the contents of comments that end before point."
During execution of Lisp code, this character causes a quit directly.
At top-level, as an editor command, this simply beeps."
(interactive)
(deactivate-mark)
;; Avoid adding the region to the window selection.
(setq saved-region-selection nil)
(let (select-active-regions)
(deactivate-mark))
(if (fboundp 'kmacro-keyboard-quit)
(kmacro-keyboard-quit))
(setq defining-kbd-macro nil)

View file

@ -1,3 +1,16 @@
2010-08-07 Chong Yidong <cyd@stupidchicken.com>
* insdel.c (prepare_to_modify_buffer): Save active region text to
Vsaved_region_selection.
* xselect.c (QPRIMARY): Move to keyboard.c.
* keyboard.c (Vselect_active_regions): Move from simple.el.
(Vsaved_region_selection, Qx_set_selection, QPRIMARY, Qlazy): New
vars.
(command_loop_1): Set window selection prior to deactivating the
mark.
2010-08-07 Juanma Barranquero <lekktu@gmail.com>
* alloc.c (lisp_malloc):

View file

@ -74,6 +74,8 @@ Lisp_Object combine_after_change_buffer;
Lisp_Object Qinhibit_modification_hooks;
extern Lisp_Object Vselect_active_regions, Vsaved_region_selection;
/* Check all markers in the current buffer, looking for something invalid. */
@ -2047,6 +2049,21 @@ prepare_to_modify_buffer (EMACS_INT start, EMACS_INT end,
base_buffer->filename);
#endif /* not CLASH_DETECTION */
/* If `select-active-regions' is non-nil, save the region text. */
if (!NILP (Vselect_active_regions)
&& !NILP (current_buffer->mark_active)
&& !NILP (Vtransient_mark_mode)
&& NILP (Vsaved_region_selection))
{
Lisp_Object b = Fmarker_position (current_buffer->mark);
Lisp_Object e = make_number (PT);
if (NILP (Fequal (b, e)))
{
validate_region (&b, &e);
Vsaved_region_selection = make_buffer_string (XINT (b), XINT (e), 0);
}
}
signal_before_change (start, end, preserve_ptr);
if (current_buffer->newline_cache)

View file

@ -361,6 +361,15 @@ Lisp_Object Vlast_event_frame;
X Windows wants this for selection ownership. */
unsigned long last_event_timestamp;
/* If non-nil, active regions automatically become the window selection. */
Lisp_Object Vselect_active_regions;
/* The text in the active region prior to modifying the buffer.
Used by the `select-active-regions' feature. */
Lisp_Object Vsaved_region_selection;
Lisp_Object Qx_set_selection, QPRIMARY, Qlazy;
Lisp_Object Qself_insert_command;
Lisp_Object Qforward_char;
Lisp_Object Qbackward_char;
@ -1781,11 +1790,26 @@ command_loop_1 (void)
Vtransient_mark_mode = Qnil;
else if (EQ (Vtransient_mark_mode, Qonly))
Vtransient_mark_mode = Qidentity;
else if (EQ (Vselect_active_regions, Qlazy)
? EQ (CAR_SAFE (Vtransient_mark_mode), Qonly)
: (!NILP (Vselect_active_regions)
&& !NILP (Vtransient_mark_mode)))
{
/* Set window selection. If `select-active-regions' is
`lazy', only do it for temporarily active regions. */
Lisp_Object beg = Fmarker_position (current_buffer->mark);
Lisp_Object end = make_number (PT);
validate_region (&beg, &end);
call2 (Qx_set_selection, QPRIMARY,
make_buffer_string (XINT (beg), XINT (end), 0));
}
if (!NILP (Vdeactivate_mark))
call0 (Qdeactivate_mark);
else if (current_buffer != prev_buffer || MODIFF != prev_modiff)
call1 (Vrun_hooks, intern ("activate-mark-hook"));
Vsaved_region_selection = Qnil;
}
finalize:
@ -11682,6 +11706,13 @@ syms_of_keyboard (void)
Qinput_method_function = intern_c_string ("input-method-function");
staticpro (&Qinput_method_function);
Qx_set_selection = intern_c_string ("x-set-selection");
staticpro (&Qx_set_selection);
QPRIMARY = intern_c_string ("PRIMARY");
staticpro (&QPRIMARY);
Qlazy = intern_c_string ("lazy");
staticpro (&Qlazy);
Qinput_method_exit_on_first_char = intern_c_string ("input-method-exit-on-first-char");
staticpro (&Qinput_method_exit_on_first_char);
Qinput_method_use_echo_area = intern_c_string ("input-method-use-echo-area");
@ -12289,6 +12320,28 @@ Help functions bind this to allow help on disabled menu items
and tool-bar buttons. */);
Venable_disabled_menus_and_buttons = Qnil;
DEFVAR_LISP ("select-active-regions",
&Vselect_active_regions,
doc: /* If non-nil, an active region automatically becomes the window selection.
This takes effect only when Transient Mark mode is enabled.
If the value is `lazy', Emacs only sets the window selection during
`deactivate-mark'; unless the region is temporarily active
(e.g. mouse-drags or shift-selection), in which case it sets the
window selection after each command.
For other non-nil value, Emacs sets the window selection after every
command. */);
Vselect_active_regions = Qlazy;
DEFVAR_LISP ("saved-region-selection",
&Vsaved_region_selection,
doc: /* Contents of active region prior to buffer modification.
If `select-active-regions' is non-nil, Emacs sets this to the
text in the region before modifying the buffer. The next
`deactivate-mark' call uses this to set the window selection. */);
Vsaved_region_selection = Qnil;
/* Create the initial keyboard. */
initial_kboard = (KBOARD *) xmalloc (sizeof (KBOARD));
init_kboard (initial_kboard);

View file

@ -2916,7 +2916,7 @@ A value of 0 means wait as long as necessary. This is initialized from the
\"*selectionTimeout\" resource. */);
x_selection_timeout = 0;
QPRIMARY = intern_c_string ("PRIMARY"); staticpro (&QPRIMARY);
/* QPRIMARY is defined in keyboard.c. */
QSECONDARY = intern_c_string ("SECONDARY"); staticpro (&QSECONDARY);
QSTRING = intern_c_string ("STRING"); staticpro (&QSTRING);
QINTEGER = intern_c_string ("INTEGER"); staticpro (&QINTEGER);