[PATCH] winex11: The correct way to search the target window for drag&drop operations.

John Found johnfound at asm32.info
Fri Apr 19 15:58:44 CDT 2019


On Fri, 19 Apr 2019 15:43:46 -0500
Zebediah Figura <z.figura12 at gmail.com> wrote:

> On 4/19/19 3:28 AM, John Found wrote:
> > On Thu, 18 Apr 2019 12:53:35 -0500
> > Zebediah Figura <z.figura12 at gmail.com> wrote:
> > 
> >> On 04/18/2019 12:35 PM, John Found wrote:
> >>> On Thu, 18 Apr 2019 12:09:02 -0500
> >>> Zebediah Figura <z.figura12 at gmail.com> wrote:
> >>>
> >>>>
> >>>> Really? I'm looking at this test right here:
> >>>>
> >>>> <https://source.winehq.org/git/wine.git/blob/refs/heads/master:/dlls/user32/tests/win.c#l9398>
> >>>>
> >>>
> >>> Well, yes, I am wrong about the WindowFromPoint, but still only the first level of the children is checked.
> >>>
> >>> The mentioned test checks exactly this in 3 cases:
> >>>
> >>> 1. Main window without child created - main window returned.
> >>> 2. Main window with single STATIC child created - main window returned. (correct, according to MSDN)
> >>> 3. Main window with single BUTTON child created - the child returned.
> >>>
> >>> There is no child-in-child cases (and IMHO, should not be).
> >>>
> >>
> >> Really? Why not? Our implementation is recursive, so it should return
> >> the deepest child. If it's wrong, we should add tests to prove it.
> >>
> >>
> > 
> > Well, I finished my extended tests and they are contradictory.
> > 
> > 1. Yes, WindowFromPoint searches recursively on random depth, both in Windows and WINE.
> > I was totally wrong about this. Excuse my ignorance.
> > 
> > 2. But WindowFromPoint still does not work properly in my drag&drop patch. The problem is that WindowFromPoint
> > fully ignores the STATIC controls (documented and correct behavior), but in Windows the STATIC controls are
> > valid drop target if they have WS_EX_ACCEPTFILES set.
> > 
> > This way, the implemented in the patch "window_from_point_dnd" function correctly returns the STATIC windows drop targets.
> > Comparing with the original Windows behavior, I can't see any differences.
> > 
> > (I will attach the improved test application I used, now it has STATIC as a drop targets and WindowFromPoint test tool as well.)
> > 
> > So, the question is what to do now?
> > 
> > Regards.
> > 
> > 
> > 
> 
> Thanks for testing, that makes sense. In that case it seems your 
> original approach is necessary. I would recommend adding a comment to 
> clarify this, so that someone doesn't make the mistake of trying to 
> replace it with WindowFromPoint() in the future.
> 
> I also have some stylistic comments on your original patch:
> 
> > +/* the recursive worker for window_from_point_dnd */
> > +HWND do_window_from_point_dnd(HWND hwnd, POINT* point)
> > +{
> > +    HWND w;
> > +    w = ChildWindowFromPointEx(hwnd, *point, CWP_SKIPDISABLED | CWP_SKIPINVISIBLE);
> > +    if (w && (w != hwnd))
> > +    {
> > +        MapWindowPoints(hwnd, w, point, 1);
> > +        w = do_window_from_point_dnd(w, point);
> > +    }
> > +    return w;
> > +}
> > +
> > +
> > +/* Recursively search for the window on given coordinates in a drag&drop specific manner. */
> > +HWND window_from_point_dnd(HWND hwnd, POINT point)
> > +{
> > +    POINT p;
> > +    p.x = point.x;
> > +    p.y = point.y;
> > +    ScreenToClient(hwnd, &p);
> > +    return do_window_from_point_dnd(hwnd, &p);
> > +}
> > +
> 
> These functions should be static, since they're not used elsewhere.
> 
> I also feel like this would more readable formatted as a loop instead of 
> a recursive function. Something like:
> 
> /* Find the deepest child window at the given point. We can't use 
> WindowFromPoint() for this, because it skips HTTRANSPARENT windows, and 
> those should still receive drop notifications. */
> static HWND window_from_point( HWND hwnd, POINT point )
> {
>      HWND child;
> 
>      ScreenToClient( hwnd, &point );
> 
>      while ((child = ChildWindowFromPointEx( hwnd, point, 
> CWP_SKIPDISABLED | CWP_SKIPINVISIBLE )) && child != hwnd)
>      {
>          MapWindowPoints( hwnd, child, &point, 1 );
>          hwnd = child;
>      }
>      return hwnd;
> }
> 
> > +        while (targetWindow && !(GetWindowLongW(targetWindow, GWL_EXSTYLE) & WS_EX_ACCEPTFILES))
> > +            targetWindow = GetParent(targetWindow);
> 
> ...
> 
> > +        while (hwnd_drop && !(GetWindowLongW(hwnd_drop, GWL_EXSTYLE) & WS_EX_ACCEPTFILES))
> > +            hwnd_drop = GetParent(hwnd_drop);
> 
> Since you do this in both places, you could also factor it into the 
> window_from_point helper, in which case it might be better to call it 
> something like get_drop_target().
> 
> > +        POINT pt;
> > +        HWND hwnd_drop;
> > +
> > +        pt.x = XDNDxy.x;
> > +        pt.y = XDNDxy.y;
> > +
> > +        hwnd_drop = window_from_point_dnd(hWnd, pt);
> 
> You're passing pt by value, so you don't need to copy it into a local 
> variable.
> 
> 

Thanks for the hints. My C skills are really not the best of my skills. 
Will fix it and submit as a v2.

BTW, what you think about the notice of Gabriel Ivăncescu in his post above, about the difference between GetParent (returns the owner as well) and GetAncestor(...,GA_PARENT) (returns only the parent)?

-- 
John Found <johnfound at asm32.info>



More information about the wine-devel mailing list