commit
45a2e25d6d
@ -51,6 +51,9 @@ static const int repeat_delay = 600;
|
|||||||
{ MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
|
{ MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
|
||||||
{ MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,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 */
|
||||||
|
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||||
|
|
||||||
/* commands */
|
/* commands */
|
||||||
static const char *termcmd[] = { "alacritty", NULL };
|
static const char *termcmd[] = { "alacritty", NULL };
|
||||||
|
|
||||||
|
168
dwl.c
168
dwl.c
@ -17,6 +17,7 @@
|
|||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_data_device.h>
|
#include <wlr/types/wlr_data_device.h>
|
||||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||||
|
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
#include <wlr/types/wlr_keyboard.h>
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
#include <wlr/types/wlr_matrix.h>
|
#include <wlr/types/wlr_matrix.h>
|
||||||
@ -40,6 +41,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* macros */
|
/* macros */
|
||||||
|
#define BARF(fmt, ...) do { fprintf(stderr, fmt "\n", ##__VA_ARGS__); exit(EXIT_FAILURE); } while (0)
|
||||||
|
#define EBARF(fmt, ...) BARF(fmt ": %s", ##__VA_ARGS__, strerror(errno))
|
||||||
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
||||||
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||||
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
|
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
|
||||||
@ -55,9 +58,9 @@
|
|||||||
|
|
||||||
/* enums */
|
/* enums */
|
||||||
enum { CurNormal, CurMove, CurResize }; /* cursor */
|
enum { CurNormal, CurMove, CurResize }; /* cursor */
|
||||||
|
#ifdef XWAYLAND
|
||||||
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
|
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
|
||||||
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
|
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
|
||||||
#ifdef XWAYLAND
|
|
||||||
enum { XDGShell, X11Managed, X11Unmanaged }; /* client types */
|
enum { XDGShell, X11Managed, X11Unmanaged }; /* client types */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -177,6 +180,7 @@ static void arrange(Monitor *m);
|
|||||||
static void axisnotify(struct wl_listener *listener, void *data);
|
static void axisnotify(struct wl_listener *listener, void *data);
|
||||||
static void buttonpress(struct wl_listener *listener, void *data);
|
static void buttonpress(struct wl_listener *listener, void *data);
|
||||||
static void chvt(const Arg *arg);
|
static void chvt(const Arg *arg);
|
||||||
|
static void cleanup(void);
|
||||||
static void cleanupkeyboard(struct wl_listener *listener, void *data);
|
static void cleanupkeyboard(struct wl_listener *listener, void *data);
|
||||||
static void cleanupmon(struct wl_listener *listener, void *data);
|
static void cleanupmon(struct wl_listener *listener, void *data);
|
||||||
static void commitnotify(struct wl_listener *listener, void *data);
|
static void commitnotify(struct wl_listener *listener, void *data);
|
||||||
@ -224,6 +228,7 @@ static void setlayout(const Arg *arg);
|
|||||||
static void setmfact(const Arg *arg);
|
static void setmfact(const Arg *arg);
|
||||||
static void setmon(Client *c, Monitor *m, unsigned int newtags);
|
static void setmon(Client *c, Monitor *m, unsigned int newtags);
|
||||||
static void setup(void);
|
static void setup(void);
|
||||||
|
static void sigchld(int unused);
|
||||||
static void spawn(const Arg *arg);
|
static void spawn(const Arg *arg);
|
||||||
static void tag(const Arg *arg);
|
static void tag(const Arg *arg);
|
||||||
static void tagmon(const Arg *arg);
|
static void tagmon(const Arg *arg);
|
||||||
@ -286,6 +291,7 @@ static Atom getatom(xcb_connection_t *xc, const char *name);
|
|||||||
static void renderindependents(struct wlr_output *output, struct timespec *now);
|
static void renderindependents(struct wlr_output *output, struct timespec *now);
|
||||||
static void updatewindowtype(Client *c);
|
static void updatewindowtype(Client *c);
|
||||||
static void xwaylandready(struct wl_listener *listener, void *data);
|
static void xwaylandready(struct wl_listener *listener, void *data);
|
||||||
|
static Client *xytoindependent(double x, double y);
|
||||||
static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};
|
static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};
|
||||||
static struct wl_listener xwayland_ready = {.notify = xwaylandready};
|
static struct wl_listener xwayland_ready = {.notify = xwaylandready};
|
||||||
static struct wlr_xwayland *xwayland;
|
static struct wlr_xwayland *xwayland;
|
||||||
@ -327,8 +333,8 @@ applyrules(Client *c)
|
|||||||
/* rule matching */
|
/* rule matching */
|
||||||
c->isfloating = 0;
|
c->isfloating = 0;
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
updatewindowtype(c);
|
|
||||||
if (c->type != XDGShell) {
|
if (c->type != XDGShell) {
|
||||||
|
updatewindowtype(c);
|
||||||
appid = c->surface.xwayland->class;
|
appid = c->surface.xwayland->class;
|
||||||
title = c->surface.xwayland->title;
|
title = c->surface.xwayland->title;
|
||||||
} else
|
} else
|
||||||
@ -427,10 +433,21 @@ buttonpress(struct wl_listener *listener, void *data)
|
|||||||
void
|
void
|
||||||
chvt(const Arg *arg)
|
chvt(const Arg *arg)
|
||||||
{
|
{
|
||||||
struct wlr_session *s = wlr_backend_get_session(backend);
|
wlr_session_change_vt(wlr_backend_get_session(backend), arg->ui);
|
||||||
if (!s)
|
}
|
||||||
return;
|
|
||||||
wlr_session_change_vt(s, arg->ui);
|
void
|
||||||
|
cleanup(void)
|
||||||
|
{
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
wlr_xwayland_destroy(xwayland);
|
||||||
|
#endif
|
||||||
|
wl_display_destroy_clients(dpy);
|
||||||
|
wl_display_destroy(dpy);
|
||||||
|
|
||||||
|
wlr_xcursor_manager_destroy(cursor_mgr);
|
||||||
|
wlr_cursor_destroy(cursor);
|
||||||
|
wlr_output_layout_destroy(output_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -971,7 +988,16 @@ motionnotify(uint32_t time)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
/* Find an independent under the pointer and send the event along. */
|
||||||
|
if ((c = xytoindependent(cursor->x, cursor->y))) {
|
||||||
|
surface = wlr_surface_surface_at(c->surface.xwayland->surface,
|
||||||
|
cursor->x - c->surface.xwayland->x - c->bw,
|
||||||
|
cursor->y - c->surface.xwayland->y - c->bw, &sx, &sy);
|
||||||
|
|
||||||
/* Otherwise, find the client under the pointer and send the event along. */
|
/* Otherwise, find the client under the pointer and send the event along. */
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
if ((c = xytoclient(cursor->x, cursor->y))) {
|
if ((c = xytoclient(cursor->x, cursor->y))) {
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (c->type != XDGShell)
|
if (c->type != XDGShell)
|
||||||
@ -1060,6 +1086,12 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
|
|||||||
/* Otherwise, let the client know that the mouse cursor has entered one
|
/* Otherwise, let the client know that the mouse cursor has entered one
|
||||||
* of its surfaces, and make keyboard focus follow if desired. */
|
* of its surfaces, and make keyboard focus follow if desired. */
|
||||||
wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
|
wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
|
||||||
|
|
||||||
|
#if XWAYLAND
|
||||||
|
if (c->type == X11Unmanaged)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (sloppyfocus)
|
if (sloppyfocus)
|
||||||
focusclient(selclient(), c, 0);
|
focusclient(selclient(), c, 0);
|
||||||
}
|
}
|
||||||
@ -1266,20 +1298,13 @@ run(char *startup_cmd)
|
|||||||
|
|
||||||
/* Add a Unix socket to the Wayland display. */
|
/* Add a Unix socket to the Wayland display. */
|
||||||
const char *socket = wl_display_add_socket_auto(dpy);
|
const char *socket = wl_display_add_socket_auto(dpy);
|
||||||
if (!socket) {
|
if (!socket)
|
||||||
perror("startup: display_add_socket_auto");
|
BARF("startup: display_add_socket_auto");
|
||||||
wlr_backend_destroy(backend);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start the backend. This will enumerate outputs and inputs, become the DRM
|
/* Start the backend. This will enumerate outputs and inputs, become the DRM
|
||||||
* master, etc */
|
* master, etc */
|
||||||
if (!wlr_backend_start(backend)) {
|
if (!wlr_backend_start(backend))
|
||||||
perror("startup: backend_start");
|
BARF("startup: backend_start");
|
||||||
wlr_backend_destroy(backend);
|
|
||||||
wl_display_destroy(dpy);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now that outputs are initialized, choose initial selmon based on
|
/* Now that outputs are initialized, choose initial selmon based on
|
||||||
* cursor position, and set default cursor image */
|
* cursor position, and set default cursor image */
|
||||||
@ -1297,24 +1322,17 @@ run(char *startup_cmd)
|
|||||||
setenv("WAYLAND_DISPLAY", socket, 1);
|
setenv("WAYLAND_DISPLAY", socket, 1);
|
||||||
if (startup_cmd) {
|
if (startup_cmd) {
|
||||||
startup_pid = fork();
|
startup_pid = fork();
|
||||||
if (startup_pid < 0) {
|
if (startup_pid < 0)
|
||||||
perror("startup: fork");
|
EBARF("startup: fork");
|
||||||
wl_display_destroy(dpy);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
if (startup_pid == 0) {
|
if (startup_pid == 0) {
|
||||||
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, (void *)NULL);
|
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, (void *)NULL);
|
||||||
perror("startup: execl");
|
EBARF("startup: execl");
|
||||||
wl_display_destroy(dpy);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Run the Wayland event loop. This does not return until you exit the
|
/* Run the Wayland event loop. This does not return until you exit the
|
||||||
* compositor. Starting the backend rigged up all of the necessary event
|
* compositor. Starting the backend rigged up all of the necessary event
|
||||||
* loop configuration to listen to libinput events, DRM events, generate
|
* loop configuration to listen to libinput events, DRM events, generate
|
||||||
* frame events at the refresh rate, and so on. */
|
* frame events at the refresh rate, and so on. */
|
||||||
wlr_log(WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s",
|
|
||||||
socket);
|
|
||||||
wl_display_run(dpy);
|
wl_display_run(dpy);
|
||||||
|
|
||||||
if (startup_cmd) {
|
if (startup_cmd) {
|
||||||
@ -1445,6 +1463,13 @@ setsel(struct wl_listener *listener, void *data)
|
|||||||
void
|
void
|
||||||
setup(void)
|
setup(void)
|
||||||
{
|
{
|
||||||
|
/* The Wayland display is managed by libwayland. It handles accepting
|
||||||
|
* clients from the Unix socket, manging Wayland globals, and so on. */
|
||||||
|
dpy = wl_display_create();
|
||||||
|
|
||||||
|
/* clean up child processes immediately */
|
||||||
|
sigchld(0);
|
||||||
|
|
||||||
/* The backend is a wlroots feature which abstracts the underlying input and
|
/* The backend is a wlroots feature which abstracts the underlying input and
|
||||||
* output hardware. The autocreate option will choose the most suitable
|
* output hardware. The autocreate option will choose the most suitable
|
||||||
* backend based on the current environment, such as opening an X11 window
|
* backend based on the current environment, such as opening an X11 window
|
||||||
@ -1453,7 +1478,8 @@ setup(void)
|
|||||||
* backend uses the renderer, for example, to fall back to software cursors
|
* backend uses the renderer, for example, to fall back to software cursors
|
||||||
* if the backend does not support hardware cursors (some older GPUs
|
* if the backend does not support hardware cursors (some older GPUs
|
||||||
* don't). */
|
* don't). */
|
||||||
backend = wlr_backend_autocreate(dpy, NULL);
|
if (!(backend = wlr_backend_autocreate(dpy, NULL)))
|
||||||
|
BARF("couldn't create backend");
|
||||||
|
|
||||||
/* If we don't provide a renderer, autocreate makes a GLES2 renderer for us.
|
/* If we don't provide a renderer, autocreate makes a GLES2 renderer for us.
|
||||||
* The renderer is responsible for defining the various pixel formats it
|
* The renderer is responsible for defining the various pixel formats it
|
||||||
@ -1471,6 +1497,7 @@ setup(void)
|
|||||||
wlr_export_dmabuf_manager_v1_create(dpy);
|
wlr_export_dmabuf_manager_v1_create(dpy);
|
||||||
wlr_screencopy_manager_v1_create(dpy);
|
wlr_screencopy_manager_v1_create(dpy);
|
||||||
wlr_data_device_manager_create(dpy);
|
wlr_data_device_manager_create(dpy);
|
||||||
|
wlr_gamma_control_manager_v1_create(dpy);
|
||||||
wlr_primary_selection_v1_device_manager_create(dpy);
|
wlr_primary_selection_v1_device_manager_create(dpy);
|
||||||
wlr_viewporter_create(dpy);
|
wlr_viewporter_create(dpy);
|
||||||
|
|
||||||
@ -1566,15 +1593,22 @@ setup(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sigchld(int unused)
|
||||||
|
{
|
||||||
|
if (signal(SIGCHLD, sigchld) == SIG_ERR)
|
||||||
|
EBARF("can't install SIGCHLD handler");
|
||||||
|
while (0 < waitpid(-1, NULL, WNOHANG))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
spawn(const Arg *arg)
|
spawn(const Arg *arg)
|
||||||
{
|
{
|
||||||
if (fork() == 0) {
|
if (fork() == 0) {
|
||||||
setsid();
|
setsid();
|
||||||
execvp(((char **)arg->v)[0], (char **)arg->v);
|
execvp(((char **)arg->v)[0], (char **)arg->v);
|
||||||
fprintf(stderr, "dwl: execvp %s", ((char **)arg->v)[0]);
|
EBARF("dwl: execvp %s failed", ((char **)arg->v)[0]);
|
||||||
perror(" failed");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1827,8 +1861,6 @@ void
|
|||||||
updatewindowtype(Client *c)
|
updatewindowtype(Client *c)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (c->type != XDGShell)
|
|
||||||
for (i = 0; i < c->surface.xwayland->window_type_len; i++)
|
for (i = 0; i < c->surface.xwayland->window_type_len; i++)
|
||||||
if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] ||
|
if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] ||
|
||||||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] ||
|
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] ||
|
||||||
@ -1859,65 +1891,53 @@ xwaylandready(struct wl_listener *listener, void *data)
|
|||||||
|
|
||||||
xcb_disconnect(xc);
|
xcb_disconnect(xc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Client *
|
||||||
|
xytoindependent(double x, double y)
|
||||||
|
{
|
||||||
|
/* Find the topmost visible independent at point (x, y).
|
||||||
|
* For independents, the most recently created can be used as the "top".
|
||||||
|
* We rely on the X11 convention of unmapping unmanaged when the "owning"
|
||||||
|
* client loses focus, which ensures that unmanaged are only visible on
|
||||||
|
* the current tag. */
|
||||||
|
Client *c;
|
||||||
|
struct wlr_box geom;
|
||||||
|
wl_list_for_each_reverse(c, &independents, link) {
|
||||||
|
geom.x = c->surface.xwayland->x;
|
||||||
|
geom.y = c->surface.xwayland->y;
|
||||||
|
geom.width = c->surface.xwayland->width;
|
||||||
|
geom.height = c->surface.xwayland->height;
|
||||||
|
if (wlr_box_contains_point(&geom, x, y))
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char *startup_cmd = NULL;
|
char *startup_cmd = NULL;
|
||||||
enum wlr_log_importance loglevel = WLR_ERROR;
|
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while ((c = getopt(argc, argv, "qvds:h")) != -1) {
|
|
||||||
switch (c) {
|
while ((c = getopt(argc, argv, "s:h")) != -1) {
|
||||||
case 'q':
|
if (c == 's')
|
||||||
loglevel = WLR_SILENT;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
loglevel = WLR_INFO;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
loglevel = WLR_DEBUG;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
startup_cmd = optarg;
|
startup_cmd = optarg;
|
||||||
break;
|
else
|
||||||
default:
|
|
||||||
goto usage;
|
goto usage;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (optind < argc)
|
if (optind < argc)
|
||||||
goto usage;
|
goto usage;
|
||||||
wlr_log_init(loglevel, NULL);
|
|
||||||
|
|
||||||
// Wayland requires XDG_RUNTIME_DIR for creating its communications
|
// Wayland requires XDG_RUNTIME_DIR for creating its communications
|
||||||
// socket
|
// socket
|
||||||
if (!getenv("XDG_RUNTIME_DIR")) {
|
if (!getenv("XDG_RUNTIME_DIR"))
|
||||||
fprintf(stderr, "XDG_RUNTIME_DIR must be set\n");
|
BARF("XDG_RUNTIME_DIR must be set");
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The Wayland display is managed by libwayland. It handles accepting
|
|
||||||
* clients from the Unix socket, manging Wayland globals, and so on. */
|
|
||||||
dpy = wl_display_create();
|
|
||||||
|
|
||||||
setup();
|
setup();
|
||||||
run(startup_cmd);
|
run(startup_cmd);
|
||||||
|
cleanup();
|
||||||
/* Once wl_display_run returns, we shut down the server. */
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
wlr_xwayland_destroy(xwayland);
|
|
||||||
#endif
|
|
||||||
wl_display_destroy_clients(dpy);
|
|
||||||
wl_display_destroy(dpy);
|
|
||||||
|
|
||||||
wlr_xcursor_manager_destroy(cursor_mgr);
|
|
||||||
wlr_cursor_destroy(cursor);
|
|
||||||
wlr_output_layout_destroy(output_layout);
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
usage:
|
usage:
|
||||||
printf("Usage: %s [-qvd] [-s startup command]\n", argv[0]);
|
BARF("Usage: %s [-s startup command]", argv[0]);
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user