From 5a33b0075a3142b5d7d29bcd9584cd412393cdd4 Mon Sep 17 00:00:00 2001 From: Sebastian Wick Date: Wed, 13 Sep 2023 16:19:38 +0200 Subject: [PATCH] core: Move window enter/leave to display The following commits will make it possible to pass a NULL window to display_handle_window_enter/leave to represent the cursor entering the desktop. This means it can't be a method of the window class anymore. Part-of: --- src/core/display-private.h | 9 ++ src/core/display.c | 153 +++++++++++++++++++++++++++++ src/core/window-private.h | 6 -- src/core/window.c | 153 ----------------------------- src/wayland/meta-wayland-pointer.c | 7 +- src/x11/events.c | 11 ++- 6 files changed, 172 insertions(+), 167 deletions(-) diff --git a/src/core/display-private.h b/src/core/display-private.h index 21a4b1959..deb09260d 100644 --- a/src/core/display-private.h +++ b/src/core/display-private.h @@ -353,3 +353,12 @@ gboolean meta_display_process_captured_input (MetaDisplay *display, const ClutterEvent *event); void meta_display_cancel_input_capture (MetaDisplay *display); + +void meta_display_handle_window_enter (MetaDisplay *display, + MetaWindow *window, + uint32_t timestamp_ms, + int root_x, + int root_y); + +void meta_display_handle_window_leave (MetaDisplay *display, + MetaWindow *window); diff --git a/src/core/display.c b/src/core/display.c index 0a191c0fb..a4d102c64 100644 --- a/src/core/display.c +++ b/src/core/display.c @@ -3803,3 +3803,156 @@ meta_display_flush_queued_window (MetaDisplay *display, window_queue_func[queue_idx] (display, windows); } } + +typedef struct +{ + MetaWindow *window; + int pointer_x; + int pointer_y; +} MetaFocusData; + +static void +focus_mouse_mode (MetaWindow *window, + uint32_t timestamp_ms) +{ + MetaDisplay *display = window->display; + + if (window->override_redirect) + return; + + if (window->type != META_WINDOW_DESKTOP) + { + meta_topic (META_DEBUG_FOCUS, + "Focusing %s at time %u.", window->desc, timestamp_ms); + + meta_window_focus (window, timestamp_ms); + + if (meta_prefs_get_auto_raise ()) + meta_display_queue_autoraise_callback (display, window); + else + meta_topic (META_DEBUG_FOCUS, "Auto raise is disabled"); + } + else + { + /* In mouse focus mode, we defocus when the mouse *enters* + * the DESKTOP window, instead of defocusing on LeaveNotify. + * This is because having the mouse enter override-redirect + * child windows unfortunately causes LeaveNotify events that + * we can't distinguish from the mouse actually leaving the + * toplevel window as we expect. But, since we filter out + * EnterNotify events on override-redirect windows, this + * alternative mechanism works great. + */ + if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_MOUSE && + display->focus_window != NULL) + { + meta_topic (META_DEBUG_FOCUS, + "Unsetting focus from %s due to mouse entering " + "the DESKTOP window", + display->focus_window->desc); + meta_display_unset_input_focus (display, timestamp_ms); + } + } +} + +static gboolean +focus_on_pointer_rest_callback (gpointer data) +{ + MetaFocusData *focus_data = data; + MetaWindow *window = focus_data->window; + MetaDisplay *display = window->display; + MetaBackend *backend = backend_from_display (display); + MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); + graphene_point_t point; + uint32_t timestamp_ms; + + if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) + goto out; + + meta_cursor_tracker_get_pointer (cursor_tracker, &point, NULL); + + if ((int) point.x != focus_data->pointer_x || + (int) point.y != focus_data->pointer_y) + { + focus_data->pointer_x = point.x; + focus_data->pointer_y = point.y; + return G_SOURCE_CONTINUE; + } + + if (!meta_window_has_pointer (window)) + goto out; + + timestamp_ms = meta_display_get_current_time_roundtrip (display); + focus_mouse_mode (window, timestamp_ms); + + out: + display->focus_timeout_id = 0; + return G_SOURCE_REMOVE; +} + +/* The interval, in milliseconds, we use in focus-follows-mouse + * mode to check whether the pointer has stopped moving after a + * crossing event. + */ +#define FOCUS_TIMEOUT_DELAY 25 + +static void +queue_pointer_rest_callback (MetaDisplay *display, + MetaWindow *window, + int pointer_x, + int pointer_y) +{ + MetaFocusData *focus_data; + + focus_data = g_new (MetaFocusData, 1); + focus_data->window = window; + focus_data->pointer_x = pointer_x; + focus_data->pointer_y = pointer_y; + + g_clear_handle_id (&display->focus_timeout_id, g_source_remove); + + display->focus_timeout_id = + g_timeout_add_full (G_PRIORITY_DEFAULT, + FOCUS_TIMEOUT_DELAY, + focus_on_pointer_rest_callback, + focus_data, + g_free); + g_source_set_name_by_id (display->focus_timeout_id, + "[mutter] focus_on_pointer_rest_callback"); +} + +void +meta_display_handle_window_enter (MetaDisplay *display, + MetaWindow *window, + uint32_t timestamp_ms, + int root_x, + int root_y) +{ + switch (meta_prefs_get_focus_mode ()) + { + case G_DESKTOP_FOCUS_MODE_SLOPPY: + case G_DESKTOP_FOCUS_MODE_MOUSE: + display->mouse_mode = TRUE; + if (window->type != META_WINDOW_DOCK) + { + if (meta_prefs_get_focus_change_on_pointer_rest()) + queue_pointer_rest_callback (display, window, root_x, root_y); + else + focus_mouse_mode (window, timestamp_ms); + } + break; + case G_DESKTOP_FOCUS_MODE_CLICK: + break; + } + + if (window->type == META_WINDOW_DOCK) + meta_window_raise (window); +} + +void +meta_display_handle_window_leave (MetaDisplay *display, + MetaWindow *window) +{ + if (window->type == META_WINDOW_DOCK && !window->has_focus) + meta_window_lower (window); +} diff --git a/src/core/window-private.h b/src/core/window-private.h index 1375eee40..03429271c 100644 --- a/src/core/window-private.h +++ b/src/core/window-private.h @@ -807,12 +807,6 @@ void meta_window_set_transient_for (MetaWindow *window, void meta_window_set_opacity (MetaWindow *window, guint8 opacity); -void meta_window_handle_enter (MetaWindow *window, - guint32 timestamp, - guint root_x, - guint root_y); -void meta_window_handle_leave (MetaWindow *window); - void meta_window_handle_ungrabbed_event (MetaWindow *window, const ClutterEvent *event); diff --git a/src/core/window.c b/src/core/window.c index d58764b1c..95a9528d6 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -7409,57 +7409,6 @@ meta_window_set_opacity (MetaWindow *window, meta_compositor_window_opacity_changed (window->display->compositor, window); } -typedef struct -{ - MetaWindow *window; - int pointer_x; - int pointer_y; -} MetaFocusData; - -static void -mouse_mode_focus (MetaWindow *window, - guint32 timestamp) -{ - MetaDisplay *display = window->display; - - if (window->override_redirect) - return; - - if (window->type != META_WINDOW_DESKTOP) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing %s at time %u.", window->desc, timestamp); - - meta_window_focus (window, timestamp); - - if (meta_prefs_get_auto_raise ()) - meta_display_queue_autoraise_callback (display, window); - else - meta_topic (META_DEBUG_FOCUS, "Auto raise is disabled"); - } - else - { - /* In mouse focus mode, we defocus when the mouse *enters* - * the DESKTOP window, instead of defocusing on LeaveNotify. - * This is because having the mouse enter override-redirect - * child windows unfortunately causes LeaveNotify events that - * we can't distinguish from the mouse actually leaving the - * toplevel window as we expect. But, since we filter out - * EnterNotify events on override-redirect windows, this - * alternative mechanism works great. - */ - if (meta_prefs_get_focus_mode() == G_DESKTOP_FOCUS_MODE_MOUSE && - display->focus_window != NULL) - { - meta_topic (META_DEBUG_FOCUS, - "Unsetting focus from %s due to mouse entering " - "the DESKTOP window", - display->focus_window->desc); - meta_display_unset_input_focus (display, timestamp); - } - } -} - static gboolean window_has_pointer_wayland (MetaWindow *window) { @@ -7509,108 +7458,6 @@ meta_window_has_pointer (MetaWindow *window) return window_has_pointer_x11 (window); } -static gboolean -window_focus_on_pointer_rest_callback (gpointer data) -{ - MetaFocusData *focus_data = data; - MetaWindow *window = focus_data->window; - MetaDisplay *display = window->display; - MetaBackend *backend = backend_from_window (window); - MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); - graphene_point_t point; - guint32 timestamp; - - if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK) - goto out; - - meta_cursor_tracker_get_pointer (cursor_tracker, &point, NULL); - - if ((int) point.x != focus_data->pointer_x || - (int) point.y != focus_data->pointer_y) - { - focus_data->pointer_x = point.x; - focus_data->pointer_y = point.y; - return G_SOURCE_CONTINUE; - } - - if (!meta_window_has_pointer (window)) - goto out; - - timestamp = meta_display_get_current_time_roundtrip (display); - mouse_mode_focus (window, timestamp); - - out: - display->focus_timeout_id = 0; - return G_SOURCE_REMOVE; -} - -/* The interval, in milliseconds, we use in focus-follows-mouse - * mode to check whether the pointer has stopped moving after a - * crossing event. - */ -#define FOCUS_TIMEOUT_DELAY 25 - -static void -queue_focus_callback (MetaDisplay *display, - MetaWindow *window, - int pointer_x, - int pointer_y) -{ - MetaFocusData *focus_data; - - focus_data = g_new (MetaFocusData, 1); - focus_data->window = window; - focus_data->pointer_x = pointer_x; - focus_data->pointer_y = pointer_y; - - g_clear_handle_id (&display->focus_timeout_id, g_source_remove); - - display->focus_timeout_id = - g_timeout_add_full (G_PRIORITY_DEFAULT, - FOCUS_TIMEOUT_DELAY, - window_focus_on_pointer_rest_callback, - focus_data, - g_free); - g_source_set_name_by_id (display->focus_timeout_id, - "[mutter] window_focus_on_pointer_rest_callback"); -} - -void -meta_window_handle_enter (MetaWindow *window, - guint32 timestamp, - guint root_x, - guint root_y) -{ - MetaDisplay *display = window->display; - - switch (meta_prefs_get_focus_mode ()) - { - case G_DESKTOP_FOCUS_MODE_SLOPPY: - case G_DESKTOP_FOCUS_MODE_MOUSE: - display->mouse_mode = TRUE; - if (window->type != META_WINDOW_DOCK) - { - if (meta_prefs_get_focus_change_on_pointer_rest()) - queue_focus_callback (display, window, root_x, root_y); - else - mouse_mode_focus (window, timestamp); - } - break; - case G_DESKTOP_FOCUS_MODE_CLICK: - break; - } - - if (window->type == META_WINDOW_DOCK) - meta_window_raise (window); -} - -void -meta_window_handle_leave (MetaWindow *window) -{ - if (window->type == META_WINDOW_DOCK && !window->has_focus) - meta_window_lower (window); -} - void meta_window_handle_ungrabbed_event (MetaWindow *window, const ClutterEvent *event) diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index 89ac75faf..8ab737b15 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -713,9 +713,10 @@ meta_wayland_pointer_update (MetaWaylandPointer *pointer, graphene_point_t pos; clutter_event_get_coords (event, &pos.x, &pos.y); - meta_window_handle_enter (focus_window, - clutter_event_get_time (event), - pos.x, pos.y); + meta_display_handle_window_enter (focus_window->display, + focus_window, + clutter_event_get_time (event), + pos.x, pos.y); } } } diff --git a/src/x11/events.c b/src/x11/events.c index ac4e0059d..f3ff945e6 100644 --- a/src/x11/events.c +++ b/src/x11/events.c @@ -969,10 +969,11 @@ handle_input_xevent (MetaX11Display *x11_display, !meta_is_wayland_compositor () && enter_event->sourceid != enter_event->deviceid) { - meta_window_handle_enter (window, - enter_event->time, - enter_event->root_x, - enter_event->root_y); + meta_display_handle_window_enter (display, + window, + enter_event->time, + enter_event->root_x, + enter_event->root_y); } break; case XI_Leave: @@ -983,7 +984,7 @@ handle_input_xevent (MetaX11Display *x11_display, enter_event->mode != XINotifyGrab && enter_event->mode != XINotifyUngrab) { - meta_window_handle_leave (window); + meta_display_handle_window_leave (display, window); } break; case XI_FocusIn: