unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#26816: mouse movement support for OS X
@ 2017-05-07 15:11 Charles A. Roelli
  2017-05-07 16:51 ` Eli Zaretskii
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Charles A. Roelli @ 2017-05-07 15:11 UTC (permalink / raw)
  To: 26816

As far as I know, mouse movement by Emacs has never worked in OS X.

The following change to frame_set_mouse_pixel_position allows you to 
move the mouse from Lisp:

diff --git a/src/nsterm.m b/src/nsterm.m
index c22c5a7..e81b7ee 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2322,14 +2322,14 @@ so some key presses (TAB) are swallowed by the 
system. */
  {
    NSTRACE ("frame_set_mouse_pixel_position");
    ns_raise_frame (f);
-#if 0
-  /* FIXME: this does not work, and what about GNUstep? */
+  /* FIXME: what about GNUstep? */
  #ifdef NS_IMPL_COCOA
    [FRAME_NS_VIEW (f) lockFocus];
-  PSsetmouse ((float)pix_x, (float)pix_y);
+  CGPoint mouse_pos = CGPointMake(f->left_pos + pix_x,
+                                  f->top_pos + pix_y);
+  CGWarpMouseCursorPosition (mouse_pos);
    [FRAME_NS_VIEW (f) unlockFocus];
  #endif
-#endif
  }

  static int

(test with (set-mouse-position (selected-frame) 0 0))

Still some things to fix:

With a portrait monitor to the left of the main monitor (the left 
monitor being in the negative x-coord. space), running the above test 
code on a single frame inside the left monitor leaves the mouse pointer 
about half a frame further down than the bottom-left corner of the 
frame.  The pointer should end up in the top-left corner.

Also, tested only in 10.6, but it should work in later versions.






^ permalink raw reply related	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-07 15:11 bug#26816: mouse movement support for OS X Charles A. Roelli
@ 2017-05-07 16:51 ` Eli Zaretskii
  2017-05-08 18:34   ` Charles A. Roelli
  2017-05-07 18:07 ` martin rudalics
  2017-05-07 20:00 ` Alan Third
  2 siblings, 1 reply; 17+ messages in thread
From: Eli Zaretskii @ 2017-05-07 16:51 UTC (permalink / raw)
  To: Charles A. Roelli; +Cc: 26816

> From: "Charles A. Roelli" <charles@aurox.ch>
> Date: Sun, 7 May 2017 17:11:52 +0200
> 
> As far as I know, mouse movement by Emacs has never worked in OS X.
> 
> The following change to frame_set_mouse_pixel_position allows you to 
> move the mouse from Lisp:

Thanks.  Can you also add a test for this feature?

I think this also warrants a NEWS entry.





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-07 15:11 bug#26816: mouse movement support for OS X Charles A. Roelli
  2017-05-07 16:51 ` Eli Zaretskii
@ 2017-05-07 18:07 ` martin rudalics
  2017-05-07 20:00 ` Alan Third
  2 siblings, 0 replies; 17+ messages in thread
From: martin rudalics @ 2017-05-07 18:07 UTC (permalink / raw)
  To: Charles A. Roelli, 26816

 > Still some things to fix:

It would be nice to have ‘set-mouse-absolute-pixel-position’ on NS too.

Thanks, martin






^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-07 15:11 bug#26816: mouse movement support for OS X Charles A. Roelli
  2017-05-07 16:51 ` Eli Zaretskii
  2017-05-07 18:07 ` martin rudalics
@ 2017-05-07 20:00 ` Alan Third
  2017-05-09 19:09   ` Charles A. Roelli
  2 siblings, 1 reply; 17+ messages in thread
From: Alan Third @ 2017-05-07 20:00 UTC (permalink / raw)
  To: Charles A. Roelli; +Cc: 26816

On Sun, May 07, 2017 at 05:11:52PM +0200, Charles A. Roelli wrote:
> As far as I know, mouse movement by Emacs has never worked in OS X.
> 
> The following change to frame_set_mouse_pixel_position allows you to move
> the mouse from Lisp:
> 
> diff --git a/src/nsterm.m b/src/nsterm.m
> index c22c5a7..e81b7ee 100644
> --- a/src/nsterm.m
> +++ b/src/nsterm.m
> @@ -2322,14 +2322,14 @@ so some key presses (TAB) are swallowed by the
> system. */
>  {
>    NSTRACE ("frame_set_mouse_pixel_position");
>    ns_raise_frame (f);
> -#if 0
> -  /* FIXME: this does not work, and what about GNUstep? */
> +  /* FIXME: what about GNUstep? */
>  #ifdef NS_IMPL_COCOA
>    [FRAME_NS_VIEW (f) lockFocus];

AFAICT this call to lockFocus isn’t required. It should tie subsequent
actions to the NSView, however CGWarpMouseCursorPosition always uses
the global screen space.

> -  PSsetmouse ((float)pix_x, (float)pix_y);
> +  CGPoint mouse_pos = CGPointMake(f->left_pos + pix_x,
> +                                  f->top_pos + pix_y);
> +  CGWarpMouseCursorPosition (mouse_pos);
>    [FRAME_NS_VIEW (f) unlockFocus];

Same with unlockFocus.

> (test with (set-mouse-position (selected-frame) 0 0))

set-mouse-position takes coordinates in characters, so (0, 0) should,
I think, be below the title and tool bars. You should be able to just
add (or subtract?) FRAME_NS_TITLEBAR_HEIGHT and FRAME_TOOLBAR_HEIGHT
to get it in the right place.

Unless I’ve misunderstood it.

> Still some things to fix:
> 
> With a portrait monitor to the left of the main monitor (the left monitor
> being in the negative x-coord. space), running the above test code on a
> single frame inside the left monitor leaves the mouse pointer about half a
> frame further down than the bottom-left corner of the frame.  The pointer
> should end up in the top-left corner.

Does this mean that the top of the portrait monitor is higher than the
top of the main monitor? It might be that NS_PARENT_WINDOW_TOP_POS
isn’t taking that extra height into account.

#define NS_PARENT_WINDOW_TOP_POS(f)                                     \
  (FRAME_PARENT_FRAME (f) != NULL                                       \
   ? ([[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.y          \
      + [[FRAME_NS_VIEW (f) window] parentWindow].frame.size.height     \
      - FRAME_NS_TITLEBAR_HEIGHT (FRAME_PARENT_FRAME (f)))              \
   : [[[FRAME_NS_VIEW (f) window] screen] frame].size.height)

That last line just takes the screen’s height, and I guess that’s
wrong. It should probably be the top left co‐ord (origin.y +
size.height)?

-- 
Alan Third





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-07 16:51 ` Eli Zaretskii
@ 2017-05-08 18:34   ` Charles A. Roelli
  2017-05-08 18:54     ` Eli Zaretskii
  0 siblings, 1 reply; 17+ messages in thread
From: Charles A. Roelli @ 2017-05-08 18:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 26816


>> Date: Sun, 7 May 2017 17:11:52 +0200
>>
>> As far as I know, mouse movement by Emacs has never worked in OS X.
>>
>> The following change to frame_set_mouse_pixel_position allows you to
>> move the mouse from Lisp:
> Thanks.  Can you also add a test for this feature?

Do you mean an automated test?  If so, where might this go in the source 
tree?

> I think this also warrants a NEWS entry.

Sure, I will add one in my next revision of the patch.





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-08 18:34   ` Charles A. Roelli
@ 2017-05-08 18:54     ` Eli Zaretskii
  0 siblings, 0 replies; 17+ messages in thread
From: Eli Zaretskii @ 2017-05-08 18:54 UTC (permalink / raw)
  To: Charles A. Roelli; +Cc: 26816

> Cc: 26816@debbugs.gnu.org
> From: "Charles A. Roelli" <charles@aurox.ch>
> Date: Mon, 8 May 2017 20:34:56 +0200
> 
> > Thanks.  Can you also add a test for this feature?
> 
> Do you mean an automated test?

Yes.

> If so, where might this go in the source tree?

Under the test/ subdirectory.

> > I think this also warrants a NEWS entry.
> 
> Sure, I will add one in my next revision of the patch.

Thanks.





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-07 20:00 ` Alan Third
@ 2017-05-09 19:09   ` Charles A. Roelli
  2017-05-09 22:44     ` Alan Third
  0 siblings, 1 reply; 17+ messages in thread
From: Charles A. Roelli @ 2017-05-09 19:09 UTC (permalink / raw)
  To: Alan Third; +Cc: 26816

On 07/05/2017 22:00, Alan Third wrote:
>> diff --git a/src/nsterm.m b/src/nsterm.m
>> index c22c5a7..e81b7ee 100644
>> --- a/src/nsterm.m
>> +++ b/src/nsterm.m
>> @@ -2322,14 +2322,14 @@ so some key presses (TAB) are swallowed by the
>> system. */
>>   {
>>     NSTRACE ("frame_set_mouse_pixel_position");
>>     ns_raise_frame (f);
>> -#if 0
>> -  /* FIXME: this does not work, and what about GNUstep? */
>> +  /* FIXME: what about GNUstep? */
>>   #ifdef NS_IMPL_COCOA
>>     [FRAME_NS_VIEW (f) lockFocus];
> AFAICT this call to lockFocus isn’t required. It should tie subsequent
> actions to the NSView, however CGWarpMouseCursorPosition always uses
> the global screen space.
>
>> -  PSsetmouse ((float)pix_x, (float)pix_y);
>> +  CGPoint mouse_pos = CGPointMake(f->left_pos + pix_x,
>> +                                  f->top_pos + pix_y);
>> +  CGWarpMouseCursorPosition (mouse_pos);
>>     [FRAME_NS_VIEW (f) unlockFocus];
> Same with unlockFocus.
>
>> (test with (set-mouse-position (selected-frame) 0 0))
> set-mouse-position takes coordinates in characters, so (0, 0) should,
> I think, be below the title and tool bars. You should be able to just
> add (or subtract?) FRAME_NS_TITLEBAR_HEIGHT and FRAME_TOOLBAR_HEIGHT
> to get it in the right place.
>
> Unless I’ve misunderstood it.

Right, right and right: I got rid of the [un]lockFocus calls, and added 
in the adjustments for the toolbar height and titlebar height.  After 
this, moving the mouse
to position x, y with:

(set-mouse-position (selected-frame) x y)

results in a call to (mouse-position) returning (<frame ...> x . y) -- 
except for the specific case I mentioned (see below).  I'm still working 
on the patch, and will send a new one in the next few days.

>> Still some things to fix:
>>
>> With a portrait monitor to the left of the main monitor (the left monitor
>> being in the negative x-coord. space), running the above test code on a
>> single frame inside the left monitor leaves the mouse pointer about half a
>> frame further down than the bottom-left corner of the frame.  The pointer
>> should end up in the top-left corner.
> Does this mean that the top of the portrait monitor is higher than the
> top of the main monitor?

Yes.  For reference, this is what (display-monitor-attributes-list) 
gives in Emacs 25.2:

(((name . "Color LCD")
   (geometry 0 0 1280 800)
   (workarea 0 22 1280 714)
   (mm-size 290 180)
   (frames #<frame emacs-devel 0x105058460> #<frame nsterm.h 0x1179a1500>)
   (source . "NS"))
  ((name . "DELL 2007WFP")
   (geometry -1050 -880 1050 1680)
   (workarea -1050 -880 1050 1680)
   (mm-size 430 270)
   (frames #<frame  *Minibuf-1* 0x1189a4198>)
   (source . "NS")))

With the frame in the taller monitor as mentioned, after calling 
(set-mouse-position (selected-frame) 0 0), (mouse-position) returns 
(#<frame *scratch* 0x1058883a8> 0 . 55), which happens to be about 800 
pixels from the place where it should end up (i.e. it sounds like the 
calculation is off the mark by the height of the primary monitor).

> It might be that NS_PARENT_WINDOW_TOP_POS
> isn’t taking that extra height into account.
>
> #define NS_PARENT_WINDOW_TOP_POS(f)                                     \
>    (FRAME_PARENT_FRAME (f) != NULL                                       \
>     ? ([[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.y          \
>        + [[FRAME_NS_VIEW (f) window] parentWindow].frame.size.height     \
>        - FRAME_NS_TITLEBAR_HEIGHT (FRAME_PARENT_FRAME (f)))              \
>     : [[[FRAME_NS_VIEW (f) window] screen] frame].size.height)
>
> That last line just takes the screen’s height, and I guess that’s
> wrong. It should probably be the top left co‐ord (origin.y +
> size.height)?
>

I ran NS_PARENT_WINDOW_TOP_POS(f) on the frame in the taller monitor as 
described, and it always returned 1680.  I tried adding 
([[[FRAME_NS_VIEW (f) window] screen] frame].origin.y) to the last line 
in the macro you mentioned, but this must always be returning zero, 
because it made no difference and the macro still returned 1680.






^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-09 19:09   ` Charles A. Roelli
@ 2017-05-09 22:44     ` Alan Third
  2017-05-11 18:06       ` Charles A. Roelli
  0 siblings, 1 reply; 17+ messages in thread
From: Alan Third @ 2017-05-09 22:44 UTC (permalink / raw)
  To: Charles A. Roelli; +Cc: 26816

On Tue, May 09, 2017 at 09:09:29PM +0200, Charles A. Roelli wrote:
> With the frame in the taller monitor as mentioned, after calling
> (set-mouse-position (selected-frame) 0 0), (mouse-position) returns (#<frame
> *scratch* 0x1058883a8> 0 . 55), which happens to be about 800 pixels from
> the place where it should end up (i.e. it sounds like the calculation is off
> the mark by the height of the primary monitor).
> 
> > It might be that NS_PARENT_WINDOW_TOP_POS
> > isn’t taking that extra height into account.
> > 
> > #define NS_PARENT_WINDOW_TOP_POS(f)                                     \
> >    (FRAME_PARENT_FRAME (f) != NULL                                       \
> >     ? ([[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.y          \
> >        + [[FRAME_NS_VIEW (f) window] parentWindow].frame.size.height     \
> >        - FRAME_NS_TITLEBAR_HEIGHT (FRAME_PARENT_FRAME (f)))              \
> >     : [[[FRAME_NS_VIEW (f) window] screen] frame].size.height)
> > 
> > That last line just takes the screen’s height, and I guess that’s
> > wrong. It should probably be the top left co‐ord (origin.y +
> > size.height)?
> > 
> 
> I ran NS_PARENT_WINDOW_TOP_POS(f) on the frame in the taller monitor as
> described, and it always returned 1680.  I tried adding ([[[FRAME_NS_VIEW
> (f) window] screen] frame].origin.y) to the last line in the macro you
> mentioned, but this must always be returning zero, because it made no
> difference and the macro still returned 1680.

Hmm, this is harder than I first thought.

Presumably (frame-position) returns nonsensical values on your
portrait monitor, and (set-frame-position nil 0 0) also plants the
frame in the wrong place (ie. not the top left)?

Can you try changing that last line of NS_PARENT_WINDOW_TOP_POS to
return

    NSScreen.screens[0].frame.size.height

I *think* that should set the top left of the primary screen as (0,
0). If that works for this, there may be other places where we’re
using window.screen that we’ll have to change to use the primary
screen, but I’m not really sure.

I wonder if it’ll break when ‘screens have separate spaces’ is turned
on...? :/

Almost anything seems to work here, but I’m not using multiple
monitors.

-- 
Alan Third





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-09 22:44     ` Alan Third
@ 2017-05-11 18:06       ` Charles A. Roelli
  2017-05-11 21:43         ` Alan Third
  0 siblings, 1 reply; 17+ messages in thread
From: Charles A. Roelli @ 2017-05-11 18:06 UTC (permalink / raw)
  To: Alan Third; +Cc: 26816

>> I ran NS_PARENT_WINDOW_TOP_POS(f) on the frame in the taller monitor as
>> described, and it always returned 1680.  I tried adding ([[[FRAME_NS_VIEW
>> (f) window] screen] frame].origin.y) to the last line in the macro you
>> mentioned, but this must always be returning zero, because it made no
>> difference and the macro still returned 1680.
> Hmm, this is harder than I first thought.
>
> Presumably (frame-position) returns nonsensical values on your
> portrait monitor, and (set-frame-position nil 0 0) also plants the
> frame in the wrong place (ie. not the top left)?

(set-frame-position nil 0 0) places the frame in the top-left corner of 
the primary monitor for me in Emacs 25.2.  (frame-position) with the 
frame in the top-left corner of the secondary monitor reports (-1050 . 
-880).

I'm not sure: is this expected behavior?

> Can you try changing that last line of NS_PARENT_WINDOW_TOP_POS to
> return
>
>      NSScreen.screens[0].frame.size.height
>
> I *think* that should set the top left of the primary screen as (0,
> 0). If that works for this, there may be other places where we’re
> using window.screen that we’ll have to change to use the primary
> screen, but I’m not really sure.
>
> I wonder if it’ll break when ‘screens have separate spaces’ is turned
> on...? :/
>
> Almost anything seems to work here, but I’m not using multiple
> monitors.
>

I made the line say [[[NSScreen screens] objectAtIndex: 0] 
frame].size.height (equivalent to what you wrote) and the mouse can now 
be set to a position in the frame as expected.  Thanks for your help 
with this.

This now reminds me of a related problem, though: with Emacs 25.2 (or in 
Emacs 26, with the above change applied to NS_PARENT_WINDOW_TOP_POS(f)), 
tooltips originating from an area with a help-echo property (like "Lisp 
Interaction" in the mode line in emacs -Q) in a frame on the secondary 
monitor actually show up in the primary monitor instead -- as if the 
tooltip frame is constrained to having a positive x-coordinate only.  I 
haven't found where it happens, but I guess the cause is similar.





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-11 18:06       ` Charles A. Roelli
@ 2017-05-11 21:43         ` Alan Third
  2017-05-14 13:29           ` Charles A. Roelli
  0 siblings, 1 reply; 17+ messages in thread
From: Alan Third @ 2017-05-11 21:43 UTC (permalink / raw)
  To: Charles A. Roelli; +Cc: 26816

On Thu, May 11, 2017 at 08:06:13PM +0200, Charles A. Roelli wrote:
> > Presumably (frame-position) returns nonsensical values on your
> > portrait monitor, and (set-frame-position nil 0 0) also plants the
> > frame in the wrong place (ie. not the top left)?
> 
> (set-frame-position nil 0 0) places the frame in the top-left corner of the
> primary monitor for me in Emacs 25.2.  (frame-position) with the frame in
> the top-left corner of the secondary monitor reports (-1050 . -880).
> 
> I'm not sure: is this expected behavior?

It’s what I’d expect with the below modification to
NS_PARENT_WINDOW_TOP_POS, so if Emacs 25 does that too then I’m happy.

I was thinking that without the modification, Emacs 26 would do
strange things, just like it did with positioning the mouse pointer.

> I made the line say [[[NSScreen screens] objectAtIndex: 0]
> frame].size.height (equivalent to what you wrote) and the mouse can
> now be set to a position in the frame as expected. Thanks for your
> help with this.

Thank you for working on it. Besides, I introduced this particular
bug.

> This now reminds me of a related problem, though: with Emacs 25.2 (or in
> Emacs 26, with the above change applied to NS_PARENT_WINDOW_TOP_POS(f)),
> tooltips originating from an area with a help-echo property (like "Lisp
> Interaction" in the mode line in emacs -Q) in a frame on the secondary
> monitor actually show up in the primary monitor instead -- as if the tooltip
> frame is constrained to having a positive x-coordinate only.  I haven't
> found where it happens, but I guess the cause is similar.

Look at compute_tip_xy in nsfns.m. It moves tooltips into the positive
screen space. I’ve not managed to get to grips with this code yet.

I think what we want is for it to try to keep the tooltip on one
screen, so it’s not spanning two monitors, but allow it to go into
negative space.

Perhaps this should be a separate bug report.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-11 21:43         ` Alan Third
@ 2017-05-14 13:29           ` Charles A. Roelli
  2017-05-14 13:59             ` Alan Third
  0 siblings, 1 reply; 17+ messages in thread
From: Charles A. Roelli @ 2017-05-14 13:29 UTC (permalink / raw)
  To: Alan Third; +Cc: 26816

[-- Attachment #1: Type: text/plain, Size: 1718 bytes --]

Attached is a patch now working with multiple monitors.  I also added 
`ns-set-mouse-absolute-pixel-position', a test and a NEWS entry.  The 
test works interactively, but it requires a frame to run and I'm not 
sure whether tests run with them by default.

The code for handling the y-coord in 
`ns-set-mouse-absolute-pixel-position' is from 
`ns-display-monitor-attributes-list' (in the calculation of the screen 
geometry).  I also made (set-mouse-absolute-pixel-position 0 0) put the 
mouse in the top-left corner of the current screen.

I tried out both `set-mouse-position' and 
`set-mouse-absolute-pixel-position' on setups with the secondary monitor 
on the left, right, top and bottom, and they seem to work right.

I also got rid of the call to `ns_raise_frame' in 
`frame_set_mouse_pixel_position', which is unnecessary.

>> This now reminds me of a related problem, though: with Emacs 25.2 (or in
>> Emacs 26, with the above change applied to NS_PARENT_WINDOW_TOP_POS(f)),
>> tooltips originating from an area with a help-echo property (like "Lisp
>> Interaction" in the mode line in emacs -Q) in a frame on the secondary
>> monitor actually show up in the primary monitor instead -- as if the tooltip
>> frame is constrained to having a positive x-coordinate only.  I haven't
>> found where it happens, but I guess the cause is similar.
> Look at compute_tip_xy in nsfns.m. It moves tooltips into the positive
> screen space. I’ve not managed to get to grips with this code yet.
>
> I think what we want is for it to try to keep the tooltip on one
> screen, so it’s not spanning two monitors, but allow it to go into
> negative space.
>
> Perhaps this should be a separate bug report.

Done (#26905).

[-- Attachment #2: 0001-mouse-movement-macos.patch --]
[-- Type: text/x-patch, Size: 5177 bytes --]

diff --git a/etc/NEWS b/etc/NEWS
index 6667a44..25f0f18 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1292,6 +1292,9 @@ This is in contrast to the default action on POSIX Systems, where it
 causes the receiving process to terminate with a core dump if no
 debugger has been attached to it.
 
+** `set-mouse-position' and `set-mouse-absolute-pixel-position' work
+on macOS.
+
 \f
 ----------------------------------------------------------------------
 This file is part of GNU Emacs.
diff --git a/lisp/frame.el b/lisp/frame.el
index 05db8cf..02871e0 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -1465,6 +1465,7 @@ mouse-absolute-pixel-position
      (t
       (cons 0 0)))))
 
+(declare-function ns-set-mouse-absolute-pixel-position "nsfns.m" (x y))
 (declare-function w32-set-mouse-absolute-pixel-position "w32fns.c" (x y))
 (declare-function x-set-mouse-absolute-pixel-position "xfns.c" (x y))
 
@@ -1474,6 +1475,8 @@ set-mouse-absolute-pixel-position
 position (0, 0) of the selected frame's terminal."
   (let ((frame-type (framep-on-display)))
     (cond
+     ((eq frame-type 'ns)
+      (ns-set-mouse-absolute-pixel-position x y))
      ((eq frame-type 'x)
       (x-set-mouse-absolute-pixel-position x y))
      ((eq frame-type 'w32)
diff --git a/src/nsfns.m b/src/nsfns.m
index cbe0ffb..e916f6a 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -3053,6 +3053,44 @@ value is a list of the form (LEFT, TOP, RIGHT, BOTTOM).  All values are
 				 : Qnative_edges));
 }
 
+DEFUN ("ns-set-mouse-absolute-pixel-position",
+       Fns_set_mouse_absolute_pixel_position,
+       Sns_set_mouse_absolute_pixel_position, 2, 2, 0,
+       doc: /* Move mouse pointer to absolute pixel position (X, Y).
+The coordinates X and Y are interpreted in pixels relative to a position
+\(0, 0) of the selected frame's display.  */)
+       (Lisp_Object x, Lisp_Object y)
+{
+  struct frame *f = SELECTED_FRAME ();
+  EmacsView *view = FRAME_NS_VIEW (f);
+  NSScreen *screen = [[view window] screen];
+  NSRect screen_frame = [screen frame];
+  int mouse_x, mouse_y;
+
+  NSScreen *primary_screen = [[NSScreen screens] objectAtIndex:0];
+  NSRect primary_screen_frame = [primary_screen frame];
+  CGFloat primary_screen_height = primary_screen_frame.size.height;
+
+  if (FRAME_INITIAL_P (f) || !FRAME_NS_P (f))
+    return Qnil;
+
+  CHECK_TYPE_RANGED_INTEGER (int, x);
+  CHECK_TYPE_RANGED_INTEGER (int, y);
+
+  mouse_x = screen_frame.origin.x + XINT (x);
+
+  if (screen == primary_screen)
+    mouse_y = screen_frame.origin.y + XINT (y);
+  else
+    mouse_y = (primary_screen_height - screen_frame.size.height
+	       - screen_frame.origin.y) + XINT (y);
+
+  CGPoint mouse_pos = CGPointMake(mouse_x, mouse_y);
+  CGWarpMouseCursorPosition (mouse_pos);
+
+  return Qnil;
+}
+
 /* ==========================================================================
 
     Class implementations
@@ -3241,6 +3279,7 @@ - (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename
   defsubr (&Sns_frame_edges);
   defsubr (&Sns_frame_list_z_order);
   defsubr (&Sns_frame_restack);
+  defsubr (&Sns_set_mouse_absolute_pixel_position);
   defsubr (&Sx_display_mm_width);
   defsubr (&Sx_display_mm_height);
   defsubr (&Sx_display_screens);
diff --git a/src/nsterm.h b/src/nsterm.h
index 9285178..ac339bf 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -1087,7 +1087,7 @@ struct x_output
    ? ([[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.y          \
       + [[FRAME_NS_VIEW (f) window] parentWindow].frame.size.height     \
       - FRAME_NS_TITLEBAR_HEIGHT (FRAME_PARENT_FRAME (f)))              \
-   : [[[FRAME_NS_VIEW (f) window] screen] frame].size.height)
+   : [[[NSScreen screens] objectAtIndex: 0] frame].size.height)
 
 #define FRAME_NS_FONT_TABLE(f) (FRAME_DISPLAY_INFO (f)->font_table)
 
diff --git a/src/nsterm.m b/src/nsterm.m
index c22c5a7..a7ab73b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2321,14 +2321,14 @@ so some key presses (TAB) are swallowed by the system. */
    -------------------------------------------------------------------------- */
 {
   NSTRACE ("frame_set_mouse_pixel_position");
-  ns_raise_frame (f);
-#if 0
-  /* FIXME: this does not work, and what about GNUstep? */
+
+  /* FIXME: what about GNUstep? */
 #ifdef NS_IMPL_COCOA
-  [FRAME_NS_VIEW (f) lockFocus];
-  PSsetmouse ((float)pix_x, (float)pix_y);
-  [FRAME_NS_VIEW (f) unlockFocus];
-#endif
+  CGPoint mouse_pos =
+    CGPointMake(f->left_pos + pix_x,
+                f->top_pos + pix_y +
+                FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
+  CGWarpMouseCursorPosition (mouse_pos);
 #endif
 }
 
diff --git a/test/lisp/mouse-tests.el b/test/lisp/mouse-tests.el
index fffaa2f..c743df4 100644
--- a/test/lisp/mouse-tests.el
+++ b/test/lisp/mouse-tests.el
@@ -47,4 +47,12 @@
     (should-not (mouse--down-1-maybe-follows-link))
     (should (equal unread-command-events '((mouse-2 nil 1))))))
 
+(ert-deftest bug26816-mouse-frame-movement ()
+  "Mouse moves relative to frame."
+  (let ((frame (selected-frame)))
+    (set-mouse-position frame 0 0)
+    (should (equal (mouse-position)
+		   (cons frame (cons 0 0))))))
+
+
 ;;; mouse-tests.el ends here

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-14 13:29           ` Charles A. Roelli
@ 2017-05-14 13:59             ` Alan Third
  2017-05-14 14:37               ` Eli Zaretskii
  0 siblings, 1 reply; 17+ messages in thread
From: Alan Third @ 2017-05-14 13:59 UTC (permalink / raw)
  To: Charles A. Roelli; +Cc: 26816

On Sun, May 14, 2017 at 03:29:57PM +0200, Charles A. Roelli wrote:
> Attached is a patch now working with multiple monitors.  I also added
> `ns-set-mouse-absolute-pixel-position', a test and a NEWS entry.  The test
> works interactively, but it requires a frame to run and I'm not sure whether
> tests run with them by default.

Usually you run tests with ’make check’, and there’s no frame
available. I’ve just checked and it does throw up an error for that
test. I’m not sure how that should be handled.

> The code for handling the y-coord in `ns-set-mouse-absolute-pixel-position'
> is from `ns-display-monitor-attributes-list' (in the calculation of the
> screen geometry).  I also made (set-mouse-absolute-pixel-position 0 0) put
> the mouse in the top-left corner of the current screen.
> 
> I tried out both `set-mouse-position' and
> `set-mouse-absolute-pixel-position' on setups with the secondary monitor on
> the left, right, top and bottom, and they seem to work right.
> 
> I also got rid of the call to `ns_raise_frame' in
> `frame_set_mouse_pixel_position', which is unnecessary.

It all looks good to me. Leave this here a few days and if nobody
complains push it to master. I’m not sure what to do about the test.
If nobody offers a suggestion here, you could ask in emacs-devel.

Thanks for working on this.
-- 
Alan Third





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-14 13:59             ` Alan Third
@ 2017-05-14 14:37               ` Eli Zaretskii
  2017-05-15 18:23                 ` Charles A. Roelli
  0 siblings, 1 reply; 17+ messages in thread
From: Eli Zaretskii @ 2017-05-14 14:37 UTC (permalink / raw)
  To: Alan Third; +Cc: 26816, charles

> Date: Sun, 14 May 2017 14:59:10 +0100
> From: Alan Third <alan@idiocy.org>
> Cc: 26816@debbugs.gnu.org, martin rudalics <rudalics@gmx.at>,
> 	Eli Zaretskii <eliz@gnu.org>
> 
> On Sun, May 14, 2017 at 03:29:57PM +0200, Charles A. Roelli wrote:
> > Attached is a patch now working with multiple monitors.  I also added
> > `ns-set-mouse-absolute-pixel-position', a test and a NEWS entry.  The test
> > works interactively, but it requires a frame to run and I'm not sure whether
> > tests run with them by default.
> 
> Usually you run tests with ’make check’, and there’s no frame
> available.

There's always a frame, even in batch sessions.  Observe:

  emacs -batch --eval "(message \"%s\" (selected-frame))"
    => #<frame F1 017b9d08>

It's just that it's not a frame which this feature could use.

> I’ve just checked and it does throw up an error for that
> test. I’m not sure how that should be handled.

You could explicitly test for non-interactive sessions, and skip the
test, or display a message that this test can only be run
interactively.  Would that be good enough?





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-14 14:37               ` Eli Zaretskii
@ 2017-05-15 18:23                 ` Charles A. Roelli
  2017-05-16 22:53                   ` Alan Third
  0 siblings, 1 reply; 17+ messages in thread
From: Charles A. Roelli @ 2017-05-15 18:23 UTC (permalink / raw)
  To: Eli Zaretskii, Alan Third; +Cc: 26816

[-- Attachment #1: Type: text/plain, Size: 1338 bytes --]

I've added a `skip-unless' form to the beginning of the test:


(skip-unless (display-graphic-p))


Seems to take care of the issue.  Patch is attached, with a commit message.


On 14/05/2017 16:37, Eli Zaretskii wrote:
>> Date: Sun, 14 May 2017 14:59:10 +0100
>> From: Alan Third <alan@idiocy.org>
>> Cc: 26816@debbugs.gnu.org, martin rudalics <rudalics@gmx.at>,
>> 	Eli Zaretskii <eliz@gnu.org>
>>
>> On Sun, May 14, 2017 at 03:29:57PM +0200, Charles A. Roelli wrote:
>>> Attached is a patch now working with multiple monitors.  I also added
>>> `ns-set-mouse-absolute-pixel-position', a test and a NEWS entry.  The test
>>> works interactively, but it requires a frame to run and I'm not sure whether
>>> tests run with them by default.
>> Usually you run tests with ’make check’, and there’s no frame
>> available.
> There's always a frame, even in batch sessions.  Observe:
>
>    emacs -batch --eval "(message \"%s\" (selected-frame))"
>      => #<frame F1 017b9d08>
>
> It's just that it's not a frame which this feature could use.
>
>> I’ve just checked and it does throw up an error for that
>> test. I’m not sure how that should be handled.
> You could explicitly test for non-interactive sessions, and skip the
> test, or display a message that this test can only be run
> interactively.  Would that be good enough?


[-- Attachment #2: 0001-Fix-macOS-mouse-movement.patch --]
[-- Type: text/x-patch, Size: 6311 bytes --]

From 66c9d13f9709d11dd06cf640a5873d39a8fb952c Mon Sep 17 00:00:00 2001
From: Charles A. Roelli <charles@aurox.ch>
Date: Mon, 15 May 2017 20:18:21 +0200
Subject: [PATCH] Fix macOS mouse movement

* lisp/frame.el (ns-set-mouse-absolute-pixel-position): New
function (Lisp).
(set-mouse-absolute-pixel-position): Change it to call
`ns-set-mouse-absolute-pixel-position' on macOS.
* src/nsfns.m (Fns_set_mouse_absolute_pixel_position): New
function.
* src/nsterm.h (NS_PARENT_WINDOW_TOP_POS): Use the primary
screen's height as a base for calculating global coordinates.
* src/nsterm.m (frame_set_mouse_pixel_position): Fix it in macOS.
* test/lisp/mouse-tests.el (bug26816-mouse-frame-movement): Test
movement of mouse relative to frame.
---
 etc/NEWS                 |    3 +++
 lisp/frame.el            |    3 +++
 src/nsfns.m              |   39 +++++++++++++++++++++++++++++++++++++++
 src/nsterm.h             |    2 +-
 src/nsterm.m             |   14 +++++++-------
 test/lisp/mouse-tests.el |    9 +++++++++
 6 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 6667a44..25f0f18 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1292,6 +1292,9 @@ This is in contrast to the default action on POSIX Systems, where it
 causes the receiving process to terminate with a core dump if no
 debugger has been attached to it.
 
+** `set-mouse-position' and `set-mouse-absolute-pixel-position' work
+on macOS.
+
 \f
 ----------------------------------------------------------------------
 This file is part of GNU Emacs.
diff --git a/lisp/frame.el b/lisp/frame.el
index 05db8cf..02871e0 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -1465,6 +1465,7 @@ mouse-absolute-pixel-position
      (t
       (cons 0 0)))))
 
+(declare-function ns-set-mouse-absolute-pixel-position "nsfns.m" (x y))
 (declare-function w32-set-mouse-absolute-pixel-position "w32fns.c" (x y))
 (declare-function x-set-mouse-absolute-pixel-position "xfns.c" (x y))
 
@@ -1474,6 +1475,8 @@ set-mouse-absolute-pixel-position
 position (0, 0) of the selected frame's terminal."
   (let ((frame-type (framep-on-display)))
     (cond
+     ((eq frame-type 'ns)
+      (ns-set-mouse-absolute-pixel-position x y))
      ((eq frame-type 'x)
       (x-set-mouse-absolute-pixel-position x y))
      ((eq frame-type 'w32)
diff --git a/src/nsfns.m b/src/nsfns.m
index cbe0ffb..e916f6a 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -3053,6 +3053,44 @@ value is a list of the form (LEFT, TOP, RIGHT, BOTTOM).  All values are
 				 : Qnative_edges));
 }
 
+DEFUN ("ns-set-mouse-absolute-pixel-position",
+       Fns_set_mouse_absolute_pixel_position,
+       Sns_set_mouse_absolute_pixel_position, 2, 2, 0,
+       doc: /* Move mouse pointer to absolute pixel position (X, Y).
+The coordinates X and Y are interpreted in pixels relative to a position
+\(0, 0) of the selected frame's display.  */)
+       (Lisp_Object x, Lisp_Object y)
+{
+  struct frame *f = SELECTED_FRAME ();
+  EmacsView *view = FRAME_NS_VIEW (f);
+  NSScreen *screen = [[view window] screen];
+  NSRect screen_frame = [screen frame];
+  int mouse_x, mouse_y;
+
+  NSScreen *primary_screen = [[NSScreen screens] objectAtIndex:0];
+  NSRect primary_screen_frame = [primary_screen frame];
+  CGFloat primary_screen_height = primary_screen_frame.size.height;
+
+  if (FRAME_INITIAL_P (f) || !FRAME_NS_P (f))
+    return Qnil;
+
+  CHECK_TYPE_RANGED_INTEGER (int, x);
+  CHECK_TYPE_RANGED_INTEGER (int, y);
+
+  mouse_x = screen_frame.origin.x + XINT (x);
+
+  if (screen == primary_screen)
+    mouse_y = screen_frame.origin.y + XINT (y);
+  else
+    mouse_y = (primary_screen_height - screen_frame.size.height
+              - screen_frame.origin.y) + XINT (y);
+
+  CGPoint mouse_pos = CGPointMake(mouse_x, mouse_y);
+  CGWarpMouseCursorPosition (mouse_pos);
+
+  return Qnil;
+}
+
 /* ==========================================================================
 
     Class implementations
@@ -3241,6 +3279,7 @@ - (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename
   defsubr (&Sns_frame_edges);
   defsubr (&Sns_frame_list_z_order);
   defsubr (&Sns_frame_restack);
+  defsubr (&Sns_set_mouse_absolute_pixel_position);
   defsubr (&Sx_display_mm_width);
   defsubr (&Sx_display_mm_height);
   defsubr (&Sx_display_screens);
diff --git a/src/nsterm.h b/src/nsterm.h
index 9285178..ac339bf 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -1087,7 +1087,7 @@ struct x_output
    ? ([[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.y          \
       + [[FRAME_NS_VIEW (f) window] parentWindow].frame.size.height     \
       - FRAME_NS_TITLEBAR_HEIGHT (FRAME_PARENT_FRAME (f)))              \
-   : [[[FRAME_NS_VIEW (f) window] screen] frame].size.height)
+   : [[[NSScreen screens] objectAtIndex: 0] frame].size.height)
 
 #define FRAME_NS_FONT_TABLE(f) (FRAME_DISPLAY_INFO (f)->font_table)
 
diff --git a/src/nsterm.m b/src/nsterm.m
index c22c5a7..a7ab73b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2321,14 +2321,14 @@ so some key presses (TAB) are swallowed by the system. */
    -------------------------------------------------------------------------- */
 {
   NSTRACE ("frame_set_mouse_pixel_position");
-  ns_raise_frame (f);
-#if 0
-  /* FIXME: this does not work, and what about GNUstep? */
+
+  /* FIXME: what about GNUstep? */
 #ifdef NS_IMPL_COCOA
-  [FRAME_NS_VIEW (f) lockFocus];
-  PSsetmouse ((float)pix_x, (float)pix_y);
-  [FRAME_NS_VIEW (f) unlockFocus];
-#endif
+  CGPoint mouse_pos =
+    CGPointMake(f->left_pos + pix_x,
+                f->top_pos + pix_y +
+                FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
+  CGWarpMouseCursorPosition (mouse_pos);
 #endif
 }
 
diff --git a/test/lisp/mouse-tests.el b/test/lisp/mouse-tests.el
index fffaa2f..70e932b 100644
--- a/test/lisp/mouse-tests.el
+++ b/test/lisp/mouse-tests.el
@@ -47,5 +47,13 @@
     (should-not (mouse--down-1-maybe-follows-link))
     (should (equal unread-command-events '((mouse-2 nil 1))))))
 
+(ert-deftest bug26816-mouse-frame-movement ()
+  "Mouse moves relative to frame."
+  (skip-unless (display-graphic-p))
+  (let ((frame (selected-frame)))
+    (set-mouse-position frame 0 0)
+    (should (equal (mouse-position)
+                   (cons frame (cons 0 0))))))
+
+
 ;;; mouse-tests.el ends here
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-15 18:23                 ` Charles A. Roelli
@ 2017-05-16 22:53                   ` Alan Third
  2017-05-17  8:36                     ` Andreas Schwab
  0 siblings, 1 reply; 17+ messages in thread
From: Alan Third @ 2017-05-16 22:53 UTC (permalink / raw)
  To: Charles A. Roelli; +Cc: 26816

On Mon, May 15, 2017 at 08:23:27PM +0200, Charles A. Roelli wrote:
> Patch is attached, with a commit message.

For some reason I can’t apply this patch. It looks fine, and I can’t
see what the problem is at all.

Do you have commit access to the repository? If so then I don’t
suppose it matters if I can’t apply it locally, but if not then either
I need to fix this or someone else needs to push it for you.

Here’s the error from magit, in case it means something to someone:

128 git … am --3way -- /Users/alan/0001-Fix-macOS-mouse-movement.patch
Applying: Fix macOS mouse movement
Using index info to reconstruct a base tree...
M	src/nsfns.m
M	src/nsterm.m
error: patch failed: test/lisp/mouse-tests.el:47
error: test/lisp/mouse-tests.el: patch does not apply
error: Did you hand edit your patch?
It does not apply to blobs recorded in its index.
Patch failed at 0001 Fix macOS mouse movement
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

-- 
Alan Third





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-16 22:53                   ` Alan Third
@ 2017-05-17  8:36                     ` Andreas Schwab
  2017-05-18 19:43                       ` Charles A. Roelli
  0 siblings, 1 reply; 17+ messages in thread
From: Andreas Schwab @ 2017-05-17  8:36 UTC (permalink / raw)
  To: Alan Third; +Cc: 26816, Charles A. Roelli

On Mai 16 2017, Alan Third <alan@idiocy.org> wrote:

> On Mon, May 15, 2017 at 08:23:27PM +0200, Charles A. Roelli wrote:
>> Patch is attached, with a commit message.
>
> For some reason I can’t apply this patch. It looks fine, and I can’t
> see what the problem is at all.

The patch is broken, the hunk for test/lisp/mouse-tests.el has the wrong
line count:

@@ -47,5 +47,13 @@
     (should-not (mouse--down-1-maybe-follows-link))
     (should (equal unread-command-events '((mouse-2 nil 1))))))
 
+(ert-deftest bug26816-mouse-frame-movement ()
+  "Mouse moves relative to frame."
+  (skip-unless (display-graphic-p))
+  (let ((frame (selected-frame)))
+    (set-mouse-position frame 0 0)
+    (should (equal (mouse-position)
+                   (cons frame (cons 0 0))))))
+
+
 ;;; mouse-tests.el ends here
-- 

Note that the last line of the hunk should not be part of it.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."





^ permalink raw reply	[flat|nested] 17+ messages in thread

* bug#26816: mouse movement support for OS X
  2017-05-17  8:36                     ` Andreas Schwab
@ 2017-05-18 19:43                       ` Charles A. Roelli
  0 siblings, 0 replies; 17+ messages in thread
From: Charles A. Roelli @ 2017-05-18 19:43 UTC (permalink / raw)
  To: Andreas Schwab, Alan Third; +Cc: 26816

[-- Attachment #1: Type: text/plain, Size: 1105 bytes --]

Sorry for the trouble -- I had called M-x untabify on two lines of the 
patch (bad idea, I think) and I must have messed up the line count at 
that point too.  Second attempt attached.


Cheers,

Charles


On 17/05/2017 10:36, Andreas Schwab wrote:
> On Mai 16 2017, Alan Third <alan@idiocy.org> wrote:
>
>> On Mon, May 15, 2017 at 08:23:27PM +0200, Charles A. Roelli wrote:
>>> Patch is attached, with a commit message.
>> For some reason I can’t apply this patch. It looks fine, and I can’t
>> see what the problem is at all.
> The patch is broken, the hunk for test/lisp/mouse-tests.el has the wrong
> line count:
>
> @@ -47,5 +47,13 @@
>       (should-not (mouse--down-1-maybe-follows-link))
>       (should (equal unread-command-events '((mouse-2 nil 1))))))
>   
> +(ert-deftest bug26816-mouse-frame-movement ()
> +  "Mouse moves relative to frame."
> +  (skip-unless (display-graphic-p))
> +  (let ((frame (selected-frame)))
> +    (set-mouse-position frame 0 0)
> +    (should (equal (mouse-position)
> +                   (cons frame (cons 0 0))))))
> +
> +
>   ;;; mouse-tests.el ends here


[-- Attachment #2: 0001-Fix-macOS-mouse-movement.patch --]
[-- Type: text/x-patch, Size: 6312 bytes --]

From c052ea0a343beefe35c6d7343740724e062a5989 Mon Sep 17 00:00:00 2001
From: Charles A. Roelli <charles@aurox.ch>
Date: Thu, 18 May 2017 21:31:46 +0200
Subject: [PATCH] Fix macOS mouse movement

* lisp/frame.el (ns-set-mouse-absolute-pixel-position): New
function (Lisp).
(set-mouse-absolute-pixel-position): Change it to call
`ns-set-mouse-absolute-pixel-position' on macOS.
* src/nsfns.m (Fns_set_mouse_absolute_pixel_position): New
function.
* src/nsterm.h (NS_PARENT_WINDOW_TOP_POS): Use the primary
screen's height as a base for calculating global coordinates.
* src/nsterm.m (frame_set_mouse_pixel_position): Fix it in macOS.
* test/lisp/mouse-tests.el (bug26816-mouse-frame-movement): Test
movement of mouse relative to frame.
---
 etc/NEWS                 |    3 +++
 lisp/frame.el            |    3 +++
 src/nsfns.m              |   39 +++++++++++++++++++++++++++++++++++++++
 src/nsterm.h             |    2 +-
 src/nsterm.m             |   14 +++++++-------
 test/lisp/mouse-tests.el |    9 +++++++++
 6 files changed, 62 insertions(+), 8 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 6851dc9..1faa1db 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1294,6 +1294,9 @@ This is in contrast to the default action on POSIX Systems, where it
 causes the receiving process to terminate with a core dump if no
 debugger has been attached to it.
 
+** `set-mouse-position' and `set-mouse-absolute-pixel-position' work
+on macOS.
+
 \f
 ----------------------------------------------------------------------
 This file is part of GNU Emacs.
diff --git a/lisp/frame.el b/lisp/frame.el
index 05db8cf..02871e0 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -1465,6 +1465,7 @@ mouse-absolute-pixel-position
      (t
       (cons 0 0)))))
 
+(declare-function ns-set-mouse-absolute-pixel-position "nsfns.m" (x y))
 (declare-function w32-set-mouse-absolute-pixel-position "w32fns.c" (x y))
 (declare-function x-set-mouse-absolute-pixel-position "xfns.c" (x y))
 
@@ -1474,6 +1475,8 @@ set-mouse-absolute-pixel-position
 position (0, 0) of the selected frame's terminal."
   (let ((frame-type (framep-on-display)))
     (cond
+     ((eq frame-type 'ns)
+      (ns-set-mouse-absolute-pixel-position x y))
      ((eq frame-type 'x)
       (x-set-mouse-absolute-pixel-position x y))
      ((eq frame-type 'w32)
diff --git a/src/nsfns.m b/src/nsfns.m
index cbe0ffb..f9fb964 100644
--- a/src/nsfns.m
+++ b/src/nsfns.m
@@ -3053,6 +3053,44 @@ value is a list of the form (LEFT, TOP, RIGHT, BOTTOM).  All values are
 				 : Qnative_edges));
 }
 
+DEFUN ("ns-set-mouse-absolute-pixel-position",
+       Fns_set_mouse_absolute_pixel_position,
+       Sns_set_mouse_absolute_pixel_position, 2, 2, 0,
+       doc: /* Move mouse pointer to absolute pixel position (X, Y).
+The coordinates X and Y are interpreted in pixels relative to a position
+\(0, 0) of the selected frame's display.  */)
+       (Lisp_Object x, Lisp_Object y)
+{
+  struct frame *f = SELECTED_FRAME ();
+  EmacsView *view = FRAME_NS_VIEW (f);
+  NSScreen *screen = [[view window] screen];
+  NSRect screen_frame = [screen frame];
+  int mouse_x, mouse_y;
+
+  NSScreen *primary_screen = [[NSScreen screens] objectAtIndex:0];
+  NSRect primary_screen_frame = [primary_screen frame];
+  CGFloat primary_screen_height = primary_screen_frame.size.height;
+
+  if (FRAME_INITIAL_P (f) || !FRAME_NS_P (f))
+    return Qnil;
+
+  CHECK_TYPE_RANGED_INTEGER (int, x);
+  CHECK_TYPE_RANGED_INTEGER (int, y);
+
+  mouse_x = screen_frame.origin.x + XINT (x);
+
+  if (screen == primary_screen)
+    mouse_y = screen_frame.origin.y + XINT (y);
+  else
+    mouse_y = (primary_screen_height - screen_frame.size.height
+               - screen_frame.origin.y) + XINT (y);
+
+  CGPoint mouse_pos = CGPointMake(mouse_x, mouse_y);
+  CGWarpMouseCursorPosition (mouse_pos);
+
+  return Qnil;
+}
+
 /* ==========================================================================
 
     Class implementations
@@ -3241,6 +3279,7 @@ - (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename
   defsubr (&Sns_frame_edges);
   defsubr (&Sns_frame_list_z_order);
   defsubr (&Sns_frame_restack);
+  defsubr (&Sns_set_mouse_absolute_pixel_position);
   defsubr (&Sx_display_mm_width);
   defsubr (&Sx_display_mm_height);
   defsubr (&Sx_display_screens);
diff --git a/src/nsterm.h b/src/nsterm.h
index 9285178..ac339bf 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -1087,7 +1087,7 @@ struct x_output
    ? ([[FRAME_NS_VIEW (f) window] parentWindow].frame.origin.y          \
       + [[FRAME_NS_VIEW (f) window] parentWindow].frame.size.height     \
       - FRAME_NS_TITLEBAR_HEIGHT (FRAME_PARENT_FRAME (f)))              \
-   : [[[FRAME_NS_VIEW (f) window] screen] frame].size.height)
+   : [[[NSScreen screens] objectAtIndex: 0] frame].size.height)
 
 #define FRAME_NS_FONT_TABLE(f) (FRAME_DISPLAY_INFO (f)->font_table)
 
diff --git a/src/nsterm.m b/src/nsterm.m
index c22c5a7..a7ab73b 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -2321,14 +2321,14 @@ so some key presses (TAB) are swallowed by the system. */
    -------------------------------------------------------------------------- */
 {
   NSTRACE ("frame_set_mouse_pixel_position");
-  ns_raise_frame (f);
-#if 0
-  /* FIXME: this does not work, and what about GNUstep? */
+
+  /* FIXME: what about GNUstep? */
 #ifdef NS_IMPL_COCOA
-  [FRAME_NS_VIEW (f) lockFocus];
-  PSsetmouse ((float)pix_x, (float)pix_y);
-  [FRAME_NS_VIEW (f) unlockFocus];
-#endif
+  CGPoint mouse_pos =
+    CGPointMake(f->left_pos + pix_x,
+                f->top_pos + pix_y +
+                FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
+  CGWarpMouseCursorPosition (mouse_pos);
 #endif
 }
 
diff --git a/test/lisp/mouse-tests.el b/test/lisp/mouse-tests.el
index fffaa2f..a8eca28 100644
--- a/test/lisp/mouse-tests.el
+++ b/test/lisp/mouse-tests.el
@@ -47,4 +47,13 @@
     (should-not (mouse--down-1-maybe-follows-link))
     (should (equal unread-command-events '((mouse-2 nil 1))))))
 
+(ert-deftest bug26816-mouse-frame-movement ()
+  "Mouse moves relative to frame."
+  (skip-unless (display-graphic-p))
+  (let ((frame (selected-frame)))
+    (set-mouse-position frame 0 0)
+    (should (equal (mouse-position)
+                   (cons frame (cons 0 0))))))
+
+
 ;;; mouse-tests.el ends here
-- 
1.7.4.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2017-05-18 19:43 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-05-07 15:11 bug#26816: mouse movement support for OS X Charles A. Roelli
2017-05-07 16:51 ` Eli Zaretskii
2017-05-08 18:34   ` Charles A. Roelli
2017-05-08 18:54     ` Eli Zaretskii
2017-05-07 18:07 ` martin rudalics
2017-05-07 20:00 ` Alan Third
2017-05-09 19:09   ` Charles A. Roelli
2017-05-09 22:44     ` Alan Third
2017-05-11 18:06       ` Charles A. Roelli
2017-05-11 21:43         ` Alan Third
2017-05-14 13:29           ` Charles A. Roelli
2017-05-14 13:59             ` Alan Third
2017-05-14 14:37               ` Eli Zaretskii
2017-05-15 18:23                 ` Charles A. Roelli
2017-05-16 22:53                   ` Alan Third
2017-05-17  8:36                     ` Andreas Schwab
2017-05-18 19:43                       ` Charles A. Roelli

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).