Fix T95608: Mac issues with drag drop on multi-monitor
Mousemove events are sent to windows. In Windows OS, almost all mousemove events are sent to the window whose mouse cursor is over. On MacOS, the window with mousemove events is always the active window. It doesn't matter if the mouse cursor is inside or outside the window. So, in order for non-active windows to also have events, `WM_window_find_under_cursor` is called to find those windows and send the same events. The problem is that to find the window, `WM_window_find_under_cursor` only has the mouse coordinates available, it doesn't differentiate which monitor these coordinates came from. So the mouse on one monitor may incorrectly send events to a window on another monitor. The solution used is to use a native API on Mac to detect the window under the cursor. For Windows and Linux nothing has changed. Reviewed By: brecht Differential Revision: https://developer.blender.org/D14197
This commit is contained in:
parent
8e88af9934
commit
9bd586a01e
Notes:
blender-bot
2023-08-21 22:34:44 +02:00
Referenced by issue #95608, Asset browser: cursor offset when dragging from low-DPI to high-DPI display Referenced by pull request #111359, Fix #111295: Add Missing Win32 Platform-Specific Window functions
|
@ -265,6 +265,16 @@ extern GHOST_TSuccess GHOST_EndFullScreen(GHOST_SystemHandle systemhandle);
|
|||
*/
|
||||
extern int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle);
|
||||
|
||||
/**
|
||||
* Get the Window under the cursor.
|
||||
* \param x: The x-coordinate of the cursor.
|
||||
* \param y: The y-coordinate of the cursor.
|
||||
* @return The window under the cursor or nullptr in none.
|
||||
*/
|
||||
extern GHOST_WindowHandle GHOST_GetWindowUnderCursor(GHOST_SystemHandle systemhandle,
|
||||
int32_t x,
|
||||
int32_t y);
|
||||
|
||||
/***************************************************************************************
|
||||
* Event management functionality
|
||||
***************************************************************************************/
|
||||
|
|
|
@ -325,6 +325,14 @@ class GHOST_ISystem {
|
|||
*/
|
||||
virtual void useWindowFocus(const bool use_focus) = 0;
|
||||
|
||||
/**
|
||||
* Get the Window under the cursor.
|
||||
* \param x: The x-coordinate of the cursor.
|
||||
* \param y: The y-coordinate of the cursor.
|
||||
* @return The window under the cursor or nullptr if none.
|
||||
*/
|
||||
virtual GHOST_IWindow *getWindowUnderCursor(int32_t x, int32_t y) = 0;
|
||||
|
||||
/***************************************************************************************
|
||||
* Event management functionality
|
||||
***************************************************************************************/
|
||||
|
|
|
@ -249,6 +249,16 @@ int GHOST_GetFullScreen(GHOST_SystemHandle systemhandle)
|
|||
return (int)system->getFullScreen();
|
||||
}
|
||||
|
||||
GHOST_WindowHandle GHOST_GetWindowUnderCursor(GHOST_SystemHandle systemhandle,
|
||||
int32_t x,
|
||||
int32_t y)
|
||||
{
|
||||
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
|
||||
GHOST_IWindow *window = system->getWindowUnderCursor(x, y);
|
||||
|
||||
return (GHOST_WindowHandle)window;
|
||||
}
|
||||
|
||||
bool GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, bool waitForEvent)
|
||||
{
|
||||
GHOST_ISystem *system = (GHOST_ISystem *)systemhandle;
|
||||
|
|
|
@ -205,6 +205,25 @@ bool GHOST_System::getFullScreen(void)
|
|||
return fullScreen;
|
||||
}
|
||||
|
||||
GHOST_IWindow *GHOST_System::getWindowUnderCursor(int32_t x, int32_t y)
|
||||
{
|
||||
/* TODO: This solution should follow the order of the activated windows (Z-order).
|
||||
* It is imperfect but usable in most cases. */
|
||||
for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) {
|
||||
if (iwindow->getState() == GHOST_kWindowStateMinimized) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GHOST_Rect bounds;
|
||||
iwindow->getClientBounds(bounds);
|
||||
if (bounds.isInside(x, y)) {
|
||||
return iwindow;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GHOST_System::dispatchEvents()
|
||||
{
|
||||
#ifdef WITH_INPUT_NDOF
|
||||
|
|
|
@ -173,6 +173,14 @@ class GHOST_System : public GHOST_ISystem {
|
|||
void useWindowFocus(const bool use_focus);
|
||||
bool m_windowFocus;
|
||||
|
||||
/**
|
||||
* Get the Window under the cursor.
|
||||
* \param x: The x-coordinate of the cursor.
|
||||
* \param y: The y-coordinate of the cursor.
|
||||
* @return The window under the cursor or nullptr if none.
|
||||
*/
|
||||
GHOST_IWindow *getWindowUnderCursor(int32_t x, int32_t y);
|
||||
|
||||
/***************************************************************************************
|
||||
* Event management functionality
|
||||
***************************************************************************************/
|
||||
|
|
|
@ -125,6 +125,14 @@ class GHOST_SystemCocoa : public GHOST_System {
|
|||
*/
|
||||
GHOST_TSuccess disposeContext(GHOST_IContext *context);
|
||||
|
||||
/**
|
||||
* Get the Window under the cursor.
|
||||
* \param x: The x-coordinate of the cursor.
|
||||
* \param y: The y-coordinate of the cursor.
|
||||
* @return The window under the cursor or nullptr if none.
|
||||
*/
|
||||
GHOST_IWindow *getWindowUnderCursor(int32_t x, int32_t y);
|
||||
|
||||
/***************************************************************************************
|
||||
* Event management functionality
|
||||
***************************************************************************************/
|
||||
|
|
|
@ -788,6 +788,20 @@ GHOST_TSuccess GHOST_SystemCocoa::disposeContext(GHOST_IContext *context)
|
|||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_IWindow *GHOST_SystemCocoa::getWindowUnderCursor(int32_t x, int32_t y)
|
||||
{
|
||||
NSPoint scr_co = NSMakePoint(x, y);
|
||||
|
||||
int windowNumberAtPoint = [NSWindow windowNumberAtPoint:scr_co belowWindowWithWindowNumber:0];
|
||||
NSWindow *nswindow = [NSApp windowWithWindowNumber:windowNumberAtPoint];
|
||||
|
||||
if (nswindow == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return m_windowManager->getWindowAssociatedWithOSWindow((void *)nswindow);
|
||||
}
|
||||
|
||||
/**
|
||||
* \note : returns coordinates in Cocoa screen coordinates
|
||||
*/
|
||||
|
|
|
@ -128,4 +128,9 @@ class GHOST_SystemNULL : public GHOST_System {
|
|||
type,
|
||||
((glSettings.flags & GHOST_glStereoVisual) != 0));
|
||||
}
|
||||
|
||||
GHOST_IWindow *getWindowUnderCursor(int32_t x, int32_t y)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -165,8 +165,7 @@ void datadropper_win_area_find(
|
|||
*r_win = CTX_wm_window(C);
|
||||
*r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mval);
|
||||
if (*r_area == NULL) {
|
||||
wmWindowManager *wm = CTX_wm_manager(C);
|
||||
*r_win = WM_window_find_under_cursor(wm, NULL, *r_win, mval, r_mval);
|
||||
*r_win = WM_window_find_under_cursor(*r_win, mval, r_mval);
|
||||
if (*r_win) {
|
||||
screen = WM_window_get_active_screen(*r_win);
|
||||
*r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval);
|
||||
|
|
|
@ -143,11 +143,7 @@ void WM_reinit_gizmomap_all(struct Main *bmain);
|
|||
*/
|
||||
void WM_script_tag_reload(void);
|
||||
|
||||
wmWindow *WM_window_find_under_cursor(const wmWindowManager *wm,
|
||||
const wmWindow *win_ignore,
|
||||
const wmWindow *win,
|
||||
const int mval[2],
|
||||
int r_mval[2]);
|
||||
wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mval[2]);
|
||||
void WM_window_pixel_sample_read(const wmWindowManager *wm,
|
||||
const wmWindow *win,
|
||||
const int pos[2],
|
||||
|
|
|
@ -4663,8 +4663,8 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi
|
|||
}
|
||||
}
|
||||
|
||||
wmWindow *win_other = WM_window_find_under_cursor(wm, win, win, mval, mval);
|
||||
if (win_other) {
|
||||
wmWindow *win_other = WM_window_find_under_cursor(win, mval, mval);
|
||||
if (win_other && win_other != win) {
|
||||
copy_v2_v2_int(event->xy, mval);
|
||||
return win_other;
|
||||
}
|
||||
|
|
|
@ -1855,56 +1855,23 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut)
|
|||
/** \name Find Window Utility
|
||||
* \{ */
|
||||
|
||||
static void wm_window_desktop_pos_get(const wmWindow *win,
|
||||
const int screen_pos[2],
|
||||
int r_desk_pos[2])
|
||||
wmWindow *WM_window_find_under_cursor(wmWindow *win, const int mval[2], int r_mval[2])
|
||||
{
|
||||
/* To desktop space. */
|
||||
r_desk_pos[0] = screen_pos[0] + (int)(U.pixelsize * win->posx);
|
||||
r_desk_pos[1] = screen_pos[1] + (int)(U.pixelsize * win->posy);
|
||||
}
|
||||
int tmp[2];
|
||||
copy_v2_v2_int(tmp, mval);
|
||||
wm_cursor_position_to_ghost(win, &tmp[0], &tmp[1]);
|
||||
|
||||
static void wm_window_screen_pos_get(const wmWindow *win,
|
||||
const int desktop_pos[2],
|
||||
int r_scr_pos[2])
|
||||
{
|
||||
/* To window space. */
|
||||
r_scr_pos[0] = desktop_pos[0] - (int)(U.pixelsize * win->posx);
|
||||
r_scr_pos[1] = desktop_pos[1] - (int)(U.pixelsize * win->posy);
|
||||
}
|
||||
GHOST_WindowHandle ghostwin = GHOST_GetWindowUnderCursor(g_system, tmp[0], tmp[1]);
|
||||
|
||||
wmWindow *WM_window_find_under_cursor(const wmWindowManager *wm,
|
||||
const wmWindow *win_ignore,
|
||||
const wmWindow *win,
|
||||
const int mval[2],
|
||||
int r_mval[2])
|
||||
{
|
||||
int desk_pos[2];
|
||||
wm_window_desktop_pos_get(win, mval, desk_pos);
|
||||
|
||||
/* TODO: This should follow the order of the activated windows.
|
||||
* The current solution is imperfect but usable in most cases. */
|
||||
LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) {
|
||||
if (win_iter == win_ignore) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (win_iter->windowstate == GHOST_kWindowStateMinimized) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int scr_pos[2];
|
||||
wm_window_screen_pos_get(win_iter, desk_pos, scr_pos);
|
||||
|
||||
if (scr_pos[0] >= 0 && scr_pos[1] >= 0 && scr_pos[0] <= WM_window_pixels_x(win_iter) &&
|
||||
scr_pos[1] <= WM_window_pixels_y(win_iter)) {
|
||||
|
||||
copy_v2_v2_int(r_mval, scr_pos);
|
||||
return win_iter;
|
||||
}
|
||||
if (!ghostwin) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
wmWindow *r_win = GHOST_GetWindowUserData(ghostwin);
|
||||
wm_cursor_position_from_ghost(r_win, &tmp[0], &tmp[1]);
|
||||
copy_v2_v2_int(r_mval, tmp);
|
||||
|
||||
return r_win;
|
||||
}
|
||||
|
||||
void WM_window_pixel_sample_read(const wmWindowManager *wm,
|
||||
|
|
Loading…
Reference in New Issue