Skip to content

Commit afa1401

Browse files
committed
feat: add scroller touchpad scroll
1 parent cd90465 commit afa1401

4 files changed

Lines changed: 142 additions & 0 deletions

File tree

include/scroller.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ void scroller_cycle_proportion_preset(client_t *client);
7575

7676
void scroller_apply_active_focus(desktop_t *d, struct output_t *m);
7777

78+
void scroller_view_offset_gesture_begin(desktop_t *d, bool is_touchpad);
79+
void scroller_view_offset_gesture_update(desktop_t *d, double delta_x);
80+
bool scroller_view_offset_gesture_end(desktop_t *d);
81+
7882
int scroller_collect(desktop_t *d, node_t ***out_nodes);
7983

8084
extern float scroller_default_proportion;

include/server.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ typedef struct server_t {
105105
struct wl_listener swipe_update;
106106
struct wl_listener swipe_end;
107107

108+
struct {
109+
bool ongoing;
110+
bool is_touchpad;
111+
} touchpad_scroll;
112+
108113
struct wlr_relative_pointer_manager_v1 *relative_pointer_manager;
109114
struct wlr_idle_notifier_v1 *idle_notifier;
110115

src/cursor.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "keyboard.h"
77
#include "layer.h"
88
#include "output.h"
9+
#include "scroller.h"
910
#include "seat.h"
1011
#include "server.h"
1112
#include "tablet.h"
@@ -974,6 +975,38 @@ void cursor_axis(struct wl_listener *listener, void *data) {
974975
}
975976
}
976977

978+
output_t *m = server.focused_output;
979+
desktop_t *d = m ? m->desk : NULL;
980+
bool is_touchpad = (event->source == WL_POINTER_AXIS_SOURCE_FINGER ||
981+
event->source == WL_POINTER_AXIS_SOURCE_CONTINUOUS);
982+
983+
// cancel any ongoing touchpad scroll gesture if the layout is not scroller
984+
if (server.touchpad_scroll.ongoing && (!d || d->layout != LAYOUT_SCROLLER))
985+
server.touchpad_scroll.ongoing = false;
986+
987+
// handle touchpad horizontal scrolling in the scroller layout
988+
if (d && d->layout == LAYOUT_SCROLLER && is_touchpad &&
989+
event->orientation == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
990+
if (!server.touchpad_scroll.ongoing) {
991+
server.touchpad_scroll.ongoing = true;
992+
server.touchpad_scroll.is_touchpad = is_touchpad;
993+
scroller_view_offset_gesture_begin(d, is_touchpad);
994+
}
995+
scroller_view_offset_gesture_update(d, event->delta);
996+
arrange(m, d, true);
997+
return;
998+
}
999+
1000+
// cancel any ongoing touchpad scroll gesture if this event is not a
1001+
// horizontal touchpad scroll
1002+
if (server.touchpad_scroll.ongoing) {
1003+
server.touchpad_scroll.ongoing = false;
1004+
if (d && d->layout == LAYOUT_SCROLLER) {
1005+
scroller_view_offset_gesture_end(d);
1006+
arrange(m, d, true);
1007+
}
1008+
}
1009+
9771010
wlr_seat_pointer_notify_axis(server.seat, event->time_msec, event->orientation, event->delta,
9781011
event->delta_discrete, event->source, event->relative_direction);
9791012
wlr_idle_notifier_v1_notify_activity(server.idle_notifier, server.seat);

src/scroller.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "scroller.h"
33
#include "toplevel.h"
44
#include "tree.h"
5+
#include <math.h>
56
#include <stdlib.h>
67
#include <string.h>
78
#include <wlr/types/wlr_xdg_shell.h>
@@ -458,6 +459,105 @@ void scroller_apply_active_focus(desktop_t *d, struct output_t *m) {
458459
}
459460
}
460461

462+
463+
#define VIEW_GESTURE_WORKING_AREA_MOVEMENT 300.
464+
465+
void scroller_view_offset_gesture_begin(desktop_t *d, bool is_touchpad) {
466+
scroller_state_t *s = d ? d->scroller_state : NULL;
467+
if (!s || s->column_count == 0)
468+
return;
469+
s->view_offset = 0.0;
470+
(void)is_touchpad;
471+
}
472+
473+
void scroller_view_offset_gesture_update(desktop_t *d, double delta_x) {
474+
scroller_state_t *s = d ? d->scroller_state : NULL;
475+
if (!s || s->column_count == 0)
476+
return;
477+
478+
double gap = (double)compute_window_gap(d);
479+
if (gap < 0)
480+
gap = 0.0;
481+
482+
double area_w = (double)s->working_area.width;
483+
double norm_factor = area_w / VIEW_GESTURE_WORKING_AREA_MOVEMENT;
484+
if (norm_factor < 5.0)
485+
norm_factor = 5.0;
486+
487+
double delta = delta_x * norm_factor;
488+
489+
double *col_xs = malloc((size_t)(s->column_count + 1) * sizeof(*col_xs));
490+
if (!col_xs)
491+
return;
492+
493+
double wx = 0.0;
494+
for (int i = 0; i < s->column_count; i++) {
495+
col_xs[i] = wx;
496+
wx += s->columns[i].resolved_width + gap;
497+
}
498+
col_xs[s->column_count] = wx;
499+
500+
double active_col_x = col_xs[s->active_column_idx];
501+
double total_width = col_xs[s->column_count];
502+
double min_offset = -active_col_x;
503+
double max_offset = total_width - active_col_x - area_w;
504+
505+
s->view_offset += delta;
506+
if (s->view_offset < min_offset)
507+
s->view_offset = min_offset;
508+
if (s->view_offset > max_offset)
509+
s->view_offset = max_offset;
510+
511+
free(col_xs);
512+
}
513+
514+
bool scroller_view_offset_gesture_end(desktop_t *d) {
515+
scroller_state_t *s = d ? d->scroller_state : NULL;
516+
if (!s || s->column_count == 0)
517+
return false;
518+
519+
double gap = (double)compute_window_gap(d);
520+
if (gap < 0)
521+
gap = 0.0;
522+
523+
/* compute column x positions */
524+
double *col_xs = malloc((size_t)(s->column_count + 1) * sizeof(*col_xs));
525+
if (!col_xs)
526+
return false;
527+
528+
double wx = 0.0;
529+
for (int i = 0; i < s->column_count; i++) {
530+
col_xs[i] = wx;
531+
wx += s->columns[i].resolved_width + gap;
532+
}
533+
col_xs[s->column_count] = wx;
534+
535+
double active_col_x = col_xs[s->active_column_idx];
536+
double view_pos = active_col_x + s->view_offset;
537+
538+
int nearest = s->active_column_idx;
539+
double nearest_dist = fabs(view_pos - active_col_x);
540+
for (int i = 0; i < s->column_count; i++) {
541+
double dist = fabs(view_pos - col_xs[i]);
542+
if (dist < nearest_dist) {
543+
nearest_dist = dist;
544+
nearest = i;
545+
}
546+
}
547+
548+
free(col_xs);
549+
550+
if (nearest != s->active_column_idx) {
551+
s->active_column_idx = nearest;
552+
s->view_offset = 0.0;
553+
s->activate_prev_column_on_removal = false;
554+
return true;
555+
}
556+
557+
s->view_offset = 0.0;
558+
return true;
559+
}
560+
461561
bool scroller_focus_next(desktop_t *d) {
462562
scroller_state_t *s = d->scroller_state;
463563
if (!s || s->column_count == 0)

0 commit comments

Comments
 (0)