Added uselessgaps patch
This commit is contained in:
parent
833988a1ac
commit
ece9df9049
|
@ -1,3 +1,5 @@
|
|||
#include <X11/XF86keysym.h>
|
||||
|
||||
/* Taken from https://github.com/djpohly/dwl/issues/466 */
|
||||
#define COLOR(hex) { ((hex >> 24) & 0xFF) / 255.0f, \
|
||||
((hex >> 16) & 0xFF) / 255.0f, \
|
||||
|
@ -5,8 +7,10 @@
|
|||
(hex & 0xFF) / 255.0f }
|
||||
/* appearance */
|
||||
static const int sloppyfocus = 1; /* focus follows mouse */
|
||||
static const int smartgaps = 0;
|
||||
static const unsigned int gappx = 10; /* horiz inner gap between windows */
|
||||
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 = 4; /* border pixel of windows */
|
||||
static const unsigned int borderpx = 2; /* border pixel of windows */
|
||||
static const float bordercolor[] = COLOR(0x444444ff);
|
||||
static const float focuscolor[] = COLOR(0x005577ff);
|
||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
|
@ -19,9 +23,19 @@ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can al
|
|||
/* logging */
|
||||
static int log_level = WLR_ERROR;
|
||||
|
||||
#define CLOSE_TAB "Extension: (Tree Style Tab) - Close tabs? — Mozilla Firefox"
|
||||
static const Rule rules[] = {
|
||||
/* app_id title tags mask isfloating monitor */
|
||||
{ "firefox", NULL, 1, 0, -1 },
|
||||
{ "firefox", NULL, 1, 0, 1 },
|
||||
{ "firefox", CLOSE_TAB, 1, 1, -1},
|
||||
{ "q4wine", NULL, 1 << 7, 1, 1 },
|
||||
{ "pragha", NULL, 1 << 5, 0, 1 },
|
||||
{ "org.keepassxc.KeePassXC", NULL, 1, 0, 0 },
|
||||
{ "org.kde.akregator", NULL, 1 << 6, 0, 1 },
|
||||
{ "Signal", NULL, 1 << 2, 0, 1 },
|
||||
{ "Element", NULL, 1 << 2, 0, 1 },
|
||||
{ "thunderbird-default", NULL, 1 << 1, 0, 1 },
|
||||
{ "flameshot", NULL, ~0, 1, -1},
|
||||
};
|
||||
|
||||
/* layout(s) */
|
||||
|
@ -109,14 +123,19 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
|
|||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||
|
||||
/* commands */
|
||||
//static const char *termcmd[] = { "foot", NULL };
|
||||
//static const char *menucmd[] = { "bemenu-run", NULL };
|
||||
|
||||
static const Key keys[] = {
|
||||
/* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
|
||||
/* modifier key function argument */
|
||||
{ MODKEY, XKB_KEY_p, spawn, SHCMD("xfce4-terminal") },
|
||||
{ MODKEY, XKB_KEY_r, spawn, SHCMD("/home/charadon/Applications/dwl/builddir/subprojects/wofi/wofi -l top -H 200 -W 1920 -G -o DP-1 -m -I -S drun") },
|
||||
{ 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("pamixer -i 10 && ogg123 /usr/share/sounds/freedesktop/stereo/audio-volume-change.oga")},
|
||||
{ 0, XF86XK_AudioLowerVolume, spawn, SHCMD("pamixer -d 10 && ogg123 /usr/share/sounds/freedesktop/stereo/audio-volume-change.oga")},
|
||||
{ 0, XKB_KEY_Print, spawn, SHCMD("org.flameshot.Flameshot gui") },
|
||||
{ 0, XKB_KEY_XF86AudioPlay, spawn, SHCMD("./runtime-scripts/playerctl-toggle.sh") },
|
||||
{ 0, XKB_KEY_XF86AudioNext, spawn, SHCMD("playerctl -p pragha next") },
|
||||
{ 0, XKB_KEY_XF86AudioPrev, spawn, SHCMD("playerctl -p pragha previous") },
|
||||
{ 0, XKB_KEY_XF86AudioStop, spawn, SHCMD("playerctl -p pragha stop") },
|
||||
{ MODKEY, XKB_KEY_g, togglegaps, {0} },
|
||||
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
|
||||
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
|
||||
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
|
||||
|
@ -131,7 +150,7 @@ static const Key keys[] = {
|
|||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_ALT, XKB_KEY_space, togglefloating, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_f, togglefullscreen, {0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_F, togglefullscreen, {0} },
|
||||
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
|
||||
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
|
||||
|
|
30
run.sh
30
run.sh
|
@ -1,6 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Panel must come first!
|
||||
builddir/subprojects/dwl-bar/dwl-bar <&- &
|
||||
|
||||
# Audio
|
||||
pipewire &
|
||||
sleep 0.2s
|
||||
|
@ -8,13 +10,37 @@ pipewire-pulse &
|
|||
sleep 0.2s
|
||||
wireplumber &
|
||||
sleep 0.2s
|
||||
# This is an autostart
|
||||
|
||||
|
||||
# xdg-desktop-portal
|
||||
#/usr/lib64/libexec/xdg-desktop-portal-kde &
|
||||
/usr/libexec/xdg-desktop-portal-wlr &
|
||||
|
||||
# Notifactions
|
||||
swaync &
|
||||
|
||||
# Tray
|
||||
builddir/subprojects/someblocks/someblocks &
|
||||
nm-applet &
|
||||
|
||||
# Backgrounds
|
||||
swaybg -o DP-1 -i "/home/charadon/Pictures/wp1926016.jpg" &
|
||||
swaybg -o HDMI-A-2 -i "/home/charadon/Pictures/1583944.jpg" &
|
||||
|
||||
# Autostart Applications
|
||||
keepassxc &
|
||||
akregator &
|
||||
/opt/Element/element-desktop &
|
||||
/opt/Signal/signal-desktop &
|
||||
"/opt/Mullvad VPN/mullvad-gui" &
|
||||
thunderbird &
|
||||
firefox &
|
||||
pragha &
|
||||
q4wine &
|
||||
flameshot &
|
||||
|
||||
# Daemons
|
||||
gammastep &
|
||||
|
||||
|
||||
# Lock Screen
|
||||
builddir/subprojects/swayidle/swayidle -w before-sleep swaylock &
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/sh
|
||||
set -eu
|
||||
# Purpose:
|
||||
# Pragha doesn't properly support mpris standards. So I need to check it's status
|
||||
# and act accordingly.
|
||||
|
||||
if [ "$(playerctl -p pragha status)" = "Paused" ];
|
||||
then
|
||||
playerctl -p pragha play
|
||||
else
|
||||
playerctl -p pragha pause
|
||||
fi
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
# Set up environment.
|
||||
$ENV{XDG_CURRENT_DESKTOP} = "sway";
|
||||
$ENV{XDG_CURRENT_SESSION} = "sway";
|
||||
$ENV{SDL_VIDEODRIVER} = "wayland,x11";
|
||||
$ENV{QT_QPA_PLATFORM} = "wayland";
|
||||
$ENV{CLUTTER_BACKEND} = "wayland";
|
||||
|
||||
my $XDG_RUNTIME_DIR = $ENV{XDG_RUNTIME_DIR};
|
||||
|
||||
# Clean up some files
|
||||
unlink("$XDG_RUNTIME_DIR/dwl-bar-0");
|
||||
|
||||
# Run window manager.
|
||||
system("ninja -C builddir && dbus-run-session builddir/dwl -s \"./run.sh\"");
|
||||
|
||||
# Terminate problematic programs.
|
||||
`pkill someblocks`;
|
42
src/dwl.c
42
src/dwl.c
|
@ -202,6 +202,7 @@ struct Monitor {
|
|||
struct wlr_box w; /* window area, layout-relative */
|
||||
struct wl_list layers[4]; /* LayerSurface::link */
|
||||
const Layout *lt[2];
|
||||
int gappx; /* Useless Gaps: How wide the gap is in pixels */
|
||||
Pertag *pertag;
|
||||
unsigned int seltags;
|
||||
unsigned int sellt;
|
||||
|
@ -341,6 +342,7 @@ static void togglebar(const Arg *arg);
|
|||
static void tile(Monitor *m);
|
||||
static void togglefloating(const Arg *arg);
|
||||
static void togglefullscreen(const Arg *arg);
|
||||
static void togglegaps(const Arg *arg); /* Useless Gaps */
|
||||
static void toggletag(const Arg *arg);
|
||||
static void toggleview(const Arg *arg);
|
||||
static void unlocksession(struct wl_listener *listener, void *data);
|
||||
|
@ -407,6 +409,7 @@ static struct wlr_output_layout *output_layout;
|
|||
static struct wlr_box sgeom;
|
||||
static struct wl_list mons;
|
||||
static Monitor *selmon;
|
||||
static int enablegaps = 1; /* enables gaps, used by togglegaps */
|
||||
|
||||
#ifdef XWAYLAND
|
||||
static void activatex11(struct wl_listener *listener, void *data);
|
||||
|
@ -925,6 +928,7 @@ createmon(struct wl_listener *listener, void *data)
|
|||
/* Initialize monitor state using configured rules */
|
||||
for (i = 0; i < LENGTH(m->layers); i++)
|
||||
wl_list_init(&m->layers[i]);
|
||||
m->gappx = gappx; /* Useless Gaps: Adds gap width to monitor */
|
||||
m->tagset[0] = m->tagset[1] = 1;
|
||||
for (r = monrules; r < END(monrules); r++) {
|
||||
if (!r->name || strstr(wlr_output->name, r->name)) {
|
||||
|
@ -2618,7 +2622,7 @@ tagmon(const Arg *arg)
|
|||
void
|
||||
tile(Monitor *m)
|
||||
{
|
||||
unsigned int i, n = 0, mw, my, ty;
|
||||
unsigned int i, n = 0, h, r, e = enablegaps, mw, my, ty;
|
||||
Client *c;
|
||||
|
||||
wl_list_for_each(c, &clients, link)
|
||||
|
@ -2627,22 +2631,32 @@ tile(Monitor *m)
|
|||
if (n == 0)
|
||||
return;
|
||||
|
||||
/* If window is the only one there, hide gaps */
|
||||
if (smartgaps == n) {
|
||||
e = 0; // outer gaps disabled
|
||||
}
|
||||
|
||||
if (n > m->nmaster)
|
||||
mw = m->nmaster ? m->w.width * m->mfact : 0;
|
||||
mw = m->nmaster ? (m->w.width + m->gappx*e) * m->mfact : 0;
|
||||
else
|
||||
mw = m->w.width;
|
||||
i = my = ty = 0;
|
||||
mw = m->w.width - 2*m->gappx*e + m->gappx*e;
|
||||
i = 0;
|
||||
my = ty = m->gappx*e;
|
||||
wl_list_for_each(c, &clients, link) {
|
||||
if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
|
||||
continue;
|
||||
if (i < m->nmaster) {
|
||||
resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
|
||||
.height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);
|
||||
my += c->geom.height;
|
||||
r = MIN(n, m->nmaster) - i;
|
||||
h = (m->w.height - my - m->gappx*e - m->gappx*e * (r - 1)) / r;
|
||||
resize(c, (struct wlr_box){.x = m->w.x + m->gappx*e, .y = m->w.y + my,
|
||||
.width = mw - m->gappx*e, .height = h}, 0);
|
||||
my += c->geom.height + m->gappx*e;
|
||||
} else {
|
||||
resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
|
||||
.width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
|
||||
ty += c->geom.height;
|
||||
r = n - i;
|
||||
h = (m->w.height - ty - m->gappx*e - m->gappx*e * (r - 1)) / r;
|
||||
resize(c, (struct wlr_box){.x = m->w.x + mw + m->gappx*e, .y = m->w.y + ty,
|
||||
.width = m->w.width - mw - 2*m->gappx*e, .height = h}, 0);
|
||||
ty += c->geom.height + m->gappx*e;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -2674,6 +2688,14 @@ togglefullscreen(const Arg *arg)
|
|||
setfullscreen(sel, !sel->isfullscreen);
|
||||
}
|
||||
|
||||
void
|
||||
togglegaps(const Arg *arg)
|
||||
{
|
||||
enablegaps = !enablegaps;
|
||||
arrange(selmon);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
toggletag(const Arg *arg)
|
||||
{
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ec8662603915b368172eab92d14913c14b223e56
|
|
@ -0,0 +1,4 @@
|
|||
xdg-shell-protocol.c
|
||||
xdg-shell-protocol.h
|
||||
wev
|
||||
wev.1
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2019 Drew DeVault
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,43 @@
|
|||
WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
|
||||
WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner)
|
||||
SCDOC=$(shell pkg-config --variable=scdoc scdoc)
|
||||
LIBS=\
|
||||
$(shell pkg-config --cflags --libs wayland-client) \
|
||||
$(shell pkg-config --cflags --libs xkbcommon)
|
||||
|
||||
xdg-shell-protocol.h:
|
||||
$(WAYLAND_SCANNER) client-header \
|
||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
||||
|
||||
xdg-shell-protocol.c: xdg-shell-protocol.h
|
||||
$(WAYLAND_SCANNER) private-code \
|
||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
||||
|
||||
wev: wev.c shm.c xdg-shell-protocol.h xdg-shell-protocol.c
|
||||
$(CC) $(CFLAGS) \
|
||||
-g -std=c11 -I. \
|
||||
-o wev wev.c shm.c xdg-shell-protocol.c \
|
||||
$(LIBS) -lrt
|
||||
|
||||
wev.1: wev.1.scd
|
||||
$(SCDOC) < wev.1.scd > wev.1
|
||||
|
||||
all: wev wev.1
|
||||
|
||||
PREFIX?=/usr/local
|
||||
BINDIR?=$(PREFIX)/bin
|
||||
SHAREDIR?=$(PREFIX)/share
|
||||
MANDIR?=$(SHAREDIR)/man
|
||||
DESTDIR?=
|
||||
|
||||
install: wev
|
||||
mkdir -p $(DESTDIR)$(BINDIR)
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||
install -m755 wev $(DESTDIR)$(BINDIR)/wev
|
||||
install -m644 wev.1 $(DESTDIR)$(MANDIR)/man1/wev.1
|
||||
|
||||
clean:
|
||||
rm -f wev wev.1 xdg-shell-protocol.h xdg-shell-protocol.c
|
||||
|
||||
.DEFAULT_GOAL=all
|
||||
.PHONY: all install clean
|
|
@ -0,0 +1,22 @@
|
|||
# wayland event viewer
|
||||
|
||||
This is a tool for debugging events on a Wayland window, analagous to the X11
|
||||
tool xev.
|
||||
|
||||
## Installation
|
||||
|
||||
wev depends on libwayland-client and libxkbcommon.
|
||||
|
||||
$ make
|
||||
# make install
|
||||
|
||||
## Usage
|
||||
|
||||
wev [-g] [-f <interface[:event]>] [-F <interface[:event]>] [-M <path>]
|
||||
|
||||
See `wev(1)` for details.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please send patches to
|
||||
[~sircmpwn/public-inbox@lists.sr.ht](https://lists.sr.ht/~sircmpwn/public-inbox)
|
|
@ -0,0 +1,53 @@
|
|||
#define _POSIX_C_SOURCE 200112L
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void randname(char *buf) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
long r = ts.tv_nsec;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
buf[i] = 'A'+(r&15)+(r&16)*2;
|
||||
r >>= 5;
|
||||
}
|
||||
}
|
||||
|
||||
int create_shm_file(void) {
|
||||
int retries = 100;
|
||||
do {
|
||||
char name[] = "/wev-XXXXXX";
|
||||
randname(name + strlen(name) - 6);
|
||||
|
||||
--retries;
|
||||
// CLOEXEC is guaranteed to be set by shm_open
|
||||
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (fd >= 0) {
|
||||
shm_unlink(name);
|
||||
return fd;
|
||||
}
|
||||
} while (retries > 0 && errno == EEXIST);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int allocate_shm_file(size_t size) {
|
||||
int fd = create_shm_file();
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret;
|
||||
do {
|
||||
ret = ftruncate(fd, size);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
if (ret < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef SHM_H
|
||||
#define SHM_H
|
||||
|
||||
int create_shm_file(void);
|
||||
int allocate_shm_file(size_t size);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
wev(1)
|
||||
|
||||
# NAME
|
||||
|
||||
wev - show wayland events
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
*wev* [-g] [-f <_interface[:event]_>] [-F <_interface[:event]_>] [-M <_path_>]
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
wev opens an xdg-shell toplevel on the default Wayland display (via the
|
||||
*WAYLAND_DISPLAY* environment variable), then prints events associated with
|
||||
that display.
|
||||
|
||||
# OPTIONS
|
||||
|
||||
*-g*
|
||||
Print globals.
|
||||
|
||||
*-f* <_interface[:event]_>
|
||||
Only show events for the given Wayland interface, or for a specific event
|
||||
from that interface. May be specified more than once to show several
|
||||
interfaces and/or events.
|
||||
|
||||
*-F* <_interface[:event]_>
|
||||
Show all events except those from the given Wayland interface, or except
|
||||
for a specific event from that interface. May be specified more than once to
|
||||
hide several interfaces and/or events.
|
||||
|
||||
*-M* <_path_>
|
||||
Writes the wl_keyboard's keymap to the specified path.
|
||||
|
||||
# AUTHORS
|
||||
|
||||
Maintained by Drew DeVault <sir@cmpwn.com>. Up-to-date sources can be found at
|
||||
https://git.sr.ht/~sircmpwn/wev and bugs/patches can be submitted by email to
|
||||
~sircmpwn/public-inbox@lists.sr.ht.
|
|
@ -0,0 +1,927 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client-core.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "shm.h"
|
||||
#include "xdg-shell-protocol.h"
|
||||
|
||||
struct wev_filter {
|
||||
char *interface;
|
||||
char *event;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
struct wev_options {
|
||||
bool print_globals;
|
||||
char *dump_map;
|
||||
struct wl_list filters;
|
||||
struct wl_list inverse_filters;
|
||||
};
|
||||
|
||||
struct wev_state {
|
||||
struct wev_options opts;
|
||||
bool closed;
|
||||
|
||||
struct wl_display *display;
|
||||
struct wl_registry *registry;
|
||||
struct wl_compositor *compositor;
|
||||
struct wl_seat *seat;
|
||||
struct wl_shm *shm;
|
||||
struct xdg_wm_base *wm_base;
|
||||
struct wl_data_device_manager *data_device_manager;
|
||||
|
||||
struct wl_surface *surface;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
|
||||
int32_t width, height;
|
||||
|
||||
struct xkb_state *xkb_state;
|
||||
struct xkb_context *xkb_context;
|
||||
struct xkb_keymap *xkb_keymap;
|
||||
|
||||
struct wl_data_offer *selection;
|
||||
struct wl_data_offer *dnd;
|
||||
};
|
||||
|
||||
#define SPACER " "
|
||||
|
||||
static int proxy_log(struct wev_state *state,
|
||||
struct wl_proxy *proxy, const char *event, const char *fmt, ...) {
|
||||
const char *class = wl_proxy_get_class(proxy);
|
||||
|
||||
if (!wl_list_empty(&state->opts.filters)) {
|
||||
bool found = false;
|
||||
struct wev_filter *filter;
|
||||
wl_list_for_each(filter, &state->opts.filters, link) {
|
||||
if (strcmp(filter->interface, class) == 0 &&
|
||||
(!filter->event || strcmp(filter->event, event) == 0)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!wl_list_empty(&state->opts.inverse_filters)) {
|
||||
bool found = false;
|
||||
struct wev_filter *filter;
|
||||
wl_list_for_each(filter, &state->opts.inverse_filters, link) {
|
||||
if (strcmp(filter->interface, class) == 0 &&
|
||||
(!filter->event || strcmp(filter->event, event) == 0)) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int n = 0;
|
||||
n += printf("[%02u:%16s] %s%s",
|
||||
wl_proxy_get_id(proxy),
|
||||
class, event, strcmp(fmt, "\n") != 0 ? ": " : "");
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
n += vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t serial, struct wl_surface *surface,
|
||||
wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_pointer, "enter",
|
||||
"serial: %d; surface: %d, x, y: %f, %f\n",
|
||||
serial, wl_proxy_get_id((struct wl_proxy *)surface),
|
||||
wl_fixed_to_double(surface_x),
|
||||
wl_fixed_to_double(surface_y));
|
||||
}
|
||||
|
||||
static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t serial, struct wl_surface *surface) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_pointer, "leave", "surface: %d\n",
|
||||
wl_proxy_get_id((struct wl_proxy *)surface));
|
||||
}
|
||||
|
||||
static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_pointer, "motion",
|
||||
"time: %d; x, y: %f, %f\n", time,
|
||||
wl_fixed_to_double(surface_x),
|
||||
wl_fixed_to_double(surface_y));
|
||||
}
|
||||
|
||||
static const char *pointer_button_str(uint32_t button) {
|
||||
switch (button) {
|
||||
case BTN_LEFT:
|
||||
return "left";
|
||||
case BTN_RIGHT:
|
||||
return "right";
|
||||
case BTN_MIDDLE:
|
||||
return "middle";
|
||||
case BTN_SIDE:
|
||||
return "side";
|
||||
case BTN_EXTRA:
|
||||
return "extra";
|
||||
case BTN_FORWARD:
|
||||
return "forward";
|
||||
case BTN_BACK:
|
||||
return "back";
|
||||
case BTN_TASK:
|
||||
return "task";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *pointer_state_str(uint32_t state) {
|
||||
switch (state) {
|
||||
case WL_POINTER_BUTTON_STATE_RELEASED:
|
||||
return "released";
|
||||
case WL_POINTER_BUTTON_STATE_PRESSED:
|
||||
return "pressed";
|
||||
default:
|
||||
return "unknown state";
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
|
||||
struct wev_state *wev_state = data;
|
||||
proxy_log(wev_state, (struct wl_proxy *)wl_pointer, "button",
|
||||
"serial: %d; time: %d; button: %d (%s), state: %d (%s)\n",
|
||||
serial, time,
|
||||
button, pointer_button_str(button),
|
||||
state, pointer_state_str(state));
|
||||
}
|
||||
|
||||
static const char *pointer_axis_str(uint32_t axis) {
|
||||
switch (axis) {
|
||||
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
||||
return "vertical";
|
||||
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
||||
return "horizontal";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t time, uint32_t axis, wl_fixed_t value) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_pointer, "axis",
|
||||
"time: %d; axis: %d (%s), value: %f\n",
|
||||
time, axis, pointer_axis_str(axis), wl_fixed_to_double(value));
|
||||
}
|
||||
|
||||
static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_pointer, "frame", "\n");
|
||||
}
|
||||
|
||||
static const char *pointer_axis_source_str(uint32_t axis_source) {
|
||||
switch (axis_source) {
|
||||
case WL_POINTER_AXIS_SOURCE_WHEEL:
|
||||
return "wheel";
|
||||
case WL_POINTER_AXIS_SOURCE_FINGER:
|
||||
return "finger";
|
||||
case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
|
||||
return "continuous";
|
||||
case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
|
||||
return "wheel tilt";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t axis_source) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_pointer, "axis_source",
|
||||
"%d (%s)\n", axis_source, pointer_axis_source_str(axis_source));
|
||||
}
|
||||
|
||||
static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t time, uint32_t axis) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_pointer, "axis_stop",
|
||||
"time: %d; axis: %d (%s)\n",
|
||||
time, axis, pointer_axis_str(axis));
|
||||
}
|
||||
|
||||
static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer,
|
||||
uint32_t axis, int32_t discrete) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_pointer, "axis_stop",
|
||||
"axis: %d (%s), discrete: %d\n",
|
||||
axis, pointer_axis_str(axis), discrete);
|
||||
}
|
||||
|
||||
static const struct wl_pointer_listener wl_pointer_listener = {
|
||||
.enter = wl_pointer_enter,
|
||||
.leave = wl_pointer_leave,
|
||||
.motion = wl_pointer_motion,
|
||||
.button = wl_pointer_button,
|
||||
.axis = wl_pointer_axis,
|
||||
.frame = wl_pointer_frame,
|
||||
.axis_source = wl_pointer_axis_source,
|
||||
.axis_stop = wl_pointer_axis_stop,
|
||||
.axis_discrete = wl_pointer_axis_discrete,
|
||||
};
|
||||
|
||||
static const char *keymap_format_str(uint32_t format) {
|
||||
switch (format) {
|
||||
case WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP:
|
||||
return "none";
|
||||
case WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1:
|
||||
return "xkb v1";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t format, int32_t fd, uint32_t size) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_keyboard, "keymap",
|
||||
"format: %d (%s), size: %d\n",
|
||||
format, keymap_format_str(format), size);
|
||||
char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (map_shm == MAP_FAILED) {
|
||||
close(fd);
|
||||
fprintf(stderr, "Unable to mmap keymap: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (state->opts.dump_map) {
|
||||
FILE *f = fopen(state->opts.dump_map, "w");
|
||||
fwrite(map_shm, 1, size, f);
|
||||
fclose(f);
|
||||
}
|
||||
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
||||
munmap(map_shm, size);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
struct xkb_keymap *keymap = xkb_keymap_new_from_string(
|
||||
state->xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
munmap(map_shm, size);
|
||||
close(fd);
|
||||
|
||||
struct xkb_state *xkb_state = xkb_state_new(keymap);
|
||||
xkb_keymap_unref(state->xkb_keymap);
|
||||
xkb_state_unref(state->xkb_state);
|
||||
state->xkb_keymap = keymap;
|
||||
state->xkb_state = xkb_state;
|
||||
}
|
||||
|
||||
static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
|
||||
struct wev_state *state = data;
|
||||
int n = proxy_log(state, (struct wl_proxy *)wl_keyboard, "enter",
|
||||
"serial: %d; surface: %d\n", serial,
|
||||
wl_proxy_get_id((struct wl_proxy *)surface));
|
||||
if (n != 0) {
|
||||
uint32_t *key;
|
||||
wl_array_for_each(key, keys) {
|
||||
char buf[128];
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(
|
||||
state->xkb_state, *key + 8);
|
||||
xkb_keysym_get_name(sym, buf, sizeof(buf));
|
||||
printf(SPACER "sym: %-12s (%d), ", buf, sym);
|
||||
xkb_state_key_get_utf8(
|
||||
state->xkb_state, *key + 8, buf, sizeof(buf));
|
||||
printf("utf8: '%s'\n", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, struct wl_surface *surface) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_keyboard, "leave",
|
||||
"serial: %d; surface: %d\n", serial,
|
||||
wl_proxy_get_id((struct wl_proxy *)surface));
|
||||
}
|
||||
|
||||
static const char *key_state_str(uint32_t state) {
|
||||
switch (state) {
|
||||
case WL_KEYBOARD_KEY_STATE_RELEASED:
|
||||
return "released";
|
||||
case WL_KEYBOARD_KEY_STATE_PRESSED:
|
||||
return "pressed";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
|
||||
struct wev_state *wev_state = data;
|
||||
int n = proxy_log(wev_state, (struct wl_proxy *)wl_keyboard, "key",
|
||||
"serial: %d; time: %d; key: %d; state: %d (%s)\n",
|
||||
serial, time, key + 8, state, key_state_str(state));
|
||||
|
||||
char buf[128];
|
||||
xkb_keysym_t sym = xkb_state_key_get_one_sym(wev_state->xkb_state, key + 8);
|
||||
uint32_t keycode = state == WL_KEYBOARD_KEY_STATE_PRESSED ? key + 8 : 0;
|
||||
|
||||
if (n != 0) {
|
||||
xkb_keysym_get_name(sym, buf, sizeof(buf));
|
||||
printf(SPACER "sym: %-12s (%d), ", buf, sym);
|
||||
|
||||
xkb_state_key_get_utf8(wev_state->xkb_state, keycode, buf, sizeof(buf));
|
||||
printf("utf8: '%s'\n", buf);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_modifiers(struct wev_state *state, uint32_t mods) {
|
||||
if (mods != 0) {
|
||||
printf(": ");
|
||||
}
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
if ((mods >> i) & 1) {
|
||||
printf("%s ", xkb_keymap_mod_get_name(state->xkb_keymap, i));
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,
|
||||
uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched,
|
||||
uint32_t mods_locked, uint32_t group) {
|
||||
struct wev_state *state = data;
|
||||
int n = proxy_log(state, (struct wl_proxy *)wl_keyboard, "modifiers",
|
||||
"serial: %d; group: %d\n", group);
|
||||
if (n != 0) {
|
||||
printf(SPACER "depressed: %08X", mods_depressed);
|
||||
print_modifiers(state, mods_depressed);
|
||||
printf(SPACER "latched: %08X", mods_latched);
|
||||
print_modifiers(state, mods_latched);
|
||||
printf(SPACER "locked: %08X", mods_locked);
|
||||
print_modifiers(state, mods_locked);
|
||||
}
|
||||
xkb_state_update_mask(state->xkb_state,
|
||||
mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
}
|
||||
|
||||
static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
|
||||
int32_t rate, int32_t delay) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_keyboard, "repeat_info",
|
||||
"rate: %d keys/sec; delay: %d ms\n", rate, delay);
|
||||
}
|
||||
|
||||
static const struct wl_keyboard_listener wl_keyboard_listener = {
|
||||
.keymap = wl_keyboard_keymap,
|
||||
.enter = wl_keyboard_enter,
|
||||
.leave = wl_keyboard_leave,
|
||||
.key = wl_keyboard_key,
|
||||
.modifiers = wl_keyboard_modifiers,
|
||||
.repeat_info = wl_keyboard_repeat_info,
|
||||
};
|
||||
|
||||
void wl_touch_down(void *data, struct wl_touch *wl_touch,
|
||||
uint32_t serial, uint32_t time, struct wl_surface *surface, int32_t id,
|
||||
wl_fixed_t x, wl_fixed_t y) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_touch, "down",
|
||||
"serial: %d; time: %d; surface: %d; id: %d; x, y: %f, %f\n",
|
||||
serial, time, wl_proxy_get_id((struct wl_proxy *)surface),
|
||||
id, wl_fixed_to_double(x), wl_fixed_to_double(y));
|
||||
}
|
||||
|
||||
void wl_touch_up(void *data, struct wl_touch *wl_touch,
|
||||
uint32_t serial, uint32_t time, int32_t id) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_touch, "up",
|
||||
"serial: %d; time: %d; id: %d\n", serial, time, id);
|
||||
}
|
||||
|
||||
void wl_touch_motion(void *data, struct wl_touch *wl_touch,
|
||||
uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_touch, "motion",
|
||||
"time: %d; id: %d; x, y: %f, %f\n",
|
||||
time, id, wl_fixed_to_double(x), wl_fixed_to_double(y));
|
||||
}
|
||||
|
||||
void wl_touch_frame(void *data, struct wl_touch *wl_touch) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_touch, "frame", "\n");
|
||||
}
|
||||
|
||||
void wl_touch_cancel(void *data, struct wl_touch *wl_touch) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_touch, "cancel", "\n");
|
||||
}
|
||||
|
||||
void wl_touch_shape(void *data, struct wl_touch *wl_touch,
|
||||
int32_t id, wl_fixed_t major, wl_fixed_t minor) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_touch, "shape",
|
||||
"id: %d; major, minor: %f, %f\n",
|
||||
id, wl_fixed_to_double(major), wl_fixed_to_double(minor));
|
||||
}
|
||||
|
||||
void wl_touch_orientation(void *data, struct wl_touch *wl_touch,
|
||||
int32_t id, wl_fixed_t orientation) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)wl_touch, "shape",
|
||||
"id: %d; orientation: %f\n",
|
||||
id, wl_fixed_to_double(orientation));
|
||||
}
|
||||
|
||||
static const struct wl_touch_listener wl_touch_listener = {
|
||||
.down = wl_touch_down,
|
||||
.up = wl_touch_up,
|
||||
.motion = wl_touch_motion,
|
||||
.frame = wl_touch_frame,
|
||||
.cancel = wl_touch_cancel,
|
||||
.shape = wl_touch_shape,
|
||||
.orientation = wl_touch_orientation,
|
||||
};
|
||||
|
||||
static void wl_seat_capabilities(void *data, struct wl_seat *wl_seat,
|
||||
uint32_t capabilities) {
|
||||
struct wev_state *state = data;
|
||||
int n = proxy_log(state, (struct wl_proxy *)wl_seat, "capabilities", "");
|
||||
if (capabilities == 0 && n != 0) {
|
||||
printf(" none");
|
||||
}
|
||||
if ((capabilities & WL_SEAT_CAPABILITY_POINTER)) {
|
||||
if (n != 0) {
|
||||
printf("pointer ");
|
||||
}
|
||||
struct wl_pointer *pointer = wl_seat_get_pointer(wl_seat);
|
||||
wl_pointer_add_listener(pointer, &wl_pointer_listener, data);
|
||||
}
|
||||
if ((capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) {
|
||||
if (n != 0) {
|
||||
printf("keyboard ");
|
||||
}
|
||||
struct wl_keyboard *keyboard = wl_seat_get_keyboard(wl_seat);
|
||||
wl_keyboard_add_listener(keyboard, &wl_keyboard_listener, data);
|
||||
}
|
||||
if ((capabilities & WL_SEAT_CAPABILITY_TOUCH)) {
|
||||
if (n != 0) {
|
||||
printf("touch ");
|
||||
}
|
||||
struct wl_touch *touch = wl_seat_get_touch(wl_seat);
|
||||
wl_touch_add_listener(touch, &wl_touch_listener, data);
|
||||
}
|
||||
if (n != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_seat_name(void *data, struct wl_seat *seat, const char *name) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)seat, "name", "%s\n", name);
|
||||
}
|
||||
|
||||
static const struct wl_seat_listener wl_seat_listener = {
|
||||
.capabilities = wl_seat_capabilities,
|
||||
.name = wl_seat_name,
|
||||
};
|
||||
|
||||
static void wl_buffer_release(void *data, struct wl_buffer *wl_buffer) {
|
||||
wl_buffer_destroy(wl_buffer);
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener wl_buffer_listener = {
|
||||
.release = wl_buffer_release,
|
||||
};
|
||||
|
||||
static struct wl_buffer *create_buffer(struct wev_state *state) {
|
||||
int stride = state->width * 4;
|
||||
int size = stride * state->height;
|
||||
|
||||
int fd = allocate_shm_file(size);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "Failed to create shm pool file: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t *data = mmap(NULL, size,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (data == MAP_FAILED) {
|
||||
fprintf(stderr, "shm buffer mmap failed\n");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wl_shm_pool *pool = wl_shm_create_pool(state->shm, fd, size);
|
||||
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0,
|
||||
state->width, state->height, stride, WL_SHM_FORMAT_XRGB8888);
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
for (int y = 0; y < state->height; ++y) {
|
||||
for (int x = 0; x < state->width; ++x) {
|
||||
if ((x + y / 8 * 8) % 16 < 8) {
|
||||
data[y * state->width + x] = 0xFF666666;
|
||||
} else {
|
||||
data[y * state->width + x] = 0xFFEEEEEE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wl_buffer_add_listener(buffer, &wl_buffer_listener, NULL);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void xdg_toplevel_configure(void *data,
|
||||
struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height,
|
||||
struct wl_array *states) {
|
||||
struct wev_state *state = data;
|
||||
state->width = width;
|
||||
state->height = height;
|
||||
if (state->width == 0 || state->height == 0) {
|
||||
state->width = 640;
|
||||
state->height = 480;
|
||||
}
|
||||
int n = proxy_log(state, (struct wl_proxy *)xdg_toplevel, "configure",
|
||||
"width: %d; height: %d", width, height);
|
||||
if (n != 0) {
|
||||
if (states->size > 0) {
|
||||
printf("\n" SPACER);
|
||||
}
|
||||
uint32_t *s;
|
||||
wl_array_for_each(s, states) {
|
||||
switch (*s) {
|
||||
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
||||
printf("maximized ");
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
||||
printf("fullscreen ");
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_RESIZING:
|
||||
printf("resizing ");
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_ACTIVATED:
|
||||
printf("activated ");
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_TILED_LEFT:
|
||||
printf("tiled-left ");
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
|
||||
printf("tiled-right ");
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_TILED_TOP:
|
||||
printf("tiled-top ");
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
|
||||
printf("tiled-bottom ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) {
|
||||
struct wev_state *state = data;
|
||||
state->closed = true;
|
||||
proxy_log(state, (struct wl_proxy *)xdg_toplevel, "close", "\n");
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||
.configure = xdg_toplevel_configure,
|
||||
.close = xdg_toplevel_close,
|
||||
};
|
||||
|
||||
static void xdg_surface_configure(
|
||||
void *data, struct xdg_surface *xdg_surface, uint32_t serial) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)xdg_surface, "configure",
|
||||
"serial: %d\n", serial);
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
struct wl_buffer *buffer = create_buffer(state);
|
||||
wl_surface_attach(state->surface, buffer, 0, 0);
|
||||
wl_surface_damage_buffer(state->surface, 0, 0, INT32_MAX, INT32_MAX);
|
||||
wl_surface_commit(state->surface);
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
.configure = xdg_surface_configure,
|
||||
};
|
||||
|
||||
static void wm_base_ping(void *data,
|
||||
struct xdg_wm_base *wm_base, uint32_t serial) {
|
||||
xdg_wm_base_pong(wm_base, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
||||
.ping = wm_base_ping,
|
||||
};
|
||||
|
||||
static void wl_data_offer_offer(void *data, struct wl_data_offer *offer,
|
||||
const char * mime_type) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)offer, "offer",
|
||||
"mime_type: %s\n", mime_type);
|
||||
}
|
||||
|
||||
static const char *dnd_actions_str(uint32_t state) {
|
||||
switch (state) {
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
|
||||
return "none";
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
|
||||
return "copy";
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
|
||||
return "move";
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
|
||||
return "copy, move";
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
|
||||
return "ask";
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
|
||||
return "copy, ask";
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
|
||||
return "move, ask";
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
|
||||
return "copy, move, ask";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_data_offer_source_actions(void *data,
|
||||
struct wl_data_offer *offer, uint32_t actions) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)offer, "source_actions",
|
||||
"actions: %u (%s)\n", actions, dnd_actions_str(actions));
|
||||
}
|
||||
|
||||
static void wl_data_offer_action(void *data, struct wl_data_offer *offer,
|
||||
uint32_t dnd_action) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)offer, "action",
|
||||
"dnd_action: %u (%s)\n", dnd_action, dnd_actions_str(dnd_action));
|
||||
}
|
||||
|
||||
static const struct wl_data_offer_listener wl_data_offer_listener = {
|
||||
.offer = wl_data_offer_offer,
|
||||
.source_actions = wl_data_offer_source_actions,
|
||||
.action = wl_data_offer_action,
|
||||
};
|
||||
|
||||
static void wl_data_device_data_offer(void *data,
|
||||
struct wl_data_device *device, struct wl_data_offer *id) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)device, "data_offer",
|
||||
"id: %u\n", wl_proxy_get_id((struct wl_proxy *)id));
|
||||
|
||||
wl_data_offer_add_listener(id, &wl_data_offer_listener, data);
|
||||
}
|
||||
|
||||
static void wl_data_device_enter(void *data,
|
||||
struct wl_data_device *device, uint32_t serial,
|
||||
struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y,
|
||||
struct wl_data_offer *id) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)device, "enter",
|
||||
"serial: %d; surface: %d; x, y: %f, %f; id: %u\n", serial,
|
||||
wl_proxy_get_id((struct wl_proxy *)surface),
|
||||
wl_fixed_to_double(x), wl_fixed_to_double(y),
|
||||
wl_proxy_get_id((struct wl_proxy *)id));
|
||||
|
||||
state->dnd = id;
|
||||
wl_data_offer_set_actions(id,
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK,
|
||||
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
|
||||
|
||||
// Static accept just so we have something.
|
||||
wl_data_offer_accept(id, serial, "text/plain");
|
||||
}
|
||||
|
||||
static void wl_data_device_leave(void *data,
|
||||
struct wl_data_device *device) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)device, "leave", "\n");
|
||||
|
||||
// Might have already been destroyed during a drop event.
|
||||
if (state->dnd != NULL) {
|
||||
wl_data_offer_destroy(state->dnd);
|
||||
state->dnd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_data_device_motion(void *data,
|
||||
struct wl_data_device *device, uint32_t serial, wl_fixed_t x,
|
||||
wl_fixed_t y) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)device, "motion",
|
||||
"serial: %d; x, y: %f, %f\n", serial, wl_fixed_to_double(x),
|
||||
wl_fixed_to_double(y));
|
||||
}
|
||||
|
||||
static void wl_data_device_drop(void *data,
|
||||
struct wl_data_device *device) {
|
||||
struct wev_state *state = data;
|
||||
proxy_log(state, (struct wl_proxy *)device, "drop", "\n");
|
||||
|
||||
// We don't actually want the data, so cancel the drop.
|
||||
wl_data_offer_destroy(state->dnd);
|
||||
state->dnd = NULL;
|
||||
}
|
||||
|
||||
static void wl_data_device_selection(void *data,
|
||||
struct wl_data_device *device, struct wl_data_offer *id) {
|
||||
struct wev_state *state = data;
|
||||
if (id == NULL) {
|
||||
proxy_log(state, (struct wl_proxy *)device, "selection",
|
||||
"(cleared)\n");
|
||||
}
|
||||
else {
|
||||
proxy_log(state, (struct wl_proxy *)device, "selection", "id: %u\n",
|
||||
wl_proxy_get_id((struct wl_proxy *)id));
|
||||
}
|
||||
|
||||
if (state->selection != NULL) {
|
||||
wl_data_offer_destroy(state->selection);
|
||||
}
|
||||
state->selection = id; // May be NULL.
|
||||
}
|
||||
|
||||
static const struct wl_data_device_listener wl_data_device_listener = {
|
||||
.data_offer = wl_data_device_data_offer,
|
||||
.enter = wl_data_device_enter,
|
||||
.leave = wl_data_device_leave,
|
||||
.motion = wl_data_device_motion,
|
||||
.drop = wl_data_device_drop,
|
||||
.selection = wl_data_device_selection,
|
||||
};
|
||||
|
||||
static void registry_global(void *data, struct wl_registry *wl_registry,
|
||||
uint32_t name, const char *interface, uint32_t version) {
|
||||
struct wev_state *state = data;
|
||||
struct {
|
||||
const struct wl_interface *interface;
|
||||
int version;
|
||||
void **ptr;
|
||||
} handles[] = {
|
||||
{ &wl_compositor_interface, 4, (void **)&state->compositor },
|
||||
{ &wl_seat_interface, 6, (void **)&state->seat },
|
||||
{ &wl_shm_interface, 1, (void **)&state->shm },
|
||||
{ &xdg_wm_base_interface, 2, (void **)&state->wm_base },
|
||||
{ &wl_data_device_manager_interface, 3,
|
||||
(void **)&state->data_device_manager },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(handles) / sizeof(handles[0]); ++i) {
|
||||
if (strcmp(interface, handles[i].interface->name) == 0) {
|
||||
*handles[i].ptr = wl_registry_bind(wl_registry,
|
||||
name, handles[i].interface, handles[i].version);
|
||||
}
|
||||
}
|
||||
|
||||
if (state->opts.print_globals) {
|
||||
proxy_log(state, (struct wl_proxy *)wl_registry, "global",
|
||||
"interface: '%s', version: %d, name: %d\n",
|
||||
interface, version, name);
|
||||
}
|
||||
}
|
||||
|
||||
static void registry_global_remove(
|
||||
void *data, struct wl_registry *wl_registry, uint32_t name) {
|
||||
/* Who cares */
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener wl_registry_listener = {
|
||||
.global = registry_global,
|
||||
.global_remove = registry_global_remove,
|
||||
};
|
||||
|
||||
void show_usage(void) {
|
||||
printf("Usage: wev [-g] "
|
||||
"[-f <interface[:event]>] [-F <interface[:event]>] [-M <path>]\n");
|
||||
}
|
||||
|
||||
void add_filter(struct wl_list *list, char *filter) {
|
||||
char *iface = strtok(filter, ":");
|
||||
char *event = strtok(NULL, ":");
|
||||
struct wev_filter *f = calloc(1, sizeof(struct wev_filter));
|
||||
f->interface = strdup(iface);
|
||||
f->event = event ? strdup(event) : 0;
|
||||
wl_list_insert(list, &f->link);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct wev_state state = { 0 };
|
||||
wl_list_init(&state.opts.filters);
|
||||
wl_list_init(&state.opts.inverse_filters);
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "f:F:ghM:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
add_filter(&state.opts.filters, optarg);
|
||||
break;
|
||||
case 'F':
|
||||
add_filter(&state.opts.inverse_filters, optarg);
|
||||
break;
|
||||
case 'g':
|
||||
state.opts.print_globals = true;
|
||||
break;
|
||||
case 'h':
|
||||
show_usage();
|
||||
return 0;
|
||||
case 'M':
|
||||
state.opts.dump_map = optarg;
|
||||
break;
|
||||
default:
|
||||
show_usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (optind < argc) {
|
||||
show_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
|
||||
state.display = wl_display_connect(NULL);
|
||||
if (!state.display) {
|
||||
fprintf(stderr, "Failed to connect to Wayland display\n");
|
||||
return 1;
|
||||
}
|
||||
state.registry = wl_display_get_registry(state.display);
|
||||
if (!state.registry) {
|
||||
fprintf(stderr, "Failed to obtain Wayland registry\n");
|
||||
return 1;
|
||||
}
|
||||
wl_registry_add_listener(state.registry, &wl_registry_listener, &state);
|
||||
wl_display_roundtrip(state.display);
|
||||
|
||||
struct {
|
||||
char *name;
|
||||
void *ptr;
|
||||
} required[] = {
|
||||
{ "wl_compositor", state.compositor, },
|
||||
{ "wl_seat", state.seat, },
|
||||
{ "wl_shm", state.shm, },
|
||||
{ "xdg_wm_base", state.wm_base, },
|
||||
{ "wl_data_device_manager", state.data_device_manager, },
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(required) / sizeof(required[0]); ++i) {
|
||||
if (required->ptr == NULL) {
|
||||
fprintf(stderr, "%s is required but is not present.\n",
|
||||
required[i].name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
xdg_wm_base_add_listener(state.wm_base, &xdg_wm_base_listener, NULL);
|
||||
|
||||
state.surface = wl_compositor_create_surface(state.compositor);
|
||||
state.xdg_surface = xdg_wm_base_get_xdg_surface(
|
||||
state.wm_base, state.surface);
|
||||
xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, &state);
|
||||
|
||||
state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface);
|
||||
xdg_toplevel_set_title(state.xdg_toplevel, "wev");
|
||||
xdg_toplevel_set_app_id(state.xdg_toplevel, "wev");
|
||||
xdg_toplevel_add_listener(state.xdg_toplevel,
|
||||
&xdg_toplevel_listener, &state);
|
||||
|
||||
wl_seat_add_listener(state.seat, &wl_seat_listener, &state);
|
||||
|
||||
struct wl_data_device *data_device =
|
||||
wl_data_device_manager_get_data_device(state.data_device_manager,
|
||||
state.seat);
|
||||
wl_data_device_add_listener(data_device, &wl_data_device_listener, &state);
|
||||
|
||||
wl_surface_commit(state.surface);
|
||||
wl_display_roundtrip(state.display);
|
||||
|
||||
while (wl_display_dispatch(state.display) && !state.closed) {
|
||||
/* This space deliberately left blank */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue