Implement high precision scrolling with the trackpad on platforms such as macOS and Wayland that implement it.

Fixes #819. Note that I have no idea whether the code works well on
retina screens, might have to multiple the pixel count by the scale
factor on those screens?
This commit is contained in:
Kovid Goyal 2018-08-24 11:00:58 +05:30
parent 0e0e25f986
commit 009ef54de7
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
13 changed files with 56 additions and 46 deletions

View File

@ -20,6 +20,9 @@ Changelog
- Add an option :opt:`env` to set environment variables in child processes
from kitty.conf
- Implement high precision scrolling with the trackpad on platforms such as
macOS and Wayland that implement it. (:pull:`819`)
- macOS: Allow scrolling window contents using mouse wheel/trackpad even when the
window is not the active window (:iss:`729`)

View File

@ -884,15 +884,10 @@ is_ascii_control_char(char x) {
deltaX = [event scrollingDeltaX];
deltaY = [event scrollingDeltaY];
if ([event hasPreciseScrollingDeltas])
{
deltaX *= 0.1;
deltaY *= 0.1;
}
int flags = [event hasPreciseScrollingDeltas] ? 1 : 0;
if (fabs(deltaX) > 0.0 || fabs(deltaY) > 0.0)
_glfwInputScroll(window, deltaX, deltaY);
_glfwInputScroll(window, deltaX, deltaY, flags);
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender

4
glfw/glfw3.h vendored
View File

@ -1372,15 +1372,17 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
* @param[in] window The window that received the event.
* @param[in] xoffset The scroll offset along the x-axis.
* @param[in] yoffset The scroll offset along the y-axis.
* @param[in] flags A bit-mask providing extra data about the event. flags & 1 will be true if and only if the offset values are "high-precision". Typically pixel values. Otherwise the offset values are number of lines.
*
* @sa @ref scrolling
* @sa @ref glfwSetScrollCallback
*
* @since Added in version 3.0. Replaces `GLFWmousewheelfun`.
* @since Changed in version 4.0. Added `flags` parameter.
*
* @ingroup input
*/
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double);
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int);
/*! @brief The function signature for key callbacks.
*

4
glfw/input.c vendored
View File

@ -286,10 +286,10 @@ void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action,
// Notifies shared code of a scroll event
//
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags)
{
if (window->callbacks.scroll)
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset);
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags);
}
// Notifies shared code of a mouse button click event

2
glfw/internal.h vendored
View File

@ -717,7 +717,7 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window);
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state);
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset);
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags);
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered);

11
glfw/wl_init.c vendored
View File

@ -319,11 +319,6 @@ static void pointerHandleAxis(void* data,
{
_GLFWwindow* window = _glfw.wl.pointerFocus;
double x = 0.0, y = 0.0;
// Wayland scroll events are in pointer motion coordinate space (think two
// finger scroll). The factor 10 is commonly used to convert to "scroll
// step means 1.0.
const double scrollFactor = 1.0 / 10.0;
if (!window)
return;
@ -331,11 +326,11 @@ static void pointerHandleAxis(void* data,
axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
x = wl_fixed_to_double(value) * scrollFactor;
x = wl_fixed_to_double(value) * -1;
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
y = wl_fixed_to_double(value) * scrollFactor;
y = wl_fixed_to_double(value) * -1;
_glfwInputScroll(window, x, y);
_glfwInputScroll(window, x, y, 1);
}
static const struct wl_pointer_listener pointerListener = {

8
glfw/x11_window.c vendored
View File

@ -1309,13 +1309,13 @@ static void processEvent(XEvent *event)
// Modern X provides scroll events as mouse button presses
else if (event->xbutton.button == Button4)
_glfwInputScroll(window, 0.0, 1.0);
_glfwInputScroll(window, 0.0, 1.0, 0);
else if (event->xbutton.button == Button5)
_glfwInputScroll(window, 0.0, -1.0);
_glfwInputScroll(window, 0.0, -1.0, 0);
else if (event->xbutton.button == Button6)
_glfwInputScroll(window, 1.0, 0.0);
_glfwInputScroll(window, 1.0, 0.0, 0);
else if (event->xbutton.button == Button7)
_glfwInputScroll(window, -1.0, 0.0);
_glfwInputScroll(window, -1.0, 0.0, 0);
else
{

View File

@ -302,8 +302,9 @@ INPUT_LINE_NUMBER in the command line above will be replaced by an integer
representing which line should be at the top of the screen.'''))
o('wheel_scroll_multiplier', 5.0, long_text=_('''
Modify the amount scrolled by the mouse wheel or touchpad. Use
negative numbers to change scroll direction.'''))
Modify the amount scrolled by the mouse wheel. Note this is only used for low
precision scrolling devices, not for high precision scrolling on platforms such
as macOS and Wayland. Use negative numbers to change scroll direction.'''))
# }}}
g('mouse') # {{{

View File

@ -284,7 +284,7 @@ void enter_event();
void mouse_event(int, int);
void focus_in_event();
void wakeup_io_loop(bool);
void scroll_event(double, double);
void scroll_event(double, double, int);
void fake_scroll(int, bool);
void set_special_key_combo(int glfw_key, int mods, bool is_native);
void on_key_input(int key, int scancode, int action, int mods, const char*, int);

2
kitty/glfw-wrapper.h generated
View File

@ -1141,7 +1141,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
*
* @ingroup input
*/
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double);
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int);
/*! @brief The function signature for key callbacks.
*

View File

@ -178,12 +178,12 @@ cursor_pos_callback(GLFWwindow *w, double x, double y) {
}
static void
scroll_callback(GLFWwindow *w, double xoffset, double yoffset) {
scroll_callback(GLFWwindow *w, double xoffset, double yoffset, int flags) {
if (!set_callback_window(w)) return;
show_mouse_cursor(w);
double now = monotonic();
global_state.callback_os_window->last_mouse_activity_at = now;
if (is_window_ready_for_callbacks()) scroll_event(xoffset, yoffset);
if (is_window_ready_for_callbacks()) scroll_event(xoffset, yoffset, flags);
global_state.callback_os_window = NULL;
}

View File

@ -527,13 +527,7 @@ mouse_event(int button, int modifiers) {
}
void
scroll_event(double UNUSED xoffset, double yoffset) {
// glfw inverts the y-axis when reporting scroll events under wayland
// Until this is fixed in upstream, invert y ourselves.
if (global_state.is_wayland) yoffset *= -1;
int s = (int) round(yoffset * OPT(wheel_scroll_multiplier));
if (s == 0) return;
bool upwards = s > 0;
scroll_event(double UNUSED xoffset, double yoffset, int flags) {
bool in_tab_bar;
unsigned int window_idx = 0;
Window *w = window_for_event(&window_idx, &in_tab_bar);
@ -544,17 +538,36 @@ scroll_event(double UNUSED xoffset, double yoffset) {
Tab *t = global_state.callback_os_window->tabs + global_state.callback_os_window->active_tab;
if (t) w = t->windows + t->active_window;
}
if (w) {
Screen *screen = w->render_data.screen;
if (screen->linebuf == screen->main_linebuf) {
screen_history_scroll(screen, abs(s), upwards);
if (!w) return;
int s;
if (flags & 1) {
if (yoffset * global_state.callback_os_window->pending_scroll_pixels < 0) {
global_state.callback_os_window->pending_scroll_pixels = 0; // change of direction
}
double pixels = global_state.callback_os_window->pending_scroll_pixels + yoffset;
if (fabs(pixels) < global_state.callback_os_window->fonts_data->cell_height) {
global_state.callback_os_window->pending_scroll_pixels = pixels;
return;
}
s = abs(((int)round(pixels))) / global_state.callback_os_window->fonts_data->cell_height;
if (pixels < 0) s *= -1;
global_state.callback_os_window->pending_scroll_pixels = pixels - s;
} else {
s = (int) round(yoffset * OPT(wheel_scroll_multiplier));
global_state.callback_os_window->pending_scroll_pixels = 0;
}
if (s == 0) return;
bool upwards = s > 0;
Screen *screen = w->render_data.screen;
if (screen->linebuf == screen->main_linebuf) {
screen_history_scroll(screen, abs(s), upwards);
} else {
if (screen->modes.mouse_tracking_mode) {
int sz = encode_mouse_event(w, upwards ? GLFW_MOUSE_BUTTON_4 : GLFW_MOUSE_BUTTON_5, PRESS, 0);
if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); }
} else {
if (screen->modes.mouse_tracking_mode) {
int sz = encode_mouse_event(w, upwards ? GLFW_MOUSE_BUTTON_4 : GLFW_MOUSE_BUTTON_5, PRESS, 0);
if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); }
} else {
fake_scroll(abs(s), upwards);
}
fake_scroll(abs(s), upwards);
}
}
}

View File

@ -124,6 +124,7 @@ typedef struct {
float background_opacity;
FONTS_DATA_HANDLE fonts_data;
id_type temp_font_group_id;
double pending_scroll_pixels;
} OSWindow;