commit
45a2e25d6d
@ -51,6 +51,9 @@ static const int repeat_delay = 600;
|
||||
{ MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.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 */
|
||||
static const char *termcmd[] = { "alacritty", NULL };
|
||||
|
||||
|
180
dwl.c
180
dwl.c
@ -17,6 +17,7 @@
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_data_device.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_keyboard.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
@ -40,6 +41,8 @@
|
||||
#endif
|
||||
|
||||
/* 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 MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
|
||||
@ -55,9 +58,9 @@
|
||||
|
||||
/* enums */
|
||||
enum { CurNormal, CurMove, CurResize }; /* cursor */
|
||||
#ifdef XWAYLAND
|
||||
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
|
||||
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
|
||||
#ifdef XWAYLAND
|
||||
enum { XDGShell, X11Managed, X11Unmanaged }; /* client types */
|
||||
#endif
|
||||
|
||||
@ -177,6 +180,7 @@ static void arrange(Monitor *m);
|
||||
static void axisnotify(struct wl_listener *listener, void *data);
|
||||
static void buttonpress(struct wl_listener *listener, void *data);
|
||||
static void chvt(const Arg *arg);
|
||||
static void cleanup(void);
|
||||
static void cleanupkeyboard(struct wl_listener *listener, void *data);
|
||||
static void cleanupmon(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 setmon(Client *c, Monitor *m, unsigned int newtags);
|
||||
static void setup(void);
|
||||
static void sigchld(int unused);
|
||||
static void spawn(const Arg *arg);
|
||||
static void tag(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 updatewindowtype(Client *c);
|
||||
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 xwayland_ready = {.notify = xwaylandready};
|
||||
static struct wlr_xwayland *xwayland;
|
||||
@ -327,8 +333,8 @@ applyrules(Client *c)
|
||||
/* rule matching */
|
||||
c->isfloating = 0;
|
||||
#ifdef XWAYLAND
|
||||
updatewindowtype(c);
|
||||
if (c->type != XDGShell) {
|
||||
updatewindowtype(c);
|
||||
appid = c->surface.xwayland->class;
|
||||
title = c->surface.xwayland->title;
|
||||
} else
|
||||
@ -427,10 +433,21 @@ buttonpress(struct wl_listener *listener, void *data)
|
||||
void
|
||||
chvt(const Arg *arg)
|
||||
{
|
||||
struct wlr_session *s = wlr_backend_get_session(backend);
|
||||
if (!s)
|
||||
return;
|
||||
wlr_session_change_vt(s, arg->ui);
|
||||
wlr_session_change_vt(wlr_backend_get_session(backend), 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
|
||||
@ -971,7 +988,16 @@ motionnotify(uint32_t time)
|
||||
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. */
|
||||
} else
|
||||
#endif
|
||||
if ((c = xytoclient(cursor->x, cursor->y))) {
|
||||
#ifdef XWAYLAND
|
||||
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
|
||||
* of its surfaces, and make keyboard focus follow if desired. */
|
||||
wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
|
||||
|
||||
#if XWAYLAND
|
||||
if (c->type == X11Unmanaged)
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (sloppyfocus)
|
||||
focusclient(selclient(), c, 0);
|
||||
}
|
||||
@ -1266,20 +1298,13 @@ run(char *startup_cmd)
|
||||
|
||||
/* Add a Unix socket to the Wayland display. */
|
||||
const char *socket = wl_display_add_socket_auto(dpy);
|
||||
if (!socket) {
|
||||
perror("startup: display_add_socket_auto");
|
||||
wlr_backend_destroy(backend);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!socket)
|
||||
BARF("startup: display_add_socket_auto");
|
||||
|
||||
/* Start the backend. This will enumerate outputs and inputs, become the DRM
|
||||
* master, etc */
|
||||
if (!wlr_backend_start(backend)) {
|
||||
perror("startup: backend_start");
|
||||
wlr_backend_destroy(backend);
|
||||
wl_display_destroy(dpy);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!wlr_backend_start(backend))
|
||||
BARF("startup: backend_start");
|
||||
|
||||
/* Now that outputs are initialized, choose initial selmon based on
|
||||
* cursor position, and set default cursor image */
|
||||
@ -1297,24 +1322,17 @@ run(char *startup_cmd)
|
||||
setenv("WAYLAND_DISPLAY", socket, 1);
|
||||
if (startup_cmd) {
|
||||
startup_pid = fork();
|
||||
if (startup_pid < 0) {
|
||||
perror("startup: fork");
|
||||
wl_display_destroy(dpy);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (startup_pid < 0)
|
||||
EBARF("startup: fork");
|
||||
if (startup_pid == 0) {
|
||||
execl("/bin/sh", "/bin/sh", "-c", startup_cmd, (void *)NULL);
|
||||
perror("startup: execl");
|
||||
wl_display_destroy(dpy);
|
||||
exit(EXIT_FAILURE);
|
||||
EBARF("startup: execl");
|
||||
}
|
||||
}
|
||||
/* Run the Wayland event loop. This does not return until you exit the
|
||||
* compositor. Starting the backend rigged up all of the necessary event
|
||||
* loop configuration to listen to libinput events, DRM events, generate
|
||||
* 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);
|
||||
|
||||
if (startup_cmd) {
|
||||
@ -1445,6 +1463,13 @@ setsel(struct wl_listener *listener, void *data)
|
||||
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
|
||||
* output hardware. The autocreate option will choose the most suitable
|
||||
* 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
|
||||
* if the backend does not support hardware cursors (some older GPUs
|
||||
* 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.
|
||||
* 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_screencopy_manager_v1_create(dpy);
|
||||
wlr_data_device_manager_create(dpy);
|
||||
wlr_gamma_control_manager_v1_create(dpy);
|
||||
wlr_primary_selection_v1_device_manager_create(dpy);
|
||||
wlr_viewporter_create(dpy);
|
||||
|
||||
@ -1566,15 +1593,22 @@ setup(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
sigchld(int unused)
|
||||
{
|
||||
if (signal(SIGCHLD, sigchld) == SIG_ERR)
|
||||
EBARF("can't install SIGCHLD handler");
|
||||
while (0 < waitpid(-1, NULL, WNOHANG))
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
spawn(const Arg *arg)
|
||||
{
|
||||
if (fork() == 0) {
|
||||
setsid();
|
||||
execvp(((char **)arg->v)[0], (char **)arg->v);
|
||||
fprintf(stderr, "dwl: execvp %s", ((char **)arg->v)[0]);
|
||||
perror(" failed");
|
||||
exit(EXIT_FAILURE);
|
||||
EBARF("dwl: execvp %s failed", ((char **)arg->v)[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1827,14 +1861,12 @@ void
|
||||
updatewindowtype(Client *c)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (c->type != XDGShell)
|
||||
for (i = 0; i < c->surface.xwayland->window_type_len; i++)
|
||||
if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] ||
|
||||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] ||
|
||||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] ||
|
||||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeUtility])
|
||||
c->isfloating = 1;
|
||||
for (i = 0; i < c->surface.xwayland->window_type_len; i++)
|
||||
if (c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeDialog] ||
|
||||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeSplash] ||
|
||||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeToolbar] ||
|
||||
c->surface.xwayland->window_type[i] == netatom[NetWMWindowTypeUtility])
|
||||
c->isfloating = 1;
|
||||
}
|
||||
|
||||
void
|
||||
@ -1859,65 +1891,53 @@ xwaylandready(struct wl_listener *listener, void *data)
|
||||
|
||||
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
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char *startup_cmd = NULL;
|
||||
enum wlr_log_importance loglevel = WLR_ERROR;
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "qvds:h")) != -1) {
|
||||
switch (c) {
|
||||
case 'q':
|
||||
loglevel = WLR_SILENT;
|
||||
break;
|
||||
case 'v':
|
||||
loglevel = WLR_INFO;
|
||||
break;
|
||||
case 'd':
|
||||
loglevel = WLR_DEBUG;
|
||||
break;
|
||||
case 's':
|
||||
|
||||
while ((c = getopt(argc, argv, "s:h")) != -1) {
|
||||
if (c == 's')
|
||||
startup_cmd = optarg;
|
||||
break;
|
||||
default:
|
||||
else
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
if (optind < argc)
|
||||
goto usage;
|
||||
wlr_log_init(loglevel, NULL);
|
||||
|
||||
// Wayland requires XDG_RUNTIME_DIR for creating its communications
|
||||
// socket
|
||||
if (!getenv("XDG_RUNTIME_DIR")) {
|
||||
fprintf(stderr, "XDG_RUNTIME_DIR must be set\n");
|
||||
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();
|
||||
|
||||
if (!getenv("XDG_RUNTIME_DIR"))
|
||||
BARF("XDG_RUNTIME_DIR must be set");
|
||||
setup();
|
||||
run(startup_cmd);
|
||||
|
||||
/* 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);
|
||||
|
||||
cleanup();
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
usage:
|
||||
printf("Usage: %s [-qvd] [-s startup command]\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
BARF("Usage: %s [-s startup command]", argv[0]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user