changeset 109678:14830418f9fc

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.
author Chong Yidong <cyd@stupidchicken.com>
date Sat, 07 Aug 2010 15:39:04 -0400
parents 73b2acbfa01b
children 0e4b6259df92
files etc/NEWS lisp/ChangeLog lisp/cus-start.el lisp/mouse.el lisp/simple.el src/ChangeLog src/insdel.c src/keyboard.c src/xselect.c
diffstat 9 files changed, 132 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/etc/NEWS	Sat Aug 07 13:26:42 2010 +0300
+++ b/etc/NEWS	Sat Aug 07 15:39:04 2010 -0400
@@ -192,7 +192,10 @@
 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.
 
--- a/lisp/ChangeLog	Sat Aug 07 13:26:42 2010 +0300
+++ b/lisp/ChangeLog	Sat Aug 07 15:39:04 2010 -0400
@@ -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.
--- a/lisp/cus-start.el	Sat Aug 07 13:26:42 2010 +0300
+++ b/lisp/cus-start.el	Sat Aug 07 15:39:04 2010 -0400
@@ -197,6 +197,11 @@
 	     (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")))
--- a/lisp/mouse.el	Sat Aug 07 13:26:42 2010 +0300
+++ b/lisp/mouse.el	Sat Aug 07 15:39:04 2010 -0400
@@ -697,9 +697,6 @@
 	(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 @@
 `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 @@
 	  (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 @@
 
 	    ;; 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 @@
 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)
--- a/lisp/simple.el	Sat Aug 07 13:26:42 2010 +0300
+++ b/lisp/simple.el	Sat Aug 07 15:39:04 2010 -0400
@@ -3666,29 +3666,27 @@
       (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 @@
   (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 @@
       (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 @@
 	(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 @@
 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 @@
 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)
--- a/src/ChangeLog	Sat Aug 07 13:26:42 2010 +0300
+++ b/src/ChangeLog	Sat Aug 07 15:39:04 2010 -0400
@@ -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):
--- a/src/insdel.c	Sat Aug 07 13:26:42 2010 +0300
+++ b/src/insdel.c	Sat Aug 07 15:39:04 2010 -0400
@@ -74,6 +74,8 @@
 
 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 @@
 	   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)
--- a/src/keyboard.c	Sat Aug 07 13:26:42 2010 +0300
+++ b/src/keyboard.c	Sat Aug 07 15:39:04 2010 -0400
@@ -361,6 +361,15 @@
    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 @@
 	    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 @@
   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 @@
 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);
--- a/src/xselect.c	Sat Aug 07 13:26:42 2010 +0300
+++ b/src/xselect.c	Sat Aug 07 15:39:04 2010 -0400
@@ -2916,7 +2916,7 @@
 \"*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);