wayland: Support alternative focus modes like focus-follows-mouse
Use the existing code for MetaWindow focus-follows-mouse to support this.
This commit is contained in:
parent
08df9bf559
commit
23ba3e527f
@ -117,15 +117,6 @@ typedef struct
|
||||
guint ping_timeout_id;
|
||||
} MetaPingData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
int pointer_x;
|
||||
int pointer_y;
|
||||
} MetaFocusData;
|
||||
|
||||
|
||||
G_DEFINE_TYPE(MetaDisplay, meta_display, G_TYPE_OBJECT);
|
||||
|
||||
/* Signals */
|
||||
@ -1596,21 +1587,6 @@ crossing_serial_is_ignored (MetaDisplay *display,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_ignored_crossing_serials (MetaDisplay *display)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while (i < N_IGNORED_CROSSING_SERIALS)
|
||||
{
|
||||
display->ignored_crossing_serials[i] = 0;
|
||||
++i;
|
||||
}
|
||||
|
||||
display->ungrab_should_not_cause_focus_window = None;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_raise_with_delay_callback (void *data)
|
||||
{
|
||||
@ -1651,110 +1627,6 @@ window_raise_with_delay_callback (void *data)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_display_mouse_mode_focus (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
guint32 timestamp)
|
||||
{
|
||||
if (window->type != META_WINDOW_DESKTOP)
|
||||
{
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Focusing %s at time %u.\n", 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\n");
|
||||
}
|
||||
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\n",
|
||||
display->focus_window->desc);
|
||||
meta_display_focus_the_no_focus_window (display,
|
||||
window->screen,
|
||||
timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_focus_on_pointer_rest_callback (gpointer data)
|
||||
{
|
||||
MetaFocusData *focus_data;
|
||||
MetaDisplay *display;
|
||||
MetaScreen *screen;
|
||||
MetaWindow *window;
|
||||
Window root, child;
|
||||
double root_x, root_y, x, y;
|
||||
guint32 timestamp;
|
||||
XIButtonState buttons;
|
||||
XIModifierState mods;
|
||||
XIGroupState group;
|
||||
|
||||
focus_data = data;
|
||||
display = focus_data->display;
|
||||
screen = focus_data->window->screen;
|
||||
|
||||
if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK)
|
||||
goto out;
|
||||
|
||||
meta_error_trap_push (display);
|
||||
XIQueryPointer (display->xdisplay,
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
screen->xroot,
|
||||
&root, &child,
|
||||
&root_x, &root_y, &x, &y,
|
||||
&buttons, &mods, &group);
|
||||
meta_error_trap_pop (display);
|
||||
free (buttons.mask);
|
||||
|
||||
if (root_x != focus_data->pointer_x ||
|
||||
root_y != focus_data->pointer_y)
|
||||
{
|
||||
focus_data->pointer_x = root_x;
|
||||
focus_data->pointer_y = root_y;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Explicitly check for the overlay window, as get_focus_window_at_point()
|
||||
* may return windows that extend underneath the chrome (like
|
||||
* override-redirect or DESKTOP windows)
|
||||
*/
|
||||
if (child == meta_get_overlay_window (screen))
|
||||
goto out;
|
||||
|
||||
window =
|
||||
meta_stack_get_default_focus_window_at_point (screen->stack,
|
||||
screen->active_workspace,
|
||||
None, root_x, root_y);
|
||||
|
||||
if (window == NULL)
|
||||
goto out;
|
||||
|
||||
timestamp = meta_display_get_current_time_roundtrip (display);
|
||||
meta_display_mouse_mode_focus (display, window, timestamp);
|
||||
|
||||
out:
|
||||
display->focus_timeout_id = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_display_queue_autoraise_callback (MetaDisplay *display,
|
||||
MetaWindow *window)
|
||||
@ -1775,37 +1647,6 @@ meta_display_queue_autoraise_callback (MetaDisplay *display,
|
||||
display->autoraise_window = window;
|
||||
}
|
||||
|
||||
/* 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
|
||||
meta_display_queue_focus_callback (MetaDisplay *display,
|
||||
MetaWindow *window,
|
||||
int pointer_x,
|
||||
int pointer_y)
|
||||
{
|
||||
MetaFocusData *focus_data;
|
||||
|
||||
focus_data = g_new (MetaFocusData, 1);
|
||||
focus_data->display = display;
|
||||
focus_data->window = window;
|
||||
focus_data->pointer_x = pointer_x;
|
||||
focus_data->pointer_y = pointer_y;
|
||||
|
||||
if (display->focus_timeout_id != 0)
|
||||
g_source_remove (display->focus_timeout_id);
|
||||
|
||||
display->focus_timeout_id =
|
||||
g_timeout_add_full (G_PRIORITY_DEFAULT,
|
||||
FOCUS_TIMEOUT_DELAY,
|
||||
window_focus_on_pointer_rest_callback,
|
||||
focus_data,
|
||||
g_free);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
handle_net_restack_window (MetaDisplay* display,
|
||||
@ -2502,36 +2343,10 @@ handle_input_xevent (MetaDisplay *display,
|
||||
enter_event->detail != XINotifyInferior &&
|
||||
meta_display_focus_sentinel_clear (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)
|
||||
{
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Queuing a focus change for %s due to "
|
||||
"enter notify with serial %lu at time %lu, "
|
||||
"and setting display->mouse_mode to TRUE.\n",
|
||||
window->desc,
|
||||
serial,
|
||||
enter_event->time);
|
||||
|
||||
if (meta_prefs_get_focus_change_on_pointer_rest())
|
||||
meta_display_queue_focus_callback (display, window,
|
||||
enter_event->root_x,
|
||||
enter_event->root_y);
|
||||
else
|
||||
meta_display_mouse_mode_focus (display, window,
|
||||
enter_event->time);
|
||||
|
||||
/* stop ignoring stuff */
|
||||
reset_ignored_crossing_serials (display);
|
||||
}
|
||||
break;
|
||||
case G_DESKTOP_FOCUS_MODE_CLICK:
|
||||
break;
|
||||
}
|
||||
meta_window_handle_enter (window,
|
||||
enter_event->time,
|
||||
enter_event->root_x,
|
||||
enter_event->root_y);
|
||||
|
||||
if (window->type == META_WINDOW_DOCK)
|
||||
meta_window_raise (window);
|
||||
|
@ -734,4 +734,9 @@ void meta_window_set_gtk_dbus_properties (MetaWindow *window,
|
||||
void meta_window_set_transient_for (MetaWindow *window,
|
||||
MetaWindow *parent);
|
||||
|
||||
void meta_window_handle_enter (MetaWindow *window,
|
||||
guint32 timestamp,
|
||||
guint root_x,
|
||||
guint root_y);
|
||||
|
||||
#endif
|
||||
|
@ -11667,3 +11667,185 @@ meta_window_set_transient_for (MetaWindow *window,
|
||||
if (meta_window_appears_focused (window) && window->transient_for != None)
|
||||
meta_window_propagate_focus_appearance (window, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_ignored_crossing_serials (MetaDisplay *display)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
while (i < N_IGNORED_CROSSING_SERIALS)
|
||||
{
|
||||
display->ignored_crossing_serials[i] = 0;
|
||||
++i;
|
||||
}
|
||||
|
||||
display->ungrab_should_not_cause_focus_window = None;
|
||||
}
|
||||
|
||||
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->type != META_WINDOW_DESKTOP)
|
||||
{
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Focusing %s at time %u.\n", 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\n");
|
||||
}
|
||||
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\n",
|
||||
display->focus_window->desc);
|
||||
meta_display_focus_the_no_focus_window (display,
|
||||
window->screen,
|
||||
timestamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
window_focus_on_pointer_rest_callback (gpointer data)
|
||||
{
|
||||
MetaFocusData *focus_data = data;
|
||||
MetaWindow *window = focus_data->window;
|
||||
MetaDisplay *display = window->display;
|
||||
MetaScreen *screen = window->screen;
|
||||
Window root, child;
|
||||
double root_x, root_y, x, y;
|
||||
guint32 timestamp;
|
||||
XIButtonState buttons;
|
||||
XIModifierState mods;
|
||||
XIGroupState group;
|
||||
|
||||
if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK)
|
||||
goto out;
|
||||
|
||||
meta_error_trap_push (display);
|
||||
XIQueryPointer (display->xdisplay,
|
||||
META_VIRTUAL_CORE_POINTER_ID,
|
||||
screen->xroot,
|
||||
&root, &child,
|
||||
&root_x, &root_y, &x, &y,
|
||||
&buttons, &mods, &group);
|
||||
meta_error_trap_pop (display);
|
||||
free (buttons.mask);
|
||||
|
||||
if (root_x != focus_data->pointer_x ||
|
||||
root_y != focus_data->pointer_y)
|
||||
{
|
||||
focus_data->pointer_x = root_x;
|
||||
focus_data->pointer_y = root_y;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Explicitly check for the overlay window, as get_focus_window_at_point()
|
||||
* may return windows that extend underneath the chrome (like
|
||||
* override-redirect or DESKTOP windows)
|
||||
*/
|
||||
if (child == meta_get_overlay_window (screen))
|
||||
goto out;
|
||||
|
||||
window =
|
||||
meta_stack_get_default_focus_window_at_point (screen->stack,
|
||||
screen->active_workspace,
|
||||
None, root_x, root_y);
|
||||
|
||||
if (window == NULL)
|
||||
goto out;
|
||||
|
||||
timestamp = meta_display_get_current_time_roundtrip (display);
|
||||
mouse_mode_focus (window, timestamp);
|
||||
|
||||
out:
|
||||
display->focus_timeout_id = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
if (display->focus_timeout_id != 0)
|
||||
g_source_remove (display->focus_timeout_id);
|
||||
|
||||
display->focus_timeout_id =
|
||||
g_timeout_add_full (G_PRIORITY_DEFAULT,
|
||||
FOCUS_TIMEOUT_DELAY,
|
||||
window_focus_on_pointer_rest_callback,
|
||||
focus_data,
|
||||
g_free);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* stop ignoring stuff */
|
||||
reset_ignored_crossing_serials (display);
|
||||
}
|
||||
break;
|
||||
case G_DESKTOP_FOCUS_MODE_CLICK:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -353,6 +353,11 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
|
||||
}
|
||||
|
||||
meta_wayland_pointer_get_relative_coordinates (pointer, surface, &sx, &sy);
|
||||
meta_window_handle_enter (surface->window,
|
||||
/* XXX -- can we reliably get a timestamp for setting focus? */
|
||||
clutter_get_current_event_time (),
|
||||
wl_fixed_to_int (pointer->x),
|
||||
wl_fixed_to_int (pointer->y));
|
||||
wl_pointer_send_enter (resource, serial, surface->resource, sx, sy);
|
||||
wl_resource_add_destroy_listener (resource, &pointer->focus_listener);
|
||||
pointer->focus_serial = serial;
|
||||
|
Loading…
Reference in New Issue
Block a user