mirror of
https://codeberg.org/dwl/dwl.git
synced 2026-09-20 14:22:53 +00:00
Compare commits
3
Commits
v0.9
..
f4249db613
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4249db613 | ||
|
|
b2d2b701d7 | ||
|
|
2c9cb2af1b |
+7
-90
@@ -1,98 +1,12 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
* [0.9](#0.9)
|
* [Unreleased](#unreleased)
|
||||||
* [0.8](#0.8)
|
|
||||||
* [0.7](#0.7)
|
* [0.7](#0.7)
|
||||||
* [0.6](#0.6)
|
* [0.6](#0.6)
|
||||||
* [0.5](#0.5)
|
* [0.5](#0.5)
|
||||||
|
|
||||||
|
|
||||||
## 0.9
|
## Unreleased
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
* Add axis mouse bindings ([#652][652])
|
|
||||||
* Add support for the ext-data-control protocol ([#1184][1184])
|
|
||||||
* Add support for the ext-foreign-toplevel-list protocol ([#1223][1223])
|
|
||||||
* Add support for the ext-image-copy-capture and ext-image-capture-source protocols (screensharing) ([#1218][1218], [#1223][1223], [#1224][1224])
|
|
||||||
* Add support for version 4 of the layer shell protocol (on-demand keyboard interactivity) ([#674][674])
|
|
||||||
* Add support for wlr-text-input and wlr-input-method protocols (IME) ([#1219][1219])
|
|
||||||
* Snap windows to edges when moving or resizing them ([#608][608])
|
|
||||||
|
|
||||||
[1184]: https://codeberg.org/dwl/dwl/pulls/1184
|
|
||||||
[1218]: https://codeberg.org/dwl/dwl/pulls/1218
|
|
||||||
[1219]: https://codeberg.org/dwl/dwl/pulls/1219
|
|
||||||
[1223]: https://codeberg.org/dwl/dwl/pulls/1223
|
|
||||||
[1224]: https://codeberg.org/dwl/dwl/pulls/1224
|
|
||||||
[608]: https://codeberg.org/dwl/dwl/pulls/608
|
|
||||||
[652]: https://codeberg.org/dwl/dwl/pulls/652
|
|
||||||
[674]: https://codeberg.org/dwl/dwl/pulls/674
|
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
* Update wlroots to version 0.20 ([#1218][1218])
|
|
||||||
* Use modifier-independent key symbols in config.h keybindings ([#1075][1075])
|
|
||||||
|
|
||||||
[1075]: https://codeberg.org/dwl/dwl/pulls/1075
|
|
||||||
[1218]: https://codeberg.org/dwl/dwl/pulls/1218
|
|
||||||
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
* Apply a minimum window size of 1x1 ([#1231][1231])
|
|
||||||
* Close Xwayland submenus when changing tag or focus ([#1233][1233])
|
|
||||||
* Don't make Firefox draw rounded corners when it is opened ([#d1ebf3c][d1ebf3c])
|
|
||||||
* Don't send key release events to the wrong client ([#1108][1108])
|
|
||||||
* Fix a crash when closing mpv ([#1220][1220])
|
|
||||||
* Fix a crash when destroying an idle-inhibitor ([#1214][1214])
|
|
||||||
* Fix choppy resizing on newer wlroots ([#1280][1280])
|
|
||||||
* Fix the position of certain sub-menus in Xwayland applications ([#1232][1232])
|
|
||||||
* Keep the focused border color on the regular client when opening a layer shell surface like wmenu ([#6013835][6013835])
|
|
||||||
* Let keybindings focus and tag monitors above and below ([#5fd19fe][5fd19fe])
|
|
||||||
* Preserve asleep disabled outputs in output config ([#1198][1198])
|
|
||||||
* Respect size hints ([#4de32d2][4de32d2])
|
|
||||||
* Set seat capabilities for virtual keyboards and pointers when there is no other input device ([#99cdc9a][99cdc9a])
|
|
||||||
* Show popups in fullscreen Xwayland applications ([#1fe1b4e][1fe1b4e])
|
|
||||||
* Show the correct cursor after moving and resizing ([#8ad2c92][8ad2c92])
|
|
||||||
|
|
||||||
[1108]: https://codeberg.org/dwl/dwl/pulls/1108
|
|
||||||
[1198]: https://codeberg.org/dwl/dwl/pulls/1198
|
|
||||||
[1214]: https://codeberg.org/dwl/dwl/pulls/1214
|
|
||||||
[1220]: https://codeberg.org/dwl/dwl/pulls/1220
|
|
||||||
[1231]: https://codeberg.org/dwl/dwl/pulls/1231
|
|
||||||
[1232]: https://codeberg.org/dwl/dwl/pulls/1232
|
|
||||||
[1233]: https://codeberg.org/dwl/dwl/pulls/1233
|
|
||||||
[1280]: https://codeberg.org/dwl/dwl/pulls/1280
|
|
||||||
[1fe1b4e]: https://codeberg.org/dwl/dwl/commit/1fe1b4e
|
|
||||||
[4de32d2]: https://codeberg.org/dwl/dwl/commit/4de32d2
|
|
||||||
[5fd19fe]: https://codeberg.org/dwl/dwl/commit/5fd19fe
|
|
||||||
[6013835]: https://codeberg.org/dwl/dwl/commit/6013835
|
|
||||||
[8ad2c92]: https://codeberg.org/dwl/dwl/commit/8ad2c92
|
|
||||||
[99cdc9a]: https://codeberg.org/dwl/dwl/commit/99cdc9a
|
|
||||||
[d1ebf3c]: https://codeberg.org/dwl/dwl/commit/d1ebf3c
|
|
||||||
|
|
||||||
|
|
||||||
### Contributors
|
|
||||||
|
|
||||||
|
|
||||||
* A Frederick Christensen
|
|
||||||
* Alex Denes
|
|
||||||
* Andrea Chiavazza
|
|
||||||
* Diego Viola
|
|
||||||
* Guido Cella
|
|
||||||
* Leonardo Hernández Hernández
|
|
||||||
* Peter Hofmann
|
|
||||||
* Siva Mahadevan
|
|
||||||
* julmajustus
|
|
||||||
* klim
|
|
||||||
* save196
|
|
||||||
* sewn
|
|
||||||
* thanatos
|
|
||||||
|
|
||||||
|
|
||||||
## 0.8
|
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
* Support for the linux-drm-syncobj-v1 protocol ([wlroots!4715][wlroots!4715], [#685][685])
|
* Support for the linux-drm-syncobj-v1 protocol ([wlroots!4715][wlroots!4715], [#685][685])
|
||||||
@@ -103,12 +17,15 @@
|
|||||||
[646]: https://codeberg.org/dwl/dwl/pulls/646
|
[646]: https://codeberg.org/dwl/dwl/pulls/646
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
### Deprecated
|
||||||
|
### Removed
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
* Crash when a client is created while all outputs are disabled.
|
* Crash when a client is created while all outputs are disabled.
|
||||||
|
|
||||||
|
### Security
|
||||||
Most changes in this release are not listed. See the commits for details.
|
### Contributors
|
||||||
|
|
||||||
|
|
||||||
## 0.7
|
## 0.7
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ include config.mk
|
|||||||
|
|
||||||
# flags for compiling
|
# flags for compiling
|
||||||
DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \
|
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 \
|
DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
|
||||||
-Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \
|
-Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \
|
||||||
-Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \
|
-Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \
|
||||||
@@ -17,11 +17,12 @@ DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEV
|
|||||||
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
|
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
|
||||||
|
|
||||||
all: dwl
|
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
|
||||||
ext-image-copy-capture-v1-protocol.h \
|
$(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 \
|
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
|
||||||
$(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
|
# 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
|
# protocols, which are specified in XML. wlroots requires you to rig these up
|
||||||
@@ -32,9 +33,6 @@ WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols`
|
|||||||
cursor-shape-v1-protocol.h:
|
cursor-shape-v1-protocol.h:
|
||||||
$(WAYLAND_SCANNER) enum-header \
|
$(WAYLAND_SCANNER) enum-header \
|
||||||
$(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@
|
$(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@
|
||||||
ext-image-copy-capture-v1-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) enum-header \
|
|
||||||
$(WAYLAND_PROTOCOLS)/staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml $@
|
|
||||||
pointer-constraints-unstable-v1-protocol.h:
|
pointer-constraints-unstable-v1-protocol.h:
|
||||||
$(WAYLAND_SCANNER) enum-header \
|
$(WAYLAND_SCANNER) enum-header \
|
||||||
$(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
|
$(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
|
||||||
@@ -56,7 +54,7 @@ clean:
|
|||||||
dist: clean
|
dist: clean
|
||||||
mkdir -p dwl-$(VERSION)
|
mkdir -p dwl-$(VERSION)
|
||||||
cp -R LICENSE* Makefile CHANGELOG.md README.md client.h config.def.h \
|
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)
|
dwl-$(VERSION)
|
||||||
tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION)
|
tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION)
|
||||||
rm -rf dwl-$(VERSION)
|
rm -rf dwl-$(VERSION)
|
||||||
@@ -75,3 +73,7 @@ install: dwl
|
|||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 \
|
rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 \
|
||||||
$(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
$(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
||||||
|
|
||||||
|
.SUFFIXES: .c .o
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -c $<
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ primarily in terms of functionality, and secondarily in terms of
|
|||||||
philosophy. Like [dwm], dwl is:
|
philosophy. Like [dwm], dwl is:
|
||||||
|
|
||||||
- Easy to understand, hack on, and extend with patches
|
- 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
|
- Tied to as few external dependencies as possible
|
||||||
|
|
||||||
## Getting Started:
|
## Getting Started:
|
||||||
@@ -31,7 +31,7 @@ depend on functionality that is not in the current release of `wlroots`.
|
|||||||
The `wlroots-next` branch is built against the git version of [wlroots], which
|
The `wlroots-next` branch is built against the git version of [wlroots], which
|
||||||
is unstable and changes frequently. PRs requiring functionality from the git
|
is unstable and changes frequently. PRs requiring functionality from the git
|
||||||
version of `wlroots` should target this branch.
|
version of `wlroots` should target this branch.
|
||||||
|
|
||||||
### Building dwl
|
### Building dwl
|
||||||
dwl has the following dependencies:
|
dwl has the following dependencies:
|
||||||
- libinput
|
- libinput
|
||||||
@@ -153,6 +153,7 @@ given the base on which it is built. Implemented default features are:
|
|||||||
- Support screen lockers via ext-session-lock-v1 protocol
|
- Support screen lockers via ext-session-lock-v1 protocol
|
||||||
- Various Wayland protocols
|
- Various Wayland protocols
|
||||||
- XWayland support as provided by wlroots (can be enabled in `config.mk`)
|
- XWayland support as provided by wlroots (can be enabled in `config.mk`)
|
||||||
|
- Zero flickering - Wayland users naturally expect that "every frame is perfect"
|
||||||
- Layer shell popups (used by Waybar)
|
- Layer shell popups (used by Waybar)
|
||||||
- Damage tracking provided by scenegraph API
|
- Damage tracking provided by scenegraph API
|
||||||
|
|
||||||
@@ -165,6 +166,9 @@ indiscriminately. We will try to keep the code as small as possible.
|
|||||||
Features under consideration (possibly as patches) are:
|
Features under consideration (possibly as patches) are:
|
||||||
|
|
||||||
- Protocols made trivial by wlroots
|
- 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:
|
Feature *non-goals* for the main codebase include:
|
||||||
|
|
||||||
@@ -189,10 +193,6 @@ inspiration, and to the various contributors to the project, including:
|
|||||||
and for helping to keep the project running
|
and for helping to keep the project running
|
||||||
- Stivvo for output management and fullscreen support, and patch maintenance
|
- 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
|
[wlroots]: https://gitlab.freedesktop.org/wlroots
|
||||||
[dwm]: https://dwm.suckless.org/
|
[dwm]: https://dwm.suckless.org/
|
||||||
@@ -213,4 +213,4 @@ Also, thanks to our current lead developers:
|
|||||||
[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars
|
[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars
|
||||||
[Discord server]: https://discord.gg/jJxZnrGPWN
|
[Discord server]: https://discord.gg/jJxZnrGPWN
|
||||||
[Wayland]: https://wayland.freedesktop.org/
|
[Wayland]: https://wayland.freedesktop.org/
|
||||||
[#dwl-official:matrix.org]: https://matrix.to/#/#dwl-official:matrix.org
|
[#dwl-official:matrix.org]: https://matrix.to/#/#dwl-official:matrix.org
|
||||||
@@ -15,32 +15,6 @@ client_is_x11(Client *c)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
|
||||||
client_get_size_hints(Client *c, struct wlr_box *max, struct wlr_box *min)
|
|
||||||
{
|
|
||||||
struct wlr_xdg_toplevel_state *state;
|
|
||||||
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c)) {
|
|
||||||
xcb_size_hints_t *size_hints = c->surface.xwayland->size_hints;
|
|
||||||
if (size_hints) {
|
|
||||||
max->width = size_hints->max_width;
|
|
||||||
max->height = size_hints->max_height;
|
|
||||||
min->width = size_hints->min_width;
|
|
||||||
min->height = size_hints->min_height;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
state = &c->surface.xdg->toplevel->current;
|
|
||||||
max->width = state->max_width;
|
|
||||||
max->height = state->max_height;
|
|
||||||
min->width = state->min_width;
|
|
||||||
min->height = state->min_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline struct wlr_surface *
|
static inline struct wlr_surface *
|
||||||
client_surface(Client *c)
|
client_surface(Client *c)
|
||||||
{
|
{
|
||||||
@@ -232,12 +206,13 @@ client_get_title(Client *c)
|
|||||||
static inline int
|
static inline int
|
||||||
client_is_float_type(Client *c)
|
client_is_float_type(Client *c)
|
||||||
{
|
{
|
||||||
struct wlr_box min = {0}, max = {0};
|
struct wlr_xdg_toplevel *toplevel;
|
||||||
client_get_size_hints(c, &max, &min);
|
struct wlr_xdg_toplevel_state state;
|
||||||
|
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (client_is_x11(c)) {
|
if (client_is_x11(c)) {
|
||||||
struct wlr_xwayland_surface *surface = c->surface.xwayland;
|
struct wlr_xwayland_surface *surface = c->surface.xwayland;
|
||||||
|
xcb_size_hints_t *size_hints = surface->size_hints;
|
||||||
if (surface->modal)
|
if (surface->modal)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -248,13 +223,17 @@ client_is_float_type(Client *c)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return min.width > 0 && min.height > 0 &&
|
return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
|
||||||
(min.width == max.width || min.height == max.height);
|
&& (size_hints->max_width == size_hints->min_width
|
||||||
|
|| size_hints->max_height == size_hints->min_height);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return c->surface.xdg->toplevel->parent || (min.width > 0 && min.height > 0 &&
|
toplevel = c->surface.xdg->toplevel;
|
||||||
(min.width == max.width || min.height == max.height));
|
state = toplevel->current;
|
||||||
|
return toplevel->parent || (state.min_width != 0 && state.min_height != 0
|
||||||
|
&& (state.min_width == state.max_width
|
||||||
|
|| state.min_height == state.max_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
@@ -312,18 +291,11 @@ client_is_unmanaged(Client *c)
|
|||||||
static inline void
|
static inline void
|
||||||
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
|
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
|
||||||
{
|
{
|
||||||
uint32_t filtered[WLR_KEYBOARD_KEYS_CAP];
|
if (kb)
|
||||||
size_t size = 0;
|
wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes,
|
||||||
if (!kb) {
|
kb->num_keycodes, &kb->modifiers);
|
||||||
|
else
|
||||||
wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
|
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
|
static inline void
|
||||||
@@ -365,19 +337,20 @@ client_set_scale(struct wlr_surface *s, float scale)
|
|||||||
wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
|
wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline uint32_t
|
||||||
client_set_size(Client *c, uint32_t width, uint32_t height)
|
client_set_size(Client *c, uint32_t width, uint32_t height)
|
||||||
{
|
{
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (client_is_x11(c)) {
|
if (client_is_x11(c)) {
|
||||||
wlr_xwayland_surface_configure(c->surface.xwayland,
|
wlr_xwayland_surface_configure(c->surface.xwayland,
|
||||||
c->geom.x + c->bw, c->geom.y + c->bw, width, height);
|
c->geom.x + c->bw, c->geom.y + c->bw, width, height);
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if ((int32_t)width != c->surface.xdg->toplevel->current.width
|
if ((int32_t)width == c->surface.xdg->toplevel->current.width
|
||||||
|| (int32_t)height != c->surface.xdg->toplevel->current.height)
|
&& (int32_t)height == c->surface.xdg->toplevel->current.height)
|
||||||
wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
|
return 0;
|
||||||
|
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|||||||
+18
-23
@@ -7,7 +7,6 @@
|
|||||||
static const int sloppyfocus = 1; /* focus follows mouse */
|
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 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 */
|
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||||
static const unsigned int snap = 32; /* snap pixel */
|
|
||||||
static const float rootcolor[] = COLOR(0x222222ff);
|
static const float rootcolor[] = COLOR(0x222222ff);
|
||||||
static const float bordercolor[] = COLOR(0x444444ff);
|
static const float bordercolor[] = COLOR(0x444444ff);
|
||||||
static const float focuscolor[] = COLOR(0x005577ff);
|
static const float focuscolor[] = COLOR(0x005577ff);
|
||||||
@@ -106,11 +105,11 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
|
|||||||
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
|
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
|
||||||
#define MODKEY WLR_MODIFIER_ALT
|
#define MODKEY WLR_MODIFIER_ALT
|
||||||
|
|
||||||
#define TAGKEYS(KEY,TAG) \
|
#define TAGKEYS(KEY,SKEY,TAG) \
|
||||||
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||||
{ MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \
|
{ MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, KEY, tag, {.ui = 1 << TAG} }, \
|
{ MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
|
||||||
{ MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,KEY,toggletag, {.ui = 1 << TAG} }
|
{ MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }
|
||||||
|
|
||||||
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
|
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
|
||||||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||||
@@ -120,6 +119,7 @@ static const char *termcmd[] = { "foot", NULL };
|
|||||||
static const char *menucmd[] = { "wmenu-run", NULL };
|
static const char *menucmd[] = { "wmenu-run", NULL };
|
||||||
|
|
||||||
static const Key keys[] = {
|
static const Key keys[] = {
|
||||||
|
/* Note that Shift changes certain key codes: 2 -> at, etc. */
|
||||||
/* modifier key function argument */
|
/* modifier key function argument */
|
||||||
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
|
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
||||||
@@ -139,28 +139,28 @@ static const Key keys[] = {
|
|||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||||
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
|
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_0, tag, {.ui = ~0} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
|
||||||
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
|
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
|
||||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_comma, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_period, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||||
TAGKEYS( XKB_KEY_1, 0),
|
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||||
TAGKEYS( XKB_KEY_2, 1),
|
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||||
TAGKEYS( XKB_KEY_3, 2),
|
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||||
TAGKEYS( XKB_KEY_4, 3),
|
TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3),
|
||||||
TAGKEYS( XKB_KEY_5, 4),
|
TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4),
|
||||||
TAGKEYS( XKB_KEY_6, 5),
|
TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5),
|
||||||
TAGKEYS( XKB_KEY_7, 6),
|
TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
|
||||||
TAGKEYS( XKB_KEY_8, 7),
|
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
|
||||||
TAGKEYS( XKB_KEY_9, 8),
|
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q, quit, {0} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q, quit, {0} },
|
||||||
|
|
||||||
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
|
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
|
||||||
{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_BackSpace, quit, {0} },
|
{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
|
||||||
/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
|
/* Ctrl-Alt-Fx is used to switch to another VT, if you don't know what a VT is
|
||||||
* do not remove them.
|
* do not remove them.
|
||||||
*/
|
*/
|
||||||
#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_F##n, chvt, {.ui = (n)} }
|
#define CHVT(n) { WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_XF86Switch_VT_##n, chvt, {.ui = (n)} }
|
||||||
CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),
|
CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(5), CHVT(6),
|
||||||
CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
|
CHVT(7), CHVT(8), CHVT(9), CHVT(10), CHVT(11), CHVT(12),
|
||||||
};
|
};
|
||||||
@@ -170,8 +170,3 @@ static const Button buttons[] = {
|
|||||||
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
|
{ MODKEY, BTN_MIDDLE, togglefloating, {0} },
|
||||||
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
|
{ MODKEY, BTN_RIGHT, moveresize, {.ui = CurResize} },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Axis axes[] = {
|
|
||||||
{ MODKEY, AxisUp, spawn, SHCMD("volume-up_EXAMPLE") },
|
|
||||||
{ MODKEY, AxisDown, spawn, SHCMD("volume-down_EXAMPLE") },
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -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 \
|
#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \
|
||||||
# -I$(PWD)/wlroots/include
|
# -I$(PWD)/wlroots/include
|
||||||
# Set -rpath to avoid using the wrong library.
|
# 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 \
|
#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \
|
||||||
# -I$(PWD)/wlroots/0.20/include/wlroots-0.20
|
# -I$(PWD)/wlroots/0.19/include/wlroots-0.19
|
||||||
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.20/lib64 -L$(PWD)/wlroots/0.20/lib64 -lwlroots-0.20
|
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.19/lib64 -L$(PWD)/wlroots/0.19/lib64 -lwlroots-0.19
|
||||||
|
|
||||||
XWAYLAND =
|
XWAYLAND =
|
||||||
XLIBS =
|
XLIBS =
|
||||||
|
|||||||
@@ -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 || 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);
|
|
||||||
}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -1,70 +1,5 @@
|
|||||||
/* See LICENSE.dwm file for copyright and license details. */
|
/* 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 <xkbcommon/xkbcommon.h>
|
|
||||||
|
|
||||||
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
void die(const char *fmt, ...);
|
||||||
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
void *ecalloc(size_t nmemb, size_t size);
|
||||||
#define LENGTH(X) (sizeof X / sizeof X[0])
|
int fd_set_nonblock(int fd);
|
||||||
#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);
|
|
||||||
xkb_keysym_t keymap_get_one_sym_by_level(struct xkb_keymap *keymap,
|
|
||||||
xkb_keycode_t key, xkb_layout_index_t layout, xkb_level_index_t level);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
xkb_keysym_t
|
|
||||||
keymap_get_one_sym_by_level(struct xkb_keymap *keymap, xkb_keycode_t key,
|
|
||||||
xkb_layout_index_t layout, xkb_level_index_t level)
|
|
||||||
{
|
|
||||||
const xkb_keysym_t *syms;
|
|
||||||
int count = xkb_keymap_key_get_syms_by_level(keymap, key, layout, level, &syms);
|
|
||||||
return count ? syms[0] : XKB_KEY_NoSymbol;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user