mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2026-03-22 08:51:31 +00:00
Compare commits
4 Commits
22c114606f
...
58e371fcb3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58e371fcb3 | ||
|
|
898bc7a946 | ||
|
|
507f76f981 | ||
|
|
97b9dbc1e6 |
31
patches/bar-modes/README.md
Normal file
31
patches/bar-modes/README.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|

|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
Add a mode indicator to bar that tells which mode you are in, just like
|
||||||
|
river-classic's [dam](https://codeberg.org/sewn/dam) bar.
|
||||||
|
|
||||||
|
The string from `modes_labels` defined in `config.h` is used, while normal mode
|
||||||
|
is ignored.
|
||||||
|
|
||||||
|
Another usage is to serve as a hint for each modes keybindings:
|
||||||
|
|
||||||
|
```c
|
||||||
|
enum {
|
||||||
|
BROWSER,
|
||||||
|
};
|
||||||
|
const char *modes_lablels[] = {
|
||||||
|
"[f]irefox [b]rave [c]hromium [q]utebrowser",
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
this patch depends on:
|
||||||
|
- [bar](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/bar/) patch
|
||||||
|
- [modes](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/modes/) patch
|
||||||
|
|
||||||
|
### Download
|
||||||
|
- [v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/bar-modes/bar-modes.patch)
|
||||||
|
|
||||||
|
### Authors
|
||||||
|
- [unixchad](https://codeberg.org/unixchad/)
|
||||||
131
patches/bar-modes/bar-modes.patch
Normal file
131
patches/bar-modes/bar-modes.patch
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
From 4f2c8a99720d90a551bf38f2c8d25ad239346eef Mon Sep 17 00:00:00 2001
|
||||||
|
From: nate zhou <gnuunixchad@outlook.com>
|
||||||
|
Date: Mon, 2 Mar 2026 21:54:03 +0800
|
||||||
|
Subject: [PATCH] Patch: bar-modes for 0.8
|
||||||
|
|
||||||
|
Add modes_labels indicator to bar, which behaves like river-classic's
|
||||||
|
dam bar. This patch has to be applied after the bar and modes patch.
|
||||||
|
---
|
||||||
|
dwl.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++----------
|
||||||
|
1 file changed, 59 insertions(+), 11 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/dwl.c b/dwl.c
|
||||||
|
index ae290ad..df525d3 100644
|
||||||
|
--- a/dwl.c
|
||||||
|
+++ b/dwl.c
|
||||||
|
@@ -1585,19 +1585,26 @@ drawbar(Monitor *m)
|
||||||
|
uint32_t i, occ = 0, urg = 0;
|
||||||
|
Client *c;
|
||||||
|
Buffer *buf;
|
||||||
|
+ char mode_text[256] = "";
|
||||||
|
+ int mode_width = 0;
|
||||||
|
|
||||||
|
if (!m->scene_buffer->node.enabled)
|
||||||
|
return;
|
||||||
|
if (!(buf = bufmon(m)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
- /* draw status first so it can be overdrawn by tags later */
|
||||||
|
- if (m == selmon) { /* status is only drawn on selected monitor */
|
||||||
|
- drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||||
|
- tw = TEXTW(m, stext) - m->lrpad + 2; /* 2px right padding */
|
||||||
|
- drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0);
|
||||||
|
+ /* get current mode text if in a mode (not normal) */
|
||||||
|
+ if (active_mode_index >= 0 && active_mode_index < LENGTH(modes_labels) &&
|
||||||
|
+ modes_labels[active_mode_index]) {
|
||||||
|
+ strncpy(mode_text, modes_labels[active_mode_index], sizeof(mode_text) - 1);
|
||||||
|
+ mode_text[sizeof(mode_text) - 1] = '\0';
|
||||||
|
+ mode_width = TEXTW(m, mode_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* calculate status text width */
|
||||||
|
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||||
|
+ tw = TEXTW(m, stext) - m->lrpad + 2;
|
||||||
|
+
|
||||||
|
wl_list_for_each(c, &clients, link) {
|
||||||
|
if (c->mon != m)
|
||||||
|
continue;
|
||||||
|
@@ -1607,6 +1614,8 @@ drawbar(Monitor *m)
|
||||||
|
}
|
||||||
|
x = 0;
|
||||||
|
c = focustop(m);
|
||||||
|
+
|
||||||
|
+ /* draw tags (always shown) */
|
||||||
|
for (i = 0; i < LENGTH(tags); i++) {
|
||||||
|
w = TEXTW(m, tags[i]);
|
||||||
|
drwl_setscheme(m->drw, colors[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
|
||||||
|
@@ -1617,19 +1626,57 @@ drawbar(Monitor *m)
|
||||||
|
urg & 1 << i);
|
||||||
|
x += w;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ /* draw mode indicator after tags if in a mode */
|
||||||
|
+ if (mode_text[0]) {
|
||||||
|
+ drwl_setscheme(m->drw, colors[SchemeSel]);
|
||||||
|
+ drwl_text(m->drw, x, 0, mode_width, m->b.height, m->lrpad / 2, mode_text, 0);
|
||||||
|
+ x += mode_width;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* draw layout symbol after mode */
|
||||||
|
w = TEXTW(m, m->ltsymbol);
|
||||||
|
drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||||
|
- x = drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0);
|
||||||
|
+ drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, m->ltsymbol, 0);
|
||||||
|
+ x += w;
|
||||||
|
+
|
||||||
|
+ int remaining = m->b.width - x;
|
||||||
|
|
||||||
|
- if ((w = m->b.width - tw - x) > m->b.height) {
|
||||||
|
- if (c) {
|
||||||
|
+ if (mode_text[0]) {
|
||||||
|
+ int title_width = remaining;
|
||||||
|
+
|
||||||
|
+ if (title_width > m->b.height && c) {
|
||||||
|
drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]);
|
||||||
|
- drwl_text(m->drw, x, 0, w, m->b.height, m->lrpad / 2, client_get_title(c), 0);
|
||||||
|
+ drwl_text(m->drw, x, 0, title_width, m->b.height, m->lrpad / 2,
|
||||||
|
+ client_get_title(c), 0);
|
||||||
|
if (c && c->isfloating)
|
||||||
|
drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
|
||||||
|
- } else {
|
||||||
|
+ } else if (title_width > 0) {
|
||||||
|
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||||
|
+ drwl_rect(m->drw, x, 0, title_width, m->b.height, 1, 1);
|
||||||
|
+ }
|
||||||
|
+ /* no status text when in a mode - completely omitted */
|
||||||
|
+ } else {
|
||||||
|
+ /* not in a mode - normal behavior with status */
|
||||||
|
+ if (remaining >= tw) {
|
||||||
|
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||||
|
+ drwl_text(m->drw, m->b.width - tw, 0, tw, m->b.height, 0, stext, 0);
|
||||||
|
+
|
||||||
|
+ int title_space = remaining - tw;
|
||||||
|
+ if (title_space > m->b.height && c) {
|
||||||
|
+ drwl_setscheme(m->drw, colors[m == selmon ? SchemeSel : SchemeNorm]);
|
||||||
|
+ drwl_text(m->drw, x, 0, title_space, m->b.height, m->lrpad / 2,
|
||||||
|
+ client_get_title(c), 0);
|
||||||
|
+ if (c && c->isfloating)
|
||||||
|
+ drwl_rect(m->drw, x + boxs, boxs, boxw, boxw, 0, 0);
|
||||||
|
+ } else if (title_space > 0) {
|
||||||
|
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||||
|
+ drwl_rect(m->drw, x, 0, title_space, m->b.height, 1, 1);
|
||||||
|
+ }
|
||||||
|
+ } else if (remaining > 0) {
|
||||||
|
drwl_setscheme(m->drw, colors[SchemeNorm]);
|
||||||
|
- drwl_rect(m->drw, x, 0, w, m->b.height, 1, 1);
|
||||||
|
+ drwl_text(m->drw, m->b.width - remaining, 0, remaining, m->b.height, 0,
|
||||||
|
+ stext, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -3437,6 +3484,7 @@ entermode(const Arg *arg)
|
||||||
|
{
|
||||||
|
active_mode_index = arg->i;
|
||||||
|
printstatus();
|
||||||
|
+ drawbars();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
--
|
||||||
|
2.53.0
|
||||||
|
|
||||||
BIN
patches/bar-modes/example.png
Normal file
BIN
patches/bar-modes/example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
15
patches/hide-cursor-when-typing/README.md
Normal file
15
patches/hide-cursor-when-typing/README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
### Description
|
||||||
|
|
||||||
|
Hide the mouse cursor when you start typing, and restore it again when the
|
||||||
|
mouse cursor moves or a mouse button is pressed, just like
|
||||||
|
[xbanish](https://github.com/jcs/xbanish).
|
||||||
|
|
||||||
|
### credits
|
||||||
|
Some code is taken from the
|
||||||
|
[unclutter](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/unclutter) patch.
|
||||||
|
|
||||||
|
### Download
|
||||||
|
[v0.8](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/hide-cursor-when-typing/hide-cursor-when-typing.patch)
|
||||||
|
|
||||||
|
### Authors
|
||||||
|
- [unixchad](https://codeberg.org/unixchad/)
|
||||||
170
patches/hide-cursor-when-typing/hide-cursor-when-typing.patch
Normal file
170
patches/hide-cursor-when-typing/hide-cursor-when-typing.patch
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
From c72de058e6635c5bb3d973995ccbdb6e028f354d Mon Sep 17 00:00:00 2001
|
||||||
|
From: nate zhou <gnuunixchad@outlook.com>
|
||||||
|
Date: Tue, 3 Mar 2026 16:48:46 +0800
|
||||||
|
Subject: [PATCH] Patch: hide-cursor-when-typing-0.8.patch
|
||||||
|
|
||||||
|
Hide the cursor when start typing, and restore it when start moving
|
||||||
|
cursor again, just like xbanish.
|
||||||
|
---
|
||||||
|
config.def.h | 2 ++
|
||||||
|
dwl.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++------
|
||||||
|
2 files changed, 63 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 8a6eda0..6205c0a 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -102,6 +102,8 @@ LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
|
||||||
|
*/
|
||||||
|
static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
|
||||||
|
|
||||||
|
+static const int hide_cursor_when_typing = 1;
|
||||||
|
+
|
||||||
|
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
|
||||||
|
#define MODKEY WLR_MODIFIER_ALT
|
||||||
|
|
||||||
|
diff --git a/dwl.c b/dwl.c
|
||||||
|
index 44f3ad9..9a076b6 100644
|
||||||
|
--- a/dwl.c
|
||||||
|
+++ b/dwl.c
|
||||||
|
@@ -289,6 +289,8 @@ static Client *focustop(Monitor *m);
|
||||||
|
static void fullscreennotify(struct wl_listener *listener, void *data);
|
||||||
|
static void gpureset(struct wl_listener *listener, void *data);
|
||||||
|
static void handlesig(int signo);
|
||||||
|
+static void handlecursoractivity(void);
|
||||||
|
+static int hidecursor(void *data);
|
||||||
|
static void incnmaster(const Arg *arg);
|
||||||
|
static void inputdevice(struct wl_listener *listener, void *data);
|
||||||
|
static int keybinding(uint32_t mods, xkb_keysym_t sym);
|
||||||
|
@@ -389,6 +391,14 @@ static struct wlr_pointer_constraint_v1 *active_constraint;
|
||||||
|
|
||||||
|
static struct wlr_cursor *cursor;
|
||||||
|
static struct wlr_xcursor_manager *cursor_mgr;
|
||||||
|
+static struct wl_event_source *hide_source;
|
||||||
|
+static bool cursor_hidden = false;
|
||||||
|
+static struct {
|
||||||
|
+ enum wp_cursor_shape_device_v1_shape shape;
|
||||||
|
+ struct wlr_surface *surface;
|
||||||
|
+ int hotspot_x;
|
||||||
|
+ int hotspot_y;
|
||||||
|
+} last_cursor;
|
||||||
|
|
||||||
|
static struct wlr_scene_rect *root_bg;
|
||||||
|
static struct wlr_session_lock_manager_v1 *session_lock_mgr;
|
||||||
|
@@ -610,6 +620,7 @@ axisnotify(struct wl_listener *listener, void *data)
|
||||||
|
* for example when you move the scroll wheel. */
|
||||||
|
struct wlr_pointer_axis_event *event = data;
|
||||||
|
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||||
|
+ handlecursoractivity();
|
||||||
|
/* TODO: allow usage of scroll wheel for mousebindings, it can be implemented
|
||||||
|
* by checking the event's orientation and the delta of the event */
|
||||||
|
/* Notify the client with pointer focus of the axis event. */
|
||||||
|
@@ -628,6 +639,7 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||||
|
const Button *b;
|
||||||
|
|
||||||
|
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||||
|
+ handlecursoractivity();
|
||||||
|
|
||||||
|
switch (event->state) {
|
||||||
|
case WL_POINTER_BUTTON_STATE_PRESSED:
|
||||||
|
@@ -1566,6 +1578,30 @@ handlesig(int signo)
|
||||||
|
quit(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
+void
|
||||||
|
+handlecursoractivity(void)
|
||||||
|
+{
|
||||||
|
+ if (!cursor_hidden)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ cursor_hidden = false;
|
||||||
|
+
|
||||||
|
+ if (last_cursor.shape)
|
||||||
|
+ wlr_cursor_set_xcursor(cursor, cursor_mgr,
|
||||||
|
+ wlr_cursor_shape_v1_name(last_cursor.shape));
|
||||||
|
+ else
|
||||||
|
+ wlr_cursor_set_surface(cursor, last_cursor.surface,
|
||||||
|
+ last_cursor.hotspot_x, last_cursor.hotspot_y);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int
|
||||||
|
+hidecursor(void *data)
|
||||||
|
+{
|
||||||
|
+ wlr_cursor_unset_image(cursor);
|
||||||
|
+ cursor_hidden = true;
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
incnmaster(const Arg *arg)
|
||||||
|
{
|
||||||
|
@@ -1645,6 +1681,11 @@ keypress(struct wl_listener *listener, void *data)
|
||||||
|
|
||||||
|
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||||
|
|
||||||
|
+ /* hide cursor when typing starts */
|
||||||
|
+ if (hide_cursor_when_typing && !cursor_hidden && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
|
+ hidecursor(NULL);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* On _press_ if there is no active screen locker,
|
||||||
|
* attempt to process a compositor keybinding. */
|
||||||
|
if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
|
@@ -1907,6 +1948,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||||
|
|
||||||
|
wlr_cursor_move(cursor, device, dx, dy);
|
||||||
|
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
||||||
|
+ handlecursoractivity();
|
||||||
|
|
||||||
|
/* Update selmon (even while dragging a window) */
|
||||||
|
if (sloppyfocus)
|
||||||
|
@@ -1931,7 +1973,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
|
||||||
|
/* If there's no client surface under the cursor, set the cursor image to a
|
||||||
|
* default. This is what makes the cursor image appear when you move it
|
||||||
|
* off of a client or over its border. */
|
||||||
|
- if (!surface && !seat->drag)
|
||||||
|
+ if (!surface && !seat->drag && !cursor_hidden)
|
||||||
|
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||||
|
|
||||||
|
pointerfocus(c, surface, sx, sy, time);
|
||||||
|
@@ -2311,9 +2353,16 @@ setcursor(struct wl_listener *listener, void *data)
|
||||||
|
* use the provided surface as the cursor image. It will set the
|
||||||
|
* hardware cursor on the output that it's currently on and continue to
|
||||||
|
* do so as the cursor moves between outputs. */
|
||||||
|
- if (event->seat_client == seat->pointer_state.focused_client)
|
||||||
|
- wlr_cursor_set_surface(cursor, event->surface,
|
||||||
|
- event->hotspot_x, event->hotspot_y);
|
||||||
|
+ if (event->seat_client == seat->pointer_state.focused_client) {
|
||||||
|
+ last_cursor.shape = 0;
|
||||||
|
+ last_cursor.surface = event->surface;
|
||||||
|
+ last_cursor.hotspot_x = event->hotspot_x;
|
||||||
|
+ last_cursor.hotspot_y = event->hotspot_y;
|
||||||
|
+
|
||||||
|
+ if (!cursor_hidden)
|
||||||
|
+ wlr_cursor_set_surface(cursor, event->surface,
|
||||||
|
+ event->hotspot_x, event->hotspot_y);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
@@ -2325,9 +2374,14 @@ setcursorshape(struct wl_listener *listener, void *data)
|
||||||
|
/* This can be sent by any client, so we check to make sure this one
|
||||||
|
* actually has pointer focus first. If so, we can tell the cursor to
|
||||||
|
* use the provided cursor shape. */
|
||||||
|
- if (event->seat_client == seat->pointer_state.focused_client)
|
||||||
|
- wlr_cursor_set_xcursor(cursor, cursor_mgr,
|
||||||
|
- wlr_cursor_shape_v1_name(event->shape));
|
||||||
|
+ if (event->seat_client == seat->pointer_state.focused_client) {
|
||||||
|
+ last_cursor.shape = event->shape;
|
||||||
|
+ last_cursor.surface = NULL;
|
||||||
|
+
|
||||||
|
+ if (!cursor_hidden)
|
||||||
|
+ wlr_cursor_set_xcursor(cursor, cursor_mgr,
|
||||||
|
+ wlr_cursor_shape_v1_name(event->shape));
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
--
|
||||||
|
2.53.0
|
||||||
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
### Description
|
|
||||||
This combines
|
|
||||||
[tablet-input](../tablet-input) and
|
|
||||||
[touch-input](../touch-input)
|
|
||||||
into a single appliable patch.
|
|
||||||
The two patches modify similar code areas in `dwl.c` and will conflict if one attempts to direcly apply both.
|
|
||||||
|
|
||||||
|
|
||||||
### Download
|
|
||||||
- [tablet-and-touch-wlroots-next-f4249db.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-and-touch/tablet-and-touch-wlroots-next-f4249db.patch)
|
|
||||||
- [tablet-and-touch-0.8.patch](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-and-touch/tablet-and-touch-0.8.patch)
|
|
||||||
### Authors
|
|
||||||
- [fauxmight](https://codeberg.org/fauxmight)
|
|
||||||
@ -1,584 +0,0 @@
|
|||||||
From f0f797f8abebc4624c7e6bdfbb1ec2a3122f3914 Mon Sep 17 00:00:00 2001
|
|
||||||
From: A Frederick Christensen <dwl@ivories.org>
|
|
||||||
Date: Thu, 26 Feb 2026 23:20:03 -0600
|
|
||||||
Subject: [PATCH] Apply tablet-and-touch patch
|
|
||||||
|
|
||||||
---
|
|
||||||
Makefile | 6 +-
|
|
||||||
config.def.h | 1 +
|
|
||||||
dwl.c | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
3 files changed, 404 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/Makefile b/Makefile
|
|
||||||
index 578194f..e0d1835 100644
|
|
||||||
--- a/Makefile
|
|
||||||
+++ b/Makefile
|
|
||||||
@@ -21,7 +21,8 @@ dwl: dwl.o util.o
|
|
||||||
$(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
|
||||||
dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
|
|
||||||
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
|
||||||
- wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
|
||||||
+ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \
|
|
||||||
+ tablet-v2-protocol.h
|
|
||||||
util.o: util.c util.h
|
|
||||||
|
|
||||||
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
|
||||||
@@ -45,6 +46,9 @@ wlr-output-power-management-unstable-v1-protocol.h:
|
|
||||||
xdg-shell-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
|
||||||
+tablet-v2-protocol.h:
|
|
||||||
+ $(WAYLAND_SCANNER) server-header \
|
|
||||||
+ $(WAYLAND_PROTOCOLS)/unstable/tablet/tablet-unstable-v2.xml $@
|
|
||||||
|
|
||||||
config.h:
|
|
||||||
cp config.def.h $@
|
|
||||||
diff --git a/config.def.h b/config.def.h
|
|
||||||
index 8a6eda0..1f20dfd 100644
|
|
||||||
--- a/config.def.h
|
|
||||||
+++ b/config.def.h
|
|
||||||
@@ -4,6 +4,7 @@
|
|
||||||
((hex >> 8) & 0xFF) / 255.0f, \
|
|
||||||
(hex & 0xFF) / 255.0f }
|
|
||||||
/* appearance */
|
|
||||||
+static const int tabletmaptosurface = 0; /* map tablet input to surface(1) or monitor(0) */
|
|
||||||
static const int sloppyfocus = 1; /* focus follows mouse */
|
|
||||||
static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
|
|
||||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
|
||||||
diff --git a/dwl.c b/dwl.c
|
|
||||||
index 44f3ad9..5ed467d 100644
|
|
||||||
--- a/dwl.c
|
|
||||||
+++ b/dwl.c
|
|
||||||
@@ -51,6 +51,10 @@
|
|
||||||
#include <wlr/types/wlr_session_lock_v1.h>
|
|
||||||
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
|
|
||||||
#include <wlr/types/wlr_subcompositor.h>
|
|
||||||
+#include <wlr/types/wlr_tablet_pad.h>
|
|
||||||
+#include <wlr/types/wlr_tablet_tool.h>
|
|
||||||
+#include <wlr/types/wlr_tablet_v2.h>
|
|
||||||
+#include <wlr/types/wlr_touch.h>
|
|
||||||
#include <wlr/types/wlr_viewporter.h>
|
|
||||||
#include <wlr/types/wlr_virtual_keyboard_v1.h>
|
|
||||||
#include <wlr/types/wlr_virtual_pointer_v1.h>
|
|
||||||
@@ -161,6 +165,12 @@ typedef struct {
|
|
||||||
struct wl_listener destroy;
|
|
||||||
} KeyboardGroup;
|
|
||||||
|
|
||||||
+typedef struct TouchGroup {
|
|
||||||
+ struct wl_list link;
|
|
||||||
+ struct wlr_touch *touch;
|
|
||||||
+ Monitor *m;
|
|
||||||
+} TouchGroup;
|
|
||||||
+
|
|
||||||
typedef struct {
|
|
||||||
/* Must keep this field first */
|
|
||||||
unsigned int type; /* LayerShell */
|
|
||||||
@@ -268,7 +278,10 @@ static void createnotify(struct wl_listener *listener, void *data);
|
|
||||||
static void createpointer(struct wlr_pointer *pointer);
|
|
||||||
static void createpointerconstraint(struct wl_listener *listener, void *data);
|
|
||||||
static void createpopup(struct wl_listener *listener, void *data);
|
|
||||||
+static void createtablet(struct wlr_input_device *device);
|
|
||||||
+static void createtouch(struct wlr_touch *touch);
|
|
||||||
static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
|
|
||||||
+static void createtouch(struct wlr_touch *touch);
|
|
||||||
static void cursorframe(struct wl_listener *listener, void *data);
|
|
||||||
static void cursorwarptohint(void);
|
|
||||||
static void destroydecoration(struct wl_listener *listener, void *data);
|
|
||||||
@@ -281,6 +294,9 @@ static void destroynotify(struct wl_listener *listener, void *data);
|
|
||||||
static void destroypointerconstraint(struct wl_listener *listener, void *data);
|
|
||||||
static void destroysessionlock(struct wl_listener *listener, void *data);
|
|
||||||
static void destroykeyboardgroup(struct wl_listener *listener, void *data);
|
|
||||||
+static void destroytablet(struct wl_listener *listener, void *data);
|
|
||||||
+static void destroytabletsurfacenotify(struct wl_listener *listener, void *data);
|
|
||||||
+static void destroytablettool(struct wl_listener *listener, void *data);
|
|
||||||
static Monitor *dirtomon(enum wlr_direction dir);
|
|
||||||
static void focusclient(Client *c, int lift);
|
|
||||||
static void focusmon(const Arg *arg);
|
|
||||||
@@ -333,11 +349,20 @@ static void spawn(const Arg *arg);
|
|
||||||
static void startdrag(struct wl_listener *listener, void *data);
|
|
||||||
static void tag(const Arg *arg);
|
|
||||||
static void tagmon(const Arg *arg);
|
|
||||||
+static void tablettoolmotion(struct wlr_tablet_v2_tablet_tool *tool, bool change_x, bool change_y, double x, double y, double dx, double dy);
|
|
||||||
+static void tablettoolproximity(struct wl_listener *listener, void *data);
|
|
||||||
+static void tablettoolaxis(struct wl_listener *listener, void *data);
|
|
||||||
+static void tablettoolbutton(struct wl_listener *listener, void *data);
|
|
||||||
+static void tablettooltip(struct wl_listener *listener, void *data);
|
|
||||||
static void tile(Monitor *m);
|
|
||||||
static void togglefloating(const Arg *arg);
|
|
||||||
static void togglefullscreen(const Arg *arg);
|
|
||||||
static void toggletag(const Arg *arg);
|
|
||||||
static void toggleview(const Arg *arg);
|
|
||||||
+static void touchdown(struct wl_listener *listener, void *data);
|
|
||||||
+static void touchup(struct wl_listener *listener, void *data);
|
|
||||||
+static void touchframe(struct wl_listener *listener, void *data);
|
|
||||||
+static void touchmotion(struct wl_listener *listener, void *data);
|
|
||||||
static void unlocksession(struct wl_listener *listener, void *data);
|
|
||||||
static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
|
|
||||||
static void unmapnotify(struct wl_listener *listener, void *data);
|
|
||||||
@@ -390,6 +415,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint;
|
|
||||||
static struct wlr_cursor *cursor;
|
|
||||||
static struct wlr_xcursor_manager *cursor_mgr;
|
|
||||||
|
|
||||||
+static struct wlr_tablet_manager_v2 *tablet_mgr;
|
|
||||||
+static struct wlr_tablet_v2_tablet *tablet = NULL;
|
|
||||||
+static struct wlr_tablet_v2_tablet_tool *tablet_tool = NULL;
|
|
||||||
+static struct wlr_tablet_v2_tablet_pad *tablet_pad = NULL;
|
|
||||||
+static struct wlr_surface *tablet_curr_surface = NULL;
|
|
||||||
+static struct wl_listener destroy_tablet_surface_listener = {.notify = destroytabletsurfacenotify};
|
|
||||||
+
|
|
||||||
static struct wlr_scene_rect *root_bg;
|
|
||||||
static struct wlr_session_lock_manager_v1 *session_lock_mgr;
|
|
||||||
static struct wlr_scene_rect *locked_bg;
|
|
||||||
@@ -405,6 +437,7 @@ static struct wlr_output_layout *output_layout;
|
|
||||||
static struct wlr_box sgeom;
|
|
||||||
static struct wl_list mons;
|
|
||||||
static Monitor *selmon;
|
|
||||||
+static struct wl_list touches;
|
|
||||||
|
|
||||||
/* global event handlers */
|
|
||||||
static struct wl_listener cursor_axis = {.notify = axisnotify};
|
|
||||||
@@ -412,6 +445,12 @@ static struct wl_listener cursor_button = {.notify = buttonpress};
|
|
||||||
static struct wl_listener cursor_frame = {.notify = cursorframe};
|
|
||||||
static struct wl_listener cursor_motion = {.notify = motionrelative};
|
|
||||||
static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute};
|
|
||||||
+static struct wl_listener tablet_device_destroy = {.notify = destroytablet};
|
|
||||||
+static struct wl_listener tablet_tool_axis = {.notify = tablettoolaxis};
|
|
||||||
+static struct wl_listener tablet_tool_button = {.notify = tablettoolbutton};
|
|
||||||
+static struct wl_listener tablet_tool_destroy = {.notify = destroytablettool};
|
|
||||||
+static struct wl_listener tablet_tool_proximity = {.notify = tablettoolproximity};
|
|
||||||
+static struct wl_listener tablet_tool_tip = {.notify = tablettooltip};
|
|
||||||
static struct wl_listener gpu_reset = {.notify = gpureset};
|
|
||||||
static struct wl_listener layout_change = {.notify = updatemons};
|
|
||||||
static struct wl_listener new_idle_inhibitor = {.notify = createidleinhibitor};
|
|
||||||
@@ -434,6 +473,10 @@ static struct wl_listener request_set_sel = {.notify = setsel};
|
|
||||||
static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
|
|
||||||
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
|
||||||
static struct wl_listener start_drag = {.notify = startdrag};
|
|
||||||
+static struct wl_listener touch_down = {.notify = touchdown};
|
|
||||||
+static struct wl_listener touch_frame = {.notify = touchframe};
|
|
||||||
+static struct wl_listener touch_motion = {.notify = touchmotion};
|
|
||||||
+static struct wl_listener touch_up = {.notify = touchup};
|
|
||||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
|
||||||
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
@@ -781,6 +824,10 @@ cleanuplisteners(void)
|
|
||||||
wl_list_remove(&request_set_cursor_shape.link);
|
|
||||||
wl_list_remove(&request_start_drag.link);
|
|
||||||
wl_list_remove(&start_drag.link);
|
|
||||||
+ wl_list_remove(&touch_down.link);
|
|
||||||
+ wl_list_remove(&touch_frame.link);
|
|
||||||
+ wl_list_remove(&touch_motion.link);
|
|
||||||
+ wl_list_remove(&touch_up.link);
|
|
||||||
wl_list_remove(&new_session_lock.link);
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
wl_list_remove(&new_xwayland_surface.link);
|
|
||||||
@@ -1199,6 +1246,38 @@ createpopup(struct wl_listener *listener, void *data)
|
|
||||||
LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
|
|
||||||
}
|
|
||||||
|
|
||||||
+void
|
|
||||||
+createtablet(struct wlr_input_device *device)
|
|
||||||
+{
|
|
||||||
+ if (!tablet) {
|
|
||||||
+ struct libinput_device *device_handle = NULL;
|
|
||||||
+ if (!wlr_input_device_is_libinput(device) ||
|
|
||||||
+ !(device_handle = wlr_libinput_get_device_handle(device)))
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ tablet = wlr_tablet_create(tablet_mgr, seat, device);
|
|
||||||
+ wl_signal_add(&tablet->wlr_device->events.destroy, &tablet_device_destroy);
|
|
||||||
+ if (libinput_device_config_send_events_get_modes(device_handle)) {
|
|
||||||
+ libinput_device_config_send_events_set_mode(device_handle, send_events_mode);
|
|
||||||
+ wlr_cursor_attach_input_device(cursor, device);
|
|
||||||
+ }
|
|
||||||
+ } else if (device == tablet->wlr_device) {
|
|
||||||
+ wlr_log(WLR_ERROR, "createtablet: duplicate device");
|
|
||||||
+ } else {
|
|
||||||
+ wlr_log(WLR_ERROR, "createtablet: already have one tablet");
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+createtouch(struct wlr_touch *wlr_touch)
|
|
||||||
+{
|
|
||||||
+ TouchGroup *touch = ecalloc(1, sizeof(TouchGroup));
|
|
||||||
+
|
|
||||||
+ touch->touch = wlr_touch;
|
|
||||||
+ wl_list_insert(&touches, &touch->link);
|
|
||||||
+ wlr_cursor_attach_input_device(cursor, &wlr_touch->base);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void
|
|
||||||
cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
|
|
||||||
{
|
|
||||||
@@ -1383,6 +1462,29 @@ destroykeyboardgroup(struct wl_listener *listener, void *data)
|
|
||||||
free(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
+void
|
|
||||||
+destroytablet(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ wl_list_remove(&tablet_device_destroy.link);
|
|
||||||
+ wlr_cursor_detach_input_device(cursor, tablet->wlr_device);
|
|
||||||
+ tablet = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+destroytabletsurfacenotify(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ if (tablet_curr_surface)
|
|
||||||
+ wl_list_remove(&destroy_tablet_surface_listener.link);
|
|
||||||
+ tablet_curr_surface = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+destroytablettool(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ destroytabletsurfacenotify(NULL, NULL);
|
|
||||||
+ tablet_tool = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
Monitor *
|
|
||||||
dirtomon(enum wlr_direction dir)
|
|
||||||
{
|
|
||||||
@@ -1590,6 +1692,15 @@ inputdevice(struct wl_listener *listener, void *data)
|
|
||||||
case WLR_INPUT_DEVICE_POINTER:
|
|
||||||
createpointer(wlr_pointer_from_input_device(device));
|
|
||||||
break;
|
|
||||||
+ case WLR_INPUT_DEVICE_TABLET:
|
|
||||||
+ createtablet(device);
|
|
||||||
+ break;
|
|
||||||
+ case WLR_INPUT_DEVICE_TABLET_PAD:
|
|
||||||
+ tablet_pad = wlr_tablet_pad_create(tablet_mgr, seat, device);
|
|
||||||
+ break;
|
|
||||||
+ case WLR_INPUT_DEVICE_TOUCH:
|
|
||||||
+ createtouch(wlr_touch_from_input_device(device));
|
|
||||||
+ break;
|
|
||||||
default:
|
|
||||||
/* TODO handle other input device types */
|
|
||||||
break;
|
|
||||||
@@ -1602,6 +1713,8 @@ inputdevice(struct wl_listener *listener, void *data)
|
|
||||||
caps = WL_SEAT_CAPABILITY_POINTER;
|
|
||||||
if (!wl_list_empty(&kb_group->wlr_group->devices))
|
|
||||||
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
|
||||||
+ if (!wl_list_empty(&touches))
|
|
||||||
+ caps |= WL_SEAT_CAPABILITY_TOUCH;
|
|
||||||
wlr_seat_set_capabilities(seat, caps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2585,6 +2698,8 @@ setup(void)
|
|
||||||
|
|
||||||
relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy);
|
|
||||||
|
|
||||||
+ tablet_mgr = wlr_tablet_v2_create(dpy);
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* Creates a cursor, which is a wlroots utility for tracking the cursor
|
|
||||||
* image shown on screen.
|
|
||||||
@@ -2614,6 +2729,18 @@ setup(void)
|
|
||||||
wl_signal_add(&cursor->events.button, &cursor_button);
|
|
||||||
wl_signal_add(&cursor->events.axis, &cursor_axis);
|
|
||||||
wl_signal_add(&cursor->events.frame, &cursor_frame);
|
|
||||||
+ wl_signal_add(&cursor->events.tablet_tool_proximity, &tablet_tool_proximity);
|
|
||||||
+ wl_signal_add(&cursor->events.tablet_tool_axis, &tablet_tool_axis);
|
|
||||||
+ wl_signal_add(&cursor->events.tablet_tool_button, &tablet_tool_button);
|
|
||||||
+ wl_signal_add(&cursor->events.tablet_tool_tip, &tablet_tool_tip);
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ wl_list_init(&touches);
|
|
||||||
+
|
|
||||||
+ wl_signal_add(&cursor->events.touch_down, &touch_down);
|
|
||||||
+ wl_signal_add(&cursor->events.touch_frame, &touch_frame);
|
|
||||||
+ wl_signal_add(&cursor->events.touch_motion, &touch_motion);
|
|
||||||
+ wl_signal_add(&cursor->events.touch_up, &touch_up);
|
|
||||||
|
|
||||||
cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
|
|
||||||
wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape);
|
|
||||||
@@ -2709,6 +2836,163 @@ tagmon(const Arg *arg)
|
|
||||||
setmon(sel, dirtomon(arg->i), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
+void
|
|
||||||
+tabletapplymap(double x, double y, struct wlr_input_device *dev)
|
|
||||||
+{
|
|
||||||
+ Client *p;
|
|
||||||
+ struct wlr_box geom = {0};
|
|
||||||
+ if (tabletmaptosurface && tablet_curr_surface) {
|
|
||||||
+ toplevel_from_wlr_surface(tablet_curr_surface, &p, NULL);
|
|
||||||
+ if (p) {
|
|
||||||
+ for (; client_get_parent(p); p = client_get_parent(p));
|
|
||||||
+ geom.x = p->geom.x + p->bw;
|
|
||||||
+ geom.y = p->geom.y + p->bw;
|
|
||||||
+ geom.width = p->geom.width - 2 * p->bw;
|
|
||||||
+ geom.height = p->geom.height - 2 * p->bw;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ wlr_cursor_map_input_to_region(cursor, dev, &geom);
|
|
||||||
+ wlr_cursor_map_input_to_output(cursor, dev, selmon->wlr_output);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+tablettoolmotion(struct wlr_tablet_v2_tablet_tool *tool, bool change_x, bool change_y,
|
|
||||||
+ double x, double y, double dx, double dy)
|
|
||||||
+{
|
|
||||||
+ struct wlr_surface *surface = NULL;
|
|
||||||
+ double sx, sy;
|
|
||||||
+
|
|
||||||
+ if (!change_x && !change_y)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ tabletapplymap(x, y, tablet->wlr_device);
|
|
||||||
+
|
|
||||||
+ // TODO: apply constraints
|
|
||||||
+ switch (tablet_tool->wlr_tool->type) {
|
|
||||||
+ case WLR_TABLET_TOOL_TYPE_LENS:
|
|
||||||
+ case WLR_TABLET_TOOL_TYPE_MOUSE:
|
|
||||||
+ wlr_cursor_move(cursor, tablet->wlr_device, dx, dy);
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ wlr_cursor_warp_absolute(cursor, tablet->wlr_device, change_x ? x : NAN, change_y ? y : NAN);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ motionnotify(0, NULL, 0, 0, 0, 0);
|
|
||||||
+
|
|
||||||
+ xytonode(cursor->x, cursor->y, &surface, NULL, NULL, &sx, &sy);
|
|
||||||
+ if (surface && !wlr_surface_accepts_tablet_v2(surface, tablet))
|
|
||||||
+ surface = NULL;
|
|
||||||
+
|
|
||||||
+ if (surface != tablet_curr_surface) {
|
|
||||||
+ if (tablet_curr_surface) {
|
|
||||||
+ // TODO: wait until all buttons released before leaving
|
|
||||||
+ if (tablet_tool)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_proximity_out(tablet_tool);
|
|
||||||
+ if (tablet_pad)
|
|
||||||
+ wlr_tablet_v2_tablet_pad_notify_leave(tablet_pad, tablet_curr_surface);
|
|
||||||
+ wl_list_remove(&destroy_tablet_surface_listener.link);
|
|
||||||
+ }
|
|
||||||
+ if (surface) {
|
|
||||||
+ if (tablet_pad)
|
|
||||||
+ wlr_tablet_v2_tablet_pad_notify_enter(tablet_pad, tablet, surface);
|
|
||||||
+ if (tablet_tool)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_proximity_in(tablet_tool, tablet, surface);
|
|
||||||
+ wl_signal_add(&surface->events.destroy, &destroy_tablet_surface_listener);
|
|
||||||
+ }
|
|
||||||
+ tablet_curr_surface = surface;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (surface)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_motion(tablet_tool, sx, sy);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+tablettoolproximity(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_tablet_tool_proximity_event *event = data;
|
|
||||||
+ struct wlr_tablet_tool *tool = event->tool;
|
|
||||||
+
|
|
||||||
+ if (!tablet_tool) {
|
|
||||||
+ tablet_tool = wlr_tablet_tool_create(tablet_mgr, seat, tool);
|
|
||||||
+ wl_signal_add(&tablet_tool->wlr_tool->events.destroy, &tablet_tool_destroy);
|
|
||||||
+ wl_signal_add(&tablet_tool->events.set_cursor, &request_cursor);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ switch (event->state) {
|
|
||||||
+ case WLR_TABLET_TOOL_PROXIMITY_OUT:
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_proximity_out(tablet_tool);
|
|
||||||
+ destroytabletsurfacenotify(NULL, NULL);
|
|
||||||
+ break;
|
|
||||||
+ case WLR_TABLET_TOOL_PROXIMITY_IN:
|
|
||||||
+ tablettoolmotion(tablet_tool, true, true, event->x, event->y, 0, 0);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+double tilt_x = 0;
|
|
||||||
+double tilt_y = 0;
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+tablettoolaxis(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_tablet_tool_axis_event *event = data;
|
|
||||||
+
|
|
||||||
+ tablettoolmotion(tablet_tool,
|
|
||||||
+ event->updated_axes & WLR_TABLET_TOOL_AXIS_X,
|
|
||||||
+ event->updated_axes & WLR_TABLET_TOOL_AXIS_Y,
|
|
||||||
+ event->x, event->y, event->dx, event->dy);
|
|
||||||
+
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_pressure(tablet_tool, event->pressure);
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_distance(tablet_tool, event->distance);
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X)
|
|
||||||
+ tilt_x = event->tilt_x;
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y)
|
|
||||||
+ tilt_y = event->tilt_y;
|
|
||||||
+ if (event->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y))
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_tilt(tablet_tool, tilt_x, tilt_y);
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_rotation(tablet_tool, event->rotation);
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_slider(tablet_tool, event->slider);
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_wheel(tablet_tool, event->wheel_delta, 0);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+tablettoolbutton(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_tablet_tool_button_event *event = data;
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_button(tablet_tool, event->button,
|
|
||||||
+ (enum zwp_tablet_pad_v2_button_state)event->state);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+tablettooltip(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_tablet_tool_tip_event *event = data;
|
|
||||||
+
|
|
||||||
+ if (!tablet_curr_surface) {
|
|
||||||
+ struct wlr_pointer_button_event fakeptrbtnevent = {
|
|
||||||
+ .button = BTN_LEFT,
|
|
||||||
+ .state = event->state == WLR_TABLET_TOOL_TIP_UP ?
|
|
||||||
+ WL_POINTER_BUTTON_STATE_RELEASED : WL_POINTER_BUTTON_STATE_PRESSED,
|
|
||||||
+ .time_msec = event->time_msec,
|
|
||||||
+ };
|
|
||||||
+ buttonpress(NULL, (void *)&fakeptrbtnevent);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (event->state == WLR_TABLET_TOOL_TIP_UP) {
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_up(tablet_tool);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_down(tablet_tool);
|
|
||||||
+ wlr_tablet_tool_v2_start_implicit_grab(tablet_tool);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void
|
|
||||||
tile(Monitor *m)
|
|
||||||
{
|
|
||||||
@@ -2787,6 +3071,120 @@ toggleview(const Arg *arg)
|
|
||||||
printstatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
+void
|
|
||||||
+touchdown(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_touch_down_event *event = data;
|
|
||||||
+ double lx, ly;
|
|
||||||
+ double sx, sy;
|
|
||||||
+ struct wlr_surface *surface;
|
|
||||||
+ Client *c = NULL;
|
|
||||||
+ uint32_t serial = 0;
|
|
||||||
+ Monitor *m;
|
|
||||||
+
|
|
||||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
|
||||||
+
|
|
||||||
+ // Map the input to the appropriate output, to ensure that rotation is
|
|
||||||
+ // handled.
|
|
||||||
+ wl_list_for_each(m, &mons, link) {
|
|
||||||
+ if (m == NULL || m->wlr_output == NULL) {
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+ if (event->touch->output_name != NULL && 0 != strcmp(event->touch->output_name, m->wlr_output->name)) {
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wlr_cursor_map_input_to_output(cursor, &event->touch->base, m->wlr_output);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly);
|
|
||||||
+
|
|
||||||
+ /* Find the client under the pointer and send the event along. */
|
|
||||||
+ xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
|
|
||||||
+ if (sloppyfocus)
|
|
||||||
+ focusclient(c, 0);
|
|
||||||
+
|
|
||||||
+ if (surface != NULL) {
|
|
||||||
+ serial = wlr_seat_touch_notify_down(seat, surface, event->time_msec, event->touch_id, sx, sy);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (serial && wlr_seat_touch_num_points(seat) == 1) {
|
|
||||||
+ /* Emulate a mouse click if the touch event wasn't handled */
|
|
||||||
+ struct wlr_pointer_button_event *button_event = data;
|
|
||||||
+ struct wlr_pointer_motion_absolute_event *motion_event = data;
|
|
||||||
+ double dx, dy;
|
|
||||||
+
|
|
||||||
+ wlr_cursor_absolute_to_layout_coords(cursor, &motion_event->pointer->base, motion_event->x, motion_event->y, &lx, &ly);
|
|
||||||
+ wlr_cursor_warp_closest(cursor, &motion_event->pointer->base, lx, ly);
|
|
||||||
+ dx = lx - cursor->x;
|
|
||||||
+ dy = ly - cursor->y;
|
|
||||||
+ motionnotify(motion_event->time_msec, &motion_event->pointer->base, dx, dy, dx, dy);
|
|
||||||
+
|
|
||||||
+ button_event->button = BTN_LEFT;
|
|
||||||
+ button_event->state = WL_POINTER_BUTTON_STATE_PRESSED;
|
|
||||||
+ buttonpress(listener, button_event);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+touchup(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_touch_up_event *event = data;
|
|
||||||
+
|
|
||||||
+ if (!wlr_seat_touch_get_point(seat, event->touch_id)) {
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (wlr_seat_touch_num_points(seat) == 1) {
|
|
||||||
+ struct wlr_pointer_button_event *button_event = data;
|
|
||||||
+
|
|
||||||
+ button_event->button = BTN_LEFT;
|
|
||||||
+ button_event->state = WL_POINTER_BUTTON_STATE_RELEASED;
|
|
||||||
+ buttonpress(listener, button_event);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wlr_seat_touch_notify_up(seat, event->time_msec, event->touch_id);
|
|
||||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+touchframe(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ wlr_seat_touch_notify_frame(seat);
|
|
||||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+touchmotion(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_touch_motion_event *event = data;
|
|
||||||
+ double lx, ly;
|
|
||||||
+ double sx, sy;
|
|
||||||
+ struct wlr_surface *surface;
|
|
||||||
+ Client *c = NULL;
|
|
||||||
+
|
|
||||||
+ if (!wlr_seat_touch_get_point(seat, event->touch_id)) {
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly);
|
|
||||||
+ xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
|
|
||||||
+
|
|
||||||
+ if (c != NULL && surface != NULL) {
|
|
||||||
+ if (sloppyfocus)
|
|
||||||
+ focusclient(c, 0);
|
|
||||||
+ wlr_seat_touch_point_focus(seat, surface, event->time_msec, event->touch_id, sx, sy);
|
|
||||||
+ } else {
|
|
||||||
+ if (sloppyfocus)
|
|
||||||
+ focusclient(NULL, 0);
|
|
||||||
+ wlr_seat_touch_point_clear_focus(seat, event->time_msec, event->touch_id);
|
|
||||||
+ }
|
|
||||||
+ wlr_seat_touch_notify_motion(seat, event->time_msec, event->touch_id, sx, sy);
|
|
||||||
+
|
|
||||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
void
|
|
||||||
unlocksession(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
--
|
|
||||||
2.52.0
|
|
||||||
|
|
||||||
@ -1,584 +0,0 @@
|
|||||||
From 78eda59b86ca01188fd645fe4062dda75d60acb1 Mon Sep 17 00:00:00 2001
|
|
||||||
From: A Frederick Christensen <dwl@ivories.org>
|
|
||||||
Date: Thu, 26 Feb 2026 23:23:49 -0600
|
|
||||||
Subject: [PATCH] Apply tablet-and-touch patch
|
|
||||||
|
|
||||||
---
|
|
||||||
Makefile | 6 +-
|
|
||||||
config.def.h | 1 +
|
|
||||||
dwl.c | 398 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
3 files changed, 404 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/Makefile b/Makefile
|
|
||||||
index 578194f..e0d1835 100644
|
|
||||||
--- a/Makefile
|
|
||||||
+++ b/Makefile
|
|
||||||
@@ -21,7 +21,8 @@ dwl: dwl.o util.o
|
|
||||||
$(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
|
||||||
dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
|
|
||||||
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
|
||||||
- wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
|
||||||
+ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \
|
|
||||||
+ tablet-v2-protocol.h
|
|
||||||
util.o: util.c util.h
|
|
||||||
|
|
||||||
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
|
||||||
@@ -45,6 +46,9 @@ wlr-output-power-management-unstable-v1-protocol.h:
|
|
||||||
xdg-shell-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
|
||||||
+tablet-v2-protocol.h:
|
|
||||||
+ $(WAYLAND_SCANNER) server-header \
|
|
||||||
+ $(WAYLAND_PROTOCOLS)/unstable/tablet/tablet-unstable-v2.xml $@
|
|
||||||
|
|
||||||
config.h:
|
|
||||||
cp config.def.h $@
|
|
||||||
diff --git a/config.def.h b/config.def.h
|
|
||||||
index 8a6eda0..1f20dfd 100644
|
|
||||||
--- a/config.def.h
|
|
||||||
+++ b/config.def.h
|
|
||||||
@@ -4,6 +4,7 @@
|
|
||||||
((hex >> 8) & 0xFF) / 255.0f, \
|
|
||||||
(hex & 0xFF) / 255.0f }
|
|
||||||
/* appearance */
|
|
||||||
+static const int tabletmaptosurface = 0; /* map tablet input to surface(1) or monitor(0) */
|
|
||||||
static const int sloppyfocus = 1; /* focus follows mouse */
|
|
||||||
static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
|
|
||||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
|
||||||
diff --git a/dwl.c b/dwl.c
|
|
||||||
index 8a9715d..6dc462a 100644
|
|
||||||
--- a/dwl.c
|
|
||||||
+++ b/dwl.c
|
|
||||||
@@ -52,6 +52,10 @@
|
|
||||||
#include <wlr/types/wlr_session_lock_v1.h>
|
|
||||||
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
|
|
||||||
#include <wlr/types/wlr_subcompositor.h>
|
|
||||||
+#include <wlr/types/wlr_tablet_pad.h>
|
|
||||||
+#include <wlr/types/wlr_tablet_tool.h>
|
|
||||||
+#include <wlr/types/wlr_tablet_v2.h>
|
|
||||||
+#include <wlr/types/wlr_touch.h>
|
|
||||||
#include <wlr/types/wlr_viewporter.h>
|
|
||||||
#include <wlr/types/wlr_virtual_keyboard_v1.h>
|
|
||||||
#include <wlr/types/wlr_virtual_pointer_v1.h>
|
|
||||||
@@ -163,6 +167,12 @@ typedef struct {
|
|
||||||
struct wl_listener destroy;
|
|
||||||
} KeyboardGroup;
|
|
||||||
|
|
||||||
+typedef struct TouchGroup {
|
|
||||||
+ struct wl_list link;
|
|
||||||
+ struct wlr_touch *touch;
|
|
||||||
+ Monitor *m;
|
|
||||||
+} TouchGroup;
|
|
||||||
+
|
|
||||||
typedef struct {
|
|
||||||
/* Must keep this field first */
|
|
||||||
unsigned int type; /* LayerShell */
|
|
||||||
@@ -270,7 +280,10 @@ static void createnotify(struct wl_listener *listener, void *data);
|
|
||||||
static void createpointer(struct wlr_pointer *pointer);
|
|
||||||
static void createpointerconstraint(struct wl_listener *listener, void *data);
|
|
||||||
static void createpopup(struct wl_listener *listener, void *data);
|
|
||||||
+static void createtablet(struct wlr_input_device *device);
|
|
||||||
+static void createtouch(struct wlr_touch *touch);
|
|
||||||
static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
|
|
||||||
+static void createtouch(struct wlr_touch *touch);
|
|
||||||
static void cursorframe(struct wl_listener *listener, void *data);
|
|
||||||
static void cursorwarptohint(void);
|
|
||||||
static void destroydecoration(struct wl_listener *listener, void *data);
|
|
||||||
@@ -283,6 +296,9 @@ static void destroynotify(struct wl_listener *listener, void *data);
|
|
||||||
static void destroypointerconstraint(struct wl_listener *listener, void *data);
|
|
||||||
static void destroysessionlock(struct wl_listener *listener, void *data);
|
|
||||||
static void destroykeyboardgroup(struct wl_listener *listener, void *data);
|
|
||||||
+static void destroytablet(struct wl_listener *listener, void *data);
|
|
||||||
+static void destroytabletsurfacenotify(struct wl_listener *listener, void *data);
|
|
||||||
+static void destroytablettool(struct wl_listener *listener, void *data);
|
|
||||||
static Monitor *dirtomon(enum wlr_direction dir);
|
|
||||||
static void focusclient(Client *c, int lift);
|
|
||||||
static void focusmon(const Arg *arg);
|
|
||||||
@@ -335,11 +351,20 @@ static void spawn(const Arg *arg);
|
|
||||||
static void startdrag(struct wl_listener *listener, void *data);
|
|
||||||
static void tag(const Arg *arg);
|
|
||||||
static void tagmon(const Arg *arg);
|
|
||||||
+static void tablettoolmotion(struct wlr_tablet_v2_tablet_tool *tool, bool change_x, bool change_y, double x, double y, double dx, double dy);
|
|
||||||
+static void tablettoolproximity(struct wl_listener *listener, void *data);
|
|
||||||
+static void tablettoolaxis(struct wl_listener *listener, void *data);
|
|
||||||
+static void tablettoolbutton(struct wl_listener *listener, void *data);
|
|
||||||
+static void tablettooltip(struct wl_listener *listener, void *data);
|
|
||||||
static void tile(Monitor *m);
|
|
||||||
static void togglefloating(const Arg *arg);
|
|
||||||
static void togglefullscreen(const Arg *arg);
|
|
||||||
static void toggletag(const Arg *arg);
|
|
||||||
static void toggleview(const Arg *arg);
|
|
||||||
+static void touchdown(struct wl_listener *listener, void *data);
|
|
||||||
+static void touchup(struct wl_listener *listener, void *data);
|
|
||||||
+static void touchframe(struct wl_listener *listener, void *data);
|
|
||||||
+static void touchmotion(struct wl_listener *listener, void *data);
|
|
||||||
static void unlocksession(struct wl_listener *listener, void *data);
|
|
||||||
static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
|
|
||||||
static void unmapnotify(struct wl_listener *listener, void *data);
|
|
||||||
@@ -392,6 +417,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint;
|
|
||||||
static struct wlr_cursor *cursor;
|
|
||||||
static struct wlr_xcursor_manager *cursor_mgr;
|
|
||||||
|
|
||||||
+static struct wlr_tablet_manager_v2 *tablet_mgr;
|
|
||||||
+static struct wlr_tablet_v2_tablet *tablet = NULL;
|
|
||||||
+static struct wlr_tablet_v2_tablet_tool *tablet_tool = NULL;
|
|
||||||
+static struct wlr_tablet_v2_tablet_pad *tablet_pad = NULL;
|
|
||||||
+static struct wlr_surface *tablet_curr_surface = NULL;
|
|
||||||
+static struct wl_listener destroy_tablet_surface_listener = {.notify = destroytabletsurfacenotify};
|
|
||||||
+
|
|
||||||
static struct wlr_scene_rect *root_bg;
|
|
||||||
static struct wlr_session_lock_manager_v1 *session_lock_mgr;
|
|
||||||
static struct wlr_scene_rect *locked_bg;
|
|
||||||
@@ -407,6 +439,7 @@ static struct wlr_output_layout *output_layout;
|
|
||||||
static struct wlr_box sgeom;
|
|
||||||
static struct wl_list mons;
|
|
||||||
static Monitor *selmon;
|
|
||||||
+static struct wl_list touches;
|
|
||||||
|
|
||||||
/* global event handlers */
|
|
||||||
static struct wl_listener cursor_axis = {.notify = axisnotify};
|
|
||||||
@@ -414,6 +447,12 @@ static struct wl_listener cursor_button = {.notify = buttonpress};
|
|
||||||
static struct wl_listener cursor_frame = {.notify = cursorframe};
|
|
||||||
static struct wl_listener cursor_motion = {.notify = motionrelative};
|
|
||||||
static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute};
|
|
||||||
+static struct wl_listener tablet_device_destroy = {.notify = destroytablet};
|
|
||||||
+static struct wl_listener tablet_tool_axis = {.notify = tablettoolaxis};
|
|
||||||
+static struct wl_listener tablet_tool_button = {.notify = tablettoolbutton};
|
|
||||||
+static struct wl_listener tablet_tool_destroy = {.notify = destroytablettool};
|
|
||||||
+static struct wl_listener tablet_tool_proximity = {.notify = tablettoolproximity};
|
|
||||||
+static struct wl_listener tablet_tool_tip = {.notify = tablettooltip};
|
|
||||||
static struct wl_listener gpu_reset = {.notify = gpureset};
|
|
||||||
static struct wl_listener layout_change = {.notify = updatemons};
|
|
||||||
static struct wl_listener new_idle_inhibitor = {.notify = createidleinhibitor};
|
|
||||||
@@ -436,6 +475,10 @@ static struct wl_listener request_set_sel = {.notify = setsel};
|
|
||||||
static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
|
|
||||||
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
|
|
||||||
static struct wl_listener start_drag = {.notify = startdrag};
|
|
||||||
+static struct wl_listener touch_down = {.notify = touchdown};
|
|
||||||
+static struct wl_listener touch_frame = {.notify = touchframe};
|
|
||||||
+static struct wl_listener touch_motion = {.notify = touchmotion};
|
|
||||||
+static struct wl_listener touch_up = {.notify = touchup};
|
|
||||||
static struct wl_listener new_session_lock = {.notify = locksession};
|
|
||||||
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
@@ -783,6 +826,10 @@ cleanuplisteners(void)
|
|
||||||
wl_list_remove(&request_set_cursor_shape.link);
|
|
||||||
wl_list_remove(&request_start_drag.link);
|
|
||||||
wl_list_remove(&start_drag.link);
|
|
||||||
+ wl_list_remove(&touch_down.link);
|
|
||||||
+ wl_list_remove(&touch_frame.link);
|
|
||||||
+ wl_list_remove(&touch_motion.link);
|
|
||||||
+ wl_list_remove(&touch_up.link);
|
|
||||||
wl_list_remove(&new_session_lock.link);
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
wl_list_remove(&new_xwayland_surface.link);
|
|
||||||
@@ -1201,6 +1248,38 @@ createpopup(struct wl_listener *listener, void *data)
|
|
||||||
LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
|
|
||||||
}
|
|
||||||
|
|
||||||
+void
|
|
||||||
+createtablet(struct wlr_input_device *device)
|
|
||||||
+{
|
|
||||||
+ if (!tablet) {
|
|
||||||
+ struct libinput_device *device_handle = NULL;
|
|
||||||
+ if (!wlr_input_device_is_libinput(device) ||
|
|
||||||
+ !(device_handle = wlr_libinput_get_device_handle(device)))
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ tablet = wlr_tablet_create(tablet_mgr, seat, device);
|
|
||||||
+ wl_signal_add(&tablet->wlr_device->events.destroy, &tablet_device_destroy);
|
|
||||||
+ if (libinput_device_config_send_events_get_modes(device_handle)) {
|
|
||||||
+ libinput_device_config_send_events_set_mode(device_handle, send_events_mode);
|
|
||||||
+ wlr_cursor_attach_input_device(cursor, device);
|
|
||||||
+ }
|
|
||||||
+ } else if (device == tablet->wlr_device) {
|
|
||||||
+ wlr_log(WLR_ERROR, "createtablet: duplicate device");
|
|
||||||
+ } else {
|
|
||||||
+ wlr_log(WLR_ERROR, "createtablet: already have one tablet");
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+createtouch(struct wlr_touch *wlr_touch)
|
|
||||||
+{
|
|
||||||
+ TouchGroup *touch = ecalloc(1, sizeof(TouchGroup));
|
|
||||||
+
|
|
||||||
+ touch->touch = wlr_touch;
|
|
||||||
+ wl_list_insert(&touches, &touch->link);
|
|
||||||
+ wlr_cursor_attach_input_device(cursor, &wlr_touch->base);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void
|
|
||||||
cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
|
|
||||||
{
|
|
||||||
@@ -1385,6 +1464,29 @@ destroykeyboardgroup(struct wl_listener *listener, void *data)
|
|
||||||
free(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
+void
|
|
||||||
+destroytablet(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ wl_list_remove(&tablet_device_destroy.link);
|
|
||||||
+ wlr_cursor_detach_input_device(cursor, tablet->wlr_device);
|
|
||||||
+ tablet = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+destroytabletsurfacenotify(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ if (tablet_curr_surface)
|
|
||||||
+ wl_list_remove(&destroy_tablet_surface_listener.link);
|
|
||||||
+ tablet_curr_surface = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+destroytablettool(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ destroytabletsurfacenotify(NULL, NULL);
|
|
||||||
+ tablet_tool = NULL;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
Monitor *
|
|
||||||
dirtomon(enum wlr_direction dir)
|
|
||||||
{
|
|
||||||
@@ -1592,6 +1694,15 @@ inputdevice(struct wl_listener *listener, void *data)
|
|
||||||
case WLR_INPUT_DEVICE_POINTER:
|
|
||||||
createpointer(wlr_pointer_from_input_device(device));
|
|
||||||
break;
|
|
||||||
+ case WLR_INPUT_DEVICE_TABLET:
|
|
||||||
+ createtablet(device);
|
|
||||||
+ break;
|
|
||||||
+ case WLR_INPUT_DEVICE_TABLET_PAD:
|
|
||||||
+ tablet_pad = wlr_tablet_pad_create(tablet_mgr, seat, device);
|
|
||||||
+ break;
|
|
||||||
+ case WLR_INPUT_DEVICE_TOUCH:
|
|
||||||
+ createtouch(wlr_touch_from_input_device(device));
|
|
||||||
+ break;
|
|
||||||
default:
|
|
||||||
/* TODO handle other input device types */
|
|
||||||
break;
|
|
||||||
@@ -1604,6 +1715,8 @@ inputdevice(struct wl_listener *listener, void *data)
|
|
||||||
caps = WL_SEAT_CAPABILITY_POINTER;
|
|
||||||
if (!wl_list_empty(&kb_group->wlr_group->devices))
|
|
||||||
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
|
||||||
+ if (!wl_list_empty(&touches))
|
|
||||||
+ caps |= WL_SEAT_CAPABILITY_TOUCH;
|
|
||||||
wlr_seat_set_capabilities(seat, caps);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2588,6 +2701,8 @@ setup(void)
|
|
||||||
|
|
||||||
relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy);
|
|
||||||
|
|
||||||
+ tablet_mgr = wlr_tablet_v2_create(dpy);
|
|
||||||
+
|
|
||||||
/*
|
|
||||||
* Creates a cursor, which is a wlroots utility for tracking the cursor
|
|
||||||
* image shown on screen.
|
|
||||||
@@ -2617,6 +2732,18 @@ setup(void)
|
|
||||||
wl_signal_add(&cursor->events.button, &cursor_button);
|
|
||||||
wl_signal_add(&cursor->events.axis, &cursor_axis);
|
|
||||||
wl_signal_add(&cursor->events.frame, &cursor_frame);
|
|
||||||
+ wl_signal_add(&cursor->events.tablet_tool_proximity, &tablet_tool_proximity);
|
|
||||||
+ wl_signal_add(&cursor->events.tablet_tool_axis, &tablet_tool_axis);
|
|
||||||
+ wl_signal_add(&cursor->events.tablet_tool_button, &tablet_tool_button);
|
|
||||||
+ wl_signal_add(&cursor->events.tablet_tool_tip, &tablet_tool_tip);
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ wl_list_init(&touches);
|
|
||||||
+
|
|
||||||
+ wl_signal_add(&cursor->events.touch_down, &touch_down);
|
|
||||||
+ wl_signal_add(&cursor->events.touch_frame, &touch_frame);
|
|
||||||
+ wl_signal_add(&cursor->events.touch_motion, &touch_motion);
|
|
||||||
+ wl_signal_add(&cursor->events.touch_up, &touch_up);
|
|
||||||
|
|
||||||
cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
|
|
||||||
wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape);
|
|
||||||
@@ -2712,6 +2839,163 @@ tagmon(const Arg *arg)
|
|
||||||
setmon(sel, dirtomon(arg->i), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
+void
|
|
||||||
+tabletapplymap(double x, double y, struct wlr_input_device *dev)
|
|
||||||
+{
|
|
||||||
+ Client *p;
|
|
||||||
+ struct wlr_box geom = {0};
|
|
||||||
+ if (tabletmaptosurface && tablet_curr_surface) {
|
|
||||||
+ toplevel_from_wlr_surface(tablet_curr_surface, &p, NULL);
|
|
||||||
+ if (p) {
|
|
||||||
+ for (; client_get_parent(p); p = client_get_parent(p));
|
|
||||||
+ geom.x = p->geom.x + p->bw;
|
|
||||||
+ geom.y = p->geom.y + p->bw;
|
|
||||||
+ geom.width = p->geom.width - 2 * p->bw;
|
|
||||||
+ geom.height = p->geom.height - 2 * p->bw;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ wlr_cursor_map_input_to_region(cursor, dev, &geom);
|
|
||||||
+ wlr_cursor_map_input_to_output(cursor, dev, selmon->wlr_output);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+tablettoolmotion(struct wlr_tablet_v2_tablet_tool *tool, bool change_x, bool change_y,
|
|
||||||
+ double x, double y, double dx, double dy)
|
|
||||||
+{
|
|
||||||
+ struct wlr_surface *surface = NULL;
|
|
||||||
+ double sx, sy;
|
|
||||||
+
|
|
||||||
+ if (!change_x && !change_y)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ tabletapplymap(x, y, tablet->wlr_device);
|
|
||||||
+
|
|
||||||
+ // TODO: apply constraints
|
|
||||||
+ switch (tablet_tool->wlr_tool->type) {
|
|
||||||
+ case WLR_TABLET_TOOL_TYPE_LENS:
|
|
||||||
+ case WLR_TABLET_TOOL_TYPE_MOUSE:
|
|
||||||
+ wlr_cursor_move(cursor, tablet->wlr_device, dx, dy);
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ wlr_cursor_warp_absolute(cursor, tablet->wlr_device, change_x ? x : NAN, change_y ? y : NAN);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ motionnotify(0, NULL, 0, 0, 0, 0);
|
|
||||||
+
|
|
||||||
+ xytonode(cursor->x, cursor->y, &surface, NULL, NULL, &sx, &sy);
|
|
||||||
+ if (surface && !wlr_surface_accepts_tablet_v2(surface, tablet))
|
|
||||||
+ surface = NULL;
|
|
||||||
+
|
|
||||||
+ if (surface != tablet_curr_surface) {
|
|
||||||
+ if (tablet_curr_surface) {
|
|
||||||
+ // TODO: wait until all buttons released before leaving
|
|
||||||
+ if (tablet_tool)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_proximity_out(tablet_tool);
|
|
||||||
+ if (tablet_pad)
|
|
||||||
+ wlr_tablet_v2_tablet_pad_notify_leave(tablet_pad, tablet_curr_surface);
|
|
||||||
+ wl_list_remove(&destroy_tablet_surface_listener.link);
|
|
||||||
+ }
|
|
||||||
+ if (surface) {
|
|
||||||
+ if (tablet_pad)
|
|
||||||
+ wlr_tablet_v2_tablet_pad_notify_enter(tablet_pad, tablet, surface);
|
|
||||||
+ if (tablet_tool)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_proximity_in(tablet_tool, tablet, surface);
|
|
||||||
+ wl_signal_add(&surface->events.destroy, &destroy_tablet_surface_listener);
|
|
||||||
+ }
|
|
||||||
+ tablet_curr_surface = surface;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (surface)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_motion(tablet_tool, sx, sy);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+tablettoolproximity(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_tablet_tool_proximity_event *event = data;
|
|
||||||
+ struct wlr_tablet_tool *tool = event->tool;
|
|
||||||
+
|
|
||||||
+ if (!tablet_tool) {
|
|
||||||
+ tablet_tool = wlr_tablet_tool_create(tablet_mgr, seat, tool);
|
|
||||||
+ wl_signal_add(&tablet_tool->wlr_tool->events.destroy, &tablet_tool_destroy);
|
|
||||||
+ wl_signal_add(&tablet_tool->events.set_cursor, &request_cursor);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ switch (event->state) {
|
|
||||||
+ case WLR_TABLET_TOOL_PROXIMITY_OUT:
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_proximity_out(tablet_tool);
|
|
||||||
+ destroytabletsurfacenotify(NULL, NULL);
|
|
||||||
+ break;
|
|
||||||
+ case WLR_TABLET_TOOL_PROXIMITY_IN:
|
|
||||||
+ tablettoolmotion(tablet_tool, true, true, event->x, event->y, 0, 0);
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+double tilt_x = 0;
|
|
||||||
+double tilt_y = 0;
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+tablettoolaxis(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_tablet_tool_axis_event *event = data;
|
|
||||||
+
|
|
||||||
+ tablettoolmotion(tablet_tool,
|
|
||||||
+ event->updated_axes & WLR_TABLET_TOOL_AXIS_X,
|
|
||||||
+ event->updated_axes & WLR_TABLET_TOOL_AXIS_Y,
|
|
||||||
+ event->x, event->y, event->dx, event->dy);
|
|
||||||
+
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_pressure(tablet_tool, event->pressure);
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_distance(tablet_tool, event->distance);
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X)
|
|
||||||
+ tilt_x = event->tilt_x;
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y)
|
|
||||||
+ tilt_y = event->tilt_y;
|
|
||||||
+ if (event->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y))
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_tilt(tablet_tool, tilt_x, tilt_y);
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_rotation(tablet_tool, event->rotation);
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_slider(tablet_tool, event->slider);
|
|
||||||
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL)
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_wheel(tablet_tool, event->wheel_delta, 0);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+tablettoolbutton(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_tablet_tool_button_event *event = data;
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_button(tablet_tool, event->button,
|
|
||||||
+ (enum zwp_tablet_pad_v2_button_state)event->state);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+tablettooltip(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_tablet_tool_tip_event *event = data;
|
|
||||||
+
|
|
||||||
+ if (!tablet_curr_surface) {
|
|
||||||
+ struct wlr_pointer_button_event fakeptrbtnevent = {
|
|
||||||
+ .button = BTN_LEFT,
|
|
||||||
+ .state = event->state == WLR_TABLET_TOOL_TIP_UP ?
|
|
||||||
+ WL_POINTER_BUTTON_STATE_RELEASED : WL_POINTER_BUTTON_STATE_PRESSED,
|
|
||||||
+ .time_msec = event->time_msec,
|
|
||||||
+ };
|
|
||||||
+ buttonpress(NULL, (void *)&fakeptrbtnevent);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (event->state == WLR_TABLET_TOOL_TIP_UP) {
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_up(tablet_tool);
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wlr_tablet_v2_tablet_tool_notify_down(tablet_tool);
|
|
||||||
+ wlr_tablet_tool_v2_start_implicit_grab(tablet_tool);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
void
|
|
||||||
tile(Monitor *m)
|
|
||||||
{
|
|
||||||
@@ -2790,6 +3074,120 @@ toggleview(const Arg *arg)
|
|
||||||
printstatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
+void
|
|
||||||
+touchdown(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_touch_down_event *event = data;
|
|
||||||
+ double lx, ly;
|
|
||||||
+ double sx, sy;
|
|
||||||
+ struct wlr_surface *surface;
|
|
||||||
+ Client *c = NULL;
|
|
||||||
+ uint32_t serial = 0;
|
|
||||||
+ Monitor *m;
|
|
||||||
+
|
|
||||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
|
||||||
+
|
|
||||||
+ // Map the input to the appropriate output, to ensure that rotation is
|
|
||||||
+ // handled.
|
|
||||||
+ wl_list_for_each(m, &mons, link) {
|
|
||||||
+ if (m == NULL || m->wlr_output == NULL) {
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+ if (event->touch->output_name != NULL && 0 != strcmp(event->touch->output_name, m->wlr_output->name)) {
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wlr_cursor_map_input_to_output(cursor, &event->touch->base, m->wlr_output);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly);
|
|
||||||
+
|
|
||||||
+ /* Find the client under the pointer and send the event along. */
|
|
||||||
+ xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
|
|
||||||
+ if (sloppyfocus)
|
|
||||||
+ focusclient(c, 0);
|
|
||||||
+
|
|
||||||
+ if (surface != NULL) {
|
|
||||||
+ serial = wlr_seat_touch_notify_down(seat, surface, event->time_msec, event->touch_id, sx, sy);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (serial && wlr_seat_touch_num_points(seat) == 1) {
|
|
||||||
+ /* Emulate a mouse click if the touch event wasn't handled */
|
|
||||||
+ struct wlr_pointer_button_event *button_event = data;
|
|
||||||
+ struct wlr_pointer_motion_absolute_event *motion_event = data;
|
|
||||||
+ double dx, dy;
|
|
||||||
+
|
|
||||||
+ wlr_cursor_absolute_to_layout_coords(cursor, &motion_event->pointer->base, motion_event->x, motion_event->y, &lx, &ly);
|
|
||||||
+ wlr_cursor_warp_closest(cursor, &motion_event->pointer->base, lx, ly);
|
|
||||||
+ dx = lx - cursor->x;
|
|
||||||
+ dy = ly - cursor->y;
|
|
||||||
+ motionnotify(motion_event->time_msec, &motion_event->pointer->base, dx, dy, dx, dy);
|
|
||||||
+
|
|
||||||
+ button_event->button = BTN_LEFT;
|
|
||||||
+ button_event->state = WL_POINTER_BUTTON_STATE_PRESSED;
|
|
||||||
+ buttonpress(listener, button_event);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+touchup(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_touch_up_event *event = data;
|
|
||||||
+
|
|
||||||
+ if (!wlr_seat_touch_get_point(seat, event->touch_id)) {
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (wlr_seat_touch_num_points(seat) == 1) {
|
|
||||||
+ struct wlr_pointer_button_event *button_event = data;
|
|
||||||
+
|
|
||||||
+ button_event->button = BTN_LEFT;
|
|
||||||
+ button_event->state = WL_POINTER_BUTTON_STATE_RELEASED;
|
|
||||||
+ buttonpress(listener, button_event);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wlr_seat_touch_notify_up(seat, event->time_msec, event->touch_id);
|
|
||||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+touchframe(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ wlr_seat_touch_notify_frame(seat);
|
|
||||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+void
|
|
||||||
+touchmotion(struct wl_listener *listener, void *data)
|
|
||||||
+{
|
|
||||||
+ struct wlr_touch_motion_event *event = data;
|
|
||||||
+ double lx, ly;
|
|
||||||
+ double sx, sy;
|
|
||||||
+ struct wlr_surface *surface;
|
|
||||||
+ Client *c = NULL;
|
|
||||||
+
|
|
||||||
+ if (!wlr_seat_touch_get_point(seat, event->touch_id)) {
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly);
|
|
||||||
+ xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
|
|
||||||
+
|
|
||||||
+ if (c != NULL && surface != NULL) {
|
|
||||||
+ if (sloppyfocus)
|
|
||||||
+ focusclient(c, 0);
|
|
||||||
+ wlr_seat_touch_point_focus(seat, surface, event->time_msec, event->touch_id, sx, sy);
|
|
||||||
+ } else {
|
|
||||||
+ if (sloppyfocus)
|
|
||||||
+ focusclient(NULL, 0);
|
|
||||||
+ wlr_seat_touch_point_clear_focus(seat, event->time_msec, event->touch_id);
|
|
||||||
+ }
|
|
||||||
+ wlr_seat_touch_notify_motion(seat, event->time_msec, event->touch_id, sx, sy);
|
|
||||||
+
|
|
||||||
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
void
|
|
||||||
unlocksession(struct wl_listener *listener, void *data)
|
|
||||||
{
|
|
||||||
--
|
|
||||||
2.52.0
|
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user