Subject: bug#26816: mouse movement support for OS X

From: "Charles A. Roelli" <[email-masked]>
Date: Tue, 9 May 2017 21:09:29 +0200

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.