Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/core/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "core/display-private.h"
#include "core/keybindings-private.h"
#include "core/window-private.h"
#include "core/zoom-grab.h"
#include "meta/meta-backend.h"

#ifdef HAVE_NATIVE_BACKEND
Expand Down Expand Up @@ -291,6 +292,10 @@ meta_display_handle_event (MetaDisplay *display,
meta_display_a11y_zoom (display, FALSE);
}

/* Hold an active pointer grab so subsequent scroll-valuator motion
* events in this gesture are captured and not delivered to clients. */
meta_zoom_pointer_grab_ensure (display, clutter_event_get_time (event));

bypass_wayland = bypass_clutter = TRUE;
goto out;
}
Expand Down
6 changes: 6 additions & 0 deletions src/core/keybindings-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ typedef struct
/* Alt+click button grabs */
ClutterModifierType window_grab_modifiers;
ClutterModifierType mouse_zoom_modifiers;

/* Active pointer grab held during a11y mouse-wheel zoom, so that
* scroll-valuator motion events are not delivered to client windows
* (passive button-4/5 grabs cannot intercept XI_Motion scroll events). */
gboolean zoom_pointer_grab_active;
guint zoom_pointer_grab_timeout_id;
} MetaKeyBindingManager;

void meta_display_init_keys (MetaDisplay *display);
Expand Down
3 changes: 3 additions & 0 deletions src/core/keybindings.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "core/edge-resistance.h"
#include "core/frame.h"
#include "core/keybindings-private.h"
#include "core/zoom-grab.h"
#include "core/meta-accel-parse.h"
#include "core/meta-workspace-manager-private.h"
#include "core/workspace-private.h"
Expand Down Expand Up @@ -1500,6 +1501,8 @@ meta_display_shutdown_keys (MetaDisplay *display)

meta_prefs_remove_listener (prefs_changed_callback, display);

meta_zoom_pointer_grab_release_all (display);

g_hash_table_destroy (keys->key_bindings_index);
g_hash_table_destroy (keys->key_bindings);

Expand Down
83 changes: 83 additions & 0 deletions src/core/zoom-grab.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Zoom pointer grab.
*
* Cinnamon's magnifier (Accessibility > Zoom) can be driven by holding a
* configurable modifier and turning the mouse wheel. On X11, scroll-valuator
* motion events are delivered directly to the client window under the pointer
* by the X server, so the magnified application keeps scrolling while the user
* is zooming. The passive button-4/5 grab in keybindings.c cannot intercept
* XI_Motion scroll events, so we hold a short-lived active pointer grab for
* the duration of the zoom gesture; an active grab captures all pointer
* events, including scroll-valuator motion. The grab is released shortly after
* the last zoom-scroll event so normal pointer interaction resumes promptly.
*/

#include "config.h"
#include "core/zoom-grab.h"
#include "core/keybindings-private.h"
#include "backends/meta-backend-private.h"
#include "meta/meta-backend.h"

#define ZOOM_GRAB_IDLE_MS 350

static gboolean
zoom_pointer_grab_release (gpointer user_data)
{
MetaDisplay *display = META_DISPLAY (user_data);
MetaKeyBindingManager *keys = &display->key_binding_manager;

if (keys->zoom_pointer_grab_active)
{
meta_backend_ungrab_device (meta_get_backend (),
META_VIRTUAL_CORE_POINTER_ID,
CLUTTER_CURRENT_TIME);
keys->zoom_pointer_grab_active = FALSE;
}

keys->zoom_pointer_grab_timeout_id = 0;
return G_SOURCE_REMOVE;
}

void
meta_zoom_pointer_grab_ensure (MetaDisplay *display,
uint32_t timestamp)
{
MetaKeyBindingManager *keys = &display->key_binding_manager;

if (meta_is_wayland_compositor ())
return;

if (!keys->zoom_pointer_grab_active)
{
keys->zoom_pointer_grab_active =
meta_backend_grab_device (meta_get_backend (),
META_VIRTUAL_CORE_POINTER_ID,
timestamp);
}

if (keys->zoom_pointer_grab_timeout_id)
g_source_remove (keys->zoom_pointer_grab_timeout_id);
keys->zoom_pointer_grab_timeout_id =
g_timeout_add_full (G_PRIORITY_DEFAULT, ZOOM_GRAB_IDLE_MS,
zoom_pointer_grab_release, display, NULL);
}

void
meta_zoom_pointer_grab_release_all (MetaDisplay *display)
{
MetaKeyBindingManager *keys = &display->key_binding_manager;

if (keys->zoom_pointer_grab_timeout_id)
{
g_source_remove (keys->zoom_pointer_grab_timeout_id);
keys->zoom_pointer_grab_timeout_id = 0;
}

if (keys->zoom_pointer_grab_active)
{
meta_backend_ungrab_device (meta_get_backend (),
META_VIRTUAL_CORE_POINTER_ID,
CLUTTER_CURRENT_TIME);
keys->zoom_pointer_grab_active = FALSE;
}
}
25 changes: 25 additions & 0 deletions src/core/zoom-grab.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Zoom pointer grab.
*
* Cinnamon's magnifier (Accessibility > Zoom) can be driven by holding a
* configurable modifier and turning the mouse wheel. On X11, scroll-valuator
* motion events are delivered directly to the client window under the pointer
* by the X server, so the magnified application keeps scrolling while the user
* is zooming. The passive button-4/5 grab in keybindings.c cannot intercept
* XI_Motion scroll events, so we hold a short-lived active pointer grab for
* the duration of the zoom gesture; an active grab captures all pointer
* events, including scroll-valuator motion. The grab is released shortly after
* the last zoom-scroll event so normal pointer interaction resumes promptly.
*/

#ifndef META_ZOOM_GRAB_H
#define META_ZOOM_GRAB_H

#include "core/display-private.h"

void meta_zoom_pointer_grab_ensure (MetaDisplay *display,
uint32_t timestamp);

void meta_zoom_pointer_grab_release_all (MetaDisplay *display);

#endif /* META_ZOOM_GRAB_H */
2 changes: 2 additions & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,8 @@ muffin_sources = [
'core/meta-accel-parse.c',
'core/meta-accel-parse.h',
'core/meta-anonymous-file.c',
'core/zoom-grab.c',
'core/zoom-grab.h',
'core/meta-anonymous-file.h',
'core/meta-border.c',
'core/meta-border.h',
Expand Down