aboutsummaryrefslogtreecommitdiff
path: root/sway/input/seatop_down.c
blob: b40773d01d95b387ed9e414f30fccf684d287c94 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#define _POSIX_C_SOURCE 200809L
#include <float.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_tablet_v2.h>
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
#include "sway/tree/view.h"
#include "sway/desktop/transaction.h"
#include "log.h"

struct seatop_down_event {
	struct sway_container *con;
	struct sway_seat *seat;
	struct wl_listener surface_destroy;
	struct wlr_surface *surface;
	double ref_lx, ref_ly;         // cursor's x/y at start of op
	double ref_con_lx, ref_con_ly; // container's x/y at start of op
};

static void handle_pointer_axis(struct sway_seat *seat,
		struct wlr_pointer_axis_event *event) {
	struct sway_input_device *input_device =
		event->pointer ? event->pointer->base.data : NULL;
	struct input_config *ic =
		input_device ? input_device_get_config(input_device) : NULL;
	float scroll_factor =
		(ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor;

	wlr_seat_pointer_notify_axis(seat->wlr_seat, event->time_msec,
		event->orientation, scroll_factor * event->delta,
		round(scroll_factor * event->delta_discrete), event->source);
}

static void handle_button(struct sway_seat *seat, uint32_t time_msec,
		struct wlr_input_device *device, uint32_t button,
		enum wlr_button_state state) {
	seat_pointer_notify_button(seat, time_msec, button, state);

	if (seat->cursor->pressed_button_count == 0) {
		seatop_begin_default(seat);
	}
}

static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
	struct seatop_down_event *e = seat->seatop_data;
	if (seat_is_input_allowed(seat, e->surface)) {
		double moved_x = seat->cursor->cursor->x - e->ref_lx;
		double moved_y = seat->cursor->cursor->y - e->ref_ly;
		double sx = e->ref_con_lx + moved_x;
		double sy = e->ref_con_ly + moved_y;
		wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy);
	}
}

static void handle_tablet_tool_tip(struct sway_seat *seat,
		struct sway_tablet_tool *tool, uint32_t time_msec,
		enum wlr_tablet_tool_tip_state state) {
	if (state == WLR_TABLET_TOOL_TIP_UP) {
		wlr_tablet_v2_tablet_tool_notify_up(tool->tablet_v2_tool);
		seatop_begin_default(seat);
	}
}

static void handle_tablet_tool_motion(struct sway_seat *seat,
		struct sway_tablet_tool *tool, uint32_t time_msec) {
	struct seatop_down_event *e = seat->seatop_data;
	if (seat_is_input_allowed(seat, e->surface)) {
		double moved_x = seat->cursor->cursor->x - e->ref_lx;
		double moved_y = seat->cursor->cursor->y - e->ref_ly;
		double sx = e->ref_con_lx + moved_x;
		double sy = e->ref_con_ly + moved_y;
		wlr_tablet_v2_tablet_tool_notify_motion(tool->tablet_v2_tool, sx, sy);
	}
}

static void handle_destroy(struct wl_listener *listener, void *data) {
	struct seatop_down_event *e =
		wl_container_of(listener, e, surface_destroy);
	if (e) {
		seatop_begin_default(e->seat);
	}
}

static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
	struct seatop_down_event *e = seat->seatop_data;
	if (e->con == con) {
		seatop_begin_default(seat);
	}
}

static void handle_end(struct sway_seat *seat) {
	struct seatop_down_event *e = seat->seatop_data;
	wl_list_remove(&e->surface_destroy.link);
}

static const struct sway_seatop_impl seatop_impl = {
	.button = handle_button,
	.pointer_motion = handle_pointer_motion,
	.pointer_axis = handle_pointer_axis,
	.tablet_tool_tip = handle_tablet_tool_tip,
	.tablet_tool_motion = handle_tablet_tool_motion,
	.unref = handle_unref,
	.end = handle_end,
	.allow_set_cursor = true,
};

void seatop_begin_down(struct sway_seat *seat, struct sway_container *con,
		uint32_t time_msec, double sx, double sy) {
	seatop_begin_down_on_surface(seat, con->view->surface, time_msec, sx, sy);
	struct seatop_down_event *e = seat->seatop_data;
	e->con = con;

	container_raise_floating(con);
	transaction_commit_dirty();
}

void seatop_begin_down_on_surface(struct sway_seat *seat,
		struct wlr_surface *surface, uint32_t time_msec, double sx, double sy) {
	seatop_end(seat);

	struct seatop_down_event *e =
		calloc(1, sizeof(struct seatop_down_event));
	if (!e) {
		return;
	}
	e->con = NULL;
	e->seat = seat;
	e->surface = surface;
	wl_signal_add(&e->surface->events.destroy, &e->surface_destroy);
	e->surface_destroy.notify = handle_destroy;
	e->ref_lx = seat->cursor->cursor->x;
	e->ref_ly = seat->cursor->cursor->y;
	e->ref_con_lx = sx;
	e->ref_con_ly = sy;

	seat->seatop_impl = &seatop_impl;
	seat->seatop_data = e;
}