Author SHA1 Message Date
julmajustus 88c0c68d59 Remove rendermon pending resize frame skip
This is no longer needed as wlroots => 0.19 handles this internally via scene-level surface state tracking and
linux-drm-syncobj explicit sync.

The manual commit skip now causes the c->resize to be stuck on non-zero
state which leads to choppy resizing experience.
2026-09-08 18:04:52 +03:00
A Frederick Christensen d41ecb745c add support for ext-image-copy-capture-v1 and ext-image-capture-source-v1 (wlroots!4545) 2026-03-08 17:35:11 +01:00
A Frederick Christensen 52c4fb58ec Revert "Post 0.3 release modification"
This reverts commit 38c7bd7ee8.
Accidental commit intended for a testing repository.
2026-03-01 19:54:28 -06:00
A Frederick Christensen 38c7bd7ee8 Post 0.3 release modification 2026-03-01 19:53:43 -06:00
A Frederick Christensen 6e1bfa86c7 Remove trailing whitespace from README
Adapted from PR #1188 by @diegoviola
2026-03-01 19:15:22 -06:00
A Frederick Christensen e32535cf97 Fix typos -- adapted from PR #1189 by @diegoviola 2026-03-01 19:10:43 -06:00
thanatos f4249db613 Updated README to clarify branch roles
This change effectively reverts DWL to the prior development model, where development of DWL itself happens against the current wlroots release, and changes in anticipation of the next wlroots release are made on a separate branch.
2026-02-21 11:51:17 -07:00
thanatos b2d2b701d7 Corrected README 2026-02-21 11:37:48 -07:00
Thanatos 2c9cb2af1b Bumped to 0.9 for wlroots-0.20.0. Updated cursor image buffer handling for xwayland 2026-02-21 11:33:09 -07:00
8 changed files with 124 additions and 890 deletions
+10 -4
View File
@@ -5,7 +5,7 @@ include config.mk
# flags for compiling
DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \
-DVERSION=\"$(VERSION)\" $(XWAYLAND) $(CPPFLAGS)
-DVERSION=\"$(VERSION)\" $(XWAYLAND)
DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
-Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \
-Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \
@@ -17,11 +17,13 @@ DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEV
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
all: dwl
dwl: dwl.c client.h config.h ime.h util.h config.mk cursor-shape-v1-protocol.h \
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 \
ext-image-copy-capture-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
$(CC) dwl.c $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
util.o: util.c util.h
# wayland-scanner is a tool which generates C headers and rigging for Wayland
# protocols, which are specified in XML. wlroots requires you to rig these up
@@ -56,7 +58,7 @@ clean:
dist: clean
mkdir -p dwl-$(VERSION)
cp -R LICENSE* Makefile CHANGELOG.md README.md client.h config.def.h \
config.mk protocols dwl.1 dwl.c ime.h util.h dwl.desktop \
config.mk protocols dwl.1 dwl.c util.c util.h dwl.desktop \
dwl-$(VERSION)
tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION)
rm -rf dwl-$(VERSION)
@@ -75,3 +77,7 @@ install: dwl
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 \
$(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
.SUFFIXES: .c .o
.c.o:
$(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -c $<
+4 -5
View File
@@ -10,7 +10,7 @@ primarily in terms of functionality, and secondarily in terms of
philosophy. Like [dwm], dwl is:
- Easy to understand, hack on, and extend with patches
- One C source file configurable via `config.h`
- One C source file (or a very small number) configurable via `config.h`
- Tied to as few external dependencies as possible
## Getting Started:
@@ -166,6 +166,9 @@ indiscriminately. We will try to keep the code as small as possible.
Features under consideration (possibly as patches) are:
- Protocols made trivial by wlroots
- Implement the text-input and input-method protocols to support IME once ibus
implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and
https://codeberg.org/dwl/dwl/pulls/235)
Feature *non-goals* for the main codebase include:
@@ -190,10 +193,6 @@ inspiration, and to the various contributors to the project, including:
and for helping to keep the project running
- Stivvo for output management and fullscreen support, and patch maintenance
Also, thanks to our current lead developers:
- @thanatos
- @guidocella
[wlroots]: https://gitlab.freedesktop.org/wlroots
[dwm]: https://dwm.suckless.org/
+4 -11
View File
@@ -291,18 +291,11 @@ client_is_unmanaged(Client *c)
static inline void
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
{
uint32_t filtered[WLR_KEYBOARD_KEYS_CAP];
size_t size = 0;
if (!kb) {
if (kb)
wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes,
kb->num_keycodes, &kb->modifiers);
else
wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
return;
}
for (size_t i = 0; i < kb->num_keycodes; i++) {
uint32_t key = kb->keycodes[i];
if (!consumed[key])
filtered[size++] = key;
}
wlr_seat_keyboard_notify_enter(seat, s, filtered, size, &kb->modifiers);
}
static inline void
+4 -4
View File
@@ -17,12 +17,12 @@ WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.20`
#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \
# -I$(PWD)/wlroots/include
# Set -rpath to avoid using the wrong library.
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/build -L$(PWD)/wlroots/build -lwlroots-0.20
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/build -L$(PWD)/wlroots/build -lwlroots-0.19
# Assuming you ran "meson setup --prefix ${PWD}/0.20 build && ninja -C build install"
# Assuming you ran "meson setup --prefix ${PWD}/0.19 build && ninja -C build install"
#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \
# -I$(PWD)/wlroots/0.20/include/wlroots-0.20
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.20/lib64 -L$(PWD)/wlroots/0.20/lib64 -lwlroots-0.20
# -I$(PWD)/wlroots/0.19/include/wlroots-0.19
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.19/lib64 -L$(PWD)/wlroots/0.19/lib64 -lwlroots-0.19
XWAYLAND =
XLIBS =
+47 -170
View File
@@ -27,7 +27,6 @@
#include <wlr/types/wlr_ext_data_control_v1.h>
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
#include <wlr/types/wlr_fractional_scale_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
@@ -76,8 +75,12 @@
#include "util.h"
/* macros */
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define END(A) ((A) + LENGTH(A))
#define TAGMASK ((1u << TAGCOUNT) - 1)
#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
#define LISTEN_STATIC(E, H) do { struct wl_listener *_l = ecalloc(1, sizeof(*_l)); _l->notify = (H); wl_signal_add((E), _l); } while (0)
@@ -85,7 +88,7 @@
/* enums */
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrIMPopup, LyrBlock, NUM_LAYERS }; /* scene layers */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
typedef union {
int i;
@@ -120,13 +123,6 @@ typedef struct {
struct wlr_xwayland_surface *xwayland;
} surface;
struct wlr_xdg_toplevel_decoration_v1 *decoration;
struct wlr_ext_foreign_toplevel_handle_v1 *foreign_toplevel_handle;
struct wlr_scene *image_capture_scene;
struct wlr_ext_image_capture_source_v1 *image_capture_source;
union {
struct wlr_scene_tree *image_capture_tree;
struct wlr_scene_surface *image_capture_scene_surface;
} capture;
struct wl_listener commit;
struct wl_listener map;
struct wl_listener maximize;
@@ -158,7 +154,6 @@ typedef struct {
typedef struct {
struct wlr_keyboard_group *wlr_group;
struct wlr_keyboard *virtual_keyboard;
int nsyms;
const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */
@@ -257,7 +252,6 @@ static void arrangelayer(Monitor *m, struct wl_list *list,
static void arrangelayers(Monitor *m);
static void axisnotify(struct wl_listener *listener, void *data);
static void buttonpress(struct wl_listener *listener, void *data);
static void capturerequest(struct wl_listener *listener, void *data);
static void chvt(const Arg *arg);
static void checkidleinhibitor(struct wlr_surface *exclude);
static void cleanup(void);
@@ -301,7 +295,7 @@ static void gpureset(struct wl_listener *listener, void *data);
static void handlesig(int signo);
static void incnmaster(const Arg *arg);
static void inputdevice(struct wl_listener *listener, void *data);
static const Key *keybinding(uint32_t mods, xkb_keysym_t sym);
static int keybinding(uint32_t mods, xkb_keysym_t sym);
static void keypress(struct wl_listener *listener, void *data);
static void keypressmod(struct wl_listener *listener, void *data);
static int keyrepeat(void *data);
@@ -318,7 +312,7 @@ static void moveresize(const Arg *arg);
static void outputmgrapply(struct wl_listener *listener, void *data);
static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test);
static void outputmgrtest(struct wl_listener *listener, void *data);
static void pointerfocus(Client *c, LayerSurface* l, struct wlr_surface *surface,
static void pointerfocus(Client *c, struct wlr_surface *surface,
double sx, double sy, uint32_t time);
static void printstatus(void);
static void powermgrsetmode(struct wl_listener *listener, void *data);
@@ -392,8 +386,6 @@ static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr;
static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr;
static struct wlr_output_power_manager_v1 *power_mgr;
static struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list;
static struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1 *ext_foreign_toplevel_image_capture_source_manager_v1;
static struct wlr_pointer_constraints_v1 *pointer_constraints;
static struct wlr_relative_pointer_manager_v1 *relative_pointer_mgr;
@@ -417,7 +409,6 @@ static struct wlr_output_layout *output_layout;
static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
static int consumed[KEY_MAX + 1];
/* global event handlers */
static struct wl_listener cursor_axis = {.notify = axisnotify};
@@ -448,7 +439,6 @@ 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 new_session_lock = {.notify = locksession};
static struct wl_listener new_foreign_toplevel_capture_request = {.notify = capturerequest};
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
@@ -469,8 +459,6 @@ static struct wlr_xwayland *xwayland;
/* attempt to encapsulate suck into one file */
#include "client.h"
#include "ime.h"
/* function implementations */
void
applybounds(Client *c, struct wlr_box *bbox)
@@ -605,13 +593,10 @@ arrangelayers(Monitor *m)
for (i = 3; i >= 0; i--)
arrangelayer(m, &m->layers[i], &usable_area, 0);
/* Find topmost keyboard interactive layer that has indicated it wants
* exclusive access to the keyboard, if such a layer exists */
/* Find topmost keyboard interactive layer, if such a layer exists */
for (i = 0; i < (int)LENGTH(layers_above_shell); i++) {
wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) {
if (locked ||
l->layer_surface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE ||
!l->mapped)
if (locked || !l->layer_surface->current.keyboard_interactive || !l->mapped)
continue;
/* Deactivate the focused client. */
focusclient(NULL, 0);
@@ -643,8 +628,7 @@ buttonpress(struct wl_listener *listener, void *data)
struct wlr_pointer_button_event *event = data;
struct wlr_keyboard *keyboard;
uint32_t mods;
Client *c = NULL;
LayerSurface *l = NULL;
Client *c;
const Button *b;
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
@@ -656,15 +640,10 @@ buttonpress(struct wl_listener *listener, void *data)
if (locked)
break;
/* Change focus if the button was _pressed_ over a client
or a layer surface with on-demand keyboard interactivity */
xytonode(cursor->x, cursor->y, NULL, &c, &l, NULL, NULL);
if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) {
/* Change focus if the button was _pressed_ over a client */
xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
if (c && (!client_is_unmanaged(c) || client_wants_focus(c)))
focusclient(c, 1);
} else if (l && l->layer_surface->current.keyboard_interactive) {
focusclient(NULL, 0);
client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat));
}
keyboard = wlr_seat_get_keyboard(seat);
mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
@@ -697,23 +676,6 @@ buttonpress(struct wl_listener *listener, void *data)
event->time_msec, event->button, event->state);
}
void
capturerequest(struct wl_listener *listener, void *data)
{
struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *request = data;
Client *view = request->toplevel_handle->data;
if (!view->image_capture_source) {
view->image_capture_source = wlr_ext_image_capture_source_v1_create_with_scene_node(
&view->image_capture_scene->tree.node, event_loop, alloc, drw);
if (!view->image_capture_source)
return;
}
wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept(
request, view->image_capture_source);
}
void
chvt(const Arg *arg)
{
@@ -755,8 +717,6 @@ cleanup(void)
destroykeyboardgroup(&kb_group->destroy, NULL);
input_method_relay_finish(input_method_relay);
/* If it's not destroyed manually, it will cause a use-after-free of wlr_seat.
* Destroy it until it's fixed on the wlroots side */
wlr_backend_destroy(backend);
@@ -826,7 +786,6 @@ cleanuplisteners(void)
wl_list_remove(&request_start_drag.link);
wl_list_remove(&start_drag.link);
wl_list_remove(&new_session_lock.link);
wl_list_remove(&new_foreign_toplevel_capture_request.link);
#ifdef XWAYLAND
wl_list_remove(&new_xwayland_surface.link);
wl_list_remove(&xwayland_ready.link);
@@ -882,11 +841,6 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data)
return;
}
if (layer_surface == exclusive_focus
&& layer_surface->current.keyboard_interactive !=
ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
exclusive_focus = NULL;
if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped)
return;
l->mapped = layer_surface->surface->mapped;
@@ -1291,7 +1245,6 @@ void
destroydecoration(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, destroy_decoration);
c->decoration = NULL;
wl_list_remove(&c->destroy_decoration.link);
wl_list_remove(&c->set_decoration_mode.link);
@@ -1397,10 +1350,6 @@ destroynotify(struct wl_listener *listener, void *data)
wl_list_remove(&c->map.link);
wl_list_remove(&c->unmap.link);
wl_list_remove(&c->maximize.link);
if (c->decoration) {
wl_list_remove(&c->set_decoration_mode.link);
wl_list_remove(&c->destroy_decoration.link);
}
}
free(c);
}
@@ -1498,8 +1447,7 @@ focusclient(Client *c, int lift)
* and focus it after the overlay is closed. */
if (old_client_type == LayerShell && wlr_scene_node_coords(
&old_l->scene->node, &unused_lx, &unused_ly)
&& old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP
&& old_l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
&& old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) {
return;
} else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) {
return;
@@ -1515,7 +1463,6 @@ focusclient(Client *c, int lift)
if (!c) {
/* With no client, all we have left is to clear focus */
input_method_relay_set_focus(input_method_relay, NULL);
wlr_seat_keyboard_notify_clear_focus(seat);
return;
}
@@ -1523,8 +1470,6 @@ focusclient(Client *c, int lift)
/* Change cursor surface */
motionnotify(0, NULL, 0, 0, 0, 0);
input_method_relay_set_focus(input_method_relay, client_surface(c));
/* Have a client, so focus its top-level wlr_surface */
client_notify_enter(client_surface(c), wlr_seat_get_keyboard(seat));
@@ -1664,7 +1609,7 @@ inputdevice(struct wl_listener *listener, void *data)
wlr_seat_set_capabilities(seat, caps);
}
const Key *
int
keybinding(uint32_t mods, xkb_keysym_t sym)
{
/*
@@ -1677,10 +1622,11 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
if (CLEANMASK(mods) == CLEANMASK(k->mod)
&& xkb_keysym_to_lower(sym) == xkb_keysym_to_lower(k->keysym)
&& k->func) {
return k;
k->func(&k->arg);
return 1;
}
}
return NULL;
return 0;
}
void
@@ -1706,14 +1652,8 @@ keypress(struct wl_listener *listener, void *data)
/* On _press_ if there is no active screen locker,
* attempt to process a compositor keybinding. */
if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
for (i = 0; i < nsyms; i++) {
const Key *key = keybinding(mods, syms[i]);
if (key) {
consumed[event->keycode] = 1;
key->func(&key->arg);
handled = 1;
}
}
for (i = 0; i < nsyms; i++)
handled = keybinding(mods, syms[i]) || handled;
}
if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) {
@@ -1727,14 +1667,9 @@ keypress(struct wl_listener *listener, void *data)
wl_event_source_timer_update(group->key_repeat_source, 0);
}
if (handled || input_method_keyboard_grab_forward_key(group, event))
if (handled)
return;
if (consumed[event->keycode]) {
if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED)
consumed[event->keycode] = 0;
return; /* Don't pass to the client the release event of a handled key-press */
}
wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);
/* Pass unhandled keycodes along to the client. */
wlr_seat_keyboard_notify_key(seat, event->time_msec,
@@ -1748,9 +1683,6 @@ keypressmod(struct wl_listener *listener, void *data)
* pressed. We simply communicate this to the client. */
KeyboardGroup *group = wl_container_of(listener, group, modifiers);
if (input_method_keyboard_grab_forward_modifiers(group))
return;
wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard);
/* Send modifiers to the client. */
wlr_seat_keyboard_notify_modifiers(seat,
@@ -1768,11 +1700,8 @@ keyrepeat(void *data)
wl_event_source_timer_update(group->key_repeat_source,
1000 / group->wlr_group->keyboard.repeat_info.rate);
for (i = 0; i < group->nsyms; i++) {
const Key *key = keybinding(group->mods, group->keysyms[i]);
if (key)
key->func(&key->arg);
}
for (i = 0; i < group->nsyms; i++)
keybinding(group->mods, group->keysyms[i]);
return 0;
}
@@ -1818,11 +1747,6 @@ mapnotify(struct wl_listener *listener, void *data)
Monitor *m;
int i;
struct wlr_ext_foreign_toplevel_handle_v1_state foreign_toplevel_state = {
.app_id = client_get_appid(c),
.title = client_get_title(c),
};
/* Create scene tree for this client and its border */
c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]);
/* Enabled later by a call to arrange() */
@@ -1862,18 +1786,6 @@ mapnotify(struct wl_listener *listener, void *data)
wl_list_insert(&clients, &c->link);
wl_list_insert(&fstack, &c->flink);
c->foreign_toplevel_handle = wlr_ext_foreign_toplevel_handle_v1_create(
foreign_toplevel_list, &foreign_toplevel_state);
c->foreign_toplevel_handle->data = c;
c->image_capture_scene = wlr_scene_create();
if (c->type == XDGShell)
c->capture.image_capture_tree = wlr_scene_xdg_surface_create(&c->image_capture_scene->tree, c->surface.xdg);
#ifdef XWAYLAND
else
c->capture.image_capture_scene_surface = wlr_scene_surface_create(&c->image_capture_scene->tree, c->surface.xwayland->surface);
#endif
/* Set initial monitor, tags, floating status, and focus:
* we always consider floating, clients that have parent and thus
* we set the same tags and monitor as its parent.
@@ -1956,20 +1868,20 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
{
double sx = 0, sy = 0, sx_confined, sy_confined;
Client *c = NULL, *w = NULL;
LayerSurface *l = NULL, *focusedl = NULL;
LayerSurface *l = NULL;
struct wlr_surface *surface = NULL;
struct wlr_pointer_constraint_v1 *constraint;
/* Find the client under the pointer and send the event along. */
xytonode(cursor->x, cursor->y, &surface, &c, &l, &sx, &sy);
xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy);
if (cursor_mode == CurPressed && !seat->drag
&& surface != seat->pointer_state.focused_surface
&& toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &focusedl) >= 0) {
&& toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= 0) {
c = w;
surface = seat->pointer_state.focused_surface;
sx = cursor->x - (focusedl ? focusedl->scene->node.x : w->geom.x);
sy = cursor->y - (focusedl ? focusedl->scene->node.y : w->geom.y);
sx = cursor->x - (l ? l->scene->node.x : w->geom.x);
sy = cursor->y - (l ? l->scene->node.y : w->geom.y);
}
/* time is 0 in internal calls meant to restore pointer focus. */
@@ -2026,7 +1938,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
if (!surface && !seat->drag)
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
pointerfocus(c, l, surface, sx, sy, time);
pointerfocus(c, surface, sx, sy, time);
}
void
@@ -2150,19 +2062,14 @@ outputmgrtest(struct wl_listener *listener, void *data)
}
void
pointerfocus(Client *c, LayerSurface *l, struct wlr_surface *surface, double sx, double sy,
pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
uint32_t time)
{
struct timespec now;
if (surface != seat->pointer_state.focused_surface && sloppyfocus && time) {
if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) {
if (surface != seat->pointer_state.focused_surface &&
sloppyfocus && time && c && !client_is_unmanaged(c))
focusclient(c, 0);
} else if (l && l->layer_surface->current.keyboard_interactive) {
focusclient(NULL, 0);
client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat));
}
}
/* If surface is NULL, clear pointer focus */
if (!surface) {
@@ -2650,7 +2557,7 @@ setup(void)
wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
wl_signal_add(&xdg_shell->events.new_popup, &new_xdg_popup);
layer_shell = wlr_layer_shell_v1_create(dpy, 4);
layer_shell = wlr_layer_shell_v1_create(dpy, 3);
wl_signal_add(&layer_shell->events.new_surface, &new_layer_surface);
idle_notifier = wlr_idle_notifier_v1_create(dpy);
@@ -2664,12 +2571,6 @@ setup(void)
(float [4]){0.1f, 0.1f, 0.1f, 1.0f});
wlr_scene_node_set_enabled(&locked_bg->node, 0);
foreign_toplevel_list = wlr_ext_foreign_toplevel_list_v1_create(dpy,1);
ext_foreign_toplevel_image_capture_source_manager_v1 =
wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(dpy, 1);
wl_signal_add(&ext_foreign_toplevel_image_capture_source_manager_v1->events.new_request,
&new_foreign_toplevel_capture_request);
/* Use decoration protocols to negotiate server-side decorations */
wlr_server_decoration_manager_set_default_mode(
wlr_server_decoration_manager_create(dpy),
@@ -2743,11 +2644,6 @@ setup(void)
wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
wl_signal_add(&output_mgr->events.test, &output_mgr_test);
input_method_manager = wlr_input_method_manager_v2_create(dpy);
text_input_manager = wlr_text_input_manager_v3_create(dpy);
input_method_relay = ecalloc(1, sizeof(*input_method_relay));
input_method_relay = input_method_relay_create();
/* Make sure XWayland clients don't connect to the parent X server,
* e.g when running in the x11 backend or the wayland backend and the
* compositor has Xwayland support */
@@ -2933,20 +2829,7 @@ unmapnotify(struct wl_listener *listener, void *data)
wl_list_remove(&c->flink);
}
if (c->foreign_toplevel_handle) {
wlr_ext_foreign_toplevel_handle_v1_destroy(c->foreign_toplevel_handle);
c->foreign_toplevel_handle = NULL;
}
#ifdef XWAYLAND
if (c->type != XDGShell && c->capture.image_capture_scene_surface) {
wlr_scene_node_destroy(&c->capture.image_capture_scene_surface->buffer->node);
c->capture.image_capture_scene_surface = NULL;
}
#endif
wlr_scene_node_destroy(&c->image_capture_scene->tree.node);
wlr_scene_node_destroy(&c->scene->node);
client_surface(c)->data = NULL;
printstatus();
motionnotify(0, NULL, 0, 0, 0, 0);
}
@@ -2969,13 +2852,10 @@ updatemons(struct wl_listener *listener, void *data)
/* First remove from the layout the disabled monitors */
wl_list_for_each(m, &mons, link) {
if (m->wlr_output->enabled)
if (m->wlr_output->enabled || m->asleep)
continue;
config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
config_head->state.enabled = 0;
if (m->asleep)
continue;
/* Remove this output from the layout to avoid cursor enter inside it */
wlr_output_layout_remove(output_layout, m->wlr_output);
closemon(m);
@@ -3066,15 +2946,6 @@ updatetitle(struct wl_listener *listener, void *data)
Client *c = wl_container_of(listener, c, set_title);
if (c == focustop(c->mon))
printstatus();
if (c->foreign_toplevel_handle) {
struct wlr_ext_foreign_toplevel_handle_v1_state foreign_toplevel_state = {
.app_id = client_get_appid(c),
.title = client_get_title(c),
};
wlr_ext_foreign_toplevel_handle_v1_update_state(c->foreign_toplevel_handle,
&foreign_toplevel_state);
}
}
void
@@ -3112,14 +2983,12 @@ virtualkeyboard(struct wl_listener *listener, void *data)
struct wlr_virtual_keyboard_v1 *kb = data;
/* virtual keyboards shouldn't share keyboard group */
KeyboardGroup *group = createkeyboardgroup();
group->virtual_keyboard = &kb->keyboard;
/* Set the keymap to match the group keymap */
wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap);
LISTEN(&kb->keyboard.base.events.destroy, &group->destroy, destroykeyboardgroup);
/* Add the new keyboard to the group */
wlr_keyboard_group_add_keyboard(group->wlr_group, &kb->keyboard);
wlr_seat_set_capabilities(seat, seat->capabilities | WL_SEAT_CAPABILITY_KEYBOARD);
}
void
@@ -3131,7 +3000,6 @@ virtualpointer(struct wl_listener *listener, void *data)
wlr_cursor_attach_input_device(cursor, device);
if (event->suggested_output)
wlr_cursor_map_input_to_output(cursor, device, event->suggested_output);
wlr_seat_set_capabilities(seat, seat->capabilities | WL_SEAT_CAPABILITY_POINTER);
}
Monitor *
@@ -3145,22 +3013,31 @@ void
xytonode(double x, double y, struct wlr_surface **psurface,
Client **pc, LayerSurface **pl, double *nx, double *ny)
{
struct wlr_scene_node *node;
struct wlr_scene_node *node, *pnode;
struct wlr_surface *surface = NULL;
Client *c = NULL;
LayerSurface *l = NULL;
int layer;
for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) {
if (layer == LyrIMPopup ||
!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny)))
if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny)))
continue;
if (node->type == WLR_SCENE_NODE_BUFFER)
surface = wlr_scene_surface_try_from_buffer(
wlr_scene_buffer_from_node(node))->surface;
/* Walk the tree to find a node that knows the client */
for (pnode = node; pnode && !c; pnode = &pnode->parent->node)
c = pnode->data;
if (c && c->type == LayerShell) {
c = NULL;
l = pnode->data;
}
}
if (psurface) *psurface = surface;
toplevel_from_wlr_surface(surface, pc, pl);
if (pc) *pc = c;
if (pl) *pl = l;
}
void
-639
View File
@@ -1,639 +0,0 @@
#include <wlr/types/wlr_input_method_v2.h>
#include <wlr/types/wlr_text_input_v3.h>
struct input_method_relay {
struct wl_list text_inputs; /* struct text_input.link */
struct wlr_input_method_v2 *input_method;
struct wlr_surface *focused_surface;
struct text_input *active_text_input;
struct wl_list popups; /* input_method_popup.link */
struct wlr_scene_tree *popup_tree;
struct wl_listener new_text_input;
struct wl_listener new_input_method;
struct wl_listener input_method_commit;
struct wl_listener input_method_grab_keyboard;
struct wl_listener input_method_destroy;
struct wl_listener input_method_new_popup_surface;
struct wl_listener keyboard_grab_destroy;
struct wl_listener focused_surface_destroy;
};
struct input_method_popup {
struct wlr_input_popup_surface_v2 *popup_surface;
struct wlr_scene_tree *tree;
struct wlr_scene_tree *scene_surface;
struct input_method_relay *relay;
struct wl_list link; /* input_method_relay.popups */
struct wl_listener destroy;
struct wl_listener commit;
};
struct text_input {
struct input_method_relay *relay;
struct wlr_text_input_v3 *input;
struct wl_list link;
struct wl_listener enable;
struct wl_listener commit;
struct wl_listener disable;
struct wl_listener destroy;
};
struct wlr_input_method_manager_v2 *input_method_manager;
struct wlr_text_input_manager_v3 *text_input_manager;
struct input_method_relay *input_method_relay;
/* functions used in dwl.c */
static int input_method_keyboard_grab_forward_key(
KeyboardGroup *keyboard, struct wlr_keyboard_key_event *event);
static int input_method_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard);
static struct input_method_relay *input_method_relay_create(void);
static void input_method_relay_finish(struct input_method_relay *relay);
static void input_method_relay_set_focus(struct input_method_relay *relay,
struct wlr_surface *surface);
/* internal functions */
static struct text_input *get_active_text_input(struct input_method_relay *relay);
static struct wlr_input_method_keyboard_grab_v2 *get_keyboard_grab(KeyboardGroup *keyboard);
static int keyboard_is_emulated_by_input_method(struct wlr_keyboard *keyboard,
struct wlr_input_method_v2 *input_method);
static void handle_focused_surface_destroy(struct wl_listener *listener, void *data);
static void handle_input_method_commit(struct wl_listener *listener, void *data);
static void handle_input_method_destroy(struct wl_listener *listener, void *data);
static void handle_input_method_grab_keyboard(struct wl_listener *listener, void *data);
static void handle_input_method_new_popup_surface(struct wl_listener *listener, void *data);
static void handle_keyboard_grab_destroy(struct wl_listener *listener, void *data);
static void handle_new_input_method(struct wl_listener *listener, void *data);
static void handle_new_text_input(struct wl_listener *listener, void *data);
static void handle_popup_surface_commit(struct wl_listener *listener, void *data);
static void handle_popup_surface_destroy(struct wl_listener *listener, void *data);
static void handle_text_input_commit(struct wl_listener *listener, void *data);
static void handle_text_input_destroy(struct wl_listener *listener, void *data);
static void handle_text_input_disable(struct wl_listener *listener, void *data);
static void handle_text_input_enable(struct wl_listener *listener, void *data);
static Monitor *output_from_wlr_output(struct wlr_output *wlr_output);
static Monitor *output_nearest_to(int lx, int ly);
static void send_state_to_input_method(struct input_method_relay *relay);
static void update_active_text_input(struct input_method_relay *relay);
static void update_popup_position(struct input_method_popup *popup);
static void update_popups_position(struct input_method_relay *relay);
static void update_text_inputs_focused_surface(struct input_method_relay *relay);
Monitor *
output_from_wlr_output(struct wlr_output *wlr_output)
{
Monitor *m = NULL;
wl_list_for_each(m, &mons, link) {
if (m->wlr_output == wlr_output)
return m;
}
return NULL;
}
Monitor *
output_nearest_to(int lx, int ly)
{
double closest_x, closest_y;
wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x,
&closest_y);
return output_from_wlr_output(
wlr_output_layout_output_at(output_layout, closest_x, closest_y));
}
int
keyboard_is_emulated_by_input_method(struct wlr_keyboard *keyboard,
struct wlr_input_method_v2 *input_method)
{
struct wlr_virtual_keyboard_v1 *virtual_keyboard;
if (!keyboard || !input_method)
return 0;
virtual_keyboard = wlr_input_device_get_virtual_keyboard(&keyboard->base);
return virtual_keyboard &&
wl_resource_get_client(virtual_keyboard->resource) ==
wl_resource_get_client(input_method->resource);
}
struct wlr_input_method_keyboard_grab_v2 *
get_keyboard_grab(KeyboardGroup *keyboard)
{
struct wlr_input_method_v2 *input_method = input_method_relay->input_method;
if (!input_method || !input_method->keyboard_grab || keyboard != kb_group ||
keyboard_is_emulated_by_input_method(keyboard->virtual_keyboard,
input_method))
return NULL;
return input_method->keyboard_grab;
}
int
input_method_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard)
{
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab =
get_keyboard_grab(keyboard);
struct wlr_keyboard_modifiers *modifiers =
&keyboard->wlr_group->keyboard.modifiers;
if (keyboard_grab) {
wlr_input_method_keyboard_grab_v2_set_keyboard(
keyboard_grab, &keyboard->wlr_group->keyboard);
wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab, modifiers);
return 1;
} else {
return 0;
}
}
int
input_method_keyboard_grab_forward_key(
KeyboardGroup *keyboard, struct wlr_keyboard_key_event *event)
{
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab =
get_keyboard_grab(keyboard);
if (keyboard_grab) {
wlr_input_method_keyboard_grab_v2_set_keyboard(
keyboard_grab, &keyboard->wlr_group->keyboard);
wlr_input_method_keyboard_grab_v2_send_key(keyboard_grab, event->time_msec,
event->keycode, event->state);
return 1;
} else {
return 0;
}
}
struct text_input *
get_active_text_input(struct input_method_relay *relay)
{
struct text_input *text_input;
if (!relay->input_method)
return NULL;
wl_list_for_each(text_input, &relay->text_inputs, link) {
if (text_input->input->focused_surface &&
text_input->input->current_enabled)
return text_input;
}
return NULL;
}
void
update_active_text_input(struct input_method_relay *relay)
{
struct text_input *active_text_input = get_active_text_input(relay);
if (relay->input_method && relay->active_text_input != active_text_input) {
if (active_text_input)
wlr_input_method_v2_send_activate(relay->input_method);
else
wlr_input_method_v2_send_deactivate(relay->input_method);
wlr_input_method_v2_send_done(relay->input_method);
}
relay->active_text_input = active_text_input;
}
void
update_text_inputs_focused_surface(struct input_method_relay *relay)
{
struct text_input *text_input;
wl_list_for_each(text_input, &relay->text_inputs, link) {
struct wlr_text_input_v3 *input = text_input->input;
struct wlr_surface *new_focused_surface;
if (relay->input_method && relay->focused_surface &&
wl_resource_get_client(input->resource) ==
wl_resource_get_client(relay->focused_surface->resource)) {
new_focused_surface = relay->focused_surface;
} else {
new_focused_surface = NULL;
}
if (input->focused_surface == new_focused_surface)
continue;
if (input->focused_surface)
wlr_text_input_v3_send_leave(input);
if (new_focused_surface)
wlr_text_input_v3_send_enter(input, new_focused_surface);
}
}
void
update_popup_position(struct input_method_popup *popup)
{
struct input_method_relay *relay = popup->relay;
struct text_input *text_input = relay->active_text_input;
struct wlr_box cursor_rect;
struct wlr_xdg_surface *xdg_surface;
struct wlr_layer_surface_v1 *layer_surface;
struct wlr_scene_tree *tree;
int lx, ly;
Monitor *output;
struct wlr_box output_box;
struct wlr_xdg_positioner_rules positioner_rules;
struct wlr_box popup_box;
if (!text_input || !relay->focused_surface ||
!popup->popup_surface->surface->mapped)
return;
xdg_surface = wlr_xdg_surface_try_from_wlr_surface(relay->focused_surface);
layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(relay->focused_surface);
if ((text_input->input->current.features &
WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE) &&
(xdg_surface || layer_surface)) {
cursor_rect = text_input->input->current.cursor_rectangle;
tree = relay->focused_surface->data;
wlr_scene_node_coords(&tree->node, &lx, &ly);
cursor_rect.x += lx;
cursor_rect.y += ly;
if (xdg_surface) {
cursor_rect.x -= xdg_surface->geometry.x;
cursor_rect.y -= xdg_surface->geometry.y;
}
} else {
cursor_rect = (struct wlr_box){0};
}
output = output_nearest_to(cursor_rect.x, cursor_rect.y);
if (!output || !output->wlr_output->enabled)
return;
wlr_output_layout_get_box(output_layout, output->wlr_output, &output_box);
positioner_rules = (struct wlr_xdg_positioner_rules) {
.anchor_rect = cursor_rect,
.anchor = XDG_POSITIONER_ANCHOR_BOTTOM_LEFT,
.gravity = XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
.size =
{
.width = popup->popup_surface->surface->current.width,
.height = popup->popup_surface->surface->current.height,
},
.constraint_adjustment = XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y |
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X,
};
wlr_xdg_positioner_rules_get_geometry(&positioner_rules, &popup_box);
wlr_xdg_positioner_rules_unconstrain_box(&positioner_rules, &output_box, &popup_box);
wlr_scene_node_set_position(&popup->tree->node, popup_box.x, popup_box.y);
wlr_scene_node_raise_to_top(&relay->popup_tree->node);
wlr_input_popup_surface_v2_send_text_input_rectangle(
popup->popup_surface, &(struct wlr_box){
.x = cursor_rect.x - popup_box.x,
.y = cursor_rect.y - popup_box.y,
.width = cursor_rect.width,
.height = cursor_rect.height,
});
}
void
update_popups_position(struct input_method_relay *relay)
{
struct input_method_popup *popup;
wl_list_for_each(popup, &relay->popups, link) {
update_popup_position(popup);
}
}
void
handle_input_method_commit(struct wl_listener *listener,
void *data)
{
struct input_method_relay *relay =
wl_container_of(listener, relay, input_method_commit);
struct wlr_input_method_v2 *input_method = relay->input_method;
struct text_input *text_input = relay->active_text_input;
if (!text_input)
return;
if (input_method->current.preedit.text) {
wlr_text_input_v3_send_preedit_string(text_input->input,
input_method->current.preedit.text,
input_method->current.preedit.cursor_begin,
input_method->current.preedit.cursor_end);
}
if (input_method->current.commit_text) {
wlr_text_input_v3_send_commit_string(text_input->input,
input_method->current.commit_text);
}
if (input_method->current.delete.before_length ||
input_method->current.delete.after_length) {
wlr_text_input_v3_send_delete_surrounding_text(text_input->input,
input_method->current.delete.before_length,
input_method->current.delete.after_length);
}
wlr_text_input_v3_send_done(text_input->input);
}
void
handle_keyboard_grab_destroy(struct wl_listener *listener,
void *data)
{
struct input_method_relay *relay =
wl_container_of(listener, relay, keyboard_grab_destroy);
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab =
relay->input_method->keyboard_grab;
wl_list_remove(&relay->keyboard_grab_destroy.link);
if (keyboard_grab->keyboard) {
/* Send modifier state to original client */
wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat,
&keyboard_grab->keyboard->modifiers);
}
}
void
handle_input_method_grab_keyboard(struct wl_listener *listener,
void *data)
{
struct input_method_relay *relay =
wl_container_of(listener, relay, input_method_grab_keyboard);
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
struct wlr_keyboard *active_keyboard = &kb_group->wlr_group->keyboard;
if (!keyboard_is_emulated_by_input_method(active_keyboard,
relay->input_method)) {
/* Send modifier state to grab */
wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab,
active_keyboard);
}
relay->keyboard_grab_destroy.notify = handle_keyboard_grab_destroy;
wl_signal_add(&keyboard_grab->events.destroy, &relay->keyboard_grab_destroy);
}
void
handle_input_method_destroy(struct wl_listener *listener,
void *data)
{
struct input_method_relay *relay =
wl_container_of(listener, relay, input_method_destroy);
wl_list_remove(&relay->input_method_commit.link);
wl_list_remove(&relay->input_method_grab_keyboard.link);
wl_list_remove(&relay->input_method_new_popup_surface.link);
wl_list_remove(&relay->input_method_destroy.link);
relay->input_method = NULL;
update_text_inputs_focused_surface(relay);
update_active_text_input(relay);
}
void
handle_popup_surface_destroy(struct wl_listener *listener,
void *data)
{
struct input_method_popup *popup = wl_container_of(listener, popup, destroy);
wlr_scene_node_destroy(&popup->tree->node);
wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->commit.link);
wl_list_remove(&popup->link);
free(popup);
}
void
handle_popup_surface_commit(struct wl_listener *listener,
void *data)
{
struct input_method_popup *popup = wl_container_of(listener, popup, commit);
update_popup_position(popup);
}
void
handle_input_method_new_popup_surface(struct wl_listener *listener,
void *data)
{
struct input_method_relay *relay =
wl_container_of(listener, relay, input_method_new_popup_surface);
struct input_method_popup *popup = ecalloc(1, sizeof(*popup));
popup->popup_surface = data;
popup->relay = relay;
popup->destroy.notify = handle_popup_surface_destroy;
wl_signal_add(&popup->popup_surface->events.destroy, &popup->destroy);
popup->commit.notify = handle_popup_surface_commit;
wl_signal_add(&popup->popup_surface->surface->events.commit, &popup->commit);
popup->tree = wlr_scene_tree_create(layers[LyrIMPopup]);
popup->scene_surface = wlr_scene_subsurface_tree_create(
popup->tree, popup->popup_surface->surface);
popup->scene_surface->node.data = popup;
wl_list_insert(&relay->popups, &popup->link);
update_popup_position(popup);
}
void
handle_new_input_method(struct wl_listener *listener, void *data)
{
struct input_method_relay *relay =
wl_container_of(listener, relay, new_input_method);
struct wlr_input_method_v2 *input_method = data;
if (seat != input_method->seat)
return;
if (relay->input_method) {
wlr_input_method_v2_send_unavailable(input_method);
return;
}
relay->input_method = input_method;
relay->input_method_commit.notify = handle_input_method_commit;
wl_signal_add(&relay->input_method->events.commit,
&relay->input_method_commit);
relay->input_method_grab_keyboard.notify = handle_input_method_grab_keyboard;
wl_signal_add(&relay->input_method->events.grab_keyboard,
&relay->input_method_grab_keyboard);
relay->input_method_destroy.notify = handle_input_method_destroy;
wl_signal_add(&relay->input_method->events.destroy,
&relay->input_method_destroy);
relay->input_method_new_popup_surface.notify =
handle_input_method_new_popup_surface;
wl_signal_add(&relay->input_method->events.new_popup_surface,
&relay->input_method_new_popup_surface);
update_text_inputs_focused_surface(relay);
update_active_text_input(relay);
}
void
send_state_to_input_method(struct input_method_relay *relay)
{
struct wlr_input_method_v2 *input_method = relay->input_method;
struct wlr_text_input_v3 *input = relay->active_text_input->input;
if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT) {
wlr_input_method_v2_send_surrounding_text(input_method,
input->current.surrounding.text,
input->current.surrounding.cursor,
input->current.surrounding.anchor);
}
wlr_input_method_v2_send_text_change_cause(input_method,
input->current.text_change_cause);
if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE) {
wlr_input_method_v2_send_content_type(input_method,
input->current.content_type.hint,
input->current.content_type.purpose);
}
wlr_input_method_v2_send_done(input_method);
}
void
handle_text_input_enable(struct wl_listener *listener, void *data)
{
struct text_input *text_input = wl_container_of(listener, text_input, enable);
struct input_method_relay *relay = text_input->relay;
update_active_text_input(relay);
if (relay->active_text_input == text_input) {
update_popups_position(relay);
send_state_to_input_method(relay);
}
wlr_text_input_v3_send_done(text_input->input);
}
void
handle_text_input_disable(struct wl_listener *listener,
void *data)
{
struct text_input *text_input =
wl_container_of(listener, text_input, disable);
update_active_text_input(text_input->relay);
}
void
handle_text_input_commit(struct wl_listener *listener, void *data)
{
struct text_input *text_input = wl_container_of(listener, text_input, commit);
struct input_method_relay *relay = text_input->relay;
if (relay->active_text_input == text_input) {
update_popups_position(relay);
send_state_to_input_method(relay);
}
}
void
handle_text_input_destroy(struct wl_listener *listener,
void *data)
{
struct text_input *text_input =
wl_container_of(listener, text_input, destroy);
wl_list_remove(&text_input->enable.link);
wl_list_remove(&text_input->disable.link);
wl_list_remove(&text_input->commit.link);
wl_list_remove(&text_input->destroy.link);
wl_list_remove(&text_input->link);
update_active_text_input(text_input->relay);
free(text_input);
}
void
handle_new_text_input(struct wl_listener *listener, void *data)
{
struct input_method_relay *relay =
wl_container_of(listener, relay, new_text_input);
struct wlr_text_input_v3 *wlr_text_input = data;
struct text_input *text_input;
if (seat != wlr_text_input->seat)
return;
text_input = ecalloc(1, sizeof(*text_input));
text_input->input = wlr_text_input;
text_input->relay = relay;
wl_list_insert(&relay->text_inputs, &text_input->link);
text_input->enable.notify = handle_text_input_enable;
wl_signal_add(&text_input->input->events.enable, &text_input->enable);
text_input->disable.notify = handle_text_input_disable;
wl_signal_add(&text_input->input->events.disable, &text_input->disable);
text_input->commit.notify = handle_text_input_commit;
wl_signal_add(&text_input->input->events.commit, &text_input->commit);
text_input->destroy.notify = handle_text_input_destroy;
wl_signal_add(&text_input->input->events.destroy, &text_input->destroy);
update_text_inputs_focused_surface(relay);
}
void
handle_focused_surface_destroy(struct wl_listener *listener,
void *data)
{
struct input_method_relay *relay =
wl_container_of(listener, relay, focused_surface_destroy);
input_method_relay_set_focus(relay, NULL);
}
struct input_method_relay *
input_method_relay_create()
{
struct input_method_relay *relay = ecalloc(1, sizeof(*relay));
wl_list_init(&relay->text_inputs);
wl_list_init(&relay->popups);
relay->popup_tree = wlr_scene_tree_create(&scene->tree);
relay->new_text_input.notify = handle_new_text_input;
wl_signal_add(&text_input_manager->events.new_text_input, &relay->new_text_input);
relay->new_input_method.notify = handle_new_input_method;
wl_signal_add(&input_method_manager->events.new_input_method,
&relay->new_input_method);
relay->focused_surface_destroy.notify = handle_focused_surface_destroy;
return relay;
}
void
input_method_relay_finish(struct input_method_relay *relay)
{
wl_list_remove(&relay->new_text_input.link);
wl_list_remove(&relay->new_input_method.link);
free(relay);
}
void
input_method_relay_set_focus(struct input_method_relay *relay,
struct wlr_surface *surface)
{
if (relay->focused_surface == surface)
return;
if (relay->focused_surface)
wl_list_remove(&relay->focused_surface_destroy.link);
relay->focused_surface = surface;
if (surface)
wl_signal_add(&surface->events.destroy, &relay->focused_surface_destroy);
update_text_inputs_focused_surface(relay);
update_active_text_input(relay);
}
+51
View File
@@ -0,0 +1,51 @@
/* See LICENSE.dwm file for copyright and license details. */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "util.h"
void
die(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
fputc(' ', stderr);
perror(NULL);
} else {
fputc('\n', stderr);
}
exit(1);
}
void *
ecalloc(size_t nmemb, size_t size)
{
void *p;
if (!(p = calloc(nmemb, size)))
die("calloc:");
return p;
}
int
fd_set_nonblock(int fd) {
int flags = fcntl(fd, F_GETFL);
if (flags < 0) {
perror("fcntl(F_GETFL):");
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
perror("fcntl(F_SETFL):");
return -1;
}
return 0;
}
+3 -56
View File
@@ -1,58 +1,5 @@
/* See LICENSE.dwm file for copyright and license details. */
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define END(A) ((A) + LENGTH(A))
static void die(const char *fmt, ...);
static void *ecalloc(size_t nmemb, size_t size);
static int fd_set_nonblock(int fd);
void
die(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
fputc(' ', stderr);
perror(NULL);
} else {
fputc('\n', stderr);
}
exit(1);
}
void *
ecalloc(size_t nmemb, size_t size)
{
void *p;
if (!(p = calloc(nmemb, size)))
die("calloc:");
return p;
}
int
fd_set_nonblock(int fd) {
int flags = fcntl(fd, F_GETFL);
if (flags < 0) {
perror("fcntl(F_GETFL):");
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
perror("fcntl(F_SETFL):");
return -1;
}
return 0;
}
void die(const char *fmt, ...);
void *ecalloc(size_t nmemb, size_t size);
int fd_set_nonblock(int fd);